public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [C++ PATCH] RFC: implement P0386R2 - C++17 inline variables
@ 2016-10-11 13:39 Jakub Jelinek
  2016-10-13 19:34 ` Jason Merrill
  2016-10-20 10:51 ` Eric Botcazou
  0 siblings, 2 replies; 15+ messages in thread
From: Jakub Jelinek @ 2016-10-11 13:39 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 39758 bytes --]

Hi!

Here is an attempt to implement C++17 inline variables.
Bootstrapped/regtested on x86_64-linux and i686-linux.

The main question is if the inline variables, which are vague linkage,
should be !DECL_EXTERNAL or DECL_EXTERNAL DECL_NOT_REALLY_EXTERN while
in the FE.  In the patch, they are !DECL_EXTERNAL, except for inline
static data members in instantiated templates.  As the inline-var3.C
testcase shows, even if they are !DECL_EXTERNAL (except for the instantiated
static data members), even at -O0 we do not actually emit them unless
odr-used, so to some extent I don't see the point in forcing them to
be DECL_EXTERNAL DECL_NOT_REALLY_EXTERN.  E.g. for debug info it seems
desirable that they are not DECL_EXTERNAL, otherwise we emit the in-class
definitions as if they were just declarations, which is bad.  Right now
the patch emits them correctly, except for the instantiated inline
static data members (where one sees only the in-class declaration which
is actually definition, and not any definition).
I've attempted to use the DECL_EXTERNAL DECL_NOT_REALLY_EXTERN for all the
inline vars, see the first attached patch, but that just breaks too much
(e.g. most of the vars aren't recorded in pending_statics, so nothing really
finalizes them using import_export_decl at eof).  So, shall we still
attempt to do it the DECL_EXTERNAL DECL_NOT_REALLY_EXTERN way everywhere
and e.g. solve the debug info stuff using langhooks, push all the inline
vars into pending_statics (or defer them for further processing later on)?
Or instead e.g. change the DECL_EXTERNAL DECL_NOT_REALLY_EXTERN for the
instantiated inline static data members earlier (and tweak instantiate_decl
to cope with that)?

Another thing is I've noticed (with Jonathan's help to look it up) that
we aren't implementing DR1511, I'm willing to try to implement that, but
as it will need to touch the same spots as the patch, I think it should be
resolved incrementally.

Yet another thing are thread_local inline vars.  E.g. on:
struct S { S (); ~S (); };
struct T { ~T (); };
int foo ();
thread_local inline S s;
inline thread_local T t;
inline thread_local int u = foo ();
it seems both clang++ (~2 months old) and g++ with the patch emits:
8 byte TLS _ZGV1{stu] variables
1 byte TLS __tls_guard variable
and _ZTH1[stu] being aliases to __tls_init, which does essentially:
  if (__tls_guard) return;
  __tls_guard = 1;
  if (*(char *)&_ZGV1s == 0) {
    *(char *)&_ZGV1s = 1;
    S::S (&s);
    __cxa_thread_atexit (S::~S, &s, &__dso_handle);
  }
  if (*(char *)&_ZGV1t == 0) {
    *(char *)&_ZGV1t = 1;
    __cxa_thread_atexit (T::~T, &t, &__dso_handle);
  }
  if (*(char *)&_ZGV1u == 0) {
    *(char *)&_ZGV1u = 1;
    u = foo ();
  }
Is that what we want to emit?  At first I doubted this could work properly,
now thinking about it more, perhaps it can.  And, do we really want all the
_ZGV* vars for the TLS inline vars (and other TLS comdats) to be 8 byte,
even when we are using just a single byte?  Or is it too late to change (ABI
break)?

For the non-TLS inline vars that need runtime construction/initialization
and/or destruction, GCC with the patch emits just non-atomic comparisons
of the _ZGV* vars, while clang++ apparently emits __cxa_guard*.  As it
happens in the library/binary constructors only, I think what G++ emits
looks right to me, but am not 100% sure.

And, as mentioned in the DWARF mailing list, I think we should emit
DW_AT_inline on the inline vars (both explicit and implicit - static
constexpr data members in C++17 mode).  I hope that can be done as a
follow-up.

2016-10-11  Jakub Jelinek  <jakub@redhat.com>

	Implement P0386R2 - C++17 inline variables
	* dwarf2out.c (gen_member_die): Handle inline static data member
	definitions.
cp/
	* cp-tree.h (struct lang_type): Shrink language field to 1 bit
	from 4.  Add var_declared_inline_p field.  Mention 2 spare bits.
	(DECL_VAR_DECLARED_INLINE_P): Define.
	(SET_DECL_VAR_DECLARED_INLINE_P): Define.
	(DECL_INLINE_VAR_P): Define.
	(diagnose_inline_vars_for_namespace): Declare.
	* decl.c (diagnose_inline_vars_for_namespace): New function.
	(duplicate_decls): For static data members copy
	DECL_DECLARED_CONSTEXPR_P.
	(redeclaration_error_message): Handle C++17 redundant redeclaration
	of constexpr static data member outside of class.
	(maybe_commonize_var): Handle inline variables.
	(check_initializer): Ignore inline variables for diagnostics.
	Adjust diagnostic wording for C++17.
	(make_rtl_for_nonlocal_decl): Allow in-class definition of
	inline static data members.
	(bad_specifiers): Don't diagnose inline on variables here.
	(grokvardecl): Add inlinep argument, non-static const inline variables
	are TREE_PUBLIC.
	(check_static_variable_definition): Return early also for inline
	variables.
	(grokdeclarator): Handle inline variables and inline static data
	members.
	* typeck2.c (store_init_value): Don't diagnose non-constant
	initializers for non-constexpr inline static data members.
	* decl2.c (vague_linkage_p): Return true for inline variables.
	(c_parse_final_cleanups): In-class declaration of inline static
	data members is a definition.  Call diagnose_inline_vars_for_namespace
	through walk_namespaces.
	* pt.c (instantiate_decl): Set pattern_defined for in-class definitions
	of inline static data members.
testsuite/
	* g++.dg/cpp1z/inline-var1.C: New test.
	* g++.dg/cpp1z/inline-var1a.C: New test.
	* g++.dg/cpp1z/inline-var1.h: New file.
	* g++.dg/cpp1z/inline-var2.C: New test.
	* g++.dg/cpp1z/inline-var3.C: New test.
	* g++.dg/concepts/decl-diagnose.C (struct X): Expect also error about
	uninitialized const.

--- gcc/cp/cp-tree.h.jj	2016-10-09 13:17:44.660649116 +0200
+++ gcc/cp/cp-tree.h	2016-10-10 16:08:42.972908494 +0200
@@ -2214,7 +2214,7 @@ struct GTY(()) lang_type {
 
 struct GTY(()) lang_decl_base {
   unsigned selector : 16;   /* Larger than necessary for faster access.  */
-  ENUM_BITFIELD(languages) language : 4;
+  ENUM_BITFIELD(languages) language : 1;
   unsigned use_template : 2;
   unsigned not_really_extern : 1;	   /* var or fn */
   unsigned initialized_in_class : 1;	   /* var or fn */
@@ -2227,7 +2227,8 @@ struct GTY(()) lang_decl_base {
   unsigned odr_used : 1;		   /* var or fn */
   unsigned u2sel : 1;
   unsigned concept_p : 1;                  /* applies to vars and functions */
-  /* 0 spare bits */
+  unsigned var_declared_inline_p : 1;	   /* var */
+  /* 2 spare bits */
 };
 
 /* True for DECL codes which have template info and access.  */
@@ -3607,6 +3608,23 @@ more_aggr_init_expr_args_p (const aggr_i
 #define CP_DECL_THREADPRIVATE_P(DECL) \
   (DECL_LANG_SPECIFIC (VAR_DECL_CHECK (DECL))->u.base.threadprivate_or_deleted_p)
 
+/* Nonzero if NODE is a VAR_DECL which has been declared inline.  */
+#define DECL_VAR_DECLARED_INLINE_P(NODE) \
+  (DECL_LANG_SPECIFIC (VAR_DECL_CHECK (NODE))			\
+   ? DECL_LANG_SPECIFIC (NODE)->u.base.var_declared_inline_p	\
+   : false)
+#define SET_DECL_VAR_DECLARED_INLINE_P(NODE) \
+  (DECL_LANG_SPECIFIC (VAR_DECL_CHECK (NODE))->u.base.var_declared_inline_p \
+   = true)
+
+/* Nonzero if NODE is an inline VAR_DECL.  In C++17, static data members
+   declared with constexpr specifier are implicitly inline variables.  */
+#define DECL_INLINE_VAR_P(NODE) \
+  (DECL_VAR_DECLARED_INLINE_P (NODE)				\
+   || (cxx_dialect >= cxx1z					\
+       && DECL_DECLARED_CONSTEXPR_P (NODE)			\
+       && DECL_CLASS_SCOPE_P (NODE)))
+
 /* Nonzero if DECL was declared with '= delete'.  */
 #define DECL_DELETED_FN(DECL) \
   (LANG_DECL_FN_CHECK (DECL)->min.base.threadprivate_or_deleted_p)
@@ -5799,6 +5817,7 @@ typedef int (*walk_namespaces_fn)		(tree
 extern int walk_namespaces			(walk_namespaces_fn,
 						 void *);
 extern int wrapup_globals_for_namespace		(tree, void *);
+extern int diagnose_inline_vars_for_namespace	(tree, void *);
 extern tree create_implicit_typedef		(tree, tree);
 extern int local_variable_p			(const_tree);
 extern tree register_dtor_fn			(tree);
--- gcc/cp/decl.c.jj	2016-10-07 21:36:00.175443903 +0200
+++ gcc/cp/decl.c	2016-10-11 15:05:52.537759432 +0200
@@ -68,7 +68,7 @@ static int unary_op_p (enum tree_code);
 static void push_local_name (tree);
 static tree grok_reference_init (tree, tree, tree, int);
 static tree grokvardecl (tree, tree, tree, const cp_decl_specifier_seq *,
-			 int, int, int, tree);
+			 int, int, int, int, tree);
 static int check_static_variable_definition (tree, tree);
 static void record_unknown_type (tree, const char *);
 static tree builtin_function_1 (tree, tree, bool);
@@ -937,6 +937,27 @@ wrapup_globals_for_namespace (tree name_
   /* Write out any globals that need to be output.  */
   return wrapup_global_declarations (vec, len);
 }
+
+/* Diagnose odr-used extern inline variables without definitions
+   in the current TU.  */
+int
+diagnose_inline_vars_for_namespace (tree name_space, void *)
+{
+  cp_binding_level *level = NAMESPACE_LEVEL (name_space);
+  vec<tree, va_gc> *statics = level->static_decls;
+  tree decl;
+  unsigned int i;
+
+  FOR_EACH_VEC_SAFE_ELT (statics, i, decl)
+    if (VAR_P (decl)
+	&& DECL_EXTERNAL (decl)
+	&& DECL_INLINE_VAR_P (decl)
+	&& DECL_ODR_USED (decl))
+      error_at (DECL_SOURCE_LOCATION (decl),
+		"odr-used inline variable %qD is not defined", decl);
+
+  return 0;
+}
 \f
 /* In C++, you don't have to write `struct S' to refer to `S'; you
    can just use `S'.  We accomplish this by creating a TYPE_DECL as
@@ -2098,6 +2119,9 @@ duplicate_decls (tree newdecl, tree oldd
 	    |= DECL_NONTRIVIALLY_INITIALIZED_P (olddecl);
 	  DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (newdecl)
 	    |= DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (olddecl);
+          if (DECL_CLASS_SCOPE_P (olddecl))
+            DECL_DECLARED_CONSTEXPR_P (newdecl)
+	      |= DECL_DECLARED_CONSTEXPR_P (olddecl);
 
 	  /* Merge the threadprivate attribute from OLDDECL into NEWDECL.  */
 	  if (DECL_LANG_SPECIFIC (olddecl)
@@ -2882,6 +2906,25 @@ redeclaration_error_message (tree newdec
 	 is valid.  */
       if (DECL_EXTERNAL (newdecl) || DECL_EXTERNAL (olddecl))
 	return NULL;
+
+      /* Static data member declared outside a class definition
+	 if the variable is defined within the class with constexpr
+	 specifier is declaration rather than definition (and
+	 deprecated).  */
+      if (cxx_dialect >= cxx1z
+	  && DECL_CLASS_SCOPE_P (olddecl)
+	  && DECL_DECLARED_CONSTEXPR_P (olddecl)
+	  && !DECL_INITIAL (newdecl))
+	{
+	  DECL_EXTERNAL (newdecl) = 1;
+	  if (warning_at (DECL_SOURCE_LOCATION (newdecl), OPT_Wdeprecated,
+			  "redundant redeclaration of %<constexpr%> static "
+			  "data member %qD", newdecl))
+	    inform (DECL_SOURCE_LOCATION (olddecl),
+		    "previous declaration of %qD", olddecl);
+	  return NULL;
+	}
+
       /* Reject two definitions.  */
       return G_("redefinition of %q#D");
     }
@@ -5405,11 +5448,12 @@ maybe_commonize_var (tree decl)
 {
   /* Static data in a function with comdat linkage also has comdat
      linkage.  */
-  if (TREE_STATIC (decl)
-      /* Don't mess with __FUNCTION__.  */
-      && ! DECL_ARTIFICIAL (decl)
-      && DECL_FUNCTION_SCOPE_P (decl)
-      && vague_linkage_p (DECL_CONTEXT (decl)))
+  if ((TREE_STATIC (decl)
+       /* Don't mess with __FUNCTION__.  */
+       && ! DECL_ARTIFICIAL (decl)
+       && DECL_FUNCTION_SCOPE_P (decl)
+       && vague_linkage_p (DECL_CONTEXT (decl)))
+      || (TREE_PUBLIC (decl) && DECL_INLINE_VAR_P (decl)))
     {
       if (flag_weak)
 	{
@@ -5435,12 +5479,18 @@ maybe_commonize_var (tree decl)
 		 be merged.  */
 	      TREE_PUBLIC (decl) = 0;
 	      DECL_COMMON (decl) = 0;
-	      if (warning_at (DECL_SOURCE_LOCATION (decl), 0,
-			      "sorry: semantics of inline function static "
-			      "data %q#D are wrong (you%'ll wind up "
-			      "with multiple copies)", decl))
+	      if (DECL_INLINE_VAR_P (decl))
+		warning_at (DECL_SOURCE_LOCATION (decl), 0,
+			    "sorry: semantics of inline variable "
+			    "%q#D are wrong (you%'ll wind up with "
+			    "multiple copies)", decl);
+	      else if (warning_at (DECL_SOURCE_LOCATION (decl), 0,
+				   "sorry: semantics of inline function "
+				   "static data %q#D are wrong (you%'ll wind "
+				   "up with multiple copies)", decl))
 		inform (DECL_SOURCE_LOCATION (decl),
-			"you can work around this by removing the initializer");
+			"you can work around this by removing the "
+			"initializer");
 	    }
 	}
     }
@@ -6282,15 +6332,19 @@ check_initializer (tree decl, tree init,
       TREE_CONSTANT (decl) = false;
     }
 
-  if (init_code && DECL_IN_AGGR_P (decl))
+  if (init_code
+      && (DECL_IN_AGGR_P (decl) && !DECL_VAR_DECLARED_INLINE_P (decl)))
     {
       static int explained = 0;
 
       if (cxx_dialect < cxx11)
 	error ("initializer invalid for static member with constructor");
-      else
+      else if (cxx_dialect < cxx1z)
 	error ("non-constant in-class initialization invalid for static "
 	       "member %qD", decl);
+      else
+	error ("non-constant in-class initialization invalid for non-inline "
+	       "static member %qD", decl);
       if (!explained)
 	{
 	  inform (input_location,
@@ -6346,7 +6400,9 @@ make_rtl_for_nonlocal_decl (tree decl, t
       /* An in-class declaration of a static data member should be
 	 external; it is only a declaration, and not a definition.  */
       if (init == NULL_TREE)
-	gcc_assert (DECL_EXTERNAL (decl) || !TREE_PUBLIC (decl));
+	gcc_assert (DECL_EXTERNAL (decl)
+		    || !TREE_PUBLIC (decl)
+		    || DECL_INLINE_VAR_P (decl));
     }
 
   /* We don't create any RTL for local variables.  */
@@ -7745,8 +7801,6 @@ bad_specifiers (tree object,
       case BSP_VAR:
 	if (virtualp)
 	  error ("%qD declared as a %<virtual%> variable", object);
-	if (inlinep)
-	  error ("%qD declared as an %<inline%> variable", object);
 	if (quals)
 	  error ("%<const%> and %<volatile%> function specifiers on "
 	         "%qD invalid in variable declaration", object);
@@ -8456,6 +8510,7 @@ grokvardecl (tree type,
 	     const cp_decl_specifier_seq *declspecs,
 	     int initialized,
 	     int flags,
+	     int inlinep,
 	     int template_count,
 	     tree scope)
 {
@@ -8520,7 +8575,9 @@ grokvardecl (tree type,
   else if (toplevel_bindings_p ())
     {
       TREE_PUBLIC (decl) = (declspecs->storage_class != sc_static
-			    && (DECL_THIS_EXTERN (decl) || ! constp));
+			    && (DECL_THIS_EXTERN (decl)
+				|| ! constp
+				|| inlinep));
       TREE_STATIC (decl) = ! DECL_EXTERNAL (decl);
     }
   /* Not at top level, only `static' makes a static definition.  */
@@ -8692,8 +8749,10 @@ check_static_variable_definition (tree d
   if (dependent_type_p (type))
     return 0;
   /* If DECL is declared constexpr, we'll do the appropriate checks
-     in check_initializer.  */
-  if (DECL_P (decl) && DECL_DECLARED_CONSTEXPR_P (decl))
+     in check_initializer.  Similarly for inline static data members.  */
+  if (DECL_P (decl)
+      && (DECL_DECLARED_CONSTEXPR_P (decl)
+	  || DECL_VAR_DECLARED_INLINE_P (decl)))
     return 0;
   else if (cxx_dialect >= cxx11 && !INTEGRAL_OR_ENUMERATION_TYPE_P (type))
     {
@@ -11349,11 +11408,6 @@ grokdeclarator (const cp_declarator *dec
 					    : input_location,
 					    VAR_DECL, unqualified_id, type);
 		set_linkage_for_static_data_member (decl);
-		/* Even if there is an in-class initialization, DECL
-		   is considered undefined until an out-of-class
-		   definition is provided.  */
-		DECL_EXTERNAL (decl) = 1;
-
 		if (thread_p)
 		  {
 		    CP_DECL_THREAD_LOCAL_P (decl) = true;
@@ -11371,6 +11425,30 @@ grokdeclarator (const cp_declarator *dec
 			   "initializer", decl);
 		    constexpr_p = false;
 		  }
+
+		if (inlinep)
+		  {
+		    if (! toplevel_bindings_p ())
+		      {
+			error ("%<inline%> specifier invalid for variable "
+			       "%qD declared at block scope", decl);
+			inlinep = false;
+		      }
+		    else if (cxx_dialect < cxx1z)
+		      pedwarn (DECL_SOURCE_LOCATION (decl), 0,
+			       "inline variables are only available "
+			       "with -std=c++1z or -std=gnu++1z");
+		    if (inlinep)
+		      SET_DECL_VAR_DECLARED_INLINE_P (decl);
+		  }
+
+		if (!DECL_VAR_DECLARED_INLINE_P (decl)
+		    && !(cxx_dialect >= cxx1z && constexpr_p))
+		  /* Even if there is an in-class initialization, DECL
+		     is considered undefined until an out-of-class
+		     definition is provided, unless this is an inline
+		     variable.  */
+		  DECL_EXTERNAL (decl) = 1;
 	      }
 	    else
 	      {
@@ -11411,7 +11489,8 @@ grokdeclarator (const cp_declarator *dec
 
 	    bad_specifiers (decl, BSP_FIELD, virtualp,
 			    memfn_quals != TYPE_UNQUALIFIED,
-			    inlinep, friendp, raises != NULL_TREE);
+			    staticp ? false : inlinep, friendp,
+			    raises != NULL_TREE);
 	  }
       }
     else if (TREE_CODE (type) == FUNCTION_TYPE
@@ -11535,6 +11614,7 @@ grokdeclarator (const cp_declarator *dec
 			    declspecs,
 			    initialized,
 			    ((type_quals & TYPE_QUAL_CONST) != 0) | (2 * concept_p),
+			    inlinep,
 			    template_count,
 			    ctype ? ctype : in_namespace);
 	if (decl == NULL_TREE)
@@ -11573,6 +11653,25 @@ grokdeclarator (const cp_declarator *dec
 		   decl);
 	    constexpr_p = false;
 	  }
+
+	if (inlinep)
+	  {
+	    if (! toplevel_bindings_p ())
+	      {
+		error ("%<inline%> specifier invalid for variable %qs "
+		       "declared at block scope", name);
+		inlinep = false;
+	      }
+	    else if (cxx_dialect < cxx1z)
+	      pedwarn (DECL_SOURCE_LOCATION (decl), 0,
+		       "inline variables are only available "
+		       "with -std=c++1z or -std=gnu++1z");
+	    if (inlinep)
+	      {
+		retrofit_lang_decl (decl);
+		SET_DECL_VAR_DECLARED_INLINE_P (decl);
+	      }
+	  }
       }
 
     if (VAR_P (decl) && !initialized)
--- gcc/cp/typeck2.c.jj	2016-10-05 17:01:29.000000000 +0200
+++ gcc/cp/typeck2.c	2016-10-10 14:46:27.595386236 +0200
@@ -807,7 +807,7 @@ store_init_value (tree decl, tree init,
       bool const_init;
       value = instantiate_non_dependent_expr (value);
       if (DECL_DECLARED_CONSTEXPR_P (decl)
-	  || DECL_IN_AGGR_P (decl))
+	  || (DECL_IN_AGGR_P (decl) && !DECL_VAR_DECLARED_INLINE_P (decl)))
 	{
 	  /* Diagnose a non-constant initializer for constexpr.  */
 	  if (processing_template_decl
--- gcc/cp/decl2.c.jj	2016-10-04 17:30:36.000000000 +0200
+++ gcc/cp/decl2.c	2016-10-10 20:58:12.696961960 +0200
@@ -1826,7 +1826,8 @@ vague_linkage_p (tree decl)
       || (TREE_CODE (decl) == FUNCTION_DECL
 	  && DECL_DECLARED_INLINE_P (decl))
       || (DECL_LANG_SPECIFIC (decl)
-	  && DECL_TEMPLATE_INSTANTIATION (decl)))
+	  && DECL_TEMPLATE_INSTANTIATION (decl))
+      || (VAR_P (decl) && DECL_INLINE_VAR_P (decl)))
     return true;
   else if (DECL_FUNCTION_SCOPE_P (decl))
     /* A local static in an inline effectively has vague linkage.  */
@@ -4710,7 +4711,7 @@ c_parse_final_cleanups (void)
 	{
 	  if (var_finalized_p (decl) || DECL_REALLY_EXTERN (decl)
 	      /* Don't write it out if we haven't seen a definition.  */
-	      || DECL_IN_AGGR_P (decl))
+	      || (DECL_IN_AGGR_P (decl) && !DECL_INLINE_VAR_P (decl)))
 	    continue;
 	  import_export_decl (decl);
 	  /* If this static data member is needed, provide it to the
@@ -4727,6 +4728,8 @@ c_parse_final_cleanups (void)
     }
   while (reconsider);
 
+  walk_namespaces (diagnose_inline_vars_for_namespace, /*data=*/0);
+
   lower_var_init ();
 
   generate_mangling_aliases ();
--- gcc/cp/pt.c.jj	2016-10-08 12:41:26.000000000 +0200
+++ gcc/cp/pt.c	2016-10-10 20:13:09.526213150 +0200
@@ -21919,7 +21919,8 @@ instantiate_decl (tree d, int defer_ok,
     {
       deleted_p = false;
       if (DECL_CLASS_SCOPE_P (code_pattern))
-	pattern_defined = ! DECL_IN_AGGR_P (code_pattern);
+	pattern_defined = (! DECL_IN_AGGR_P (code_pattern)
+			   || DECL_INLINE_VAR_P (code_pattern));
       else
 	pattern_defined = ! DECL_EXTERNAL (code_pattern);
     }
--- gcc/dwarf2out.c.jj	2016-10-09 13:19:09.000000000 +0200
+++ gcc/dwarf2out.c	2016-10-11 11:48:20.105509362 +0200
@@ -22594,7 +22594,17 @@ gen_member_die (tree type, dw_die_ref co
 
       child = lookup_decl_die (member);
       if (child)
-	splice_child_die (context_die, child);
+	{
+	  /* Handle inline static data members.  */
+	  if (child->die_tag == DW_TAG_variable
+	      && child->die_parent == comp_unit_die ())
+	    {
+	      reparent_child (child, context_die);
+	      child->die_tag = DW_TAG_member;
+	    }
+	  else
+	    splice_child_die (context_die, child);
+	}
 
       /* Do not generate standard DWARF for variant parts if we are generating
 	 the corresponding GNAT encodings: DIEs generated for both would
--- gcc/testsuite/g++.dg/cpp1z/inline-var1.C.jj	2016-10-10 13:22:46.824587637 +0200
+++ gcc/testsuite/g++.dg/cpp1z/inline-var1.C	2016-10-11 10:01:45.536515171 +0200
@@ -0,0 +1,216 @@
+// { dg-do run }
+// { dg-options "-std=c++1z -Wno-deprecated" }
+// { dg-require-weak "" }
+// { dg-additional-sources "inline-var1a.C" }
+
+#include "inline-var1.h"
+
+static inline int var19 = bar (0);
+static int inline var20 = bar (1);
+extern inline int var23;
+inline int var21 = foo (6);
+inline int var22 = foo (7);
+extern inline int var23, var22;
+inline int var23 = foo (8);
+
+static int v, w;
+
+int
+foo (int x)
+{
+  if (x != v++)
+    __builtin_abort ();
+  return 36 + x;
+}
+
+int
+bar (int x)
+{
+  if (v < 6)
+    __builtin_abort ();
+  if ((x >> 4) != (w >> 4))
+    {
+      if ((x & 15) != 0 || (w & 15) != 2)
+	__builtin_abort ();
+      w = x + 1;
+    }
+  else if (x != w++)
+    __builtin_abort ();
+  return 46 + x;
+}
+
+int &ref1 = var1;
+int &ref2 = N::var2;
+const int &ref3 = S::var3;
+int &ref4 = S::var4;
+const int &ref5 = S::var5;
+const int &ref6 = N::var6;
+int &ref7 = var7;
+double &ref8 = N::var8;
+double &ref9 = S::var9;
+const int &ref11 = S::var11;
+int &ref12 = var12;
+int &ref13 = var13;
+int &ref14 = U::var14;
+T &ref15 = U::var15;
+T &ref16 = U::var16;
+int &ref17 = U::var17;
+const double &ref18 = U::var18;
+int &ref19 = var19;
+int &ref20 = var20;
+int &ref21 = var21;
+int &ref22 = var22;
+int &ref23 = var23;
+const int &ref24 = Y<int>::var24;
+int &ref25 = Y<int>::var25;
+int &ref26 = Y<int>::var26;
+int &ref27 = var27<int>;
+const int &ref28 = Y<int>::var28;
+const char &ref24a = Y<char>::var24;
+char &ref25a = Y<char>::var25;
+int &ref26a = Y<char>::var26;
+char &ref27a = var27<char>;
+const char &ref28a = Y<char>::var28;
+extern int &alt1;
+extern int &alt2;
+extern const int &alt3;
+extern int &alt4;
+extern const int &alt5;
+extern const int &alt6;
+extern int &alt7;
+extern double &alt8;
+extern double &alt9;
+extern const int &alt11;
+extern int &alt12;
+extern int &alt13;
+extern int &alt14;
+extern T &alt15;
+extern T &alt16;
+extern int &alt17;
+extern const double &alt18;
+extern int &alt19;
+extern int &alt20;
+extern int &alt21;
+extern int &alt22;
+extern int &alt23;
+extern const int &alt24;
+extern int &alt25;
+extern int &alt26;
+extern int &alt27;
+extern const int &alt28;
+extern const char &alt24a;
+extern char &alt25a;
+extern int &alt26a;
+extern char &alt27a;
+extern const char &alt28a;
+
+int
+main ()
+{
+  if (v != 9)
+    __builtin_abort ();
+  if (var1 != 4
+      || N::var2 != 0
+      || S::var3 != 5
+      || S::var4 != 6
+      || S::var5 != 7
+      || N::var6 != 8
+      || var7 != 9
+      || N::var8 != 2.0
+      || S::var9 != 3.0
+      || sizeof (N::var10) != 1
+      || S::var11 != 11
+      || var12 != 36
+      || var13 != 37
+      || U::var14 != 38
+      || U::var15.t != 39
+      || U::var16.t != 40
+      || U::var17 != 41
+      || U::var18 != 4.0
+      || var19 != 46
+      || var20 != 47
+      || var21 != 42
+      || var22 != 43
+      || var23 != 44
+      || Y<int>::var24 != 6
+      || Y<int>::var25 != 7
+      || Y<int>::var26 != 8
+      || var27<int> != 9
+      || Y<int>::var28 != 10
+      || Y<char>::var24 != 6
+      || Y<char>::var25 != 7
+      || Y<char>::var26 != 8
+      || var27<char> != 9
+      || Y<char>::var28 != 10)
+    __builtin_abort ();
+  if (ref1 != 4
+      || ref2 != 0
+      || ref3 != 5
+      || ref4 != 6
+      || ref5 != 7
+      || ref6 != 8
+      || ref7 != 9
+      || alt7 != 9
+      || ref8 != 2.0
+      || alt8 != 2.0
+      || ref9 != 3.0
+      || ref11 != 11
+      || ref12 != 36
+      || ref13 != 37
+      || ref14 != 38
+      || ref15.t != 39
+      || ref16.t != 40
+      || ref17 != 41
+      || ref18 != 4.0
+      || ref19 != 46
+      || alt19 != 62
+      || ref20 != 47
+      || alt20 != 63
+      || ref21 != 42
+      || ref22 != 43
+      || ref23 != 44
+      || ref24 != 6
+      || ref25 != 7
+      || ref26 != 8
+      || ref27 != 9
+      || ref28 != 10
+      || ref24a != 6
+      || ref25a != 7
+      || ref26a != 8
+      || ref27a != 9
+      || ref28a != 10)
+    __builtin_abort ();
+  if (&ref1 != &alt1
+      || &ref2 != &alt2
+      || &ref3 != &alt3
+      || &ref4 != &alt4
+      || &ref5 != &alt5
+      || &ref6 != &alt6
+      || &ref7 == &alt7
+      || &ref8 == &alt8
+      || &ref9 != &alt9
+      || &ref11 != &alt11
+      || &ref12 != &alt12
+      || &ref13 != &alt13
+      || &ref14 != &alt14
+      || &ref15 != &alt15
+      || &ref16 != &alt16
+      || &ref17 != &alt17
+      || &ref18 != &alt18
+      || &ref19 == &alt19
+      || &ref20 == &alt20
+      || &ref21 != &alt21
+      || &ref22 != &alt22
+      || &ref23 != &alt23
+      || &ref24 != &alt24
+      || &ref25 != &alt25
+      || &ref26 != &alt26
+      || &ref27 != &alt27
+      || &ref28 != &alt28
+      || &ref24a != &alt24a
+      || &ref25a != &alt25a
+      || &ref26a != &alt26a
+      || &ref27a != &alt27a
+      || &ref28a != &alt28a)
+    __builtin_abort ();
+}
--- gcc/testsuite/g++.dg/cpp1z/inline-var1a.C.jj	2016-10-10 13:27:19.252122373 +0200
+++ gcc/testsuite/g++.dg/cpp1z/inline-var1a.C	2016-10-11 10:02:16.582121384 +0200
@@ -0,0 +1,44 @@
+// { dg-do compile }
+// { dg-options "-std=c++1z -Wno-deprecated -g" }
+
+#include "inline-var1.h"
+
+static inline int var19 = bar (16);
+static int inline var20 = bar (17);
+inline int var21 = foo (6);
+inline int var22 = foo (7);
+extern inline int var23;   
+inline int var23 = foo (8);
+
+int &alt1 = var1;
+int &alt2 = N::var2;   
+const int &alt3 = S::var3;
+int &alt4 = S::var4;   
+const int &alt5 = S::var5;
+const int &alt6 = N::var6;
+int &alt7 = var7;
+double &alt8 = N::var8;
+double &alt9 = S::var9; 
+const int &alt11 = S::var11;
+int &alt12 = var12;
+int &alt13 = var13;
+int &alt14 = U::var14;
+T &alt15 = U::var15;
+T &alt16 = U::var16;
+int &alt17 = U::var17;
+const double &alt18 = U::var18;
+int &alt19 = var19;
+int &alt20 = var20;
+int &alt21 = var21;
+int &alt22 = var22;
+int &alt23 = var23;
+const int &alt24 = Y<int>::var24;
+int &alt25 = Y<int>::var25;
+int &alt26 = Y<int>::var26;
+int &alt27 = var27<int>;
+const int &alt28 = Y<int>::var28;
+const char &alt24a = Y<char>::var24;
+char &alt25a = Y<char>::var25;
+int &alt26a = Y<char>::var26;
+char &alt27a = var27<char>;
+const char &alt28a = Y<char>::var28;
--- gcc/testsuite/g++.dg/cpp1z/inline-var1.h.jj	2016-10-10 13:22:37.704703274 +0200
+++ gcc/testsuite/g++.dg/cpp1z/inline-var1.h	2016-10-11 09:59:34.307179703 +0200
@@ -0,0 +1,46 @@
+inline int var1 = 4;
+static inline int var7 = 9;
+namespace N
+{
+  int inline var2;
+  inline const int var6 = 8;
+  static inline double var8 = 2.0;
+  extern inline char var10;
+}
+struct S
+{
+  static constexpr int var3 = 5;
+  static inline int var4 = 6;
+  static constexpr int var5 = 7;
+  static inline double var9 = 3.0;
+  static constexpr inline int var11 = 11;
+};
+const int S::var3;
+const int S::var3;
+extern int foo (int);
+extern int bar (int);
+struct T { T () { t = foo (3); } T (int x) { t = foo (x); } int t; };
+inline int var12 = foo (0);
+int inline var13 = foo (1);
+struct U
+{
+  static inline int var14 = foo (2);
+  static inline T var15;
+  static inline T var16 = 4;
+  static int inline var17 = foo (5);
+  static constexpr double var18 = 4.0;
+};
+template <typename T>
+struct Y
+{
+  static constexpr T var24 = 6;
+  static inline T var25 = 7;
+  static inline int var26 = 8;
+  static constexpr T var28 = 10;
+};
+template <typename T>
+const T Y<T>::var24;
+template <typename T>
+const T Y<T>::var24;
+template <typename T>
+inline T var27 = 9;
--- gcc/testsuite/g++.dg/cpp1z/inline-var2.C.jj	2016-10-10 15:39:58.966712519 +0200
+++ gcc/testsuite/g++.dg/cpp1z/inline-var2.C	2016-10-11 15:04:50.994531166 +0200
@@ -0,0 +1,117 @@
+// { dg-do compile { target c++11 } }
+// { dg-options "-Wdeprecated" }
+
+inline int var1 = 4;				// { dg-warning "inline variables are only available with" "" { target c++14_down } }
+static inline int var7 = 9;			// { dg-warning "inline variables are only available with" "" { target c++14_down } }
+namespace N
+{
+  int inline var2;				// { dg-warning "inline variables are only available with" "" { target c++14_down } }
+  inline const int var6 = 8;			// { dg-warning "inline variables are only available with" "" { target c++14_down } }
+  static inline double var8 = 2.0;		// { dg-warning "inline variables are only available with" "" { target c++14_down } }
+  extern inline char var10;			// { dg-warning "inline variables are only available with" "" { target c++14_down } }
+}
+struct S
+{
+  static constexpr int var3 = 5;
+  static inline int var4 = 6;			// { dg-warning "inline variables are only available with" "" { target c++14_down } }
+  static constexpr int var5 = 7;
+  static inline double var9 = 3.0;		// { dg-warning "inline variables are only available with" "" { target c++14_down } }
+  static constexpr inline int var11 = 11;	// { dg-warning "inline variables are only available with" "" { target c++14_down } }
+};
+const int S::var3;				// { dg-warning "redundant redeclaration of" "" { target c++1z } }
+const int S::var3;				// { dg-error "redefinition of" "" { target c++14_down } }
+extern int foo (int);				// { dg-warning "redundant redeclaration of" "" { target c++1z } .-1 }
+extern int bar (int);
+struct T { T () { t = foo (3); } T (int x) { t = foo (x); } int t; };
+inline int var12 = foo (0);			// { dg-warning "inline variables are only available with" "" { target c++14_down } }
+int inline var13 = foo (1);			// { dg-warning "inline variables are only available with" "" { target c++14_down } }
+struct U
+{
+  static inline int var14 = foo (2);		// { dg-warning "inline variables are only available with" "" { target c++14_down } }
+  static inline T var15;			// { dg-warning "inline variables are only available with" "" { target c++14_down } }
+  static inline T var16 = 4;			// { dg-warning "inline variables are only available with" "" { target c++14_down } }
+  static int inline var17 = foo (5);		// { dg-warning "inline variables are only available with" "" { target c++14_down } }
+  static constexpr double var18 = 4.0;
+};
+extern inline int var19;			// { dg-warning "inline variables are only available with" "" { target c++14_down } }
+extern inline int var20;			// { dg-warning "inline variables are only available with" "" { target c++14_down } }
+int &ref19 = var19;				// { dg-error "odr-used inline variable 'var19' is not defined" "" { target *-*-* } .-2 }
+int sz20 = sizeof (var20);
+struct V
+{
+  static struct A var21;			// { dg-warning "inline variables are only available with" "" { target c++14_down } .+1 }
+  static inline struct B var22;			// { dg-error "has incomplete type" }
+  static inline struct C var23 = {};		// { dg-error "has incomplete type" }
+};						// { dg-warning "inline variables are only available with" "" { target c++14_down } .-1 }
+struct W
+{
+  static inline int var24;			// { dg-warning "inline variables are only available with" "" { target c++14_down } }
+  static inline const int var25;		// { dg-warning "inline variables are only available with" "" { target c++14_down } }
+						// { dg-error "uninitialized const" "" { target *-*-* } .-1 }
+  static inline int var26 = 5;			// { dg-warning "inline variables are only available with" "" { target c++14_down } }
+  static inline const int var27 = 6;		// { dg-warning "inline variables are only available with" "" { target c++14_down } }
+  static inline double var28 = { 4.0 };		// { dg-warning "inline variables are only available with" "" { target c++14_down } }
+  static const inline double var29 = { 5.0 };	// { dg-warning "inline variables are only available with" "" { target c++14_down } }
+};
+int W::var24;					// { dg-error "redefinition of" }
+const int W::var25;				// { dg-error "redefinition of" }
+int W::var26;					// { dg-error "redefinition of" }
+const int W::var27;				// { dg-error "redefinition of" }
+double W::var28;				// { dg-error "redefinition of" }
+double const W::var29;				// { dg-error "redefinition of" }
+struct X
+{
+  inline int var30;				// { dg-error "'var30' declared as an 'inline' field" }
+};
+inline typedef int TT;				// { dg-error "'TT' declared as an 'inline' type" }
+int
+foo (inline int var31)				// { dg-error "'var31' declared as an 'inline' parameter" }
+{
+  inline int var32;				// { dg-error "'inline' specifier invalid for variable 'var32' declared at block scope" }
+  static inline int var33;			// { dg-error "'inline' specifier invalid for variable 'var33' declared at block scope" }
+}
+template <typename A, typename B, typename C>
+struct Y
+{
+  static A var34;				// { dg-warning "inline variables are only available with" "" { target c++14_down } .+1 }
+  static inline B var35;			// { dg-error "has incomplete type" }
+  static inline C var36;			// { dg-error "has incomplete type" }
+};						// { dg-warning "inline variables are only available with" "" { target c++14_down } .-1 }
+struct A;
+struct B;
+struct C;
+Y<A, B, C> y;
+A *ptr34 = &Y<A, B, C>::var34;
+B *ptr35 = &Y<A, B, C>::var35;
+C *ptr36 = &Y<A, B, C>::var36;
+template <int N>
+struct Z
+{
+  static inline int var37;			// { dg-warning "inline variables are only available with" "" { target c++14_down } }
+  static inline const int var38;		// { dg-warning "inline variables are only available with" "" { target c++14_down } }
+						// { dg-error "uninitialized const" "" { target *-*-* } .-1 }
+  static inline int var39 = 5;			// { dg-warning "inline variables are only available with" "" { target c++14_down } }
+  static inline const int var40 = 6;		// { dg-warning "inline variables are only available with" "" { target c++14_down } }
+  static inline double var41 = { 4.0 };		// { dg-warning "inline variables are only available with" "" { target c++14_down } }
+  static const inline double var42 = { 5.0 };	// { dg-warning "inline variables are only available with" "" { target c++14_down } }
+  static constexpr int var43 = 5;
+  static constexpr inline int var44 = 5;	// { dg-warning "inline variables are only available with" "" { target c++14_down } }
+};
+template <int N>
+int Z<N>::var37;				// { dg-error "redefinition of" }
+template <int N>
+const int Z<N>::var38;				// { dg-error "redefinition of" }
+const int &ref38 = Z<0>::var38;
+template <int N>
+int Z<N>::var39;				// { dg-error "redefinition of" }
+template <int N>
+const int Z<N>::var40;				// { dg-error "redefinition of" }
+template <int N>
+double Z<N>::var41;				// { dg-error "redefinition of" }
+template <int N>
+double const Z<N>::var42;			// { dg-error "redefinition of" }
+template <int N>
+const int Z<N>::var43;				// { dg-warning "redundant redeclaration of" "" { target c++1z } }
+template <int N>				// { dg-warning "redundant redeclaration of" "" { target c++1z } .+1 }
+const int Z<N>::var43;				// { dg-error "redefinition of" "" { target c++14_down } }
+Z<0> z;
--- gcc/testsuite/g++.dg/cpp1z/inline-var3.C.jj	2016-10-11 11:15:17.284704647 +0200
+++ gcc/testsuite/g++.dg/cpp1z/inline-var3.C	2016-10-11 11:29:11.740101399 +0200
@@ -0,0 +1,58 @@
+// { dg-do compile }
+// { dg-options "-g0" }
+// Verify that inline variables and static data members that aren't odr-used
+// aren't emitted into assembly even at -O0.
+// { dg-final { scan-assembler-not "inlvarvariable" } }
+
+inline int inlvarvariable1 = 1;				// { dg-warning "inline variables are only available with" "" { target c++14_down } }
+const inline int inlvarvariable2 = 2;			// { dg-warning "inline variables are only available with" "" { target c++14_down } }
+namespace N
+{
+  int inline inlvarvariable3;				// { dg-warning "inline variables are only available with" "" { target c++14_down } }
+  const int inline inlvarvariable4 = 4;			// { dg-warning "inline variables are only available with" "" { target c++14_down } }
+}
+struct S
+{
+  static inline double inlvarvariable5 = 5.0;		// { dg-warning "inline variables are only available with" "" { target c++14_down } }
+#if __cplusplus >= 201103L
+  static constexpr int inlvarvariable6 = 6;
+  static inline constexpr int inlvarvariable7 = 7;	// { dg-warning "inline variables are only available with" "" { target { c++11 && c++14_down } } }
+#endif
+};
+template <int N>					// { dg-warning "variable templates only available with" "" { target c++11_down } .+1 }
+inline int inlvarvariable8;				// { dg-warning "inline variables are only available with" "" { target c++14_down } }
+template <int N>					// { dg-warning "variable templates only available with" "" { target c++11_down } .+1 }
+const int inline inlvarvariable9 = 9;			// { dg-warning "inline variables are only available with" "" { target c++14_down } }
+namespace N
+{
+  template <int N>					// { dg-warning "variable templates only available with" "" { target c++11_down } .+1 }
+  int inline inlvarvariable10 = 10;			// { dg-warning "inline variables are only available with" "" { target c++14_down } }
+  template <int N>					// { dg-warning "variable templates only available with" "" { target c++11_down } .+1 }
+  const inline double inlvarvariable11 = 11.0;		// { dg-warning "inline variables are only available with" "" { target c++14_down } }
+}
+template <int N>
+struct T
+{
+  static inline int inlvarvariable12 = 12;		// { dg-warning "inline variables are only available with" "" { target c++14_down } }
+#if __cplusplus >= 201103L
+  static constexpr int inlvarvariable13 = 13;
+  static inline constexpr double inlvarvariable14 = 14.0; // { dg-warning "inline variables are only available with" "" { target { c++11 && c++14_down } } }
+#endif
+};
+#if __cplusplus < 201103L
+#define decltype(x) int
+#endif
+decltype (inlvarvariable1) v1 = inlvarvariable2 + sizeof (inlvarvariable1);
+decltype (N::inlvarvariable3) v2 = N::inlvarvariable4 + sizeof (N::inlvarvariable3);
+#if __cplusplus >= 201103L
+decltype (S::inlvarvariable6) v3 = sizeof (S::inlvarvariable5) + S::inlvarvariable6 + S::inlvarvariable7;
+#else
+int v3 = sizeof (S::inlvarvariable5);
+#endif
+decltype (inlvarvariable8<2>) v4 = inlvarvariable9<2> + sizeof (inlvarvariable8<2>);
+decltype (N::inlvarvariable10<0>) v5 = sizeof (N::inlvarvariable10<0>) + sizeof (N::inlvarvariable11<0>);
+#if __cplusplus >= 201103L
+decltype (T<-1>::inlvarvariable12) v6 = sizeof (T<-1>::inlvarvariable14) + sizeof (T<-1>::inlvarvariable12) + T<-1>::inlvarvariable13;
+#else
+int v6 = sizeof (T<-1>::inlvarvariable12);
+#endif
--- gcc/testsuite/g++.dg/concepts/decl-diagnose.C.jj	2016-03-09 10:19:18.000000000 +0100
+++ gcc/testsuite/g++.dg/concepts/decl-diagnose.C	2016-10-11 10:55:12.161963462 +0200
@@ -16,6 +16,7 @@ struct X
   template<typename T>
   static concept bool f6() { return true; } // { dg-error "a concept cannot be a member function" }
   static concept bool x; // { dg-error "declared 'concept'" }
+			 // { dg-error "uninitialized const" "" { target *-*-* } .-1 }
   concept int x2; // { dg-error "declared 'concept'" }
   concept ~X(); // { dg-error "a destructor cannot be 'concept'" }
   concept X(); // { dg-error "a constructor cannot be 'concept'" }

	Jakub

[-- Attachment #2: 1 --]
[-- Type: text/plain, Size: 2165 bytes --]

--- gcc/cp/decl.c.jj	2016-10-11 14:41:38.729063554 +0200
+++ gcc/cp/decl.c	2016-10-11 14:41:51.992894870 +0200
@@ -950,7 +950,7 @@ diagnose_inline_vars_for_namespace (tree
 
   FOR_EACH_VEC_SAFE_ELT (statics, i, decl)
     if (VAR_P (decl)
-	&& DECL_EXTERNAL (decl)
+	&& DECL_REALLY_EXTERN (decl)
 	&& DECL_INLINE_VAR_P (decl)
 	&& DECL_ODR_USED (decl))
       error_at (DECL_SOURCE_LOCATION (decl),
@@ -2904,7 +2904,7 @@ redeclaration_error_message (tree newdec
 	   extern int i;
 
 	 is valid.  */
-      if (DECL_EXTERNAL (newdecl) || DECL_EXTERNAL (olddecl))
+      if (DECL_REALLY_EXTERN (newdecl) || DECL_REALLY_EXTERN (olddecl))
 	return NULL;
 
       /* Static data member declared outside a class definition
@@ -5066,6 +5066,7 @@ start_decl (const cp_declarator *declara
 	}
 
       if (DECL_EXTERNAL (decl) && ! DECL_TEMPLATE_SPECIALIZATION (decl)
+	  && (!DECL_INLINE_VAR_P (decl) || DECL_REALLY_EXTERN (decl))
 	  /* Aliases are definitions. */
 	  && !alias)
 	permerror (input_location, "declaration of %q#D outside of class is not definition",
@@ -11444,13 +11445,14 @@ grokdeclarator (const cp_declarator *dec
 		      SET_DECL_VAR_DECLARED_INLINE_P (decl);
 		  }
 
-		if (!DECL_VAR_DECLARED_INLINE_P (decl)
-		    && !(cxx_dialect >= cxx1z && constexpr_p))
-		  /* Even if there is an in-class initialization, DECL
-		     is considered undefined until an out-of-class
-		     definition is provided, unless this is an inline
-		     variable.  */
-		  DECL_EXTERNAL (decl) = 1;
+		/* Even if there is an in-class initialization, DECL
+		   is considered undefined until an out-of-class
+		   definition is provided, unless this is an inline
+		   variable.  */
+		DECL_EXTERNAL (decl) = 1;
+		if (DECL_VAR_DECLARED_INLINE_P (decl)
+		    || (cxx_dialect >= cxx1z && constexpr_p))
+		  DECL_NOT_REALLY_EXTERN (decl) = 1;
 	      }
 	    else
 	      {
@@ -11672,6 +11674,11 @@ grokdeclarator (const cp_declarator *dec
 	      {
 		retrofit_lang_decl (decl);
 		SET_DECL_VAR_DECLARED_INLINE_P (decl);
+		if (!DECL_EXTERNAL (decl))
+		  {
+		    DECL_EXTERNAL (decl) = 1;
+		    DECL_NOT_REALLY_EXTERN (decl) = 1;
+		  }
 	      }
 	  }
       }

[-- Attachment #3: any.ii --]
[-- Type: text/plain, Size: 7181 bytes --]

namespace std
{
template <typename _Tp, _Tp __v> struct integral_constant
{
  static constexpr _Tp value = __v;
  typedef integral_constant type;
};
typedef integral_constant<int, 1> true_type;
typedef integral_constant<int, 0> false_type;
template <bool, typename, typename> struct conditional;
template <typename...> struct __or_;
template <typename _B1, typename _B2>
struct __or_<_B1, _B2> : conditional<_B1::value, _B1, _B2>::type
{
};
template <typename...> struct __and_;
template <typename _B1, typename _B2>
struct __and_<_B1, _B2> : conditional<_B1::value, _B2, _B1>::type
{
};
template <typename _Pp> struct __not_ : integral_constant<int, !_Pp::value>
{
};
struct __is_void_helper : false_type
{
};
struct is_void : __is_void_helper::type
{
};
struct is_lvalue_reference : false_type
{
};
template <typename> struct is_rvalue_reference : false_type
{
};
template <typename _Tp> struct is_rvalue_reference<_Tp &&> : true_type
{
};
template <typename> struct is_function : false_type
{
};
template <typename _Tp>
struct is_reference
    : __or_<is_lvalue_reference, is_rvalue_reference<_Tp> >::type
{
};
template <typename _Tp> _Tp declval ();
template <typename> struct remove_all_extents;
struct __do_is_destructible_impl
{
  template <typename _Tp, typename = decltype(declval<_Tp &>().~_Tp)>
  static true_type __test (int);
};
template <typename _Tp>
struct __is_destructible_impl : __do_is_destructible_impl
{
  typedef decltype(__test<_Tp>(0)) type;
};
template <typename _Tp>
struct __is_destructible_safe
    : __is_destructible_impl<typename remove_all_extents<_Tp>::type>::type
{
};
template <typename _Tp>
struct is_destructible : __is_destructible_safe<_Tp>::type
{
};
struct __do_is_static_castable_impl
{
  template <typename _From, typename _To,
            typename = decltype(static_cast<_To>(declval<_From>()))>
  static true_type __test (int);
};
template <typename _From, typename _To>
struct __is_static_castable_impl : __do_is_static_castable_impl
{
  typedef decltype(__test<_From, _To>(0)) type;
};
template <typename _From, typename _To>
struct __is_static_castable_safe : __is_static_castable_impl<_From, _To>::type
{
};
template <typename _From, typename _To>
struct __is_static_castable
    : integral_constant<bool, __is_static_castable_safe<_From, _To>::value>
{
};
struct __do_is_direct_constructible_impl
{
  template <typename, typename> static false_type __test (...);
};
template <typename _Tp, typename _Arg>
struct __is_direct_constructible_impl : __do_is_direct_constructible_impl
{
  typedef decltype(__test<_Tp, _Arg>()) type;
};
template <typename _Arg>
struct __is_direct_constructible_new_safe
    : __and_<is_destructible<int>, __is_direct_constructible_impl<int, _Arg> >
{
};
template <typename> struct is_same;
template <typename _From, typename,
          int = __not_<__or_<is_void, is_function<_From> > >::value>
struct __is_base_to_derived_ref;
template <typename, typename... _Args> struct is_constructible;
template <typename _From, typename _To>
struct __is_base_to_derived_ref<_From, _To, true>
{
  typedef _To __dst_t;
  typedef __and_<__not_<is_same<__dst_t> >,
                 __not_<is_constructible<__dst_t, _From> > > type;
  static constexpr int value = type::value;
};
template <typename _Tp, typename _Arg>
struct __is_direct_constructible_ref_cast
    : __and_<__is_static_castable<_Arg, _Tp>,
             __not_<__or_<__is_base_to_derived_ref<_Arg, _Tp>, false_type> > >
{
};
template <typename _Tp, typename _Arg>
struct __is_direct_constructible_new
    : conditional<is_reference<_Tp>::value,
                  __is_direct_constructible_ref_cast<_Tp, _Arg>,
                  __is_direct_constructible_new_safe<_Arg> >::type
{
};
template <typename _Tp, typename _Arg>
struct __is_direct_constructible
    : __is_direct_constructible_new<_Tp, _Arg>::type
{
};
template <typename, typename... _Args> struct __is_nary_constructible;
template <typename _Tp, typename _Arg>
struct __is_nary_constructible<_Tp, _Arg>
    : __is_direct_constructible<_Tp, _Arg>
{
};
template <typename _Tp, typename... _Args>
struct is_constructible : __is_nary_constructible<_Tp, _Args...>::type
{
};
template <typename _Tp> struct is_copy_constructible;
template <typename _Tp>
struct __is_move_constructible_impl : is_constructible<_Tp, _Tp &&>
{
};
template <typename _Tp>
struct is_move_constructible : __is_move_constructible_impl<_Tp>
{
};
template <typename, typename... _Args> struct __is_nt_constructible_impl;
template <typename, typename... _Args>
struct is_nothrow_constructible
    : __and_<is_constructible<int, _Args...>,
             __is_nt_constructible_impl<int, _Args...> >
{
};
template <typename _Tp>
struct __is_nothrow_move_constructible_impl
    : is_nothrow_constructible<_Tp, _Tp &&>
{
};
template <typename _Tp>
struct is_nothrow_move_constructible
    : __is_nothrow_move_constructible_impl<_Tp>
{
};
template <typename _Tp> struct is_same : true_type
{
};
template <typename _Tp> struct remove_all_extents
{
  typedef int type;
};
template <bool> struct enable_if
{
  typedef int type;
};
template <bool, typename _Iftrue, typename _Iffalse> struct conditional
{
  typedef _Iftrue type;
};
template <typename _Iftrue, typename _Iffalse>
struct conditional<false, _Iftrue, _Iffalse>
{
  typedef _Iffalse type;
};
template <typename _Tp> using decay_t = int;
template <bool, typename = void> using enable_if_t = int;
template <bool _Cond, typename _Iftrue, typename _Iffalse>
using conditional_t = typename conditional<_Cond, _Iftrue, _Iffalse>::type;
template <typename _Tp> struct __is_in_place_type;
class any
{
  template <typename _Tp, typename _Safe = is_nothrow_move_constructible<_Tp>,
            int _Fits = alignof 0>
  using _Internal = std::integral_constant<bool, _Safe::value && _Fits>;
  template <typename _Tp> struct _Manager_internal;
  template <typename _Tp> struct _Manager_external;
  template <typename _Tp>
  using _Manager = conditional_t<_Internal<_Tp>::value, _Manager_internal<_Tp>,
                                 _Manager_external<_Tp> >;
  template <typename _Tp, typename _Decayed = decay_t<_Tp> >
  using _Decay = enable_if_t<is_same<int>::value, _Decayed>;

public:
  any ();
  template <typename _ValueType, typename _Tp = _Decay<_ValueType>,
            typename _Mgr = _Manager<_Tp>,
            enable_if_t<__and_<is_copy_constructible<_Tp>,
                               __not_<is_constructible<_Tp, _ValueType &&> >,
                               __not_<__is_in_place_type<_ValueType> > >::
                            value,
                        bool> = false>
  any (_ValueType &&)
      : _M_manager (&_Mgr::_S_manage)
  {
  }
private:
  enum _Op
  {
  };
  void (*_M_manager)(_Op, const any *, int *);
  template <typename _Tp> struct _Manager_external
  {
    static void _S_manage (_Op, const any *, int *);
  };
};
template <typename _ValueType,
          typename enable_if<is_move_constructible<_ValueType>::value
                             && is_lvalue_reference::value>::type = false>
_ValueType any_cast (any &&)
{
}
}

using std::any_cast;
void test03 ()
{
  struct MoveDeleted;
  MoveDeleted &&md3 = any_cast<MoveDeleted &&>(0);
}

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [C++ PATCH] RFC: implement P0386R2 - C++17 inline variables
  2016-10-11 13:39 [C++ PATCH] RFC: implement P0386R2 - C++17 inline variables Jakub Jelinek
@ 2016-10-13 19:34 ` Jason Merrill
  2016-10-20 16:21   ` Andre Vieira (lists)
  2016-10-20 10:51 ` Eric Botcazou
  1 sibling, 1 reply; 15+ messages in thread
From: Jason Merrill @ 2016-10-13 19:34 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches List

[-- Attachment #1: Type: text/plain, Size: 3289 bytes --]

On Tue, Oct 11, 2016 at 9:39 AM, Jakub Jelinek <jakub@redhat.com> wrote:
> Here is an attempt to implement C++17 inline variables.
> Bootstrapped/regtested on x86_64-linux and i686-linux.
>
> The main question is if the inline variables, which are vague linkage,
> should be !DECL_EXTERNAL or DECL_EXTERNAL DECL_NOT_REALLY_EXTERN while
> in the FE.  In the patch, they are !DECL_EXTERNAL, except for inline
> static data members in instantiated templates.  As the inline-var3.C
> testcase shows, even if they are !DECL_EXTERNAL (except for the instantiated
> static data members), even at -O0 we do not actually emit them unless
> odr-used, so to some extent I don't see the point in forcing them to
> be DECL_EXTERNAL DECL_NOT_REALLY_EXTERN.

Yeah, I ended up agreeing with you.  There's no need to work hard to
make them work with an obsolete system.  So I've checked in the patch
with a few minor tweaks, attached.

> Another thing is I've noticed (with Jonathan's help to look it up) that
> we aren't implementing DR1511, I'm willing to try to implement that, but
> as it will need to touch the same spots as the patch, I think it should be
> resolved incrementally.

Sounds good.

> Yet another thing are thread_local inline vars.  E.g. on:
> struct S { S (); ~S (); };
> struct T { ~T (); };
> int foo ();
> thread_local inline S s;
> inline thread_local T t;
> inline thread_local int u = foo ();
> it seems both clang++ (~2 months old) and g++ with the patch emits:
> 8 byte TLS _ZGV1{stu] variables
> 1 byte TLS __tls_guard variable
> and _ZTH1[stu] being aliases to __tls_init, which does essentially:
>   if (__tls_guard) return;
>   __tls_guard = 1;
>   if (*(char *)&_ZGV1s == 0) {
>     *(char *)&_ZGV1s = 1;
>     S::S (&s);
>     __cxa_thread_atexit (S::~S, &s, &__dso_handle);
>   }
>   if (*(char *)&_ZGV1t == 0) {
>     *(char *)&_ZGV1t = 1;
>     __cxa_thread_atexit (T::~T, &t, &__dso_handle);
>   }
>   if (*(char *)&_ZGV1u == 0) {
>     *(char *)&_ZGV1u = 1;
>     u = foo ();
>   }
> Is that what we want to emit?  At first I doubted this could work properly,
> now thinking about it more, perhaps it can.

I think so; I don't see a reason for inline vars to work differently
from templates here.

> And, do we really want all the
> _ZGV* vars for the TLS inline vars (and other TLS comdats) to be 8 byte,
> even when we are using just a single byte?  Or is it too late to change (ABI
> break)?

Right, the ABI specifies that the guard variable is 8 bytes.  A
comment says, "The intent of specifying an 8-byte structure for the
guard variable, but only describing one byte of its contents, is to
allow flexibility in the implementation of the API above. On systems
with good small lock support, the second word might be used for a
mutex lock. On others, it might identify (as a pointer or index) a
more complex lock structure to use."  This seems unnecessary for
systems with byte atomic instructions, and we might be able to get
away with changing it without breaking any actual usage, but it would
indeed be an ABI change.

> And, as mentioned in the DWARF mailing list, I think we should emit
> DW_AT_inline on the inline vars (both explicit and implicit - static
> constexpr data members in C++17 mode).  I hope that can be done as a
> follow-up.

Makes sense.

[-- Attachment #2: inline-tweaks.diff --]
[-- Type: text/plain, Size: 6791 bytes --]

diff --git a/gcc/c-family/c-cppbuiltin.c b/gcc/c-family/c-cppbuiltin.c
index 94af585..06b5aa3 100644
--- a/gcc/c-family/c-cppbuiltin.c
+++ b/gcc/c-family/c-cppbuiltin.c
@@ -935,6 +935,7 @@ c_cpp_builtins (cpp_reader *pfile)
 	  cpp_define (pfile, "__cpp_constexpr=201603");
 	  cpp_define (pfile, "__cpp_if_constexpr=201606");
 	  cpp_define (pfile, "__cpp_capture_star_this=201603");
+	  cpp_define (pfile, "__cpp_inline_variables=201606");
 	}
       if (flag_concepts)
 	/* Use a value smaller than the 201507 specified in
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 7670162..f761d0d 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -2917,9 +2917,11 @@ redeclaration_error_message (tree newdecl, tree olddecl)
 	  && !DECL_INITIAL (newdecl))
 	{
 	  DECL_EXTERNAL (newdecl) = 1;
-	  if (warning_at (DECL_SOURCE_LOCATION (newdecl), OPT_Wdeprecated,
-			  "redundant redeclaration of %<constexpr%> static "
-			  "data member %qD", newdecl))
+	  /* For now, only warn with explicit -Wdeprecated.  */
+	  if (global_options_set.x_warn_deprecated
+	      && warning_at (DECL_SOURCE_LOCATION (newdecl), OPT_Wdeprecated,
+			     "redundant redeclaration of %<constexpr%> static "
+			     "data member %qD", newdecl))
 	    inform (DECL_SOURCE_LOCATION (olddecl),
 		    "previous declaration of %qD", olddecl);
 	  return NULL;
@@ -5479,18 +5481,19 @@ maybe_commonize_var (tree decl)
 		 be merged.  */
 	      TREE_PUBLIC (decl) = 0;
 	      DECL_COMMON (decl) = 0;
+	      const char *msg;
 	      if (DECL_INLINE_VAR_P (decl))
-		warning_at (DECL_SOURCE_LOCATION (decl), 0,
-			    "sorry: semantics of inline variable "
-			    "%q#D are wrong (you%'ll wind up with "
-			    "multiple copies)", decl);
-	      else if (warning_at (DECL_SOURCE_LOCATION (decl), 0,
-				   "sorry: semantics of inline function "
-				   "static data %q#D are wrong (you%'ll wind "
-				   "up with multiple copies)", decl))
+		msg = G_("sorry: semantics of inline variable "
+			 "%q#D are wrong (you%'ll wind up with "
+			 "multiple copies)");
+	      else
+		msg = G_("sorry: semantics of inline function "
+			 "static data %q#D are wrong (you%'ll wind "
+			 "up with multiple copies)");
+	      if (warning_at (DECL_SOURCE_LOCATION (decl), 0,
+			      msg, decl))
 		inform (DECL_SOURCE_LOCATION (decl),
-			"you can work around this by removing the "
-			"initializer");
+			"you can work around this by removing the initializer");
 	    }
 	}
     }
@@ -9300,6 +9303,29 @@ check_var_type (tree identifier, tree type)
   return type;
 }
 
+/* Handle declaring DECL as an inline variable.  */
+
+static void
+mark_inline_variable (tree decl)
+{
+  bool inlinep = true;
+  if (! toplevel_bindings_p ())
+    {
+      error ("%<inline%> specifier invalid for variable "
+	     "%qD declared at block scope", decl);
+      inlinep = false;
+    }
+  else if (cxx_dialect < cxx1z)
+    pedwarn (DECL_SOURCE_LOCATION (decl), 0,
+	     "inline variables are only available "
+	     "with -std=c++1z or -std=gnu++1z");
+  if (inlinep)
+    {
+      retrofit_lang_decl (decl);
+      SET_DECL_VAR_DECLARED_INLINE_P (decl);
+    }
+}
+
 /* Given declspecs and a declarator (abstract or otherwise), determine
    the name and type of the object declared and construct a DECL node
    for it.
@@ -11427,20 +11453,7 @@ grokdeclarator (const cp_declarator *declarator,
 		  }
 
 		if (inlinep)
-		  {
-		    if (! toplevel_bindings_p ())
-		      {
-			error ("%<inline%> specifier invalid for variable "
-			       "%qD declared at block scope", decl);
-			inlinep = false;
-		      }
-		    else if (cxx_dialect < cxx1z)
-		      pedwarn (DECL_SOURCE_LOCATION (decl), 0,
-			       "inline variables are only available "
-			       "with -std=c++1z or -std=gnu++1z");
-		    if (inlinep)
-		      SET_DECL_VAR_DECLARED_INLINE_P (decl);
-		  }
+		  mark_inline_variable (decl);
 
 		if (!DECL_VAR_DECLARED_INLINE_P (decl)
 		    && !(cxx_dialect >= cxx1z && constexpr_p))
@@ -11655,23 +11668,7 @@ grokdeclarator (const cp_declarator *declarator,
 	  }
 
 	if (inlinep)
-	  {
-	    if (! toplevel_bindings_p ())
-	      {
-		error ("%<inline%> specifier invalid for variable %qs "
-		       "declared at block scope", name);
-		inlinep = false;
-	      }
-	    else if (cxx_dialect < cxx1z)
-	      pedwarn (DECL_SOURCE_LOCATION (decl), 0,
-		       "inline variables are only available "
-		       "with -std=c++1z or -std=gnu++1z");
-	    if (inlinep)
-	      {
-		retrofit_lang_decl (decl);
-		SET_DECL_VAR_DECLARED_INLINE_P (decl);
-	      }
-	  }
+	  mark_inline_variable (decl);
       }
 
     if (VAR_P (decl) && !initialized)
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 661853e..541faf7 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -22654,7 +22654,8 @@ gen_member_die (tree type, dw_die_ref context_die)
       child = lookup_decl_die (member);
       if (child)
 	{
-	  /* Handle inline static data members.  */
+	  /* Handle inline static data members, which only have in-class
+	     declarations.  */
 	  if (child->die_tag == DW_TAG_variable
 	      && child->die_parent == comp_unit_die ())
 	    {
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ice10.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-ice10.C
index 5161273..381b8a4 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-ice10.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ice10.C
@@ -6,3 +6,5 @@ struct A
   constexpr A() {}
   static constexpr A a[2] = {};  // { dg-error "22:elements of array 'constexpr const A A::a \\\[2\\\]' have incomplete type" }
 };
+
+// { dg-prune-output "storage size" }
diff --git a/gcc/testsuite/g++.dg/cpp1z/feat-cxx1z.C b/gcc/testsuite/g++.dg/cpp1z/feat-cxx1z.C
index eeeae45..c86dbe2 100644
--- a/gcc/testsuite/g++.dg/cpp1z/feat-cxx1z.C
+++ b/gcc/testsuite/g++.dg/cpp1z/feat-cxx1z.C
@@ -356,6 +356,12 @@
 #  error "__cpp_aligned_new != 201606"
 #endif
 
+#ifndef __cpp_inline_variables
+#  error "__cpp_inline_variables"
+#elif __cpp_inline_variables != 201606
+#  error "__cpp_inline_variables != 201606"
+#endif
+
 #ifndef __cpp_capture_star_this
 #  error "__cpp_capture_star_this"
 #elif __cpp_capture_star_this != 201603
diff --git a/gcc/testsuite/g++.old-deja/g++.brendan/misc6.C b/gcc/testsuite/g++.old-deja/g++.brendan/misc6.C
index 93b241b..c7d35b7 100644
--- a/gcc/testsuite/g++.old-deja/g++.brendan/misc6.C
+++ b/gcc/testsuite/g++.old-deja/g++.brendan/misc6.C
@@ -1,7 +1,7 @@
 // { dg-do assemble  }
 // GROUPS passed miscellaneous
 // test that use of `inline' is forbidden when it should be
-inline int i;// { dg-error "" } .*
+inline int i;// { dg-error "" "" { target c++14_down } } .*
 struct c { inline int i; };// { dg-error "" } .*
 int foo (inline int i);// { dg-error "" } .*
 inline class c; // { dg-error "'inline' can only be specified for functions" } inline

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [C++ PATCH] RFC: implement P0386R2 - C++17 inline variables
  2016-10-11 13:39 [C++ PATCH] RFC: implement P0386R2 - C++17 inline variables Jakub Jelinek
  2016-10-13 19:34 ` Jason Merrill
@ 2016-10-20 10:51 ` Eric Botcazou
  2016-10-20 11:02   ` Jakub Jelinek
  1 sibling, 1 reply; 15+ messages in thread
From: Eric Botcazou @ 2016-10-20 10:51 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches, Jason Merrill

> testsuite/
> 	* g++.dg/cpp1z/inline-var1.C: New test.
> 	* g++.dg/cpp1z/inline-var1a.C: New test.
> 	* g++.dg/cpp1z/inline-var1.h: New file.

This one fails on SPARC/Solaris:

0xfefcaa58 in _lwp_kill () from /lib/libc.so.1
(gdb) bt
#0  0xfefcaa58 in _lwp_kill () from /lib/libc.so.1
#1  0xfef65a64 in raise () from /lib/libc.so.1
#2  0xfef41954 in abort () from /lib/libc.so.1
#3  0x00011770 in bar (x=16) at inline-var1.C:34
#4  0x00012984 in __static_initialization_and_destruction_0 (__initialize_p=1, 
    __priority=65535) at inline-var1a.C:6
#5  0x00012b18 in _GLOBAL__sub_I_alt1 () at inline-var1a.C:44
#6  0x00012b54 in __do_global_ctors_aux ()
#7  0x00012b8c in _init ()
#8  0x00011458 in _start ()

(gdb) frame 3
#3  0x00011770 in bar (x=16) at inline-var1.C:34
34              __builtin_abort ();

(gdb) frame 4
#4  0x00012984 in __static_initialization_and_destruction_0 (__initialize_p=1, 
    __priority=65535) at inline-var1a.C:6
6       static inline int var19 = bar (16);

(gdb) p w
$2 = 0

The testcase is rather cryptic, in particular the logic in 'bar', so it's hard 
to figure out what doesn't work as expected, but does it require support for 
constructor priorities for example?  Or does it assume an order of invocation 
for the constructors of inline-var1.C vs those of inline-var1a.C?

-- 
Eric Botcazou

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [C++ PATCH] RFC: implement P0386R2 - C++17 inline variables
  2016-10-20 10:51 ` Eric Botcazou
@ 2016-10-20 11:02   ` Jakub Jelinek
  2016-10-20 11:22     ` Eric Botcazou
  0 siblings, 1 reply; 15+ messages in thread
From: Jakub Jelinek @ 2016-10-20 11:02 UTC (permalink / raw)
  To: Eric Botcazou; +Cc: gcc-patches, Jason Merrill

On Thu, Oct 20, 2016 at 12:50:56PM +0200, Eric Botcazou wrote:
> > testsuite/
> > 	* g++.dg/cpp1z/inline-var1.C: New test.
> > 	* g++.dg/cpp1z/inline-var1a.C: New test.
> > 	* g++.dg/cpp1z/inline-var1.h: New file.
> 
> This one fails on SPARC/Solaris:
> 
> 0xfefcaa58 in _lwp_kill () from /lib/libc.so.1
> (gdb) bt
> #0  0xfefcaa58 in _lwp_kill () from /lib/libc.so.1
> #1  0xfef65a64 in raise () from /lib/libc.so.1
> #2  0xfef41954 in abort () from /lib/libc.so.1
> #3  0x00011770 in bar (x=16) at inline-var1.C:34
> #4  0x00012984 in __static_initialization_and_destruction_0 (__initialize_p=1, 
>     __priority=65535) at inline-var1a.C:6
> #5  0x00012b18 in _GLOBAL__sub_I_alt1 () at inline-var1a.C:44
> #6  0x00012b54 in __do_global_ctors_aux ()
> #7  0x00012b8c in _init ()
> #8  0x00011458 in _start ()
> 
> (gdb) frame 3
> #3  0x00011770 in bar (x=16) at inline-var1.C:34
> 34              __builtin_abort ();
> 
> (gdb) frame 4
> #4  0x00012984 in __static_initialization_and_destruction_0 (__initialize_p=1, 
>     __priority=65535) at inline-var1a.C:6
> 6       static inline int var19 = bar (16);
> 
> (gdb) p w
> $2 = 0
> 
> The testcase is rather cryptic, in particular the logic in 'bar', so it's hard 
> to figure out what doesn't work as expected, but does it require support for 
> constructor priorities for example?  Or does it assume an order of invocation 
> for the constructors of inline-var1.C vs those of inline-var1a.C?

The test wants to ensure:
1) the foo calls in the ctors are invoked in increasing order (this is used
   for inline vars defined in both CUs)
2) ensure that the first bar call in the ctors is invoked after foo (5)
3) that bar used in ctors (it is used for inline vars defined in one or the
   other CU, but not both) is invoked either in the order
   bar (0); bar (1); /* optionally some foo calls here */ bar (16); bar (17);
   or in the order
   bar (16); bar (17); /* optionally some foo calls here */ bar (0); bar (1);

So, in what order is it run on Solaris and why does it fail?

	Jakub

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [C++ PATCH] RFC: implement P0386R2 - C++17 inline variables
  2016-10-20 11:02   ` Jakub Jelinek
@ 2016-10-20 11:22     ` Eric Botcazou
  2016-10-20 16:02       ` Jakub Jelinek
  0 siblings, 1 reply; 15+ messages in thread
From: Eric Botcazou @ 2016-10-20 11:22 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches, Jason Merrill

> The test wants to ensure:
> 1) the foo calls in the ctors are invoked in increasing order (this is used
>    for inline vars defined in both CUs)
> 2) ensure that the first bar call in the ctors is invoked after foo (5)
> 3) that bar used in ctors (it is used for inline vars defined in one or the
>    other CU, but not both) is invoked either in the order
>    bar (0); bar (1); /* optionally some foo calls here */ bar (16); bar
> (17); or in the order
>    bar (16); bar (17); /* optionally some foo calls here */ bar (0); bar
> (1);
> 
> So, in what order is it run on Solaris and why does it fail?

The latter:

(gdb) run
Starting program: /sydney.a/users/botcazou/gcc-head/inline-var1 
[Thread debugging using libthread_db enabled]
[New Thread 1 (LWP 1)]
[Switching to Thread 1 (LWP 1)]

Breakpoint 1, bar (x=16) at inline-var1.C:29
29        if (v < 6)
(gdb) continue
Continuing.

Program received signal SIGABRT, Aborted.
0xfefcaa58 in _lwp_kill () from /lib/libc.so.1

If fails because x == 16 and w == 0 on the first invocation to bar but, given 
that w is not modified anywhere else, this seems to be expected.

-- 
Eric Botcazou

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [C++ PATCH] RFC: implement P0386R2 - C++17 inline variables
  2016-10-20 11:22     ` Eric Botcazou
@ 2016-10-20 16:02       ` Jakub Jelinek
  2016-10-20 16:23         ` Eric Botcazou
  0 siblings, 1 reply; 15+ messages in thread
From: Jakub Jelinek @ 2016-10-20 16:02 UTC (permalink / raw)
  To: Eric Botcazou; +Cc: gcc-patches, Jason Merrill

On Thu, Oct 20, 2016 at 01:22:16PM +0200, Eric Botcazou wrote:
> If fails because x == 16 and w == 0 on the first invocation to bar but, given 
> that w is not modified anywhere else, this seems to be expected.

Does this fix it?  It still works on Linux:

2016-10-20  Jakub Jelinek  <jakub@redhat.com>

	* g++.dg/cpp1z/inline-var1.C (w): Initialize to 64 + 2.

--- gcc/testsuite/g++.dg/cpp1z/inline-var1.C.jj	2016-10-14 12:31:44.000000000 +0200
+++ gcc/testsuite/g++.dg/cpp1z/inline-var1.C	2016-10-20 17:59:26.671358964 +0200
@@ -13,7 +13,7 @@ inline int var22 = foo (7);
 extern inline int var23, var22;
 inline int var23 = foo (8);
 
-static int v, w;
+static int v, w = 64 + 2;
 
 int
 foo (int x)


	Jakub

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [C++ PATCH] RFC: implement P0386R2 - C++17 inline variables
  2016-10-13 19:34 ` Jason Merrill
@ 2016-10-20 16:21   ` Andre Vieira (lists)
  2016-10-21 14:57     ` Yao Qi
  0 siblings, 1 reply; 15+ messages in thread
From: Andre Vieira (lists) @ 2016-10-20 16:21 UTC (permalink / raw)
  To: gcc-patches; +Cc: jason, Jakub Jelinek

On 13/10/16 20:34, Jason Merrill wrote:
> On Tue, Oct 11, 2016 at 9:39 AM, Jakub Jelinek <jakub@redhat.com> wrote:

> 
>> And, as mentioned in the DWARF mailing list, I think we should emit
>> DW_AT_inline on the inline vars (both explicit and implicit - static
>> constexpr data members in C++17 mode).  I hope that can be done as a
>> follow-up.
> 
> Makes sense.
> 

As I write this I have been waiting for my registration email for the
DWARF mailing list, so I havent seen the email you sent.

I was wondering whether the regressions I'm picking up for
arm-none-eabi-gdb are related to the change in behavior you are
suggesting. These are the fails:

$9 = {static s = 10, _vptr.A = 0xbb14 <vtable for A+8>, c = 120 'x', j =
33, jj = 1331, s = 47892}^M
(gdb) FAIL: gdb.cp/member-ptr.exp: print a (j = 33)
...
$12 = {static s = 10, _vptr.A = 0xbb14 <vtable for A+8>, c = 120 'x', j
= 44, jj = 1331, s = 47892}^M
(gdb) FAIL: gdb.cp/member-ptr.exp: print a (j = 44)

The logs used to read:
$9 = {_vptr.A = 0xbb44 <vtable for A+8>, c = 120 'x', j = 33, jj = 1331,
static s = 10}^M
(gdb) PASS: gdb.cp/member-ptr.exp: print a (j = 33)
...
$12 = {_vptr.A = 0xbb44 <vtable for A+8>, c = 120 'x', j = 44, jj =
1331, static s = 10}^M
(gdb) PASS: gdb.cp/member-ptr.exp: print a (j = 44)

As you see the Classe's structure has changed.

After bisecting GCC it does seem it's this patch that causes the change
in debug information.

I did the following to inspect the debug information (renaming A to
BANANA, to make it easier to search):

$ cp src/binutils-gdb/gdb/testsuite/gdb.cp/member-ptr.cc t.c
$ sed -i "s/A/BANANA/g" t.c
$ arm-none-eabi-g++ -c -g -mthumb -mcpu=cortex-m3  t.c
$ arm-none-eabi-g++ t.o -g  -lm -specs=rdimon.specs -lc -lg -lrdimon
-mthumb  -mcpu=cortex-m3
$ arm-none-eabi-readelf -wi a.out

Before this patch you see BANANA's first DW_TAG_MEMBER is '_vptr.BANANA'
and there is only one DW_TAG_MEMBER entry for the 'static s'.
Whereas after this patch you see the first DW_TAG_MEMBER is:
 <2><8be>: Abbrev Number: 34 (DW_TAG_member)
    <8bf>   DW_AT_name        : s
    <8c1>   DW_AT_decl_file   : 1
    <8c2>   DW_AT_decl_line   : 40
    <8c3>   DW_AT_type        : <0x5d>
    <8c7>   DW_AT_external    : 1
    <8c7>   DW_AT_accessibility: 1      (public)
    <8c8>   DW_AT_declaration : 1

the 'static s' that used to be the last, followed by '_vptr.BANANA' and
its last DW_TAG_MEMBER is:
 <2><8f5>: Abbrev Number: 38 (DW_TAG_member)
    <8f6>   DW_AT_specification: <0x8be>
    <8fa>   DW_AT_linkage_name: (indirect string, offset: 0x4a0):
_ZN6BANANA1sE
    <8fe>   DW_AT_location    : 5 byte block: 3 64 bf 1 0
(DW_OP_addr: 1bf64)

I haven't tested it on other targets.

Is this expected behavior?

Regards,
Andre

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [C++ PATCH] RFC: implement P0386R2 - C++17 inline variables
  2016-10-20 16:02       ` Jakub Jelinek
@ 2016-10-20 16:23         ` Eric Botcazou
  0 siblings, 0 replies; 15+ messages in thread
From: Eric Botcazou @ 2016-10-20 16:23 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches, Jason Merrill

> Does this fix it?  It still works on Linux:
> 
> 2016-10-20  Jakub Jelinek  <jakub@redhat.com>
> 
> 	* g++.dg/cpp1z/inline-var1.C (w): Initialize to 64 + 2.

Yes, it does, thanks!

-- 
Eric Botcazou

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [C++ PATCH] RFC: implement P0386R2 - C++17 inline variables
  2016-10-20 16:21   ` Andre Vieira (lists)
@ 2016-10-21 14:57     ` Yao Qi
  2016-10-21 15:15       ` Jakub Jelinek
  0 siblings, 1 reply; 15+ messages in thread
From: Yao Qi @ 2016-10-21 14:57 UTC (permalink / raw)
  To: Andre Vieira (lists); +Cc: gcc-patches, jason, Jakub Jelinek

Hi Jakub,

On Thu, Oct 20, 2016 at 5:21 PM, Andre Vieira (lists)
<Andre.SimoesDiasVieira@arm.com> wrote:
>  <2><8f5>: Abbrev Number: 38 (DW_TAG_member)
>     <8f6>   DW_AT_specification: <0x8be>
>     <8fa>   DW_AT_linkage_name: (indirect string, offset: 0x4a0):
> _ZN6BANANA1sE
>     <8fe>   DW_AT_location    : 5 byte block: 3 64 bf 1 0
> (DW_OP_addr: 1bf64)
>
> I haven't tested it on other targets.

I can reproduce it on x86_64 as well.

 <1><328>: Abbrev Number: 20 (DW_TAG_class_type)
    <329>   DW_AT_name        : A
    <32b>   DW_AT_byte_size   : 24
    <32c>   DW_AT_decl_file   : 1
    <32d>   DW_AT_decl_line   : 23
    <32e>   DW_AT_containing_type: <0x328>
    <332>   DW_AT_sibling     : <0x458>

 <2><336>: Abbrev Number: 19 (DW_TAG_member)
    <337>   DW_AT_name        : s
    <339>   DW_AT_decl_file   : 1
    <33a>   DW_AT_decl_line   : 40
    <33b>   DW_AT_type        : <0x5e>
    <33f>   DW_AT_external    : 1
    <33f>   DW_AT_accessibility: 1      (public)
    <340>   DW_AT_declaration : 1
 <2><36d>: Abbrev Number: 23 (DW_TAG_member)
    <36e>   DW_AT_specification: <0x336>
    <372>   DW_AT_linkage_name: (indirect string, offset: 0x447): _ZN1A1sE
    <376>   DW_AT_location    : 9 byte block: 3 10 15 60 0 0 0 0 0
 (DW_OP_addr: 601510)

We have two DIEs for member 's'.  GDB adds both of them as two fields,
the first one as static member (because of DW_AT_declaration), and the
second one as a non-static member.  GDB doesn't understand the
relationship between these two DIEs by DW_AT_specification.

Is attribute DW_AT_specification applicable to DW_TAG_member?
This is not documented in DWARF5 Appendix A "Attribute by Tage Value",
Page 258.

-- 
Yao (齐尧)

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [C++ PATCH] RFC: implement P0386R2 - C++17 inline variables
  2016-10-21 14:57     ` Yao Qi
@ 2016-10-21 15:15       ` Jakub Jelinek
  2016-10-25 15:05         ` Andre Vieira (lists)
  0 siblings, 1 reply; 15+ messages in thread
From: Jakub Jelinek @ 2016-10-21 15:15 UTC (permalink / raw)
  To: Yao Qi; +Cc: Andre Vieira (lists), gcc-patches, jason

On Fri, Oct 21, 2016 at 03:57:34PM +0100, Yao Qi wrote:
> Hi Jakub,
> 
> On Thu, Oct 20, 2016 at 5:21 PM, Andre Vieira (lists)
> <Andre.SimoesDiasVieira@arm.com> wrote:
> >  <2><8f5>: Abbrev Number: 38 (DW_TAG_member)
> >     <8f6>   DW_AT_specification: <0x8be>
> >     <8fa>   DW_AT_linkage_name: (indirect string, offset: 0x4a0):
> > _ZN6BANANA1sE
> >     <8fe>   DW_AT_location    : 5 byte block: 3 64 bf 1 0
> > (DW_OP_addr: 1bf64)
> >
> > I haven't tested it on other targets.
> 
> I can reproduce it on x86_64 as well.

First of all, I have a pending patch for this area:
http://gcc.gnu.org/ml/gcc-patches/2016-10/msg01183.html
so I think it doesn't really make much sense to discuss it until it gets in.
But unless you are talking about -std=c++17 or code with explicit inline
vars, I don't think anything has really changed in the debug representation
with that patch.

	Jakub

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [C++ PATCH] RFC: implement P0386R2 - C++17 inline variables
  2016-10-21 15:15       ` Jakub Jelinek
@ 2016-10-25 15:05         ` Andre Vieira (lists)
  2016-10-25 18:06           ` Jakub Jelinek
  0 siblings, 1 reply; 15+ messages in thread
From: Andre Vieira (lists) @ 2016-10-25 15:05 UTC (permalink / raw)
  To: Jakub Jelinek, Yao Qi; +Cc: gcc-patches, jason

On 21/10/16 16:14, Jakub Jelinek wrote:
> On Fri, Oct 21, 2016 at 03:57:34PM +0100, Yao Qi wrote:
>> Hi Jakub,
>>
>> On Thu, Oct 20, 2016 at 5:21 PM, Andre Vieira (lists)
>> <Andre.SimoesDiasVieira@arm.com> wrote:
>>>  <2><8f5>: Abbrev Number: 38 (DW_TAG_member)
>>>     <8f6>   DW_AT_specification: <0x8be>
>>>     <8fa>   DW_AT_linkage_name: (indirect string, offset: 0x4a0):
>>> _ZN6BANANA1sE
>>>     <8fe>   DW_AT_location    : 5 byte block: 3 64 bf 1 0
>>> (DW_OP_addr: 1bf64)
>>>
>>> I haven't tested it on other targets.
>>
>> I can reproduce it on x86_64 as well.
> 
> First of all, I have a pending patch for this area:
> http://gcc.gnu.org/ml/gcc-patches/2016-10/msg01183.html
> so I think it doesn't really make much sense to discuss it until it gets in.
> But unless you are talking about -std=c++17 or code with explicit inline
> vars, I don't think anything has really changed in the debug representation
> with that patch.
> 
> 	Jakub
> 

Hi Jakub,

I built gcc for the following:
1) revision r241135
2) revision r241135  + cherry-picked your patch in revision r241137
(skipped the patch in revision r241136 because that gives a build failure).
3) trunk + patch in http://gcc.gnu.org/ml/gcc-patches/2016-10/msg01183.html

And compiling the member-ptr.cc file in the gdb testsuite without
-std=c17 (see
https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=blob;f=gdb/testsuite/gdb.cp/member-ptr.cc;h=4b7da34d3a77e3b5c045bd76d1f0a01514a039d7;hb=HEAD)
leads to the following behavior:

1) expected behavior, debug of information of objects of 'class A' looks
fine.
2) new debug information for objects of 'class A' breaking the test.
3) same as 2)

As you can see the file has no explicit inline vars and I do not compile
it with -std=c++17.

So I'm suspecting your patch changes this behavior in an unexpected way.

Regards,
Andre

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [C++ PATCH] RFC: implement P0386R2 - C++17 inline variables
  2016-10-25 15:05         ` Andre Vieira (lists)
@ 2016-10-25 18:06           ` Jakub Jelinek
  2016-10-25 19:56             ` [PATCH] Fix dwarf2out regression from C++17 inline variables changes Jakub Jelinek
  2016-10-26 10:07             ` [C++ PATCH] RFC: implement P0386R2 - C++17 inline variables Yao Qi
  0 siblings, 2 replies; 15+ messages in thread
From: Jakub Jelinek @ 2016-10-25 18:06 UTC (permalink / raw)
  To: Andre Vieira (lists); +Cc: Yao Qi, gcc-patches, jason

On Tue, Oct 25, 2016 at 04:05:30PM +0100, Andre Vieira (lists) wrote:
> I built gcc for the following:
> 1) revision r241135
> 2) revision r241135  + cherry-picked your patch in revision r241137
> (skipped the patch in revision r241136 because that gives a build failure).
> 3) trunk + patch in http://gcc.gnu.org/ml/gcc-patches/2016-10/msg01183.html
> 
> And compiling the member-ptr.cc file in the gdb testsuite without
> -std=c17 (see
> https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=blob;f=gdb/testsuite/gdb.cp/member-ptr.cc;h=4b7da34d3a77e3b5c045bd76d1f0a01514a039d7;hb=HEAD)
> leads to the following behavior:
> 
> 1) expected behavior, debug of information of objects of 'class A' looks
> fine.
> 2) new debug information for objects of 'class A' breaking the test.
> 3) same as 2)
> 
> As you can see the file has no explicit inline vars and I do not compile
> it with -std=c++17.
> 
> So I'm suspecting your patch changes this behavior in an unexpected way.

I think this patch should fix it, will bootstrap/regtest it now:

2016-10-25  Jakub Jelinek  <jakub@redhat.com>

	* dwarf2out.c (gen_member_die): Only reparent_child instead of
	splice_child_die if child doesn't have DW_AT_specification attribute.

--- gcc/dwarf2out.c.jj	2016-10-25 19:49:28.000000000 +0200
+++ gcc/dwarf2out.c	2016-10-25 20:02:33.264639847 +0200
@@ -22624,7 +22624,8 @@ gen_member_die (tree type, dw_die_ref co
 	  /* Handle inline static data members, which only have in-class
 	     declarations.  */
 	  if (child->die_tag == DW_TAG_variable
-	      && child->die_parent == comp_unit_die ())
+	      && child->die_parent == comp_unit_die ()
+	      && get_AT (child, DW_AT_specification) == NULL)
 	    {
 	      reparent_child (child, context_die);
 	      child->die_tag = DW_TAG_member;


	Jakub

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH] Fix dwarf2out regression from C++17 inline variables changes
  2016-10-25 18:06           ` Jakub Jelinek
@ 2016-10-25 19:56             ` Jakub Jelinek
  2016-10-27 13:55               ` Jason Merrill
  2016-10-26 10:07             ` [C++ PATCH] RFC: implement P0386R2 - C++17 inline variables Yao Qi
  1 sibling, 1 reply; 15+ messages in thread
From: Jakub Jelinek @ 2016-10-25 19:56 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Andre Vieira (lists), Yao Qi, gcc-patches

On Tue, Oct 25, 2016 at 08:06:12PM +0200, Jakub Jelinek wrote:
> I think this patch should fix it, will bootstrap/regtest it now:
> 
> 2016-10-25  Jakub Jelinek  <jakub@redhat.com>
> 
> 	* dwarf2out.c (gen_member_die): Only reparent_child instead of
> 	splice_child_die if child doesn't have DW_AT_specification attribute.

Bootstrapped/regtested on x86_64-linux and i686-linux now, with this
patch C++14 static data members are treated in debug info as they were in
the past, just C++17 static constexpr data mambers or other static inline
data members are treated the new way (definition in DW_TAG_member).

Ok for trunk?

> --- gcc/dwarf2out.c.jj	2016-10-25 19:49:28.000000000 +0200
> +++ gcc/dwarf2out.c	2016-10-25 20:02:33.264639847 +0200
> @@ -22624,7 +22624,8 @@ gen_member_die (tree type, dw_die_ref co
>  	  /* Handle inline static data members, which only have in-class
>  	     declarations.  */
>  	  if (child->die_tag == DW_TAG_variable
> -	      && child->die_parent == comp_unit_die ())
> +	      && child->die_parent == comp_unit_die ()
> +	      && get_AT (child, DW_AT_specification) == NULL)
>  	    {
>  	      reparent_child (child, context_die);
>  	      child->die_tag = DW_TAG_member;
> 

	Jakub

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [C++ PATCH] RFC: implement P0386R2 - C++17 inline variables
  2016-10-25 18:06           ` Jakub Jelinek
  2016-10-25 19:56             ` [PATCH] Fix dwarf2out regression from C++17 inline variables changes Jakub Jelinek
@ 2016-10-26 10:07             ` Yao Qi
  1 sibling, 0 replies; 15+ messages in thread
From: Yao Qi @ 2016-10-26 10:07 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Andre Vieira (lists), gcc-patches, jason

On Tue, Oct 25, 2016 at 7:06 PM, Jakub Jelinek <jakub@redhat.com> wrote:
>
> I think this patch should fix it, will bootstrap/regtest it now:
>

Yes, the fails in gdb.cp/member-ptr.exp go away with the patched g++.
I run gdb.cp/member-ptr.exp with three different c++ variations,

Schedule of variations:
    unix/-std=c++03
    unix/-std=c++11
    unix/-std=c++1z

Thanks for the fix.

-- 
Yao (齐尧)

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH] Fix dwarf2out regression from C++17 inline variables changes
  2016-10-25 19:56             ` [PATCH] Fix dwarf2out regression from C++17 inline variables changes Jakub Jelinek
@ 2016-10-27 13:55               ` Jason Merrill
  0 siblings, 0 replies; 15+ messages in thread
From: Jason Merrill @ 2016-10-27 13:55 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: Andre Vieira (lists), Yao Qi, gcc-patches List

OK.

On Tue, Oct 25, 2016 at 3:56 PM, Jakub Jelinek <jakub@redhat.com> wrote:
> On Tue, Oct 25, 2016 at 08:06:12PM +0200, Jakub Jelinek wrote:
>> I think this patch should fix it, will bootstrap/regtest it now:
>>
>> 2016-10-25  Jakub Jelinek  <jakub@redhat.com>
>>
>>       * dwarf2out.c (gen_member_die): Only reparent_child instead of
>>       splice_child_die if child doesn't have DW_AT_specification attribute.
>
> Bootstrapped/regtested on x86_64-linux and i686-linux now, with this
> patch C++14 static data members are treated in debug info as they were in
> the past, just C++17 static constexpr data mambers or other static inline
> data members are treated the new way (definition in DW_TAG_member).
>
> Ok for trunk?
>
>> --- gcc/dwarf2out.c.jj        2016-10-25 19:49:28.000000000 +0200
>> +++ gcc/dwarf2out.c   2016-10-25 20:02:33.264639847 +0200
>> @@ -22624,7 +22624,8 @@ gen_member_die (tree type, dw_die_ref co
>>         /* Handle inline static data members, which only have in-class
>>            declarations.  */
>>         if (child->die_tag == DW_TAG_variable
>> -           && child->die_parent == comp_unit_die ())
>> +           && child->die_parent == comp_unit_die ()
>> +           && get_AT (child, DW_AT_specification) == NULL)
>>           {
>>             reparent_child (child, context_die);
>>             child->die_tag = DW_TAG_member;
>>
>
>         Jakub

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2016-10-27 13:55 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-10-11 13:39 [C++ PATCH] RFC: implement P0386R2 - C++17 inline variables Jakub Jelinek
2016-10-13 19:34 ` Jason Merrill
2016-10-20 16:21   ` Andre Vieira (lists)
2016-10-21 14:57     ` Yao Qi
2016-10-21 15:15       ` Jakub Jelinek
2016-10-25 15:05         ` Andre Vieira (lists)
2016-10-25 18:06           ` Jakub Jelinek
2016-10-25 19:56             ` [PATCH] Fix dwarf2out regression from C++17 inline variables changes Jakub Jelinek
2016-10-27 13:55               ` Jason Merrill
2016-10-26 10:07             ` [C++ PATCH] RFC: implement P0386R2 - C++17 inline variables Yao Qi
2016-10-20 10:51 ` Eric Botcazou
2016-10-20 11:02   ` Jakub Jelinek
2016-10-20 11:22     ` Eric Botcazou
2016-10-20 16:02       ` Jakub Jelinek
2016-10-20 16:23         ` Eric Botcazou

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).