Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -11323,6 +11323,11 @@ void checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D, SourceLocation IdLoc = SourceLocation()); + + /// Adds OMPDeclareTargetDeclAttr to referenced variables in declare target + /// directive. + void ActOnOpenMPImplicitDeclareTarget(Decl *D); + /// Finishes analysis of the deferred functions calls that may be declared as /// host/nohost during device/host compilation. void finalizeOpenMPDelayedAnalysis(const FunctionDecl *Caller, Index: clang/lib/Sema/SemaDecl.cpp =================================================================== --- clang/lib/Sema/SemaDecl.cpp +++ clang/lib/Sema/SemaDecl.cpp @@ -14468,6 +14468,13 @@ for (unsigned i = 0, e = Group.size(); i != e; ++i) { if (Decl *D = Group[i]) { + // Check if the Decl has been declared in '#pragma omp declare target' + // directive and has static storage duration. + if (auto *VD = dyn_cast(D); + LangOpts.OpenMP && VD && VD->hasAttr() && + VD->hasGlobalStorage()) { + ActOnOpenMPImplicitDeclareTarget(D); + } // For declarators, there are some additional syntactic-ish checks we need // to perform. if (auto *DD = dyn_cast(D)) { Index: clang/lib/Sema/SemaOpenMP.cpp =================================================================== --- clang/lib/Sema/SemaOpenMP.cpp +++ clang/lib/Sema/SemaOpenMP.cpp @@ -23088,6 +23088,59 @@ checkDeclInTargetContext(E->getExprLoc(), E->getSourceRange(), *this, D); } +class GlobalDeclRefChecker final + : public ConstStmtVisitor { + SmallVector DeclVector; + Decl *TargetDecl; + +public: + void SetTargetDecl(Decl *TargetDecl) { this->TargetDecl = TargetDecl; } + bool CheckDeclVector() { return this->DeclVector.empty(); } + void PushDeclVector(VarDecl *TargetVarDecl) { + this->DeclVector.push_back(TargetVarDecl); + } + VarDecl *PopDeclVector() { return (this->DeclVector.pop_back_val()); } + void VisitDeclRefExpr(const DeclRefExpr *Node) { + if (auto *VD = const_cast(dyn_cast(Node->getDecl()))) { + VD->addAttr(this->TargetDecl->getAttr()); + this->PushDeclVector(VD); + } + } + void VisitExpr(const Expr *Ex) { + for (Expr::const_child_iterator it = Ex->child_begin(); + it != Ex->child_end(); ++it) { + Visit(*it); + } + } +}; + +/// Adding OMPDeclareTargetDeclAttr to variables with static storage +/// duration that are referenced in the initializer expression list of +/// variables with static storage duration in declare target directive. +void Sema::ActOnOpenMPImplicitDeclareTarget(Decl *TargetDecl) { + GlobalDeclRefChecker Checker; + Checker.SetTargetDecl(TargetDecl); + VarDecl *TargetVarDecl = nullptr; + if (TargetVarDecl = dyn_cast_or_null(TargetDecl)) + Checker.PushDeclVector(TargetVarDecl); + while (!Checker.CheckDeclVector()) { + VarDecl *TargetVarDecl = Checker.PopDeclVector(); + if (TargetVarDecl->hasAttr()) { + if (TargetVarDecl->hasInit() && TargetVarDecl->hasGlobalStorage()) { + Expr *Ex = TargetVarDecl->getInit(); + if (Ex) { + if (auto *DeclRef = dyn_cast_or_null(Ex)) { + Checker.Visit(DeclRef); + continue; + } + Checker.VisitExpr(Ex); + } + } + } + } + return; +} + OMPClause *Sema::ActOnOpenMPToClause( ArrayRef MotionModifiers, ArrayRef MotionModifiersLoc, Index: clang/test/OpenMP/declare_target_messages.cpp =================================================================== --- clang/test/OpenMP/declare_target_messages.cpp +++ clang/test/OpenMP/declare_target_messages.cpp @@ -233,6 +233,42 @@ #pragma omp declare target to(MultiDevTy) device_type(host) // omp45-error {{unexpected 'device_type' clause, only 'to' or 'link' clauses expected}} omp5-error {{'device_type(host)' does not match previously specified 'device_type(any)' for the same declaration}} omp51-error {{'device_type(host)' does not match previously specified 'device_type(any)' for the same declaration}} omp52-error {{unexpected 'to' clause, use 'enter' instead}} omp52-error {{expected at least one 'enter', 'link' or 'indirect' clause}} #pragma omp declare target to(MultiDevTy) device_type(nohost) // omp45-error {{unexpected 'device_type' clause, only 'to' or 'link' clauses expected}} omp5-error {{'device_type(nohost)' does not match previously specified 'device_type(any)' for the same declaration}} // omp51-error {{'device_type(nohost)' does not match previously specified 'device_type(any)' for the same declaration}} omp52-error {{unexpected 'to' clause, use 'enter' instead}} omp52-error {{expected at least one 'enter', 'link' or 'indirect' clause}} +static int variable = 100; //expected-warning {{declaration is not declared in any declare target region}} +static float variable1 = 200; +static float variable2 = variable1; //expected-warning {{declaration is not declared in any declare target region}} + +static int var = 1; //expected-warning {{declaration is not declared in any declare target region}} + +static int var1 = 10; +static int *var2 = &var1; +static int **ptr1 = &var2; //expected-warning {{declaration is not declared in any declare target region}} + +int arr[2] = {1,2}; +int (*arrptr)[2] = &arr; //expected-warning {{declaration is not declared in any declare target region}} + +class declare{ + public: int x; + void print(); +}; +declare obj1; +declare *obj2 = &obj1; //expected-warning {{declaration is not declared in any declare target region}} + +struct target{ + int x; + void print(); +}; +static target S; //expected-warning {{declaration is not declared in any declare target region}} + +#pragma omp declare target +int target_var = variable; //expected-note {{used here}} +float target_var1 = variable2; //expected-note {{used here}} +int *ptr = &var; //expected-note {{used here}} +int ***ptr2 = &ptr1; //expected-note {{used here}} +int (**ptr3)[2] = &arrptr; //expected-note {{used here}} +declare **obj3 = &obj2; //expected-note {{used here}} +target *S1 = &S; //expected-note {{used here}} +#pragma omp end declare target + #if TESTENDINC #include "unterminated_declare_target_include.h" #elif TESTEND Index: clang/test/OpenMP/declare_target_variables_ast_print.cpp =================================================================== --- /dev/null +++ clang/test/OpenMP/declare_target_variables_ast_print.cpp @@ -0,0 +1,111 @@ +// RUN: %clang_cc1 -w -verify -fopenmp -I %S/Inputs -ast-print %s | FileCheck %s --check-prefix=CHECK +// expected-no-diagnostics + +static int variable = 100; +static float variable1 = 200; +static float variable2 = variable1; + +static int var = 1; + +static int var1 = 10; +static int *var2 = &var1; +static int **ptr1 = &var2; + +int arr[2] = {1,2}; +int (*arrptr)[2] = &arr; + +class declare{ + public: int x; + void print(); +}; +declare obj1; +declare *obj2 = &obj1; + +struct target{ + int x; + void print(); +}; +static target S; + +#pragma omp declare target +int target_var = variable; +float target_var1 = variable2; +int *ptr = &var; +int ***ptr2 = &ptr1; +int (**ptr3)[2] = &arrptr; +declare **obj3 = &obj2; +target *S1 = &S; +#pragma omp end declare target +// CHECK: #pragma omp declare target +// CHECK-NEXT: static int variable = 100; +// CHECK-NEXT: #pragma omp end declare target + +// CHECK-NEXT: #pragma omp declare target +// CHECK-NEXT: static float variable1 = 200; +// CHECK-NEXT: #pragma omp end declare target +// CHECK-NEXT: #pragma omp declare target +// CHECK-NEXT: static float variable2 = variable1; +// CHECK-NEXT: #pragma omp end declare target + +// CHECK: #pragma omp declare target +// CHECK-NEXT: static int var = 1; +// CHECK-NEXT: #pragma omp end declare target + +// CHECK-NEXT: #pragma omp declare target +// CHECK-NEXT: static int var1 = 10; +// CHECK-NEXT: #pragma omp end declare target +// CHECK-NEXT: #pragma omp declare target +// CHECK-NEXT: static int *var2 = &var1; +// CHECK-NEXT: #pragma omp end declare target +// CHECK-NEXT: #pragma omp declare target +// CHECK-NEXT: static int **ptr1 = &var2; +// CHECK-NEXT: #pragma omp end declare target + +// CHECK-NEXT: #pragma omp declare target +// CHECK-NEXT: int arr[2] = {1, 2}; +// CHECK-NEXT: #pragma omp end declare target +// CHECK-NEXT: #pragma omp declare target +// CHECK-NEXT: int (*arrptr)[2] = &arr; +// CHECK-NEXT: #pragma omp end declare target + +// CHECK-NEXT: class declare { +// CHECK-NEXT: public: +// CHECK-NEXT: int x; +// CHECK-NEXT: void print(); +// CHECK-NEXT: }; +// CHECK-NEXT: #pragma omp declare target +// CHECK-NEXT: declare obj1; +// CHECK-NEXT: #pragma omp end declare target +// CHECK-NEXT: #pragma omp declare target +// CHECK-NEXT: declare *obj2 = &obj1; +// CHECK-NEXT: #pragma omp end declare target + +// CHECK-NEXT: struct target { +// CHECK-NEXT: int x; +// CHECK-NEXT: void print(); +// CHECK-NEXT: }; +// CHECK-NEXT: #pragma omp declare target +// CHECK-NEXT: static target S; +// CHECK-NEXT: #pragma omp end declare target + +// CHECK-NEXT: #pragma omp declare target +// CHECK-NEXT: int target_var = variable; +// CHECK-NEXT: #pragma omp end declare target +// CHECK-NEXT: #pragma omp declare target +// CHECK-NEXT: float target_var1 = variable2; +// CHECK-NEXT: #pragma omp end declare target +// CHECK-NEXT: #pragma omp declare target +// CHECK-NEXT: int *ptr = &var; +// CHECK-NEXT: #pragma omp end declare target +// CHECK-NEXT: #pragma omp declare target +// CHECK-NEXT: int ***ptr2 = &ptr1; +// CHECK-NEXT: #pragma omp end declare target +// CHECK-NEXT: #pragma omp declare target +// CHECK-NEXT: int (**ptr3)[2] = &arrptr; +// CHECK-NEXT: #pragma omp end declare target +// CHECK-NEXT: #pragma omp declare target +// CHECK-NEXT: declare **obj3 = &obj2; +// CHECK-NEXT: #pragma omp end declare target +// CHECK-NEXT: #pragma omp declare target +// CHECK-NEXT: target *S1 = &S; +// CHECK-NEXT: #pragma omp end declare target Index: clang/test/OpenMP/nvptx_target_exceptions_messages.cpp =================================================================== --- clang/test/OpenMP/nvptx_target_exceptions_messages.cpp +++ clang/test/OpenMP/nvptx_target_exceptions_messages.cpp @@ -95,7 +95,7 @@ int (*D)() = C; // expected-note {{used here}} // host-note@-1 {{used here}} #pragma omp end declare target -int foobar3() { throw 1; } +int foobar3() { throw 1; } // expected-error {{cannot use 'throw' with exceptions disabled}} // Check no infinite recursion in deferred diagnostic emitter. long E = (long)&E;