diff options
| author | Justin Lebar <jlebar@google.com> | 2016-11-08 23:45:51 +0000 |
|---|---|---|
| committer | Justin Lebar <jlebar@google.com> | 2016-11-08 23:45:51 +0000 |
| commit | 2d56c265046de717dd117c248c3ba8d2a5ff7a5d (patch) | |
| tree | 81306e43c91b58c327c1daf1cc1ca37d3da4e6a7 | |
| parent | 4f243e8d93d17a5346f147b20c80a95352616e74 (diff) | |
| download | bcm5719-llvm-2d56c265046de717dd117c248c3ba8d2a5ff7a5d.tar.gz bcm5719-llvm-2d56c265046de717dd117c248c3ba8d2a5ff7a5d.zip | |
[CUDA] Use only the GVALinkage on function definitions.
Summary:
Previously we'd look at the GVALinkage of whatever FunctionDecl you
happened to be calling.
This is not right. In the absence of the gnu_inline attribute, to be
handled separately, the function definition determines the function's
linkage. So we need to wait until we get a def before we can know
whether something is known-emitted.
Reviewers: tra
Subscribers: cfe-commits, rsmith
Differential Revision: https://reviews.llvm.org/D26268
llvm-svn: 286313
| -rw-r--r-- | clang/lib/Sema/SemaCUDA.cpp | 18 | ||||
| -rw-r--r-- | clang/test/SemaCUDA/add-inline-in-definition.cu | 52 |
2 files changed, 68 insertions, 2 deletions
diff --git a/clang/lib/Sema/SemaCUDA.cpp b/clang/lib/Sema/SemaCUDA.cpp index fbaede1e9d7..d99f8e03ca8 100644 --- a/clang/lib/Sema/SemaCUDA.cpp +++ b/clang/lib/Sema/SemaCUDA.cpp @@ -577,8 +577,22 @@ static bool IsKnownEmitted(Sema &S, FunctionDecl *FD) { (T == Sema::CFT_Device || T == Sema::CFT_Global)) return false; - // Externally-visible and similar functions are always emitted. - if (!isDiscardableGVALinkage(S.getASTContext().GetGVALinkageForFunction(FD))) + // Check whether this function is externally visible -- if so, it's + // known-emitted. + // + // We have to check the GVA linkage of the function's *definition* -- if we + // only have a declaration, we don't know whether or not the function will be + // emitted, because (say) the definition could include "inline". + FunctionDecl *Def = FD->getDefinition(); + + // We may currently be parsing the body of FD, in which case + // FD->getDefinition() will be null, but we still want to treat FD as though + // it's a definition. + if (!Def && FD->willHaveBody()) + Def = FD; + + if (Def && + !isDiscardableGVALinkage(S.getASTContext().GetGVALinkageForFunction(Def))) return true; // Otherwise, the function is known-emitted if it's in our set of diff --git a/clang/test/SemaCUDA/add-inline-in-definition.cu b/clang/test/SemaCUDA/add-inline-in-definition.cu new file mode 100644 index 00000000000..33176c580d4 --- /dev/null +++ b/clang/test/SemaCUDA/add-inline-in-definition.cu @@ -0,0 +1,52 @@ +// RUN: %clang_cc1 -std=c++11 -fcuda-is-device -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s + +#include "Inputs/cuda.h" + +#ifndef __CUDA_ARCH__ +// expected-no-diagnostics +#endif + +// When compiling for device, foo()'s call to host_fn() is an error, because +// foo() is known-emitted. +// +// The trickiness here comes from the fact that the FunctionDecl bar() sees +// foo() does not have the "inline" keyword, so we might incorrectly think that +// foo() is a priori known-emitted. This would prevent us from marking foo() +// as known-emitted when we see the call from bar() to foo(), which would +// prevent us from emitting an error for foo()'s call to host_fn() when we +// eventually see it. + +void host_fn() {} +#ifdef __CUDA_ARCH__ + // expected-note@-2 {{declared here}} +#endif + +__host__ __device__ void foo(); +__device__ void bar() { + foo(); +#ifdef __CUDA_ARCH__ + // expected-note@-2 {{called by 'bar'}} +#endif +} +inline __host__ __device__ void foo() { + host_fn(); +#ifdef __CUDA_ARCH__ + // expected-error@-2 {{reference to __host__ function}} +#endif +} + +// This is similar to the above, except there's no error here. This code used +// to trip an assertion due to us noticing, when emitting the definition of +// boom(), that T::operator S() was (incorrectly) considered a priori +// known-emitted. +struct S {}; +struct T { + __device__ operator S() const; +}; +__device__ inline T::operator S() const { return S(); } + +__device__ T t; +__device__ void boom() { + S s = t; +} |

