Hi,
this is an accepts-invalid issue about an explicit specialization
redeclared deleted. AFAICS, the problem is that start_decl sets
DECL_DELETED_FN on the fndecl too late, that is, *after* calling
grokdeclarator, whereas we want to have it set by the time the latter
calls grokfndecl, because then the problem can be diagnosed by
duplicate_decls (called by register_specialization via
check_explicit_specialization). The below solves the issue by passing
down the information about SD_DELETED from grokdeclator to grokfndecl.
Tested x86_64-linux.
Thanks,
Paolo.
///
/cp
2015-01-07 Paolo Carlini
PR c++/60753
* decl.c (grokfndecl): Add bool parameter.
(grokdeclarator): Adjust calls.
(start_decl): Don't set DECL_DELETED_FN here.
/testsuite
2015-01-07 Paolo Carlini
PR c++/60753
* g++.dg/cpp0x/deleted10.C: New.
Index: cp/decl.c
===
--- cp/decl.c (revision 219318)
+++ cp/decl.c (working copy)
@@ -4631,27 +4631,16 @@ start_decl (const cp_declarator *declarator,
if (context != global_namespace)
*pushed_scope_p = push_scope (context);
- if (initialized)
-/* Is it valid for this decl to have an initializer at all?
- If not, set INITIALIZED to zero, which will indirectly
- tell `cp_finish_decl' to ignore the initializer once it is parsed. */
-switch (TREE_CODE (decl))
- {
- case TYPE_DECL:
- error ("typedef %qD is initialized (use decltype instead)", decl);
- return error_mark_node;
+ /* Is it valid for this decl to have an initializer at all?
+ If not, set INITIALIZED to zero, which will indirectly
+ tell `cp_finish_decl' to ignore the initializer once it is parsed. */
+ if (initialized
+ && TREE_CODE (decl) == TYPE_DECL)
+{
+ error ("typedef %qD is initialized (use decltype instead)", decl);
+ return error_mark_node;
+}
- case FUNCTION_DECL:
- if (initialized == SD_DELETED)
- /* We'll handle the rest of the semantics later, but we need to
-set this now so it's visible to duplicate_decls. */
- DECL_DELETED_FN (decl) = 1;
- break;
-
- default:
- break;
- }
-
if (initialized)
{
if (! toplevel_bindings_p ()
@@ -7630,6 +7619,7 @@ grokfndecl (tree ctype,
int friendp,
int publicp,
int inlinep,
+ bool deletedp,
special_function_kind sfk,
bool funcdef_flag,
int template_count,
@@ -7768,6 +7758,9 @@ grokfndecl (tree ctype,
DECL_CONTEXT (decl) = ctype;
}
+ if (deletedp)
+DECL_DELETED_FN (decl) = 1;
+
if (ctype)
{
DECL_CONTEXT (decl) = ctype;
@@ -10756,7 +10749,7 @@ grokdeclarator (const cp_declarator *declarator,
virtualp, flags, memfn_quals, rqual, raises,
friendp ? -1 : 0, friendp, publicp,
inlinep | (2 * constexpr_p),
- sfk,
+ initialized == SD_DELETED, sfk,
funcdef_flag, template_count, in_namespace,
attrlist, declarator->id_loc);
decl = set_virt_specifiers (decl, virt_specifiers);
@@ -10978,7 +10971,8 @@ grokdeclarator (const cp_declarator *declarator,
decl = grokfndecl (ctype, type, original_name, parms, unqualified_id,
virtualp, flags, memfn_quals, rqual, raises,
1, friendp,
- publicp, inlinep | (2 * constexpr_p), sfk,
+ publicp, inlinep | (2 * constexpr_p),
+ initialized == SD_DELETED, sfk,
funcdef_flag,
template_count, in_namespace, attrlist,
declarator->id_loc);
Index: testsuite/g++.dg/cpp0x/deleted10.C
===
--- testsuite/g++.dg/cpp0x/deleted10.C (revision 0)
+++ testsuite/g++.dg/cpp0x/deleted10.C (working copy)
@@ -0,0 +1,15 @@
+// PR c++/60753
+// { dg-do compile { target c++11 } }
+
+template void foo (T);
+
+template<> void foo (int);
+template<> void foo (int) = delete; // { dg-error "deleted" }
+
+struct S
+{
+ template void bar (T);
+};
+
+template<> void S::bar (int);
+template<> void S::bar (int) = delete; // { dg-error "deleted" }