jlebar created this revision.
jlebar added a reviewer: rnk.
jlebar added subscribers: tra, cfe-commits.

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.


https://reviews.llvm.org/D25115

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

Index: clang/test/Parser/lambda-attr.cu
===================================================================
--- clang/test/Parser/lambda-attr.cu
+++ clang/test/Parser/lambda-attr.cu
@@ -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.
Index: clang/lib/Parse/ParseExprCXX.cpp
===================================================================
--- clang/lib/Parse/ParseExprCXX.cpp
+++ clang/lib/Parse/ParseExprCXX.cpp
@@ -1134,6 +1134,18 @@
     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 @@
 
     PrototypeScope.Exit();
 
+    WarnIfHasCUDATargetAttr();
+
     SourceLocation NoLoc;
     D.AddTypeInfo(DeclaratorChunk::getFunction(/*hasProto=*/true,
                                            /*isAmbiguous=*/false,
@@ -1275,6 +1289,8 @@
         DeclEndLoc = Range.getEnd();
     }
 
+    WarnIfHasCUDATargetAttr();
+
     SourceLocation NoLoc;
     D.AddTypeInfo(DeclaratorChunk::getFunction(/*hasProto=*/true,
                                                /*isAmbiguous=*/false,
Index: clang/include/clang/Basic/DiagnosticParseKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticParseKinds.td
+++ clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1022,6 +1022,10 @@
 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 {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to