diff mbox

C++0x constexpr PATCH #2: improve type checking of constexpr declarations

Message ID 4CC87E03.2070005@redhat.com
State New
Headers show

Commit Message

Jason Merrill Oct. 27, 2010, 7:31 p.m. UTC
This patch improves our type checking of constexpr declarations: 
variables must have literal type, functions must have parameter and 
return types of literal or reference type, constructors must have an 
empty body and have mem-initializers for any bases or members.  The 
patch also adds various syntax and redeclaration checks.

Tested x86_64-pc-linux-gnu, applied to trunk.
diff mbox

Patch

commit 93c3af7c9f729c6675598c9e47e11b3e2b25673a
Author: Jason Merrill <jason@redhat.com>
Date:   Tue Oct 26 18:28:45 2010 -0400

    	* 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.

diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 00af0ae..c3e3c53 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -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
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 8c0c9b1..1cd776a 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -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);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index e27a64d..8b2af9cd 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -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;
 
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index f27e7d6..13fa5f6 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -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
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 9c2afba..3a6e2e7 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -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))
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index d0bd6bb..0d28345 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -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);
 
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 4e73068..0ca8c33 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -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))
+  if (processing_template_decl || !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)
-    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
index 0000000..ddf0da0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-auto.C
@@ -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
index 0000000..e2328fc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-condition.C
@@ -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
index 0000000..91c489d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ctor.C
@@ -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
index 0000000..2089873
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-expinst.C
@@ -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
index 0000000..35643b9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ice2.C
@@ -0,0 +1,3 @@ 
+// { dg-options -std=c++0x }
+int x;
+constexpr int& rx = x; // { dg-error "int&" }