]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Add namespaces to class templates.
authorKeith Seitz <keiths@redhat.com>
Mon, 23 Jan 2017 21:37:39 +0000 (13:37 -0800)
committerKeith Seitz <keiths@redhat.com>
Fri, 3 Feb 2017 19:44:00 +0000 (11:44 -0800)
This fixes an error that occurs because the class template generic is
defined only at the global scope. Also add namespace information to the
generic in case we have two similarly named templates in different
namespaces.

!!keiths: There are still symbol lookup failures!

gdb/compile/compile-cplus-templates.c
gdb/compile/compile-cplus-types.c
gdb/compile/compile-cplus.h
gdb/testsuite/gdb.compile/cp-namespace-template.cc [new file with mode: 0644]
gdb/testsuite/gdb.compile/cp-namespace-template.exp [new file with mode: 0644]

index 362cd26766217f401aa6640e6f62351d8126d530..683fe78952f6fa66d380b01cb888adc52385d57b 100644 (file)
@@ -307,7 +307,7 @@ compute_class_template_generic (std::string name, struct type *type)
   struct ui_file *stream = mem_fileopen ();
   struct cleanup *back_to = make_cleanup_ui_file_delete (stream);
 
-  /* Format: class|struct|union NAME<parameters>  */
+  /* Format: class|struct|union namespaces::NAME<parameters>  */
   if (TYPE_CODE (type) == TYPE_CODE_STRUCT)
     {
       if (TYPE_DECLARED_CLASS (type))
@@ -321,6 +321,22 @@ compute_class_template_generic (std::string name, struct type *type)
       fputs_unfiltered ("union ", stream);
     }
 
+  /* Print all namespaces.  Note that we do not push the last
+     scope_component -- that's the actual type we are defining.  */
+
+  compile::compile_scope scope = type_name_to_scope (TYPE_NAME (type), NULL);
+  std::for_each (scope.begin (), scope.end () - 1, [&] (const auto &comp)
+     {
+       gdb_assert (TYPE_CODE (SYMBOL_TYPE (comp.bsymbol.symbol))
+                  == TYPE_CODE_NAMESPACE);
+
+       if (comp.name != CP_ANONYMOUS_NAMESPACE_STR)
+        {
+          fputs_unfiltered (comp.name.c_str (), stream);
+          fputs_unfiltered ("::", stream);
+        }
+     });
+
   fputs_unfiltered (name.c_str (), stream);
   fputc_unfiltered ('<', stream);
   print_template_parameter_list (stream, TYPE_TEMPLATE_ARGUMENT_INFO (type));
@@ -645,8 +661,7 @@ compile_cplus_instance::maybe_define_new_class_template
   if (pos == m_class_template_defns->end ())
     {
       /* Insert the new template definition into the cache.  */
-      defn
-       = new class_template_defn (decl_name, generic, type);
+      defn = new class_template_defn (decl_name, generic, type);
       m_class_template_defns->insert (std::make_pair (generic, defn));
     }
   else
@@ -1337,7 +1352,7 @@ class class_template_definer
 
     /* Create/push new scope.  */
     compile_scope scope
-      = m_instance->new_scope (defn->decl_name (), defn->type ());
+      = m_instance->new_scope (TYPE_NAME (defn->type ()), defn->type ());
 
     if (scope.nested_type () != GCC_TYPE_NONE)
       {
index 22088b17bc0c6c43b35b1268778d8978f8c8786d..ce1b9399720bd98d31821b03dd97e5570d7b0832 100644 (file)
@@ -186,15 +186,10 @@ type_code_to_string (enum type_code code)
   return s[code + 1];
 }
 
-/* Convert TYPENAME into a vector of namespace and top-most/super
-   composite scopes.
-
-   For example, for the input "Namespace::classB::classInner", the
-   resultant vector will contain the tokens "Namespace" and
-   "classB".  */
+/* See description in compile-cplus.h.  */
 
-static compile_scope
-ccp_type_name_to_scope (const char *type_name, const struct block *block)
+compile_scope
+compile::type_name_to_scope (const char *type_name, const struct block *block)
 {
   compile_scope scope;
 
@@ -402,7 +397,7 @@ compile_cplus_instance::new_scope (const char *type_name, struct type *type)
   /* Break the type name into components.  If TYPE was defined in some
      superclass, we do not process TYPE but process the enclosing type
      instead.  */
-  compile_scope scope = ccp_type_name_to_scope (type_name, block ());
+  compile_scope scope = type_name_to_scope (type_name, block ());
 
   if (!scope.empty ())
     {
index 15b4ca17d180ba557f0ac4bb68cbdefcdb347b43..f9d2fef8ff6c2b8bdf0363e4bf30b162093a52df 100644 (file)
@@ -107,6 +107,16 @@ namespace compile
   bool operator== (const compile_scope &lhs, const compile_scope &rhs);
   bool operator!= (const compile_scope &lhs, const compile_scope &rhs);
 
+  /* Convert TYPENAME into a vector of namespace and top-most/super
+     composite scopes.
+
+     For example, for the input "Namespace::classB::classInner", the
+     resultant vector will contain the tokens "Namespace" and
+     "classB".  */
+
+  compile_scope type_name_to_scope (const char *type_name,
+                                   const struct block *block);
+
   /* A subclass of compile_instance that is specific to the C++ front
      end.  */
 
diff --git a/gdb/testsuite/gdb.compile/cp-namespace-template.cc b/gdb/testsuite/gdb.compile/cp-namespace-template.cc
new file mode 100644 (file)
index 0000000..d009484
--- /dev/null
@@ -0,0 +1,139 @@
+/* Copyright 2016-2017 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+namespace N1
+{
+  namespace N2
+  {
+    template <typename T, int V>
+    T mytemplate (int a)
+    {
+      return static_cast<T> (a) + V;
+    }
+
+    template <typename T, int V>
+    T mytemplate (void)
+    {
+      return -V;
+    }
+
+    template <int V = 100>
+    int mytemplate (void)
+    {
+      return V;
+    }
+
+    struct A
+    {
+      A (int val) : value (val) { }
+      operator int () const { return value; }
+
+      template <typename T = A>
+      T tempmethod (void)
+      {
+       return value;
+      }
+
+      template <typename T = A, int V = -1>
+      static T stempmethod (void)
+      {
+       return V;
+      }
+
+      template <typename T = A, int V = -2>
+      static T stempmethod (T arg)
+      {
+       return arg + V;
+      }
+
+      int value;
+    };
+
+    template<>
+    int
+    A::tempmethod (void)
+    {
+      return -value;
+    }
+
+    // A handful of operator templates
+    struct O
+    {
+      O (int v) : v_ (v) { }
+
+      template <typename T>
+      operator T (void) { return -v_; }
+
+      template <typename T>
+      O operator+ (T val)
+      {
+       return v_ + val;
+      }
+
+      int v_;
+    };
+
+    // A simple class template
+    template <typename T1 = O, typename T2 = int, int V = 3>
+    class classt
+    {
+    public:
+      classt (T1 v) : val1_ (v), val2_ (107) { }
+      T1 get1 (void) const { return val1_; }
+      T2 get2 (void) const { return val2_; }
+      int get3 (void) const { return V; }
+
+    private:
+      T1 val1_;
+      T2 val2_;
+    };
+  };
+};
+
+int
+main (void)
+{
+  using namespace N1::N2;
+
+  A a (20);
+  O o (30);
+  int var = 0xdeadbeef;
+  int i = 1;
+  const int j = 1;
+  int* pi = &i;
+  int const* const cpci = &j;
+  int *const cpi = &i;
+
+  int o_val = o + 30;
+
+  classt<> cddd (o);
+  classt<int> cdd (100);
+  classt<int, char> cd (101);
+  classt<int, char, 12> c (102);
+  int cvals = cddd.get1 () + cddd.get2 () + cddd.get3 ();
+  cvals += cdd.get1 () + cdd.get2 () + cdd.get3 ();
+  cvals += cd.get1 () + cd.get2 () + cd.get3 ();
+  cvals += c.get1 () + c.get2 () + c.get3 ();
+
+  return mytemplate<int, 1> (0)
+    + mytemplate<int, 1> ()
+    + mytemplate<0> ()
+    + mytemplate ()
+    + a.tempmethod ()
+    + a.tempmethod<int> ()
+    + A::stempmethod ()
+    + A::stempmethod (0); // break here
+}
+
diff --git a/gdb/testsuite/gdb.compile/cp-namespace-template.exp b/gdb/testsuite/gdb.compile/cp-namespace-template.exp
new file mode 100644 (file)
index 0000000..a320d29
--- /dev/null
@@ -0,0 +1,67 @@
+# Copyright 2016-2017 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Namespace-qualified template tests.
+
+load_lib compiler-support.exp
+
+standard_testfile .cc
+
+if {[skip_cplus_tests]} {
+    untested "skipping C++ tests"
+    return
+}
+
+if {[prepare_for_testing $testfile $testfile $srcfile \
+        {debug nowarnings c++}]} {
+    return -1
+}
+
+if {![runto_main]} {
+    return -1
+}
+
+if {[skip_compile_feature_tests]} {
+    untested \
+       "compile command not supported (could not find libcc1 shared library?)"
+    return -1
+}
+
+gdb_breakpoint [gdb_get_line_number "break here" $srcfile]
+gdb_continue_to_breakpoint "testing location"
+
+CompileExpression::new "var"
+CompileExpression::test "N1::N2::mytemplate<int, 1> ()" -1
+CompileExpression::test "N1::N2::mytemplate<int, 1> (1)" 2
+CompileExpression::test "N1::N2::mytemplate<0> ()" 0
+CompileExpression::test "N1::N2::mytemplate ()" 100
+CompileExpression::test "a.tempmethod ()" {(20|{value = 20})} \
+    -print {xfail *-*-* gcc/debug/49348} \
+    -value {xfail *-*-* gcc/debug/49348}
+CompileExpression::test "a.tempmethod<N1::N2::A> ()" {(20|{value = 20})}
+CompileExpression::test "a.tempmethod<int> ()" -20
+CompileExpression::test "o + 3" {(-33|{v_ = 33})}
+CompileExpression::test "cddd.get1 ()" {(-30|{v_ = 30})}
+CompileExpression::test "cddd.get2 ()" 107
+CompileExpression::test "cddd.get3 ()" 3
+CompileExpression::test "cdd.get1 ()" 100
+CompileExpression::test "cdd.get2 ()" 107
+CompileExpression::test "cdd.get3 ()" 3
+CompileExpression::test "cd.get1 ()" 101
+CompileExpression::test "cd.get2 ()" {107( 'k')?}
+CompileExpression::test "cd.get3 ()" 3
+CompileExpression::test "c.get1 ()" 102
+CompileExpression::test "c.get2 ()" {107( 'k')?}
+CompileExpression::test "c.get3 ()" 12