From 7c5fe081f876186ed071fa1024d18f1864accb28 Mon Sep 17 00:00:00 2001 From: Keith Seitz Date: Mon, 23 Jan 2017 13:37:39 -0800 Subject: [PATCH] Add namespaces to class templates. 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 | 23 ++- gdb/compile/compile-cplus-types.c | 13 +- gdb/compile/compile-cplus.h | 10 ++ .../gdb.compile/cp-namespace-template.cc | 139 ++++++++++++++++++ .../gdb.compile/cp-namespace-template.exp | 67 +++++++++ 5 files changed, 239 insertions(+), 13 deletions(-) create mode 100644 gdb/testsuite/gdb.compile/cp-namespace-template.cc create mode 100644 gdb/testsuite/gdb.compile/cp-namespace-template.exp diff --git a/gdb/compile/compile-cplus-templates.c b/gdb/compile/compile-cplus-templates.c index 362cd267662..683fe78952f 100644 --- a/gdb/compile/compile-cplus-templates.c +++ b/gdb/compile/compile-cplus-templates.c @@ -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 */ + /* Format: class|struct|union namespaces::NAME */ 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) { diff --git a/gdb/compile/compile-cplus-types.c b/gdb/compile/compile-cplus-types.c index 22088b17bc0..ce1b9399720 100644 --- a/gdb/compile/compile-cplus-types.c +++ b/gdb/compile/compile-cplus-types.c @@ -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 ()) { diff --git a/gdb/compile/compile-cplus.h b/gdb/compile/compile-cplus.h index 15b4ca17d18..f9d2fef8ff6 100644 --- a/gdb/compile/compile-cplus.h +++ b/gdb/compile/compile-cplus.h @@ -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 index 00000000000..d0094846e36 --- /dev/null +++ b/gdb/testsuite/gdb.compile/cp-namespace-template.cc @@ -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 . */ + +namespace N1 +{ + namespace N2 + { + template + T mytemplate (int a) + { + return static_cast (a) + V; + } + + template + T mytemplate (void) + { + return -V; + } + + template + int mytemplate (void) + { + return V; + } + + struct A + { + A (int val) : value (val) { } + operator int () const { return value; } + + template + T tempmethod (void) + { + return value; + } + + template + static T stempmethod (void) + { + return V; + } + + template + 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 + operator T (void) { return -v_; } + + template + O operator+ (T val) + { + return v_ + val; + } + + int v_; + }; + + // A simple class template + template + 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 cdd (100); + classt cd (101); + classt 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 (0) + + mytemplate () + + mytemplate<0> () + + mytemplate () + + a.tempmethod () + + a.tempmethod () + + 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 index 00000000000..a320d29f8cc --- /dev/null +++ b/gdb/testsuite/gdb.compile/cp-namespace-template.exp @@ -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 . + +# 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 ()" -1 +CompileExpression::test "N1::N2::mytemplate (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 ()" {(20|{value = 20})} +CompileExpression::test "a.tempmethod ()" -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 -- 2.47.3