Bug 33911 - attribute deprecated vs. templates
Summary: attribute deprecated vs. templates
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.3.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: diagnostic
: 33912 36307 55557 (view as bug list)
Depends on:
Blocks:
 
Reported: 2007-10-26 15:08 UTC by Benjamin Kosnik
Modified: 2022-04-01 13:33 UTC (History)
13 users (show)

See Also:
Host: all
Target:
Build:
Known to work: 8.0
Known to fail:
Last reconfirmed: 2008-05-02 21:41:07


Attachments
patch (840 bytes, patch)
2014-11-11 17:52 UTC, Jason Merrill
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Benjamin Kosnik 2007-10-26 15:08:28 UTC
In the following example, class "foo" gets a deprecated warning, but a similar class template "goo" does not. Typedefs constructed with foo or goo get an error.

What up?


struct foo
{
  int i;
} __attribute__ ((__deprecated__));

template<typename _Tp>
struct goo
{
  int i;
} __attribute__ ((__deprecated__));

typedef foo foo_type __attribute__ ((__deprecated__));
typedef goo<int> goo_type __attribute__ ((__deprecated__));


int main()
{
  foo f1;
  goo<int> f2;

  foo_type f3;
  goo_type f4;

  return 0;
}


I have a patch to mark the C++0x bits deprecated, but it's not working because of this issue.
Comment 1 Paolo Carlini 2007-10-26 16:08:26 UTC
*** Bug 33912 has been marked as a duplicate of this bug. ***
Comment 2 niemayer 2007-12-20 14:32:56 UTC
I can second that problem for template member functions - in contrast to non-template member functions, where the attribute works.

This gives a warning about deprecation as expected:
-----------------------------------------------------------------
struct T { } ;

struct A {
	inline void foo(T & ) __attribute__((deprecated));
};

inline void A::foo(T & ) { }

void test(T & t) {
	A a;
	a.foo(t);
}
-------------------------------------------------------------

... while this is not causing a warning as it should:
-------------------------------------------------------------
struct A {
	template <class T> inline void foo(T & ) __attribute__((deprecated));
};

template <class T> inline void A::foo(T & ) { }

void test(A & t) {
	A a;
	a.foo(t);
}
-------------------------------------------------------------
Comment 3 Jason Merrill 2008-01-04 22:23:02 UTC
Subject: Re:  attribute deprecated vs. templates

niemayer at isg dot de wrote:
> I can second that problem for template member functions - in contrast to
> non-template member functions, where the attribute works.

This is a parser bug: parsing the member template declaration winds up 
in cp_parser_init_declarator, which ignores attributes at the end of a 
declaration.  A normal member function goes through 
cp_parser_member_declaration, which handles the attributes properly. 
You can work around this bug by moving the attribute into the 
decl-specifier-seq, i.e. "void __attribute ((deprecated)) foo(T&)".

Jason

Comment 4 Andrew Pinski 2008-12-28 03:17:42 UTC
*** Bug 36307 has been marked as a duplicate of this bug. ***
Comment 5 Jason Merrill 2009-11-05 23:08:54 UTC
Not planning to work on this soon since there's a reasonable workaround.
Comment 6 Paolo Carlini 2012-12-01 22:12:13 UTC
*** Bug 55557 has been marked as a duplicate of this bug. ***
Comment 7 Victor Gaydov 2012-12-02 08:16:04 UTC
I also have experienced bug 55557.

I'm porting a project that uses std::auto_ptr in several places to c++11. However, there are no deprecated warnings because it happened that every unit uses auto_ptr once.

If there is a workaround, may be it can be added to c++11 deprecated classes?
Comment 8 Paolo Carlini 2012-12-02 09:56:41 UTC
Personally, I'm not aware of any wa, if somebody finds one, please add it here, thanks.
Comment 9 Jonathan Wakely 2012-12-02 12:38:03 UTC
(In reply to comment #5)
> Not planning to work on this soon since there's a reasonable workaround.

Jason, that workaround is only for function templates, not class templates, right?

It's odd that the warning works for class templates except on the first instantiation (PR 55557)
Comment 10 Easwaran Raman 2013-10-01 00:06:09 UTC
For template member functions, is concatenating the parsed attributes to prefix_attributes and passing them to grokfield a valid fix? This patch works for a small test case I have and I wonder if this is correct:

Index: gcc/cp/parser.c
===================================================================
--- gcc/cp/parser.c	(revision 202261)
+++ gcc/cp/parser.c	(working copy)
@@ -16489,7 +16489,7 @@ cp_parser_init_declarator (cp_parser* parser,
       decl = grokfield (declarator, decl_specifiers,
 			initializer, !is_non_constant_init,
 			/*asmspec=*/NULL_TREE,
-			prefix_attributes);
+			chainon (prefix_attributes, attributes));
       if (decl && TREE_CODE (decl) == FUNCTION_DECL)
 	cp_parser_save_default_args (parser, decl);
     }
Comment 11 eraman 2013-10-03 17:39:37 UTC
Author: eraman
Date: Thu Oct  3 17:39:35 2013
New Revision: 203174

URL: http://gcc.gnu.org/viewcvs?rev=203174&root=gcc&view=rev
Log:
2013-10-03  Easwaran Raman  <eraman@google.com>

        PR c++/33911
        * parser.c (cp_parser_init_declarator): Do not drop attributes
        of template member functions.

2013-10-03  Easwaran Raman  <eraman@google.com>

        PR c++/33911
        * g++.dg/ext/attribute47.C: New.



Added:
    trunk/gcc/testsuite/g++.dg/ext/attrib47.C
Modified:
    trunk/gcc/cp/ChangeLog
    trunk/gcc/cp/parser.c
    trunk/gcc/testsuite/ChangeLog
Comment 12 Jonathan Wakely 2014-11-11 14:18:44 UTC
The comment below is from Richard Smith. I don't think we do have the same problem for abi_tag, so Jason must have solved this problem there.

--------

I was amazed to discover that clang has the *exact* same bug as gcc:

template<typename T> struct S {} __attribute__((deprecated));
S<int> s1; // no warning
S<int> s2; // warning, deprecated

Moving the attribute earlier makes no difference to either compiler.

And... I can tell you exactly why this is happening: when we see the use of S<int>, we instantiate the declaration. That does not instantiate attributes. The use is checked, it's not marked deprecated, so no warning occurs.

Then we perform initialization of s1. That triggers the instantiation of the definition and the attribute. But we don't use the name S<int> here; that already happened earlier.

Finally, we use S<int> again in the declaration of s2, and now we have both a use and an attribute, so we warn.

I'm not entirely sure what the right resolution is here. Maybe some attributes should be instantiated when we instantiate a class template specialization declaration, rather than delaying all of them until we instantiate the definition. I expect that your abi_tag attribute has the same bug, by the way, and if you never trigger the instantiation of the definition of basic_string<T>, then that type won't get an ABI tag. =)
Comment 13 Jonathan Wakely 2014-11-11 14:25:52 UTC
Also, even after the template definition (and the attribute) have been instantiated, typedefs for the instantiation don't get a warning unless the typedef itself is also marked deprecated:

template<typename T> struct S {} __attribute__((deprecated));
using Si = S<int>;
using Sd __attribute__((deprecated)) = S<int>;
S<int> s1; // no warning
S<int> s2; // warning, deprecated
Si s3; // no warning
Sd s4; // warning, deprecated

This means that users with a typedef for std::auto_ptr<int> will never get the warning, because libstdc++ can only add the attribute to the primary template, not to users' own typedefs.

This matters more now because WG21 just voted to remove auto_ptr from C++17 so we really want the deprecated attributes in libstdc++ to issue warnings.
Comment 14 Jason Merrill 2014-11-11 17:52:30 UTC
Created attachment 33938 [details]
patch

Here's a compiler patch.  Jonathan, can you decide what to do with the library testsuite regressions it introduces and check it in?
Comment 15 Jonathan Wakely 2014-11-12 10:32:50 UTC
Author: redi
Date: Wed Nov 12 10:32:17 2014
New Revision: 217412

URL: https://gcc.gnu.org/viewcvs?rev=217412&root=gcc&view=rev
Log:
Add -Wno-deprecated to dg-options.

	PR c++/33911
	* testsuite/20_util/shared_ptr/assign/auto_ptr.cc: Use -Wno-deprecated.
	* testsuite/20_util/shared_ptr/assign/auto_ptr_neg.cc: Likewise.
	* testsuite/20_util/shared_ptr/cons/43820_neg.cc: Likewise.
	* testsuite/20_util/shared_ptr/cons/auto_ptr.cc: Likewise.
	* testsuite/20_util/shared_ptr/cons/auto_ptr_neg.cc: Likewise.
	* testsuite/20_util/unique_ptr/cons/auto_ptr.cc: Likewise.
	* testsuite/20_util/unique_ptr/cons/auto_ptr_neg.cc: Likewise.
	* testsuite/ext/array_allocator/variadic_construct.cc: Likewise.

Modified:
    trunk/libstdc++-v3/ChangeLog
    trunk/libstdc++-v3/testsuite/20_util/shared_ptr/assign/auto_ptr.cc
    trunk/libstdc++-v3/testsuite/20_util/shared_ptr/assign/auto_ptr_neg.cc
    trunk/libstdc++-v3/testsuite/20_util/shared_ptr/cons/43820_neg.cc
    trunk/libstdc++-v3/testsuite/20_util/shared_ptr/cons/auto_ptr.cc
    trunk/libstdc++-v3/testsuite/20_util/shared_ptr/cons/auto_ptr_neg.cc
    trunk/libstdc++-v3/testsuite/20_util/unique_ptr/cons/auto_ptr.cc
    trunk/libstdc++-v3/testsuite/20_util/unique_ptr/cons/auto_ptr_neg.cc
    trunk/libstdc++-v3/testsuite/ext/array_allocator/variadic_construct.cc
Comment 16 Jonathan Wakely 2014-11-13 03:06:25 UTC
I've fixed most of the tests but I think the remaining ones reveal that the warning is a bit too eager:

template<typename T>
struct B
{
  B(T t) { }

} __attribute__ ((__deprecated__));

template<typename T>
B<T> b(T t)
{
  return B<T>(t);
}

int main()
{
}

dep.cc:9:11: warning: ‘B’ is deprecated (declared at dep.cc:2) [-Wdeprecated-declarations]
 B<T> b(T t)
           ^
dep.cc: In function ‘B<T> b(T)’:
dep.cc:11:16: warning: ‘B’ is deprecated (declared at dep.cc:2) [-Wdeprecated-declarations]
   return B<T>(t);
                ^

The warning comes even when b() isn't instantiated and can't be disabled with a #pragma.

I have no idea why this only affects 3 tests, not all the -std=gnu++11 tests, so maybe I should just add -D_GLIBCXX_USE_DEPRECATED=0 to the dg-options for those three tests to prevent the deprecated components being included.
Comment 17 Jason Merrill 2014-11-17 22:09:59 UTC
Author: jason
Date: Mon Nov 17 22:09:27 2014
New Revision: 217677

URL: https://gcc.gnu.org/viewcvs?rev=217677&root=gcc&view=rev
Log:
	PR c++/33911
gcc/cp/
	* call.c (build_call_a): Don't warn_deprecated_use here.
	(build_over_call): Or here.
	* decl2.c (mark_used): Do it here.
	(is_late_template_attribute): Attribute deprecated is not deferred.
	(cplus_decl_attributes): Propagate TREE_DEPRECATED out to the template.
	* parser.c (cp_parser_template_name): Warn about deprecated template.
	(cp_parser_template_argument): Likewise.
libstdc++-v3/
	* include/backward/binders.h: Suppress -Wdeprecated-declarations.
	* include/ext/array_allocator.h: Likewise.

Added:
    trunk/gcc/testsuite/g++.dg/ext/attr-deprecated-1.C
Modified:
    trunk/gcc/cp/ChangeLog
    trunk/gcc/cp/call.c
    trunk/gcc/cp/decl2.c
    trunk/gcc/cp/parser.c
    trunk/libstdc++-v3/ChangeLog
    trunk/libstdc++-v3/include/backward/binders.h
    trunk/libstdc++-v3/include/ext/array_allocator.h
Comment 18 Elias Pipping 2016-01-22 17:08:12 UTC
The current status (with gcc 5.3) of these deprecation warnings is quite surprising: from my point of view there are both false negatives and false positives. Since clang's behaviour, additionally, differs considerably from gcc's, it's currently almost impossible to deprecate something in a portable fashion.

Here's an example. Let's assume I've reimplemented enable_if and want to deprecated it.

namespace Dune {
  template<bool B, class T = void>
  struct [[deprecated]] enable_if
  {};

  template<class T>
  struct enable_if<true,T>
  {
    typedef T type;
  };
}

This generates a warning even if enable_if is never used anywhere, simply through the template specialisation (if I were to remove the specialisation, the warning would go away):

% g++ -c -std=c++14 test.cc -Wall -Wextra
test.cc:7:10: warning: ‘template<bool B, class T> struct Dune::enable_if’ is deprecated [-Wdeprecated-declarations]
   struct enable_if<true,T>
          ^
test.cc:3:25: note: declared here
   struct [[deprecated]] enable_if
                         ^
%

Clang does not emit a warning here.

Fair enough, maybe I should deprecate specialisations rather than the template. But this does not work as expected, either. The following code surprisingly does not emit a single warning:

#include <type_traits>

namespace Dune {
  template<bool B, class T = void>
  struct enable_if
  {};

  template<class T>
  struct [[deprecated]] enable_if<false,T>
  {};

  template<class T>
  struct [[deprecated]] enable_if<true,T>
  {
    typedef T type;
  };
}

int
main()
{
  using newint = Dune::enable_if<std::is_integral<int>::value,int>::type;
  newint i = 2;
  ++i;
}
Comment 19 Martin Sebor 2018-02-12 21:54:19 UTC
(In reply to Elias Pipping from comment #18)

In my view (while working on some fixes in this area), deprecating a primary template is a request to diagnose all uses of the template-id, including declarations of partial specializations and explicit specializations.  The way to achieve the effect you are looking for is to

1) declare the primary template without deprecated:

  template<bool B, class T = void> struct enable_if;

2) define one partial specialization deprecated:

  template<class T> struct [[deprecated]] enable_if<false, T> {};

3) define the complement of the first partial specialization that's not deprecated:

  template<class T> struct enable_if<true,T> { };

This should cause uses of the first (deprecated) partial specialization to be diagnosed.  This is also what Clang does.  GCC doesn't diagnose it because of bug 84347 but will once the bug is fixed.
Comment 20 Martin Sebor 2018-02-12 22:12:55 UTC
(In reply to Jonathan Wakely from comment #16)

Although Clang doesn't, warning for uses of a deprecated primary seems correct/useful to me because there's no way to define a specialization of the primary that's not deprecated.  In your test case, there is no specialization of  b() that would not use some specialization of the primary class template, and since every specialization is a use of the primary, that would not be subject to its deprecated attribute.  (It seems analogous to warning for an unused constexpr function that can never be used in a core constant expression.)

I've compiled all the test cases in this bug and, modulo bug(s) that are already being tracked elsewhere, they all result in the expected warnings.  With that I'm going to resolve this bug as fixed.

If you feel it's important to only warn for code that's instantiated, rather than reopening this bug I suggest opening a separate bug just for that.
Comment 21 Louis Dionne 2022-03-02 15:51:31 UTC
(In reply to Martin Sebor from comment #20)
> (In reply to Jonathan Wakely from comment #16)
> 
> Although Clang doesn't, warning for uses of a deprecated primary seems
> correct/useful to me because there's no way to define a specialization of
> the primary that's not deprecated.  In your test case, there is no
> specialization of  b() that would not use some specialization of the primary
> class template, and since every specialization is a use of the primary, that
> would not be subject to its deprecated attribute.  (It seems analogous to
> warning for an unused constexpr function that can never be used in a core
> constant expression.)

I believe it is important to *not* diagnose when the template is never instantiated. Indeed, imagine a library is providing these declarations. It needs to keep them around for backwards compatibility, but it also wants to mark them as deprecated to make sure that no users actually use them.

With the current state of affairs, GCC will issue a warning just because the declarations exist and are marked as deprecated, even if the user doesn't actually use these declarations. This is not useful behavior -- it ends up being so noisy that the only reasonable solution is to remove deprecation warnings altogether, which defeats the whole thing. This is exactly what we're hitting with libc++ on GCC right now. I think it would be worth reconsidering the resolution of this issue to make GCC's behavior match Clang's behavior more closely.

> If you feel it's important to only warn for code that's instantiated, rather
> than reopening this bug I suggest opening a separate bug just for that.

See https://gcc.gnu.org/PR104760.