From 3bb1ed661a7dc49c4536613d430699d124641b10 Mon Sep 17 00:00:00 2001
From: Nathan Sidwell <nathan@codesourcery.com>
Date: Tue, 8 Jun 2010 09:59:10 +0000
Subject: [PATCH] decl.c (record_key_method_defined): New, broken out of ...

	cp/
	* decl.c (record_key_method_defined): New, broken out of ...
	(finish_function): ... here.  Call it.
	(start_decl): Treat aliases as definitions.

	testsuite/
	* g++.dg/ext/attr-alias-1.C: New.
	* g++.dg/ext/attr-alias-2.C: New.

From-SVN: r160431
---
 gcc/cp/ChangeLog                        |  6 ++++
 gcc/cp/decl.c                           | 35 +++++++++++++++++------
 gcc/testsuite/ChangeLog                 |  5 ++++
 gcc/testsuite/g++.dg/ext/attr-alias-1.C | 37 +++++++++++++++++++++++++
 gcc/testsuite/g++.dg/ext/attr-alias-2.C | 37 +++++++++++++++++++++++++
 5 files changed, 111 insertions(+), 9 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/ext/attr-alias-1.C
 create mode 100644 gcc/testsuite/g++.dg/ext/attr-alias-2.C

diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 931cbe141ebe..3bb19a09af08 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,9 @@
+2010-06-08  Nathan Sidwell  <nathan@codesourcery.com>
+
+	* decl.c (record_key_method_defined): New, broken out of ...
+	(finish_function): ... here.  Call it.	
+	(start_decl): Treat aliases as definitions.
+
 2010-06-08  Laurynas Biveinis  <laurynas.biveinis@gmail.com>
 
 	* typeck2.c (abstract_virtuals_error): Use typed GC allocation.
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 706eee9b6669..ca3152f9caf6 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -90,6 +90,7 @@ static void check_function_type (tree, tree);
 static void finish_constructor_body (void);
 static void begin_destructor_body (void);
 static void finish_destructor_body (void);
+static void record_key_method_defined (tree);
 static tree create_array_type_for_decl (tree, tree, tree);
 static tree get_atexit_node (void);
 static tree get_dso_handle_node (void);
@@ -4129,6 +4130,7 @@ start_decl (const cp_declarator *declarator,
   tree context;
   bool was_public;
   int flags;
+  bool alias;
 
   *pushed_scope_p = NULL_TREE;
 
@@ -4190,6 +4192,10 @@ start_decl (const cp_declarator *declarator,
       if (toplevel_bindings_p ())
 	TREE_STATIC (decl) = 1;
     }
+  alias = lookup_attribute ("alias", DECL_ATTRIBUTES (decl)) != 0;
+  
+  if (alias && TREE_CODE (decl) == FUNCTION_DECL)
+    record_key_method_defined (decl);
 
   /* If this is a typedef that names the class for linkage purposes
      (7.1.3p8), apply any attributes directly to the type.  */
@@ -4292,7 +4298,9 @@ start_decl (const cp_declarator *declarator,
 	    DECL_EXTERNAL (decl) = 1;
 	}
 
-      if (DECL_EXTERNAL (decl) && ! DECL_TEMPLATE_SPECIALIZATION (decl))
+      if (DECL_EXTERNAL (decl) && ! DECL_TEMPLATE_SPECIALIZATION (decl)
+	  /* Aliases are definitions. */
+	  && !alias)
 	permerror (input_location, "declaration of %q#D outside of class is not definition",
 		   decl);
 
@@ -12502,6 +12510,22 @@ outer_curly_brace_block (tree fndecl)
   return block;
 }
 
+/* If FNDECL is a class's key method, add the class to the list of
+   keyed classes that should be emitted.  */
+
+static void
+record_key_method_defined (tree fndecl)
+{
+  if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fndecl)
+      && DECL_VIRTUAL_P (fndecl)
+      && !processing_template_decl)
+    {
+      tree fnclass = DECL_CONTEXT (fndecl);
+      if (fndecl == CLASSTYPE_KEY_METHOD (fnclass))
+	keyed_classes = tree_cons (NULL_TREE, fnclass, keyed_classes);
+    }
+}
+
 /* Finish up a function declaration and compile that function
    all the way to assembler language output.  The free the storage
    for the function definition.
@@ -12528,14 +12552,7 @@ finish_function (int flags)
   gcc_assert (!defer_mark_used_calls);
   defer_mark_used_calls = true;
 
-  if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fndecl)
-      && DECL_VIRTUAL_P (fndecl)
-      && !processing_template_decl)
-    {
-      tree fnclass = DECL_CONTEXT (fndecl);
-      if (fndecl == CLASSTYPE_KEY_METHOD (fnclass))
-	keyed_classes = tree_cons (NULL_TREE, fnclass, keyed_classes);
-    }
+  record_key_method_defined (fndecl);
 
   nested = function_depth > 1;
   fntype = TREE_TYPE (fndecl);
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 239ef3eead6e..284bbc951fbb 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2010-06-08  Nathan Sidwell  <nathan@codesourcery.com>
+
+	* g++.dg/ext/attr-alias-1.C: New.
+	* g++.dg/ext/attr-alias-2.C: New.
+
 2010-06-07  Tobias Burnus  <burnus@net-b.de>
 
 	PR fortran/44446
diff --git a/gcc/testsuite/g++.dg/ext/attr-alias-1.C b/gcc/testsuite/g++.dg/ext/attr-alias-1.C
new file mode 100644
index 000000000000..1427267e5173
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/attr-alias-1.C
@@ -0,0 +1,37 @@
+/* { dg-do run }  */
+/* { dg-require-alias "" } */
+
+#include <typeinfo>
+
+struct Klass
+{
+  int implementation () const;
+  int magic () const;
+};
+
+int Klass::implementation (void) const
+{
+  return 0;
+}
+
+int Klass::magic () const
+  __attribute__ ((alias ("_ZNK5Klass14implementationEv")));
+
+int __attribute__ ((noinline))
+  Foo (Klass const *ptr)
+{
+  if (ptr->magic () != 0)
+    return 1;
+
+  if (typeid (*ptr) != typeid (Klass))
+    return 2;
+
+  return 0;
+}
+
+int main ()
+{
+  Klass obj;
+  
+  return Foo (&obj);
+}
diff --git a/gcc/testsuite/g++.dg/ext/attr-alias-2.C b/gcc/testsuite/g++.dg/ext/attr-alias-2.C
new file mode 100644
index 000000000000..61a132f77a7b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/attr-alias-2.C
@@ -0,0 +1,37 @@
+/* { dg-do run }  */
+/* { dg-require-alias "" } */
+
+#include <typeinfo>
+
+struct Klass
+{
+  int implementation () const;
+  virtual int magic () const;
+};
+
+int Klass::implementation (void) const
+{
+  return 0;
+}
+
+int Klass::magic () const
+  __attribute__ ((alias ("_ZNK5Klass14implementationEv")));
+
+int __attribute__ ((noinline))
+  Foo (Klass const *ptr)
+{
+  if (ptr->magic () != 0)
+    return 1;
+
+  if (typeid (*ptr) != typeid (Klass))
+    return 2;
+
+  return 0;
+}
+
+int main ()
+{
+  Klass obj;
+  
+  return Foo (&obj);
+}
-- 
GitLab