diff mbox

RFA (libstdc++): C++/v3 PATCH for c++/24163 (lookup in dependent bases) and c++/29131

Message ID 4DD69790.8070101@redhat.com
State New
Headers show

Commit Message

Jason Merrill May 20, 2011, 4:32 p.m. UTC
G++ has had a long-standing bug with unqualified name resolution in 
templates: if we didn't find any declaration when looking up a name in 
the template definition, we would do an additional unqualified lookup at 
the point of instantiation.  This led to incorrectly finding 
namespace-scope functions declared later (29131) and member functions of 
dependent bases (24163).  This patch fixes that bug.

To be friendly to users, the patch also allows affected code to compile 
with -fpermissive and provides suggestions about how to fix the code: 
either declaring the desired function earlier (29131) or explicitly 
qualifying the name with this-> or Class:: (24163).

This caused a lot of regressions in the libstdc++ testsuite, which I've 
fixed.  To find names in dependent bases, I've added explicit this-> in 
non-static member functions, and explicit Class:: in static member 
functions.  I'd like confirmation from the library folks that this is 
the style they want to use for this.

There were also a couple of issues with calls to functions that hadn't 
been declared yet; library folks should definitely check my formatting 
on the forward declarations I've added, for mem_fn in functional and for 
__expint_E1 in exp_integral.tcc.

Tested x86_64-pc-linux-gnu.  Are the library changes OK for trunk?

Comments

Paolo Carlini May 20, 2011, 4:41 p.m. UTC | #1
On 05/20/2011 06:32 PM, Jason Merrill wrote:
> Tested x86_64-pc-linux-gnu.  Are the library changes OK for trunk?
The changes look fine to me.

Paolo.
Gabriel Dos Reis May 20, 2011, 5:01 p.m. UTC | #2
On Fri, May 20, 2011 at 11:32 AM, Jason Merrill <jason@redhat.com> wrote:
> G++ has had a long-standing bug with unqualified name resolution in
> templates: if we didn't find any declaration when looking up a name in the
> template definition, we would do an additional unqualified lookup at the
> point of instantiation.  This led to incorrectly finding namespace-scope
> functions declared later (29131) and member functions of dependent bases
> (24163).  This patch fixes that bug.

Ah, I had always assumed that the previous implementation was exploiting
a license given by the standard which says that both contexts should
yield the same resolution, otherwise the program was ill-formed, no diagnostic
required.

>
> To be friendly to users, the patch also allows affected code to compile with
> -fpermissive and provides suggestions about how to fix the code: either
> declaring the desired function earlier (29131) or explicitly qualifying the
> name with this-> or Class:: (24163).
>
> This caused a lot of regressions in the libstdc++ testsuite, which I've
> fixed.  To find names in dependent bases, I've added explicit this-> in
> non-static member functions, and explicit Class:: in static member
> functions.  I'd like confirmation from the library folks that this is the
> style they want to use for this.
>
> There were also a couple of issues with calls to functions that hadn't been
> declared yet; library folks should definitely check my formatting on the
> forward declarations I've added, for mem_fn in functional and for
> __expint_E1 in exp_integral.tcc.
>
> Tested x86_64-pc-linux-gnu.  Are the library changes OK for trunk?
>

OK.

-- Gaby
Jason Merrill May 20, 2011, 6:01 p.m. UTC | #3
On 05/20/2011 01:01 PM, Gabriel Dos Reis wrote:
> Ah, I had always assumed that the previous implementation was exploiting
> a license given by the standard which says that both contexts should
> yield the same resolution, otherwise the program was ill-formed, no diagnostic
> required.

I believe that only applies to multiple points of instantiation, not to 
the template definition context.

Jason
Gabriel Dos Reis May 20, 2011, 6:26 p.m. UTC | #4
On Fri, May 20, 2011 at 1:01 PM, Jason Merrill <jason@redhat.com> wrote:
> On 05/20/2011 01:01 PM, Gabriel Dos Reis wrote:
>>
>> Ah, I had always assumed that the previous implementation was exploiting
>> a license given by the standard which says that both contexts should
>> yield the same resolution, otherwise the program was ill-formed, no
>> diagnostic
>> required.
>
> I believe that only applies to multiple points of instantiation, not to the
> template definition context.

right you are.  Thanks,

-- Gaby
Joe Buck May 20, 2011, 7:30 p.m. UTC | #5
On Fri, May 20, 2011 at 09:32:16AM -0700, Jason Merrill wrote:
> G++ has had a long-standing bug with unqualified name resolution in 
> templates: if we didn't find any declaration when looking up a name in 
> the template definition, we would do an additional unqualified lookup at 
> the point of instantiation.  This led to incorrectly finding 
> namespace-scope functions declared later (29131) and member functions of 
> dependent bases (24163).  This patch fixes that bug.

I get the impression that most competing C++ compilers (other than the
old HP compiler) were (or are) very loose about that rule.

> To be friendly to users, the patch also allows affected code to compile 
> with -fpermissive and provides suggestions about how to fix the code: 
> either declaring the desired function earlier (29131) or explicitly 
> qualifying the name with this-> or Class:: (24163).

I think that it's quite likely that there is a lot of C++ code out there
that depends on this bug to compile.  So I'm glad that you've included
user guidance in the error messages, and it would be interesting to see
how much code is affected when, say, compiling a distro.
Christopher Jefferson May 20, 2011, 7:45 p.m. UTC | #6
On 20 May 2011, at 20:30, Joe Buck wrote:

> On Fri, May 20, 2011 at 09:32:16AM -0700, Jason Merrill wrote:
>> G++ has had a long-standing bug with unqualified name resolution in 
>> templates: if we didn't find any declaration when looking up a name in 
>> the template definition, we would do an additional unqualified lookup at 
>> the point of instantiation.  This led to incorrectly finding 
>> namespace-scope functions declared later (29131) and member functions of 
>> dependent bases (24163).  This patch fixes that bug.
> 
> I get the impression that most competing C++ compilers (other than the
> old HP compiler) were (or are) very loose about that rule.
> 
>> To be friendly to users, the patch also allows affected code to compile 
>> with -fpermissive and provides suggestions about how to fix the code: 
>> either declaring the desired function earlier (29131) or explicitly 
>> qualifying the name with this-> or Class:: (24163).
> 
> I think that it's quite likely that there is a lot of C++ code out there
> that depends on this bug to compile.  So I'm glad that you've included
> user guidance in the error messages, and it would be interesting to see
> how much code is affected when, say, compiling a distro.

Fortunately clang already implements this rule correctly, so many code bases are already getting fixed. I personally (with a couple of other people) fixed dozens of places in boost where this was breaking code. I expect this to break huge amounts of code in g++-only code bases, but will also help improve compatibility with other compilers.

I could see the temptation to introduce this as a mandatory warning for a while, and only add it under -pedantic. However, it might be easier to just force people to fix their code.

Chris
Jason Merrill May 20, 2011, 8:09 p.m. UTC | #7
On 05/20/2011 03:45 PM, Christopher Jefferson wrote:
> I could see the temptation to introduce this as a mandatory warning for a while, and only add it under -pedantic. However, it might be easier to just force people to fix their code.

With the patch I just checked in it's an error by default or a warning 
with -fpermissive (or silent with -fpermissive -w), so people can delay 
fixing their code if they want to.

Jason
diff mbox

Patch

commit 84edd3cd9bba178a9789678ea77d11bfc6323454
Author: Jason Merrill <jason@redhat.com>
Date:   Fri May 20 12:13:17 2011 -0400

    	PR c++/24163
    	PR c++/29131
    gcc/cp/
    	* pt.c (tsubst_copy_and_build) [CALL_EXPR]: Avoid repeating
    	unqualified lookup.
    	* semantics.c (perform_koenig_lookup): Add complain parm.
    	* cp-tree.h: Adjust.
    	* parser.c (cp_parser_postfix_expression): Adjust.
    	(cp_parser_perform_range_for_lookup): Adjust.
    libstdc++-v3/
    	* include/ext/pb_ds/assoc_container.hpp: Explicitly qualify calls to
    	functions from dependent bases.
    	* include/ext/pb_ds/detail/rb_tree_map_/erase_fn_imps.hpp: Likewise.
    	* include/ext/pb_ds/detail/rb_tree_map_/
    	split_join_fn_imps.hpp: Likewise.
    	* include/ext/pb_ds/detail/splay_tree_/erase_fn_imps.hpp: Likewise.
    	* include/ext/pb_ds/detail/splay_tree_/insert_fn_imps.hpp: Likewise.
    	* include/ext/pb_ds/detail/splay_tree_/splay_fn_imps.hpp: Likewise.
    	* include/ext/pb_ds/detail/splay_tree_/
    	split_join_fn_imps.hpp: Likewise.
    	* include/ext/pb_ds/detail/tree_policy/
    	order_statistics_imp.hpp: Likewise.
    	* include/ext/pb_ds/detail/trie_policy/
    	prefix_search_node_update_imp.hpp: Likewise.
    	* include/ext/rc_string_base.h: Likewise.
    	* include/ext/rope: Likewise.
    	* include/ext/ropeimpl.h: Likewise.
    	* testsuite/util/exception/safety.h: Likewise.
    	* testsuite/util/native_type/native_priority_queue.hpp: Likewise.
    	* testsuite/util/testsuite_io.h: Likewise.
    	* include/std/functional: Declare mem_fn earlier.
    	* include/tr1/functional: Likewise.
    	* include/tr1/exp_integral.tcc: Declare __expint_E1 earlier.

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 3ccbfda..ada01fb 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5365,7 +5365,8 @@  extern tree finish_stmt_expr_expr		(tree, tree);
 extern tree finish_stmt_expr			(tree, bool);
 extern tree stmt_expr_value_expr		(tree);
 bool empty_expr_stmt_p				(tree);
-extern tree perform_koenig_lookup		(tree, VEC(tree,gc) *, bool);
+extern tree perform_koenig_lookup		(tree, VEC(tree,gc) *, bool,
+						 tsubst_flags_t);
 extern tree finish_call_expr			(tree, VEC(tree,gc) **, bool,
 						 bool, tsubst_flags_t);
 extern tree finish_increment_expr		(tree, enum tree_code);
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index cf9286a..2b45260 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -5019,7 +5019,8 @@  cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
 			if (!any_type_dependent_arguments_p (args))
 			  postfix_expression
 			    = perform_koenig_lookup (postfix_expression, args,
-						     /*include_std=*/false);
+						     /*include_std=*/false,
+						     tf_warning_or_error);
 		      }
 		    else
 		      postfix_expression
@@ -5044,7 +5045,8 @@  cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p,
 			if (!any_type_dependent_arguments_p (args))
 			  postfix_expression
 			    = perform_koenig_lookup (postfix_expression, args,
-						     /*include_std=*/false);
+						     /*include_std=*/false,
+						     tf_warning_or_error);
 		      }
 		  }
 	      }
@@ -8741,11 +8743,13 @@  cp_parser_perform_range_for_lookup (tree range, tree *begin, tree *end)
 	  VEC_safe_push (tree, gc, vec, range);
 
 	  member_begin = perform_koenig_lookup (id_begin, vec,
-						/*include_std=*/true);
+						/*include_std=*/true,
+						tf_warning_or_error);
 	  *begin = finish_call_expr (member_begin, &vec, false, true,
 				     tf_warning_or_error);
 	  member_end = perform_koenig_lookup (id_end, vec,
-					      /*include_std=*/true);
+					      /*include_std=*/true,
+					      tf_warning_or_error);
 	  *end = finish_call_expr (member_end, &vec, false, true,
 				   tf_warning_or_error);
 
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 75d0674..d72596f 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -12894,6 +12894,20 @@  tsubst_copy_and_build (tree t,
 					    /*done=*/false,
 					    /*address_p=*/false);
 	  }
+	else if (koenig_p && TREE_CODE (function) == IDENTIFIER_NODE)
+	  {
+	    /* Do nothing; calling tsubst_copy_and_build on an identifier
+	       would incorrectly perform unqualified lookup again.
+
+	       Note that we can also have an IDENTIFIER_NODE if the earlier
+	       unqualified lookup found a member function; in that case
+	       koenig_p will be false and we do want to do the lookup
+	       again to find the instantiated member function.
+
+	       FIXME but doing that causes c++/15272, so we need to stop
+	       using IDENTIFIER_NODE in that situation.  */
+	    qualified_p = false;
+	  }
 	else
 	  {
 	    if (TREE_CODE (function) == COMPONENT_REF)
@@ -12965,14 +12979,59 @@  tsubst_copy_and_build (tree t,
 	       into a non-dependent call.  */
 	    && type_dependent_expression_p_push (t)
 	    && !any_type_dependent_arguments_p (call_args))
-	  function = perform_koenig_lookup (function, call_args, false);
+	  function = perform_koenig_lookup (function, call_args, false,
+					    tf_none);
 
 	if (TREE_CODE (function) == IDENTIFIER_NODE
-	    && !processing_template_decl)
+	    && !any_type_dependent_arguments_p (call_args))
 	  {
-	    unqualified_name_lookup_error (function);
-	    release_tree_vector (call_args);
-	    return error_mark_node;
+	    if (koenig_p && (complain & tf_warning_or_error))
+	      {
+		/* For backwards compatibility and good diagnostics, try
+		   the unqualified lookup again if we aren't in SFINAE
+		   context.  */
+		tree unq = (tsubst_copy_and_build
+			    (function, args, complain, in_decl, true,
+			     integral_constant_expression_p));
+		if (unq != function)
+		  {
+		    tree fn = unq;
+		    if (TREE_CODE (fn) == COMPONENT_REF)
+		      fn = TREE_OPERAND (fn, 1);
+		    if (is_overloaded_fn (fn))
+		      fn = get_first_fn (fn);
+		    permerror (EXPR_LOC_OR_HERE (t),
+			       "%qD was not declared in this scope, "
+			       "and no declarations were found by "
+			       "argument-dependent lookup at the point "
+			       "of instantiation", function);
+		    if (DECL_CLASS_SCOPE_P (fn))
+		      {
+			inform (EXPR_LOC_OR_HERE (t),
+				"declarations in dependent base %qT are "
+				"not found by unqualified lookup",
+				DECL_CLASS_CONTEXT (fn));
+			if (current_class_ptr)
+			  inform (EXPR_LOC_OR_HERE (t),
+				  "use %<this->%D%> instead", function);
+			else
+			  inform (EXPR_LOC_OR_HERE (t),
+				  "use %<%T::%D%> instead",
+				  TYPE_IDENTIFIER (current_class_type),
+				  function);
+		      }
+		    else
+		      inform (0, "%q+D declared here, later in the "
+				"translation unit", fn);
+		    function = unq;
+		  }
+	      }
+	    if (TREE_CODE (function) == IDENTIFIER_NODE)
+	      {
+		unqualified_name_lookup_error (function);
+		release_tree_vector (call_args);
+		return error_mark_node;
+	      }
 	  }
 
 	/* Remember that there was a reference to this entity.  */
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 02e08e3..a7ca50d 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -1953,7 +1953,8 @@  empty_expr_stmt_p (tree expr_stmt)
    Returns the functions to be considered by overload resolution.  */
 
 tree
-perform_koenig_lookup (tree fn, VEC(tree,gc) *args, bool include_std)
+perform_koenig_lookup (tree fn, VEC(tree,gc) *args, bool include_std,
+		       tsubst_flags_t complain)
 {
   tree identifier = NULL_TREE;
   tree functions = NULL_TREE;
@@ -1991,8 +1992,13 @@  perform_koenig_lookup (tree fn, VEC(tree,gc) *args, bool include_std)
     {
       fn = lookup_arg_dependent (identifier, functions, args, include_std);
       if (!fn)
-	/* The unqualified name could not be resolved.  */
-	fn = unqualified_fn_lookup_error (identifier);
+	{
+	  /* The unqualified name could not be resolved.  */
+	  if (complain)
+	    fn = unqualified_fn_lookup_error (identifier);
+	  else
+	    fn = identifier;
+	}
     }
 
   if (fn && template_id)
diff --git a/gcc/testsuite/g++.dg/opt/pr47615.C b/gcc/testsuite/g++.dg/opt/pr47615.C
index bbbcbe1..f8dbcf7 100644
--- a/gcc/testsuite/g++.dg/opt/pr47615.C
+++ b/gcc/testsuite/g++.dg/opt/pr47615.C
@@ -360,7 +360,7 @@  template < typename Const_Node_Iterator, typename Node_Iterator, typename, typen
 {
 {
 {
-	    rotate_right (p_nd);
+	    this->rotate_right (p_nd);
 	  }
 	}
       }
diff --git a/gcc/testsuite/g++.dg/overload/defarg1.C b/gcc/testsuite/g++.dg/overload/defarg1.C
index 44de733..5d34a45 100644
--- a/gcc/testsuite/g++.dg/overload/defarg1.C
+++ b/gcc/testsuite/g++.dg/overload/defarg1.C
@@ -3,7 +3,9 @@ 
 template<typename T>
 int foo (T t, int = foo(T()));
 
+struct A { };
+
 int main()
 {
-  foo(0);			// { dg-error "default argument" }
+  foo(A());			// { dg-error "default argument" }
 }
diff --git a/gcc/testsuite/g++.dg/tc1/dr213.C b/gcc/testsuite/g++.dg/tc1/dr213.C
index 2cc7013..b616ff9 100644
--- a/gcc/testsuite/g++.dg/tc1/dr213.C
+++ b/gcc/testsuite/g++.dg/tc1/dr213.C
@@ -8,7 +8,7 @@ 
 template <class T> struct A : T {
   void h(T t) {
     f(t);
-    g(t);     // { dg-error "" "" { xfail *-*-* } }
+    g(t);     // { dg-message "" }
   }
 };
 
@@ -21,7 +21,7 @@  void f(B) {}
 
 int main()
 {
-  A<B> ab;   // { dg-error "" "" { xfail *-*-* } }
+  A<B> ab;
   B b;
-  ab.h(b);
+  ab.h(b);   // { dg-message "instantiated" }
 }
diff --git a/gcc/testsuite/g++.dg/template/koenig9.C b/gcc/testsuite/g++.dg/template/koenig9.C
new file mode 100644
index 0000000..ae74a47
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/koenig9.C
@@ -0,0 +1,33 @@ 
+// PR c++/29131
+// int has no associated namespaces, so arg-dep lookup doesn't find g(int).
+
+template <class T> int f() { return g(T()); } // { dg-error "argument-dependent" }
+int g(int);				      // { dg-message "declared here" }
+int i = f<int>();
+
+// PR c++/24163
+// Unqualified lookup doesn't find names from dependent bases.
+
+template <class T>
+struct A
+{
+  static void h(T);
+};
+
+template <class T> struct B: A<T>
+{
+  void f() { h(T()); }		// { dg-error "argument-dependent" }
+  static void g() { h(T()); }	// { dg-error "argument-dependent" }
+};
+
+int main()
+{
+  B<int> b;
+  b.f();
+  b.g();
+}
+
+// { dg-message "dependent base .A.int" "" { target *-*-* } 19 }
+// { dg-message "this->h" "" { target *-*-* } 19 }
+// { dg-message "dependent base .A.int" "" { target *-*-* } 20 }
+// { dg-message "B::h" "" { target *-*-* } 20 }
diff --git a/gcc/testsuite/g++.dg/torture/pr34850.C b/gcc/testsuite/g++.dg/torture/pr34850.C
index 4f630f8..5e30f1d 100644
--- a/gcc/testsuite/g++.dg/torture/pr34850.C
+++ b/gcc/testsuite/g++.dg/torture/pr34850.C
@@ -48,7 +48,7 @@  template<typename T> void MemoryRegion<T>::create(u32bit n)    {
 template<typename T> class SecureVector : public MemoryRegion<T>    {
 public:
     SecureVector<T>& operator=(const MemoryRegion<T>& in)          {
-	if(this != &in) set(in);
+	if(this != &in) this->set(in);
     }
 };
 class OctetString    {
diff --git a/gcc/testsuite/g++.dg/torture/pr39362.C b/gcc/testsuite/g++.dg/torture/pr39362.C
index fb23439..e7b0774 100644
--- a/gcc/testsuite/g++.dg/torture/pr39362.C
+++ b/gcc/testsuite/g++.dg/torture/pr39362.C
@@ -55,7 +55,7 @@  template <typename T, int cap> class I;
 template <typename T> struct I <T, 0> : H <T>
 {
   I (int capacity) { allocateBuffer (capacity); }
-  ~I () { deallocateBuffer (buffer ()); }
+  ~I () { this->deallocateBuffer (buffer ()); }
   using H <T>::allocateBuffer;
   H <T>::buffer;
 };
diff --git a/gcc/testsuite/g++.old-deja/g++.brendan/crash56.C b/gcc/testsuite/g++.old-deja/g++.brendan/crash56.C
index ad652cf..a22615d 100644
--- a/gcc/testsuite/g++.old-deja/g++.brendan/crash56.C
+++ b/gcc/testsuite/g++.old-deja/g++.brendan/crash56.C
@@ -253,7 +253,7 @@  void
 SetLD<T>::add(const T& item)
 {
     if ( ! contains(item) )
-	append(item);
+      this->append(item);
 }
 template<class T>
 void
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/memtemp47.C b/gcc/testsuite/g++.old-deja/g++.pt/memtemp47.C
index 7ed5a24..242a299 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/memtemp47.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/memtemp47.C
@@ -18,7 +18,7 @@  struct T : public S<X>
 {
   template <class U>
   void f(U u)
-  { printf ("In T::f(U)\n"); g(u); }
+  { printf ("In T::f(U)\n"); this->g(u); }
 };
 
 int main()
diff --git a/libstdc++-v3/include/ext/pb_ds/assoc_container.hpp b/libstdc++-v3/include/ext/pb_ds/assoc_container.hpp
index 9cec3b7..12a3fc5 100644
--- a/libstdc++-v3/include/ext/pb_ds/assoc_container.hpp
+++ b/libstdc++-v3/include/ext/pb_ds/assoc_container.hpp
@@ -234,7 +234,7 @@  namespace __gnu_pbds
     template<typename It>
     cc_hash_table(It first, It last, const hash_fn& h)
     : base_type(h)
-    { copy_from_range(first, last); }
+    { this->copy_from_range(first, last); }
 
     // Constructor taking __iterators to a range of value_types and
     // some policy objects The value_types between first_it and
@@ -245,7 +245,7 @@  namespace __gnu_pbds
     template<typename It>
     cc_hash_table(It first, It last, const hash_fn& h, const eq_fn& e)
     : base_type(h, e)
-    { copy_from_range(first, last); }
+    { this->copy_from_range(first, last); }
 
     // Constructor taking __iterators to a range of value_types and
     // some policy objects The value_types between first_it and
@@ -258,7 +258,7 @@  namespace __gnu_pbds
     cc_hash_table(It first, It last, const hash_fn& h, const eq_fn& e,
 		  const comb_hash_fn& ch)
     : base_type(h, e, ch)
-    { copy_from_range(first, last); }
+    { this->copy_from_range(first, last); }
 
     // Constructor taking __iterators to a range of value_types and
     // some policy objects The value_types between first_it and
@@ -272,7 +272,7 @@  namespace __gnu_pbds
     cc_hash_table(It first, It last, const hash_fn& h, const eq_fn& e, 
 		  const comb_hash_fn& ch, const resize_policy& rp)
     : base_type(h, e, ch, rp)
-    { copy_from_range(first, last); }
+    { this->copy_from_range(first, last); }
 
     cc_hash_table(const cc_hash_table& other)
     : base_type((const base_type&)other)
diff --git a/libstdc++-v3/include/ext/pb_ds/detail/rb_tree_map_/erase_fn_imps.hpp b/libstdc++-v3/include/ext/pb_ds/detail/rb_tree_map_/erase_fn_imps.hpp
index 5a335a6..0ef925f 100644
--- a/libstdc++-v3/include/ext/pb_ds/detail/rb_tree_map_/erase_fn_imps.hpp
+++ b/libstdc++-v3/include/ext/pb_ds/detail/rb_tree_map_/erase_fn_imps.hpp
@@ -43,7 +43,7 @@  inline bool
 PB_DS_CLASS_C_DEC::
 erase(const_key_reference r_key)
 {
-  point_iterator it = find(r_key);
+  point_iterator it = this->find(r_key);
   if (it == base_type::end())
     return false;
   erase(it);
@@ -121,7 +121,7 @@  void
 PB_DS_CLASS_C_DEC::
 remove_node(node_pointer p_z)
 {
-  update_min_max_for_erased_node(p_z);
+  this->update_min_max_for_erased_node(p_z);
   node_pointer p_y = p_z;
   node_pointer p_x = 0;
   node_pointer p_new_x_parent = 0;
@@ -185,7 +185,7 @@  remove_node(node_pointer p_z)
       p_y = p_z;
     }
 
-  update_to_top(p_new_x_parent, (node_update* )this);
+  this->update_to_top(p_new_x_parent, (node_update* )this);
 
   if (p_y->m_red)
     return;
@@ -238,7 +238,7 @@  remove_fixup(node_pointer p_x, node_pointer p_new_x_parent)
 	      p_w->m_p_right->m_red = false;
 
 	    base_type::rotate_left(p_new_x_parent);
-	    update_to_top(p_new_x_parent, (node_update* )this);
+	    this->update_to_top(p_new_x_parent, (node_update* )this);
 	    break;
 	  }
       }
@@ -279,7 +279,7 @@  remove_fixup(node_pointer p_x, node_pointer p_new_x_parent)
 	      p_w->m_p_left->m_red = false;
 
 	    base_type::rotate_right(p_new_x_parent);
-	    update_to_top(p_new_x_parent, (node_update* )this);
+	    this->update_to_top(p_new_x_parent, (node_update* )this);
 	    break;
 	  }
       }
diff --git a/libstdc++-v3/include/ext/pb_ds/detail/rb_tree_map_/split_join_fn_imps.hpp b/libstdc++-v3/include/ext/pb_ds/detail/rb_tree_map_/split_join_fn_imps.hpp
index a0d079b..198caca 100644
--- a/libstdc++-v3/include/ext/pb_ds/detail/rb_tree_map_/split_join_fn_imps.hpp
+++ b/libstdc++-v3/include/ext/pb_ds/detail/rb_tree_map_/split_join_fn_imps.hpp
@@ -246,7 +246,7 @@  split(const_key_reference r_key, PB_DS_CLASS_C_DEC& other)
 
   PB_DS_STRUCT_ONLY_ASSERT_VALID((*this))
   PB_DS_STRUCT_ONLY_ASSERT_VALID(other)
-  node_pointer p_nd = upper_bound(r_key).m_p_nd;
+  node_pointer p_nd = this->upper_bound(r_key).m_p_nd;
   do
     {
       node_pointer p_next_nd = p_nd->m_p_parent;
@@ -292,7 +292,7 @@  split_at_node(node_pointer p_nd, PB_DS_CLASS_C_DEC& other)
       if (p_l != 0)
 	p_l->m_p_parent = p_parent;
 
-      update_to_top(p_parent, (node_update* )this);
+      this->update_to_top(p_parent, (node_update* )this);
 
       if (!p_nd->m_red)
 	remove_fixup(p_l, p_parent);
diff --git a/libstdc++-v3/include/ext/pb_ds/detail/splay_tree_/erase_fn_imps.hpp b/libstdc++-v3/include/ext/pb_ds/detail/splay_tree_/erase_fn_imps.hpp
index 207577c..22f8e68 100644
--- a/libstdc++-v3/include/ext/pb_ds/detail/splay_tree_/erase_fn_imps.hpp
+++ b/libstdc++-v3/include/ext/pb_ds/detail/splay_tree_/erase_fn_imps.hpp
@@ -142,7 +142,7 @@  erase_node(node_pointer p_nd)
   if (p_l != 0)
     p_l->m_p_parent = p_target_r;
   PB_DS_ASSERT_VALID((*this))
-  apply_update(p_target_r, (node_update* )this);
+  this->apply_update(p_target_r, (node_update* )this);
 }
 
 PB_DS_CLASS_T_DEC
diff --git a/libstdc++-v3/include/ext/pb_ds/detail/splay_tree_/insert_fn_imps.hpp b/libstdc++-v3/include/ext/pb_ds/detail/splay_tree_/insert_fn_imps.hpp
index 97441c9..4e1179e 100644
--- a/libstdc++-v3/include/ext/pb_ds/detail/splay_tree_/insert_fn_imps.hpp
+++ b/libstdc++-v3/include/ext/pb_ds/detail/splay_tree_/insert_fn_imps.hpp
@@ -90,5 +90,5 @@  insert_leaf_imp(const_reference r_value)
   while (p_nd->m_p_right != 0)
     p_nd = p_nd->m_p_right;
 
-  return std::make_pair(insert_leaf_new(r_value, p_nd, false), true);
+  return std::make_pair(this->insert_leaf_new(r_value, p_nd, false), true);
 }
diff --git a/libstdc++-v3/include/ext/pb_ds/detail/splay_tree_/splay_fn_imps.hpp b/libstdc++-v3/include/ext/pb_ds/detail/splay_tree_/splay_fn_imps.hpp
index ec38cf8..b152366 100644
--- a/libstdc++-v3/include/ext/pb_ds/detail/splay_tree_/splay_fn_imps.hpp
+++ b/libstdc++-v3/include/ext/pb_ds/detail/splay_tree_/splay_fn_imps.hpp
@@ -274,9 +274,9 @@  splay_zz_end(node_pointer p_nd, node_pointer p_parent,
   if (p_nd->m_p_parent == base_type::m_p_head)
     base_type::m_p_head->m_p_parent = p_nd;
 
-  apply_update(p_grandparent, (node_update* )this);
-  apply_update(p_parent, (node_update* )this);
-  apply_update(p_nd, (node_update* )this);
+  this->apply_update(p_grandparent, (node_update* )this);
+  this->apply_update(p_parent, (node_update* )this);
+  this->apply_update(p_nd, (node_update* )this);
 
   PB_DS_ASSERT_BASE_NODE_CONSISTENT(p_nd)
 }
diff --git a/libstdc++-v3/include/ext/pb_ds/detail/splay_tree_/split_join_fn_imps.hpp b/libstdc++-v3/include/ext/pb_ds/detail/splay_tree_/split_join_fn_imps.hpp
index cb04d65..fe4cfa5 100644
--- a/libstdc++-v3/include/ext/pb_ds/detail/splay_tree_/split_join_fn_imps.hpp
+++ b/libstdc++-v3/include/ext/pb_ds/detail/splay_tree_/split_join_fn_imps.hpp
@@ -66,7 +66,7 @@  join(PB_DS_CLASS_C_DEC& other)
 
   base_type::m_p_head->m_p_parent = p_target_r;
   p_target_r->m_p_parent = base_type::m_p_head;
-  apply_update(p_target_r, (node_update* )this);
+  this->apply_update(p_target_r, (node_update* )this);
 
   base_type::join_finish(other);
 
@@ -89,7 +89,7 @@  split(const_key_reference r_key, PB_DS_CLASS_C_DEC& other)
       return;
     }
 
-  node_pointer p_upper_bound = upper_bound(r_key).m_p_nd;
+  node_pointer p_upper_bound = this->upper_bound(r_key).m_p_nd;
   _GLIBCXX_DEBUG_ASSERT(p_upper_bound != 0);
 
   splay(p_upper_bound);
@@ -103,7 +103,7 @@  split(const_key_reference r_key, PB_DS_CLASS_C_DEC& other)
   other.m_p_head->m_p_parent = p_upper_bound;
   p_upper_bound->m_p_parent = other.m_p_head;
   p_upper_bound->m_p_left = 0;
-  apply_update(p_upper_bound, (node_update* )this);
+  this->apply_update(p_upper_bound, (node_update* )this);
   base_type::split_finish(other);
 
   PB_DS_ASSERT_VALID((*this))
diff --git a/libstdc++-v3/include/ext/pb_ds/detail/tree_policy/order_statistics_imp.hpp b/libstdc++-v3/include/ext/pb_ds/detail/tree_policy/order_statistics_imp.hpp
index 1d33767..d3b2792 100644
--- a/libstdc++-v3/include/ext/pb_ds/detail/tree_policy/order_statistics_imp.hpp
+++ b/libstdc++-v3/include/ext/pb_ds/detail/tree_policy/order_statistics_imp.hpp
@@ -96,9 +96,9 @@  order_of_key(const_key_reference r_key) const
     {
       const_node_iterator l_it = it.get_l_child();
 
-      if (r_cmp_fn(r_key, extract_key(*(*it))))
+      if (r_cmp_fn(r_key, this->extract_key(*(*it))))
 	it = l_it;
-      else if (r_cmp_fn(extract_key(*(*it)), r_key))
+      else if (r_cmp_fn(this->extract_key(*(*it)), r_key))
         {
 
 	  ord += (l_it == end_it)?
diff --git a/libstdc++-v3/include/ext/pb_ds/detail/trie_policy/prefix_search_node_update_imp.hpp b/libstdc++-v3/include/ext/pb_ds/detail/trie_policy/prefix_search_node_update_imp.hpp
index cdd8989..ff2799e 100644
--- a/libstdc++-v3/include/ext/pb_ds/detail/trie_policy/prefix_search_node_update_imp.hpp
+++ b/libstdc++-v3/include/ext/pb_ds/detail/trie_policy/prefix_search_node_update_imp.hpp
@@ -104,9 +104,9 @@  prefix_range(typename e_access_traits::const_iterator b, typename e_access_trait
 
       if (common_range_length >= given_range_length)
         {
-	  iterator ret_b = leftmost_it(nd_it);
+	  iterator ret_b = this->leftmost_it(nd_it);
 
-	  iterator ret_e = rightmost_it(nd_it);
+	  iterator ret_e = this->rightmost_it(nd_it);
 
 	  return (std::make_pair(ret_b, ++ret_e));
         }
diff --git a/libstdc++-v3/include/ext/rc_string_base.h b/libstdc++-v3/include/ext/rc_string_base.h
index 4a27ff6..afd4d9e 100644
--- a/libstdc++-v3/include/ext/rc_string_base.h
+++ b/libstdc++-v3/include/ext/rc_string_base.h
@@ -461,7 +461,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 				  __alloc);
 
       if (_M_info._M_length)
-	_S_copy(__r->_M_refdata(), _M_refdata(), _M_info._M_length);
+	__rc_string_base::_S_copy(__r->_M_refdata(), _M_refdata(), _M_info._M_length);
 
       __r->_M_set_length(_M_info._M_length);
       return __r->_M_refdata();
@@ -569,7 +569,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	// Check for out_of_range and length_error exceptions.
 	_Rep* __r = _Rep::_S_create(__dnew, size_type(0), __a);
 	__try
-	  { _S_copy_chars(__r->_M_refdata(), __beg, __end); }
+	  { __rc_string_base::_S_copy_chars(__r->_M_refdata(), __beg, __end); }
 	__catch(...)
 	  {
 	    __r->_M_destroy(__a);
@@ -590,7 +590,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       // Check for out_of_range and length_error exceptions.
       _Rep* __r = _Rep::_S_create(__n, size_type(0), __a);
       if (__n)
-	_S_assign(__r->_M_refdata(), __n, __c);
+	__rc_string_base::_S_assign(__r->_M_refdata(), __n, __c);
 
       __r->_M_set_length(__n);
       return __r->_M_refdata();
@@ -659,11 +659,11 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 				  _M_capacity(), _M_get_allocator());
 
       if (__pos)
-	_S_copy(__r->_M_refdata(), _M_data(), __pos);
+	this->_S_copy(__r->_M_refdata(), _M_data(), __pos);
       if (__s && __len2)
-	_S_copy(__r->_M_refdata() + __pos, __s, __len2);
+	this->_S_copy(__r->_M_refdata() + __pos, __s, __len2);
       if (__how_much)
-	_S_copy(__r->_M_refdata() + __pos + __len2,
+	this->_S_copy(__r->_M_refdata() + __pos + __len2,
 		_M_data() + __pos + __len1, __how_much);
 
       _M_dispose();
@@ -685,9 +685,9 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 				      _M_get_allocator());
 
 	  if (__pos)
-	    _S_copy(__r->_M_refdata(), _M_data(), __pos);
+	    this->_S_copy(__r->_M_refdata(), _M_data(), __pos);
 	  if (__how_much)
-	    _S_copy(__r->_M_refdata() + __pos,
+	    this->_S_copy(__r->_M_refdata() + __pos,
 		    _M_data() + __pos + __n, __how_much);
 
 	  _M_dispose();
@@ -696,7 +696,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       else if (__how_much && __n)
 	{
 	  // Work in-place.
-	  _S_move(_M_data() + __pos,
+	  this->_S_move(_M_data() + __pos,
 		  _M_data() + __pos + __n, __how_much);
 	}
 
diff --git a/libstdc++-v3/include/ext/rope b/libstdc++-v3/include/ext/rope
index 4292151..5e82811 100644
--- a/libstdc++-v3/include/ext/rope
+++ b/libstdc++-v3/include/ext/rope
@@ -729,7 +729,7 @@  protected:
         if (_M_data != this->_M_c_string)
 	  this->_M_free_c_string();
 	
-        __STL_FREE_STRING(_M_data, this->_M_size, this->_M_get_allocator());
+	this->__STL_FREE_STRING(_M_data, this->_M_size, this->_M_get_allocator());
       }
 #endif
 protected:
@@ -1170,7 +1170,7 @@  protected:
       operator*()
       {
         if (0 == this->_M_buf_ptr)
-	  _S_setcache(*this);
+	  this->_S_setcache(*this);
         return *this->_M_buf_ptr;
       }
 
@@ -1299,7 +1299,7 @@  protected:
         _M_root_rope(__r)
       { _RopeRep::_S_ref(this->_M_root);
         if (!(__r -> empty()))
-	  _S_setcache(*this);
+	  this->_S_setcache(*this);
       }
 
       void _M_check();
diff --git a/libstdc++-v3/include/ext/ropeimpl.h b/libstdc++-v3/include/ext/ropeimpl.h
index 467b8fd..3ee0610 100644
--- a/libstdc++-v3/include/ext/ropeimpl.h
+++ b/libstdc++-v3/include/ext/ropeimpl.h
@@ -380,7 +380,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	    _Rope_RopeLeaf<_CharT, _Alloc>* __l
 	      = (_Rope_RopeLeaf<_CharT, _Alloc>*)this;
 	    __l->_Rope_RopeLeaf<_CharT, _Alloc>::~_Rope_RopeLeaf();
-	    _L_deallocate(__l, 1);
+	    this->_L_deallocate(__l, 1);
 	    break;
 	  }
 	case __detail::_S_concat:
@@ -389,7 +389,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	      = (_Rope_RopeConcatenation<_CharT, _Alloc>*)this;
 	    __c->_Rope_RopeConcatenation<_CharT, _Alloc>::
 	      ~_Rope_RopeConcatenation();
-	    _C_deallocate(__c, 1);
+	    this->_C_deallocate(__c, 1);
 	    break;
 	  }
 	case __detail::_S_function:
@@ -397,7 +397,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	    _Rope_RopeFunction<_CharT, _Alloc>* __f
 	      = (_Rope_RopeFunction<_CharT, _Alloc>*)this;
 	    __f->_Rope_RopeFunction<_CharT, _Alloc>::~_Rope_RopeFunction();
-	    _F_deallocate(__f, 1);
+	    this->_F_deallocate(__f, 1);
 	    break;
 	  }
 	case __detail::_S_substringfn:
@@ -406,7 +406,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	      (_Rope_RopeSubstring<_CharT, _Alloc>*)this;
 	    __ss->_Rope_RopeSubstring<_CharT, _Alloc>::
 	      ~_Rope_RopeSubstring();
-	    _S_deallocate(__ss, 1);
+	    this->_S_deallocate(__ss, 1);
 	    break;
 	  }
 	}
@@ -430,7 +430,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     {
       size_t __old_len = __r->_M_size;
       _CharT* __new_data = (_CharT*)
-	_Data_allocate(_S_rounded_up_size(__old_len + __len));
+	rope::_Data_allocate(_S_rounded_up_size(__old_len + __len));
       _RopeLeaf* __result;
 
       uninitialized_copy_n(__r->_M_data, __old_len, __new_data);
@@ -511,7 +511,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	    }
 	  __catch(...)
 	    {
-	      _C_deallocate(__result,1);
+	      rope::_C_deallocate(__result,1);
 	      __throw_exception_again;
 	    }
 	  // In case of exception, we need to deallocate
@@ -814,7 +814,7 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	    if (__result_len > __lazy_threshold)
 	      goto lazy;
 	    __section = (_CharT*)
-	      _Data_allocate(_S_rounded_up_size(__result_len));
+	      rope::_Data_allocate(_S_rounded_up_size(__result_len));
 	    __try
 	      {	(*(__f->_M_fn))(__start, __result_len, __section); }
 	    __catch(...)
diff --git a/libstdc++-v3/include/std/functional b/libstdc++-v3/include/std/functional
index f8ea41c..40cf870 100644
--- a/libstdc++-v3/include/std/functional
+++ b/libstdc++-v3/include/std/functional
@@ -62,6 +62,12 @@  namespace std _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
+  template<typename _MemberPointer>
+    class _Mem_fn;
+  template<typename _Tp, typename _Class>
+    _Mem_fn<_Tp _Class::*>
+    mem_fn(_Tp _Class::*);
+
 _GLIBCXX_HAS_NESTED_TYPE(result_type)
 
   /// If we have found a result_type, extract it.
@@ -496,9 +502,6 @@  _GLIBCXX_HAS_NESTED_TYPE(result_type)
 
   // @} group functors
 
-  template<typename _MemberPointer>
-    class _Mem_fn;
-
   /**
    * Derives from @c unary_function or @c binary_function, or perhaps
    * nothing, depending on the number of arguments provided. The
diff --git a/libstdc++-v3/include/tr1/exp_integral.tcc b/libstdc++-v3/include/tr1/exp_integral.tcc
index cf3bd63..6a49b35 100644
--- a/libstdc++-v3/include/tr1/exp_integral.tcc
+++ b/libstdc++-v3/include/tr1/exp_integral.tcc
@@ -59,6 +59,8 @@  namespace tr1
   {
   _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
+    template<typename _Tp> _Tp __expint_E1(const _Tp);
+
     /**
      *   @brief Return the exponential integral @f$ E_1(x) @f$
      *          by series summation.  This should be good
diff --git a/libstdc++-v3/include/tr1/functional b/libstdc++-v3/include/tr1/functional
index 31e72d6..7651326 100644
--- a/libstdc++-v3/include/tr1/functional
+++ b/libstdc++-v3/include/tr1/functional
@@ -52,6 +52,9 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
   template<typename _MemberPointer>
     class _Mem_fn;
+  template<typename _Tp, typename _Class>
+    _Mem_fn<_Tp _Class::*>
+    mem_fn(_Tp _Class::*);
 
   /**
    *  Actual implementation of _Has_result_type, which uses SFINAE to
diff --git a/libstdc++-v3/testsuite/util/exception/safety.h b/libstdc++-v3/testsuite/util/exception/safety.h
index 9468bff..b85f7fe 100644
--- a/libstdc++-v3/testsuite/util/exception/safety.h
+++ b/libstdc++-v3/testsuite/util/exception/safety.h
@@ -1196,20 +1196,20 @@  namespace __gnu_test
 	  // constructor or assignment operator of value_type throws.
 	  if (!traits<container_type>::has_throwing_erase::value)
 	    {
-	      _M_erasep(_M_container);
-	      _M_eraser(_M_container);
+	      this->_M_erasep(_M_container);
+	      this->_M_eraser(_M_container);
 	    }
 
-	  _M_popf(_M_container);
-	  _M_popb(_M_container);
+	  this->_M_popf(_M_container);
+	  this->_M_popb(_M_container);
 
-	  _M_iops(_M_container);
-	  _M_ciops(_M_container);
+	  this->_M_iops(_M_container);
+	  this->_M_ciops(_M_container);
 
-	  _M_swap(_M_container);
+	  this->_M_swap(_M_container);
 
 	  // Last.
-	  _M_clear(_M_container);
+	  this->_M_clear(_M_container);
 	}
       }
     };
diff --git a/libstdc++-v3/testsuite/util/native_type/native_priority_queue.hpp b/libstdc++-v3/testsuite/util/native_type/native_priority_queue.hpp
index 4367fca..dad913f 100644
--- a/libstdc++-v3/testsuite/util/native_type/native_priority_queue.hpp
+++ b/libstdc++-v3/testsuite/util/native_type/native_priority_queue.hpp
@@ -188,7 +188,7 @@  namespace __gnu_pbds
       modify(const_reference r_old, const_reference r_new)
       {
         erase(r_old);
-        push(r_new);
+        this->push(r_new);
       }
 
       void
diff --git a/libstdc++-v3/testsuite/util/testsuite_io.h b/libstdc++-v3/testsuite/util/testsuite_io.h
index 681448a..4251b71 100644
--- a/libstdc++-v3/testsuite/util/testsuite_io.h
+++ b/libstdc++-v3/testsuite/util/testsuite_io.h
@@ -144,7 +144,7 @@  namespace __gnu_test
       {
 	p[0] = char_type('s');
 	p[1] = char_type();
-	setg(p, p, p + 1); 
+	this->setg(p, p, p + 1);
       }
 
       virtual int_type underflow()