OSDN Git Service

* parser.c (cp_parser_ctor_initializer_opt_and_function_body):
authorjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 27 Oct 2010 19:31:33 +0000 (19:31 +0000)
committerjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 27 Oct 2010 19:31:33 +0000 (19:31 +0000)
Make sure a constexpr ctor has an empty body.
* class.c (type_has_constexpr_default_constructor): New.
* cp-tree.h: Declare it.
* init.c (perform_member_init): Complain about uninitialized
member in constexpr ctor.
(emit_mem_initializers): And uninitialized base.
* decl.c (check_tag_decl): Fix typo.

* semantics.c (valid_type_in_constexpr_fundecl_p): New fn.
(is_valid_constexpr_fn): New fn.
(validate_constexpr_fundecl): Use it.
* decl.c (validate_constexpr_redeclaration): New.
(duplicate_decls): Use it.
(cp_finish_decl): Call validate_constexpr_fundecl and
ensure_literal_type_for_constexpr_object here.
(start_decl): Not here.  Don't ICE on constexpr reference.
(check_for_uninitialized_const_var): Don't handle constexpr specially.
(grokfndecl): Set DECL_DECLARED_CONSTEXPR_P.
(check_static_variable_definition): Give friendly message about
missing constexpr.
(grokdeclarator): Complain about typedef and volatile with constexpr.
Reorganize.  Give sorry about non-static data members in C++0x mode.
(start_preparsed_function): Check validate_constexpr_fundecl here.
(check_function_type): Not here.
* decl2.c (finish_static_data_member_decl): Don't complain about
in-class init.
* parser.c (CP_PARSER_FLAGS_ONLY_TYPE_OR_CONSTEXPR): New.
(cp_parser_condition): Pass it to cp_parser_decl_specifier_seq.
(cp_parser_decl_specifier_seq): Handle it.
(cp_parser_explicit_instantiation): Diagnose inline and constexpr.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@166013 138bc75d-0d04-0410-961f-82ee72b054a4

13 files changed:
gcc/cp/ChangeLog
gcc/cp/class.c
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/decl2.c
gcc/cp/init.c
gcc/cp/parser.c
gcc/cp/semantics.c
gcc/testsuite/g++.dg/cpp0x/constexpr-auto.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/constexpr-condition.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/constexpr-ctor.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/constexpr-expinst.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/constexpr-ice2.C [new file with mode: 0644]

index 95a2f8b..5fe0f17 100644 (file)
@@ -1,6 +1,38 @@
 2010-10-27  Gabriel Dos Reis  <gdr@cse.tamu.edu>
            Jason Merrill  <jason@redhat.com>
 
+       * parser.c (cp_parser_ctor_initializer_opt_and_function_body):
+       Make sure a constexpr ctor has an empty body.
+       * class.c (type_has_constexpr_default_constructor): New.
+       * cp-tree.h: Declare it.
+       * init.c (perform_member_init): Complain about uninitialized
+       member in constexpr ctor.
+       (emit_mem_initializers): And uninitialized base.
+       * decl.c (check_tag_decl): Fix typo.
+
+       * semantics.c (valid_type_in_constexpr_fundecl_p): New fn.
+       (is_valid_constexpr_fn): New fn.
+       (validate_constexpr_fundecl): Use it.
+       * decl.c (validate_constexpr_redeclaration): New.
+       (duplicate_decls): Use it.
+       (cp_finish_decl): Call validate_constexpr_fundecl and
+       ensure_literal_type_for_constexpr_object here.
+       (start_decl): Not here.  Don't ICE on constexpr reference.
+       (check_for_uninitialized_const_var): Don't handle constexpr specially.
+       (grokfndecl): Set DECL_DECLARED_CONSTEXPR_P.
+       (check_static_variable_definition): Give friendly message about
+       missing constexpr.
+       (grokdeclarator): Complain about typedef and volatile with constexpr.
+       Reorganize.  Give sorry about non-static data members in C++0x mode.
+       (start_preparsed_function): Check validate_constexpr_fundecl here.
+       (check_function_type): Not here.
+       * decl2.c (finish_static_data_member_decl): Don't complain about
+       in-class init.
+       * parser.c (CP_PARSER_FLAGS_ONLY_TYPE_OR_CONSTEXPR): New.
+       (cp_parser_condition): Pass it to cp_parser_decl_specifier_seq.
+       (cp_parser_decl_specifier_seq): Handle it.
+       (cp_parser_explicit_instantiation): Diagnose inline and constexpr.
+
        * class.c (check_bases): Propagate non-literality.
        (check_field_decls): Likewise.
        (finalize_literal_type_property): New.
index 00af0ae..c3e3c53 100644 (file)
@@ -4325,6 +4325,19 @@ type_has_user_provided_default_constructor (tree t)
   return false;
 }
 
+/* Returns true iff class T has a constexpr default constructor.  */
+
+bool
+type_has_constexpr_default_constructor (tree t)
+{
+  tree fns;
+
+  if (!CLASS_TYPE_P (t))
+    return false;
+  fns = get_default_ctor (t);
+  return (fns && DECL_DECLARED_CONSTEXPR_P (fns));
+}
+
 /* Returns true iff class TYPE has a virtual destructor.  */
 
 bool
index 8c0c9b1..1cd776a 100644 (file)
@@ -4721,6 +4721,7 @@ extern tree in_class_defaulted_default_constructor (tree);
 extern bool user_provided_p                    (tree);
 extern bool type_has_user_provided_constructor  (tree);
 extern bool type_has_user_provided_default_constructor (tree);
+extern bool type_has_constexpr_default_constructor (tree);
 extern bool type_has_virtual_destructor                (tree);
 extern bool type_has_move_constructor          (tree);
 extern bool type_has_move_assign               (tree);
index e27a64d..8b2af9c 100644 (file)
@@ -1128,6 +1128,32 @@ check_redeclaration_exception_specification (tree new_decl,
     }
 }
 
+/* Return true if OLD_DECL and NEW_DECL agree on constexprness.
+   Otherwise issue diagnostics.  */
+
+static bool
+validate_constexpr_redeclaration (tree old_decl, tree new_decl)
+{
+  old_decl = STRIP_TEMPLATE (old_decl);
+  new_decl = STRIP_TEMPLATE (new_decl);
+  if (!VAR_OR_FUNCTION_DECL_P (old_decl)
+      || !VAR_OR_FUNCTION_DECL_P (new_decl))
+    return true;
+  if (DECL_DECLARED_CONSTEXPR_P (old_decl)
+      == DECL_DECLARED_CONSTEXPR_P (new_decl))
+    return true;
+  if (TREE_CODE (old_decl) == FUNCTION_DECL && DECL_BUILT_IN (old_decl))
+    {
+      /* Hide a built-in declaration.  */
+      DECL_DECLARED_CONSTEXPR_P (old_decl)
+       = DECL_DECLARED_CONSTEXPR_P (new_decl);
+      return true;
+    }
+  error ("redeclaration %qD differs in %<constexpr%>", new_decl);
+  error ("from previous declaration %q+D", old_decl);
+  return false;
+}
+
 #define GNU_INLINE_P(fn) (DECL_DECLARED_INLINE_P (fn)                  \
                          && lookup_attribute ("gnu_inline",            \
                                               DECL_ATTRIBUTES (fn)))
@@ -1607,6 +1633,9 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
      warn about it.  */
   warn_extern_redeclared_static (newdecl, olddecl);
 
+  if (!validate_constexpr_redeclaration (olddecl, newdecl))
+    return error_mark_node;
+
   /* We have committed to returning 1 at this point.  */
   if (TREE_CODE (newdecl) == FUNCTION_DECL)
     {
@@ -4029,7 +4058,7 @@ check_tag_decl (cp_decl_specifier_seq *declspecs)
       else if (saw_typedef)
        warning (0, "%<typedef%> was ignored in this declaration");
       else if (declspecs->specs[(int) ds_constexpr])
-        error ("%<constexpr> cannot be used for type declarations");
+        error ("%<constexpr%> cannot be used for type declarations");
     }
 
   return declared_type;
@@ -4310,9 +4339,6 @@ start_decl (const cp_declarator *declarator,
          && !alias)
        permerror (input_location, "declaration of %q#D outside of class is not definition",
                   decl);
-
-      if (!ensure_literal_type_for_constexpr_object (decl))
-        return error_mark_node;
     }
 
   was_public = TREE_PUBLIC (decl);
@@ -4344,7 +4370,7 @@ start_decl (const cp_declarator *declarator,
       /* This is a const variable with implicit 'static'.  Set
         DECL_THIS_STATIC so we can tell it from variables that are
         !TREE_PUBLIC because of the anonymous namespace.  */
-      gcc_assert (CP_TYPE_CONST_P (TREE_TYPE (decl)));
+      gcc_assert (CP_TYPE_CONST_P (TREE_TYPE (decl)) || errorcount);
       DECL_THIS_STATIC (decl) = 1;
     }
 
@@ -4753,14 +4779,10 @@ check_for_uninitialized_const_var (tree decl)
 {
   tree type = strip_array_types (TREE_TYPE (decl));
 
-  if (TREE_CODE (decl) == VAR_DECL && DECL_DECLARED_CONSTEXPR_P (decl)
-      && DECL_INITIAL (decl) == NULL)
-    error ("missing initializer for constexpr %qD", decl);
-
   /* ``Unless explicitly declared extern, a const object does not have
      external linkage and must be initialized. ($8.4; $12.1)'' ARM
      7.1.6 */
-  else if (TREE_CODE (decl) == VAR_DECL
+  if (TREE_CODE (decl) == VAR_DECL
       && TREE_CODE (type) != REFERENCE_TYPE
       && CP_TYPE_CONST_P (type)
       && (!TYPE_NEEDS_CONSTRUCTING (type)
@@ -5691,6 +5713,12 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
        }
     }
 
+  if (TREE_CODE (decl) == FUNCTION_DECL)
+    validate_constexpr_fundecl (decl);
+
+  else if (!ensure_literal_type_for_constexpr_object (decl))
+    DECL_DECLARED_CONSTEXPR_P (decl) = 0;
+
   if (init && TREE_CODE (decl) == FUNCTION_DECL)
     {
       tree clone;
@@ -6959,6 +6987,8 @@ grokfndecl (tree ctype,
   /* If the declaration was declared inline, mark it as such.  */
   if (inlinep)
     DECL_DECLARED_INLINE_P (decl) = 1;
+  if (inlinep & 2)
+    DECL_DECLARED_CONSTEXPR_P (decl) = true;
 
   DECL_EXTERNAL (decl) = 1;
   if (quals && TREE_CODE (type) == FUNCTION_TYPE)
@@ -7341,6 +7371,21 @@ build_ptrmem_type (tree class_type, tree member_type)
 int
 check_static_variable_definition (tree decl, tree type)
 {
+  /* If DECL is declared constexpr, we'll do the appropriate checks
+     in check_initializer.  */
+  if (DECL_P (decl) && DECL_DECLARED_CONSTEXPR_P (decl))
+    return 0;
+  else if (cxx_dialect >= cxx0x && !INTEGRAL_OR_ENUMERATION_TYPE_P (type))
+    {
+      if (literal_type_p (type))
+       error ("%<constexpr%> needed for in-class initialization of static "
+              "data member %q#D of non-integral type", decl);
+      else
+       error ("in-class initialization of static data member %q#D of "
+              "non-literal type", decl);
+      return 1;
+    }
+
   /* Motion 10 at San Diego: If a static const integral data member is
      initialized with an integral constant expression, the initializer
      may appear either in the declaration (within the class), or in
@@ -7352,10 +7397,6 @@ check_static_variable_definition (tree decl, tree type)
       error ("invalid in-class initialization of static data member "
             "of non-integral type %qT",
             type);
-      /* If we just return the declaration, crashes will sometimes
-        occur.  We therefore return void_type_node, as if this were a
-        friend declaration, to cause callers to completely ignore
-        this declaration.  */
       return 1;
     }
   else if (!CP_TYPE_CONST_P (type))
@@ -8046,6 +8087,12 @@ grokdeclarator (const cp_declarator *declarator,
   if (name == NULL)
     name = decl_context == PARM ? "parameter" : "type name";
 
+  if (constexpr_p && declspecs->specs[(int)ds_typedef])
+    {
+      error ("%<constexpr%> cannot appear in a typedef declaration");
+      return error_mark_node;
+    }
+
   /* If there were multiple types specified in the decl-specifier-seq,
      issue an error message.  */
   if (declspecs->multiple_types_p)
@@ -8299,17 +8346,6 @@ grokdeclarator (const cp_declarator *declarator,
   type_quals = TYPE_UNQUALIFIED;
   if (declspecs->specs[(int)ds_const])
     type_quals |= TYPE_QUAL_CONST;
-  /* A `constexpr' specifier used in an object declaration declares
-     the object as `const'.  */
-  if (constexpr_p)
-    {
-      if (innermost_code == cdk_function)
-        ;
-      else if (declspecs->specs[(int)ds_const] != 0)
-        error ("both %<const%> and %<constexpr%> cannot be used here");
-      else
-        type_quals |= TYPE_QUAL_CONST;
-    }
   if (declspecs->specs[(int)ds_volatile])
     type_quals |= TYPE_QUAL_VOLATILE;
   if (declspecs->specs[(int)ds_restrict])
@@ -8686,21 +8722,6 @@ grokdeclarator (const cp_declarator *declarator,
                  }
              }
 
-            /* It is not allowed to use `constexpr' in a function
-               declaration that is not a definition.
-               That is too strict, though.  */
-            if (constexpr_p && !funcdef_flag)
-              {
-                error ("the %<constexpr%> specifier cannot be used in "
-                       "a function declaration that is not a definition");
-                constexpr_p = false;
-              }
-
-            /* A constexpr non-static member function is implicitly const.  */
-            if (constexpr_p && decl_context == FIELD && staticp == 0
-                && sfk != sfk_constructor && sfk != sfk_destructor)
-              memfn_quals |= TYPE_QUAL_CONST;
-
            arg_types = grokparms (declarator->u.function.parameters,
                                   &parms);
 
@@ -8878,6 +8899,18 @@ grokdeclarator (const cp_declarator *declarator,
        }
     }
 
+  /* A `constexpr' specifier used in an object declaration declares
+     the object as `const'.  */
+  if (constexpr_p && innermost_code != cdk_function)
+    {
+      if (type_quals & TYPE_QUAL_CONST)
+        error ("both %<const%> and %<constexpr%> cannot be used here");
+      if (type_quals & TYPE_QUAL_VOLATILE)
+        error ("both %<volatile%> and %<constexpr%> cannot be used here");
+      type_quals |= TYPE_QUAL_CONST;
+      type = cp_build_qualified_type (type, type_quals);
+    }
+
   if (unqualified_id && TREE_CODE (unqualified_id) == TEMPLATE_ID_EXPR
       && TREE_CODE (type) != FUNCTION_TYPE
       && TREE_CODE (type) != METHOD_TYPE)
@@ -8964,8 +8997,6 @@ grokdeclarator (const cp_declarator *declarator,
        return error_mark_node;
       else if (TREE_CODE (type) == FUNCTION_TYPE)
        {
-         tree sname = declarator->u.id.unqualified_name;
-
          if (current_class_type
              && (!friendp || funcdef_flag))
            {
@@ -8975,20 +9006,6 @@ grokdeclarator (const cp_declarator *declarator,
                     ctype, name, current_class_type);
              return error_mark_node;
            }
-
-          /* It is not permitted to define a member function outside ist
-             membership class as `constexpr'.  */
-          if (constexpr_p)
-            error ("a constexpr function cannot be defined "
-                   "outside of its class");
-
-         if (TREE_CODE (sname) == IDENTIFIER_NODE
-             && NEW_DELETE_OPNAME_P (sname))
-           /* Overloaded operator new and operator delete
-              are always static functions.  */
-           ;
-         else
-           type = build_memfn_type (type, ctype, memfn_quals);
        }
       else if (declspecs->specs[(int)ds_typedef]
               && current_class_type)
@@ -8999,6 +9016,15 @@ grokdeclarator (const cp_declarator *declarator,
        }
     }
 
+  if (ctype == NULL_TREE && decl_context == FIELD && friendp == 0)
+    ctype = current_class_type;
+
+  /* A constexpr non-static member function is implicitly const.  */
+  if (constexpr_p && ctype && staticp == 0
+      && TREE_CODE (type) == FUNCTION_TYPE
+      && sfk != sfk_constructor && sfk != sfk_destructor)
+    memfn_quals |= TYPE_QUAL_CONST;
+
   /* Now TYPE has the actual type.  */
 
   if (returned_attrs)
@@ -9362,6 +9388,10 @@ grokdeclarator (const cp_declarator *declarator,
        type = build_pointer_type (type);
     }
 
+  if (ctype && TREE_CODE (type) == FUNCTION_TYPE && staticp < 2
+      && !NEW_DELETE_OPNAME_P (unqualified_id))
+    type = build_memfn_type (type, ctype, memfn_quals);
+
   {
     tree decl;
 
@@ -9395,22 +9425,15 @@ grokdeclarator (const cp_declarator *declarator,
            error ("invalid use of %<::%>");
            return error_mark_node;
          }
-       else if (TREE_CODE (type) == FUNCTION_TYPE)
+       else if (TREE_CODE (type) == FUNCTION_TYPE
+                || TREE_CODE (type) == METHOD_TYPE)
          {
            int publicp = 0;
            tree function_context;
 
            if (friendp == 0)
              {
-               if (ctype == NULL_TREE)
-                 ctype = current_class_type;
-
-               if (ctype == NULL_TREE)
-                 {
-                   error ("can't make %qD into a method -- not in a class",
-                          unqualified_id);
-                   return error_mark_node;
-                 }
+               gcc_assert (ctype);
 
                /* ``A union may [ ... ] not [ have ] virtual functions.''
                   ARM 9.5 */
@@ -9431,8 +9454,6 @@ grokdeclarator (const cp_declarator *declarator,
                        virtualp = 0;
                      }
                  }
-               else if (staticp < 2)
-                 type = build_memfn_type (type, ctype, memfn_quals);
              }
 
            /* Check that the name used for a destructor makes sense.  */
@@ -9455,9 +9476,12 @@ grokdeclarator (const cp_declarator *declarator,
                    return error_mark_node;
                  }
                 if (constexpr_p)
-                  error ("a destructor cannot be %<constexpr%>");
+                  {
+                    error ("a destructor cannot be %<constexpr%>");
+                    return error_mark_node;
+                  }
              }
-           else if (sfk == sfk_constructor && friendp)
+           else if (sfk == sfk_constructor && friendp && !ctype)
              {
                error ("expected qualified name in friend declaration "
                       "for constructor %qD",
@@ -9477,7 +9501,7 @@ grokdeclarator (const cp_declarator *declarator,
                               unqualified_id,
                               virtualp, flags, memfn_quals, raises,
                               friendp ? -1 : 0, friendp, publicp,
-                               inlinep || constexpr_p,
+                               inlinep | (2 * constexpr_p),
                               sfk,
                               funcdef_flag, template_count, in_namespace,
                               attrlist, declarator->id_loc);
@@ -9499,25 +9523,6 @@ grokdeclarator (const cp_declarator *declarator,
            if (explicitp == 2)
              DECL_NONCONVERTING_P (decl) = 1;
          }
-       else if (TREE_CODE (type) == METHOD_TYPE)
-         {
-           /* We only get here for friend declarations of
-              members of other classes.  */
-           /* All method decls are public, so tell grokfndecl to set
-              TREE_PUBLIC, also.  */
-           decl = grokfndecl (ctype, type,
-                              TREE_CODE (unqualified_id) != TEMPLATE_ID_EXPR
-                              ? unqualified_id : dname,
-                              parms,
-                              unqualified_id,
-                              virtualp, flags, memfn_quals, raises,
-                              friendp ? -1 : 0, friendp, 1, 0, sfk,
-                              funcdef_flag, template_count, in_namespace,
-                              attrlist,
-                              declarator->id_loc);
-           if (decl == NULL_TREE)
-             return error_mark_node;
-         }
        else if (!staticp && !dependent_type_p (type)
                 && !COMPLETE_TYPE_P (complete_type (type))
                 && (TREE_CODE (type) != ARRAY_TYPE || initialized == 0))
@@ -9596,15 +9601,25 @@ grokdeclarator (const cp_declarator *declarator,
                       the rest of the compiler does not correctly
                       handle the initialization unless the member is
                       static so we make it static below.  */
-                   permerror (input_location, "ISO C++ forbids initialization of member %qD",
-                              unqualified_id);
-                   permerror (input_location, "making %qD static", unqualified_id);
-                   staticp = 1;
+                   if (cxx_dialect >= cxx0x)
+                     {
+                       sorry ("non-static data member initializers");
+                     }
+                   else
+                     {
+                       permerror (input_location, "ISO C++ forbids initialization of member %qD",
+                                  unqualified_id);
+                       permerror (input_location, "making %qD static", unqualified_id);
+                       staticp = 1;
+                     }
                  }
 
                if (uses_template_parms (type))
                  /* We'll check at instantiation time.  */
                  ;
+               else if (constexpr_p)
+                 /* constexpr has the same requirements.  */
+                 ;
                else if (check_static_variable_definition (unqualified_id,
                                                           type))
                  /* If we just return the declaration, crashes
@@ -9714,11 +9729,6 @@ grokdeclarator (const cp_declarator *declarator,
                sfk = sfk_none;
              }
          }
-       else if (TREE_CODE (type) == FUNCTION_TYPE && staticp < 2
-                && !NEW_DELETE_OPNAME_P (original_name))
-         type = build_method_type_directly (ctype,
-                                            TREE_TYPE (type),
-                                            TYPE_ARG_TYPES (type));
 
        /* Record presence of `static'.  */
        publicp = (ctype != NULL_TREE
@@ -9728,7 +9738,8 @@ grokdeclarator (const cp_declarator *declarator,
        decl = grokfndecl (ctype, type, original_name, parms, unqualified_id,
                           virtualp, flags, memfn_quals, raises,
                           1, friendp,
-                          publicp, inlinep || constexpr_p, sfk, funcdef_flag,
+                          publicp, inlinep | (2 * constexpr_p), sfk,
+                           funcdef_flag,
                           template_count, in_namespace, attrlist,
                           declarator->id_loc);
        if (decl == NULL_TREE)
@@ -9797,6 +9808,9 @@ grokdeclarator (const cp_declarator *declarator,
                storage_class = sc_none;
              }
          }
+       else if (constexpr_p && DECL_EXTERNAL (decl))
+         error ("declaration of constexpr variable %qD is not a definition",
+                decl);
       }
 
     if (storage_class == sc_extern && initialized && !funcdef_flag)
@@ -9826,8 +9840,8 @@ grokdeclarator (const cp_declarator *declarator,
       DECL_THIS_STATIC (decl) = 1;
 
     /* Don't forget constexprness.  */
-    if (VAR_OR_FUNCTION_DECL_P (decl))
-      DECL_DECLARED_CONSTEXPR_P (decl) = constexpr_p;
+    if (constexpr_p)
+      DECL_DECLARED_CONSTEXPR_P (decl) = true;
 
     /* Record constancy and volatility on the DECL itself .  There's
        no need to do this when processing a template; we'll do this
@@ -11863,10 +11877,6 @@ check_function_type (tree decl, tree current_function_parms)
   /* In a function definition, arg types must be complete.  */
   require_complete_types_for_parms (current_function_parms);
 
-  /* constexpr functions must have literal argument types and
-     literal return type.  */
-  validate_constexpr_fundecl (decl);
-
   if (dependent_type_p (return_type))
     return;
   if (!COMPLETE_OR_VOID_TYPE_P (return_type)
@@ -12126,6 +12136,10 @@ start_preparsed_function (tree decl1, tree attrs, int flags)
        maybe_apply_pragma_weak (decl1);
     }
 
+  /* constexpr functions must have literal argument types and
+     literal return type.  */
+  validate_constexpr_fundecl (decl1);
+
   /* Reset this in case the call to pushdecl changed it.  */
   current_function_decl = decl1;
 
index f27e7d6..13fa5f6 100644 (file)
@@ -771,21 +771,6 @@ finish_static_data_member_decl (tree decl,
     permerror (input_location, "local class %q#T shall not have static data member %q#D",
               current_class_type, decl);
 
-  /* Static consts need not be initialized in the class definition.  */
-  if (init != NULL_TREE && TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)))
-    {
-      static int explained = 0;
-
-      error ("initializer invalid for static member with constructor");
-      if (!explained)
-       {
-         error ("(an out of class initialization is required)");
-         explained = 1;
-       }
-      init = NULL_TREE;
-    }
-
-  DECL_INITIAL (decl) = init;
   DECL_IN_AGGR_P (decl) = 1;
 
   if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
index 9c2afba..3a6e2e7 100644 (file)
@@ -533,6 +533,15 @@ perform_member_init (tree member, tree init)
                       "uninitialized member %qD with %<const%> type %qT",
                       member, type);
 
+         if (DECL_DECLARED_CONSTEXPR_P (current_function_decl)
+             && !type_has_constexpr_default_constructor (type))
+           {
+             if (!DECL_TEMPLATE_INSTANTIATION (current_function_decl))
+               error ("uninitialized member %qD in %<constexpr%> constructor",
+                      member);
+             DECL_DECLARED_CONSTEXPR_P (current_function_decl) = false;
+           }
+
          core_type = strip_array_types (type);
          if (CLASS_TYPE_P (core_type)
              && (CLASSTYPE_READONLY_FIELDS_NEED_INIT (core_type)
@@ -864,17 +873,30 @@ emit_mem_initializers (tree mem_inits)
       tree subobject = TREE_PURPOSE (mem_inits);
       tree arguments = TREE_VALUE (mem_inits);
 
-      /* If these initializations are taking place in a copy constructor,
-        the base class should probably be explicitly initialized if there
-        is a user-defined constructor in the base class (other than the
-        default constructor, which will be called anyway).  */
-      if (extra_warnings && !arguments
-         && DECL_COPY_CONSTRUCTOR_P (current_function_decl)
-         && type_has_user_nondefault_constructor (BINFO_TYPE (subobject)))
-       warning_at (DECL_SOURCE_LOCATION (current_function_decl), OPT_Wextra,
-                   "base class %q#T should be explicitly initialized in the "
-                   "copy constructor",
-                   BINFO_TYPE (subobject));
+      if (arguments == NULL_TREE)
+       {
+         /* If these initializations are taking place in a copy constructor,
+            the base class should probably be explicitly initialized if there
+            is a user-defined constructor in the base class (other than the
+            default constructor, which will be called anyway).  */
+         if (extra_warnings
+             && DECL_COPY_CONSTRUCTOR_P (current_function_decl)
+             && type_has_user_nondefault_constructor (BINFO_TYPE (subobject)))
+           warning_at (DECL_SOURCE_LOCATION (current_function_decl),
+                       OPT_Wextra, "base class %q#T should be explicitly "
+                       "initialized in the copy constructor",
+                       BINFO_TYPE (subobject));
+
+         if (DECL_DECLARED_CONSTEXPR_P (current_function_decl)
+             && !(type_has_constexpr_default_constructor
+                  (BINFO_TYPE (subobject))))
+           {
+             if (!DECL_TEMPLATE_INSTANTIATION (current_function_decl))
+               error ("uninitialized base %qT in %<constexpr%> constructor",
+                      BINFO_TYPE (subobject));
+             DECL_DECLARED_CONSTEXPR_P (current_function_decl) = false;
+           }
+       }
 
       /* Initialize the base.  */
       if (BINFO_VIRTUAL_P (subobject))
index d0bd6bb..0d28345 100644 (file)
@@ -1334,7 +1334,10 @@ enum
   CP_PARSER_FLAGS_NO_USER_DEFINED_TYPES = 0x2,
   /* When parsing a type-specifier, do not try to parse a class-specifier
      or enum-specifier.  */
-  CP_PARSER_FLAGS_NO_TYPE_DEFINITIONS = 0x4
+  CP_PARSER_FLAGS_NO_TYPE_DEFINITIONS = 0x4,
+  /* When parsing a decl-specifier-seq, only allow type-specifier or
+     constexpr.  */
+  CP_PARSER_FLAGS_ONLY_TYPE_OR_CONSTEXPR = 0x8
 };
 
 /* This type is used for parameters and variables which hold
@@ -8509,6 +8512,7 @@ cp_parser_condition (cp_parser* parser)
 {
   cp_decl_specifier_seq type_specifiers;
   const char *saved_message;
+  int declares_class_or_enum;
 
   /* Try the declaration first.  */
   cp_parser_parse_tentatively (parser);
@@ -8518,9 +8522,10 @@ cp_parser_condition (cp_parser* parser)
   parser->type_definition_forbidden_message
     = G_("types may not be defined in conditions");
   /* Parse the type-specifier-seq.  */
-  cp_parser_type_specifier_seq (parser, /*is_declaration==*/true,
-                               /*is_trailing_return=*/false,
-                               &type_specifiers);
+  cp_parser_decl_specifier_seq (parser,
+                               CP_PARSER_FLAGS_ONLY_TYPE_OR_CONSTEXPR,
+                               &type_specifiers,
+                               &declares_class_or_enum);
   /* Restore the saved message.  */
   parser->type_definition_forbidden_message = saved_message;
   /* If all is well, we might be looking at a declaration.  */
@@ -9851,6 +9856,11 @@ cp_parser_decl_specifier_seq (cp_parser* parser,
          break;
        }
 
+      if (found_decl_spec
+         && (flags & CP_PARSER_FLAGS_ONLY_TYPE_OR_CONSTEXPR)
+         && token->keyword != RID_CONSTEXPR)
+       error ("decl-specifier invalid in condition");
+
       /* Constructors are a special case.  The `S' in `S()' is not a
         decl-specifier; it is the beginning of the declarator.  */
       constructor_p
@@ -12231,6 +12241,13 @@ cp_parser_explicit_instantiation (cp_parser* parser)
                                                       decl_specifiers.type_location);
       if (declarator != cp_error_declarator)
        {
+         if (decl_specifiers.specs[(int)ds_inline])
+           permerror (input_location, "explicit instantiation shall not use"
+                      " %<inline%> specifier");
+         if (decl_specifiers.specs[(int)ds_constexpr])
+           permerror (input_location, "explicit instantiation shall not use"
+                      " %<constexpr%> specifier");
+
          decl = grokdeclarator (declarator, &decl_specifiers,
                                 NORMAL, 0, &decl_specifiers.attributes);
          /* Turn access control back on for names used during
@@ -16245,15 +16262,43 @@ cp_parser_function_body (cp_parser *parser)
 static bool
 cp_parser_ctor_initializer_opt_and_function_body (cp_parser *parser)
 {
-  tree body;
+  tree body, list;
   bool ctor_initializer_p;
+  const bool check_body_p =
+     DECL_CONSTRUCTOR_P (current_function_decl)
+     && DECL_DECLARED_CONSTEXPR_P (current_function_decl);
+  tree last = NULL;
 
   /* Begin the function body.  */
   body = begin_function_body ();
   /* Parse the optional ctor-initializer.  */
   ctor_initializer_p = cp_parser_ctor_initializer_opt (parser);
+
+  /* If we're parsing a constexpr constructor definition, we need
+     to check that the constructor body is indeed empty.  However,
+     before we get to cp_parser_function_body lot of junk has been
+     generated, so we can't just check that we have an empty block.
+     Rather we take a snapshot of the outermost block, and check whether
+     cp_parser_function_body changed its state.  */
+  if (check_body_p)
+    {
+      list = body;
+      if (TREE_CODE (list) == BIND_EXPR)
+       list = BIND_EXPR_BODY (list);
+      if (TREE_CODE (list) == STATEMENT_LIST
+         && STATEMENT_LIST_TAIL (list) != NULL)
+       last = STATEMENT_LIST_TAIL (list)->stmt;
+    }
   /* Parse the function-body.  */
   cp_parser_function_body (parser);
+  if (check_body_p
+      && (TREE_CODE (list) != STATEMENT_LIST
+         || (last == NULL && STATEMENT_LIST_TAIL (list) != NULL)
+         || (last != NULL && last != STATEMENT_LIST_TAIL (list)->stmt)))
+    {
+      error ("constexpr constructor does not have empty body");
+      DECL_DECLARED_CONSTEXPR_P (current_function_decl) = false;
+    }
   /* Finish the function body.  */
   finish_function_body (body);
 
index 4e73068..0ca8c33 100644 (file)
@@ -5277,6 +5277,59 @@ ensure_literal_type_for_constexpr_object (tree decl)
   return decl;
 }
 
+/* Return true if type expression T is a valid parameter type, or
+   a valid return type, of a constexpr function.  */
+
+static bool
+valid_type_in_constexpr_fundecl_p (tree t)
+{
+  return (literal_type_p (t)
+         /* FIXME we allow ref to non-literal; should change standard to
+            match, or change back if not.  */
+         || TREE_CODE (t) == REFERENCE_TYPE);
+}
+
+/* Check whether the parameter and return types of FUN are valid for a
+   constexpr function, and complain if COMPLAIN.  */
+
+static bool
+is_valid_constexpr_fn (tree fun, bool complain)
+{
+  tree parm = FUNCTION_FIRST_USER_PARM (fun);
+  bool ret = true;
+  for (; parm != NULL; parm = TREE_CHAIN (parm))
+    if (!valid_type_in_constexpr_fundecl_p (TREE_TYPE (parm)))
+      {
+       ret = false;
+       if (complain)
+         error ("invalid type for parameter %q#D of constexpr function",
+                parm);
+      }
+
+  if (!DECL_CONSTRUCTOR_P (fun))
+    {
+      tree rettype = TREE_TYPE (TREE_TYPE (fun));
+      if (!valid_type_in_constexpr_fundecl_p (rettype))
+       {
+         ret = false;
+         if (complain)
+           error ("invalid return type %qT of constexpr function %qD",
+                  rettype, fun);
+       }
+
+      if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fun)
+         && COMPLETE_TYPE_P (DECL_CONTEXT (fun))
+         && !valid_type_in_constexpr_fundecl_p (DECL_CONTEXT (fun)))
+       {
+         ret = false;
+         if (complain)
+           error ("enclosing class of %q#D is not a literal type", fun);
+       }
+    }
+
+  return ret;
+}
+
 /* Return non-null if FUN certainly designates a valid constexpr function
    declaration.  Otherwise return NULL.  Issue appropriate diagnostics
    if necessary.  Note that we only check the declaration, not the body
@@ -5285,43 +5338,18 @@ ensure_literal_type_for_constexpr_object (tree decl)
 tree
 validate_constexpr_fundecl (tree fun)
 {
-  tree rettype = NULL;
-  tree parm = NULL;
-
-  /* Don't bother if FUN is not marked constexpr.  */
-  if (!DECL_DECLARED_CONSTEXPR_P (fun))
-    return NULL;
-
-  /* For a function template, we have absolutely no guarantee that all
-     instantiations will be constexpr.  */
-  if (TREE_CODE (fun) == TEMPLATE_DECL)
+  if (processing_template_decl || !DECL_DECLARED_CONSTEXPR_P (fun))
     return NULL;
-  
-  parm = FUNCTION_FIRST_USER_PARM (fun);
-  for (; parm != NULL; parm = TREE_CHAIN (parm))
-    {
-      tree type = TREE_TYPE (parm);
-      if (dependent_type_p (type))
-        return NULL;
-      if (!literal_type_p (type))
-        {
-           error ("parameter %q#D is not of literal type", parm);
-          return NULL;
-        }
-    }
-
-  if (DECL_CONSTRUCTOR_P (fun))
+  else if (DECL_CLONED_FUNCTION_P (fun))
+    /* We already checked the original function.  */
     return fun;
 
-  rettype = TREE_TYPE (TREE_TYPE (fun));
-  if (dependent_type_p (rettype))
-    return NULL;
-  if (!literal_type_p (rettype))
+  if (!is_valid_constexpr_fn (fun, !DECL_TEMPLATE_INSTANTIATION (fun)))
     {
-      error ("return type %qT of function %qD is not a literal type",
-             TREE_TYPE (TREE_TYPE (fun)), fun);
+      DECL_DECLARED_CONSTEXPR_P (fun) = false;
       return NULL;
     }
+
   return fun;
 }
 
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-auto.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-auto.C
new file mode 100644 (file)
index 0000000..ddf0da0
--- /dev/null
@@ -0,0 +1,2 @@
+// { dg-options -std=c++0x }
+constexpr auto value = 0;
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-condition.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-condition.C
new file mode 100644 (file)
index 0000000..e2328fc
--- /dev/null
@@ -0,0 +1,9 @@
+// { dg-options -std=c++0x }
+// Core DR 948
+
+constexpr int something() { return 3; }
+
+int main() {
+  if (constexpr long v = something()) {}
+  if (static long v = something()) { } // { dg-error "decl-specifier invalid" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ctor.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-ctor.C
new file mode 100644 (file)
index 0000000..91c489d
--- /dev/null
@@ -0,0 +1,7 @@
+// { dg-options -std=c++0x }
+
+struct A
+{
+  int i;
+  constexpr A() { }            // { dg-error "uninitialized member .A::i" }
+};
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-expinst.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-expinst.C
new file mode 100644 (file)
index 0000000..2089873
--- /dev/null
@@ -0,0 +1,5 @@
+// { dg-options -std=c++0x }
+// Error: Explicit instantiation of a function template shall not use the
+// inline or constexpr specifiers
+template<class T> constexpr inline T bar(T x) { return x; }
+template constexpr inline float bar(float x); // { dg-error "specifier" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ice2.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-ice2.C
new file mode 100644 (file)
index 0000000..35643b9
--- /dev/null
@@ -0,0 +1,3 @@
+// { dg-options -std=c++0x }
+int x;
+constexpr int& rx = x; // { dg-error "int&" }