Index: include/clang/AST/ASTMutationListener.h =================================================================== --- include/clang/AST/ASTMutationListener.h +++ include/clang/AST/ASTMutationListener.h @@ -107,6 +107,12 @@ /// \param D the declaration marked OpenMP threadprivate. virtual void DeclarationMarkedOpenMPThreadPrivate(const Decl *D) {} + /// \brief A declaration is marked as OpenMP declaretarget which was not + /// previously marked as declaretarget. + /// + /// \param D the declaration marked OpenMP declaretarget. + virtual void DeclarationMarkedOpenMPDeclareTarget(const Decl *D) {} + /// \brief A definition has been made visible by being redefined locally. /// /// \param D The definition that was previously not visible. Index: include/clang/Basic/Attr.td =================================================================== --- include/clang/Basic/Attr.td +++ include/clang/Basic/Attr.td @@ -2276,6 +2276,15 @@ }]; } +def OMPDeclareTargetDecl : Attr { + let Spellings = [Pragma<"omp", "declare target">]; + let SemaHandler = 0; + let Documentation = [OMPDeclareTargetDocs]; + let AdditionalMembers = [{ + void printPrettyPragma(raw_ostream &OS, const PrintingPolicy &Policy) const {} + }]; +} + def InternalLinkage : InheritableAttr { let Spellings = [GNU<"internal_linkage">, CXX11<"clang", "internal_linkage">]; let Subjects = SubjectList<[Var, Function, CXXRecord]>; Index: include/clang/Basic/AttrDocs.td =================================================================== --- include/clang/Basic/AttrDocs.td +++ include/clang/Basic/AttrDocs.td @@ -1941,6 +1941,23 @@ }]; } +def OMPDeclareTargetDocs : Documentation { + let Category = DocCatFunction; + let Heading = "#pragma omp declare target"; + let Content = [{ +The `declare target` directive specifies that variables and functions are mapped +to a device for OpenMP offload mechanism. + +The syntax of the declare target directive is as follows: + + .. code-block:: c + + #pragma omp declare target new-line + declarations-definition-seq + #pragma omp end declare target new-line + }]; +} + def NotTailCalledDocs : Documentation { let Category = DocCatFunction; let Content = [{ Index: include/clang/Basic/DiagnosticGroups.td =================================================================== --- include/clang/Basic/DiagnosticGroups.td +++ include/clang/Basic/DiagnosticGroups.td @@ -819,6 +819,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 @@ -963,6 +963,8 @@ "missing map type">; def err_omp_declare_simd_inbranch_notinbranch : Error< "unexpected '%0' clause, '%1' is specified already">; +def err_expected_end_declare_target : Error< + "expected '#pragma omp end declare target'">; // Pragma loop support. def err_pragma_loop_missing_argument : Error< Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -7828,6 +7828,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< @@ -7903,6 +7905,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< @@ -7929,6 +7933,11 @@ 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 err_omp_enclosed_declare_target : Error< + "declare target region may not be enclosed within another declare target region">; +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 @@ -160,6 +160,8 @@ OPENMP_DIRECTIVE(taskloop) OPENMP_DIRECTIVE_EXT(taskloop_simd, "taskloop simd") OPENMP_DIRECTIVE(distribute) +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/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -7828,6 +7828,8 @@ // private: void *VarDataSharingAttributesStack; + /// Set to true inside '#pragma omp declare target' region. + bool IsInOpenMPDeclareTargetContext = false; /// \brief Initialization of data-sharing attributes stack. void InitDataSharingAttributesStack(); void DestroyDataSharingAttributesStack(); @@ -7913,6 +7915,17 @@ DeclGroupPtrTy ActOnOpenMPDeclareReductionDirectiveEnd( Scope *S, DeclGroupPtrTy DeclReductions, bool IsValid); + /// Called on the start of target region i.e. '#pragma omp declare target'. + bool ActOnStartOpenMPDeclareTargetDirective(SourceLocation Loc); + /// Called at the end of target region i.e. '#pragme omp end declare target'. + void ActOnFinishOpenMPDeclareTargetDirective(); + /// Check declaration inside target region. + void checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D); + /// Return true inside OpenMP target region. + bool isInOpenMPDeclareTargetContext() const { + return IsInOpenMPDeclareTargetContext; + } + /// \brief Initialization of captured region for OpenMP region. void ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope); /// \brief End of OpenMP region. Index: include/clang/Serialization/ASTWriter.h =================================================================== --- include/clang/Serialization/ASTWriter.h +++ include/clang/Serialization/ASTWriter.h @@ -861,6 +861,7 @@ const ObjCInterfaceDecl *IFD) override; void DeclarationMarkedUsed(const Decl *D) override; void DeclarationMarkedOpenMPThreadPrivate(const Decl *D) override; + void DeclarationMarkedOpenMPDeclareTarget(const Decl *D) override; void RedefinedHiddenDefinition(const NamedDecl *D, Module *M) override; void AddedAttributeToRecord(const Attr *Attr, const RecordDecl *Record) override; Index: lib/AST/ASTContext.cpp =================================================================== --- lib/AST/ASTContext.cpp +++ lib/AST/ASTContext.cpp @@ -8528,6 +8528,9 @@ return false; } else if (isa(D)) return true; + else if (isa(D) || + D->hasAttr()) + return true; else if (isa(D)) return true; else if (isa(D)) Index: lib/AST/DeclPrinter.cpp =================================================================== --- lib/AST/DeclPrinter.cpp +++ lib/AST/DeclPrinter.cpp @@ -358,6 +358,11 @@ if (Terminator) Out << Terminator; Out << "\n"; + + // Declare target attribute is special one, natural spelling for the pragma + // assumes "ending" construct so print it here. + if (D->hasAttr()) + Out << "#pragma omp end declare target\n"; } if (!Decls.empty()) Index: lib/Basic/OpenMPKinds.cpp =================================================================== --- lib/Basic/OpenMPKinds.cpp +++ lib/Basic/OpenMPKinds.cpp @@ -547,6 +547,8 @@ break; } break; + case OMPD_declare_target: + case OMPD_end_declare_target: case OMPD_unknown: case OMPD_threadprivate: case OMPD_section: Index: lib/Frontend/MultiplexConsumer.cpp =================================================================== --- lib/Frontend/MultiplexConsumer.cpp +++ lib/Frontend/MultiplexConsumer.cpp @@ -125,6 +125,7 @@ void FunctionDefinitionInstantiated(const FunctionDecl *D) override; void DeclarationMarkedUsed(const Decl *D) override; void DeclarationMarkedOpenMPThreadPrivate(const Decl *D) override; + void DeclarationMarkedOpenMPDeclareTarget(const Decl *D) override; void RedefinedHiddenDefinition(const NamedDecl *D, Module *M) override; void AddedAttributeToRecord(const Attr *Attr, const RecordDecl *Record) override; @@ -219,6 +220,11 @@ for (size_t i = 0, e = Listeners.size(); i != e; ++i) Listeners[i]->DeclarationMarkedOpenMPThreadPrivate(D); } +void MultiplexASTMutationListener::DeclarationMarkedOpenMPDeclareTarget( + const Decl *D) { + for (auto *L : Listeners) + L->DeclarationMarkedOpenMPDeclareTarget(D); +} void MultiplexASTMutationListener::RedefinedHiddenDefinition(const NamedDecl *D, Module *M) { for (auto *L : Listeners) Index: lib/Parse/ParseOpenMP.cpp =================================================================== --- lib/Parse/ParseOpenMP.cpp +++ lib/Parse/ParseOpenMP.cpp @@ -31,6 +31,8 @@ OMPD_cancellation = OMPD_unknown + 1, OMPD_data, OMPD_declare, + OMPD_end, + OMPD_end_declare, OMPD_enter, OMPD_exit, OMPD_point, @@ -51,6 +53,7 @@ .Case("cancellation", OMPD_cancellation) .Case("data", OMPD_data) .Case("declare", OMPD_declare) + .Case("end", OMPD_end) .Case("enter", OMPD_enter) .Case("exit", OMPD_exit) .Case("point", OMPD_point) @@ -66,6 +69,9 @@ { OMPD_cancellation, OMPD_point, OMPD_cancellation_point }, { OMPD_declare, OMPD_reduction, OMPD_declare_reduction }, { OMPD_declare, OMPD_simd, OMPD_declare_simd }, + { OMPD_declare, OMPD_target, OMPD_declare_target }, + { OMPD_end, OMPD_declare, OMPD_end_declare }, + { OMPD_end_declare, OMPD_target, OMPD_end_declare_target }, { OMPD_target, OMPD_data, OMPD_target_data }, { OMPD_target, OMPD_enter, OMPD_target_enter }, { OMPD_target, OMPD_exit, OMPD_target_exit }, @@ -456,6 +462,53 @@ return Actions.ActOnOpenMPDeclareSimdDirective(Ptr, BS, SourceRange(Loc, EndLoc)); } + 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); + SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); + } + // Skip the last annot_pragma_openmp_end. + ConsumeAnyToken(); + + if (!Actions.ActOnStartOpenMPDeclareTargetDirective(DTLoc)) + return DeclGroupPtrTy(); + + DKind = ParseOpenMPDirectiveKind(*this); + while (DKind != OMPD_end_declare_target && DKind != OMPD_declare_target && + Tok.isNot(tok::eof) && Tok.isNot(tok::r_brace)) { + ParsedAttributesWithRange attrs(AttrFactory); + MaybeParseCXX11Attributes(attrs); + MaybeParseMicrosoftAttributes(attrs); + 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) { + ConsumeAnyToken(); + if (Tok.isNot(tok::annot_pragma_openmp_end)) { + Diag(Tok, diag::warn_omp_extra_tokens_at_eol) + << getOpenMPDirectiveName(OMPD_end_declare_target); + SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); + } + // Skip the last annot_pragma_openmp_end. + ConsumeAnyToken(); + } else { + Diag(Tok, diag::err_expected_end_declare_target); + Diag(DTLoc, diag::note_matching) << "'#pragma omp declare target'"; + } + Actions.ActOnFinishOpenMPDeclareTargetDirective(); + return DeclGroupPtrTy(); + } case OMPD_unknown: Diag(Tok, diag::err_omp_unknown_directive); break; @@ -491,6 +544,7 @@ case OMPD_taskloop: case OMPD_taskloop_simd: case OMPD_distribute: + case OMPD_end_declare_target: Diag(Tok, diag::err_omp_unexpected_directive) << getOpenMPDirectiveName(DKind); break; @@ -711,6 +765,8 @@ break; } case OMPD_declare_simd: + case OMPD_declare_target: + case OMPD_end_declare_target: Diag(Tok, diag::err_omp_unexpected_directive) << getOpenMPDirectiveName(DKind); SkipUntil(tok::annot_pragma_openmp_end); Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -5052,6 +5052,9 @@ CurContext->addHiddenDecl(New); } + if (isInOpenMPDeclareTargetContext()) + checkDeclIsAllowedInOpenMPTarget(nullptr, New); + return New; } Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -13814,6 +13814,9 @@ static void MarkExprReferenced(Sema &SemaRef, SourceLocation Loc, Decl *D, Expr *E, bool MightBeOdrUse) { + if (SemaRef.isInOpenMPDeclareTargetContext()) + SemaRef.checkDeclIsAllowedInOpenMPTarget(E, D); + if (VarDecl *Var = dyn_cast(D)) { DoMarkVarDeclReferenced(SemaRef, Loc, Var, E); return; Index: lib/Sema/SemaOpenMP.cpp =================================================================== --- lib/Sema/SemaOpenMP.cpp +++ lib/Sema/SemaOpenMP.cpp @@ -644,6 +644,11 @@ return DVar; } + if (Stack.size() == 1) { + // Not in OpenMP execution region and top scope was already checked. + return DVar; + } + // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct, C/C++, predetermined, p.4] // Static data members are shared. @@ -1706,6 +1711,8 @@ case OMPD_target_exit_data: case OMPD_declare_reduction: case OMPD_declare_simd: + case OMPD_declare_target: + case OMPD_end_declare_target: llvm_unreachable("OpenMP Directive is not allowed"); case OMPD_unknown: llvm_unreachable("Unknown OpenMP directive"); @@ -3158,6 +3165,8 @@ Res = ActOnOpenMPDistributeDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); break; + case OMPD_declare_target: + case OMPD_end_declare_target: case OMPD_threadprivate: case OMPD_declare_reduction: case OMPD_declare_simd: @@ -10354,3 +10363,141 @@ return new (Context) OMPDefaultmapClause(StartLoc, LParenLoc, MLoc, KindLoc, EndLoc, Kind, M); } + +bool Sema::ActOnStartOpenMPDeclareTargetDirective(SourceLocation Loc) { + DeclContext *CurLexicalContext = getCurLexicalContext(); + if (!CurLexicalContext->isFileContext() && + !CurLexicalContext->isExternCContext() && + !CurLexicalContext->isExternCXXContext()) { + Diag(Loc, diag::err_omp_region_not_file_context); + return false; + } + if (IsInOpenMPDeclareTargetContext) { + Diag(Loc, diag::err_omp_enclosed_declare_target); + return false; + } + + IsInOpenMPDeclareTargetContext = true; + return true; +} + +void Sema::ActOnFinishOpenMPDeclareTargetDirective() { + assert(IsInOpenMPDeclareTargetContext && + "Unexpected ActOnFinishOpenMPDeclareTargetDirective"); + + IsInOpenMPDeclareTargetContext = false; +} + +static void checkDeclInTargetContext(SourceLocation SL, SourceRange SR, + Sema &SemaRef, Decl *D) { + if (!D) + return; + Decl *LD = nullptr; + 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()) { + D->addAttr(OMPDeclareTargetDeclAttr::CreateImplicit(SemaRef.Context)); + if (ASTMutationListener *ML = SemaRef.Context.getASTMutationListener()) + ML->DeclarationMarkedOpenMPDeclareTarget(D); + return; + } + + } else if (isa(D)) { + const FunctionDecl *FD = nullptr; + 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) { + D->addAttr(OMPDeclareTargetDeclAttr::CreateImplicit(SemaRef.Context)); + if (ASTMutationListener *ML = SemaRef.Context.getASTMutationListener()) + ML->DeclarationMarkedOpenMPDeclareTarget(D); + return; + } + } + if (!LD) + LD = D; + if (LD && !LD->hasAttr() && + (isa(LD) || isa(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) && + cast(DC)->hasAttr()) + break; + DC = DC->getParent(); + } + if (DC) + return; + + // Is not declared in target context. + SemaRef.Diag(LD->getLocation(), diag::warn_omp_not_in_target_context); + SemaRef.Diag(SL, diag::note_used_here) << SR; + } + // Mark decl as declared target to prevent further diagnostic. + D->addAttr(OMPDeclareTargetDeclAttr::CreateImplicit(SemaRef.Context)); + if (ASTMutationListener *ML = SemaRef.Context.getASTMutationListener()) + ML->DeclarationMarkedOpenMPDeclareTarget(D); + } +} + +static bool checkValueDeclInTarget(SourceLocation SL, SourceRange SR, + Sema &SemaRef, DSAStackTy *Stack, + ValueDecl *VD) { + if (VD->hasAttr()) + 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(); + // 2.10.6: threadprivate variable cannot appear in a declare target directive. + if (VarDecl *VD = dyn_cast(D)) { + if (DSAStack->isThreadPrivate(VD)) { + Diag(SL, diag::err_omp_threadprivate_in_target); + ReportOriginalDSA(*this, DSAStack, VD, DSAStack->getTopDSA(VD, false)); + return; + } + } + if (ValueDecl *VD = dyn_cast(D)) { + // Problem if any with var declared with incomplete type will be reported + // as normal, so no need to check it here. + if ((E || !VD->getType()->isIncompleteType()) && + !checkValueDeclInTarget(SL, SR, *this, DSAStack, VD)) { + // Mark decl as declared target to prevent further diagnostic. + if (isa(VD) || isa(VD)) { + VD->addAttr(OMPDeclareTargetDeclAttr::CreateImplicit(Context)); + if (ASTMutationListener *ML = Context.getASTMutationListener()) + ML->DeclarationMarkedOpenMPDeclareTarget(VD); + } + return; + } + } + if (!E) { + // Checking declaration inside declare target region. + if (!D->hasAttr() && + (isa(D) || isa(D))) { + D->addAttr(OMPDeclareTargetDeclAttr::CreateImplicit(Context)); + if (ASTMutationListener *ML = Context.getASTMutationListener()) + ML->DeclarationMarkedOpenMPDeclareTarget(D); + } + return; + } + checkDeclInTargetContext(E->getExprLoc(), E->getSourceRange(), *this, D); +} Index: lib/Serialization/ASTCommon.h =================================================================== --- lib/Serialization/ASTCommon.h +++ lib/Serialization/ASTCommon.h @@ -37,6 +37,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/ASTReaderDecl.cpp =================================================================== --- lib/Serialization/ASTReaderDecl.cpp +++ lib/Serialization/ASTReaderDecl.cpp @@ -3879,6 +3879,11 @@ Reader.Context, ReadSourceRange(Record, Idx))); break; + case UPD_DECL_MARKED_OPENMP_DECLARETARGET: + D->addAttr(OMPDeclareTargetDeclAttr::CreateImplicit( + Reader.Context, ReadSourceRange(Record, Idx))); + break; + case UPD_DECL_EXPORTED: { unsigned SubmoduleID = readSubmoduleID(Record, Idx); auto *Exported = cast(D); Index: lib/Serialization/ASTWriter.cpp =================================================================== --- lib/Serialization/ASTWriter.cpp +++ lib/Serialization/ASTWriter.cpp @@ -4760,6 +4760,11 @@ D->getAttr()->getRange()); break; + case UPD_DECL_MARKED_OPENMP_DECLARETARGET: + Record.AddSourceRange( + D->getAttr()->getRange()); + break; + case UPD_DECL_EXPORTED: Record.push_back(getSubmoduleID(Update.getModule())); break; @@ -5887,6 +5892,14 @@ DeclUpdates[D].push_back(DeclUpdate(UPD_DECL_MARKED_OPENMP_THREADPRIVATE)); } +void ASTWriter::DeclarationMarkedOpenMPDeclareTarget(const Decl *D) { + assert(!WritingAST && "Already writing the AST!"); + if (!D->isFromASTFile()) + return; + + DeclUpdates[D].push_back(DeclUpdate(UPD_DECL_MARKED_OPENMP_DECLARETARGET)); +} + void ASTWriter::RedefinedHiddenDefinition(const NamedDecl *D, Module *M) { assert(!WritingAST && "Already writing the AST!"); assert(D->isHidden() && "expected a hidden declaration"); Index: lib/Serialization/ASTWriterDecl.cpp =================================================================== --- lib/Serialization/ASTWriterDecl.cpp +++ lib/Serialization/ASTWriterDecl.cpp @@ -2133,8 +2133,10 @@ // 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) || + D->hasAttr()) return true; // ImportDecl is used by codegen to determine the set of imported modules to Index: test/OpenMP/declare_target_ast_print.cpp =================================================================== --- /dev/null +++ test/OpenMP/declare_target_ast_print.cpp @@ -0,0 +1,93 @@ +// 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 +} + +#pragma omp declare target +template +struct C { +// CHECK: template struct C + T t; +// CHECK-NEXT: int t; + static T ts; +// CHECK-NEXT: #pragma omp declare target +// CHECK-NEXT: static int ts; +// CHECK: #pragma omp end declare target + + C(T t) : t(t) { + } +// CHECK: #pragma omp declare target +// CHECK-NEXT: C(int t) : t(t) { +// CHECK-NEXT: } +// CHECK: #pragma omp end declare target + + T foo() { + return t; + } +// CHECK: #pragma omp declare target +// CHECK-NEXT: int foo() { +// CHECK-NEXT: return this->t; +// CHECK-NEXT: } +// CHECK: #pragma omp end declare target +}; + +// CHECK: template struct C { +// CHECK: #pragma omp declare target +// CHECK-NEXT: static T ts; +// CHECK-NEXT: #pragma omp end declare target + +template +T C::ts = 1; +// CHECK: #pragma omp declare target +// CHECK: T ts = 1; +// CHECK: #pragma omp end declare target + +// CHECK: #pragma omp declare target +// CHECK: int test1() +int test1() { + C c(1); + return c.foo() + c.ts; +} +#pragma omp end declare target +// CHECK: #pragma omp end declare target + +int main (int argc, char **argv) { + foo(); + foo_c(); + foo_cpp(); + test1(); + return (0); +} + +// CHECK: #pragma omp declare target +// CHECK-NEXT: int ts = 1; +// CHECK-NEXT: #pragma omp end declare target +#endif Index: test/OpenMP/declare_target_messages.cpp =================================================================== --- /dev/null +++ test/OpenMP/declare_target_messages.cpp @@ -0,0 +1,89 @@ +// 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 {{declaration is not declared in any declare target region}} +__thread int t; // expected-note {{defined as threadprivate or thread local}} +#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-note {{defined as threadprivate or thread local}} +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-error {{threadprivate variables cannot be used in target constructs}} + b = 0; // expected-note {{used here}} + t = 1; // expected-error {{threadprivate variables cannot be used in target constructs}} + 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); +} + +namespace { +#pragma omp declare target // expected-note {{to match this '#pragma omp declare target'}} + int x; +} // expected-error {{expected '#pragma omp end declare target'}} +#pragma omp end declare target // expected-error {{unexpected OpenMP directive '#pragma omp end declare target'}} + +#pragma omp declare target // expected-error {{expected '#pragma omp end declare target'}} expected-note {{to match this '#pragma omp declare target'}}