diff mbox

fold_builtin_FUNCTION

Message ID 4ab13a95-0131-3ecc-6167-3517b2ce7ab4@acm.org
State New
Headers show

Commit Message

Nathan Sidwell June 29, 2017, 2:03 p.m. UTC
I notied the __builtin_FUNCTION () builtin was using raw DECL_NAME,
which for C++ dtors and conversion operators gives non-useful names.
(no ~ and 'operator N' for N= some int).

This patch fixes its folder to use the lang hook that provides a 
printable name.  I did contemplate passing 1 (add scope) to the hook, 
but decided against changing that.

Applied as obvious.

nathan
diff mbox

Patch

diff -p -U2 -r ./builtins.c /data/users/nathans/modules/src/gcc/builtins.c
--- ./builtins.c	2017-06-26 07:48:42.206366313 -0700
+++ /data/users/nathans/modules/src/gcc/builtins.c	2017-06-28 13:52:53.026518086 -0700
@@ -8740,11 +8740,10 @@  static inline tree
 fold_builtin_FUNCTION ()
 {
+  const char *name = "";
+
   if (current_function_decl)
-    {
-      const char *name = IDENTIFIER_POINTER (DECL_NAME (current_function_decl));
-      return build_string_literal (strlen (name) + 1, name);
-    }
+    name= lang_hooks.decl_printable_name (current_function_decl, 0);
 
-  return build_string_literal (1, "");
+  return build_string_literal (strlen (name) + 1, name);
 }
 
diff -p -U2 -r ./cp/call.c /data/users/nathans/modules/src/gcc/cp/call.c
--- ./cp/call.c	2017-06-27 08:34:25.902966687 -0700
+++ /data/users/nathans/modules/src/gcc/cp/call.c	2017-06-28 12:05:23.188713566 -0700
@@ -232,7 +232,6 @@  check_dtor_name (tree basetype, tree nam
     {
       if ((MAYBE_CLASS_TYPE_P (basetype)
-	   && name == constructor_name (basetype))
-	  || (TREE_CODE (basetype) == ENUMERAL_TYPE
-	      && name == TYPE_IDENTIFIER (basetype)))
+	   || TREE_CODE (basetype) == ENUMERAL_TYPE)
+	  && name == constructor_name (basetype))
 	return true;
       else
@@ -8879,5 +8878,5 @@  static char *
 name_as_c_string (tree name, tree type, bool *free_p)
 {
-  char *pretty_name;
+  const char *pretty_name;
 
   /* Assume that we will not allocate memory.  */
@@ -8887,5 +8886,5 @@  name_as_c_string (tree name, tree type,
     {
       pretty_name
-	= CONST_CAST (char *, identifier_to_locale (IDENTIFIER_POINTER (constructor_name (type))));
+	= identifier_to_locale (IDENTIFIER_POINTER (constructor_name (type)));
       /* For a destructor, add the '~'.  */
       if (IDENTIFIER_DTOR_P (name))
@@ -8906,7 +8905,7 @@  name_as_c_string (tree name, tree type,
     }
   else
-    pretty_name = CONST_CAST (char *, identifier_to_locale (IDENTIFIER_POINTER (name)));
+    pretty_name = identifier_to_locale (IDENTIFIER_POINTER (name));
 
-  return pretty_name;
+  return CONST_CAST (char *, pretty_name);
 }
 
@@ -9119,9 +9115,8 @@  build_new_method_call_1 (tree instance,
     }
   else
-    {
-      add_candidates (fns, first_mem_arg, user_args, optype,
-		      explicit_targs, template_only, conversion_path,
-		      access_binfo, flags, &candidates, complain);
-    }
+    add_candidates (fns, first_mem_arg, user_args, optype,
+		    explicit_targs, template_only, conversion_path,
+		    access_binfo, flags, &candidates, complain);
+
   any_viable_p = false;
   candidates = splice_viable (candidates, false, &any_viable_p);
@@ -9141,8 +9136,9 @@  build_new_method_call_1 (tree instance,
 	      tree arglist = build_tree_list_vec (user_args);
 	      tree errname = name;
+	      bool twiddle = false;
 	      if (IDENTIFIER_CDTOR_P (errname))
 		{
-		  tree fn = DECL_ORIGIN (OVL_FIRST (fns));
-		  errname = DECL_NAME (fn);
+		  twiddle = IDENTIFIER_DTOR_P (errname);
+		  errname = constructor_name (basetype);
 		}
 	      if (explicit_targs)
@@ -9150,6 +9146,6 @@  build_new_method_call_1 (tree instance,
 	      if (skip_first_for_error)
 		arglist = TREE_CHAIN (arglist);
-	      error ("no matching function for call to %<%T::%E(%A)%#V%>",
-		     basetype, errname, arglist,
+	      error ("no matching function for call to %<%T::%s%E(%A)%#V%>",
+		     basetype, &"~"[!twiddle], errname, arglist,
 		     TREE_TYPE (instance));
 	    }
diff -p -U2 -r ./cp/class.c /data/users/nathans/modules/src/gcc/cp/class.c
--- ./cp/class.c	2017-06-27 08:33:21.756909868 -0700
+++ /data/users/nathans/modules/src/gcc/cp/class.c	2017-06-28 15:50:01.612979147 -0700
@@ -6296,6 +6240,5 @@  include_empty_classes (record_layout_inf
      offset.  However, now we need to make sure that RLI is big enough
      to reflect the entire class.  */
-  eoc = end_of_class (rli->t,
-		      CLASSTYPE_AS_BASE (rli->t) != NULL_TREE);
+  eoc = end_of_class (rli->t, CLASSTYPE_AS_BASE (rli->t) != NULL_TREE);
   rli_size = rli_size_unit_so_far (rli);
   if (TREE_CODE (rli_size) == INTEGER_CST
@@ -7445,5 +7342,5 @@  finish_struct (tree t, tree attributes)
 	  {
 	    tree fn = strip_using_decl (x);
-	    if (is_overloaded_fn (fn))
+  	    if (OVL_P (fn))
 	      for (lkp_iterator iter (fn); iter; ++iter)
 		add_method (t, *iter, true);
@@ -8506,5 +8403,4 @@  get_vfield_name (tree type)
 {
   tree binfo, base_binfo;
-  char *buf;
 
   for (binfo = TYPE_BINFO (type);
@@ -8520,8 +8416,8 @@  get_vfield_name (tree type)
 
   type = BINFO_TYPE (binfo);
-  buf = (char *) alloca (sizeof (VFIELD_NAME_FORMAT)
-			 + TYPE_NAME_LENGTH (type) + 2);
-  sprintf (buf, VFIELD_NAME_FORMAT,
-	   IDENTIFIER_POINTER (constructor_name (type)));
+  tree ctor_name = constructor_name (type);
+  char *buf = (char *) alloca (sizeof (VFIELD_NAME_FORMAT)
+			       + IDENTIFIER_LENGTH (ctor_name) + 2);
+  sprintf (buf, VFIELD_NAME_FORMAT, IDENTIFIER_POINTER (ctor_name));
   return get_identifier (buf);
 }
@@ -8553,7 +8449,6 @@  void
 build_self_reference (void)
 {
-  tree name = constructor_name (current_class_type);
+  tree name = DECL_NAME (TYPE_NAME (current_class_type));
   tree value = build_lang_decl (TYPE_DECL, name, current_class_type);
-  tree saved_cas;
 
   DECL_NONLOCAL (value) = 1;
@@ -8566,5 +8461,5 @@  build_self_reference (void)
     value = push_template_decl (value);
 
-  saved_cas = current_access_specifier;
+  tree saved_cas = current_access_specifier;
   current_access_specifier = access_public_node;
   finish_member_declaration (value);
diff -p -U2 -r ./cp/constraint.cc /data/users/nathans/modules/src/gcc/cp/constraint.cc
--- ./cp/constraint.cc	2017-06-19 11:07:28.043486829 -0700
+++ /data/users/nathans/modules/src/gcc/cp/constraint.cc	2017-06-19 11:38:31.769616147 -0700
@@ -1581,5 +1581,5 @@  tsubst_check_constraint (tree t, tree ar
   /* Substitute through by building an template-id expression
      and then substituting into that. */
-  tree expr = build_nt(TEMPLATE_ID_EXPR, tmpl, targs);
+  tree expr = build_nt (TEMPLATE_ID_EXPR, tmpl, targs);
   ++processing_template_decl;
   tree result = tsubst_expr (expr, args, complain, in_decl, false);
diff -p -U2 -r ./cp/cp-tree.h /data/users/nathans/modules/src/gcc/cp/cp-tree.h
--- ./cp/cp-tree.h	2017-06-29 04:12:52.660865522 -0700
+++ /data/users/nathans/modules/src/gcc/cp/cp-tree.h	2017-06-29 04:13:38.133894202 -0700
@@ -1815,5 +1887,5 @@  enum languages { lang_c, lang_cplusplus
    union type.  */
 #define SET_CLASS_TYPE_P(T, VAL) \
-  (TYPE_LANG_FLAG_5 (T) = (VAL))
+  (TYPE_LANG_FLAG_5 (RECORD_OR_UNION_CHECK (T)) = (VAL))
 
 /* Nonzero if T is a class type.  Zero for template type parameters,
@@ -1824,5 +1896,5 @@  enum languages { lang_c, lang_cplusplus
 /* Nonzero if T is a class type but not an union.  */
 #define NON_UNION_CLASS_TYPE_P(T) \
-  (CLASS_TYPE_P (T) && TREE_CODE (T) != UNION_TYPE)
+  (TREE_CODE (T) == RECORD_TYPE && TYPE_LANG_FLAG_5 (T))
 
 /* Keep these checks in ascending code order.  */
@@ -2557,5 +2631,7 @@  struct GTY(()) lang_decl_ns {
   vec<tree, va_gc> *inlinees;
 
-  /* Map from IDENTIFIER nodes to DECLS.  */
+  /* Map from IDENTIFIER nodes to DECLS.  It'd be nice to have this
+     inline, but as the hash_map has a dtor, we can't then put this
+     struct into a union (until moving to c++11).  */
   hash_map<lang_identifier *, tree> *bindings;
 };
@@ -4313,5 +4383,6 @@  more_aggr_init_expr_args_p (const aggr_i
 /* For a pointer-to-member constant `X::Y' this is the _DECL for
    `Y'.  */
-#define PTRMEM_CST_MEMBER(NODE) (((ptrmem_cst_t)PTRMEM_CST_CHECK (NODE))->member)
+#define PTRMEM_CST_MEMBER(NODE) \
+  (((ptrmem_cst_t)PTRMEM_CST_CHECK (NODE))->member)
 
 /* The expression in question for a TYPEOF_TYPE.  */
@@ -5193,12 +5264,4 @@  extern GTY(()) vec<tree, va_gc> *keyed_c
 #endif	/* NO_DOT_IN_LABEL */
 
-#define THIS_NAME "this"
-
-#define IN_CHARGE_NAME "__in_chrg"
-
-#define VTBL_PTR_TYPE		"__vtbl_ptr_type"
-#define VTABLE_DELTA_NAME	"__delta"
-#define VTABLE_PFN_NAME		"__pfn"
-
 #define LAMBDANAME_PREFIX "__lambda"
 #define LAMBDANAME_FORMAT LAMBDANAME_PREFIX "%d"
diff -p -U2 -r ./cp/cxx-pretty-print.c /data/users/nathans/modules/src/gcc/cp/cxx-pretty-print.c
--- ./cp/cxx-pretty-print.c	2017-06-22 10:39:31.897661992 -0700
+++ /data/users/nathans/modules/src/gcc/cp/cxx-pretty-print.c	2017-06-27 12:53:41.365646106 -0700
@@ -89,12 +89,4 @@  pp_cxx_separate_with (cxx_pretty_printer
 /* Expressions.  */
 
-static inline bool
-is_destructor_name (tree name)
-{
-  return name == complete_dtor_identifier
-    || name == base_dtor_identifier
-    || name == deleting_dtor_identifier;
-}
-
 /* conversion-function-id:
       operator conversion-type-id
@@ -163,14 +155,5 @@  pp_cxx_unqualified_id (cxx_pretty_printe
 	pp_cxx_conversion_function_id (pp, t);
       else
-	{
-	  if (is_destructor_name (t))
-	    {
-	      pp_complement (pp);
-	      /* FIXME: Why is this necessary? */
-	      if (TREE_TYPE (t))
-		t = constructor_name (TREE_TYPE (t));
-	    }
-	  pp_cxx_tree_identifier (pp, t);
-	}
+	pp_cxx_tree_identifier (pp, t);
       break;
 
diff -p -U2 -r ./cp/decl.c /data/users/nathans/modules/src/gcc/cp/decl.c
--- ./cp/decl.c	2017-06-29 04:12:52.657865521 -0700
+++ /data/users/nathans/modules/src/gcc/cp/decl.c	2017-06-29 04:13:36.819893373 -0700
@@ -3956,14 +3965,14 @@  initialize_predefined_identifiers (void)
        impossible for them to conflict with names written by users.  */
     {"__ct ", &ctor_identifier, cik_ctor},
-    {"__base_ctor ", &base_ctor_identifier, cik_ctor},
-    {"__comp_ctor ", &complete_ctor_identifier, cik_ctor},
+    {"__ct_base ", &base_ctor_identifier, cik_ctor},
+    {"__ct_comp ", &complete_ctor_identifier, cik_ctor},
     {"__dt ", &dtor_identifier, cik_dtor},
-    {"__comp_dtor ", &complete_dtor_identifier, cik_dtor},
-    {"__base_dtor ", &base_dtor_identifier, cik_dtor},
-    {"__deleting_dtor ", &deleting_dtor_identifier, cik_dtor},
-    {IN_CHARGE_NAME, &in_charge_identifier, cik_normal},
-    {THIS_NAME, &this_identifier, cik_normal},
-    {VTABLE_DELTA_NAME, &delta_identifier, cik_normal},
-    {VTABLE_PFN_NAME, &pfn_identifier, cik_normal},
+    {"__dt_base ", &base_dtor_identifier, cik_dtor},
+    {"__dt_comp ", &complete_dtor_identifier, cik_dtor},
+    {"__dt_del ", &deleting_dtor_identifier, cik_dtor},
+    {"__in_chrg", &in_charge_identifier, cik_normal},
+    {"this", &this_identifier, cik_normal},
+    {"__delta", &delta_identifier, cik_normal},
+    {"__pfn", &pfn_identifier, cik_normal},
     {"_vptr", &vptr_identifier, cik_normal},
     {"__vtt_parm", &vtt_parm_identifier, cik_normal},
@@ -4095,5 +4111,5 @@  cxx_init_decl_processing (void)
     vtable_entry_type = build_pointer_type (vfunc_type);
   }
-  record_builtin_type (RID_MAX, VTBL_PTR_TYPE, vtable_entry_type);
+  record_builtin_type (RID_MAX, "__vtbl_ptr_type", vtable_entry_type);
 
   vtbl_type_node
@@ -8503,7 +8515,9 @@  grokfndecl (tree ctype,
       SET_DECL_ALIGN (decl, MINIMUM_METHOD_BOUNDARY);
     }
+
   DECL_ARGUMENTS (decl) = parms;
   for (t = parms; t; t = DECL_CHAIN (t))
     DECL_CONTEXT (t) = decl;
+
   /* Propagate volatile out from type to decl.  */
   if (TYPE_VOLATILE (type))
@@ -8525,11 +8541,9 @@  grokfndecl (tree ctype,
     }
 
-  if (friendp
-      && TREE_CODE (orig_declarator) == TEMPLATE_ID_EXPR)
+  if (friendp && TREE_CODE (orig_declarator) == TEMPLATE_ID_EXPR)
     {
       if (funcdef_flag)
-	error
-	  ("defining explicit specialization %qD in friend declaration",
-	   orig_declarator);
+	error ("defining explicit specialization %qD in friend declaration",
+	       orig_declarator);
       else
 	{
@@ -8581,14 +8595,16 @@  grokfndecl (tree ctype,
 
   /* `main' and builtins have implicit 'C' linkage.  */
-  if ((MAIN_NAME_P (declarator)
-       || (IDENTIFIER_LENGTH (declarator) > 10
-	   && IDENTIFIER_POINTER (declarator)[0] == '_'
-	   && IDENTIFIER_POINTER (declarator)[1] == '_'
-	   && strncmp (IDENTIFIER_POINTER (declarator)+2, "builtin_", 8) == 0)
-       || (targetcm.cxx_implicit_extern_c
-	   && targetcm.cxx_implicit_extern_c(IDENTIFIER_POINTER (declarator))))
+  if (ctype == NULL_TREE
+      && DECL_FILE_SCOPE_P (decl)
       && current_lang_name == lang_name_cplusplus
-      && ctype == NULL_TREE
-      && DECL_FILE_SCOPE_P (decl))
+      && (MAIN_NAME_P (declarator)
+	  || (IDENTIFIER_LENGTH (declarator) > 10
+	      && IDENTIFIER_POINTER (declarator)[0] == '_'
+	      && IDENTIFIER_POINTER (declarator)[1] == '_'
+	      && strncmp (IDENTIFIER_POINTER (declarator)+2,
+			  "builtin_", 8) == 0)
+	  || (targetcm.cxx_implicit_extern_c
+	      && (targetcm.cxx_implicit_extern_c
+		  (IDENTIFIER_POINTER (declarator))))))
     SET_DECL_LANGUAGE (decl, lang_c);
 
@@ -9133,5 +9151,4 @@  build_ptrmemfunc_type (tree type)
      simple equality check on the list of field members.  */
 
-
   t = TYPE_PTRMEMFUNC_TYPE (type);
   if (t)
@@ -10069,6 +10086,4 @@  grokdeclarator (const cp_declarator *dec
 	      case BIT_NOT_EXPR:
 		{
-		  tree type;
-
 		  if (innermost_code != cdk_function)
 		    {
@@ -10083,5 +10098,5 @@  grokdeclarator (const cp_declarator *dec
 		    }
 
-		  type = TREE_OPERAND (decl, 0);
+		  tree type = TREE_OPERAND (decl, 0);
 		  if (TYPE_P (type))
 		    type = constructor_name (type);
diff -p -U2 -r ./cp/decl2.c /data/users/nathans/modules/src/gcc/cp/decl2.c
--- ./cp/decl2.c	2017-06-20 05:56:53.977776790 -0700
+++ /data/users/nathans/modules/src/gcc/cp/decl2.c	2017-06-22 08:40:53.100097292 -0700
@@ -1993,5 +1995,6 @@  decl_needed_p (tree decl)
      whether or not to emit it into the object file.  */
   if (TREE_USED (decl))
-      return true;
+    return true;
+
   /* Virtual functions might be needed for devirtualization.  */
   if (flag_devirtualize
@@ -1999,4 +2002,5 @@  decl_needed_p (tree decl)
       && DECL_VIRTUAL_P (decl))
     return true;
+
   /* Otherwise, DECL does not need to be emitted -- yet.  A subsequent
      reference to DECL might cause it to be emitted later.  */
@@ -4804,5 +4806,4 @@  c_parse_final_cleanups (void)
 
   finish_repo ();
-
   fini_constexpr ();
 
Only in /data/users/nathans/modules/src/gcc/cp: fnfields.diff
diff -p -U2 -r ./cp/lex.c /data/users/nathans/modules/src/gcc/cp/lex.c
--- ./cp/lex.c	2017-06-28 06:34:12.298399329 -0700
+++ /data/users/nathans/modules/src/gcc/cp/lex.c	2017-06-22 10:01:29.141924137 -0700
@@ -739,22 +741,22 @@  copy_type (tree type MEM_STAT_DECL)
 /* Add a raw lang_type to T, a type, should it need one.  */
 
-static bool
+static bool
 maybe_add_lang_type_raw (tree t)
 {
-  bool add = (RECORD_OR_UNION_CODE_P (TREE_CODE (t))
-	      || TREE_CODE (t) == BOUND_TEMPLATE_TEMPLATE_PARM);
-  if (add)
-    {
-      TYPE_LANG_SPECIFIC (t)
-	= (struct lang_type *) (ggc_internal_cleared_alloc
-				(sizeof (struct lang_type)));
+  if (!(RECORD_OR_UNION_CODE_P (TREE_CODE (t))
+	|| TREE_CODE (t) == BOUND_TEMPLATE_TEMPLATE_PARM))
+    return false;
+  
+  TYPE_LANG_SPECIFIC (t)
+    = (struct lang_type *) (ggc_internal_cleared_alloc
+			    (sizeof (struct lang_type)));
 
-      if (GATHER_STATISTICS)
-	{
-	  tree_node_counts[(int)lang_type] += 1;
-	  tree_node_sizes[(int)lang_type] += sizeof (struct lang_type);
-	}
+  if (GATHER_STATISTICS)
+    {
+      tree_node_counts[(int)lang_type] += 1;
+      tree_node_sizes[(int)lang_type] += sizeof (struct lang_type);
     }
-  return add;
+
+  return true;
 }
 
Only in /data/users/nathans/modules/src/gcc/cp: method-vec-wip.diff
diff -p -U2 -r ./cp/method.c /data/users/nathans/modules/src/gcc/cp/method.c
--- ./cp/method.c	2017-06-26 07:48:57.522383330 -0700
+++ /data/users/nathans/modules/src/gcc/cp/method.c	2017-06-28 11:20:24.519984085 -0700
@@ -1983,5 +1983,4 @@  implicitly_declare_fn (special_function_
     case sfk_inheriting_constructor:
     {
-      bool move_p;
       if (kind == sfk_copy_assignment
 	  || kind == sfk_move_assignment)
@@ -2001,6 +2000,6 @@  implicitly_declare_fn (special_function_
 	  else
 	    rhs_parm_type = type;
-	  move_p = (kind == sfk_move_assignment
-		    || kind == sfk_move_constructor);
+	  bool move_p = (kind == sfk_move_assignment
+			 || kind == sfk_move_constructor);
 	  rhs_parm_type = cp_build_reference_type (rhs_parm_type, move_p);
 
diff -p -U2 -r ./cp/name-lookup.c /data/users/nathans/modules/src/gcc/cp/name-lookup.c
--- ./cp/name-lookup.c	2017-06-27 07:47:20.224342991 -0700
+++ /data/users/nathans/modules/src/gcc/cp/name-lookup.c	2017-06-28 09:52:50.840498101 -0700
@@ -3189,5 +3724,7 @@  tree
 constructor_name (tree type)
 {
-  return TYPE_IDENTIFIER (TYPE_MAIN_VARIANT (type));
+  tree decl = TYPE_NAME (TYPE_MAIN_VARIANT (type));
+
+  return decl ? DECL_NAME (decl) : NULL_TREE;
 }
 
@@ -3200,10 +3737,4 @@  constructor_name_p (tree name, tree type
   gcc_assert (MAYBE_CLASS_TYPE_P (type));
 
-  if (!name)
-    return false;
-
-  if (!identifier_p (name))
-    return false;
-
   /* These don't have names.  */
   if (TREE_CODE (type) == DECLTYPE_TYPE
@@ -3211,6 +3742,5 @@  constructor_name_p (tree name, tree type
     return false;
 
-  tree ctor_name = constructor_name (type);
-  if (name == ctor_name)
+  if (name && name == constructor_name (type))
     return true;
 
@@ -3963,5 +4579,5 @@  push_class_level_binding_1 (tree name, t
        || (TREE_CODE (x) == FIELD_DECL
 	   && DECL_CONTEXT (x) != current_class_type))
-      && DECL_NAME (x) == constructor_name (current_class_type))
+      && DECL_NAME (x) == DECL_NAME (TYPE_NAME (current_class_type)))
     {
       tree scope = context_for_name_lookup (x);
diff -p -U2 -r ./cp/parser.c /data/users/nathans/modules/src/gcc/cp/parser.c
--- ./cp/parser.c	2017-06-29 04:12:52.659865522 -0700
+++ /data/users/nathans/modules/src/gcc/cp/parser.c	2017-06-29 04:13:37.953894088 -0700
@@ -20107,24 +20308,6 @@  cp_parser_direct_declarator (cp_parser*
 		  {
 		    tree name_type = TREE_TYPE (unqualified_name);
-		    if (class_type && same_type_p (name_type, class_type))
-		      {
-			if (qualifying_scope
-			    && CLASSTYPE_USE_TEMPLATE (name_type))
-			  {
-			    error_at (declarator_id_start_token->location,
-				      "invalid use of constructor as a template");
-			    inform (declarator_id_start_token->location,
-				    "use %<%T::%D%> instead of %<%T::%D%> to "
-				    "name the constructor in a qualified name",
-				    class_type,
-				    DECL_NAME (TYPE_TI_TEMPLATE (class_type)),
-				    class_type, name_type);
-			    declarator = cp_error_declarator;
-			    break;
-			  }
-			else
-			  unqualified_name = constructor_name (class_type);
-		      }
-		    else
+
+		    if (!class_type || !same_type_p (name_type, class_type))
 		      {
 			/* We do not attempt to print the declarator
@@ -20136,4 +20319,19 @@  cp_parser_direct_declarator (cp_parser*
 			break;
 		      }
+		    else if (qualifying_scope
+			     && CLASSTYPE_USE_TEMPLATE (name_type))
+		      {
+			error_at (declarator_id_start_token->location,
+				  "invalid use of constructor as a template");
+			inform (declarator_id_start_token->location,
+				"use %<%T::%D%> instead of %<%T::%D%> to "
+				"name the constructor in a qualified name",
+				class_type,
+				DECL_NAME (TYPE_TI_TEMPLATE (class_type)),
+				class_type, name_type);
+			declarator = cp_error_declarator;
+			break;
+		      }
+		    unqualified_name = constructor_name (class_type);
 		  }
 
@@ -20165,12 +20363,8 @@  cp_parser_direct_declarator (cp_parser*
 				  friend void N::S();
 				};  */
-			     && !(friend_p
-				  && class_type != qualifying_scope)
+			     && (!friend_p || class_type == qualifying_scope)
 			     && constructor_name_p (unqualified_name,
 						    class_type))
-		      {
-			unqualified_name = constructor_name (class_type);
-			sfk = sfk_constructor;
-		      }
+		      sfk = sfk_constructor;
 		    else if (is_overloaded_fn (unqualified_name)
 			     && DECL_CONSTRUCTOR_P (get_first_fn
diff -p -U2 -r ./cp/search.c /data/users/nathans/modules/src/gcc/cp/search.c
--- ./cp/search.c	2017-06-27 08:35:45.619037145 -0700
+++ /data/users/nathans/modules/src/gcc/cp/search.c	2017-06-28 15:41:44.447588266 -0700
@@ -508,8 +458,11 @@  current_scope (void)
 			      current_class_type))))
     return current_function_decl;
+
   if (current_class_type)
     return current_class_type;
+
   if (current_function_decl)
     return current_function_decl;
+
   return current_namespace;
 }
Only in /data/users/nathans/modules/src/gcc/testsuite/g++.dg/cpp1y: builtin_FUNCTION.C