[CUDA] Emit a warning if a CUDA host/device/global attribute is placed after '(....
authorJustin Lebar <jlebar@google.com>
Fri, 30 Sep 2016 19:55:55 +0000 (19:55 +0000)
committerJustin Lebar <jlebar@google.com>
Fri, 30 Sep 2016 19:55:55 +0000 (19:55 +0000)
Summary:
This is probably the sane place for the attribute to go, but nvcc
specifically rejects it.  Other GNU-style attributes are allowed in this
position (although judging from the warning it emits for
host/device/global, those attributes are applied to the lambda's
anonymous struct, not to the function itself).

It would be nice to have a FixIt message here, but doing so, or even
just getting the correct range for the attribute, including its '((' and
'))'s, is apparently Hard.

Reviewers: rnk

Subscribers: cfe-commits, tra

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

llvm-svn: 282911

clang/include/clang/Basic/DiagnosticParseKinds.td
clang/lib/Parse/ParseExprCXX.cpp
clang/test/Parser/lambda-attr.cu

index 66fd5c1..db713e4 100644 (file)
@@ -1022,6 +1022,10 @@ def err_pragma_invalid_keyword : Error<
 def warn_pragma_unroll_cuda_value_in_parens : Warning<
   "argument to '#pragma unroll' should not be in parentheses in CUDA C/C++">,
   InGroup<CudaCompat>;
+
+def warn_cuda_attr_lambda_position : Warning<
+  "nvcc does not allow '__%0__' to appear after '()' in lambdas">,
+  InGroup<CudaCompat>;
 } // end of Parse Issue category.
 
 let CategoryName = "Modules Issue" in {
index 7112b9e..614ba8f 100644 (file)
@@ -1134,6 +1134,18 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
     MaybeParseGNUAttributes(D);
   }
 
+  // Helper to emit a warning if we see a CUDA host/device/global attribute
+  // after '(...)'. nvcc doesn't accept this.
+  auto WarnIfHasCUDATargetAttr = [&] {
+    if (getLangOpts().CUDA)
+      for (auto *A = Attr.getList(); A != nullptr; A = A->getNext())
+        if (A->getKind() == AttributeList::AT_CUDADevice ||
+            A->getKind() == AttributeList::AT_CUDAHost ||
+            A->getKind() == AttributeList::AT_CUDAGlobal)
+          Diag(A->getLoc(), diag::warn_cuda_attr_lambda_position)
+              << A->getName()->getName();
+  };
+
   TypeResult TrailingReturnType;
   if (Tok.is(tok::l_paren)) {
     ParseScope PrototypeScope(this,
@@ -1210,6 +1222,8 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
 
     PrototypeScope.Exit();
 
+    WarnIfHasCUDATargetAttr();
+
     SourceLocation NoLoc;
     D.AddTypeInfo(DeclaratorChunk::getFunction(/*hasProto=*/true,
                                            /*isAmbiguous=*/false,
@@ -1275,6 +1289,8 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
         DeclEndLoc = Range.getEnd();
     }
 
+    WarnIfHasCUDATargetAttr();
+
     SourceLocation NoLoc;
     D.AddTypeInfo(DeclaratorChunk::getFunction(/*hasProto=*/true,
                                                /*isAmbiguous=*/false,
index c51e0a2..dfd6fc8 100644 (file)
@@ -1,33 +1,42 @@
 // RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
 // RUN: %clang_cc1 -std=c++11 -fsyntax-only -fcuda-is-device -verify %s
 
-// expected-no-diagnostics
-
 __attribute__((device)) void device_fn() {}
 __attribute__((device)) void hd_fn() {}
 
 __attribute__((device)) void device_attr() {
   ([]() __attribute__((device)) { device_fn(); })();
+  // expected-warning@-1 {{nvcc does not allow '__device__' to appear after '()' in lambdas}}
   ([] __attribute__((device)) () { device_fn(); })();
   ([] __attribute__((device)) { device_fn(); })();
 
   ([&]() __attribute__((device)){ device_fn(); })();
+  // expected-warning@-1 {{nvcc does not allow '__device__' to appear after '()' in lambdas}}
   ([&] __attribute__((device)) () { device_fn(); })();
   ([&] __attribute__((device)) { device_fn(); })();
 
   ([&](int) __attribute__((device)){ device_fn(); })(0);
+  // expected-warning@-1 {{nvcc does not allow '__device__' to appear after '()' in lambdas}}
   ([&] __attribute__((device)) (int) { device_fn(); })(0);
 }
 
 __attribute__((host)) __attribute__((device)) void host_device_attrs() {
   ([]() __attribute__((host)) __attribute__((device)){ hd_fn(); })();
+  // expected-warning@-1 {{nvcc does not allow '__host__' to appear after '()' in lambdas}}
+  // expected-warning@-2 {{nvcc does not allow '__device__' to appear after '()' in lambdas}}
   ([] __attribute__((host)) __attribute__((device)) () { hd_fn(); })();
   ([] __attribute__((host)) __attribute__((device)) { hd_fn(); })();
 
   ([&]() __attribute__((host)) __attribute__((device)){ hd_fn(); })();
+  // expected-warning@-1 {{nvcc does not allow '__host__' to appear after '()' in lambdas}}
+  // expected-warning@-2 {{nvcc does not allow '__device__' to appear after '()' in lambdas}}
   ([&] __attribute__((host)) __attribute__((device)) () { hd_fn(); })();
   ([&] __attribute__((host)) __attribute__((device)) { hd_fn(); })();
 
   ([&](int) __attribute__((host)) __attribute__((device)){ hd_fn(); })(0);
+  // expected-warning@-1 {{nvcc does not allow '__host__' to appear after '()' in lambdas}}
+  // expected-warning@-2 {{nvcc does not allow '__device__' to appear after '()' in lambdas}}
   ([&] __attribute__((host)) __attribute__((device)) (int) { hd_fn(); })(0);
 }
+
+// TODO: Add tests for __attribute__((global)) once we support global lambdas.