diff options
author | Andrew Sutton <andrew.n.sutton@gmail.com> | 2015-08-07 05:44:49 +0000 |
---|---|---|
committer | Jason Merrill <jason@gcc.gnu.org> | 2015-08-07 01:44:49 -0400 |
commit | 971e17ff87337ad533b51c2dff0bbdf607fa1faf (patch) | |
tree | 23bad22378f96699b757d5523bf73d4139ad66da /gcc/cp/decl.c | |
parent | bf5372e7f0c5c0df7f239ce96ce35a2114400269 (diff) | |
download | gcc-971e17ff87337ad533b51c2dff0bbdf607fa1faf.zip gcc-971e17ff87337ad533b51c2dff0bbdf607fa1faf.tar.gz gcc-971e17ff87337ad533b51c2dff0bbdf607fa1faf.tar.bz2 |
Add C++ Concepts TS support.
gcc/c-family/
* c-common.c (c_common_reswords): Add __is_same_as, concept, requires.
* c-common.h (enum rid): Add RID_IS_SAME_AS, RID_CONCEPT, RID_REQUIRES.
(D_CXX_CONCEPTS, D_CXX_CONCEPTS_FLAGS): New.
* c-cppbuiltin.c (c_cpp_builtins): Define __cpp_concepts.
* c-opts.c (set_std_cxx1z): Set flag_concepts.
* c.opt (fconcepts): New.
gcc/cp/
* constraint.cc, logic.cc: New files.
* Make-lang.in (CXX_AND_OBJCXX_OBJS): Add constraint.o and logic.o.
(c++.tags): Also process .cc files.
* call.c (enum rejection_reason_code): Add rr_constraint_failure.
(print_z_candidate): Handle it.
(constraint_failure): New.
(add_function_candidate): Check constraints.
(build_new_function_call): Handle evaluating concepts.
(joust): Check more_constrained.
* class.c (add_method): Check equivalently_constrained.
(build_clone): Copy constraints.
(currently_open_class): Return tree.
(resolve_address_of_overloaded_function): Check constraints.
* constexpr.c (cxx_eval_constant_expression): Handle REQUIRES_EXPR.
(potential_constant_expression_1): Likewise.
* cp-objcp-common.c (cp_tree_size): Handle CONSTRAINT_INFO.
(cp_common_init_ts): Handle WILDCARD_DECL and REQUIRES_EXPR.
* cp-tree.def: Add CONSTRAINT_INFO, WILDCARD_DECL, REQUIRES_EXPR,
SIMPLE_REQ, TYPE_REQ, COMPOUND_REQ, NESTED_REQ, PRED_CONSTR,
EXPR_CONSTR, TYPE_CONSTR, ICONV_CONSTR, DEDUCT_CONSTR,
EXCEPT_CONSTR, PARM_CONSTR, CONJ_CONSTR, DISJ_CONSTR.
* cp-tree.h (struct tree_constraint_info, check_nonnull)
(check_constraint_info, CI_TEMPLATE_REQS, CI_DECLARATOR_REQS)
(CI_ASSOCIATED_CONSTRAINTS, CI_NORMALIZED_CONSTRAINTS)
(CI_ASSUMPTIONS, TEMPLATE_PARMS_CONSTRAINTS)
(TEMPLATE_PARM_CONSTRAINTS, COMPOUND_REQ_NOEXCEPT_P)
(PLACEHOLDER_TYPE_CONSTRAINTS, PRED_CONSTR_EXPR, EXPR_CONSTR_EXPR)
(TYPE_CONSTR_TYPE, ICONV_CONSTR_EXPR, ICONV_CONSTR_TYPE)
(DEDUCT_CONSTR_EXPR, DEDUCT_CONSTR_PATTERN)
(DEDUCT_CONSTR_PLACEHOLDER, EXCEPT_CONSTR_EXPR, PARM_CONSTR_PARMS)
(PARM_CONSTR_OPERAND, CONSTRAINT_VAR_P, CONSTRAINED_PARM_CONCEPT)
(CONSTRAINED_PARM_EXTRA_ARGS, CONSTRAINED_PARM_PROTOTYPE)
(DECL_DECLARED_CONCEPT_P, WILDCARD_PACK_P, struct cp_unevaluated)
(struct local_specialization_stack, enum auto_deduction_context)
(variable_concept_p, concept_template_p)
(struct deferring_access_check_sentinel): New.
(enum cp_tree_node_structure_enum): Add TS_CP_CONSTRAINT_INFO.
(union lang_tree_node): Add constraint_info field.
(struct lang_decl_base): Add concept_p flag.
(enum cp_decl_spec): Add ds_concept.
(struct cp_declarator): Add requires_clause.
* cxx-pretty-print.c (cxx_pretty_printer::primary_expression)
(cxx_pretty_printer::expression): Handle REQUIRES_EXPR,
TRAIT_EXPR, *_CONSTR.
(pp_cxx_parameter_declaration_clause): Accept a chain of
PARM_DECLs.
(cxx_pretty_printer::declarator): Print requires-clause.
(pp_cxx_template_declaration): Likewise.
(pp_cxx_trait_expression): Handle CPTK_IS_SAME_AS.
(pp_cxx_requires_clause, pp_cxx_requirement)
(pp_cxx_requirement_list, pp_cxx_requirement_body)
(pp_cxx_requires_expr, pp_cxx_simple_requirement)
(pp_cxx_type_requirement, pp_cxx_compound_requirement)
(pp_cxx_nested_requirement, pp_cxx_predicate_constraint)
(pp_cxx_expression_constraint, pp_cxx_type_constraint)
(pp_cxx_implicit_conversion_constraint)
(pp_cxx_argument_deduction_constraint)
(pp_cxx_exception_constraint, pp_cxx_parameterized_constraint)
(pp_cxx_conjunction, pp_cxx_disjunction, pp_cxx_constraint): New.
* cxx-pretty-print.h: Declare them.
* decl.c (decls_match): Compare constraints.
(duplicate_decls): Likewise. Remove constraints before freeing.
(cxx_init_decl_processing): Call init_constraint_processing.
(cp_finish_decl): Diagnose concept without initializer.
(grokfndecl, grokvardecl): Handle concepts and constraints.
(grokdeclarator): Handle concept, requires-clause.
(grokparms): No longer static.
(xref_tag_1): Check constraints.
(finish_function): Call check_function_concept.
(cp_tree_node_structure): Handle CONSTRAINT_INFO.
(check_concept_refinement, is_concept_var, check_concept_fn): New.
* decl2.c (check_classfn): Compare constraints.
(mark_used): Don't instantiate concepts.
* error.c (dump_template_decl): Print constraints.
(dump_function_decl): Likewise.
(dump_expr): Handle REQUIRES_EXPR, *_REQ, *_CONSTR.
* lex.c (init_reswords): Set D_CXX_CONCEPTS.
* method.c (implicitly_declare_fn): Copy constraints from
inherited ctor.
* parser.h (struct cp_parser): Add in_result_type_constraint_p and
prevent_constrained_type_specifiers fields.
* parser.c (make_call_declarator): Add requires_clause parm.
(cp_parser_new): Clear prevent_constrained_type_specifiers.
(cp_parser_primary_expression): Handle RID_IS_SAME_AS, RID_REQUIRES.
(cp_parser_postfix_expression): Set prevent_constrained_type_specifiers.
(cp_parser_trait_expr): Handle RID_IS_SAME_AS.
(cp_parser_declaration): Handle concept introduction.
(cp_parser_member_declaration): Likewise.
(cp_parser_template_parameter): Handle constrained parameter.
(cp_parser_type_parameter): Handle constraints.
(cp_parser_decl_specifier_seq): Handle RID_CONCEPT.
(cp_parser_template_id): Handle partial concept id.
(cp_parser_type_name): Add overload that takes typename_keyword_p.
Handle constrained parameter.
(cp_parser_nonclass_name): Handle concept names.
(cp_parser_alias_declaration): Handle constraints.
(cp_parser_late_return_type_opt): Also handle requires-clause.
(cp_parser_type_id_1): Handle deduction constraint.
(cp_parser_parameter_declaration): Handle constrained parameters.
(cp_parser_class_specifier_1): Handle constraints.
(cp_parser_template_declaration_after_parameters): Split out from
cp_parser_template_declaration_after_export.
(cp_parser_single_declaration): Handle constraints.
(synthesize_implicit_template_parm): Handle constraints.
(cp_parser_maybe_concept_name, cp_parser_maybe_partial_concept_id)
(cp_parser_introduction_list, get_id_declarator)
(get_unqualified_id, is_constrained_parameter)
(cp_parser_check_constrained_type_parm)
(cp_parser_constrained_type_template_parm)
(cp_parser_constrained_template_template_parm)
(constrained_non_type_template_parm, finish_constrained_parameter)
(declares_constrained_type_template_parameter)
(declares_constrained_template_template_parameter)
(check_type_concept, cp_parser_maybe_constrained_type_specifier)
(cp_parser_maybe_concept_name, cp_parser_maybe_partial_concept_id)
(cp_parser_requires_clause, cp_parser_requires_clause_opt)
(cp_parser_requires_expression)
(cp_parser_requirement_parameter_list, cp_parser_requirement_body)
(cp_parser_requirement_list, cp_parser_requirement)
(cp_parser_simple_requirement, cp_parser_type_requirement)
(cp_parser_compound_requirement, cp_parser_nested_requirement)
(cp_parser_template_introduction)
(cp_parser_explicit_template_declaration)
(get_concept_from_constraint): New.
* pt.c (local_specialization_stack): Implement.
(maybe_new_partial_specialization): New.
(maybe_process_partial_specialization): Use it.
(retrieve_local_specialization, register_local_specialization)
(template_parm_to_arg, build_template_decl, extract_fnparm_pack)
(tsubst_expr): No longer static.
(spec_hasher::equal): Compare constraints.
(determine_specialization): Handle constraints.
(check_explicit_specialization): Handle concepts.
(process_template_parm): Handle constraints.
(end_template_parm_list): Add overload taking no arguments.
(process_partial_specialization): Handle concepts and constraints.
Register partial specializations of variable templates.
(redeclare_class_template): Handle constraints.
(convert_template_argument): Handle WILDCARD_DECL. Check
is_compatible_template_arg.
(coerce_template_parameter_pack): Handle wildcard packs.
(coerce_template_parms): DR 1430 also applies to concepts. Add
overloads taking fewer parameters.
(lookup_template_class_1): Handle constraints.
(lookup_template_variable): Concepts are always bool.
(finish_template_variable): Handle concepts and constraints.
(tsubst_friend_class): Handle constraints.
(gen_elem_of_pack_expansion_instantiation): Handle constraints.
(tsubst_pack_expansion): Handle local parameters.
(tsubst_decl) [FUNCTION_DECL]: Handle constraints.
(tsubst) [TEMPLATE_TYPE_PARM]: Handle deduction constraints.
(tsubst_copy_and_build): Handle REQUIRES_EXPR.
(more_specialized_fn, more_specialized_partial_spec): Check constraints.
(more_specialized_inst): Split out from most_specialized_instantiation.
(most_specialized_partial_spec): Check constraints.
(instantiate_decl): Never instantiate a concept.
(value_dependent_expression_p): Handle REQUIRES_EXPR, TYPE_REQ,
variable concepts.
(type_dependent_expression_p): Handle WILDCARD_DECL, REQUIRES_EXPR.
(instantiation_dependent_r): Handle REQUIRES_EXPR and concepts.
(do_auto_deduction): Add overload taking tsubst flags and context enum.
Handle constraints.
(get_template_for_ordering, most_constrained_function)
(is_compatible_template_arg, convert_wildcard_argument)
(struct constr_entry, struct constr_hasher, decl_constraints)
(valid_constraints_p, get_constraints, set_constraints)
(remove_constraints, init_constraint_processing): New.
* ptree.c (cxx_print_xnode): Handle CONSTRAINT_INFO.
* search.c (lookup_member): Do lookup in the open partial
instantiation.
* semantics.c (finish_template_template_parm): Handle constraints.
(fixup_template_type): New.
(finish_template_type): Call it.
(trait_expr_value, finish_trait_expr): Handle CPTK_IS_SAME_AS.
* tree.c (cp_tree_equal): Handle local parameters, CONSTRAINT_INFO.
(cp_walk_subtrees): Handle REQUIRES_EXPR.
* typeck.c (cp_build_function_call_vec): Check constraints.
Co-Authored-By: Braden Obrzut <admin@maniacsvault.net>
Co-Authored-By: Jason Merrill <jason@redhat.com>
From-SVN: r226713
Diffstat (limited to 'gcc/cp/decl.c')
-rw-r--r-- | gcc/cp/decl.c | 267 |
1 files changed, 242 insertions, 25 deletions
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 208173a..e8ed472 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -72,7 +72,6 @@ enum bad_spec_place { BSP_FIELD /* field */ }; -static tree grokparms (tree parmlist, tree *); static const char *redeclaration_error_message (tree, tree); static int decl_jump_unsafe (tree); @@ -1079,8 +1078,10 @@ decls_match (tree newdecl, tree olddecl) } else if (TREE_CODE (newdecl) == TEMPLATE_DECL) { - if (TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) - != TREE_CODE (DECL_TEMPLATE_RESULT (olddecl))) + tree oldres = DECL_TEMPLATE_RESULT (olddecl); + tree newres = DECL_TEMPLATE_RESULT (newdecl); + + if (TREE_CODE (newres) != TREE_CODE (oldres)) return 0; if (!comp_template_parms (DECL_TEMPLATE_PARMS (newdecl), @@ -1088,11 +1089,12 @@ decls_match (tree newdecl, tree olddecl) return 0; if (TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == TYPE_DECL) - types_match = same_type_p (TREE_TYPE (DECL_TEMPLATE_RESULT (olddecl)), - TREE_TYPE (DECL_TEMPLATE_RESULT (newdecl))); + types_match = (same_type_p (TREE_TYPE (oldres), TREE_TYPE (newres)) + && equivalently_constrained (olddecl, newdecl)); else - types_match = decls_match (DECL_TEMPLATE_RESULT (olddecl), - DECL_TEMPLATE_RESULT (newdecl)); + // We don't need to check equivalently_constrained for variable and + // function templates because we check it on the results. + types_match = decls_match (oldres, newres); } else { @@ -1120,6 +1122,11 @@ decls_match (tree newdecl, tree olddecl) COMPARE_REDECLARATION); } + // Normal functions can be constrained, as can variable partial + // specializations. + if (types_match && VAR_OR_FUNCTION_DECL_P (newdecl)) + types_match = equivalently_constrained (newdecl, olddecl); + return types_match; } @@ -1243,6 +1250,36 @@ validate_constexpr_redeclaration (tree old_decl, tree new_decl) return true; } +// If OLDDECL and NEWDECL are concept declarations with the same type +// (i.e., and template parameters), but different requirements, +// emit diagnostics and return true. Otherwise, return false. +static inline bool +check_concept_refinement (tree olddecl, tree newdecl) +{ + if (!DECL_DECLARED_CONCEPT_P (olddecl) || !DECL_DECLARED_CONCEPT_P (newdecl)) + return false; + + tree d1 = DECL_TEMPLATE_RESULT (olddecl); + tree d2 = DECL_TEMPLATE_RESULT (newdecl); + if (TREE_CODE (d1) != TREE_CODE (d2)) + return false; + + tree t1 = TREE_TYPE (d1); + tree t2 = TREE_TYPE (d2); + if (TREE_CODE (d1) == FUNCTION_DECL) + { + if (compparms (TYPE_ARG_TYPES (t1), TYPE_ARG_TYPES (t2)) + && comp_template_parms (DECL_TEMPLATE_PARMS (olddecl), + DECL_TEMPLATE_PARMS (newdecl)) + && !equivalently_constrained (olddecl, newdecl)) + { + error ("cannot specialize concept %q#D", olddecl); + return true; + } + } + return false; +} + /* DECL is a redeclaration of a function or function template. If it does have default arguments issue a diagnostic. Note: this function is used to enforce the requirements in C++11 8.3.6 about @@ -1571,12 +1608,17 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) /* Template functions can be disambiguated by return type. */ && same_type_p (TREE_TYPE (TREE_TYPE (newdecl)), - TREE_TYPE (TREE_TYPE (olddecl)))) + TREE_TYPE (TREE_TYPE (olddecl))) + // Template functions can also be disambiguated by + // constraints. + && equivalently_constrained (olddecl, newdecl)) { error ("ambiguating new declaration %q+#D", newdecl); inform (DECL_SOURCE_LOCATION (olddecl), "old declaration %q#D", olddecl); } + else if (check_concept_refinement (olddecl, newdecl)) + return error_mark_node; return NULL_TREE; } if (TREE_CODE (newdecl) == FUNCTION_DECL) @@ -1593,8 +1635,11 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) are not ambiguous. */ else if ((!DECL_FUNCTION_VERSIONED (newdecl) && !DECL_FUNCTION_VERSIONED (olddecl)) + // The functions have the same parameter types. && compparms (TYPE_ARG_TYPES (TREE_TYPE (newdecl)), - TYPE_ARG_TYPES (TREE_TYPE (olddecl)))) + TYPE_ARG_TYPES (TREE_TYPE (olddecl))) + // And the same constraints. + && equivalently_constrained (newdecl, olddecl)) { error ("ambiguating new declaration of %q+#D", newdecl); inform (DECL_SOURCE_LOCATION (olddecl), @@ -2576,6 +2621,12 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) if (snode) snode->remove (); } + + /* Remove the associated constraints for newdecl, if any, before + reclaiming memory. */ + if (flag_concepts) + remove_constraints (newdecl); + ggc_free (newdecl); return olddecl; @@ -3981,6 +4032,10 @@ cxx_init_decl_processing (void) /* Ensure attribs.c is initialized. */ init_attributes (); + + /* Ensure constraint.cc is initialized. */ + init_constraint_processing (); + extvisattr = build_tree_list (get_identifier ("externally_visible"), NULL_TREE); newattrs = tree_cons (get_identifier ("alloc_size"), @@ -6368,6 +6423,16 @@ value_dependent_init_p (tree init) return false; } +// Returns true if a DECL is VAR_DECL with the concept specifier. +static inline bool +is_concept_var (tree decl) +{ + return (VAR_P (decl) + // Not all variables have DECL_LANG_SPECIFIC. + && DECL_LANG_SPECIFIC (decl) + && DECL_DECLARED_CONCEPT_P (decl)); +} + /* Finish processing of a declaration; install its line number and initial value. If the length of an array type is not known before, @@ -6446,7 +6511,9 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, tf_warning_or_error); d_init = resolve_nondeduced_context (d_init); type = TREE_TYPE (decl) = do_auto_deduction (type, d_init, - auto_node); + auto_node, + tf_warning_or_error, + adc_variable_type); if (type == error_mark_node) return; cp_apply_type_quals_to_decl (cp_type_quals (type), decl); @@ -6544,6 +6611,8 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, init = NULL_TREE; release_tree_vector (cleanups); } + else if (!init && is_concept_var (decl)) + error ("variable concept has no initializer"); else if (!DECL_PRETTY_FUNCTION_P (decl)) { /* Deduce array size even if the initializer is dependent. */ @@ -7606,6 +7675,23 @@ check_static_quals (tree decl, cp_cv_quals quals) decl); } +// Check that FN takes no arguments and returns bool. +static void +check_concept_fn (tree fn) +{ + // A constraint is nullary. + if (DECL_ARGUMENTS (fn)) + error ("concept %q#D declared with function parameters", fn); + + // The declared return type of the concept shall be bool, and + // it shall not be deduced from it definition. + tree type = TREE_TYPE (TREE_TYPE (fn)); + if (is_auto (type)) + error ("concept %q#D declared with a deduced return type", fn); + else if (type != boolean_type_node) + error ("concept %q#D with non-%<bool%> return type %qT", fn, type); +} + /* Helper function. Replace the temporary this parameter injected during cp_finish_omp_declare_simd with the real this parameter. */ @@ -7646,6 +7732,7 @@ grokfndecl (tree ctype, tree declarator, tree parms, tree orig_declarator, + tree decl_reqs, int virtualp, enum overload_flags flags, cp_cv_quals quals, @@ -7667,6 +7754,16 @@ grokfndecl (tree ctype, int staticp = ctype && TREE_CODE (type) == FUNCTION_TYPE; tree t; + // 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) @@ -7674,6 +7771,21 @@ grokfndecl (tree ctype, decl = build_lang_decl (FUNCTION_DECL, declarator, type); + /* Set the constraints on the declaration. */ + if (flag_concepts) + { + tree tmpl_reqs = NULL_TREE; + if (processing_template_decl > template_class_depth (ctype)) + tmpl_reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms); + + /* Adjust the required expression into a constraint. */ + if (decl_reqs) + decl_reqs = make_predicate_constraint (decl_reqs); + + tree ci = build_constraints (tmpl_reqs, decl_reqs); + set_constraints (decl, ci); + } + /* If we have an explicit location, use it, otherwise use whatever build_lang_decl used (probably input_location). */ if (location != UNKNOWN_LOCATION) @@ -7848,6 +7960,14 @@ grokfndecl (tree ctype, if (inlinep & 2) DECL_DECLARED_CONSTEXPR_P (decl) = true; + // If the concept declaration specifier was found, check + // that the declaration satisfies the necessary requirements. + if (concept_p) + { + DECL_DECLARED_CONCEPT_P (decl) = true; + check_concept_fn (decl); + } + DECL_EXTERNAL (decl) = 1; if (TREE_CODE (type) == FUNCTION_TYPE) { @@ -7967,7 +8087,8 @@ grokfndecl (tree ctype, decl = check_explicit_specialization (orig_declarator, decl, template_count, 2 * funcdef_flag + - 4 * (friendp != 0)); + 4 * (friendp != 0) + + 8 * concept_p); if (decl == error_mark_node) return NULL_TREE; @@ -8125,7 +8246,7 @@ grokvardecl (tree type, tree orig_declarator, const cp_decl_specifier_seq *declspecs, int initialized, - int constp, + int flags, int template_count, tree scope) { @@ -8134,6 +8255,9 @@ grokvardecl (tree type, gcc_assert (!name || identifier_p (name)); + bool constp = flags&1; + bool conceptp = flags&2; + /* Compute the scope in which to place the variable, but remember whether or not that scope was explicitly specified by the user. */ explicit_scope = scope; @@ -8231,10 +8355,33 @@ grokvardecl (tree type, else DECL_INTERFACE_KNOWN (decl) = 1; + /* Check that the variable can be safely declared as a concept. + Note that this also forbids explicit specializations. */ + if (conceptp) + { + if (!processing_template_decl) + { + error ("a non-template variable cannot be %<concept%>"); + return NULL_TREE; + } + else + DECL_DECLARED_CONCEPT_P (decl) = true; + if (!same_type_ignoring_top_level_qualifiers_p (type, boolean_type_node)) + error_at (declspecs->locations[ds_type_spec], + "concept must have type %<bool%>"); + } + else if (flag_concepts + && processing_template_decl > template_class_depth (scope)) + { + tree reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms); + tree ci = build_constraints (reqs, NULL_TREE); + set_constraints (decl, ci); + } + // Handle explicit specializations and instantiations of variable templates. if (orig_declarator) decl = check_explicit_specialization (orig_declarator, decl, - template_count, 0); + template_count, conceptp * 8); return decl != error_mark_node ? decl : NULL_TREE; } @@ -8969,6 +9116,7 @@ grokdeclarator (const cp_declarator *declarator, bool array_parameter_p = false; source_location saved_loc = input_location; const char *errmsg; + tree reqs = NULL_TREE; signed_p = decl_spec_seq_has_spec_p (declspecs, ds_signed); unsigned_p = decl_spec_seq_has_spec_p (declspecs, ds_unsigned); @@ -8978,6 +9126,12 @@ grokdeclarator (const cp_declarator *declarator, explicit_intN = declspecs->explicit_intN_p; thread_p = decl_spec_seq_has_spec_p (declspecs, ds_thread); + // Was concept_p specified? Note that ds_concept + // implies ds_constexpr! + bool concept_p = decl_spec_seq_has_spec_p (declspecs, ds_concept); + if (concept_p) + constexpr_p = true; + if (decl_context == FUNCDEF) funcdef_flag = true, decl_context = NORMAL; else if (decl_context == MEMFUNCDEF) @@ -9220,6 +9374,12 @@ grokdeclarator (const cp_declarator *declarator, if (name == NULL) name = decl_context == PARM ? "parameter" : "type name"; + if (concept_p && typedef_p) + { + error ("%<concept%> cannot appear in a typedef declaration"); + return error_mark_node; + } + if (constexpr_p && typedef_p) { error ("%<constexpr%> cannot appear in a typedef declaration"); @@ -9548,9 +9708,12 @@ grokdeclarator (const cp_declarator *declarator, || thread_p) error ("storage class specifiers invalid in parameter declarations"); + /* Function parameters cannot be concept. */ + if (concept_p) + error ("a parameter cannot be declared %<concept%>"); /* Function parameters cannot be constexpr. If we saw one, moan and pretend it wasn't there. */ - if (constexpr_p) + else if (constexpr_p) { error ("a parameter cannot be declared %<constexpr%>"); constexpr_p = 0; @@ -9778,6 +9941,10 @@ grokdeclarator (const cp_declarator *declarator, if (raises == error_mark_node) raises = NULL_TREE; + if (reqs) + error_at (location_of (reqs), "requires-clause on return type"); + reqs = declarator->u.function.requires_clause; + /* Say it's a definition only for the CALL_EXPR closest to the identifier. */ funcdecl_p = inner_declarator && inner_declarator->kind == cdk_id; @@ -10373,6 +10540,9 @@ grokdeclarator (const cp_declarator *declarator, type = error_mark_node; } + if (reqs) + error_at (location_of (reqs), "requires-clause on typedef"); + if (decl_context == FIELD) decl = build_lang_decl (TYPE_DECL, unqualified_id, type); else @@ -10566,6 +10736,9 @@ grokdeclarator (const cp_declarator *declarator, error ("invalid qualifiers on non-member function type"); } + if (reqs) + error_at (location_of (reqs), "requires-clause on type-id"); + return type; } else if (unqualified_id == NULL_TREE && decl_context != PARM @@ -10587,6 +10760,13 @@ grokdeclarator (const cp_declarator *declarator, return error_mark_node; } + if (reqs + && TREE_CODE (type) != FUNCTION_TYPE + && TREE_CODE (type) != METHOD_TYPE) + error_at (location_of (reqs), + "requires-clause on declaration of non-function type %qT", + type); + /* We don't check parameter types here because we can emit a better error message later. */ if (decl_context != PARM) @@ -10744,6 +10924,11 @@ grokdeclarator (const cp_declarator *declarator, uqname, ctype); return error_mark_node; } + if (concept_p) + { + error ("a destructor cannot be %<concept%>"); + return error_mark_node; + } if (constexpr_p) { error ("a destructor cannot be %<constexpr%>"); @@ -10757,6 +10942,17 @@ grokdeclarator (const cp_declarator *declarator, id_declarator->u.id.unqualified_name); return error_mark_node; } + if (sfk == sfk_constructor) + if (concept_p) + { + error ("a constructor cannot be %<concept%>"); + return error_mark_node; + } + if (concept_p) + { + error ("a concept cannot be a member function"); + concept_p = false; + } if (TREE_CODE (unqualified_id) == TEMPLATE_ID_EXPR) { @@ -10785,9 +10981,10 @@ grokdeclarator (const cp_declarator *declarator, ? unqualified_id : dname, parms, unqualified_id, + reqs, virtualp, flags, memfn_quals, rqual, raises, friendp ? -1 : 0, friendp, publicp, - inlinep | (2 * constexpr_p), + inlinep | (2 * constexpr_p) | (4 * concept_p), initialized == SD_DELETED, sfk, funcdef_flag, template_count, in_namespace, attrlist, declarator->id_loc); @@ -10890,8 +11087,10 @@ grokdeclarator (const cp_declarator *declarator, if (declspecs->gnu_thread_keyword_p) SET_DECL_GNU_TLS_P (decl); } - - if (constexpr_p && !initialized) + if (concept_p) + error ("static data member %qE declared %<concept%>", + unqualified_id); + else if (constexpr_p && !initialized) { error ("constexpr static data member %qD must have an " "initializer", decl); @@ -10900,7 +11099,10 @@ grokdeclarator (const cp_declarator *declarator, } else { - if (constexpr_p) + if (concept_p) + error ("non-static data member %qE declared %<concept%>", + unqualified_id); + else if (constexpr_p) { error ("non-static data member %qE declared %<constexpr%>", unqualified_id); @@ -11010,10 +11212,12 @@ grokdeclarator (const cp_declarator *declarator, TYPE_HAS_LATE_RETURN_TYPE (type) = 1; decl = grokfndecl (ctype, type, original_name, parms, unqualified_id, - virtualp, flags, memfn_quals, rqual, raises, + reqs, virtualp, flags, memfn_quals, rqual, raises, 1, friendp, - publicp, inlinep | (2 * constexpr_p), - initialized == SD_DELETED, sfk, + publicp, + inlinep | (2 * constexpr_p) | (4 * concept_p), + initialized == SD_DELETED, + sfk, funcdef_flag, template_count, in_namespace, attrlist, declarator->id_loc); @@ -11054,7 +11258,7 @@ grokdeclarator (const cp_declarator *declarator, decl = grokvardecl (type, dname, unqualified_id, declspecs, initialized, - (type_quals & TYPE_QUAL_CONST) != 0, + ((type_quals & TYPE_QUAL_CONST) != 0) | (2 * concept_p), template_count, ctype ? ctype : in_namespace); if (decl == NULL_TREE) @@ -11304,7 +11508,7 @@ type_is_deprecated (tree type) *PARMS is set to the chain of PARM_DECLs created. */ -static tree +tree grokparms (tree parmlist, tree *parms) { tree result = NULL_TREE; @@ -12399,8 +12603,16 @@ xref_tag_1 (enum tag_types tag_code, tree name, { if (template_header_p && MAYBE_CLASS_TYPE_P (t)) { - if (!redeclare_class_template (t, current_template_parms)) - return error_mark_node; + /* Check that we aren't trying to overload a class with different + constraints. */ + tree constr = NULL_TREE; + if (current_template_parms) + { + tree reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms); + constr = build_constraints (reqs, NULL_TREE); + } + if (!redeclare_class_template (t, current_template_parms, constr)) + return error_mark_node; } else if (!processing_template_decl && CLASS_TYPE_P (t) @@ -14252,6 +14464,10 @@ finish_function (int flags) fntype = TREE_TYPE (fndecl); } + // If this is a concept, check that the definition is reasonable. + if (DECL_DECLARED_CONCEPT_P (fndecl)) + check_function_concept (fndecl); + /* Save constexpr function body before it gets munged by the NRV transformation. */ maybe_save_function_definition (fndecl); @@ -14742,6 +14958,7 @@ cp_tree_node_structure (union lang_tree_node * t) case TRAIT_EXPR: return TS_CP_TRAIT_EXPR; case LAMBDA_EXPR: return TS_CP_LAMBDA_EXPR; case TEMPLATE_INFO: return TS_CP_TEMPLATE_INFO; + case CONSTRAINT_INFO: return TS_CP_CONSTRAINT_INFO; case USERDEF_LITERAL: return TS_CP_USERDEF_LITERAL; default: return TS_CP_GENERIC; } |