mirror of https://github.com/microsoft/clang.git
[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:
parent
8830dfce4f
commit
bd12a41e3d
|
@ -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>;
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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}}
|
Loading…
Reference in New Issue