https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96516

            Bug ID: 96516
           Summary: template + __attribute__((copy)) produce compiler
                    errors
           Product: gcc
           Version: 9.1.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: sagebar at web dot de
  Target Milestone: ---

Created attachment 49016
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=49016&action=edit
Same code as already seen in the bug description

Using `__attribute__((copy(...)))' to inherit an `returns_nonnull' attribute
will cause a compiler error if the applied-to function's return type uses a
decltype type-expression, or has it's is-pointer-y-ness depend on a template
parameter. However, when `returns_nonnull' is not inherited via `copy()', but
explicitly used, then everything still works fine, so there appears to be a
discrepency between using `copy()' to inherit `returns_nonnull', and specifying
`returns_nonnull' directly.

```
__attribute__((returns_nonnull)) void *base(void *);

                  __attribute__((copy(base))) __typeof__((void *)0) wrap1(void
*);
                  __attribute__((copy(base)))   decltype((void *)0) wrap2(void
*);
template<class T> __attribute__((copy(base)))      T               *wrap3(T *);
template<class T> __attribute__((copy(base)))      decltype(T())   *wrap4(T *);
template<class T> __attribute__((returns_nonnull)) decltype((T *)0) wrap5(T *);
template<class T> __attribute__((copy(base)))      decltype((T *)0) wrap6(T *);
template<class T> __attribute__((copy(base)))    __typeof__((T *)0) wrap7(T *);
template<class T> __attribute__((copy(base)))      T                wrap8(T);
template<class T> __attribute__((returns_nonnull)) T                wrap9(T);
```

All of these `wrapN()' functions should work the same, and none of them should
produce an error, but `wrap6()', `wrap7()' and `wrap8()' produce errors:
`returns_nonnull attribute on a function not returning a pointer'

I know that `__attribute__((copy(...)))' is a gcc extension, and this bug only
happens with g++, and I also know that it being an extension, it's correct
behavior isn't written in stone. But in this example, it's behavior is plainly
inconsistent (if `returns_nonnull' wasn't allowed with a template-dependent
return expression, then `wrap5()' and `wrap9()' should also cause errors, even
though they don't), and as already stated, _all_ of the above should work
without issues in my opinion.

I've placed this Report under c++ since this bug seems to be specific to the
combination of `template' + `__attribute__((copy))', where the template-part is
specific to c++. But if I had to guess, this is probably caused by a minor
difference in how `copy()' sets the `returns_nonnull' attribute vs. how
directly making use of `returns_nonnull' does the same.


Note: The same thing also happens with `__attribute((malloc))' and
`__attribute((nonnull(...)))' (in the case of `nonnull(...)', it even appears
to produce errors for _all_ template-functions that use `copy()' (`wrap5' and
`wrap9' continue to work correctly, so this is most definitely a problem with
`copy()')) (s.a. the attached `bug.cc`, which is replicated in the following):
```
__attribute__((returns_nonnull, malloc, nonnull(1))) void *base(void *);

                  __attribute__((copy(base)))             __typeof__((void *)0)
wrap1(decltype((void *)0));
                  __attribute__((copy(base)))               decltype((void *)0)
wrap2(decltype((void *)0));
template<class T> __attribute__((copy(base)))                  T              
*wrap3(decltype((T *)0));
template<class T> __attribute__((copy(base)))                  decltype(T())  
*wrap4(decltype((T *)0));
template<class T> __attribute__((returns_nonnull, nonnull(1))) decltype((T *)0)
wrap5(decltype((T *)0));
template<class T> __attribute__((copy(base)))                  decltype((T *)0)
wrap6(decltype((T *)0));
template<class T> __attribute__((copy(base)))                __typeof__((T *)0)
wrap7(decltype((T *)0));
template<class T> __attribute__((copy(base)))                  T               
wrap8(T);
template<class T> __attribute__((returns_nonnull, nonnull(1))) T               
wrap9(T);
```
The following are the errors produced by the above code. Note that inheriting
`__attribute__((malloc))' causes the `returns_nonnull` error to become
duplicated for `wrap6()', `wrap7()' and `wrap8()' for some reason (possibly an
unrelated bug), and that `wrap5()' and `wrap9()' (i.e. the declarations that
don't use `copy()') produces no errors or warnings:
```
[wrap3]: warning: 'nonnull' attribute argument value '1' refers to parameter
type 'decltype ((T*)(0))' [-Wattributes]
[wrap4]: warning: 'nonnull' attribute argument value '1' refers to parameter
type 'decltype ((T*)(0))' [-Wattributes]
[wrap6]: warning: 'malloc' attribute ignored [-Wattributes]
[wrap6]: warning: 'nonnull' attribute argument value '1' refers to parameter
type 'decltype ((T*)(0))' [-Wattributes]
[wrap6]: error: returns_nonnull attribute on a function not returning a pointer
[wrap6]: error: returns_nonnull attribute on a function not returning a pointer
[wrap7]: warning: 'malloc' attribute ignored [-Wattributes]
[wrap7]: warning: 'nonnull' attribute argument value '1' refers to parameter
type 'decltype ((T*)(0))' [-Wattributes]
[wrap7]: error: returns_nonnull attribute on a function not returning a pointer
[wrap7]: error: returns_nonnull attribute on a function not returning a pointer
[wrap8]: warning: 'malloc' attribute ignored [-Wattributes]
[wrap8]: warning: 'nonnull' attribute argument value '1' refers to parameter
type 'T' [-Wattributes]
[wrap8]: error: returns_nonnull attribute on a function not returning a pointer
[wrap8]: error: returns_nonnull attribute on a function not returning a pointer
```

Reply via email to