Index: testsuite/g++.dg/cpp0x/static_assert1.C
===================================================================
--- testsuite/g++.dg/cpp0x/static_assert1.C	(revision 0)
+++ testsuite/g++.dg/cpp0x/static_assert1.C	(revision 0)
@@ -0,0 +1,14 @@
+// { dg-options "-std=c++0x" }
+void foo()
+{
+  static_assert(1, "okay");
+  static_assert (0 == 1, "zero is never equal to one"); // { dg-error "never equal" }
+}
+
+class X {
+  static_assert(1, "okay");
+  static_assert (0 == 1, "zero is never equal to one"); // { dg-error "never equal" }
+};
+
+static_assert(1, "okay");
+static_assert (0 == 1, "zero is never equal to one"); // { dg-error "never equal" }
Index: testsuite/g++.dg/cpp0x/static_assert2.C
===================================================================
--- testsuite/g++.dg/cpp0x/static_assert2.C	(revision 0)
+++ testsuite/g++.dg/cpp0x/static_assert2.C	(revision 0)
@@ -0,0 +1,35 @@
+// { dg-options "-std=c++0x" }
+template<int I>
+struct accept_evens {
+  static_assert( I % 2 == 0, "I must be an even number"); // { dg-error "even number" }
+};
+
+template<int I>
+struct accept_evens_ok {
+  static_assert( I % 2 == 0, "I must be an even number");
+};
+
+template<int I>
+void accept_odds() {
+  static_assert( I % 2 == 1, "I must be an odd number"); // { dg-error "odd number" }
+}
+
+template<int I>
+void accept_odds_ok() {
+  static_assert( I % 2 == 1, "I must be an odd number");
+}
+
+void f()
+{
+  accept_odds<1>();
+  accept_odds<2>(); 
+  accept_odds<3>();
+  accept_odds_ok<5>();
+  accept_odds_ok<7>();
+}
+
+accept_evens<0> ok0;
+accept_evens<1> error1; 
+accept_evens<2> ok2;
+accept_evens_ok<4> ok4;
+accept_evens_ok<6> ok6;
Index: testsuite/g++.dg/cpp0x/static_assert3.C
===================================================================
--- testsuite/g++.dg/cpp0x/static_assert3.C	(revision 0)
+++ testsuite/g++.dg/cpp0x/static_assert3.C	(revision 0)
@@ -0,0 +1,3 @@
+// { dg-options "-std=c++0x" }
+static_assert(7 / 0, "X"); // { dg-error "non-constant condition" }
+// { dg-warning "division by zero" "" { target *-*-* } 2 }
Index: cp/cp-tree.def
===================================================================
--- cp/cp-tree.def	(revision 119062)
+++ cp/cp-tree.def	(working copy)
@@ -342,6 +342,14 @@ DEFTREECODE (STMT_EXPR, "stmt_expr", tcc
    is applied.  */
 DEFTREECODE (UNARY_PLUS_EXPR, "unary_plus_expr", tcc_unary, 1)
 
+/** C++0x extensions. */
+
+/* A static assertion.  This is a C++0x extension.
+   STATIC_ASSERT_CONDITION contains the condition that is being
+   checked.  STATIC_ASSERT_MESSAGE contains the message (a string
+   literal) to be displayed if the condition fails to hold.  */
+DEFTREECODE (STATIC_ASSERT, "static_assert", tcc_exceptional, 0)
+
 /*
 Local variables:
 mode:c
Index: cp/cp-objcp-common.c
===================================================================
--- cp/cp-objcp-common.c	(revision 119062)
+++ cp/cp-objcp-common.c	(working copy)
@@ -123,6 +123,7 @@ cp_tree_size (enum tree_code code)
     case TEMPLATE_PARM_INDEX:	return sizeof (template_parm_index);
     case DEFAULT_ARG:		return sizeof (struct tree_default_arg);
     case OVERLOAD:		return sizeof (struct tree_overload);
+    case STATIC_ASSERT:         return sizeof (struct tree_static_assert);
     default:
       gcc_unreachable ();
     }
Index: cp/error.c
===================================================================
--- cp/error.c	(revision 119062)
+++ cp/error.c	(working copy)
@@ -886,6 +886,10 @@ dump_decl (tree t, int flags)
       dump_decl (DECL_NAME (t), flags);
       break;
 
+    case STATIC_ASSERT:
+      pp_cxx_declaration (cxx_pp, t);
+      break;
+
     case BASELINK:
       dump_decl (BASELINK_FUNCTIONS (t), flags);
       break;
Index: cp/cp-tree.h
===================================================================
--- cp/cp-tree.h	(revision 119062)
+++ cp/cp-tree.h	(working copy)
@@ -446,6 +446,29 @@ struct tree_default_arg GTY (())
   VEC(tree,gc) *instantiations;
 };
 
+/* The condition associated with the static assertion.  This must be
+   an integral constant expression.  */
+#define STATIC_ASSERT_CONDITION(NODE) \
+  (((struct tree_static_assert *)STATIC_ASSERT_CHECK (NODE))->condition)
+
+/* The message associated with the static assertion.  This must be a
+   string constant, which will be emitted as an error message when the
+   static assert condition is false.  */
+#define STATIC_ASSERT_MESSAGE(NODE) \
+  (((struct tree_static_assert *)STATIC_ASSERT_CHECK (NODE))->message)
+
+/* Source location information for a static assertion.  */
+#define STATIC_ASSERT_SOURCE_LOCATION(NODE) \
+  (((struct tree_static_assert *)STATIC_ASSERT_CHECK (NODE))->location)
+
+struct tree_static_assert GTY (())
+{
+  struct tree_common common;
+  tree condition;
+  tree message;
+  location_t location;
+};
+
 enum cp_tree_node_structure_enum {
   TS_CP_GENERIC,
   TS_CP_IDENTIFIER,
@@ -457,6 +480,7 @@ enum cp_tree_node_structure_enum {
   TS_CP_BASELINK,
   TS_CP_WRAPPER,
   TS_CP_DEFAULT_ARG,
+  TS_CP_STATIC_ASSERT,
   LAST_TS_CP_ENUM
 };
 
@@ -473,6 +497,8 @@ union lang_tree_node GTY((desc ("cp_tree
   struct tree_baselink GTY ((tag ("TS_CP_BASELINK"))) baselink;
   struct tree_default_arg GTY ((tag ("TS_CP_DEFAULT_ARG"))) default_arg;
   struct lang_identifier GTY ((tag ("TS_CP_IDENTIFIER"))) identifier;
+  struct tree_static_assert GTY ((tag ("TS_CP_STATIC_ASSERT"))) 
+    static_assertion;
 };
 
 
@@ -4326,6 +4352,8 @@ extern tree cxx_omp_clause_assign_op		(t
 extern tree cxx_omp_clause_dtor			(tree, tree);
 extern bool cxx_omp_privatize_by_reference	(tree);
 extern tree baselink_for_fns                    (tree);
+extern void finish_static_assert                (tree, tree, location_t,
+                                                 bool);
 
 /* in tree.c */
 extern void lang_check_failed			(const char *, int,
Index: cp/cxx-pretty-print.c
===================================================================
--- cp/cxx-pretty-print.c	(revision 119062)
+++ cp/cxx-pretty-print.c	(working copy)
@@ -1711,6 +1711,10 @@ pp_cxx_statement (cxx_pretty_printer *pp
       pp_newline_and_indent (pp, -2);
       break;
 
+    case STATIC_ASSERT:
+      pp_cxx_declaration (pp, t);
+      break;
+
     default:
       pp_c_statement (pp_c_base (pp), t);
       break;
@@ -1906,11 +1910,21 @@ pp_cxx_explicit_instantiation (cxx_prett
        asm-definition
        namespace-alias-definition
        using-declaration
-       using-directive  */
+       using-directive
+       static_assert-declaration */
 void
 pp_cxx_declaration (cxx_pretty_printer *pp, tree t)
 {
-  if (!DECL_LANG_SPECIFIC (t))
+  if (TREE_CODE (t) == STATIC_ASSERT)
+    {
+      pp_cxx_identifier (pp, "static_assert");
+      pp_cxx_left_paren (pp);
+      pp_cxx_expression (pp, STATIC_ASSERT_CONDITION (t));
+      pp_cxx_separate_with (pp, ',');
+      pp_cxx_expression (pp, STATIC_ASSERT_MESSAGE (t));
+      pp_cxx_right_paren (pp);
+    }
+  else if (!DECL_LANG_SPECIFIC (t))
     pp_cxx_simple_declaration (pp, t);
   else if (DECL_USE_TEMPLATE (t))
     switch (DECL_USE_TEMPLATE (t))
Index: cp/pt.c
===================================================================
--- cp/pt.c	(revision 119062)
+++ cp/pt.c	(working copy)
@@ -5886,8 +5886,18 @@ instantiate_class_template (tree type)
 	  else
 	    {
 	      /* Build new TYPE_FIELDS.  */
-
-	      if (TREE_CODE (t) != CONST_DECL)
+              if (TREE_CODE (t) == STATIC_ASSERT)
+                {
+                  tree condition = 
+                    tsubst_expr (STATIC_ASSERT_CONDITION (t), args, 
+                                 tf_warning_or_error, NULL_TREE,
+                                 /*integral_constant_expression_p=*/true);
+                  finish_static_assert (condition,
+                                        STATIC_ASSERT_MESSAGE (t), 
+                                        STATIC_ASSERT_SOURCE_LOCATION (t),
+                                        /*member_p=*/true);
+                }
+	      else if (TREE_CODE (t) != CONST_DECL)
 		{
 		  tree r;
 
@@ -8716,6 +8726,20 @@ tsubst_expr (tree t, tree args, tsubst_f
       tsubst (TREE_TYPE (t), args, complain, NULL_TREE);
       break;
 
+    case STATIC_ASSERT:
+      {
+        tree condition = 
+          tsubst_expr (STATIC_ASSERT_CONDITION (t), 
+                       args,
+                       complain, in_decl,
+                       /*integral_constant_expression_p=*/true);
+        finish_static_assert (condition,
+                              STATIC_ASSERT_MESSAGE (t),
+                              STATIC_ASSERT_SOURCE_LOCATION (t),
+                              /*member_p=*/false);
+      }
+      break;
+
     case OMP_PARALLEL:
       tmp = tsubst_omp_clauses (OMP_PARALLEL_CLAUSES (t),
 				args, complain, in_decl);
Index: cp/semantics.c
===================================================================
--- cp/semantics.c	(revision 119062)
+++ cp/semantics.c	(working copy)
@@ -3914,5 +3914,57 @@ void
 init_cp_semantics (void)
 {
 }
+
+/* Build a STATIC_ASSERT for a static assertion with the condition
+   CONDITION and the message text MESSAGE.  LOCATION is the location
+   of the static assertion in the source code.  When MEMBER_P, this
+   static assertion is a member of a class.  */
+void 
+finish_static_assert (tree condition, tree message, location_t location, 
+                      bool member_p)
+{
+  if (type_dependent_expression_p (condition) 
+      || value_dependent_expression_p (condition))
+    {
+      /* We're in a template; build a STATIC_ASSERT and put it in
+         the right place. */
+      tree assertion;
+
+      assertion = make_node (STATIC_ASSERT);
+      STATIC_ASSERT_CONDITION (assertion) = condition;
+      STATIC_ASSERT_MESSAGE (assertion) = message;
+      STATIC_ASSERT_SOURCE_LOCATION (assertion) = location;
+
+      if (member_p)
+        maybe_add_class_template_decl_list (current_class_type, 
+                                            assertion,
+                                            /*friend_p=*/0);
+      else
+        add_stmt (assertion);
+
+      return;
+    }
+
+  /* Fold the expression and convert it to a boolean value. */
+  condition = fold_non_dependent_expr (condition);
+  condition = cp_convert (boolean_type_node, condition);
+
+  if (TREE_CODE (condition) == INTEGER_CST && !integer_zerop (condition))
+    /* Do nothing; the condition is satisfied. */
+    ;
+  else 
+    {
+      location_t saved_loc = input_location;
+
+      input_location = location;
+      if (TREE_CODE (condition) == INTEGER_CST 
+          && integer_zerop (condition))
+        /* Report the error. */
+        error ("static assertion failed: %E", message);
+      else if (condition && condition != error_mark_node)
+        error ("non-constant condition for static assertion");
+      input_location = saved_loc;
+    }
+}
 
 #include "gt-cp-semantics.h"
Index: cp/lex.c
===================================================================
--- cp/lex.c	(revision 119062)
+++ cp/lex.c	(working copy)
@@ -176,6 +176,7 @@ struct resword
 #define D_EXT		0x01	/* GCC extension */
 #define D_ASM		0x02	/* in C99, but has a switch to turn it off */
 #define D_OBJC		0x04	/* Objective C++ only */
+#define D_CPP0X         0x08    /* C++0x only */
 
 CONSTRAINT(ridbits_fit, RID_LAST_MODIFIER < sizeof(unsigned long) * CHAR_BIT);
 
@@ -259,6 +260,7 @@ static const struct resword reswords[] =
   { "signed",		RID_SIGNED,	0 },
   { "sizeof",		RID_SIZEOF,	0 },
   { "static",		RID_STATIC,	0 },
+  { "static_assert",    RID_STATIC_ASSERT, D_CPP0X },
   { "static_cast",	RID_STATCAST,	0 },
   { "struct",		RID_STRUCT,	0 },
   { "switch",		RID_SWITCH,	0 },
@@ -314,7 +316,8 @@ init_reswords (void)
   tree id;
   int mask = ((flag_no_asm ? D_ASM : 0)
 	      | D_OBJC
-	      | (flag_no_gnu_keywords ? D_EXT : 0));
+	      | (flag_no_gnu_keywords ? D_EXT : 0)
+              | (flag_cpp0x ? 0 : D_CPP0X));
 
   ridpointers = GGC_CNEWVEC (tree, (int) RID_MAX);
   for (i = 0; i < ARRAY_SIZE (reswords); i++)
Index: cp/parser.c
===================================================================
--- cp/parser.c	(revision 119062)
+++ cp/parser.c	(working copy)
@@ -1589,6 +1589,8 @@ static void cp_parser_asm_definition
   (cp_parser *);
 static void cp_parser_linkage_specification
   (cp_parser *);
+static void cp_parser_static_assert
+  (cp_parser *, bool);
 
 /* Declarators [gram.dcl.decl] */
 
@@ -7211,6 +7213,11 @@ cp_parser_declaration (cp_parser* parser
      __extension__ block-declaration
      label-declaration
 
+   C++0x Extension:
+
+   block-declaration:
+     static_assert-declaration
+
    If STATEMENT_P is TRUE, then this block-declaration is occurring as
    part of a declaration-statement.  */
 
@@ -7272,6 +7279,9 @@ cp_parser_block_declaration (cp_parser *
 	cp_parser_commit_to_tentative_parse (parser);
       cp_parser_label_declaration (parser);
     }
+  /* If the next token is `static_assert' we have a static assertion.  */
+  else if (token1->keyword == RID_STATIC_ASSERT)
+    cp_parser_static_assert (parser, /*member_p=*/false);
   /* Anything else must be a simple-declaration.  */
   else
     cp_parser_simple_declaration (parser, !statement_p);
@@ -7825,6 +7835,68 @@ cp_parser_linkage_specification (cp_pars
   pop_lang_context ();
 }
 
+/* Parse a static_assert-declaration.
+
+   static_assert-declaration:
+     static_assert ( constant-expression , string-literal ) ; 
+
+   If MEMBER_P, this static_assert is a class member.  */
+
+static void 
+cp_parser_static_assert(cp_parser *parser, bool member_p)
+{
+  tree condition;
+  tree message;
+  cp_token *token;
+  location_t saved_loc;
+
+  /* Peek at the `static_assert' token so we can keep track of exactly
+     where the static assertion started.  */
+  token = cp_lexer_peek_token (parser->lexer);
+  saved_loc = token->location;
+
+  /* Look for the `static_assert' keyword.  */
+  if (!cp_parser_require_keyword (parser, RID_STATIC_ASSERT, 
+                                  "`static_assert'"))
+    return;
+
+  /*  We know we are in a static assertion; commit to any tentative
+      parse.  */
+  if (cp_parser_parsing_tentatively (parser))
+    cp_parser_commit_to_tentative_parse (parser);
+
+  /* Parse the `(' starting the static assertion condition.  */
+  cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
+
+  /* Parse the constant-expression.  */
+  condition = 
+    cp_parser_constant_expression (parser,
+                                   /*allow_non_constant_p=*/false,
+                                   /*non_constant_p=*/NULL);
+
+  /* Parse the separating `,'.  */
+  cp_parser_require (parser, CPP_COMMA, "`,'");
+
+  /* Parse the string-literal message.  */
+  message = cp_parser_string_literal (parser, 
+                                      /*translate=*/false,
+                                      /*wide_ok=*/true);
+
+  /* A `)' completes the static assertion.  */
+  if (!cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"))
+    cp_parser_skip_to_closing_parenthesis (parser, 
+                                           /*recovering=*/true, 
+                                           /*or_comma=*/false,
+					   /*consume_paren=*/true);
+
+  /* A semicolon terminates the declaration.  */
+  cp_parser_require (parser, CPP_SEMICOLON, "`;'");
+
+  /* Complete the static assertion, which may mean either processing 
+     the static assert now or saving it for template instantiation.  */
+  finish_static_assert (condition, message, saved_loc, member_p);
+}
+
 /* Special member functions [gram.special] */
 
 /* Parse a conversion-function-id.
@@ -13624,7 +13696,12 @@ cp_parser_member_specification_opt (cp_p
    member-declarator:
      declarator attributes [opt] pure-specifier [opt]
      declarator attributes [opt] constant-initializer [opt]
-     identifier [opt] attributes [opt] : constant-expression  */
+     identifier [opt] attributes [opt] : constant-expression  
+
+   C++0x Extensions:
+
+   member-declaration:
+     static_assert-declaration  */
 
 static void
 cp_parser_member_declaration (cp_parser* parser)
@@ -13687,6 +13764,13 @@ cp_parser_member_declaration (cp_parser*
       return;
     }
 
+  /* If the next token is `static_assert' we have a static assertion.  */
+  if (cp_lexer_next_token_is_keyword (parser->lexer, RID_STATIC_ASSERT))
+    {
+      cp_parser_static_assert (parser, /*member_p=*/true);
+      return;
+    }
+
   if (cp_parser_using_declaration (parser, /*access_declaration=*/true))
     return;
 
Index: c-common.h
===================================================================
--- c-common.h	(revision 119062)
+++ c-common.h	(working copy)
@@ -90,6 +90,9 @@ enum rid
   /* casts */
   RID_CONSTCAST, RID_DYNCAST, RID_REINTCAST, RID_STATCAST,
 
+  /* C++0x */
+  RID_STATIC_ASSERT,
+
   /* Objective-C */
   RID_AT_ENCODE,   RID_AT_END,
   RID_AT_CLASS,    RID_AT_ALIAS,     RID_AT_DEFS,
