Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -11316,6 +11316,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 @@ -14462,6 +14462,12 @@ 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 (D && D->hasAttr() && isa(D)) { + if ((cast(D))->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 @@ -23087,6 +23087,59 @@ checkDeclInTargetContext(E->getExprLoc(), E->getSourceRange(), *this, D); } +/// Adds OMPDeclareTargetDeclAttr to the referenced variables. +void *AddOMPDeclareTargetDeclAttr(const DeclRefExpr *DeclRef, Decl *TargetDecl, + SmallVector &DeclVector) { + Decl *DeclVar = nullptr; + if (DeclRef) { + DeclVar = (Decl *)DeclRef->getDecl(); + if (isa(DeclVar)) { + DeclVar->addAttr(TargetDecl->getAttr()); + DeclVector.push_back(DeclVar); + } + } +} + +void RecursiveExprReader(Expr *Ex, Decl *TargetDecl, + SmallVector &DeclVector) { + for (Expr::child_iterator it = Ex->child_begin(); it != Ex->child_end(); + ++it) { + if (const DeclRefExpr *refExpr = dyn_cast(*it)) { + AddOMPDeclareTargetDeclAttr(refExpr, TargetDecl, DeclVector); + } else if (isa(*it)) + RecursiveExprReader(dyn_cast(*it), TargetDecl, DeclVector); + else + continue; + } +} + +/// 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) { + SmallVector DeclVector; + DeclVector.push_back(TargetDecl); + while (DeclVector.size() != 0) { + Decl *D = DeclVector[DeclVector.size() - 1]; + DeclVector.pop_back(); + if (isa(D) && D->hasAttr()) { + VarDecl *TargetVarDecl = cast(D); + if (TargetVarDecl->hasInit() && TargetVarDecl->hasGlobalStorage()) { + Expr *Ex = TargetVarDecl->getInit(); + const DeclRefExpr *DeclRef = nullptr; + if (Ex) { + if (isa(Ex)) { + DeclRefExpr *DeclRef = dyn_cast(Ex); + AddOMPDeclareTargetDeclAttr(DeclRef, TargetDecl, DeclVector); + continue; + } + RecursiveExprReader(Ex, TargetDecl, DeclVector); + } + } + } + } +} + 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;