diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -1501,43 +1501,60 @@ } void visitUsedDecl(SourceLocation Loc, Decl *D) { - if (auto *FD = dyn_cast(D)) { - FunctionDecl *Caller = UseStack.empty() ? nullptr : UseStack.back(); - auto IsKnownEmitted = S.getEmissionStatus(FD, /*Final=*/true) == - Sema::FunctionEmissionStatus::Emitted; - if (!Caller) - ShouldEmit = IsKnownEmitted; - if ((!ShouldEmit && !S.getLangOpts().OpenMP && !Caller) || - S.shouldIgnoreInHostDeviceCheck(FD) || Visited.count(D)) - return; - // Finalize analysis of OpenMP-specific constructs. - if (Caller && S.LangOpts.OpenMP && UseStack.size() == 1) - S.finalizeOpenMPDelayedAnalysis(Caller, FD, Loc); - if (Caller) - S.DeviceKnownEmittedFns[FD] = {Caller, Loc}; - if (ShouldEmit || InOMPDeviceContext) - S.emitDeferredDiags(FD, Caller); - Visited.insert(D); - UseStack.push_back(FD); - if (auto *S = FD->getBody()) { - this->Visit(S); - } - UseStack.pop_back(); - Visited.erase(D); - } else if (auto *VD = dyn_cast(D)) { - if (auto *Init = VD->getInit()) { - auto DevTy = OMPDeclareTargetDeclAttr::getDeviceType(VD); - bool IsDev = DevTy && (*DevTy == OMPDeclareTargetDeclAttr::DT_NoHost || - *DevTy == OMPDeclareTargetDeclAttr::DT_Any); - if (IsDev) - ++InOMPDeviceContext; - this->Visit(Init); - if (IsDev) - --InOMPDeviceContext; - } - } else + if (isa(D)) + return; + if (auto *FD = dyn_cast(D)) + checkFunc(Loc, FD); + else Inherited::visitUsedDecl(Loc, D); } + + void checkVar(VarDecl *VD) { + assert(VD->isFileVarDecl() && + "Should only check file-scope variables"); + if (auto *Init = VD->getInit()) { + auto DevTy = OMPDeclareTargetDeclAttr::getDeviceType(VD); + bool IsDev = DevTy && (*DevTy == OMPDeclareTargetDeclAttr::DT_NoHost || + *DevTy == OMPDeclareTargetDeclAttr::DT_Any); + if (IsDev) + ++InOMPDeviceContext; + this->Visit(Init); + if (IsDev) + --InOMPDeviceContext; + } + } + + void checkFunc(SourceLocation Loc, FunctionDecl *FD) { + FunctionDecl *Caller = UseStack.empty() ? nullptr : UseStack.back(); + auto IsKnownEmitted = S.getEmissionStatus(FD, /*Final=*/true) == + Sema::FunctionEmissionStatus::Emitted; + if (!Caller) + ShouldEmit = IsKnownEmitted; + if ((!ShouldEmit && !S.getLangOpts().OpenMP && !Caller) || + S.shouldIgnoreInHostDeviceCheck(FD) || Visited.count(FD)) + return; + // Finalize analysis of OpenMP-specific constructs. + if (Caller && S.LangOpts.OpenMP && UseStack.size() == 1) + S.finalizeOpenMPDelayedAnalysis(Caller, FD, Loc); + if (Caller) + S.DeviceKnownEmittedFns[FD] = {Caller, Loc}; + if (ShouldEmit || InOMPDeviceContext) + S.emitDeferredDiags(FD, Caller); + Visited.insert(FD); + UseStack.push_back(FD); + if (auto *S = FD->getBody()) { + this->Visit(S); + } + UseStack.pop_back(); + Visited.erase(FD); + } + + void checkRecordedDecl(Decl *D) { + if (auto *FD = dyn_cast(D)) + checkFunc(SourceLocation(), FD); + else + checkVar(cast(D)); + } }; } // namespace @@ -1552,7 +1569,7 @@ DeferredDiagnosticsEmitter DDE(*this); for (auto D : DeclsToCheckForDeferredDiags) - DDE.visitUsedDecl(SourceLocation(), D); + DDE.checkRecordedDecl(D); } // In CUDA, there are some constructs which may appear in semantically-valid diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -12257,7 +12257,7 @@ VDecl->setInitStyle(VarDecl::ListInit); } - if (LangOpts.OpenMP && VDecl->hasGlobalStorage()) + if (LangOpts.OpenMP && VDecl->isFileVarDecl()) DeclsToCheckForDeferredDiags.push_back(VDecl); CheckCompleteVariableDeclaration(VDecl); } diff --git a/clang/test/OpenMP/nvptx_target_exceptions_messages.cpp b/clang/test/OpenMP/nvptx_target_exceptions_messages.cpp --- a/clang/test/OpenMP/nvptx_target_exceptions_messages.cpp +++ b/clang/test/OpenMP/nvptx_target_exceptions_messages.cpp @@ -1,5 +1,10 @@ -// RUN: %clang_cc1 -fopenmp -x c++ -triple powerpc64le-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm-bc %s -o %t-ppc-host.bc -fexceptions -fcxx-exceptions -// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple nvptx64-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o - -fexceptions -fcxx-exceptions -ferror-limit 100 +// RUN: %clang_cc1 -fopenmp -x c++ -triple powerpc64le-unknown-unknown \ +// RUN: -verify=host -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm-bc \ +// RUN: %s -o %t-ppc-host.bc -fexceptions -fcxx-exceptions +// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple nvptx64-unknown-unknown \ +// RUN: -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm %s \ +// RUN: -fopenmp-is-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o - \ +// RUN: -fexceptions -fcxx-exceptions -ferror-limit 100 #ifndef HEADER #define HEADER @@ -81,4 +86,17 @@ int foobar1() { throw 1; } int foobar2() { throw 1; } // expected-error {{cannot use 'throw' with exceptions disabled}} + +int foobar3(); +int (*C)() = &foobar3; // expected-warning {{declaration is not declared in any declare target region}} + // host-warning@-1 {{declaration is not declared in any declare target region}} +#pragma omp declare target +int (*D)() = C; // expected-note {{used here}} + // host-note@-1 {{used here}} +#pragma omp end declare target +int foobar3() { throw 1; } + +// Check no infinite recursion in deferred diagnostic emitter. +long E = (long)&E; + #endif // HEADER