diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 4bbc698..20f263f 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -1704,6 +1704,13 @@ finish_parenthesized_expr (cp_expr expr)
     /* This inhibits warnings in c_common_truthvalue_conversion.  */
     TREE_NO_WARNING (expr) = 1;
 
+  /* This inhibits -Wparentheses warnings for parenthesized non-dependent
+     MODOP_EXPRs, which are wrapped in an implicit INDIRECT_REF.   */
+  if (processing_template_decl
+      && REFERENCE_REF_P (expr)
+      && TREE_CODE (TREE_OPERAND (expr, 0)) == MODOP_EXPR)
+    TREE_NO_WARNING (TREE_OPERAND (expr, 0)) = 1;
+
   if (TREE_CODE (expr) == OFFSET_REF
       || TREE_CODE (expr) == SCOPE_REF)
     /* [expr.unary.op]/3 The qualified id of a pointer-to-member must not be
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 5145879..3da6ea1 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -7869,26 +7869,39 @@ build_x_modify_expr (location_t loc, tree lhs, enum tree_code modifycode,
   tree orig_lhs = lhs;
   tree orig_rhs = rhs;
   tree overload = NULL_TREE;
-  tree op = build_nt (modifycode, NULL_TREE, NULL_TREE);
+  /* Give this middle operand of the resulting MODOP_EXPR a dummy non-NULL type
+     so that instantiation_dependent_expression_p won't later consider an
+     otherwise non-dependent MODOP_EXPR to be dependent.  */
+  tree op = build_min (modifycode, void_type_node, NULL_TREE, NULL_TREE);
 
   if (processing_template_decl)
     {
-      if (modifycode == NOP_EXPR
-	  || type_dependent_expression_p (lhs)
+      if (type_dependent_expression_p (lhs)
 	  || type_dependent_expression_p (rhs))
-        return build_min_nt_loc (loc, MODOP_EXPR, lhs,
-				 build_min_nt_loc (loc, modifycode, NULL_TREE,
-						   NULL_TREE), rhs);
+        return build_min_nt_loc (loc, MODOP_EXPR, lhs, op, rhs);
 
       lhs = build_non_dependent_expr (lhs);
       rhs = build_non_dependent_expr (rhs);
     }
 
-  if (modifycode != NOP_EXPR)
+  if (modifycode == NOP_EXPR)
+    {
+      tree result = cp_build_modify_expr (lhs, modifycode, rhs, complain);
+
+      if (processing_template_decl)
+	return build_min_non_dep (MODOP_EXPR, result, orig_lhs, op, orig_rhs);
+
+      return result;
+    }
+  else
     {
       tree rval = build_new_op (loc, MODIFY_EXPR, LOOKUP_NORMAL,
 				lhs, rhs, op, &overload, complain);
-      if (rval)
+
+      /* This shouldn't happen.  */
+      if (rval == NULL_TREE)
+	gcc_unreachable ();
+      else
 	{
 	  if (rval == error_mark_node)
 	    return rval;
@@ -7905,7 +7918,6 @@ build_x_modify_expr (location_t loc, tree lhs, enum tree_code modifycode,
 	  return rval;
 	}
     }
-  return cp_build_modify_expr (lhs, modifycode, rhs, complain);
 }
 
 /* Helper function for get_delta_difference which assumes FROM is a base
diff --git a/gcc/testsuite/g++.dg/cpp0x/decltype64.C b/gcc/testsuite/g++.dg/cpp0x/decltype64.C
new file mode 100644
index 0000000..9ddd1c1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/decltype64.C
@@ -0,0 +1,30 @@
+// PR c++/69694
+// { dg-do compile { target c++11 } }
+
+// n3911: TransformationTrait Alias `void_t`
+template<typename...> struct make_void { using type = void; };
+template<typename... Ts> using void_t = typename make_void<Ts...>::type;
+
+// std::declval<void*&>
+void*& declval_void();
+
+template<typename, typename = void> struct Fun;
+template<typename R>
+  struct Fun<R(), void>
+{
+  void fun();
+};
+template<typename Desc>
+  struct Fun<Desc, void_t<decltype (declval_void() = Desc::name)>>
+    : Fun<void()>
+{
+};
+
+struct Tag { static constexpr void* name = 0; };
+
+template<typename> void a()
+{
+  Fun<Tag>{}.fun();
+}
+
+void b() { a<int>(); }
diff --git a/gcc/testsuite/g++.dg/cpp0x/decltype65.C b/gcc/testsuite/g++.dg/cpp0x/decltype65.C
new file mode 100644
index 0000000..95fe0f1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/decltype65.C
@@ -0,0 +1,24 @@
+// PR c++/69694
+// This is a reduced version of decltype64.C.
+// { dg-do compile { target c++11 } }
+
+template<typename... Ts> using void_t = void;
+
+extern void *declval_void;
+
+template<typename, typename> struct Fun { };
+
+template<typename Desc>
+struct Fun<Desc, void_t<decltype (declval_void = Desc::name)>>
+{
+  void fun();
+};
+
+struct Tag { static constexpr void* name = 0; };
+
+template<typename> void a()
+{
+  Fun<Tag, void>{}.fun();
+}
+
+void b() { a<int>(); }
diff --git a/gcc/testsuite/g++.dg/cpp0x/error2.C b/gcc/testsuite/g++.dg/cpp0x/error2.C
index e6af294..ec58c9c 100644
--- a/gcc/testsuite/g++.dg/cpp0x/error2.C
+++ b/gcc/testsuite/g++.dg/cpp0x/error2.C
@@ -5,5 +5,5 @@ template<int> int foo();
 
 template<typename F> void bar(F f)
 {
-  f((foo<0>()=0)...); // { dg-error "pattern '\\(foo\\<0\\>\\)\\(\\)=0'" }
+  f((foo<0>()=0)...); // { dg-error "lvalue|pattern '\\(foo\\<0\\>\\)\\(\\)=0'" }
 }
diff --git a/gcc/testsuite/g++.dg/expr/unary2.C b/gcc/testsuite/g++.dg/expr/unary2.C
index 8418815..80bfd7d 100644
--- a/gcc/testsuite/g++.dg/expr/unary2.C
+++ b/gcc/testsuite/g++.dg/expr/unary2.C
@@ -15,6 +15,6 @@ void f(void)
 template <int>
 void g(void)
 {
-  -n = 0;        // { dg-error "lvalue" "" { xfail *-*-* } }
-  +n = 0;        // { dg-error "lvalue" "" { xfail *-*-* } }
+  -n = 0;        // { dg-error "lvalue" "" { xfail c++98_only } }
+  +n = 0;        // { dg-error "lvalue" "" { xfail c++98_only } }
 }
diff --git a/gcc/testsuite/g++.dg/ext/fixed1.C b/gcc/testsuite/g++.dg/ext/fixed1.C
index 5a479d6..4fcea0f 100644
--- a/gcc/testsuite/g++.dg/ext/fixed1.C
+++ b/gcc/testsuite/g++.dg/ext/fixed1.C
@@ -3,6 +3,6 @@
 
 template<int> struct A {};
 
-template<typename> struct B : A<sizeof(0=0r)> {};	// { dg-error "not supported" }
+template<typename> struct B : A<sizeof(0=0r)> {}; // { dg-error "convert|not supported" }
 
-template<typename> struct C : A<sizeof(0=0r)> {};	// { dg-error "not supported" }
+template<typename> struct C : A<sizeof(0=0r)> {}; // { dg-error "convert|not supported" }
diff --git a/gcc/testsuite/g++.dg/template/error35.C b/gcc/testsuite/g++.dg/template/error35.C
index d52e599..3b11fb7 100644
--- a/gcc/testsuite/g++.dg/template/error35.C
+++ b/gcc/testsuite/g++.dg/template/error35.C
@@ -1,3 +1,3 @@
 // PR c++/33494
 
-template<int> void foo(int(*f=0)()); // { dg-error "declared void|scope|erroneous-expression" }
+template<int> void foo(int(*f=0)()); // { dg-error "declared void|scope|expression" }
diff --git a/gcc/testsuite/g++.dg/template/init7.C b/gcc/testsuite/g++.dg/template/init7.C
index bb26c8f..3410c01 100644
--- a/gcc/testsuite/g++.dg/template/init7.C
+++ b/gcc/testsuite/g++.dg/template/init7.C
@@ -6,4 +6,5 @@ template<typename> struct A
   static const int i=0;
 };
 
-template<typename T> const int A<T>::i = 0=0; /* { dg-error "duplicate initialization" } */
+template<typename T>
+const int A<T>::i = 0=0; // { dg-error "duplicate initialization|lvalue" }
