diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 2915b43..6550ec3 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -156,17 +156,6 @@ resolve_constraint_check (tree ovl, tree args)
   if (!DECL_DECLARED_CONCEPT_P (decl))
     return NULL_TREE;
 
-  // Concept declarations must have a corresponding definition.
-  //
-  // TODO: This should be part of the up-front checking for
-  // a concept declaration.
-  if (!DECL_SAVED_TREE (decl))
-    {
-      error_at (DECL_SOURCE_LOCATION (decl),
-                "concept %q#D has no definition", decl);
-      return NULL;
-    }
-
   return cands;
 }
 
@@ -610,13 +599,12 @@ normalize_template_id (tree t)
     return normalize_var (t);
   else
     {
-      // FIXME: input_location is probably wrong, but there's not necessarly
-      // an expr location with the tree.
-      error_at (input_location, "invalid constraint %qE", t);
+      location_t locus = EXPR_LOC_OR_LOC (t, input_location);
+      error_at (locus, "invalid constraint %qE", t);
 
       vec<tree, va_gc>* args = NULL;
       tree c = finish_call_expr (t, &args, true, false, 0);
-      inform (input_location, "did you mean %qE", c);
+      inform (locus, "did you mean %qE", c);
 
       return error_mark_node;
     }
@@ -865,6 +853,8 @@ valid_requirements_p (tree cinfo)
   return CI_ASSUMPTIONS (cinfo) != error_mark_node;
 }
 
+// Constructs a REQUIRES_EXPR with parameters, PARMS, and requirements, REQS,
+// that can be evaluated as a constant expression.
 tree
 build_requires_expr (tree parms, tree reqs)
 {
@@ -1836,7 +1826,7 @@ diagnose_call (location_t loc, tree t, tree args)
     inform (loc, "  %qE evaluated to false", t);
 }
 
-// Diagnose constraint failures in a variable concept.
+// Diagnose constraint failures in a variable template-id T.
 void
 diagnose_var (location_t loc, tree t, tree args)
 {
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 0f9926c..bb635d8 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -1262,8 +1262,6 @@ check_concept_refinement (tree olddecl, tree newdecl)
   if (!DECL_DECLARED_CONCEPT_P (olddecl) || !DECL_DECLARED_CONCEPT_P (newdecl))
     return false;
 
-  // TODO: This isn't currently possible, but it will almost certainly
-  // change with variable templates.
   tree d1 = DECL_TEMPLATE_RESULT (olddecl);
   tree d2 = DECL_TEMPLATE_RESULT (newdecl);
   if (TREE_CODE (d1) != TREE_CODE (d2))
@@ -7724,6 +7722,13 @@ grokfndecl (tree ctype,
   // Was the concept specifier present?
   bool concept_p = inlinep & 4;
 
+  // Concept declarations must have a corresponding definition.
+  if (concept_p && !funcdef_flag)
+    {
+      error ("concept %qD has no definition", declarator);
+      return NULL_TREE;
+    }
+
   if (rqual)
     type = build_ref_qualified_type (type, rqual);
   if (raises)
@@ -11052,8 +11057,6 @@ grokdeclarator (const cp_declarator *declarator,
 		      DECL_GNU_TLS_P (decl) = true;
 		  }
 		if (concept_p)
-		  // TODO: This needs to be revisited once variable
-		  // templates are supported
 		    error ("static data member %qE declared %<concept%>",
 			   unqualified_id);
 		else if (constexpr_p && !initialized)
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 65d4acc..70bbbab 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -13344,7 +13344,7 @@ cp_parser_template_parameter_list (cp_parser* parser)
 static tree
 cp_parser_introduction_list (cp_parser *parser)
 {
-  tree introduction_list = NULL_TREE;
+  vec<tree, va_gc> *introduction_vec = make_tree_vector ();
 
   while (true)
     {
@@ -13358,8 +13358,7 @@ cp_parser_introduction_list (cp_parser *parser)
 	= cp_lexer_peek_token (parser->lexer)->location;
       DECL_NAME (parm) = cp_parser_identifier (parser);
       INTRODUCED_PACK_P (parm) = is_pack;
-      introduction_list = chainon (introduction_list,
-				   build_tree_list (NULL_TREE, parm));
+      introduction_vec->quick_push (parm);
 
       // If the next token is not a `,', we're done.
       if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA))
@@ -13368,27 +13367,23 @@ cp_parser_introduction_list (cp_parser *parser)
       cp_lexer_consume_token (parser->lexer);
     }
 
-  // Convert the TREE_LIST into a TREE_VEC, similar to what is done in
-  // end_template_parm_list.
-  tree introduction_vec = make_tree_vec (list_length (introduction_list));
-  int n = 0;
-  while (introduction_list != NULL_TREE)
+  // Convert the vec into a TREE_VEC.
+  tree introduction_list = make_tree_vec (introduction_vec->length ());
+  unsigned int n;
+  tree parm;
+  FOR_EACH_VEC_ELT (*introduction_vec, n, parm)
     {
-       tree next = TREE_CHAIN (introduction_list);
-       TREE_VEC_ELT (introduction_vec, n) = TREE_VALUE (introduction_list);
-       TREE_CHAIN (introduction_list) = NULL_TREE;
-
-       introduction_list = next;
-       ++n;
+       TREE_VEC_ELT (introduction_list, n) = parm;
     }
 
-  return introduction_vec;
+  release_tree_vector (introduction_vec);
+  return introduction_list;
 }
 
 // Given a declarator, get the declarator-id part, or NULL_TREE if this
 // is an abstract declarator.
 static inline cp_declarator*
-cp_get_id_declarator (cp_declarator *declarator)
+get_id_declarator (cp_declarator *declarator)
 {
   cp_declarator *d = declarator;
   while (d && d->kind != cdk_id)
@@ -13399,9 +13394,9 @@ cp_get_id_declarator (cp_declarator *declarator)
 // Get the unqualified-id from the DECLARATOR or NULL_TREE if this
 // is an abstract declarator.
 static inline tree
-cp_get_identifier (cp_declarator *declarator)
+get_unqualified_id (cp_declarator *declarator)
 {
-  declarator = cp_get_id_declarator (declarator);
+  declarator = get_id_declarator (declarator);
   if (declarator)
     return declarator->u.id.unqualified_name;
   else
@@ -13410,7 +13405,7 @@ cp_get_identifier (cp_declarator *declarator)
 
 // Returns true if PARM declares a constrained-parameter.
 static inline bool
-cp_is_constrained_parameter (cp_parameter_declarator *parm)
+is_constrained_parameter (cp_parameter_declarator *parm)
 {
   gcc_assert (parm);
   tree decl = parm->decl_specifiers.type;
@@ -13426,8 +13421,8 @@ cp_is_constrained_parameter (cp_parameter_declarator *parm)
 // Check that the type parameter is only a declarator-id, and that its
 // type is not cv-qualified.
 bool
-cp_check_constrained_type_parm (cp_parser *parser,
-                                cp_parameter_declarator *parm)
+cp_parser_check_constrained_type_parm (cp_parser *parser,
+				       cp_parameter_declarator *parm)
 {
   if (!parm->declarator)
     return true;
@@ -13452,11 +13447,11 @@ cp_check_constrained_type_parm (cp_parser *parser,
 // Finish parsing/processing a template type parameter and chekcing
 // various restrictions.
 static inline tree
-cp_constrained_type_template_parm (cp_parser *parser,
-                                   tree id,
-                                   cp_parameter_declarator* parmdecl)
+cp_parser_constrained_type_template_parm (cp_parser *parser,
+                                          tree id,
+                                          cp_parameter_declarator* parmdecl)
 {
-  if (cp_check_constrained_type_parm (parser, parmdecl))
+  if (cp_parser_check_constrained_type_parm (parser, parmdecl))
     return finish_template_type_parm (class_type_node, id);
   else
     return error_mark_node;
@@ -13465,12 +13460,12 @@ cp_constrained_type_template_parm (cp_parser *parser,
 // Finish parsing/processing a template template parameter by borrowing
 // the template parameter list from the prototype parameter.
 static tree
-cp_constrained_template_template_parm (cp_parser *parser,
-                                       tree proto,
-                                       tree id,
-                                       cp_parameter_declarator *parmdecl)
+cp_parser_constrained_template_template_parm (cp_parser *parser,
+                                              tree proto,
+                                              tree id,
+                                              cp_parameter_declarator *parmdecl)
 {
-  if (!cp_check_constrained_type_parm (parser, parmdecl))
+  if (!cp_parser_check_constrained_type_parm (parser, parmdecl))
     return error_mark_node;
 
   // FIXME: This should probably be copied, and we may need to adjust
@@ -13487,8 +13482,8 @@ cp_constrained_template_template_parm (cp_parser *parser,
 
 // Create a new non-type template parameter from the given PARM declarator.
 static tree
-cp_constrained_non_type_template_parm (bool *is_non_type,
-                                       cp_parameter_declarator *parm)
+constrained_non_type_template_parm (bool *is_non_type,
+                                    cp_parameter_declarator *parm)
 {
   *is_non_type = true;
   cp_declarator *decl = parm->declarator;
@@ -13502,13 +13497,13 @@ cp_constrained_non_type_template_parm (bool *is_non_type,
 // refers to the prototype template parameter that ultimately
 // specifies the type of the declared parameter.
 static tree
-cp_finish_constrained_parameter (cp_parser *parser,
-                                 cp_parameter_declarator *parmdecl,
-                                 bool *is_non_type,
-                                 bool *is_parameter_pack)
+finish_constrained_parameter (cp_parser *parser,
+                              cp_parameter_declarator *parmdecl,
+                              bool *is_non_type,
+                              bool *is_parameter_pack)
 {
   tree decl = parmdecl->decl_specifiers.type;
-  tree id = cp_get_identifier (parmdecl->declarator);
+  tree id = get_unqualified_id (parmdecl->declarator);
   tree def = parmdecl->default_argument;
   tree proto = DECL_INITIAL (decl);
 
@@ -13521,11 +13516,12 @@ cp_finish_constrained_parameter (cp_parser *parser,
   // Build the parameter. Return an error if the declarator was invalid.
   tree parm;
   if (TREE_CODE (proto) == TYPE_DECL)
-    parm = cp_constrained_type_template_parm (parser, id, parmdecl);
+    parm = cp_parser_constrained_type_template_parm (parser, id, parmdecl);
   else if (TREE_CODE (proto) == TEMPLATE_DECL)
-    parm = cp_constrained_template_template_parm (parser, proto, id, parmdecl);
+    parm = cp_parser_constrained_template_template_parm (parser, proto, id,
+							 parmdecl);
   else
-    parm = cp_constrained_non_type_template_parm (is_non_type, parmdecl);
+    parm = constrained_non_type_template_parm (is_non_type, parmdecl);
   if (parm == error_mark_node)
     return error_mark_node;
 
@@ -13540,7 +13536,7 @@ cp_finish_constrained_parameter (cp_parser *parser,
 // a template type parameter. This is a helper function for the
 // cp_declares_type* functions below.
 static inline bool
-cp_maybe_type_parameter (tree type)
+maybe_type_parameter (tree type)
 {
   return type
          && TREE_CODE (type) == TYPE_DECL
@@ -13551,9 +13547,9 @@ cp_maybe_type_parameter (tree type)
 // Returns true if the parsed type actually represents a type or template
 // template parameter.
 static inline bool
-cp_declares_type_parameter (tree type)
+declares_type_parameter (tree type)
 {
-  if (cp_maybe_type_parameter (type))
+  if (maybe_type_parameter (type))
     {
       tree_code c = TREE_CODE (TREE_TYPE (type));
       return c == TEMPLATE_TYPE_PARM || c == TEMPLATE_TEMPLATE_PARM;
@@ -13564,9 +13560,9 @@ cp_declares_type_parameter (tree type)
 // Returns true if the parsed type actually represents the declaration
 // of a type template-parameter.
 static inline bool
-cp_declares_type_template_parameter (tree type)
+declares_type_template_parameter (tree type)
 {
-  return cp_maybe_type_parameter (type)
+  return maybe_type_parameter (type)
          && TREE_CODE (TREE_TYPE (type)) == TEMPLATE_TYPE_PARM;
 }
 
@@ -13574,9 +13570,9 @@ cp_declares_type_template_parameter (tree type)
 // Returns true if the parsed type actually represents the declaration of
 // a template template-parameter.
 static bool
-cp_declares_template_template_parameter (tree type)
+declares_template_template_parameter (tree type)
 {
-  return cp_maybe_type_parameter (type)
+  return maybe_type_parameter (type)
          && TREE_CODE (TREE_TYPE (type)) == TEMPLATE_TEMPLATE_PARM;
 }
 
@@ -13784,20 +13780,20 @@ cp_parser_template_parameter (cp_parser* parser, bool *is_non_type,
 		  "template parameter pack cannot have a default argument");
       
       /* Parse the default argument, but throw away the result.  */
-      if (cp_declares_type_template_parameter (declared_type))
+      if (declares_type_template_parameter (declared_type))
         cp_parser_default_type_template_argument (parser);
-      else if (cp_declares_template_template_parameter (declared_type))
+      else if (declares_template_template_parameter (declared_type))
         cp_parser_default_template_template_argument (parser);
       else
         cp_parser_default_argument (parser, /*template_parm_p=*/true);
     }
 
   // The parameter may have been constrained.
-  if (cp_is_constrained_parameter (parameter_declarator))
-    return cp_finish_constrained_parameter (parser,
-                                            parameter_declarator,
-                                            is_non_type,
-                                            is_parameter_pack);
+  if (is_constrained_parameter (parameter_declarator))
+    return finish_constrained_parameter (parser,
+                                         parameter_declarator,
+                                         is_non_type,
+                                         is_parameter_pack);
 
   // Now we're sure that the parameter is a non-type parameter.
   *is_non_type = true;
@@ -13878,11 +13874,8 @@ cp_parser_type_parameter (cp_parser* parser, bool *is_parameter_pack)
 	/* If the next token is an `=', we have a default argument.  */
 	if (cp_lexer_next_token_is (parser->lexer, CPP_EQ))
 	  {
-	    /* Consume the `=' token.  */
-	    cp_lexer_consume_token (parser->lexer);
-	    /* Parse the default-argument.  */
-	    push_deferring_access_checks (dk_no_deferred);
-	    default_argument = cp_parser_type_id (parser);
+	    default_argument
+	      = cp_parser_default_type_template_argument (parser);
 
             /* Template parameter packs cannot have default
                arguments. */
@@ -13898,7 +13891,6 @@ cp_parser_type_parameter (cp_parser* parser, bool *is_parameter_pack)
 			    "default arguments");
                 default_argument = NULL_TREE;
               }
-	    pop_deferring_access_checks ();
 	  }
 	else
 	  default_argument = NULL_TREE;
@@ -13977,40 +13969,8 @@ cp_parser_type_parameter (cp_parser* parser, bool *is_parameter_pack)
 	   default-argument.  */
 	if (cp_lexer_next_token_is (parser->lexer, CPP_EQ))
 	  {
-	    bool is_template;
-
-	    /* Consume the `='.  */
-	    cp_lexer_consume_token (parser->lexer);
-	    /* Parse the id-expression.  */
-	    push_deferring_access_checks (dk_no_deferred);
-	    /* save token before parsing the id-expression, for error
-	       reporting */
-	    token = cp_lexer_peek_token (parser->lexer);
-	    default_argument
-	      = cp_parser_id_expression (parser,
-					 /*template_keyword_p=*/false,
-					 /*check_dependency_p=*/true,
-					 /*template_p=*/&is_template,
-					 /*declarator_p=*/false,
-					 /*optional_p=*/false);
-	    if (TREE_CODE (default_argument) == TYPE_DECL)
-	      /* If the id-expression was a template-id that refers to
-		 a template-class, we already have the declaration here,
-		 so no further lookup is needed.  */
-		 ;
-	    else
-	      /* Look up the name.  */
-	      default_argument
-		= cp_parser_lookup_name (parser, default_argument,
-					 none_type,
-					 /*is_template=*/is_template,
-					 /*is_namespace=*/false,
-					 /*check_dependency=*/true,
-					 /*ambiguous_decls=*/NULL,
-					 token->location);
-	    /* See if the default argument is valid.  */
 	    default_argument
-	      = check_template_template_default_arg (default_argument);
+	      = cp_parser_default_template_template_argument (parser);
 
             /* Template parameter packs cannot have default
                arguments. */
@@ -14026,7 +13986,6 @@ cp_parser_type_parameter (cp_parser* parser, bool *is_parameter_pack)
 			    "have default arguments");
                 default_argument = NULL_TREE;
               }
-	    pop_deferring_access_checks ();
 	  }
 	else
 	  default_argument = NULL_TREE;
@@ -15586,7 +15545,7 @@ cp_parser_type_name (cp_parser* parser)
 	  && TREE_CODE (type_decl) == TYPE_DECL
 	  && TYPE_DECL_ALIAS_P (type_decl))
 	gcc_assert (DECL_TEMPLATE_INSTANTIATION (type_decl));
-      else if (cp_maybe_type_parameter (type_decl))
+      else if (maybe_type_parameter (type_decl))
         /* Don't do anything. */ ;
       else
 	cp_parser_simulate_error (parser);
@@ -15639,7 +15598,7 @@ cp_maybe_constrained_type_specifier (cp_parser *parser, tree decl, tree args)
 
   // Try to build a call expression that evaluates the concept. This
   // can fail if the overload set refers only to non-templates.
-  tree placeholder = build_nt (PLACEHOLDER_EXPR);
+  tree placeholder = build_nt (INTRODUCED_PARM_DECL);
   tree call = build_concept_check (decl, placeholder, args);
   if (call == error_mark_node)
     return NULL_TREE;
@@ -19639,12 +19598,12 @@ cp_parser_parameter_declaration (cp_parser *parser,
 	default_argument = cp_parser_cache_defarg (parser, /*nsdmi=*/false);
 
       // A constrained-type-specifier may declare a type template-parameter.
-      else if (cp_declares_type_template_parameter (type))
+      else if (declares_type_template_parameter (type))
         default_argument
           = cp_parser_default_type_template_argument (parser);
 
       // A constrained-type-specifier may declare a template-template-parameter.
-      else if (cp_declares_template_template_parameter (type))
+      else if (declares_template_template_parameter (type))
         default_argument
           = cp_parser_default_template_template_argument (parser);
 
@@ -23311,7 +23270,6 @@ cp_parser_requires_clause_opt (cp_parser *parser)
 // within the scope are popped prior to exiting the scope.
 struct cp_parser_requires_expr_scope
 {
-  // Enter a scope of kind K belonging to the decl D.
   cp_parser_requires_expr_scope ()
   {
     begin_scope (sk_block, NULL_TREE);
@@ -23319,9 +23277,7 @@ struct cp_parser_requires_expr_scope
 
   ~cp_parser_requires_expr_scope ()
   {
-    for (tree t = current_binding_level->names; t; t = DECL_CHAIN (t))
-      pop_binding (DECL_NAME (t), t);
-    leave_scope ();
+    pop_bindings_and_leave_scope ();
   }
 };
 
@@ -23345,10 +23301,6 @@ cp_parser_requires_expression (cp_parser *parser)
       return error_mark_node;
     }
 
-
-  // TODO: Check that requires expressions are only written inside of
-  // template declarations. They don't need to be concepts, just templates.
-
   // Parse the optional parameter list. Any local parameter declarations
   // are added to a new scope and are visible within the nested
   // requirement list.
@@ -33692,13 +33644,6 @@ tree_type_is_auto_or_concept (const_tree t)
 
 // Return the template decl being called or evaluated as part of the
 // constraint check.
-//
-// TODO: This is a bit of a hack. When we finish the template parameter
-// the constraint is just a call expression, but we don't have the full
-// context that we used to build that call expression. Since we're going
-// to be comparing declarations, it would helpful to have that. This
-// means we'll have to make the TREE_TYPE of the parameter node a pair
-// containing the context (the TYPE_DECL) and the constraint.
 static tree
 get_concept_from_constraint (tree t)
 {
diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h
index 6e57a72..ee6e2b2 100644
--- a/gcc/cp/parser.h
+++ b/gcc/cp/parser.h
@@ -397,9 +397,9 @@ typedef struct GTY(()) cp_parser {
      member definition using a generic type, it is the sk_class scope.  */
   cp_binding_level* implicit_template_scope;
 
-  /* True if parsing a template parameter list. The interpretation of a
-     constrained-type-specifiers differs inside a template parameter
-     list than outside. */
+  /* True if parsing a result type in a compound requirement. This permits
+     constrained-type-specifiers inside what would normally be a trailing
+     return type. */
   bool in_result_type_constraint_p;
 
 } cp_parser;
diff --git a/gcc/testsuite/g++.dg/concepts/decl-diagnose.C b/gcc/testsuite/g++.dg/concepts/decl-diagnose.C
index d3374f9..77fc40d 100644
--- a/gcc/testsuite/g++.dg/concepts/decl-diagnose.C
+++ b/gcc/testsuite/g++.dg/concepts/decl-diagnose.C
@@ -4,14 +4,17 @@ typedef concept int CINT; // { dg-error "'concept' cannot appear in a typedef de
 
 void f(concept int); // { dg-error "a parameter cannot be declared 'concept'" }
 
-concept int f2(); // { dg-error "return type" }
-concept bool f3();
+template<typename T>
+concept int f2() { return 0; } // { dg-error "return type" }
+concept bool f3(); // { dg-error "no definition" }
 
 struct X
 {
-  concept int f4(); // { dg-error "return type|function parameters" }
-  concept bool f5(); // { dg-error "declared with function parameters" }
-  static concept bool f6(); // { dg-error "a concept cannot be a static member function" }
+  template<typename T>
+  concept int f4() { return 0; } // { dg-error "return type|function parameters" }
+  concept bool f5() { return true; } // { dg-error "declared with function parameters" }
+  template<typename T>
+  static concept bool f6() { return true; } // { dg-error "a concept cannot be a static member function" }
   static concept bool x; // { dg-error "declared 'concept'" }
   concept int x2; // { dg-error "declared 'concept'" }
   concept ~X(); // { dg-error "a destructor cannot be 'concept'" }
