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  <ja...@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;
+}
 
 /* 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
--- 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;
+                 }
              }
          }
       }
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);
}

Reply via email to