Index: include/clang/AST/DeclBase.h =================================================================== --- include/clang/AST/DeclBase.h +++ include/clang/AST/DeclBase.h @@ -1265,6 +1265,12 @@ return DeclKind == Decl::TranslationUnit; } + bool isOMPDeclareTarget() const { return DeclKind == Decl::OMPDeclareTarget; } + + bool isTranslationUnitOrDeclareTarget() const { + return isOMPDeclareTarget() || isTranslationUnit(); + } + bool isRecord() const { return DeclKind >= Decl::firstRecord && DeclKind <= Decl::lastRecord; } Index: include/clang/AST/DeclOpenMP.h =================================================================== --- include/clang/AST/DeclOpenMP.h +++ include/clang/AST/DeclOpenMP.h @@ -15,7 +15,7 @@ #ifndef LLVM_CLANG_AST_DECLOPENMP_H #define LLVM_CLANG_AST_DECLOPENMP_H -#include "clang/AST/DeclBase.h" +#include "clang/AST/Decl.h" #include "llvm/ADT/ArrayRef.h" namespace clang { @@ -83,6 +83,39 @@ static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == OMPThreadPrivate; } +}; + +/// For example, in the following, declared target variable 'foo': +/// +/// \code +/// #pragma omp declare target +/// int foo; +/// #pragma omp end declare target +/// \endcode +/// +class OMPDeclareTargetDecl : public Decl, public DeclContext { + friend class ASTDeclReader; + + virtual void anchor(); + + OMPDeclareTargetDecl(Kind DK, DeclContext *DC, SourceLocation L) + : Decl(DK, DC, L), DeclContext(DK) { + setModulePrivate(); + } + +public: + static OMPDeclareTargetDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L); + static OMPDeclareTargetDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == OMPDeclareTarget; } + static DeclContext *castToDeclContext(const OMPDeclareTargetDecl *D) { + return static_cast(const_cast(D)); + } + static OMPDeclareTargetDecl *castFromDeclContext(const DeclContext *DC) { + return static_cast(const_cast(DC)); + } }; } // end namespace clang Index: include/clang/AST/RecursiveASTVisitor.h =================================================================== --- include/clang/AST/RecursiveASTVisitor.h +++ include/clang/AST/RecursiveASTVisitor.h @@ -1425,6 +1425,8 @@ } }) +DEF_TRAVERSE_DECL(OMPDeclareTargetDecl, {}) + // A helper method for TemplateDecl's children. template bool RecursiveASTVisitor::TraverseTemplateParameterListHelper( Index: include/clang/Basic/Attr.td =================================================================== --- include/clang/Basic/Attr.td +++ include/clang/Basic/Attr.td @@ -2165,6 +2165,13 @@ let Documentation = [Undocumented]; } +def OMPDeclareTargetDecl : InheritableAttr { + // This attribute has no spellings as it is only ever created implicitly. + let Spellings = []; + let SemaHandler = 0; + let Documentation = [Undocumented]; +} + def InternalLinkage : InheritableAttr { let Spellings = [GNU<"internal_linkage">, CXX11<"clang", "internal_linkage">]; let Subjects = SubjectList<[Var, Function, CXXRecord]>; Index: include/clang/Basic/DeclNodes.td =================================================================== --- include/clang/Basic/DeclNodes.td +++ include/clang/Basic/DeclNodes.td @@ -84,5 +84,6 @@ def ClassScopeFunctionSpecialization : Decl; def Import : Decl; def OMPThreadPrivate : Decl; +def OMPDeclareTarget : Decl, DeclContext; def Empty : Decl; Index: include/clang/Basic/DiagnosticGroups.td =================================================================== --- include/clang/Basic/DiagnosticGroups.td +++ include/clang/Basic/DiagnosticGroups.td @@ -809,6 +809,7 @@ def SourceUsesOpenMP : DiagGroup<"source-uses-openmp">; def OpenMPClauses : DiagGroup<"openmp-clauses">; def OpenMPLoopForm : DiagGroup<"openmp-loop-form">; +def OpenMPTarget : DiagGroup<"openmp-target">; // Backend warnings. def BackendInlineAsm : DiagGroup<"inline-asm">; Index: include/clang/Basic/DiagnosticParseKinds.td =================================================================== --- include/clang/Basic/DiagnosticParseKinds.td +++ include/clang/Basic/DiagnosticParseKinds.td @@ -928,6 +928,8 @@ "'#pragma omp %0' cannot be an immediate substatement">; def err_omp_expected_identifier_for_critical : Error< "expected identifier specifying the name of the 'omp critical' directive">; +def err_expected_end_declare_target : Error< + "expected '#pragma omp end declare target'">; def err_omp_unknown_map_type : Error< "incorrect map type, expected one of 'to', 'from', 'tofrom', 'alloc', 'release', or 'delete'">; def err_omp_unknown_map_type_modifier : Error< Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -7659,6 +7659,8 @@ "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 %1">; +def err_omp_region_not_file_context : Error< + "directive must be at file or namespace scope">; 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< @@ -7716,6 +7718,8 @@ def err_omp_not_integral : Error< "expression must have integral or unscoped enumeration " "type, not %0">; +def err_omp_threadprivate_in_target : Error< + "threadprivate variables cannot be used in target constructs">; def err_omp_incomplete_type : Error< "expression has incomplete class type %0">; def err_omp_explicit_conversion : Error< @@ -7742,6 +7746,9 @@ def warn_omp_alignment_not_power_of_two : Warning< "aligned clause will be ignored because the requested alignment is not a power of 2">, InGroup; +def warn_omp_not_in_target_context : Warning< + "declaration is not declared in any declare target region">, + InGroup; def err_omp_aligned_expected_array_or_ptr : Error< "argument of aligned clause should be array" "%select{ or pointer|, pointer, reference to array or reference to pointer}1" Index: include/clang/Basic/OpenMPKinds.def =================================================================== --- include/clang/Basic/OpenMPKinds.def +++ include/clang/Basic/OpenMPKinds.def @@ -123,6 +123,8 @@ OPENMP_DIRECTIVE_EXT(cancellation_point, "cancellation point") OPENMP_DIRECTIVE(taskloop) OPENMP_DIRECTIVE_EXT(taskloop_simd, "taskloop simd") +OPENMP_DIRECTIVE_EXT(declare_target, "declare target") +OPENMP_DIRECTIVE_EXT(end_declare_target, "end declare target") // OpenMP clauses. OPENMP_CLAUSE(if, OMPIfClause) Index: include/clang/Parse/Parser.h =================================================================== --- include/clang/Parse/Parser.h +++ include/clang/Parse/Parser.h @@ -2426,7 +2426,7 @@ //===--------------------------------------------------------------------===// // OpenMP: Directives and clauses. /// \brief Parses declarative OpenMP directives. - DeclGroupPtrTy ParseOpenMPDeclarativeDirective(); + DeclGroupPtrTy ParseOpenMPDeclarativeDirective(AccessSpecifier AS); /// \brief Parses simple list of variables. /// /// \param Kind Kind of the directive. Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -145,6 +145,7 @@ class ObjCProtocolDecl; class OMPThreadPrivateDecl; class OMPClause; + class OMPDeclareTargetDecl; struct OverloadCandidate; class OverloadCandidateSet; class OverloadExpr; @@ -7814,6 +7815,13 @@ OMPThreadPrivateDecl *CheckOMPThreadPrivateDecl( SourceLocation Loc, ArrayRef VarList); + + bool ActOnStartOpenMPDeclareTargetDirective(Scope *S, SourceLocation Loc); + void ActOnOpenMPDeclareTargetDecls(DeclGroupPtrTy Decls); + DeclGroupPtrTy ActOnFinishOpenMPDeclareTargetDirective(); + void ActOnOpenMPDeclareTargetDirectiveError(); + void CheckDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D); + bool IsDeclContextInOpenMPTarget(DeclContext *DC); /// \brief Initialization of captured region for OpenMP region. void ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope); Index: include/clang/Serialization/ASTBitCodes.h =================================================================== --- include/clang/Serialization/ASTBitCodes.h +++ include/clang/Serialization/ASTBitCodes.h @@ -1152,6 +1152,8 @@ DECL_EMPTY, /// \brief An ObjCTypeParamDecl record. DECL_OBJC_TYPE_PARAM, + /// \brief An OMPDeclareTargetDecl record. + DECL_OMP_DECLARETARGET, }; /// \brief Record codes for each kind of statement or expression. Index: lib/AST/ASTContext.cpp =================================================================== --- lib/AST/ASTContext.cpp +++ lib/AST/ASTContext.cpp @@ -8400,7 +8400,7 @@ // We never need to emit an uninstantiated function template. if (FD->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate) return false; - } else if (isa(D)) + } else if (isa(D) || isa(D)) return true; else return false; Index: lib/AST/Decl.cpp =================================================================== --- lib/AST/Decl.cpp +++ lib/AST/Decl.cpp @@ -1813,12 +1813,12 @@ VarDecl::TLSKind VarDecl::getTLSKind() const { switch (VarDeclBits.TSCSpec) { case TSCS_unspecified: - if (!hasAttr() && - !(getASTContext().getLangOpts().OpenMPUseTLS && - getASTContext().getTargetInfo().isTLSSupported() && - hasAttr())) - return TLS_None; - return ((getASTContext().getLangOpts().isCompatibleWithMSVC( + if (!hasAttr() && + !(getASTContext().getLangOpts().OpenMPUseTLS && + getASTContext().getTargetInfo().isTLSSupported() && + hasAttr())) + return TLS_None; + return ((getASTContext().getLangOpts().isCompatibleWithMSVC( LangOptions::MSVC2015)) || hasAttr()) ? TLS_Dynamic @@ -2481,7 +2481,7 @@ getDeclName().getCXXOverloadedOperator() == OO_Array_New || getDeclName().getCXXOverloadedOperator() == OO_Array_Delete); - if (!getDeclContext()->getRedeclContext()->isTranslationUnit()) + if (!getDeclContext()->getRedeclContext()->isTranslationUnitOrDeclareTarget()) return false; const auto *proto = getType()->castAs(); @@ -2510,7 +2510,7 @@ return false; // This can only fail for an invalid 'operator new' declaration. - if (!getDeclContext()->getRedeclContext()->isTranslationUnit()) + if (!getDeclContext()->getRedeclContext()->isTranslationUnitOrDeclareTarget()) return false; const auto *FPT = getType()->castAs(); @@ -2745,7 +2745,7 @@ static bool RedeclForcesDefC99(const FunctionDecl *Redecl) { // Only consider file-scope declarations in this test. - if (!Redecl->getLexicalDeclContext()->isTranslationUnit()) + if (!Redecl->getLexicalDeclContext()->isTranslationUnitOrDeclareTarget()) return false; // Only consider explicit declarations; the presence of a builtin for a Index: lib/AST/DeclBase.cpp =================================================================== --- lib/AST/DeclBase.cpp +++ lib/AST/DeclBase.cpp @@ -198,7 +198,7 @@ const DeclContext *Decl::getParentFunctionOrMethod() const { for (const DeclContext *DC = getDeclContext(); - DC && !DC->isTranslationUnit() && !DC->isNamespace(); + DC && !DC->isTranslationUnitOrDeclareTarget() && !DC->isNamespace(); DC = DC->getParent()) if (DC->isFunctionOrMethod()) return DC; @@ -650,6 +650,7 @@ case ObjCCategoryImpl: case Import: case OMPThreadPrivate: + case OMPDeclareTarget: case Empty: // Never looked up by name. return 0; @@ -869,7 +870,7 @@ return ND->getParent()->isStdNamespace(); } - if (!getParent()->getRedeclContext()->isTranslationUnit()) + if (!getParent()->getRedeclContext()->isTranslationUnitOrDeclareTarget()) return false; const IdentifierInfo *II = ND->getIdentifier(); @@ -913,6 +914,8 @@ return !cast(this)->isScoped(); else if (DeclKind == Decl::LinkageSpec) return true; + else if (DeclKind == Decl::OMPDeclareTarget) + return true; return false; } @@ -952,6 +955,7 @@ case Decl::LinkageSpec: case Decl::Block: case Decl::Captured: + case Decl::OMPDeclareTarget: // There is only one DeclContext for these entities. return this; Index: lib/AST/DeclOpenMP.cpp =================================================================== --- lib/AST/DeclOpenMP.cpp +++ lib/AST/DeclOpenMP.cpp @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// /// \file -/// \brief This file implements OMPThreadPrivateDecl class. +/// \brief This file implements OMPThreadPrivateDecl, OMPDeclareTarget class. /// //===----------------------------------------------------------------------===// @@ -52,3 +52,24 @@ std::copy(VL.begin(), VL.end(), Vars); } + +//===----------------------------------------------------------------------===// +// OMPDeclareTargetDecl Implementation. +//===----------------------------------------------------------------------===// + +void OMPDeclareTargetDecl::anchor() {} + +OMPDeclareTargetDecl * +OMPDeclareTargetDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) { + OMPDeclareTargetDecl *D = + new (C, DC) OMPDeclareTargetDecl(OMPDeclareTarget, DC, L); + return D; +} + +OMPDeclareTargetDecl *OMPDeclareTargetDecl::CreateDeserialized(ASTContext &C, + unsigned ID) { + // Realign + OMPDeclareTargetDecl *D = + new (C, ID) OMPDeclareTargetDecl(OMPDeclareTarget, 0, SourceLocation()); + return D; +} \ No newline at end of file Index: lib/AST/DeclPrinter.cpp =================================================================== --- lib/AST/DeclPrinter.cpp +++ lib/AST/DeclPrinter.cpp @@ -92,6 +92,7 @@ void VisitUsingDecl(UsingDecl *D); void VisitUsingShadowDecl(UsingShadowDecl *D); void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D); + void VisitOMPDeclareTargetDecl(OMPDeclareTargetDecl *D); void PrintTemplateParameters(const TemplateParameterList *Params, const TemplateArgumentList *Args = nullptr); @@ -333,7 +334,7 @@ // FIXME: Need to be able to tell the DeclPrinter when const char *Terminator = nullptr; - if (isa(*D)) + if (isa(*D) || isa(*D)) Terminator = nullptr; else if (isa(*D) && cast(*D)->isThisDeclarationADefinition()) @@ -1305,6 +1306,12 @@ getAsString(Policy) << ' ' << *PDecl; if (Policy.PolishForDeclaration) Out << ';'; +} + +void DeclPrinter::VisitOMPDeclareTargetDecl(OMPDeclareTargetDecl *D) { + Out << "#pragma omp declare target\n"; + VisitDeclContext(D); + Out << "#pragma omp end declare target\n"; } void DeclPrinter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PID) { Index: lib/AST/ItaniumMangle.cpp =================================================================== --- lib/AST/ItaniumMangle.cpp +++ lib/AST/ItaniumMangle.cpp @@ -90,7 +90,7 @@ static const RecordDecl *GetLocalClassDecl(const Decl *D) { const DeclContext *DC = getEffectiveDeclContext(D); - while (!DC->isNamespace() && !DC->isTranslationUnit()) { + while (!DC->isNamespace() && !DC->isTranslationUnitOrDeclareTarget()) { if (isLocalContainerContext(DC)) return dyn_cast(D); D = cast(DC); @@ -444,9 +444,9 @@ const DeclContext *DC = getEffectiveDeclContext(D); // Check for extern variable declared locally. if (DC->isFunctionOrMethod() && D->hasLinkage()) - while (!DC->isNamespace() && !DC->isTranslationUnit()) + while (!DC->isNamespace() && !DC->isTranslationUnitOrDeclareTarget()) DC = getEffectiveParentContext(DC); - if (DC->isTranslationUnit() && D->getFormalLinkage() != InternalLinkage && + if (DC->isTranslationUnitOrDeclareTarget() && D->getFormalLinkage() != InternalLinkage && !isa(D)) return false; } @@ -537,7 +537,7 @@ /// Return whether a given namespace is the 'std' namespace. static bool isStd(const NamespaceDecl *NS) { if (!IgnoreLinkageSpecDecls(getEffectiveParentContext(NS)) - ->isTranslationUnit()) + ->isTranslationUnitOrDeclareTarget()) return false; const IdentifierInfo *II = NS->getOriginalNamespace()->getIdentifier(); @@ -593,7 +593,7 @@ // FIXME: This is a hack; extern variables declared locally should have // a proper semantic declaration context! if (isLocalContainerContext(DC) && ND->hasLinkage() && !isLambda(ND)) - while (!DC->isNamespace() && !DC->isTranslationUnit()) + while (!DC->isNamespace() && !DC->isTranslationUnitOrDeclareTarget()) DC = getEffectiveParentContext(DC); else if (GetLocalClassDecl(ND)) { mangleLocalName(ND); @@ -602,7 +602,7 @@ DC = IgnoreLinkageSpecDecls(DC); - if (DC->isTranslationUnit() || isStdNamespace(DC)) { + if (DC->isTranslationUnitOrDeclareTarget() || isStdNamespace(DC)) { // Check if we have a template. const TemplateArgumentList *TemplateArgs = nullptr; if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) { @@ -627,7 +627,7 @@ unsigned NumTemplateArgs) { const DeclContext *DC = IgnoreLinkageSpecDecls(getEffectiveDeclContext(TD)); - if (DC->isTranslationUnit() || isStdNamespace(DC)) { + if (DC->isTranslationUnitOrDeclareTarget() || isStdNamespace(DC)) { mangleUnscopedTemplateName(TD); mangleTemplateArgs(TemplateArgs, NumTemplateArgs); } else { @@ -1342,7 +1342,7 @@ DC = IgnoreLinkageSpecDecls(DC); - if (DC->isTranslationUnit()) + if (DC->isTranslationUnitOrDeclareTarget()) return; if (NoFunction && isLocalContainerContext(DC)) Index: lib/AST/MicrosoftMangle.cpp =================================================================== --- lib/AST/MicrosoftMangle.cpp +++ lib/AST/MicrosoftMangle.cpp @@ -361,10 +361,10 @@ const DeclContext *DC = getEffectiveDeclContext(D); // Check for extern variable declared locally. if (DC->isFunctionOrMethod() && D->hasLinkage()) - while (!DC->isNamespace() && !DC->isTranslationUnit()) + while (!DC->isNamespace() && !DC->isTranslationUnitOrDeclareTarget()) DC = getEffectiveParentContext(DC); - if (DC->isTranslationUnit() && D->getFormalLinkage() == InternalLinkage && + if (DC->isTranslationUnitOrDeclareTarget() && D->getFormalLinkage() == InternalLinkage && !isa(D) && D->getIdentifier() != nullptr) return false; @@ -864,7 +864,7 @@ // ::= [] const DeclContext *DC = getEffectiveDeclContext(ND); - while (!DC->isTranslationUnit()) { + while (!DC->isTranslationUnitOrDeclareTarget()) { if (isa(ND) || isa(ND)) { unsigned Disc; if (Context.getNextDiscriminator(ND, Disc)) { Index: lib/Basic/OpenMPKinds.cpp =================================================================== --- lib/Basic/OpenMPKinds.cpp +++ lib/Basic/OpenMPKinds.cpp @@ -432,6 +432,9 @@ break; } break; + // No clauses allowed for 'omp [end] declare target' constructs. + case OMPD_declare_target: + case OMPD_end_declare_target: case OMPD_unknown: case OMPD_threadprivate: case OMPD_section: Index: lib/CodeGen/CGDecl.cpp =================================================================== --- lib/CodeGen/CGDecl.cpp +++ lib/CodeGen/CGDecl.cpp @@ -21,6 +21,7 @@ #include "clang/AST/CharUnits.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclOpenMP.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" #include "clang/CodeGen/CGFunctionInfo.h" @@ -115,6 +116,9 @@ return EmitVarDecl(VD); } + case Decl::OMPDeclareTarget: + return CGM.EmitOMPDeclareTarget(cast(&D)); + case Decl::Typedef: // typedef int X; case Decl::TypeAlias: { // using X = int; [C++0x] const TypedefNameDecl &TD = cast(D); @@ -1861,3 +1865,18 @@ if (D.hasAttr()) EmitVarAnnotations(&D, DeclPtr.getPointer()); } + +void CodeGenModule::EmitOMPDeclareTarget(const OMPDeclareTargetDecl *D) { + + for (DeclContext::decl_iterator I = D->decls_begin(), E = D->decls_end(); + I != E; ++I) { + if (const VarDecl *VD = dyn_cast(*I)) + if (VD->getTemplateSpecializationKind() != TSK_ExplicitSpecialization && + VD->getTemplateSpecializationKind() != TSK_Undeclared) + continue; + + EmitTopLevelDecl(*I); + } + + +} \ No newline at end of file Index: lib/CodeGen/CodeGenModule.h =================================================================== --- lib/CodeGen/CodeGenModule.h +++ lib/CodeGen/CodeGenModule.h @@ -1097,6 +1097,10 @@ /// \param D Threadprivate declaration. void EmitOMPThreadPrivateDecl(const OMPThreadPrivateDecl *D); + /// \brief Emit declare target decls. + /// + void EmitOMPDeclareTarget(const OMPDeclareTargetDecl *D); + /// Returns whether the given record is blacklisted from control flow /// integrity checks. bool IsCFIBlacklistedRecord(const CXXRecordDecl *RD); Index: lib/CodeGen/CodeGenModule.cpp =================================================================== --- lib/CodeGen/CodeGenModule.cpp +++ lib/CodeGen/CodeGenModule.cpp @@ -3567,6 +3567,10 @@ break; } + case Decl::OMPDeclareTarget: + EmitOMPDeclareTarget(cast(D)); + break; + default: // Make sure we handled everything we should, every other kind is a // non-top-level decl. FIXME: Would be nice to have an isTopLevelDeclKind Index: lib/Parse/ParseDecl.cpp =================================================================== --- lib/Parse/ParseDecl.cpp +++ lib/Parse/ParseDecl.cpp @@ -3618,7 +3618,7 @@ if (Tok.is(tok::annot_pragma_openmp)) { // Result can be ignored, because it must be always empty. - auto Res = ParseOpenMPDeclarativeDirective(); + auto Res = ParseOpenMPDeclarativeDirective(AS_public); assert(!Res); // Silence possible warnings. (void)Res; Index: lib/Parse/ParseDeclCXX.cpp =================================================================== --- lib/Parse/ParseDeclCXX.cpp +++ lib/Parse/ParseDeclCXX.cpp @@ -2902,7 +2902,7 @@ } if (Tok.is(tok::annot_pragma_openmp)) - return ParseOpenMPDeclarativeDirective(); + return ParseOpenMPDeclarativeDirective(AS); // Parse all the comma separated declarators. return ParseCXXClassMemberDeclaration(AS, AccessAttrs.getList()); Index: lib/Parse/ParseOpenMP.cpp =================================================================== --- lib/Parse/ParseOpenMP.cpp +++ lib/Parse/ParseOpenMP.cpp @@ -32,13 +32,17 @@ // TODO: add other combined directives in topological order. const OpenMPDirectiveKind F[][3] = { {OMPD_unknown /*cancellation*/, OMPD_unknown /*point*/, - OMPD_cancellation_point}, - {OMPD_target, OMPD_unknown /*data*/, OMPD_target_data}, - {OMPD_for, OMPD_simd, OMPD_for_simd}, - {OMPD_parallel, OMPD_for, OMPD_parallel_for}, - {OMPD_parallel_for, OMPD_simd, OMPD_parallel_for_simd}, - {OMPD_parallel, OMPD_sections, OMPD_parallel_sections}, - {OMPD_taskloop, OMPD_simd, OMPD_taskloop_simd}}; + OMPD_cancellation_point}, //0 + {OMPD_unknown /*declare*/, OMPD_target /*target*/, + OMPD_declare_target }, //1 + {OMPD_unknown /*end*/, OMPD_unknown /*declare*/, + OMPD_end_declare_target }, //2 + {OMPD_target, OMPD_unknown /*data*/, OMPD_target_data}, //3 + {OMPD_for, OMPD_simd, OMPD_for_simd}, //4 + {OMPD_parallel, OMPD_for, OMPD_parallel_for}, //5 + {OMPD_parallel_for, OMPD_simd, OMPD_parallel_for_simd}, //6 + {OMPD_parallel, OMPD_sections, OMPD_parallel_sections}, //7 + {OMPD_taskloop, OMPD_simd, OMPD_taskloop_simd}}; //8 auto Tok = P.getCurToken(); auto DKind = Tok.isAnnotation() @@ -50,7 +54,13 @@ if (!Tok.isAnnotation() && DKind == OMPD_unknown) { TokenMatched = (i == 0) && - !P.getPreprocessor().getSpelling(Tok).compare("cancellation"); + !P.getPreprocessor().getSpelling(Tok).compare("cancellation") || + ((i == 1 || i == 3) && + !P.getPreprocessor().getSpelling(Tok).compare("declare")) || + ((i == 2) && + !P.getPreprocessor().getSpelling(Tok).compare("end")) || + ((i == 3) && + !P.getPreprocessor().getSpelling(Tok).compare("target")); } else { TokenMatched = DKind == F[i][0] && DKind != OMPD_unknown; } @@ -67,7 +77,10 @@ TokenMatched = ((i == 0) && !P.getPreprocessor().getSpelling(Tok).compare("point")) || - ((i == 1) && !P.getPreprocessor().getSpelling(Tok).compare("data")); + ((i == 2) && + !P.getPreprocessor().getSpelling(Tok).compare("declare")) || + ((i == 3) && + !P.getPreprocessor().getSpelling(Tok).compare("data")); } else { TokenMatched = SDKind == F[i][1] && SDKind != OMPD_unknown; } @@ -86,7 +99,7 @@ /// threadprivate-directive: /// annot_pragma_openmp 'threadprivate' simple-variable-list /// -Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() { +Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective(AccessSpecifier AS) { assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!"); ParenBraceBracketBalancer BalancerRAIIObj(*this); @@ -110,6 +123,59 @@ return Actions.ActOnOpenMPThreadprivateDirective(Loc, Identifiers); } break; + case OMPD_declare_target: { + SourceLocation DTLoc = ConsumeAnyToken(); + if (Tok.isNot(tok::annot_pragma_openmp_end)) { + Diag(Tok, diag::warn_omp_extra_tokens_at_eol) + << getOpenMPDirectiveName(OMPD_declare_target); + while (!SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch)) + ; + } + // Skip the last annot_pragma_openmp_end. + ConsumeAnyToken(); + + ParseScope OMPDeclareTargetScope(this, Scope::DeclScope); + if (!Actions.ActOnStartOpenMPDeclareTargetDirective(getCurScope(), DTLoc)) + return DeclGroupPtrTy(); + + DKind = ParseOpenMPDirectiveKind(*this); + while (DKind != OMPD_end_declare_target && DKind != OMPD_declare_target && + Tok.isNot(tok::eof)) { + ParsedAttributesWithRange attrs(AttrFactory); + MaybeParseCXX11Attributes(attrs); + MaybeParseMicrosoftAttributes(attrs); + Actions.ActOnOpenMPDeclareTargetDecls(ParseExternalDeclaration(attrs)); + if (Tok.isAnnotation() && Tok.is(tok::annot_pragma_openmp)) { + TentativeParsingAction TPA(*this); + ConsumeToken(); + DKind = ParseOpenMPDirectiveKind(*this); + if (DKind != OMPD_end_declare_target) { + TPA.Revert(); + } + else { + TPA.Commit(); + } + } + } + if (DKind == OMPD_end_declare_target) { + // Skip the last annot_pragma_openmp_end. + ConsumeAnyToken(); + ConsumeAnyToken(); + if (Tok.isNot(tok::annot_pragma_openmp_end)) { + Diag(Tok, diag::warn_omp_extra_tokens_at_eol) + << getOpenMPDirectiveName(OMPD_end_declare_target); + while (!SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch)) + ; + } + // Skip the last annot_pragma_openmp_end. + ConsumeAnyToken(); + return Actions.ActOnFinishOpenMPDeclareTargetDirective(); + } + Actions.ActOnOpenMPDeclareTargetDirectiveError(); + Diag(Tok, diag::err_expected_end_declare_target); + Diag(DTLoc, diag::note_matching) << "'#pragma omp declare target'"; + return DeclGroupPtrTy(); + } case OMPD_unknown: Diag(Tok, diag::err_omp_unknown_directive); break; @@ -140,11 +206,13 @@ case OMPD_target_data: case OMPD_taskloop: case OMPD_taskloop_simd: + case OMPD_end_declare_target: Diag(Tok, diag::err_omp_unexpected_directive) << getOpenMPDirectiveName(DKind); break; } - SkipUntil(tok::annot_pragma_openmp_end); + while (!SkipUntil(tok::annot_pragma_openmp_end)) + ; return DeclGroupPtrTy(); } @@ -312,11 +380,19 @@ OMPDirectiveScope.Exit(); break; } - case OMPD_unknown: - Diag(Tok, diag::err_omp_unknown_directive); - SkipUntil(tok::annot_pragma_openmp_end); + case OMPD_declare_target: + case OMPD_end_declare_target: + Diag(Tok, diag::err_omp_unexpected_directive) + << getOpenMPDirectiveName(DKind); + while (!SkipUntil(tok::annot_pragma_openmp_end)) + ; break; + case OMPD_unknown: + Diag(Tok, diag::err_omp_unknown_directive); + SkipUntil(tok::annot_pragma_openmp_end); + break; } + return Directive; } Index: lib/Parse/Parser.cpp =================================================================== --- lib/Parse/Parser.cpp +++ lib/Parse/Parser.cpp @@ -658,7 +658,7 @@ HandlePragmaOpenCLExtension(); return DeclGroupPtrTy(); case tok::annot_pragma_openmp: - return ParseOpenMPDeclarativeDirective(); + return ParseOpenMPDeclarativeDirective(/*AS=*/AS_none); case tok::annot_pragma_ms_pointers_to_members: HandlePragmaMSPointersToMembers(); return DeclGroupPtrTy(); @@ -1045,7 +1045,7 @@ !TemplateInfo.TemplateParams && (Tok.is(tok::l_brace) || Tok.is(tok::kw_try) || Tok.is(tok::colon)) && - Actions.CurContext->isTranslationUnit()) { + Actions.CurContext->isTranslationUnitOrDeclareTarget()) { ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope); Scope *ParentScope = getCurScope()->getParent(); Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -4873,8 +4873,8 @@ R->isFunctionType())) { IsLinkageLookup = true; CreateBuiltins = - CurContext->getEnclosingNamespaceContext()->isTranslationUnit(); - } else if (CurContext->getRedeclContext()->isTranslationUnit() && + CurContext->getEnclosingNamespaceContext()->isTranslationUnitOrDeclareTarget(); + } else if (CurContext->getRedeclContext()->isTranslationUnitOrDeclareTarget() && D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static) CreateBuiltins = true; @@ -4990,6 +4990,10 @@ CurContext->addHiddenDecl(New); } + if (IsDeclContextInOpenMPTarget(CurContext)) { + CheckDeclIsAllowedInOpenMPTarget(0, New); + } + return New; } @@ -5118,7 +5122,7 @@ void Sema::RegisterLocallyScopedExternCDecl(NamedDecl *ND, Scope *S) { if (!getLangOpts().CPlusPlus && - ND->getLexicalDeclContext()->getRedeclContext()->isTranslationUnit()) + ND->getLexicalDeclContext()->getRedeclContext()->isTranslationUnitOrDeclareTarget()) // Don't need to track declarations in the TU in C. return; @@ -5253,7 +5257,7 @@ // If this is the C FILE type, notify the AST context. if (IdentifierInfo *II = NewTD->getIdentifier()) if (!NewTD->isInvalidDecl() && - NewTD->getDeclContext()->getRedeclContext()->isTranslationUnit()) { + NewTD->getDeclContext()->getRedeclContext()->isTranslationUnitOrDeclareTarget()) { if (II->isStr("FILE")) Context.setFILEDecl(NewTD); else if (II->isStr("jmp_buf")) @@ -6454,7 +6458,7 @@ // In C, when declaring a global variable, look for a corresponding 'extern' // variable declared in function scope. We don't need this in C++, because // we find local extern decls in the surrounding file-scope DeclContext. - if (ND->getDeclContext()->getRedeclContext()->isTranslationUnit()) { + if (ND->getDeclContext()->getRedeclContext()->isTranslationUnitOrDeclareTarget()) { if (NamedDecl *Prev = S.findLocallyScopedExternCDecl(ND->getDeclName())) { Previous.clear(); Previous.addDecl(Prev); @@ -6466,7 +6470,7 @@ // A declaration in the translation unit can conflict with an extern "C" // declaration. - if (ND->getDeclContext()->getRedeclContext()->isTranslationUnit()) + if (ND->getDeclContext()->getRedeclContext()->isTranslationUnitOrDeclareTarget()) return checkGlobalOrExternCConflict(S, ND, /*IsGlobal*/true, Previous); // An extern "C" declaration can conflict with a declaration in the @@ -8244,7 +8248,7 @@ if (getLangOpts().CUDA) if (IdentifierInfo *II = NewFD->getIdentifier()) if (!NewFD->isInvalidDecl() && - NewFD->getDeclContext()->getRedeclContext()->isTranslationUnit()) { + NewFD->getDeclContext()->getRedeclContext()->isTranslationUnitOrDeclareTarget()) { if (II->isStr("cudaConfigureCall")) { if (!R->getAs()->getReturnType()->isScalarType()) Diag(NewFD->getLocation(), diag::err_config_scalar_return); @@ -11462,7 +11466,7 @@ if (!Name) return; if ((!getLangOpts().CPlusPlus && - FD->getDeclContext()->isTranslationUnit()) || + FD->getDeclContext()->isTranslationUnitOrDeclareTarget()) || (isa(FD->getDeclContext()) && cast(FD->getDeclContext())->getLanguage() == LinkageSpecDecl::lang_c)) { @@ -11737,7 +11741,7 @@ // translation unit scope, at which point we have a fully qualified NNS. SmallVector Namespaces; DeclContext *DC = ND->getDeclContext()->getRedeclContext(); - for (; !DC->isTranslationUnit(); DC = DC->getParent()) { + for (; !DC->isTranslationUnitOrDeclareTarget(); DC = DC->getParent()) { // This tag should be declared in a namespace, which can only be enclosed by // other namespaces. Bail if there's an anonymous namespace in the chain. NamespaceDecl *Namespace = dyn_cast(DC); @@ -11755,7 +11759,7 @@ // build an NNS. SmallString<64> Insertion; llvm::raw_svector_ostream OS(Insertion); - if (DC->isTranslationUnit()) + if (DC->isTranslationUnitOrDeclareTarget()) OS << "::"; std::reverse(Namespaces.begin(), Namespaces.end()); for (auto *II : Namespaces) @@ -12617,7 +12621,7 @@ // If this is the C FILE type, notify the AST context. if (IdentifierInfo *II = New->getIdentifier()) if (!New->isInvalidDecl() && - New->getDeclContext()->getRedeclContext()->isTranslationUnit() && + New->getDeclContext()->getRedeclContext()->isTranslationUnitOrDeclareTarget() && II->isStr("FILE")) Context.setFILEDecl(New); Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -13563,6 +13563,9 @@ static void MarkExprReferenced(Sema &SemaRef, SourceLocation Loc, Decl *D, Expr *E, bool OdrUse) { + if (SemaRef.IsDeclContextInOpenMPTarget(SemaRef.CurContext)) + SemaRef.CheckDeclIsAllowedInOpenMPTarget(E, D); + if (VarDecl *Var = dyn_cast(D)) { DoMarkVarDeclReferenced(SemaRef, Loc, Var, E); return; Index: lib/Sema/SemaLookup.cpp =================================================================== --- lib/Sema/SemaLookup.cpp +++ lib/Sema/SemaLookup.cpp @@ -828,7 +828,7 @@ } } - if (!Found && DC->isTranslationUnit() && LookupBuiltin(S, R)) + if (!Found && DC->isTranslationUnitOrDeclareTarget() && LookupBuiltin(S, R)) return true; if (R.getLookupName().getNameKind() Index: lib/Sema/SemaOpenMP.cpp =================================================================== --- lib/Sema/SemaOpenMP.cpp +++ lib/Sema/SemaOpenMP.cpp @@ -138,6 +138,13 @@ DSAVarData getDSA(StackTy::reverse_iterator Iter, VarDecl *D); + typedef llvm::DenseSet DeclaredTargetDeclsTy; + + DeclaredTargetDeclsTy DeclaredTargetDecls; + + OpenMPClauseKind getDSA(StackTy::reverse_iterator Iter, VarDecl *D, + OpenMPDirectiveKind &Kind, DeclRefExpr *&E); + /// \brief Checks if the variable is a local for OpenMP region. bool isOpenMPLocal(VarDecl *D, StackTy::reverse_iterator Iter); @@ -163,6 +170,8 @@ Stack.pop_back(); } + bool IsThreadprivate(VarDecl *D, DeclRefExpr *&E); + /// \brief If 'aligned' declaration for given variable \a D was not seen yet, /// add it and return NULL; otherwise return previous occurrence's expression /// for diagnostics. @@ -289,6 +298,10 @@ return Stack.back().CancelRegion; } + void addDeclareTargetDecl(Decl *D) { DeclaredTargetDecls.insert(D); } + + bool isDeclareTargetDecl(Decl *D) { return DeclaredTargetDecls.count(D); } + /// \brief Set collapse value for the region. void setCollapseNumber(unsigned Val) { Stack.back().CollapseNumber = Val; } /// \brief Return collapse value for region. @@ -536,9 +549,27 @@ bool RefersToCapture = false) { D->setReferenced(); D->markUsed(S.Context); - return DeclRefExpr::Create(S.getASTContext(), NestedNameSpecifierLoc(), + DeclRefExpr *E; + + E = DeclRefExpr::Create(S.getASTContext(), NestedNameSpecifierLoc(), SourceLocation(), D, RefersToCapture, Loc, Ty, VK_LValue); + + if (S.IsDeclContextInOpenMPTarget(S.CurContext)) { + S.CheckDeclIsAllowedInOpenMPTarget(E, E->getDecl()); + } + return E; +} + +bool DSAStackTy::IsThreadprivate(VarDecl *D, DeclRefExpr *&E) { + E = 0; + if (D->getTLSKind() != VarDecl::TLS_None) + return true; + if (Stack[0].SharingMap.count(D)) { + E = Stack[0].SharingMap[D].RefExpr; + return true; + } + return false; } DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D, bool FromParent) { @@ -742,6 +773,13 @@ VarDataSharingAttributesStack = new DSAStackTy(*this); } +bool Sema::IsDeclContextInOpenMPTarget(DeclContext *DC) { + while (DC && !isa(DC)) { + DC = DC->getParent(); + } + return DC != 0; +} + #define DSAStack static_cast(VarDataSharingAttributesStack) bool Sema::IsOpenMPCapturedByRef(VarDecl *VD, @@ -1036,8 +1074,10 @@ // OpenMP [2.9.2, Restrictions, C/C++, p.2] // A threadprivate directive for file-scope variables must appear outside // any definition or declaration. - if (CanonicalVD->getDeclContext()->isTranslationUnit() && - !getCurLexicalContext()->isTranslationUnit()) { + + if ((!getCurLexicalContext()->isFileContext() || + !VD->getDeclContext()->isFileContext()) && + !isDeclInScope(ND, getCurLexicalContext(), getCurScope())) { Diag(Id.getLoc(), diag::err_omp_var_scope) << getOpenMPDirectiveName(OMPD_threadprivate) << VD; bool IsDecl = @@ -1223,6 +1263,210 @@ return D; } +bool Sema::ActOnStartOpenMPDeclareTargetDirective(Scope *S, + SourceLocation Loc) { + if (CurContext && !CurContext->isFileContext() && + !CurContext->isExternCContext() && !CurContext->isExternCXXContext()) { + Diag(Loc, diag::err_omp_region_not_file_context); + return false; + } + OMPDeclareTargetDecl *DT = + OMPDeclareTargetDecl::Create(Context, CurContext, Loc); + DT->setAccess(AS_public); + CurContext->addDecl(DT); + if (CurScope) + PushDeclContext(S, DT); + else + CurContext = DT; + return true; +} + +void Sema::ActOnOpenMPDeclareTargetDecls(Sema::DeclGroupPtrTy Decls) { + if (!Decls) + return; + DeclGroupRef DGR = Decls.get(); + if (DGR.isNull()) + return; + for (DeclGroupRef::iterator I = DGR.begin(), E = DGR.end(); I != E; ++I) { + if (*I) + DSAStack->addDeclareTargetDecl(*I); + } +} + +Sema::DeclGroupPtrTy Sema::ActOnFinishOpenMPDeclareTargetDirective() { + if (CurContext && isa(CurContext)) { + OMPDeclareTargetDecl *DT = cast(CurContext); + PopDeclContext(); + return DeclGroupPtrTy::make(DeclGroupRef(DT)); + } + return DeclGroupPtrTy(); +} + +void Sema::ActOnOpenMPDeclareTargetDirectiveError() { + if (CurContext && isa(CurContext)) { + PopDeclContext(); + } +} + +static bool IsCXXRecordForMappable(Sema &SemaRef, SourceLocation Loc, + DSAStackTy *Stack, CXXRecordDecl *RD) { + if (!RD || RD->isInvalidDecl()) + return true; + + auto QTy = SemaRef.Context.getRecordType(RD); + if (RD->isDynamicClass()) { + SemaRef.Diag(Loc, diag::err_omp_not_mappable_type) << QTy; + SemaRef.Diag(RD->getLocation(), diag::note_omp_polymorphic_in_target); + return false; + } + auto *DC = RD; + bool IsCorrect = true; + for (auto *I : DC->decls()) { + if (I) { + if (auto *MD = dyn_cast(I)) { + if (MD->isStatic()) { + SemaRef.Diag(Loc, diag::err_omp_not_mappable_type) << QTy; + SemaRef.Diag(MD->getLocation(), + diag::note_omp_static_member_in_target); + IsCorrect = false; + } + } else if (auto *VD = dyn_cast(I)) { + if (VD->isStaticDataMember()) { + SemaRef.Diag(Loc, diag::err_omp_not_mappable_type) << QTy; + SemaRef.Diag(VD->getLocation(), + diag::note_omp_static_member_in_target); + IsCorrect = false; + } + } + } + } + + for (auto &I : RD->bases()) { + if (!IsCXXRecordForMappable(SemaRef, I.getLocStart(), Stack, + I.getType()->getAsCXXRecordDecl())) + IsCorrect = false; + } + return IsCorrect; +} + +static void CheckDeclInTargetContext(SourceLocation SL, SourceRange SR, + Sema &SemaRef, DSAStackTy *Stack, + Decl *D) { + if (!D) + return; + Decl *LD = 0; + if (isa(D)) { + LD = cast(D)->getDefinition(); + } + else if (isa(D)) { + LD = cast(D)->getDefinition(); + + // If this is an implicit variable that is legal and we do not need to do + // anything + if (cast(D)->isImplicit()) { + Stack->addDeclareTargetDecl(D); + return; + } + + } + else if (isa(D)) { + const FunctionDecl *FD = 0; + if (cast(D)->hasBody(FD)) + LD = const_cast(FD); + + // If the definition is associated with the current declaration in the + // target region (it can be e.g. a lambda) that is legal and we do not need + // to do anything else + if (LD == D) { + Stack->addDeclareTargetDecl(D); + return; + } + } + if (!LD) + LD = D; + if (LD) { + if (!Stack->isDeclareTargetDecl(LD)) { + // Outlined declaration is not declared target. + if (LD->isOutOfLine()) { + SemaRef.Diag(LD->getLocation(), diag::warn_omp_not_in_target_context); + SemaRef.Diag(SL, diag::note_used_here) << SR; + } + else { + DeclContext *DC = LD->getDeclContext(); + while (DC) { + if (isa(DC)) + break; + DC = DC->getParent(); + } + // Is not declared in target context. + if (!DC) { + SemaRef.Diag(LD->getLocation(), diag::warn_omp_not_in_target_context); + SemaRef.Diag(SL, diag::note_used_here) << SR; + } + } + } + // Mark decl as declared to prevent further diagnostic. + if (isa(LD) || isa(LD)) + Stack->addDeclareTargetDecl(LD); + } +} + +static bool CheckTypeMappable(SourceLocation SL, SourceRange SR, Sema &SemaRef, + DSAStackTy *Stack, QualType QTy) { + NamedDecl *ND; + if (QTy->isIncompleteType(&ND)) { + SemaRef.Diag(SL, diag::err_incomplete_type) << QTy << SR; + return false; + } else if (CXXRecordDecl *RD = dyn_cast_or_null(ND)) { + if (!RD->isInvalidDecl() && + !IsCXXRecordForMappable(SemaRef, SL, Stack, RD)) + return false; + } + return true; +} + +static bool CheckValueDeclInTarget(SourceLocation SL, SourceRange SR, + Sema &SemaRef, DSAStackTy *Stack, + ValueDecl *VD) { + if (Stack->isDeclareTargetDecl(VD)) + return true; + if (!CheckTypeMappable(SL, SR, SemaRef, Stack, VD->getType())) { + return false; + } + return true; +} + +void Sema::CheckDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D) { + if (!D || D->isInvalidDecl()) + return; + SourceRange SR = E ? E->getSourceRange() : D->getSourceRange(); + SourceLocation SL = E ? E->getLocStart() : D->getLocation(); + if (VarDecl *VD = dyn_cast(D)) { + DeclRefExpr *DRE; + if (DSAStack->IsThreadprivate(VD, DRE)) { + SourceLocation Loc = DRE ? DRE->getLocation() : VD->getLocation(); + Diag(Loc, diag::err_omp_threadprivate_in_target); + Diag(SL, diag::note_used_here) << SR; + D->setInvalidDecl(); + return; + } + } + if (ValueDecl *VD = dyn_cast(D)) { + if (!CheckValueDeclInTarget(SL, SR, *this, DSAStack, VD)) { + VD->setInvalidDecl(); + return; + } + } + if (!E) { + // Checking declaration. + if (isa(D) || isa(D)) + DSAStack->addDeclareTargetDecl(D); + return; + } + CheckDeclInTargetContext(E->getExprLoc(), E->getSourceRange(), *this, + DSAStack, D); +} + static void ReportOriginalDSA(Sema &SemaRef, DSAStackTy *Stack, const VarDecl *VD, DSAStackTy::DSAVarData DVar, bool IsLoopIterVar = false) { @@ -7771,61 +8015,6 @@ return nullptr; return new (Context) OMPDeviceClause(ValExpr, StartLoc, LParenLoc, EndLoc); -} - -static bool IsCXXRecordForMappable(Sema &SemaRef, SourceLocation Loc, - DSAStackTy *Stack, CXXRecordDecl *RD) { - if (!RD || RD->isInvalidDecl()) - return true; - - auto QTy = SemaRef.Context.getRecordType(RD); - if (RD->isDynamicClass()) { - SemaRef.Diag(Loc, diag::err_omp_not_mappable_type) << QTy; - SemaRef.Diag(RD->getLocation(), diag::note_omp_polymorphic_in_target); - return false; - } - auto *DC = RD; - bool IsCorrect = true; - for (auto *I : DC->decls()) { - if (I) { - if (auto *MD = dyn_cast(I)) { - if (MD->isStatic()) { - SemaRef.Diag(Loc, diag::err_omp_not_mappable_type) << QTy; - SemaRef.Diag(MD->getLocation(), - diag::note_omp_static_member_in_target); - IsCorrect = false; - } - } else if (auto *VD = dyn_cast(I)) { - if (VD->isStaticDataMember()) { - SemaRef.Diag(Loc, diag::err_omp_not_mappable_type) << QTy; - SemaRef.Diag(VD->getLocation(), - diag::note_omp_static_member_in_target); - IsCorrect = false; - } - } - } - } - - for (auto &I : RD->bases()) { - if (!IsCXXRecordForMappable(SemaRef, I.getLocStart(), Stack, - I.getType()->getAsCXXRecordDecl())) - IsCorrect = false; - } - return IsCorrect; -} - -static bool CheckTypeMappable(SourceLocation SL, SourceRange SR, Sema &SemaRef, - DSAStackTy *Stack, QualType QTy) { - NamedDecl *ND; - if (QTy->isIncompleteType(&ND)) { - SemaRef.Diag(SL, diag::err_incomplete_type) << QTy << SR; - return false; - } else if (CXXRecordDecl *RD = dyn_cast_or_null(ND)) { - if (!RD->isInvalidDecl() && - !IsCXXRecordForMappable(SemaRef, SL, Stack, RD)) - return false; - } - return true; } OMPClause *Sema::ActOnOpenMPMapClause( Index: lib/Sema/SemaTemplateInstantiate.cpp =================================================================== --- lib/Sema/SemaTemplateInstantiate.cpp +++ lib/Sema/SemaTemplateInstantiate.cpp @@ -96,7 +96,7 @@ // that will own this template template parameter. In this case, we // use empty template parameter lists for all of the outer templates // to avoid performing any substitutions. - if (Ctx->isTranslationUnit()) { + if (Ctx->isTranslationUnitOrDeclareTarget()) { if (TemplateTemplateParmDecl *TTP = dyn_cast(D)) { for (unsigned I = 0, N = TTP->getDepth() + 1; I != N; ++I) Index: lib/Sema/SemaTemplateInstantiateDecl.cpp =================================================================== --- lib/Sema/SemaTemplateInstantiateDecl.cpp +++ lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -2477,6 +2477,11 @@ return TD; } +Decl * +TemplateDeclInstantiator::VisitOMPDeclareTargetDecl(OMPDeclareTargetDecl *D) { + llvm_unreachable("OpenMP declare target cannot be instantiated"); +} + Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D) { return VisitFunctionDecl(D, nullptr); } Index: lib/Serialization/ASTCommon.h =================================================================== --- lib/Serialization/ASTCommon.h +++ lib/Serialization/ASTCommon.h @@ -36,6 +36,7 @@ UPD_MANGLING_NUMBER, UPD_STATIC_LOCAL_NUMBER, UPD_DECL_MARKED_OPENMP_THREADPRIVATE, + UPD_DECL_MARKED_OPENMP_DECLARETARGET, UPD_DECL_EXPORTED, UPD_ADDED_ATTR_TO_RECORD }; Index: lib/Serialization/ASTCommon.cpp =================================================================== --- lib/Serialization/ASTCommon.cpp +++ lib/Serialization/ASTCommon.cpp @@ -329,6 +329,7 @@ case Decl::ClassScopeFunctionSpecialization: case Decl::Import: case Decl::OMPThreadPrivate: + case Decl::OMPDeclareTarget: case Decl::BuiltinTemplate: return false; Index: lib/Serialization/ASTReaderDecl.cpp =================================================================== --- lib/Serialization/ASTReaderDecl.cpp +++ lib/Serialization/ASTReaderDecl.cpp @@ -350,6 +350,7 @@ void VisitObjCPropertyDecl(ObjCPropertyDecl *D); void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D); void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D); + void VisitOMPDeclareTargetDecl(OMPDeclareTargetDecl *D); /// We've merged the definition \p MergedDef into the existing definition /// \p Def. Ensure that \p Def is made visible whenever \p MergedDef is made @@ -2353,6 +2354,10 @@ D->setVars(Vars); } +void ASTDeclReader::VisitOMPDeclareTargetDecl(OMPDeclareTargetDecl *D) { + VisitDecl(D); +} + //===----------------------------------------------------------------------===// // Attribute Reading //===----------------------------------------------------------------------===// @@ -2402,7 +2407,8 @@ isa(D) || isa(D) || isa(D) || - isa(D)) + isa(D) || + isa(D) ) return true; if (VarDecl *Var = dyn_cast(D)) return Var->isFileVarDecl() && @@ -2721,7 +2727,7 @@ if (needsAnonymousDeclarationNumber(New)) { setAnonymousDeclForMerging(Reader, New->getLexicalDeclContext(), AnonymousDeclNumber, New); - } else if (DC->isTranslationUnit() && Reader.SemaObj && + } else if (DC->isTranslationUnitOrDeclareTarget() && Reader.SemaObj && !Reader.getContext().getLangOpts().CPlusPlus) { if (Reader.SemaObj->IdResolver.tryAddTopLevelDecl(New, Name)) Reader.PendingFakeLookupResults[Name.getAsIdentifierInfo()] @@ -2826,7 +2832,7 @@ if (isSameEntity(Existing, D)) return FindExistingResult(Reader, D, Existing, AnonymousDeclNumber, TypedefNameForLinkage); - } else if (DC->isTranslationUnit() && Reader.SemaObj && + } else if (DC->isTranslationUnitOrDeclareTarget() && Reader.SemaObj && !Reader.getContext().getLangOpts().CPlusPlus) { IdentifierResolver &IdResolver = Reader.SemaObj->IdResolver; @@ -3298,6 +3304,9 @@ case DECL_OMP_THREADPRIVATE: D = OMPThreadPrivateDecl::CreateDeserialized(Context, ID, Record[Idx++]); break; + case DECL_OMP_DECLARETARGET: + D = OMPDeclareTargetDecl::CreateDeserialized(Context, ID); + break; case DECL_EMPTY: D = EmptyDecl::CreateDeserialized(Context, ID); break; @@ -3770,6 +3779,11 @@ case UPD_DECL_MARKED_OPENMP_THREADPRIVATE: D->addAttr(OMPThreadPrivateDeclAttr::CreateImplicit( + Reader.Context, ReadSourceRange(Record, Idx))); + break; + + case UPD_DECL_MARKED_OPENMP_DECLARETARGET: + D->addAttr(OMPDeclareTargetDeclAttr::CreateImplicit( Reader.Context, ReadSourceRange(Record, Idx))); break; Index: lib/Serialization/ASTWriter.cpp =================================================================== --- lib/Serialization/ASTWriter.cpp +++ lib/Serialization/ASTWriter.cpp @@ -4697,6 +4697,11 @@ Record); break; + case UPD_DECL_MARKED_OPENMP_DECLARETARGET: + AddSourceRange(D->getAttr()->getRange(), + Record); + break; + case UPD_DECL_EXPORTED: Record.push_back(getSubmoduleID(Update.getModule())); break; Index: lib/Serialization/ASTWriterDecl.cpp =================================================================== --- lib/Serialization/ASTWriterDecl.cpp +++ lib/Serialization/ASTWriterDecl.cpp @@ -131,6 +131,7 @@ void VisitObjCPropertyDecl(ObjCPropertyDecl *D); void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D); void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D); + void VisitOMPDeclareTargetDecl(OMPDeclareTargetDecl *D); /// Add an Objective-C type parameter list to the given record. void AddObjCTypeParamList(ObjCTypeParamList *typeParams) { @@ -1617,6 +1618,11 @@ Code = serialization::DECL_OMP_THREADPRIVATE; } +void ASTDeclWriter::VisitOMPDeclareTargetDecl(OMPDeclareTargetDecl *D) { + VisitDecl(D); + Code = serialization::DECL_OMP_DECLARETARGET; +} + //===----------------------------------------------------------------------===// // ASTWriter Implementation //===----------------------------------------------------------------------===// @@ -2071,8 +2077,8 @@ // An ObjCMethodDecl is never considered as "required" because its // implementation container always is. - // File scoped assembly or obj-c implementation must be seen. - if (isa(D) || isa(D)) + // File scoped assembly or obj-c or OMP Declare target implementation must be seen. + if (isa(D) || isa(D) || isa(D)) return true; // ImportDecl is used by codegen to determine the set of imported modules to Index: test/OpenMP/declare_target_ast_print.cpp =================================================================== --- test/OpenMP/declare_target_ast_print.cpp +++ test/OpenMP/declare_target_ast_print.cpp @@ -0,0 +1,47 @@ +// 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 + +#pragma omp declare target +// CHECK: #pragma omp declare target + +void foo() {} +// CHECK-NEXT: void foo() + +#pragma omp end declare target +// CHECK: #pragma omp end declare target + +extern "C" { +#pragma omp declare target +// CHECK: #pragma omp declare target + +void foo_c() {} +// CHECK-NEXT: void foo_c() + +#pragma omp end declare target +// CHECK: #pragma omp end declare target +} + +extern "C++" { +#pragma omp declare target +// CHECK: #pragma omp declare target + +void foo_cpp() {} +// CHECK-NEXT: void foo_cpp() + +#pragma omp end declare target +// CHECK: #pragma omp end declare target +} + +int main (int argc, char **argv) { + foo(); + foo_c(); + foo_cpp(); + return (0); +} + +#endif Index: test/OpenMP/declare_target_messages.cpp =================================================================== --- test/OpenMP/declare_target_messages.cpp +++ test/OpenMP/declare_target_messages.cpp @@ -0,0 +1,83 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macos10.7.0 -verify -fopenmp -fnoopenmp-use-tls -ferror-limit 100 -o - %s + +#pragma omp end declare target // expected-error {{unexpected OpenMP directive '#pragma omp end declare target'}} + +int a, b; // expected-warning 2 {{declaration is not declared in any declare target region}} +__thread int t; // expected-error {{threadprivate variables cannot be used in target constructs}} +#pragma omp declare target private(a) // expected-warning {{extra tokens at the end of '#pragma omp declare target' are ignored}} +void f(); +#pragma omp end declare target shared(a) // expected-warning {{extra tokens at the end of '#pragma omp end declare target' are ignored}} +void c(); // expected-warning {{declaration is not declared in any declare target region}} + +extern int b; + +struct NonT { + int a; +}; + +typedef int sint; + +#pragma omp declare target // expected-note {{to match this '#pragma omp declare target'}} +#pragma omp threadprivate(a) // expected-error {{threadprivate variables cannot be used in target constructs}} expected-note {{used here}} +extern int b; +int g; + +struct T { // expected-note {{mappable type cannot be polymorphic}} + int a; + virtual int method(); +}; + +class VC { // expected-note {{mappable type cannot be polymorphic}} + T member; + NonT member1; + public: + virtual int method() { T a; return 0; } // expected-error {{type 'T' is not mappable to target}} +}; + +struct C { + NonT a; + sint b; + int method(); + int method1(); +}; + +int C::method1() { + return 0; +} + +void foo() { + a = 0; // expected-note {{used here}} + b = 0; // expected-note {{used here}} + t = 1; // expected-note {{used here}} + C object; + VC object1; // expected-error {{type 'VC' is not mappable to target}} + g = object.method(); + g += object.method1(); + g += object1.method(); + f(); + c(); // expected-note {{used here}} +} +#pragma omp declare target // expected-error {{expected '#pragma omp end declare target'}} +void foo1() {} +#pragma omp end declare target +#pragma omp end declare target // expected-error {{unexpected OpenMP directive '#pragma omp end declare target'}} + +int C::method() { + return 0; +} + +struct S { +#pragma omp declare target // expected-error {{directive must be at file or namespace scope}} + int v; +#pragma omp end declare target // expected-error {{unexpected OpenMP directive '#pragma omp end declare target'}} +}; + +int main (int argc, char **argv) { +#pragma omp declare target // expected-error {{unexpected OpenMP directive '#pragma omp declare target'}} + int v; +#pragma omp end declare target // expected-error {{unexpected OpenMP directive '#pragma omp end declare target'}} + foo(); + return (0); +} + +#pragma omp declare target // expected-error {{expected '#pragma omp end declare target'}} expected-note {{to match this '#pragma omp declare target'}} Index: tools/libclang/CIndex.cpp =================================================================== --- tools/libclang/CIndex.cpp +++ tools/libclang/CIndex.cpp @@ -5228,6 +5228,7 @@ case Decl::ClassScopeFunctionSpecialization: case Decl::Import: case Decl::OMPThreadPrivate: + case Decl::OMPDeclareTarget: case Decl::ObjCTypeParam: case Decl::BuiltinTemplate: return C;