tra added a comment.

Richard, I've updated the patch as you've suggested -- it indeed simplifies 
things quite a bit and handles the corner cases you've mentioned.


================
Comment at: lib/CodeGen/CGDeclCXX.cpp:323-324
@@ +322,4 @@
+
+  // The constructor function has no parameters,
+  if (CD->getNumParams() != 0)
+    return false;
----------------
rsmith wrote:
> What if the constructor is a C-style varargs function:
> 
>   struct X { X(...) {} };
> 
> ?
CUDA does not support varargs on device side. nvcc fails with an error:

> error: a "device" function cannot have ellipsis

That's another thing I'll need to fix (as a separate patch) as clang currently 
accepts varargs everywhere.

This patch will ignore number of arguments passed to varargs constructor, but 
the checks for empty body still do apply.

================
Comment at: lib/CodeGen/CGDeclCXX.cpp:329
@@ +328,3 @@
+  for (const CXXCtorInitializer *CI: CD->inits())
+    if (CI->isAnyMemberInitializer() && CI->isWritten())
+      return false;
----------------
rsmith wrote:
> tra wrote:
> > @rsmith: is this a good way to find member initializer list items?
> > 
> > ```
> > struct S {
> >     int a,b,c;
> >     S() : a(1),b(2),c(3) {}
> > };
> > ```
> > I'm looking for a(),b(),c() which is what I think CUDA spec wants to check 
> > for, but CD->inits() appears to have other initializers on the list as well.
> You shouldn't need to check `isAnyMemberInitializer`: if there's any written 
> inits, the constructor violates the rules.
As it turns out, the rules don't apply to all written initializers. For 
instance, nvcc allows empty constructor on init list:
```
struct A {  __device__ A(){}; };
struct B {  __device__ B(){}; };

struct C : A {
  B b;
  __device__ C() : A(), b() {}
};

__device__ C c;
```

I've simplified the patch so that in only checks for constructor's 'emptiness', 
but disregards how that constructor gets to be executed.

================
Comment at: lib/CodeGen/CGDeclCXX.cpp:333
@@ +332,3 @@
+  // and the function body is an empty compound statement.
+  // That does not always work.
+  if (!CD->hasTrivialBody())
----------------
rsmith wrote:
> What doesn't always work?
It was leftover from early patch variant that didn't defer emitting global vars.
If I don't defer and need to emit a global var before constructor definition is 
available, hasTrivialBody() returns false and triggers diagnostics. 

================
Comment at: lib/CodeGen/CGDeclCXX.cpp:347-367
@@ +346,23 @@
+
+  // The default constructors of all base classes of its class can be
+  // considered empty.
+  for (auto &Base : RD->bases())
+    if (hasNonEmptyDefaultConstructors(*this,
+                                       Base.getType()->getAsCXXRecordDecl()))
+      return false;
+
+  // For all the nonstatic data members of its class that are of class type
+  // (or array thereof), the default constructors can be considered empty.
+  for (const auto *I : RD->decls())
+    if (const FieldDecl *V = dyn_cast<FieldDecl>(I)) {
+      QualType T = V->getType();
+
+      if (const ArrayType *Ty = dyn_cast<ArrayType>(T))
+        while ((Ty = dyn_cast<ArrayType>(T)))
+          T = Ty->getElementType();
+
+      if (const CXXRecordDecl *R = T->getAsCXXRecordDecl())
+        if (hasNonEmptyDefaultConstructors(*this, R))
+          return false;
+    }
+
----------------
rsmith wrote:
> Rather than checking these properties this way, I'd suggest you check the 
> initialization expression in each `CXXCtorInitializer` only contains 
> `CXXConstructExpr`s for empty constructors (or any other whitelisted 
> constructs). Your current approach will miss a couple of cases which the CUDA 
> spec misses but presumably meant to exclude:
> 
> 1) Default member initializers
> 
>   int f();
>   struct X { int n = f(); X() {} };
> 
> 2) Cases where a constructor other than a default constructor is implicitly 
> invoked
> 
>   struct A { template<typename ...T> A(T...); };
>   struct B : A { B() {} };
Nice. This has simplified the checks a lot.

================
Comment at: lib/CodeGen/CodeGenModule.cpp:1347-1351
@@ -1346,2 +1346,7 @@
     return false;
+  // Delay codegen for device-side CUDA variables. We need to have all
+  // constructor definitions available before we can determine whether
+  // we can skip them or produce an error.
+  if (LangOpts.CUDA && LangOpts.CUDAIsDevice && isa<VarDecl>(Global))
+    return false;
 
----------------
rsmith wrote:
> According to the quoted specification, you're supposed to check whether the 
> constructor can be considered empty at the point in the translation unit 
> where the definition of the variable occurs, so I don't think you need to 
> delay anything.
I guess it's a bug in their guide as nvcc accepts following code with 
constructor definition appearing *after* the variable:

```
struct S {  S(); };
__device__ S s;
S::S() {}

```




http://reviews.llvm.org/D15305



_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to