[PATCH] D62584: [OpenCL][PR42033] Deducing addr space with template parameter types

Anastasia Stulova via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Fri Jul 12 08:06:05 PDT 2019


Anastasia marked an inline comment as done.
Anastasia added inline comments.


================
Comment at: lib/Sema/TreeTransform.h:5363
+    if (ResultType.getAddressSpace() != LangAS::Default &&
+        (ResultType.getAddressSpace() != LangAS::opencl_private)) {
       SemaRef.Diag(TL.getReturnLoc().getBeginLoc(),
----------------
rjmccall wrote:
> Anastasia wrote:
> > rjmccall wrote:
> > > Anastasia wrote:
> > > > Anastasia wrote:
> > > > > rjmccall wrote:
> > > > > > Anastasia wrote:
> > > > > > > I am trying to be a bit more helpful here although I am not sure if we should instead require explicit template parameter and fail the template deduction instead.
> > > > > > > 
> > > > > > > Basically, do we want the following code to always require specifying template argument explicitly:
> > > > > > > 
> > > > > > > 
> > > > > > > ```
> > > > > > > template <class T>
> > > > > > > T xxx(T *in) {
> > > > > > >   T *i = in;
> > > > > > >   return *i;
> > > > > > > }
> > > > > > > 
> > > > > > > __kernel void test() {
> > > > > > >   int foo[10];
> > > > > > >   xxx<int>(&foo[0]); // if we deduce type from foo, it ends up being qualified by __private that we currently diagnose. However private is default (implicit) address space for return type so technically there is no danger in just allowing xxx(&foo[0])
> > > > > > > }
> > > > > > > ```
> > > > > > Implicitly ignoring all address-space qualifiers on the return type seems like the right thing to do; I don't think it needs to be limited to `__private`.  That's probably also the right thing to do for locals, but I'm less certain about it.
> > > > > Just to clarify by "Implicitly ignoring" you mean ignoring if the templ parameters were deduced?
> > > > > 
> > > > > Although I am a bit concerned about allowing other than `__private` address spaces in return types as we reject them in return types of functions generally. Would it not be somehow inconsistent?
> > > > Ok, I have removed the diagnostic completely. At least we don't seem to generate any incorrect IR.
> > > They should be diagnosed somehow when written explicitly on a return type, but if you just do that on the parser path you don't have to worry about it during template instantiation.  They should probably otherwise be ignored no matter where they came from — if someone typedefs `private_int_t` to `__private int`, you should just treat that as `int` in a return type.  Stripping the qualifier from the type is probably the right thing to do so that it doesn't further impact semantic analysis.
> > > 
> > > I definitely don't think you want a model where the qualifier actually means that the return is somehow done via an object in that address space.
> > > They should be diagnosed somehow when written explicitly on a return type, but if you just do that on the parser path you don't have to worry about it during template instantiation.
> > 
> > Ok, this seems to be working currently. The following won't compile:
> > 
> > ```
> > template <typename T>
> > struct S {
> >   __global T f1();     // error: return value cannot be qualified with address space
> > };
> > 
> > ```
> > 
> > > They should probably otherwise be ignored no matter where they came from — if someone typedefs private_int_t to __private int, you should just treat that as int in a return type.
> > 
> > We produce diagnostic for this case currently. I can update this in a separate patch if you think it's more helpful behavior. Although I feel a bit worried about it. However it would align with what we are doing with templates here... so perhaps it's logical change... 
> > 
> > > Stripping the qualifier from the type is probably the right thing to do so that it doesn't further impact semantic analysis.
> > 
> > I guess you mean stripping quals for the case of typedef or others where we will accept the code and ignore quals on the return type? I have tried to do this just for the template case but there are some assertions firing because we are expecting the original return type to be the same before and after template instantiation. So it feels like I would have to do it for everything together. Maybe it should rather go into separate review?
> > We produce diagnostic for this case currently. I can update this in a separate patch if you think it's more helpful behavior. Although I feel a bit worried about it. However it would align with what we are doing with templates here... so perhaps it's logical change...
> 
> Well, it's debatable.  C doesn't say that qualifiers are erased in function return types in general.  On the other hand, qualifiers are semantically meaningless there, and C has few rules that rely on exact type identity.  On reflection, we should probably keep diagnosing that at parse-time, even for typedefs, and just ignore it in templates.
> 
> Can you point out which assertion is firing?
>  On reflection, we should probably keep diagnosing that at parse-time, even for typedefs, and just ignore it in templates.

In that case we don't need to fix anything in parsing.

> Can you point out which assertion is firing?

I have tried this:

```
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 878795bb70..db4ae6e56e 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -5365,6 +5365,11 @@ QualType TreeTransform<Derived>::TransformFunctionProtoType(
     if (ResultType.isNull())
       return QualType();
 
+    if (ResultType.hasQualifiers()) {
+      ResultType = ResultType.getUnqualifiedType();
+      TLB.TypeWasModifiedSafely(ResultType);
+    }
+
     if (getDerived().TransformFunctionTypeParams(
             TL.getBeginLoc(), TL.getParams(),
             TL.getTypePtr()->param_type_begin(),
```


and I am getting some errors in tests mainly because of the differences in the return type. I.e.


```
error: 'error' diagnostics expected but not seen: 
  File llvm/tools/clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-var.cpp Line 126: binding reference of type 'const Base' to value of type 'const volatile Base' drops 'volatile' qualifier
  File llvm/tools/clang/test/CXX/dcl.decl/dcl.init/dcl.init.ref/p5-var.cpp Line 127: binding reference of type 'const Base' to value of type 'const volatile Derived' drops 'volatile' qualifier
```

Practically we no longer get diagnostics for cases like:

```
48 template<typename T> T create();

126  const Base &br5 = create<const volatile Base>();
127  const Base &br6 = create<const volatile Derived>();
```
 
Also the qualifiers are not printed in the type of return type. 

I guess this is expected. I am however struggling with this assert in a couple tests:
  llvm/tools/clang/lib/Sema/TypeLocBuilder.cpp:160: clang::TypeLoc clang::TypeLocBuilder::pushImpl(clang::QualType, size_t, unsigned int): Assertion `Capacity - Index == TypeLoc::getFullDataSizeForType(T) && "incorrect data size provided to CreateTypeSourceInfo!"' failed.

I am not sure if I am modifying `TypeLocBuilder` in a wrong way or perhaps something isn't working well in the `Index` calculation. If this is the direction we would like to go I can spend more time debugging this and upload the review. Not sure if that might be too disruptive change for the release but I would at least like to see the current patch in Clang9 because it fixes a couple of useful cases. :)



CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D62584/new/

https://reviews.llvm.org/D62584





More information about the cfe-commits mailing list