[CUDA] Reject calls to __device__ functions from host variable global initializers.

Reviewers: tra

Subscribers: cfe-commits

Differential Revision: https://reviews.llvm.org/D23335

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@278196 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Justin Lebar 2016-08-10 01:09:21 +00:00
parent 8830dfce4f
commit bd12a41e3d
3 changed files with 81 additions and 27 deletions

View File

@ -6640,6 +6640,9 @@ def err_global_call_not_config : Error<
def err_ref_bad_target : Error< def err_ref_bad_target : Error<
"reference to %select{__device__|__global__|__host__|__host__ __device__}0 " "reference to %select{__device__|__global__|__host__|__host__ __device__}0 "
"function %1 in %select{__device__|__global__|__host__|__host__ __device__}2 function">; "function %1 in %select{__device__|__global__|__host__|__host__ __device__}2 function">;
def err_ref_bad_target_global_initializer : Error<
"reference to %select{__device__|__global__|__host__|__host__ __device__}0 "
"function %1 in global initializer">;
def warn_kern_is_method : Extension< def warn_kern_is_method : Extension<
"kernel function %0 is a member function; this may not be accepted by nvcc">, "kernel function %0 is a member function; this may not be accepted by nvcc">,
InGroup<CudaCompat>; InGroup<CudaCompat>;

View File

@ -10728,11 +10728,11 @@ Sema::FinalizeDeclaration(Decl *ThisDecl) {
// 7.5). We must also apply the same checks to all __shared__ // 7.5). We must also apply the same checks to all __shared__
// variables whether they are local or not. CUDA also allows // variables whether they are local or not. CUDA also allows
// constant initializers for __constant__ and __device__ variables. // constant initializers for __constant__ and __device__ variables.
if (getLangOpts().CUDA && getLangOpts().CUDAIsDevice) { if (getLangOpts().CUDA) {
const Expr *Init = VD->getInit(); const Expr *Init = VD->getInit();
if (Init && VD->hasGlobalStorage() && if (Init && VD->hasGlobalStorage()) {
(VD->hasAttr<CUDADeviceAttr>() || VD->hasAttr<CUDAConstantAttr>() || if (VD->hasAttr<CUDADeviceAttr>() || VD->hasAttr<CUDAConstantAttr>() ||
VD->hasAttr<CUDASharedAttr>())) { VD->hasAttr<CUDASharedAttr>()) {
assert((!VD->isStaticLocal() || VD->hasAttr<CUDASharedAttr>())); assert((!VD->isStaticLocal() || VD->hasAttr<CUDASharedAttr>()));
bool AllowedInit = false; bool AllowedInit = false;
if (const CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(Init)) if (const CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(Init))
@ -10759,6 +10759,25 @@ Sema::FinalizeDeclaration(Decl *ThisDecl) {
<< Init->getSourceRange(); << Init->getSourceRange();
VD->setInvalidDecl(); VD->setInvalidDecl();
} }
} else {
// This is a host-side global variable. Check that the initializer is
// callable from the host side.
const FunctionDecl *InitFn = nullptr;
if (const CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(Init)) {
InitFn = CE->getConstructor();
} else if (const CallExpr *CE = dyn_cast<CallExpr>(Init)) {
InitFn = CE->getDirectCallee();
}
if (InitFn) {
CUDAFunctionTarget InitFnTarget = IdentifyCUDATarget(InitFn);
if (InitFnTarget != CFT_Host && InitFnTarget != CFT_HostDevice) {
Diag(VD->getLocation(), diag::err_ref_bad_target_global_initializer)
<< InitFnTarget << InitFn;
Diag(InitFn->getLocation(), diag::note_previous_decl) << InitFn;
VD->setInvalidDecl();
}
}
}
} }
} }

View File

@ -0,0 +1,32 @@
// RUN: %clang_cc1 %s --std=c++11 -triple x86_64-linux-unknown -fsyntax-only -o - -verify
#include "Inputs/cuda.h"
// Check that we get an error if we try to call a __device__ function from a
// module initializer.
struct S {
__device__ S() {}
// expected-note@-1 {{'S' declared here}}
};
S s;
// expected-error@-1 {{reference to __device__ function 'S' in global initializer}}
struct T {
__host__ __device__ T() {}
};
T t; // No error, this is OK.
struct U {
__host__ U() {}
__device__ U(int) {}
// expected-note@-1 {{'U' declared here}}
};
U u(42);
// expected-error@-1 {{reference to __device__ function 'U' in global initializer}}
__device__ int device_fn() { return 42; }
// expected-note@-1 {{'device_fn' declared here}}
int n = device_fn();
// expected-error@-1 {{reference to __device__ function 'device_fn' in global initializer}}