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
This commit is contained in:
parent
bf5372e7f0
commit
971e17ff87
|
@ -1,3 +1,15 @@
|
|||
2015-08-06 Andrew Sutton <andrew.n.sutton@gmail.com>
|
||||
Braden Obrzut <admin@maniacsvault.net>
|
||||
Jason Merrill <jason@redhat.com>
|
||||
|
||||
Add C++ Concepts TS support.
|
||||
* 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.
|
||||
|
||||
2015-08-02 Patrick Palka <ppalka@gcc.gnu.org>
|
||||
|
||||
* c-indentation.c (should_warn_for_misleading_indentation):
|
||||
|
|
|
@ -491,6 +491,7 @@ const struct c_common_resword c_common_reswords[] =
|
|||
{ "__is_literal_type", RID_IS_LITERAL_TYPE, D_CXXONLY },
|
||||
{ "__is_pod", RID_IS_POD, D_CXXONLY },
|
||||
{ "__is_polymorphic", RID_IS_POLYMORPHIC, D_CXXONLY },
|
||||
{ "__is_same_as", RID_IS_SAME_AS, D_CXXONLY },
|
||||
{ "__is_standard_layout", RID_IS_STD_LAYOUT, D_CXXONLY },
|
||||
{ "__is_trivial", RID_IS_TRIVIAL, D_CXXONLY },
|
||||
{ "__is_trivially_assignable", RID_IS_TRIVIALLY_ASSIGNABLE, D_CXXONLY },
|
||||
|
@ -589,6 +590,11 @@ const struct c_common_resword c_common_reswords[] =
|
|||
{ "volatile", RID_VOLATILE, 0 },
|
||||
{ "wchar_t", RID_WCHAR, D_CXXONLY },
|
||||
{ "while", RID_WHILE, 0 },
|
||||
|
||||
/* Concepts-related keywords */
|
||||
{ "concept", RID_CONCEPT, D_CXX_CONCEPTS_FLAGS | D_CXXWARN },
|
||||
{ "requires", RID_REQUIRES, D_CXX_CONCEPTS_FLAGS | D_CXXWARN },
|
||||
|
||||
/* These Objective-C keywords are recognized only immediately after
|
||||
an '@'. */
|
||||
{ "compatibility_alias", RID_AT_ALIAS, D_OBJC },
|
||||
|
|
|
@ -142,6 +142,7 @@ enum rid
|
|||
RID_IS_EMPTY, RID_IS_ENUM,
|
||||
RID_IS_FINAL, RID_IS_LITERAL_TYPE,
|
||||
RID_IS_POD, RID_IS_POLYMORPHIC,
|
||||
RID_IS_SAME_AS,
|
||||
RID_IS_STD_LAYOUT, RID_IS_TRIVIAL,
|
||||
RID_IS_TRIVIALLY_ASSIGNABLE, RID_IS_TRIVIALLY_CONSTRUCTIBLE,
|
||||
RID_IS_TRIVIALLY_COPYABLE,
|
||||
|
@ -150,6 +151,9 @@ enum rid
|
|||
/* C++11 */
|
||||
RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
|
||||
|
||||
/* C++ concepts */
|
||||
RID_CONCEPT, RID_REQUIRES,
|
||||
|
||||
/* Cilk Plus keywords. */
|
||||
RID_CILK_SPAWN, RID_CILK_SYNC, RID_CILK_FOR,
|
||||
|
||||
|
@ -386,6 +390,9 @@ extern machine_mode c_default_pointer_mode;
|
|||
#define D_OBJC 0x080 /* In Objective C and neither C nor C++. */
|
||||
#define D_CXX_OBJC 0x100 /* In Objective C, and C++, but not C. */
|
||||
#define D_CXXWARN 0x200 /* In C warn with -Wcxx-compat. */
|
||||
#define D_CXX_CONCEPTS 0x400 /* In C++, only with concepts. */
|
||||
|
||||
#define D_CXX_CONCEPTS_FLAGS D_CXXONLY | D_CXX_CONCEPTS
|
||||
|
||||
/* The reserved keyword table. */
|
||||
extern const struct c_common_resword c_common_reswords[];
|
||||
|
|
|
@ -865,6 +865,10 @@ c_cpp_builtins (cpp_reader *pfile)
|
|||
cpp_define (pfile, "__cpp_variable_templates=201304");
|
||||
cpp_define (pfile, "__cpp_digit_separators=201309");
|
||||
}
|
||||
if (flag_concepts)
|
||||
/* Use a value smaller than the 201507 specified in
|
||||
the TS, since we don't yet support extended auto. */
|
||||
cpp_define (pfile, "__cpp_concepts=201500");
|
||||
if (flag_sized_deallocation)
|
||||
cpp_define (pfile, "__cpp_sized_deallocation=201309");
|
||||
}
|
||||
|
|
|
@ -1558,6 +1558,8 @@ set_std_cxx1z (int iso)
|
|||
/* C++11 includes the C99 standard library. */
|
||||
flag_isoc94 = 1;
|
||||
flag_isoc99 = 1;
|
||||
/* Enable concepts by default. */
|
||||
flag_concepts = 1;
|
||||
flag_isoc11 = 1;
|
||||
cxx_dialect = cxx1z;
|
||||
lang_hooks.name = "GNU C++14"; /* Pretend C++14 till standarization. */
|
||||
|
|
|
@ -1086,6 +1086,10 @@ fcilkplus
|
|||
C ObjC C++ ObjC++ LTO Report Var(flag_cilkplus) Init(0)
|
||||
Enable Cilk Plus
|
||||
|
||||
fconcepts
|
||||
C++ ObjC++ Var(flag_concepts)
|
||||
Enable support for C++ concepts
|
||||
|
||||
fcond-mismatch
|
||||
C ObjC C++ ObjC++
|
||||
Allow the arguments of the '?' operator to have different types
|
||||
|
|
183
gcc/cp/ChangeLog
183
gcc/cp/ChangeLog
|
@ -1,3 +1,186 @@
|
|||
2015-08-06 Andrew Sutton <andrew.n.sutton@gmail.com>
|
||||
Braden Obrzut <admin@maniacsvault.net>
|
||||
Jason Merrill <jason@redhat.com>
|
||||
|
||||
Add C++ Concepts TS support.
|
||||
* 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.
|
||||
|
||||
2015-08-06 Jason Merrill <jason@redhat.com>
|
||||
|
||||
PR c++/66533
|
||||
|
|
|
@ -78,7 +78,8 @@ CXX_AND_OBJCXX_OBJS = cp/call.o cp/decl.o cp/expr.o cp/pt.o cp/typeck2.o \
|
|||
cp/mangle.o cp/cp-objcp-common.o cp/name-lookup.o cp/cxx-pretty-print.o \
|
||||
cp/cp-cilkplus.o \
|
||||
cp/cp-gimplify.o cp/cp-array-notation.o cp/lambda.o \
|
||||
cp/vtable-class-hierarchy.o cp/constexpr.o cp/cp-ubsan.o $(CXX_C_OBJS)
|
||||
cp/vtable-class-hierarchy.o cp/constexpr.o cp/cp-ubsan.o \
|
||||
cp/constraint.o cp/logic.o $(CXX_C_OBJS)
|
||||
|
||||
# Language-specific object files for C++.
|
||||
CXX_OBJS = cp/cp-lang.o c-family/stub-objc.o $(CXX_AND_OBJCXX_OBJS)
|
||||
|
@ -131,7 +132,7 @@ c++.srcinfo:
|
|||
c++.srcextra:
|
||||
|
||||
c++.tags: force
|
||||
cd $(srcdir)/cp; etags -o TAGS.sub *.c *.h --language=none \
|
||||
cd $(srcdir)/cp; etags -o TAGS.sub *.c *.cc *.h --language=none \
|
||||
--regex='/DEFTREECODE [(]\([A-Z_]+\)/\1/' cp-tree.def; \
|
||||
etags --include TAGS.sub --include ../TAGS.sub
|
||||
|
||||
|
|
|
@ -425,7 +425,8 @@ enum rejection_reason_code {
|
|||
rr_arg_conversion,
|
||||
rr_bad_arg_conversion,
|
||||
rr_template_unification,
|
||||
rr_invalid_copy
|
||||
rr_invalid_copy,
|
||||
rr_constraint_failure
|
||||
};
|
||||
|
||||
struct conversion_info {
|
||||
|
@ -688,6 +689,27 @@ invalid_copy_with_fn_template_rejection (void)
|
|||
return r;
|
||||
}
|
||||
|
||||
// Build a constraint failure record, saving information into the
|
||||
// template_instantiation field of the rejection. If FN is not a template
|
||||
// declaration, the TMPL member is the FN declaration and TARGS is empty.
|
||||
|
||||
static struct rejection_reason *
|
||||
constraint_failure (tree fn)
|
||||
{
|
||||
struct rejection_reason *r = alloc_rejection (rr_constraint_failure);
|
||||
if (tree ti = DECL_TEMPLATE_INFO (fn))
|
||||
{
|
||||
r->u.template_instantiation.tmpl = TI_TEMPLATE (ti);
|
||||
r->u.template_instantiation.targs = TI_ARGS (ti);
|
||||
}
|
||||
else
|
||||
{
|
||||
r->u.template_instantiation.tmpl = fn;
|
||||
r->u.template_instantiation.targs = NULL_TREE;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Dynamically allocate a conversion. */
|
||||
|
||||
static conversion *
|
||||
|
@ -1957,10 +1979,20 @@ add_function_candidate (struct z_candidate **candidates,
|
|||
viable = 0;
|
||||
reason = arity_rejection (first_arg, i + remaining, len);
|
||||
}
|
||||
|
||||
/* Second, for a function to be viable, its constraints must be
|
||||
satisfied. */
|
||||
if (flag_concepts && viable
|
||||
&& !constraints_satisfied_p (fn))
|
||||
{
|
||||
reason = constraint_failure (fn);
|
||||
viable = false;
|
||||
}
|
||||
|
||||
/* When looking for a function from a subobject from an implicit
|
||||
copy/move constructor/operator=, don't consider anything that takes (a
|
||||
reference to) an unrelated type. See c++/44909 and core 1092. */
|
||||
else if (parmlist && (flags & LOOKUP_DEFAULTED))
|
||||
if (viable && parmlist && (flags & LOOKUP_DEFAULTED))
|
||||
{
|
||||
if (DECL_CONSTRUCTOR_P (fn))
|
||||
i = 1;
|
||||
|
@ -1984,7 +2016,7 @@ add_function_candidate (struct z_candidate **candidates,
|
|||
if (! viable)
|
||||
goto out;
|
||||
|
||||
/* Second, for F to be a viable function, there shall exist for each
|
||||
/* Third, for F to be a viable function, there shall exist for each
|
||||
argument an implicit conversion sequence that converts that argument
|
||||
to the corresponding parameter of F. */
|
||||
|
||||
|
@ -3387,6 +3419,13 @@ print_z_candidate (location_t loc, const char *msgstr,
|
|||
" a constructor taking a single argument of its own "
|
||||
"class type is invalid");
|
||||
break;
|
||||
case rr_constraint_failure:
|
||||
{
|
||||
tree tmpl = r->u.template_instantiation.tmpl;
|
||||
tree args = r->u.template_instantiation.targs;
|
||||
diagnose_constraints (cloc, tmpl, args);
|
||||
}
|
||||
break;
|
||||
case rr_none:
|
||||
default:
|
||||
/* This candidate didn't have any issues or we failed to
|
||||
|
@ -4044,9 +4083,13 @@ build_new_function_call (tree fn, vec<tree, va_gc> **args, bool koenig_p,
|
|||
{
|
||||
if (complain & tf_error)
|
||||
{
|
||||
// If there is a single (non-viable) function candidate,
|
||||
// let the error be diagnosed by cp_build_function_call_vec.
|
||||
if (!any_viable_p && candidates && ! candidates->next
|
||||
&& (TREE_CODE (candidates->fn) == FUNCTION_DECL))
|
||||
return cp_build_function_call_vec (candidates->fn, args, complain);
|
||||
|
||||
// Otherwise, emit notes for non-viable candidates.
|
||||
if (TREE_CODE (fn) == TEMPLATE_ID_EXPR)
|
||||
fn = TREE_OPERAND (fn, 0);
|
||||
print_error_for_call_failure (fn, *args, candidates);
|
||||
|
@ -4061,7 +4104,26 @@ build_new_function_call (tree fn, vec<tree, va_gc> **args, bool koenig_p,
|
|||
through flags so that later we can use it to decide whether to warn
|
||||
about peculiar null pointer conversion. */
|
||||
if (TREE_CODE (fn) == TEMPLATE_ID_EXPR)
|
||||
flags |= LOOKUP_EXPLICIT_TMPL_ARGS;
|
||||
{
|
||||
/* If overload resolution selects a specialization of a
|
||||
function concept for non-dependent template arguments,
|
||||
the expression is true if the constraints are satisfied
|
||||
and false otherwise.
|
||||
|
||||
NOTE: This is an extension of Concepts Lite TS that
|
||||
allows constraints to be used in expressions. */
|
||||
if (flag_concepts && !processing_template_decl)
|
||||
{
|
||||
tree tmpl = DECL_TI_TEMPLATE (cand->fn);
|
||||
tree targs = DECL_TI_ARGS (cand->fn);
|
||||
tree decl = DECL_TEMPLATE_RESULT (tmpl);
|
||||
if (DECL_DECLARED_CONCEPT_P (decl))
|
||||
return evaluate_function_concept (decl, targs);
|
||||
}
|
||||
|
||||
flags |= LOOKUP_EXPLICIT_TMPL_ARGS;
|
||||
}
|
||||
|
||||
result = build_over_call (cand, flags, complain);
|
||||
}
|
||||
|
||||
|
@ -9095,6 +9157,15 @@ joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn,
|
|||
return winner;
|
||||
}
|
||||
|
||||
// C++ Concepts
|
||||
// or, if not that, F1 is more constrained than F2.
|
||||
if (flag_concepts)
|
||||
{
|
||||
winner = more_constrained (cand1->fn, cand2->fn);
|
||||
if (winner)
|
||||
return winner;
|
||||
}
|
||||
|
||||
/* Check whether we can discard a builtin candidate, either because we
|
||||
have two identical ones or matching builtin and non-builtin candidates.
|
||||
|
||||
|
|
|
@ -1138,7 +1138,8 @@ add_method (tree type, tree method, tree using_decl)
|
|||
if (compparms (parms1, parms2)
|
||||
&& (!DECL_CONV_FN_P (fn)
|
||||
|| same_type_p (TREE_TYPE (fn_type),
|
||||
TREE_TYPE (method_type))))
|
||||
TREE_TYPE (method_type)))
|
||||
&& equivalently_constrained (fn, method))
|
||||
{
|
||||
/* For function versions, their parms and types match
|
||||
but they are not duplicates. Record function versions
|
||||
|
@ -4602,6 +4603,14 @@ build_clone (tree fn, tree name)
|
|||
TREE_TYPE (clone) = TREE_TYPE (result);
|
||||
return clone;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Clone constraints.
|
||||
if (flag_concepts)
|
||||
if (tree ci = get_constraints (fn))
|
||||
set_constraints (clone, copy_node (ci));
|
||||
}
|
||||
|
||||
|
||||
SET_DECL_ASSEMBLER_NAME (clone, NULL_TREE);
|
||||
DECL_CLONED_FUNCTION (clone) = fn;
|
||||
|
@ -7281,15 +7290,17 @@ pop_class_stack (void)
|
|||
}
|
||||
|
||||
/* Returns 1 if the class type currently being defined is either T or
|
||||
a nested type of T. */
|
||||
a nested type of T. Returns the type from the current_class_stack,
|
||||
which might be equivalent to but not equal to T in case of
|
||||
constrained partial specializations. */
|
||||
|
||||
bool
|
||||
tree
|
||||
currently_open_class (tree t)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!CLASS_TYPE_P (t))
|
||||
return false;
|
||||
return NULL_TREE;
|
||||
|
||||
t = TYPE_MAIN_VARIANT (t);
|
||||
|
||||
|
@ -7309,9 +7320,9 @@ currently_open_class (tree t)
|
|||
if (!c)
|
||||
continue;
|
||||
if (same_type_p (c, t))
|
||||
return true;
|
||||
return c;
|
||||
}
|
||||
return false;
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
/* If either current_class_type or one of its enclosing classes are derived
|
||||
|
@ -7661,6 +7672,12 @@ resolve_address_of_overloaded_function (tree target_type,
|
|||
/* Instantiation failed. */
|
||||
continue;
|
||||
|
||||
/* Constraints must be satisfied. This is done before
|
||||
return type deduction since that instantiates the
|
||||
function. */
|
||||
if (flag_concepts && !constraints_satisfied_p (instantiation))
|
||||
continue;
|
||||
|
||||
/* And now force instantiation to do return type deduction. */
|
||||
if (undeduced_auto_decl (instantiation))
|
||||
{
|
||||
|
|
|
@ -3525,6 +3525,25 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
|
|||
non_constant_p, overflow_p, jump_target);
|
||||
break;
|
||||
|
||||
case REQUIRES_EXPR:
|
||||
/* It's possible to get a requires-expression in a constant
|
||||
expression. For example:
|
||||
|
||||
template<typename T> concept bool C() {
|
||||
return requires (T t) { t; };
|
||||
}
|
||||
|
||||
template<typename T> requires !C<T>() void f(T);
|
||||
|
||||
Normalization leaves f with the associated constraint
|
||||
'!requires (T t) { ... }' which is not transformed into
|
||||
a constraint. */
|
||||
if (!processing_template_decl)
|
||||
return evaluate_constraint_expression (t, NULL_TREE);
|
||||
else
|
||||
*non_constant_p = true;
|
||||
return t;
|
||||
|
||||
default:
|
||||
if (STATEMENT_CODE_P (TREE_CODE (t)))
|
||||
{
|
||||
|
@ -3897,6 +3916,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict,
|
|||
case PLACEHOLDER_EXPR:
|
||||
case BREAK_STMT:
|
||||
case CONTINUE_STMT:
|
||||
case REQUIRES_EXPR:
|
||||
return true;
|
||||
|
||||
case AGGR_INIT_EXPR:
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -100,6 +100,8 @@ cp_tree_size (enum tree_code code)
|
|||
|
||||
case TEMPLATE_INFO: return sizeof (struct tree_template_info);
|
||||
|
||||
case CONSTRAINT_INFO: return sizeof (struct tree_constraint_info);
|
||||
|
||||
case USERDEF_LITERAL: return sizeof (struct tree_userdef_literal);
|
||||
|
||||
case TEMPLATE_DECL: return sizeof (struct tree_template_decl);
|
||||
|
@ -240,6 +242,7 @@ cp_common_init_ts (void)
|
|||
{
|
||||
MARK_TS_DECL_NON_COMMON (USING_DECL);
|
||||
MARK_TS_DECL_COMMON (TEMPLATE_DECL);
|
||||
MARK_TS_DECL_COMMON (WILDCARD_DECL);
|
||||
|
||||
MARK_TS_COMMON (TEMPLATE_TEMPLATE_PARM);
|
||||
MARK_TS_COMMON (TEMPLATE_TYPE_PARM);
|
||||
|
@ -311,6 +314,7 @@ cp_common_init_ts (void)
|
|||
MARK_TS_TYPED (LAMBDA_EXPR);
|
||||
MARK_TS_TYPED (CTOR_INITIALIZER);
|
||||
MARK_TS_TYPED (ARRAY_NOTATION_REF);
|
||||
MARK_TS_TYPED (REQUIRES_EXPR);
|
||||
}
|
||||
|
||||
#include "gt-cp-cp-objcp-common.h"
|
||||
|
|
|
@ -475,6 +475,94 @@ DEFTREECODE (BASES, "bases", tcc_type, 0)
|
|||
instantiation time. */
|
||||
DEFTREECODE (TEMPLATE_INFO, "template_info", tcc_exceptional, 0)
|
||||
|
||||
/* Extensions for Concepts. */
|
||||
|
||||
/* Used to represent information associated with constrained declarations. */
|
||||
DEFTREECODE (CONSTRAINT_INFO, "constraint_info", tcc_exceptional, 0)
|
||||
|
||||
/* A wildcard declaration is a placeholder for a template parameter
|
||||
used to resolve constrained-type-names in concepts. During
|
||||
resolution, the matching argument is saved as the TREE_TYPE
|
||||
of the wildcard. */
|
||||
DEFTREECODE (WILDCARD_DECL, "wildcard_decl", tcc_declaration, 0)
|
||||
|
||||
/* A requires-expr is a binary expression. The first operand is
|
||||
its parameter list (possibly NULL). The second is a list of
|
||||
requirements, which are denoted by the _REQ* tree codes
|
||||
below. */
|
||||
DEFTREECODE (REQUIRES_EXPR, "requires_expr", tcc_expression, 2)
|
||||
|
||||
/* A requirement for an expression. */
|
||||
DEFTREECODE (SIMPLE_REQ, "simple_req", tcc_expression, 1)
|
||||
|
||||
/* A requirement for a type. */
|
||||
DEFTREECODE (TYPE_REQ, "type_req", tcc_expression, 1)
|
||||
|
||||
/* A requirement for an expression and its properties. The
|
||||
first operand is the expression, and the 2nd is its type.
|
||||
The accessor COMPOUND_REQ_NOEXCEPT determines whether
|
||||
the noexcept keyword was present. */
|
||||
DEFTREECODE (COMPOUND_REQ, "compound_req", tcc_expression, 2)
|
||||
|
||||
/* A requires clause within a requires expression. */
|
||||
DEFTREECODE (NESTED_REQ, "nested_req", tcc_expression, 1)
|
||||
|
||||
/* Constraints are modeled as kinds of expressions.
|
||||
The operands of a constraint can be either types or expressions.
|
||||
Unlike expressions, constraints do not have a type. */
|
||||
|
||||
/* A predicate constraint evaluates an expression E.
|
||||
|
||||
PRED_CONSTR_EXPR has the expression to be evaluated. */
|
||||
DEFTREECODE (PRED_CONSTR, "pred_constr", tcc_expression, 1)
|
||||
|
||||
/* An expression constraint determines the validity of a expression E.
|
||||
|
||||
EXPR_CONST_EXPR has the expression being validated. */
|
||||
DEFTREECODE (EXPR_CONSTR, "expr_constr", tcc_expression, 1)
|
||||
|
||||
/* A type constraint determines the validity of a type T. Note that
|
||||
|
||||
TYPE_CONST_TYPE has the type being validated */
|
||||
DEFTREECODE (TYPE_CONSTR, "type_constr", tcc_expression, 1)
|
||||
|
||||
/* An implicit conversion constraint determines if an expression
|
||||
E is implicitly convertible to a type T. Note that T may
|
||||
be dependent but does not contain any placeholders.
|
||||
|
||||
ICONV_CONSTR_EXPR has the expression E.
|
||||
ICONV_CONSTR_TYPE has the type T.
|
||||
*/
|
||||
DEFTREECODE (ICONV_CONSTR, "iconv_constr", tcc_expression, 2)
|
||||
|
||||
/* An argument deduction constraint determines if the type of an
|
||||
expression E can be deduced from a type pattern T. Note that
|
||||
T must contain at least one place holder.
|
||||
|
||||
DEDUCT_CONSTR_EXPR has the expression E
|
||||
DEDUCT_CONSTR_PATTERN has the type patter T.
|
||||
DEDUCT_CONSTR_PLACEHOLDERS has the list of placeholder nodes in T. */
|
||||
DEFTREECODE (DEDUCT_CONSTR, "deduct_constr", tcc_expression, 3)
|
||||
|
||||
/* An exception constraint determines if, for an expression E,
|
||||
noexcept(E) is true.
|
||||
|
||||
EXCEPT_CONSTR_EXPR has the expression E. */
|
||||
DEFTREECODE (EXCEPT_CONSTR, "except_constr", tcc_expression, 1)
|
||||
|
||||
/* A parameterized constraint declares constraint variables, which
|
||||
are used in expression, type, and exception constraints.
|
||||
|
||||
PARM_CONSTR_PARMS has a TREE_LIST of parameter declarations.
|
||||
PARM_CONSTR_OPERAND has the nested constraint. */
|
||||
DEFTREECODE (PARM_CONSTR, "parm_constr", tcc_expression, 2)
|
||||
|
||||
/* The conjunction and disjunction of two constraints, respectively.
|
||||
Operands are accessed using TREE_OPERAND. */
|
||||
DEFTREECODE (CONJ_CONSTR, "conj_constr", tcc_expression, 2)
|
||||
DEFTREECODE (DISJ_CONSTR, "disj_constr", tcc_expression, 2)
|
||||
|
||||
|
||||
/*
|
||||
Local variables:
|
||||
mode:c
|
||||
|
|
317
gcc/cp/cp-tree.h
317
gcc/cp/cp-tree.h
|
@ -77,6 +77,8 @@ c-common.h, not after.
|
|||
PACK_EXPANSION_LOCAL_P (in *_PACK_EXPANSION)
|
||||
TINFO_HAS_ACCESS_ERRORS (in TEMPLATE_INFO)
|
||||
SIZEOF_EXPR_TYPE_P (in SIZEOF_EXPR)
|
||||
COMPOUND_REQ_NOEXCEPT_P (in COMPOUND_REQ)
|
||||
WILDCARD_PACK_P (in WILDCARD_DECL)
|
||||
BLOCK_OUTER_CURLY_BRACE_P (in BLOCK)
|
||||
1: IDENTIFIER_VIRTUAL_P (in IDENTIFIER_NODE)
|
||||
TI_PENDING_TEMPLATE_FLAG.
|
||||
|
@ -154,6 +156,7 @@ c-common.h, not after.
|
|||
LABEL_DECL_CONTINUE (in LABEL_DECL)
|
||||
2: DECL_THIS_EXTERN (in VAR_DECL or FUNCTION_DECL).
|
||||
DECL_IMPLICIT_TYPEDEF_P (in a TYPE_DECL)
|
||||
DECL_CONSTRAINT_VAR_P (in a PARM_DECL)
|
||||
TEMPLATE_DECL_COMPLEX_ALIAS_P (in TEMPLATE_DECL)
|
||||
DECL_INSTANTIATING_NSDMI_P (in a FIELD_DECL)
|
||||
3: DECL_IN_AGGR_P.
|
||||
|
@ -660,6 +663,7 @@ typedef enum cp_trait_kind
|
|||
CPTK_IS_LITERAL_TYPE,
|
||||
CPTK_IS_POD,
|
||||
CPTK_IS_POLYMORPHIC,
|
||||
CPTK_IS_SAME_AS,
|
||||
CPTK_IS_STD_LAYOUT,
|
||||
CPTK_IS_TRIVIAL,
|
||||
CPTK_IS_TRIVIALLY_ASSIGNABLE,
|
||||
|
@ -812,6 +816,154 @@ struct GTY(()) tree_template_info {
|
|||
vec<qualified_typedef_usage_t, va_gc> *typedefs_needing_access_checking;
|
||||
};
|
||||
|
||||
// Constraint information for a C++ declaration. Constraint information is
|
||||
// comprised of:
|
||||
//
|
||||
// - a constraint expression introduced by the template header
|
||||
// - a constraint expression introduced by a function declarator
|
||||
// - the associated constraints, which are the conjunction of those,
|
||||
// and used for declaration matching
|
||||
// - the cached normalized associated constraints which are used
|
||||
// to support satisfaction and subsumption.
|
||||
// - assumptions which is the result of decomposing the normalized
|
||||
// constraints.
|
||||
//
|
||||
// The template and declarator requirements are kept to support pretty
|
||||
// printing constrained declarations.
|
||||
struct GTY(()) tree_constraint_info {
|
||||
struct tree_base base;
|
||||
tree template_reqs;
|
||||
tree declarator_reqs;
|
||||
tree associated_constr;
|
||||
tree normalized_constr;
|
||||
tree assumptions;
|
||||
};
|
||||
|
||||
// Require that pointer P is non-null before returning.
|
||||
template<typename T>
|
||||
inline T*
|
||||
check_nonnull (T* p)
|
||||
{
|
||||
gcc_assert (p);
|
||||
return p;
|
||||
}
|
||||
|
||||
// Returns true iff T is non-null and represents constraint info.
|
||||
inline tree_constraint_info *
|
||||
check_constraint_info (tree t)
|
||||
{
|
||||
if (t && TREE_CODE (t) == CONSTRAINT_INFO)
|
||||
return (tree_constraint_info *)t;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Access the expression describing the template constraints. This may be
|
||||
// null if no constraints were introduced in the template parameter list,
|
||||
// a requirements clause after the template parameter list, or constraints
|
||||
// through a constrained-type-specifier.
|
||||
#define CI_TEMPLATE_REQS(NODE) \
|
||||
check_constraint_info (check_nonnull(NODE))->template_reqs
|
||||
|
||||
// Access the expression describing the trailing constraints. This is non-null
|
||||
// for any implicit instantiation of a constrained declaration. For a
|
||||
// templated declaration it is non-null only when a trailing requires-clause
|
||||
// was specified.
|
||||
#define CI_DECLARATOR_REQS(NODE) \
|
||||
check_constraint_info (check_nonnull(NODE))->declarator_reqs
|
||||
|
||||
// The computed associated constraint expression for a declaration.
|
||||
#define CI_ASSOCIATED_CONSTRAINTS(NODE) \
|
||||
check_constraint_info (check_nonnull(NODE))->associated_constr
|
||||
|
||||
// The normalized associated constraints.
|
||||
#define CI_NORMALIZED_CONSTRAINTS(NODE) \
|
||||
check_constraint_info (check_nonnull(NODE))->normalized_constr
|
||||
|
||||
// Get the set of assumptions associated with the constraint info node.
|
||||
#define CI_ASSUMPTIONS(NODE) \
|
||||
check_constraint_info (check_nonnull(NODE))->assumptions
|
||||
|
||||
// Access the logical constraints on the template parameters introduced
|
||||
// at a given template parameter list level indicated by NODE.
|
||||
#define TEMPLATE_PARMS_CONSTRAINTS(NODE) \
|
||||
TREE_TYPE (TREE_LIST_CHECK (NODE))
|
||||
|
||||
// Access the logical constraints on the template parameter declaration
|
||||
// indicated by NODE.
|
||||
#define TEMPLATE_PARM_CONSTRAINTS(NODE) \
|
||||
TREE_TYPE (TREE_LIST_CHECK (NODE))
|
||||
|
||||
/* Non-zero if the noexcept is present in a compound requirement. */
|
||||
#define COMPOUND_REQ_NOEXCEPT_P(NODE) \
|
||||
TREE_LANG_FLAG_0 (TREE_CHECK (NODE, COMPOUND_REQ))
|
||||
|
||||
/* The constraints on an 'auto' placeholder type, used in an argument deduction
|
||||
constraint. */
|
||||
#define PLACEHOLDER_TYPE_CONSTRAINTS(NODE) \
|
||||
DECL_SIZE_UNIT (TYPE_NAME (NODE))
|
||||
|
||||
/* The expression evaluated by the predicate constraint. */
|
||||
#define PRED_CONSTR_EXPR(NODE) \
|
||||
TREE_OPERAND (TREE_CHECK (NODE, PRED_CONSTR), 0)
|
||||
|
||||
/* The expression validated by the predicate constraint. */
|
||||
#define EXPR_CONSTR_EXPR(NODE) \
|
||||
TREE_OPERAND (TREE_CHECK (NODE, EXPR_CONSTR), 0)
|
||||
|
||||
/* The type validated by the predicate constraint. */
|
||||
#define TYPE_CONSTR_TYPE(NODE) \
|
||||
TREE_OPERAND (TREE_CHECK (NODE, TYPE_CONSTR), 0)
|
||||
|
||||
/* In an implicit conversion constraint, the source expression. */
|
||||
#define ICONV_CONSTR_EXPR(NODE) \
|
||||
TREE_OPERAND (TREE_CHECK (NODE, ICONV_CONSTR), 0)
|
||||
|
||||
/* In an implicit conversion constraint, the target type. */
|
||||
#define ICONV_CONSTR_TYPE(NODE) \
|
||||
TREE_OPERAND (TREE_CHECK (NODE, ICONV_CONSTR), 1)
|
||||
|
||||
/* In an argument deduction constraint, the source expression. */
|
||||
#define DEDUCT_CONSTR_EXPR(NODE) \
|
||||
TREE_OPERAND (TREE_CHECK (NODE, DEDUCT_CONSTR), 0)
|
||||
|
||||
/* In an argument deduction constraint, the target type pattern. */
|
||||
#define DEDUCT_CONSTR_PATTERN(NODE) \
|
||||
TREE_OPERAND (TREE_CHECK (NODE, DEDUCT_CONSTR), 1)
|
||||
|
||||
/* In an argument deduction constraint, the list of placeholder nodes. */
|
||||
#define DEDUCT_CONSTR_PLACEHOLDER(NODE) \
|
||||
TREE_OPERAND (TREE_CHECK (NODE, DEDUCT_CONSTR), 2)
|
||||
|
||||
/* The expression of an exception constraint. */
|
||||
#define EXCEPT_CONSTR_EXPR(NODE) \
|
||||
TREE_OPERAND (TREE_CHECK (NODE, EXCEPT_CONSTR), 0)
|
||||
|
||||
/* In a parameterized constraint, the local parameters. */
|
||||
#define PARM_CONSTR_PARMS(NODE) \
|
||||
TREE_OPERAND (TREE_CHECK (NODE, PARM_CONSTR), 0)
|
||||
|
||||
/* In a parameterized constraint, the operand. */
|
||||
#define PARM_CONSTR_OPERAND(NODE) \
|
||||
TREE_OPERAND (TREE_CHECK (NODE, PARM_CONSTR), 1)
|
||||
|
||||
/* Whether a PARM_DECL represents a local parameter in a
|
||||
requires-expression. */
|
||||
#define CONSTRAINT_VAR_P(NODE) \
|
||||
DECL_LANG_FLAG_2 (TREE_CHECK (NODE, PARM_DECL))
|
||||
|
||||
/* The concept constraining this constrained template-parameter. */
|
||||
#define CONSTRAINED_PARM_CONCEPT(NODE) \
|
||||
DECL_SIZE_UNIT (TYPE_DECL_CHECK (NODE))
|
||||
/* Any extra template arguments specified for a constrained
|
||||
template-parameter. */
|
||||
#define CONSTRAINED_PARM_EXTRA_ARGS(NODE) \
|
||||
DECL_SIZE (TYPE_DECL_CHECK (NODE))
|
||||
/* The first template parameter of CONSTRAINED_PARM_CONCEPT to be used as a
|
||||
prototype for the constrained parameter in finish_shorthand_constraint,
|
||||
attached for convenience. */
|
||||
#define CONSTRAINED_PARM_PROTOTYPE(NODE) \
|
||||
DECL_INITIAL (TYPE_DECL_CHECK (NODE))
|
||||
|
||||
enum cp_tree_node_structure_enum {
|
||||
TS_CP_GENERIC,
|
||||
TS_CP_IDENTIFIER,
|
||||
|
@ -829,6 +981,7 @@ enum cp_tree_node_structure_enum {
|
|||
TS_CP_TRAIT_EXPR,
|
||||
TS_CP_LAMBDA_EXPR,
|
||||
TS_CP_TEMPLATE_INFO,
|
||||
TS_CP_CONSTRAINT_INFO,
|
||||
TS_CP_USERDEF_LITERAL,
|
||||
LAST_TS_CP_ENUM
|
||||
};
|
||||
|
@ -856,6 +1009,8 @@ union GTY((desc ("cp_tree_node_structure (&%h)"),
|
|||
lambda_expression;
|
||||
struct tree_template_info GTY ((tag ("TS_CP_TEMPLATE_INFO")))
|
||||
template_info;
|
||||
struct tree_constraint_info GTY ((tag ("TS_CP_CONSTRAINT_INFO")))
|
||||
constraint_info;
|
||||
struct tree_userdef_literal GTY ((tag ("TS_CP_USERDEF_LITERAL")))
|
||||
userdef_literal;
|
||||
};
|
||||
|
@ -2021,7 +2176,8 @@ struct GTY(()) lang_decl_base {
|
|||
unsigned template_conv_p : 1; /* var or template */
|
||||
unsigned odr_used : 1; /* var or fn */
|
||||
unsigned u2sel : 1;
|
||||
/* 1 spare bit */
|
||||
unsigned concept_p : 1; /* applies to vars and functions */
|
||||
/* 0 spare bits */
|
||||
};
|
||||
|
||||
/* True for DECL codes which have template info and access. */
|
||||
|
@ -2569,6 +2725,12 @@ struct GTY(()) lang_decl {
|
|||
#define DECL_DECLARED_CONSTEXPR_P(DECL) \
|
||||
DECL_LANG_FLAG_8 (VAR_OR_FUNCTION_DECL_CHECK (STRIP_TEMPLATE (DECL)))
|
||||
|
||||
// True if NODE was declared as 'concept'. The flag implies that the
|
||||
// declaration is constexpr, that the declaration cannot be specialized or
|
||||
// refined, and that the result type must be convertible to bool.
|
||||
#define DECL_DECLARED_CONCEPT_P(NODE) \
|
||||
(DECL_LANG_SPECIFIC (NODE)->u.base.concept_p)
|
||||
|
||||
/* Nonzero if this DECL is the __PRETTY_FUNCTION__ variable in a
|
||||
template function. */
|
||||
#define DECL_PRETTY_FUNCTION_P(NODE) \
|
||||
|
@ -3036,6 +3198,9 @@ extern void decl_shadowed_for_var_insert (tree, tree);
|
|||
/* True iff this pack expansion is within a function context. */
|
||||
#define PACK_EXPANSION_LOCAL_P(NODE) TREE_LANG_FLAG_0 (NODE)
|
||||
|
||||
/* True iff the wildcard can match a template parameter pack. */
|
||||
#define WILDCARD_PACK_P(NODE) TREE_LANG_FLAG_0 (NODE)
|
||||
|
||||
/* Determine if this is an argument pack. */
|
||||
#define ARGUMENT_PACK_P(NODE) \
|
||||
(TREE_CODE (NODE) == TYPE_ARGUMENT_PACK \
|
||||
|
@ -4504,6 +4669,15 @@ extern int comparing_specializations;
|
|||
|
||||
extern int cp_unevaluated_operand;
|
||||
|
||||
/* RAII class used to inhibit the evaluation of operands during parsing
|
||||
and template instantiation. Evaluation warnings are also inhibited. */
|
||||
|
||||
struct cp_unevaluated
|
||||
{
|
||||
cp_unevaluated ();
|
||||
~cp_unevaluated ();
|
||||
};
|
||||
|
||||
/* in pt.c */
|
||||
|
||||
/* These values are used for the `STRICT' parameter to type_unification and
|
||||
|
@ -4516,6 +4690,17 @@ typedef enum unification_kind_t {
|
|||
DEDUCE_EXACT
|
||||
} unification_kind_t;
|
||||
|
||||
// An RAII class used to create a new pointer map for local
|
||||
// specializations. When the stack goes out of scope, the
|
||||
// previous pointer map is restored.
|
||||
struct local_specialization_stack
|
||||
{
|
||||
local_specialization_stack ();
|
||||
~local_specialization_stack ();
|
||||
|
||||
hash_map<tree, tree> *saved;
|
||||
};
|
||||
|
||||
/* in class.c */
|
||||
|
||||
extern int current_class_depth;
|
||||
|
@ -4810,6 +4995,17 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, TYPENAME_FLAG };
|
|||
#define TEMPLATE_TYPE_PARAMETER_PACK(NODE) \
|
||||
(TEMPLATE_PARM_PARAMETER_PACK (TEMPLATE_TYPE_PARM_INDEX (NODE)))
|
||||
|
||||
/* Contexts in which auto deduction occurs. These flags are
|
||||
used to control diagnostics in do_auto_deduction. */
|
||||
|
||||
enum auto_deduction_context
|
||||
{
|
||||
adc_unspecified, /* Not given */
|
||||
adc_variable_type, /* Variable initializer deduction */
|
||||
adc_return_type, /* Return type deduction */
|
||||
adc_requirement /* Argument dedution constraint */
|
||||
};
|
||||
|
||||
/* True iff this TEMPLATE_TYPE_PARM represents decltype(auto). */
|
||||
#define AUTO_IS_DECLTYPE(NODE) \
|
||||
(TYPE_LANG_FLAG_5 (TEMPLATE_TYPE_PARM_CHECK (NODE)))
|
||||
|
@ -4963,6 +5159,7 @@ typedef enum cp_decl_spec {
|
|||
ds_std_attribute,
|
||||
ds_storage_class,
|
||||
ds_long_long,
|
||||
ds_concept,
|
||||
ds_last /* This enumerator must always be the last one. */
|
||||
} cp_decl_spec;
|
||||
|
||||
|
@ -5092,6 +5289,8 @@ struct cp_declarator {
|
|||
tree exception_specification;
|
||||
/* The late-specified return type, if any. */
|
||||
tree late_return_type;
|
||||
/* The trailing requires-clause, if any. */
|
||||
tree requires_clause;
|
||||
} function;
|
||||
/* For arrays. */
|
||||
struct {
|
||||
|
@ -5157,7 +5356,7 @@ class_of_this_parm (const_tree fntype)
|
|||
return TREE_TYPE (type_of_this_parm (fntype));
|
||||
}
|
||||
|
||||
/* True if T designates a variable template declaration. */
|
||||
/* True iff T is a variable template declaration. */
|
||||
inline bool
|
||||
variable_template_p (tree t)
|
||||
{
|
||||
|
@ -5170,6 +5369,30 @@ variable_template_p (tree t)
|
|||
return false;
|
||||
}
|
||||
|
||||
/* True iff T is a variable concept definition. That is, T is
|
||||
a variable template declared with the concept specifier. */
|
||||
inline bool
|
||||
variable_concept_p (tree t)
|
||||
{
|
||||
if (TREE_CODE (t) != TEMPLATE_DECL)
|
||||
return false;
|
||||
if (tree r = DECL_TEMPLATE_RESULT (t))
|
||||
return VAR_P (r) && DECL_DECLARED_CONCEPT_P (r);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* True iff T is a concept definition. That is, T is a variable or function
|
||||
template declared with the concept specifier. */
|
||||
inline bool
|
||||
concept_template_p (tree t)
|
||||
{
|
||||
if (TREE_CODE (t) != TEMPLATE_DECL)
|
||||
return false;
|
||||
if (tree r = DECL_TEMPLATE_RESULT (t))
|
||||
return VAR_OR_FUNCTION_DECL_P (r) && DECL_DECLARED_CONCEPT_P (r);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* A parameter list indicating for a function with no parameters,
|
||||
e.g "int f(void)". */
|
||||
extern cp_parameter_declarator *no_parameters;
|
||||
|
@ -5266,7 +5489,7 @@ extern tree get_vtable_decl (tree, int);
|
|||
extern void resort_type_method_vec (void *, void *,
|
||||
gt_pointer_operator, void *);
|
||||
extern bool add_method (tree, tree, tree);
|
||||
extern bool currently_open_class (tree);
|
||||
extern tree currently_open_class (tree);
|
||||
extern tree currently_open_derived_class (tree);
|
||||
extern tree outermost_open_class (void);
|
||||
extern tree current_nonlambda_class_type (void);
|
||||
|
@ -5402,6 +5625,7 @@ extern tree build_ptrmemfunc_type (tree);
|
|||
extern tree build_ptrmem_type (tree, tree);
|
||||
/* the grokdeclarator prototype is in decl.h */
|
||||
extern tree build_this_parm (tree, cp_cv_quals);
|
||||
extern tree grokparms (tree, tree *);
|
||||
extern int copy_fn_p (const_tree);
|
||||
extern bool move_fn_p (const_tree);
|
||||
extern bool move_signature_fn_p (const_tree);
|
||||
|
@ -5679,7 +5903,10 @@ extern int num_template_headers_for_class (tree);
|
|||
extern void check_template_variable (tree);
|
||||
extern tree make_auto (void);
|
||||
extern tree make_decltype_auto (void);
|
||||
extern tree do_auto_deduction (tree, tree, tree);
|
||||
extern tree do_auto_deduction (tree, tree, tree);
|
||||
extern tree do_auto_deduction (tree, tree, tree,
|
||||
tsubst_flags_t,
|
||||
auto_deduction_context);
|
||||
extern tree type_uses_auto (tree);
|
||||
extern tree type_uses_auto_or_concept (tree);
|
||||
extern void append_type_to_template_for_access_check (tree, tree, tree,
|
||||
|
@ -5691,13 +5918,14 @@ extern bool is_auto_or_concept (const_tree);
|
|||
extern tree process_template_parm (tree, location_t, tree,
|
||||
bool, bool);
|
||||
extern tree end_template_parm_list (tree);
|
||||
extern void end_template_parm_list (void);
|
||||
extern void end_template_decl (void);
|
||||
extern tree maybe_update_decl_type (tree, tree);
|
||||
extern bool check_default_tmpl_args (tree, tree, bool, bool, int);
|
||||
extern tree push_template_decl (tree);
|
||||
extern tree push_template_decl_real (tree, bool);
|
||||
extern tree add_inherited_template_parms (tree, tree);
|
||||
extern bool redeclare_class_template (tree, tree);
|
||||
extern bool redeclare_class_template (tree, tree, tree);
|
||||
extern tree lookup_template_class (tree, tree, tree, tree,
|
||||
int, tsubst_flags_t);
|
||||
extern tree lookup_template_function (tree, tree);
|
||||
|
@ -5742,6 +5970,9 @@ extern tree tsubst_default_argument (tree, tree, tree,
|
|||
extern tree tsubst (tree, tree, tsubst_flags_t, tree);
|
||||
extern tree tsubst_copy_and_build (tree, tree, tsubst_flags_t,
|
||||
tree, bool, bool);
|
||||
extern tree tsubst_expr (tree, tree, tsubst_flags_t,
|
||||
tree, bool);
|
||||
extern tree tsubst_pack_expansion (tree, tree, tsubst_flags_t, tree);
|
||||
extern tree most_general_template (tree);
|
||||
extern tree get_mostly_instantiated_function_type (tree);
|
||||
extern bool problematic_instantiation_changed (void);
|
||||
|
@ -5792,6 +6023,12 @@ extern tree get_template_argument_pack_elems (const_tree);
|
|||
extern tree get_function_template_decl (const_tree);
|
||||
extern tree resolve_nondeduced_context (tree);
|
||||
extern hashval_t iterative_hash_template_arg (tree arg, hashval_t val);
|
||||
extern tree coerce_template_parms (tree, tree, tree);
|
||||
extern tree coerce_template_parms (tree, tree, tree, tsubst_flags_t);
|
||||
extern void register_local_specialization (tree, tree);
|
||||
extern tree retrieve_local_specialization (tree);
|
||||
extern tree extract_fnparm_pack (tree, tree *);
|
||||
extern tree template_parm_to_arg (tree);
|
||||
|
||||
/* in repo.c */
|
||||
extern void init_repo (void);
|
||||
|
@ -5882,6 +6119,22 @@ extern bool perform_access_checks (vec<deferred_access_check, va_gc> *,
|
|||
extern bool perform_deferred_access_checks (tsubst_flags_t);
|
||||
extern bool perform_or_defer_access_check (tree, tree, tree,
|
||||
tsubst_flags_t);
|
||||
|
||||
/* RAII sentinel to ensures that deferred access checks are popped before
|
||||
a function returns. */
|
||||
|
||||
struct deferring_access_check_sentinel
|
||||
{
|
||||
deferring_access_check_sentinel ()
|
||||
{
|
||||
push_deferring_access_checks (dk_deferred);
|
||||
}
|
||||
~deferring_access_check_sentinel ()
|
||||
{
|
||||
pop_deferring_access_checks ();
|
||||
}
|
||||
};
|
||||
|
||||
extern int stmts_are_full_exprs_p (void);
|
||||
extern void init_cp_semantics (void);
|
||||
extern tree do_poplevel (tree);
|
||||
|
@ -6392,6 +6645,60 @@ extern bool cxx_omp_privatize_by_reference (const_tree);
|
|||
extern void suggest_alternatives_for (location_t, tree);
|
||||
extern tree strip_using_decl (tree);
|
||||
|
||||
/* in constraint.cc */
|
||||
extern void init_constraint_processing ();
|
||||
extern bool constraint_p (tree);
|
||||
extern tree make_predicate_constraint (tree);
|
||||
extern tree conjoin_constraints (tree, tree);
|
||||
extern tree conjoin_constraints (tree);
|
||||
extern bool valid_constraints_p (tree);
|
||||
extern tree get_constraints (tree);
|
||||
extern void set_constraints (tree, tree);
|
||||
extern void remove_constraints (tree);
|
||||
extern tree current_template_constraints (void);
|
||||
extern tree associate_classtype_constraints (tree);
|
||||
extern tree build_constraints (tree, tree);
|
||||
extern tree get_shorthand_constraints (tree);
|
||||
extern tree build_concept_check (tree, tree, tree = NULL_TREE);
|
||||
extern tree build_constrained_parameter (tree, tree, tree = NULL_TREE);
|
||||
extern tree make_constrained_auto (tree, tree);
|
||||
extern bool deduce_constrained_parameter (tree, tree&, tree&);
|
||||
extern tree resolve_constraint_check (tree);
|
||||
extern tree check_function_concept (tree);
|
||||
extern tree finish_template_introduction (tree, tree);
|
||||
extern bool valid_requirements_p (tree);
|
||||
extern tree finish_concept_name (tree);
|
||||
extern tree finish_shorthand_constraint (tree, tree);
|
||||
extern tree finish_requires_expr (tree, tree);
|
||||
extern tree finish_simple_requirement (tree);
|
||||
extern tree finish_type_requirement (tree);
|
||||
extern tree finish_compound_requirement (tree, tree, bool);
|
||||
extern tree finish_nested_requirement (tree);
|
||||
extern void check_constrained_friend (tree, tree);
|
||||
extern tree tsubst_requires_expr (tree, tree, tsubst_flags_t, tree);
|
||||
extern tree tsubst_constraint (tree, tree, tsubst_flags_t, tree);
|
||||
extern tree tsubst_constraint_info (tree, tree, tsubst_flags_t, tree);
|
||||
extern bool function_concept_check_p (tree);
|
||||
|
||||
extern tree evaluate_constraints (tree, tree);
|
||||
extern tree evaluate_function_concept (tree, tree);
|
||||
extern tree evaluate_variable_concept (tree, tree);
|
||||
extern tree evaluate_constraint_expression (tree, tree);
|
||||
extern bool constraints_satisfied_p (tree);
|
||||
extern bool constraints_satisfied_p (tree, tree);
|
||||
|
||||
extern bool equivalent_constraints (tree, tree);
|
||||
extern bool equivalently_constrained (tree, tree);
|
||||
extern bool subsumes_constraints (tree, tree);
|
||||
extern int more_constrained (tree, tree);
|
||||
|
||||
extern void diagnose_constraints (location_t, tree, tree);
|
||||
|
||||
/* in logic.cc */
|
||||
extern tree decompose_assumptions (tree);
|
||||
extern tree decompose_conclusions (tree);
|
||||
extern bool subsumes (tree, tree);
|
||||
|
||||
/* in vtable-class-hierarchy.c */
|
||||
extern void vtv_compute_class_hierarchy_transitive_closure (void);
|
||||
extern void vtv_generate_init_routine (void);
|
||||
|
|
|
@ -451,6 +451,10 @@ cxx_pretty_printer::primary_expression (tree t)
|
|||
pp_cxx_offsetof_expression (this, t);
|
||||
break;
|
||||
|
||||
case REQUIRES_EXPR:
|
||||
pp_cxx_requires_expr (this, t);
|
||||
break;
|
||||
|
||||
default:
|
||||
c_pretty_printer::primary_expression (t);
|
||||
break;
|
||||
|
@ -1064,6 +1068,7 @@ cxx_pretty_printer::expression (tree t)
|
|||
case TEMPLATE_PARM_INDEX:
|
||||
case TEMPLATE_TEMPLATE_PARM:
|
||||
case STMT_EXPR:
|
||||
case REQUIRES_EXPR:
|
||||
primary_expression (t);
|
||||
break;
|
||||
|
||||
|
@ -1158,6 +1163,22 @@ cxx_pretty_printer::expression (tree t)
|
|||
pp_cxx_ws_string (this, "<lambda>");
|
||||
break;
|
||||
|
||||
case TRAIT_EXPR:
|
||||
pp_cxx_trait_expression (this, t);
|
||||
break;
|
||||
|
||||
case PRED_CONSTR:
|
||||
case EXPR_CONSTR:
|
||||
case TYPE_CONSTR:
|
||||
case ICONV_CONSTR:
|
||||
case DEDUCT_CONSTR:
|
||||
case EXCEPT_CONSTR:
|
||||
case PARM_CONSTR:
|
||||
case CONJ_CONSTR:
|
||||
case DISJ_CONSTR:
|
||||
pp_cxx_constraint (this, t);
|
||||
break;
|
||||
|
||||
case PAREN_EXPR:
|
||||
pp_cxx_left_paren (this);
|
||||
expression (TREE_OPERAND (t, 0));
|
||||
|
@ -1423,10 +1444,26 @@ pp_cxx_parameter_declaration (cxx_pretty_printer *pp, tree t)
|
|||
static void
|
||||
pp_cxx_parameter_declaration_clause (cxx_pretty_printer *pp, tree t)
|
||||
{
|
||||
tree args = TYPE_P (t) ? NULL : FUNCTION_FIRST_USER_PARM (t);
|
||||
tree types =
|
||||
TYPE_P (t) ? TYPE_ARG_TYPES (t) : FUNCTION_FIRST_USER_PARMTYPE (t);
|
||||
const bool abstract = args == NULL || pp->flags & pp_c_flag_abstract;
|
||||
tree args;
|
||||
tree types;
|
||||
bool abstract;
|
||||
|
||||
// For a requires clause or the explicit printing of a parameter list
|
||||
// we expect T to be a chain of PARM_DECLs. Otherwise, the list of
|
||||
// args and types are taken from the function decl T.
|
||||
if (TREE_CODE (t) == PARM_DECL)
|
||||
{
|
||||
args = t;
|
||||
types = t;
|
||||
abstract = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
bool type_p = TYPE_P (t);
|
||||
args = type_p ? NULL : FUNCTION_FIRST_USER_PARM (t);
|
||||
types = type_p ? TYPE_ARG_TYPES (t) : FUNCTION_FIRST_USER_PARMTYPE (t);
|
||||
abstract = args == NULL || pp->flags & pp_c_flag_abstract;
|
||||
}
|
||||
bool first = true;
|
||||
|
||||
/* Skip artificial parameter for nonstatic member functions. */
|
||||
|
@ -1574,6 +1611,12 @@ void
|
|||
cxx_pretty_printer::declarator (tree t)
|
||||
{
|
||||
direct_declarator (t);
|
||||
|
||||
// Print a requires clause.
|
||||
if (flag_concepts)
|
||||
if (tree ci = get_constraints (t))
|
||||
if (tree reqs = CI_DECLARATOR_REQS (ci))
|
||||
pp_cxx_requires_clause (this, reqs);
|
||||
}
|
||||
|
||||
/* ctor-initializer:
|
||||
|
@ -2154,7 +2197,13 @@ pp_cxx_canonical_template_parameter (cxx_pretty_printer *pp, tree parm)
|
|||
|
||||
/*
|
||||
template-declaration:
|
||||
export(opt) template < template-parameter-list > declaration */
|
||||
export(opt) template < template-parameter-list > declaration
|
||||
|
||||
Concept extensions:
|
||||
|
||||
template-declaration:
|
||||
export(opt) template < template-parameter-list >
|
||||
requires-clause(opt) declaration */
|
||||
|
||||
static void
|
||||
pp_cxx_template_declaration (cxx_pretty_printer *pp, tree t)
|
||||
|
@ -2171,6 +2220,15 @@ pp_cxx_template_declaration (cxx_pretty_printer *pp, tree t)
|
|||
pp_cxx_end_template_argument_list (pp);
|
||||
pp_newline_and_indent (pp, 3);
|
||||
}
|
||||
|
||||
if (flag_concepts)
|
||||
if (tree ci = get_constraints (t))
|
||||
if (tree reqs = CI_TEMPLATE_REQS (ci))
|
||||
{
|
||||
pp_cxx_requires_clause (pp, reqs);
|
||||
pp_newline_and_indent (pp, 6);
|
||||
}
|
||||
|
||||
if (TREE_CODE (t) == FUNCTION_DECL && DECL_SAVED_TREE (t))
|
||||
pp_cxx_function_definition (pp, t);
|
||||
else
|
||||
|
@ -2387,6 +2445,9 @@ pp_cxx_trait_expression (cxx_pretty_printer *pp, tree t)
|
|||
case CPTK_IS_POLYMORPHIC:
|
||||
pp_cxx_ws_string (pp, "__is_polymorphic");
|
||||
break;
|
||||
case CPTK_IS_SAME_AS:
|
||||
pp_cxx_ws_string (pp, "__is_same_as");
|
||||
break;
|
||||
case CPTK_IS_STD_LAYOUT:
|
||||
pp_cxx_ws_string (pp, "__is_std_layout");
|
||||
break;
|
||||
|
@ -2416,7 +2477,7 @@ pp_cxx_trait_expression (cxx_pretty_printer *pp, tree t)
|
|||
pp_cxx_left_paren (pp);
|
||||
pp->type_id (TRAIT_EXPR_TYPE1 (t));
|
||||
|
||||
if (kind == CPTK_IS_BASE_OF)
|
||||
if (kind == CPTK_IS_BASE_OF || kind == CPTK_IS_SAME_AS)
|
||||
{
|
||||
pp_cxx_separate_with (pp, ',');
|
||||
pp->type_id (TRAIT_EXPR_TYPE2 (t));
|
||||
|
@ -2424,6 +2485,272 @@ pp_cxx_trait_expression (cxx_pretty_printer *pp, tree t)
|
|||
|
||||
pp_cxx_right_paren (pp);
|
||||
}
|
||||
|
||||
// requires-clause:
|
||||
// 'requires' logical-or-expression
|
||||
void
|
||||
pp_cxx_requires_clause (cxx_pretty_printer *pp, tree t)
|
||||
{
|
||||
if (!t)
|
||||
return;
|
||||
pp->padding = pp_before;
|
||||
pp_cxx_ws_string (pp, "requires");
|
||||
pp_space (pp);
|
||||
pp->expression (t);
|
||||
}
|
||||
|
||||
/* requirement:
|
||||
simple-requirement
|
||||
compound-requirement
|
||||
type-requirement
|
||||
nested-requirement */
|
||||
static void
|
||||
pp_cxx_requirement (cxx_pretty_printer *pp, tree t)
|
||||
{
|
||||
switch (TREE_CODE (t))
|
||||
{
|
||||
case SIMPLE_REQ:
|
||||
pp_cxx_simple_requirement (pp, t);
|
||||
break;
|
||||
|
||||
case TYPE_REQ:
|
||||
pp_cxx_type_requirement (pp, t);
|
||||
break;
|
||||
|
||||
case COMPOUND_REQ:
|
||||
pp_cxx_compound_requirement (pp, t);
|
||||
break;
|
||||
|
||||
case NESTED_REQ:
|
||||
pp_cxx_nested_requirement (pp, t);
|
||||
break;
|
||||
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
}
|
||||
}
|
||||
|
||||
// requirement-list:
|
||||
// requirement
|
||||
// requirement-list ';' requirement[opt]
|
||||
//
|
||||
static void
|
||||
pp_cxx_requirement_list (cxx_pretty_printer *pp, tree t)
|
||||
{
|
||||
for (; t; t = TREE_CHAIN (t))
|
||||
pp_cxx_requirement (pp, TREE_VALUE (t));
|
||||
}
|
||||
|
||||
// requirement-body:
|
||||
// '{' requirement-list '}'
|
||||
static void
|
||||
pp_cxx_requirement_body (cxx_pretty_printer *pp, tree t)
|
||||
{
|
||||
pp_cxx_left_brace (pp);
|
||||
pp_cxx_requirement_list (pp, t);
|
||||
pp_cxx_right_brace (pp);
|
||||
}
|
||||
|
||||
// requires-expression:
|
||||
// 'requires' requirement-parameter-list requirement-body
|
||||
void
|
||||
pp_cxx_requires_expr (cxx_pretty_printer *pp, tree t)
|
||||
{
|
||||
pp_string (pp, "requires");
|
||||
if (tree parms = TREE_OPERAND (t, 0))
|
||||
{
|
||||
pp_cxx_parameter_declaration_clause (pp, parms);
|
||||
pp_cxx_whitespace (pp);
|
||||
}
|
||||
pp_cxx_requirement_body (pp, TREE_OPERAND (t, 1));
|
||||
}
|
||||
|
||||
/* simple-requirement:
|
||||
expression ';' */
|
||||
void
|
||||
pp_cxx_simple_requirement (cxx_pretty_printer *pp, tree t)
|
||||
{
|
||||
pp->expression (TREE_OPERAND (t, 0));
|
||||
pp_cxx_semicolon (pp);
|
||||
}
|
||||
|
||||
/* type-requirement:
|
||||
typename type-name ';' */
|
||||
void
|
||||
pp_cxx_type_requirement (cxx_pretty_printer *pp, tree t)
|
||||
{
|
||||
pp->type_id (TREE_OPERAND (t, 0));
|
||||
pp_cxx_semicolon (pp);
|
||||
}
|
||||
|
||||
/* compound-requirement:
|
||||
'{' expression '}' 'noexcept' [opt] trailing-return-type [opt] */
|
||||
void
|
||||
pp_cxx_compound_requirement (cxx_pretty_printer *pp, tree t)
|
||||
{
|
||||
pp_cxx_left_brace (pp);
|
||||
pp->expression (TREE_OPERAND (t, 0));
|
||||
pp_cxx_right_brace (pp);
|
||||
|
||||
if (COMPOUND_REQ_NOEXCEPT_P (t))
|
||||
pp_cxx_ws_string (pp, "noexcept");
|
||||
|
||||
if (tree type = TREE_OPERAND (t, 1))
|
||||
{
|
||||
pp_cxx_ws_string (pp, "->");
|
||||
pp->type_id (type);
|
||||
}
|
||||
}
|
||||
|
||||
/* nested requirement:
|
||||
'requires' constraint-expression */
|
||||
void
|
||||
pp_cxx_nested_requirement (cxx_pretty_printer *pp, tree t)
|
||||
{
|
||||
pp_cxx_ws_string (pp, "requires");
|
||||
pp->expression (TREE_OPERAND (t, 0));
|
||||
pp_cxx_semicolon (pp);
|
||||
}
|
||||
|
||||
void
|
||||
pp_cxx_predicate_constraint (cxx_pretty_printer *pp, tree t)
|
||||
{
|
||||
pp_string (pp, "predicate");
|
||||
pp_left_paren (pp);
|
||||
pp->expression (TREE_OPERAND (t, 0));
|
||||
pp_right_paren (pp);
|
||||
}
|
||||
|
||||
void
|
||||
pp_cxx_expression_constraint (cxx_pretty_printer *pp, tree t)
|
||||
{
|
||||
pp_string (pp, "valid_expr");
|
||||
pp_left_paren (pp);
|
||||
pp->expression (TREE_OPERAND (t, 0));
|
||||
pp_right_paren (pp);
|
||||
}
|
||||
|
||||
void
|
||||
pp_cxx_type_constraint (cxx_pretty_printer *pp, tree t)
|
||||
{
|
||||
pp_string (pp, "valid_type");
|
||||
pp_left_paren (pp);
|
||||
pp->type_id (TREE_OPERAND (t, 0));
|
||||
pp_right_paren (pp);
|
||||
}
|
||||
|
||||
void
|
||||
pp_cxx_implicit_conversion_constraint (cxx_pretty_printer *pp, tree t)
|
||||
{
|
||||
pp_string (pp, "convertible");
|
||||
pp_left_paren (pp);
|
||||
pp->expression (ICONV_CONSTR_EXPR (t));
|
||||
pp_cxx_separate_with (pp, ',');
|
||||
pp->expression (ICONV_CONSTR_TYPE (t));
|
||||
pp_right_paren (pp);
|
||||
}
|
||||
|
||||
void
|
||||
pp_cxx_argument_deduction_constraint (cxx_pretty_printer *pp, tree t)
|
||||
{
|
||||
pp_string (pp, "deducible");
|
||||
pp_left_paren (pp);
|
||||
pp->expression (DEDUCT_CONSTR_EXPR (t));
|
||||
pp_cxx_separate_with (pp, ',');
|
||||
pp->expression (DEDUCT_CONSTR_PATTERN (t));
|
||||
pp_right_paren (pp);
|
||||
}
|
||||
|
||||
void
|
||||
pp_cxx_exception_constraint (cxx_pretty_printer *pp, tree t)
|
||||
{
|
||||
pp_cxx_ws_string (pp, "noexcept");
|
||||
pp_left_paren (pp);
|
||||
pp->expression (TREE_OPERAND (t, 0));
|
||||
pp_right_paren (pp);
|
||||
}
|
||||
|
||||
void
|
||||
pp_cxx_parameterized_constraint (cxx_pretty_printer *pp, tree t)
|
||||
{
|
||||
pp_left_paren (pp);
|
||||
pp_string (pp, "forall");
|
||||
if (tree parms = PARM_CONSTR_PARMS (t))
|
||||
{
|
||||
if (parms)
|
||||
pp_cxx_parameter_declaration_clause (pp, parms);
|
||||
pp_cxx_whitespace (pp);
|
||||
}
|
||||
pp_cxx_constraint (pp, PARM_CONSTR_OPERAND (t));
|
||||
pp_right_paren (pp);
|
||||
}
|
||||
|
||||
void
|
||||
pp_cxx_conjunction (cxx_pretty_printer *pp, tree t)
|
||||
{
|
||||
pp_cxx_constraint (pp, TREE_OPERAND (t, 0));
|
||||
pp_string (pp, " and ");
|
||||
pp_cxx_constraint (pp, TREE_OPERAND (t, 1));
|
||||
}
|
||||
|
||||
void
|
||||
pp_cxx_disjunction (cxx_pretty_printer *pp, tree t)
|
||||
{
|
||||
pp_cxx_constraint (pp, TREE_OPERAND (t, 0));
|
||||
pp_string (pp, " or ");
|
||||
pp_cxx_constraint (pp, TREE_OPERAND (t, 1));
|
||||
}
|
||||
|
||||
void
|
||||
pp_cxx_constraint (cxx_pretty_printer *pp, tree t)
|
||||
{
|
||||
if (t == error_mark_node)
|
||||
return pp->expression (t);
|
||||
|
||||
switch (TREE_CODE (t))
|
||||
{
|
||||
case PRED_CONSTR:
|
||||
pp_cxx_predicate_constraint (pp, t);
|
||||
break;
|
||||
|
||||
case EXPR_CONSTR:
|
||||
pp_cxx_expression_constraint (pp, t);
|
||||
break;
|
||||
|
||||
case TYPE_CONSTR:
|
||||
pp_cxx_type_constraint (pp, t);
|
||||
break;
|
||||
|
||||
case ICONV_CONSTR:
|
||||
pp_cxx_implicit_conversion_constraint (pp, t);
|
||||
break;
|
||||
|
||||
case DEDUCT_CONSTR:
|
||||
pp_cxx_argument_deduction_constraint (pp, t);
|
||||
break;
|
||||
|
||||
case EXCEPT_CONSTR:
|
||||
pp_cxx_exception_constraint (pp, t);
|
||||
break;
|
||||
|
||||
case PARM_CONSTR:
|
||||
pp_cxx_parameterized_constraint (pp, t);
|
||||
break;
|
||||
|
||||
case CONJ_CONSTR:
|
||||
pp_cxx_conjunction (pp, t);
|
||||
break;
|
||||
|
||||
case DISJ_CONSTR:
|
||||
pp_cxx_disjunction (pp, t);
|
||||
break;
|
||||
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
typedef c_pretty_print_fn pp_fun;
|
||||
|
||||
|
|
|
@ -91,6 +91,21 @@ void pp_cxx_trait_expression (cxx_pretty_printer *, tree);
|
|||
void pp_cxx_va_arg_expression (cxx_pretty_printer *, tree);
|
||||
void pp_cxx_offsetof_expression (cxx_pretty_printer *, tree);
|
||||
void pp_cxx_userdef_literal (cxx_pretty_printer *, tree);
|
||||
|
||||
void pp_cxx_requires_clause (cxx_pretty_printer *, tree);
|
||||
void pp_cxx_requires_expr (cxx_pretty_printer *, tree);
|
||||
void pp_cxx_simple_requirement (cxx_pretty_printer *, tree);
|
||||
void pp_cxx_type_requirement (cxx_pretty_printer *, tree);
|
||||
void pp_cxx_compound_requirement (cxx_pretty_printer *, tree);
|
||||
void pp_cxx_nested_requirement (cxx_pretty_printer *, tree);
|
||||
void pp_cxx_predicate_constraint (cxx_pretty_printer *, tree);
|
||||
void pp_cxx_expression_constraint (cxx_pretty_printer *, tree);
|
||||
void pp_cxx_type_constraint (cxx_pretty_printer *, tree);
|
||||
void pp_cxx_implicit_conversion_constraint (cxx_pretty_printer *, tree);
|
||||
void pp_cxx_argument_deduction_constraint (cxx_pretty_printer *, tree);
|
||||
void pp_cxx_exception_constraint (cxx_pretty_printer *, tree);
|
||||
void pp_cxx_parameterized_constraint (cxx_pretty_printer *, tree);
|
||||
void pp_cxx_conjunction (cxx_pretty_printer *, tree);
|
||||
void pp_cxx_disjunction (cxx_pretty_printer *, tree);
|
||||
void pp_cxx_constraint (cxx_pretty_printer *, tree);
|
||||
|
||||
#endif /* GCC_CXX_PRETTY_PRINT_H */
|
||||
|
|
267
gcc/cp/decl.c
267
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;
|
||||
}
|
||||
|
|
|
@ -714,6 +714,10 @@ check_classfn (tree ctype, tree function, tree template_parms)
|
|||
!= type_memfn_rqual (TREE_TYPE (fndecl)))
|
||||
continue;
|
||||
|
||||
// Include constraints in the match.
|
||||
tree c1 = get_constraints (function);
|
||||
tree c2 = get_constraints (fndecl);
|
||||
|
||||
/* While finding a match, same types and params are not enough
|
||||
if the function is versioned. Also check version ("target")
|
||||
attributes. */
|
||||
|
@ -724,6 +728,7 @@ check_classfn (tree ctype, tree function, tree template_parms)
|
|||
&& (!is_template
|
||||
|| comp_template_parms (template_parms,
|
||||
DECL_TEMPLATE_PARMS (fndecl)))
|
||||
&& equivalent_constraints (c1, c2)
|
||||
&& (DECL_TEMPLATE_SPECIALIZATION (function)
|
||||
== DECL_TEMPLATE_SPECIALIZATION (fndecl))
|
||||
&& (!DECL_TEMPLATE_SPECIALIZATION (function)
|
||||
|
@ -5081,6 +5086,7 @@ mark_used (tree decl, tsubst_flags_t complain)
|
|||
|| (TREE_CODE (decl) == FUNCTION_DECL
|
||||
&& DECL_OMP_DECLARE_REDUCTION_P (decl))
|
||||
|| undeduced_auto_decl (decl))
|
||||
&& !DECL_DECLARED_CONCEPT_P (decl)
|
||||
&& !uses_template_parms (DECL_TI_ARGS (decl)))
|
||||
{
|
||||
/* Instantiating a function will result in garbage collection. We
|
||||
|
@ -5179,6 +5185,7 @@ mark_used (tree decl, tsubst_flags_t complain)
|
|||
}
|
||||
else if (VAR_OR_FUNCTION_DECL_P (decl)
|
||||
&& DECL_TEMPLATE_INFO (decl)
|
||||
&& !DECL_DECLARED_CONCEPT_P (decl)
|
||||
&& (!DECL_EXPLICIT_INSTANTIATION (decl)
|
||||
|| always_instantiate_p (decl)))
|
||||
/* If this is a function or variable that is an instance of some
|
||||
|
|
|
@ -1333,6 +1333,15 @@ dump_template_decl (cxx_pretty_printer *pp, tree t, int flags)
|
|||
}
|
||||
}
|
||||
|
||||
if (flag_concepts)
|
||||
if (tree ci = get_constraints (t))
|
||||
if (check_constraint_info (ci))
|
||||
if (tree reqs = CI_TEMPLATE_REQS (ci))
|
||||
{
|
||||
pp_cxx_requires_clause (pp, reqs);
|
||||
pp_cxx_whitespace (pp);
|
||||
}
|
||||
|
||||
if (DECL_CLASS_TEMPLATE_P (t))
|
||||
dump_type (pp, TREE_TYPE (t),
|
||||
((flags & ~TFF_CLASS_KEY_OR_ENUM) | TFF_TEMPLATE_NAME
|
||||
|
@ -1564,6 +1573,11 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags)
|
|||
if (show_return)
|
||||
dump_type_suffix (pp, TREE_TYPE (fntype), flags);
|
||||
|
||||
if (flag_concepts)
|
||||
if (tree ci = get_constraints (t))
|
||||
if (tree reqs = CI_DECLARATOR_REQS (ci))
|
||||
pp_cxx_requires_clause (pp, reqs);
|
||||
|
||||
dump_substitution (pp, t, template_parms, template_args, flags);
|
||||
}
|
||||
else if (template_args)
|
||||
|
@ -2689,6 +2703,38 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags)
|
|||
pp_cxx_right_paren (pp);
|
||||
break;
|
||||
|
||||
case REQUIRES_EXPR:
|
||||
pp_cxx_requires_expr (cxx_pp, t);
|
||||
break;
|
||||
|
||||
case SIMPLE_REQ:
|
||||
pp_cxx_simple_requirement (cxx_pp, t);
|
||||
break;
|
||||
|
||||
case TYPE_REQ:
|
||||
pp_cxx_type_requirement (cxx_pp, t);
|
||||
break;
|
||||
|
||||
case COMPOUND_REQ:
|
||||
pp_cxx_compound_requirement (cxx_pp, t);
|
||||
break;
|
||||
|
||||
case NESTED_REQ:
|
||||
pp_cxx_nested_requirement (cxx_pp, t);
|
||||
break;
|
||||
|
||||
case PRED_CONSTR:
|
||||
case EXPR_CONSTR:
|
||||
case TYPE_CONSTR:
|
||||
case ICONV_CONSTR:
|
||||
case DEDUCT_CONSTR:
|
||||
case EXCEPT_CONSTR:
|
||||
case PARM_CONSTR:
|
||||
case CONJ_CONSTR:
|
||||
case DISJ_CONSTR:
|
||||
pp_cxx_constraint (cxx_pp, t);
|
||||
break;
|
||||
|
||||
case PLACEHOLDER_EXPR:
|
||||
pp_string (pp, M_("*this"));
|
||||
break;
|
||||
|
|
|
@ -174,6 +174,8 @@ init_reswords (void)
|
|||
|
||||
if (cxx_dialect < cxx11)
|
||||
mask |= D_CXX11;
|
||||
if (!flag_concepts)
|
||||
mask |= D_CXX_CONCEPTS;
|
||||
if (flag_no_asm)
|
||||
mask |= D_ASM | D_EXT;
|
||||
if (flag_no_gnu_keywords)
|
||||
|
|
|
@ -0,0 +1,497 @@
|
|||
/* Derivation and subsumption rules for constraints.
|
||||
Copyright (C) 2013-2015 Free Software Foundation, Inc.
|
||||
Contributed by Andrew Sutton (andrew.n.sutton@gmail.com)
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
GCC is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3, or (at your option)
|
||||
any later version.
|
||||
|
||||
GCC is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GCC; see the file COPYING3. If not see
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "config.h"
|
||||
#include "system.h"
|
||||
#include "coretypes.h"
|
||||
#include "tm.h"
|
||||
#include "hash-set.h"
|
||||
#include "machmode.h"
|
||||
#include "vec.h"
|
||||
#include "double-int.h"
|
||||
#include "input.h"
|
||||
#include "alias.h"
|
||||
#include "symtab.h"
|
||||
#include "wide-int.h"
|
||||
#include "inchash.h"
|
||||
#include "tree.h"
|
||||
#include "stringpool.h"
|
||||
#include "attribs.h"
|
||||
#include "intl.h"
|
||||
#include "flags.h"
|
||||
#include "cp-tree.h"
|
||||
#include "c-family/c-common.h"
|
||||
#include "c-family/c-objc.h"
|
||||
#include "cp-objcp-common.h"
|
||||
#include "tree-inline.h"
|
||||
#include "decl.h"
|
||||
#include "toplev.h"
|
||||
#include "type-utils.h"
|
||||
|
||||
#include <list>
|
||||
|
||||
namespace {
|
||||
|
||||
// Helper algorithms
|
||||
|
||||
// Increment iter distance(first, last) times.
|
||||
template<typename I1, typename I2, typename I3>
|
||||
I1 next_by_distance (I1 iter, I2 first, I3 last)
|
||||
{
|
||||
for ( ; first != last; ++first, ++iter)
|
||||
;
|
||||
return iter;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------
|
||||
Proof state
|
||||
---------------------------------------------------------------------------*/
|
||||
|
||||
/* A term list is a list of atomic constraints. It is used
|
||||
to maintain the lists of assumptions and conclusions in a
|
||||
proof goal.
|
||||
|
||||
Each term list maintains an iterator that refers to the current
|
||||
term. This can be used by various tactics to support iteration
|
||||
and stateful manipulation of the list. */
|
||||
struct term_list : std::list<tree>
|
||||
{
|
||||
term_list ();
|
||||
term_list (const term_list &x);
|
||||
term_list& operator= (const term_list &x);
|
||||
|
||||
tree current_term () { return *current; }
|
||||
const_tree current_term () const { return *current; }
|
||||
|
||||
|
||||
void insert (tree t);
|
||||
tree erase ();
|
||||
|
||||
void start ();
|
||||
void next ();
|
||||
bool done() const;
|
||||
|
||||
iterator current;
|
||||
};
|
||||
|
||||
inline
|
||||
term_list::term_list ()
|
||||
: std::list<tree> (), current (end ())
|
||||
{ }
|
||||
|
||||
inline
|
||||
term_list::term_list (const term_list &x)
|
||||
: std::list<tree> (x)
|
||||
, current (next_by_distance (begin (), x.begin (), x.current))
|
||||
{ }
|
||||
|
||||
inline term_list&
|
||||
term_list::operator= (const term_list &x)
|
||||
{
|
||||
std::list<tree>::operator=(x);
|
||||
current = next_by_distance (begin (), x.begin (), x.current);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/* Try saving the term T into the list of terms. If
|
||||
T is already in the list of terms, then no action is
|
||||
performed. Otherwise, insert T before the current
|
||||
position, making this term current.
|
||||
|
||||
Note that not inserting terms is an optimization
|
||||
that corresponds to the structural rule of
|
||||
contraction.
|
||||
|
||||
NOTE: With the contraction rule, this data structure
|
||||
would be more efficiently represented as an ordered set
|
||||
or hash set. */
|
||||
void
|
||||
term_list::insert (tree t)
|
||||
{
|
||||
/* Search the current term list. If there is already
|
||||
a matching term, do not add the new one. */
|
||||
for (iterator i = begin(); i != end(); ++i)
|
||||
if (cp_tree_equal (*i, t))
|
||||
return;
|
||||
|
||||
current = std::list<tree>::insert (current, t);
|
||||
}
|
||||
|
||||
/* Remove the current term from the list, repositioning to
|
||||
the term following the removed term. Note that the new
|
||||
position could be past the end of the list.
|
||||
|
||||
The removed term is returned. */
|
||||
inline tree
|
||||
term_list::erase ()
|
||||
{
|
||||
tree t = *current;
|
||||
current = std::list<tree>::erase (current);
|
||||
return t;
|
||||
}
|
||||
|
||||
/* Initialize the current term to the first in the list. */
|
||||
inline void
|
||||
term_list::start ()
|
||||
{
|
||||
current = begin ();
|
||||
}
|
||||
|
||||
/* Advance to the next term in the list. */
|
||||
inline void
|
||||
term_list::next ()
|
||||
{
|
||||
++current;
|
||||
}
|
||||
|
||||
/* Returns true when the current position is past the end. */
|
||||
inline bool
|
||||
term_list::done () const
|
||||
{
|
||||
return current == end ();
|
||||
}
|
||||
|
||||
|
||||
/* A goal (or subgoal) models a sequent of the form
|
||||
'A |- C' where A and C are lists of assumptions and
|
||||
conclusions written as propositions in the constraint
|
||||
language (i.e., lists of trees).
|
||||
*/
|
||||
struct proof_goal
|
||||
{
|
||||
term_list assumptions;
|
||||
term_list conclusions;
|
||||
};
|
||||
|
||||
/* A proof state owns a list of goals and tracks the
|
||||
current sub-goal. The class also provides facilities
|
||||
for managing subgoals and constructing term lists. */
|
||||
struct proof_state : std::list<proof_goal>
|
||||
{
|
||||
proof_state ();
|
||||
|
||||
iterator branch (iterator i);
|
||||
};
|
||||
|
||||
/* An alias for proof state iterators. */
|
||||
typedef proof_state::iterator goal_iterator;
|
||||
|
||||
/* Initialize the state with a single empty goal,
|
||||
and set that goal as the current subgoal. */
|
||||
inline
|
||||
proof_state::proof_state ()
|
||||
: std::list<proof_goal> (1)
|
||||
{ }
|
||||
|
||||
|
||||
/* Branch the current goal by creating a new subgoal,
|
||||
returning a reference to // the new object. This does
|
||||
not update the current goal. */
|
||||
inline proof_state::iterator
|
||||
proof_state::branch (iterator i)
|
||||
{
|
||||
gcc_assert (i != end());
|
||||
proof_goal& g = *i;
|
||||
return insert (++i, g);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------
|
||||
Logical rules
|
||||
---------------------------------------------------------------------------*/
|
||||
|
||||
/*These functions modify the current state and goal by decomposing
|
||||
logical expressions using the logical rules of sequent calculus for
|
||||
first order logic.
|
||||
|
||||
Note that in each decomposition rule, the term T has been erased
|
||||
from term list before the specific rule is applied. */
|
||||
|
||||
/* The left logical rule for conjunction adds both operands
|
||||
to the current set of constraints. */
|
||||
void
|
||||
left_conjunction (proof_state &, goal_iterator i, tree t)
|
||||
{
|
||||
gcc_assert (TREE_CODE (t) == CONJ_CONSTR);
|
||||
|
||||
/* Insert the operands into the current branch. Note that the
|
||||
final order of insertion is left-to-right. */
|
||||
term_list &l = i->assumptions;
|
||||
l.insert (TREE_OPERAND (t, 1));
|
||||
l.insert (TREE_OPERAND (t, 0));
|
||||
}
|
||||
|
||||
/* The left logical rule for disjunction creates a new goal,
|
||||
adding the first operand to the original set of
|
||||
constraints and the second operand to the new set
|
||||
of constraints. */
|
||||
void
|
||||
left_disjunction (proof_state &s, goal_iterator i, tree t)
|
||||
{
|
||||
gcc_assert (TREE_CODE (t) == DISJ_CONSTR);
|
||||
|
||||
/* Branch the current subgoal. */
|
||||
goal_iterator j = s.branch (i);
|
||||
term_list &l1 = i->assumptions;
|
||||
term_list &l2 = j->assumptions;
|
||||
|
||||
/* Insert operands into the different branches. */
|
||||
l1.insert (TREE_OPERAND (t, 0));
|
||||
l2.insert (TREE_OPERAND (t, 1));
|
||||
}
|
||||
|
||||
/* The left logical rules for parameterized constraints
|
||||
adds its operand to the current goal. The list of
|
||||
parameters are effectively discarded. */
|
||||
void
|
||||
left_parameterized_constraint (proof_state &, goal_iterator i, tree t)
|
||||
{
|
||||
gcc_assert (TREE_CODE (t) == PARM_CONSTR);
|
||||
term_list &l = i->assumptions;
|
||||
l.insert (PARM_CONSTR_OPERAND (t));
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------
|
||||
Decomposition
|
||||
---------------------------------------------------------------------------*/
|
||||
|
||||
/* The following algorithms decompose expressions into sets of
|
||||
atomic propositions. In terms of the sequent calculus, these
|
||||
functions exercise the logical rules only.
|
||||
|
||||
This is equivalent, for the purpose of determining subsumption,
|
||||
to rewriting a constraint in disjunctive normal form. It also
|
||||
allows the resulting assumptions to be used as declarations
|
||||
for the purpose of separate checking. */
|
||||
|
||||
/* Apply the left logical rules to the proof state. */
|
||||
void
|
||||
decompose_left_term (proof_state &s, goal_iterator i)
|
||||
{
|
||||
term_list &l = i->assumptions;
|
||||
tree t = l.current_term ();
|
||||
switch (TREE_CODE (t))
|
||||
{
|
||||
case CONJ_CONSTR:
|
||||
left_conjunction (s, i, l.erase ());
|
||||
break;
|
||||
case DISJ_CONSTR:
|
||||
left_disjunction (s, i, l.erase ());
|
||||
break;
|
||||
case PARM_CONSTR:
|
||||
left_parameterized_constraint (s, i, l.erase ());
|
||||
break;
|
||||
default:
|
||||
l.next ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Apply the left logical rules of the sequent calculus
|
||||
until the current goal is fully decomposed into atomic
|
||||
constraints. */
|
||||
void
|
||||
decompose_left_goal (proof_state &s, goal_iterator i)
|
||||
{
|
||||
term_list& l = i->assumptions;
|
||||
l.start ();
|
||||
while (!l.done ())
|
||||
decompose_left_term (s, i);
|
||||
}
|
||||
|
||||
/* Apply the left logical rules of the sequent calculus
|
||||
until the antecedents are fully decomposed into atomic
|
||||
constraints. */
|
||||
void
|
||||
decompose_left (proof_state& s)
|
||||
{
|
||||
goal_iterator iter = s.begin ();
|
||||
goal_iterator end = s.end ();
|
||||
for ( ; iter != end; ++iter)
|
||||
decompose_left_goal (s, iter);
|
||||
}
|
||||
|
||||
/* Returns a vector of terms from the term list L. */
|
||||
tree
|
||||
extract_terms (term_list& l)
|
||||
{
|
||||
tree result = make_tree_vec (l.size());
|
||||
term_list::iterator iter = l.begin();
|
||||
term_list::iterator end = l.end();
|
||||
for (int n = 0; iter != end; ++iter, ++n)
|
||||
TREE_VEC_ELT (result, n) = *iter;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Extract the assumptions from the proof state S
|
||||
as a vector of vectors of atomic constraints. */
|
||||
inline tree
|
||||
extract_assumptions (proof_state& s)
|
||||
{
|
||||
tree result = make_tree_vec (s.size ());
|
||||
goal_iterator iter = s.begin ();
|
||||
goal_iterator end = s.end ();
|
||||
for (int n = 0; iter != end; ++iter, ++n)
|
||||
TREE_VEC_ELT (result, n) = extract_terms (iter->assumptions);
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
/* Decompose the required expression T into a constraint set: a
|
||||
vector of vectors containing only atomic propositions. If T is
|
||||
invalid, return an error. */
|
||||
tree
|
||||
decompose_assumptions (tree t)
|
||||
{
|
||||
if (!t || t == error_mark_node)
|
||||
return t;
|
||||
|
||||
/* Create a proof state, and insert T as the sole assumption. */
|
||||
proof_state s;
|
||||
term_list &l = s.begin ()->assumptions;
|
||||
l.insert (t);
|
||||
|
||||
/* Decompose the expression into a constraint set, and then
|
||||
extract the terms for the AST. */
|
||||
decompose_left (s);
|
||||
return extract_assumptions (s);
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------
|
||||
Subsumption Rules
|
||||
---------------------------------------------------------------------------*/
|
||||
|
||||
namespace {
|
||||
|
||||
bool subsumes_constraint (tree, tree);
|
||||
bool subsumes_conjunction (tree, tree);
|
||||
bool subsumes_disjunction (tree, tree);
|
||||
bool subsumes_parameterized_constraint (tree, tree);
|
||||
bool subsumes_atomic_constraint (tree, tree);
|
||||
|
||||
/* Returns true if the assumption A matches the conclusion C. This
|
||||
is generally the case when A and C have the same syntax.
|
||||
|
||||
NOTE: There will be specialized matching rules to accommodate
|
||||
type equivalence, conversion, inheritance, etc. But this is not
|
||||
in the current concepts draft. */
|
||||
inline bool
|
||||
match_terms (tree a, tree c)
|
||||
{
|
||||
return cp_tree_equal (a, c);
|
||||
}
|
||||
|
||||
/* Returns true if the list of assumptions AS subsumes the atomic
|
||||
proposition C. This is the case when we can find a proposition
|
||||
in AS that entails the conclusion C. */
|
||||
bool
|
||||
subsumes_atomic_constraint (tree as, tree c)
|
||||
{
|
||||
for (int i = 0; i < TREE_VEC_LENGTH (as); ++i)
|
||||
if (match_terms (TREE_VEC_ELT (as, i), c))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Returns true when both operands of C are subsumed by the
|
||||
assumptions AS. */
|
||||
inline bool
|
||||
subsumes_conjunction (tree as, tree c)
|
||||
{
|
||||
tree l = TREE_OPERAND (c, 0);
|
||||
tree r = TREE_OPERAND (c, 1);
|
||||
return subsumes_constraint (as, l) && subsumes_constraint (as, r);
|
||||
}
|
||||
|
||||
/* Returns true when either operand of C is subsumed by the
|
||||
assumptions AS. */
|
||||
inline bool
|
||||
subsumes_disjunction (tree as, tree c)
|
||||
{
|
||||
tree l = TREE_OPERAND (c, 0);
|
||||
tree r = TREE_OPERAND (c, 1);
|
||||
return subsumes_constraint (as, l) || subsumes_constraint (as, r);
|
||||
}
|
||||
|
||||
/* Returns true when the operand of C is subsumed by the
|
||||
assumptions in AS. The parameters are not considered in
|
||||
the subsumption rules. */
|
||||
bool
|
||||
subsumes_parameterized_constraint (tree as, tree c)
|
||||
{
|
||||
tree t = PARM_CONSTR_OPERAND (c);
|
||||
return subsumes_constraint (as, t);
|
||||
}
|
||||
|
||||
|
||||
/* Returns true when the list of assumptions AS subsumes the
|
||||
concluded proposition C. This is a simple recursive descent
|
||||
on C, matching against propositions in the assumption list AS. */
|
||||
bool
|
||||
subsumes_constraint (tree as, tree c)
|
||||
{
|
||||
switch (TREE_CODE (c))
|
||||
{
|
||||
case CONJ_CONSTR:
|
||||
return subsumes_conjunction (as, c);
|
||||
case DISJ_CONSTR:
|
||||
return subsumes_disjunction (as, c);
|
||||
case PARM_CONSTR:
|
||||
return subsumes_parameterized_constraint (as, c);
|
||||
default:
|
||||
return subsumes_atomic_constraint (as, c);
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns true if the LEFT constraints subsume the RIGHT constraints.
|
||||
This is done by checking that the RIGHT requirements follow from
|
||||
each of the LEFT subgoals. */
|
||||
bool
|
||||
subsumes_constraints_nonnull (tree left, tree right)
|
||||
{
|
||||
gcc_assert (check_constraint_info (left));
|
||||
gcc_assert (check_constraint_info (right));
|
||||
|
||||
/* Check that the required expression in RIGHT is subsumed by each
|
||||
subgoal in the assumptions of LEFT. */
|
||||
tree as = CI_ASSUMPTIONS (left);
|
||||
tree c = CI_NORMALIZED_CONSTRAINTS (right);
|
||||
for (int i = 0; i < TREE_VEC_LENGTH (as); ++i)
|
||||
if (!subsumes_constraint (TREE_VEC_ELT (as, i), c))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
} /* namespace */
|
||||
|
||||
/* Returns true if the LEFT constraints subsume the RIGHT
|
||||
constraints. */
|
||||
bool
|
||||
subsumes (tree left, tree right)
|
||||
{
|
||||
if (left == right)
|
||||
return true;
|
||||
if (!left)
|
||||
return false;
|
||||
if (!right)
|
||||
return true;
|
||||
return subsumes_constraints_nonnull (left, right);
|
||||
}
|
|
@ -1924,6 +1924,14 @@ implicitly_declare_fn (special_function_kind kind, tree type,
|
|||
rest_of_decl_compilation (fn, toplevel_bindings_p (), at_eof);
|
||||
gcc_assert (!TREE_USED (fn));
|
||||
|
||||
/* Propagate constraints from the inherited constructor. */
|
||||
if (flag_concepts && inherited_ctor)
|
||||
if (tree orig_ci = get_constraints (inherited_ctor))
|
||||
{
|
||||
tree new_ci = copy_node (orig_ci);
|
||||
set_constraints (fn, new_ci);
|
||||
}
|
||||
|
||||
/* Restore PROCESSING_TEMPLATE_DECL. */
|
||||
processing_template_decl = saved_processing_template_decl;
|
||||
|
||||
|
|
1240
gcc/cp/parser.c
1240
gcc/cp/parser.c
File diff suppressed because it is too large
Load Diff
|
@ -397,6 +397,15 @@ 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 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;
|
||||
|
||||
/* True if a constrained-type-specifier is not allowed in this
|
||||
context e.g., because they could never be deduced. */
|
||||
int prevent_constrained_type_specifiers;
|
||||
|
||||
} cp_parser;
|
||||
|
||||
/* In parser.c */
|
||||
|
|
863
gcc/cp/pt.c
863
gcc/cp/pt.c
File diff suppressed because it is too large
Load Diff
|
@ -253,6 +253,19 @@ cxx_print_xnode (FILE *file, tree node, int indent)
|
|||
fprintf (file, "pending_template");
|
||||
}
|
||||
break;
|
||||
case CONSTRAINT_INFO:
|
||||
{
|
||||
tree_constraint_info *cinfo = (tree_constraint_info *)node;
|
||||
if (cinfo->template_reqs)
|
||||
print_node (file, "template_reqs", cinfo->template_reqs, indent+4);
|
||||
if (cinfo->declarator_reqs)
|
||||
print_node (file, "declarator_reqs", cinfo->declarator_reqs,
|
||||
indent+4);
|
||||
print_node (file, "associated_constr",
|
||||
cinfo->associated_constr, indent+4);
|
||||
print_node_brief (file, "assumptions", cinfo->assumptions, indent+4);
|
||||
break;
|
||||
}
|
||||
case ARGUMENT_PACK_SELECT:
|
||||
print_node (file, "pack", ARGUMENT_PACK_SELECT_FROM_PACK (node),
|
||||
indent+4);
|
||||
|
|
|
@ -1203,6 +1203,12 @@ lookup_member (tree xbasetype, tree name, int protect, bool want_type,
|
|||
}
|
||||
|
||||
type = complete_type (type);
|
||||
|
||||
/* Make sure we're looking for a member of the current instantiation in the
|
||||
right partial specialization. */
|
||||
if (flag_concepts && dependent_type_p (type))
|
||||
type = currently_open_class (type);
|
||||
|
||||
if (!basetype_path)
|
||||
basetype_path = TYPE_BINFO (type);
|
||||
|
||||
|
|
|
@ -2710,10 +2710,18 @@ finish_template_template_parm (tree aggr, tree identifier)
|
|||
{
|
||||
tree decl = build_decl (input_location,
|
||||
TYPE_DECL, identifier, NULL_TREE);
|
||||
|
||||
tree tmpl = build_lang_decl (TEMPLATE_DECL, identifier, NULL_TREE);
|
||||
DECL_TEMPLATE_PARMS (tmpl) = current_template_parms;
|
||||
DECL_TEMPLATE_RESULT (tmpl) = decl;
|
||||
DECL_ARTIFICIAL (decl) = 1;
|
||||
|
||||
// Associate the constraints with the underlying declaration,
|
||||
// not the template.
|
||||
tree reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms);
|
||||
tree constr = build_constraints (reqs, NULL_TREE);
|
||||
set_constraints (decl, constr);
|
||||
|
||||
end_template_decl ();
|
||||
|
||||
gcc_assert (DECL_TEMPLATE_PARMS (tmpl));
|
||||
|
@ -2977,6 +2985,72 @@ finish_template_decl (tree parms)
|
|||
end_specialization ();
|
||||
}
|
||||
|
||||
// Returns the template type of the class scope being entered. If we're
|
||||
// entering a constrained class scope. TYPE is the class template
|
||||
// scope being entered and we may need to match the intended type with
|
||||
// a constrained specialization. For example:
|
||||
//
|
||||
// template<Object T>
|
||||
// struct S { void f(); }; #1
|
||||
//
|
||||
// template<Object T>
|
||||
// void S<T>::f() { } #2
|
||||
//
|
||||
// We check, in #2, that S<T> refers precisely to the type declared by
|
||||
// #1 (i.e., that the constraints match). Note that the following should
|
||||
// be an error since there is no specialization of S<T> that is
|
||||
// unconstrained, but this is not diagnosed here.
|
||||
//
|
||||
// template<typename T>
|
||||
// void S<T>::f() { }
|
||||
//
|
||||
// We cannot diagnose this problem here since this function also matches
|
||||
// qualified template names that are not part of a definition. For example:
|
||||
//
|
||||
// template<Integral T, Floating_point U>
|
||||
// typename pair<T, U>::first_type void f(T, U);
|
||||
//
|
||||
// Here, it is unlikely that there is a partial specialization of
|
||||
// pair constrained for for Integral and Floating_point arguments.
|
||||
//
|
||||
// The general rule is: if a constrained specialization with matching
|
||||
// constraints is found return that type. Also note that if TYPE is not a
|
||||
// class-type (e.g. a typename type), then no fixup is needed.
|
||||
|
||||
static tree
|
||||
fixup_template_type (tree type)
|
||||
{
|
||||
// Find the template parameter list at the a depth appropriate to
|
||||
// the scope we're trying to enter.
|
||||
tree parms = current_template_parms;
|
||||
int depth = template_class_depth (type);
|
||||
for (int n = processing_template_decl; n > depth && parms; --n)
|
||||
parms = TREE_CHAIN (parms);
|
||||
if (!parms)
|
||||
return type;
|
||||
tree cur_reqs = TEMPLATE_PARMS_CONSTRAINTS (parms);
|
||||
tree cur_constr = build_constraints (cur_reqs, NULL_TREE);
|
||||
|
||||
// Search for a specialization whose type and constraints match.
|
||||
tree tmpl = CLASSTYPE_TI_TEMPLATE (type);
|
||||
tree specs = DECL_TEMPLATE_SPECIALIZATIONS (tmpl);
|
||||
while (specs)
|
||||
{
|
||||
tree spec_constr = get_constraints (TREE_VALUE (specs));
|
||||
|
||||
// If the type and constraints match a specialization, then we
|
||||
// are entering that type.
|
||||
if (same_type_p (type, TREE_TYPE (specs))
|
||||
&& equivalent_constraints (cur_constr, spec_constr))
|
||||
return TREE_TYPE (specs);
|
||||
specs = TREE_CHAIN (specs);
|
||||
}
|
||||
|
||||
// If no specialization matches, then must return the type
|
||||
// previously found.
|
||||
return type;
|
||||
}
|
||||
|
||||
/* Finish processing a template-id (which names a type) of the form
|
||||
NAME < ARGS >. Return the TYPE_DECL for the type named by the
|
||||
template-id. If ENTERING_SCOPE is nonzero we are about to enter
|
||||
|
@ -2990,6 +3064,16 @@ finish_template_type (tree name, tree args, int entering_scope)
|
|||
type = lookup_template_class (name, args,
|
||||
NULL_TREE, NULL_TREE, entering_scope,
|
||||
tf_warning_or_error | tf_user);
|
||||
|
||||
/* If we might be entering the scope of a partial specialization,
|
||||
find the one with the right constraints. */
|
||||
if (flag_concepts
|
||||
&& entering_scope
|
||||
&& CLASS_TYPE_P (type)
|
||||
&& dependent_type_p (type)
|
||||
&& PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (type)))
|
||||
type = fixup_template_type (type);
|
||||
|
||||
if (type == error_mark_node)
|
||||
return type;
|
||||
else if (CLASS_TYPE_P (type) && !alias_type_or_template_p (type))
|
||||
|
@ -7442,6 +7526,9 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
|
|||
case CPTK_IS_POLYMORPHIC:
|
||||
return (CLASS_TYPE_P (type1) && TYPE_POLYMORPHIC_P (type1));
|
||||
|
||||
case CPTK_IS_SAME_AS:
|
||||
return same_type_p (type1, type2);
|
||||
|
||||
case CPTK_IS_STD_LAYOUT:
|
||||
return (std_layout_type_p (type1));
|
||||
|
||||
|
@ -7549,8 +7636,9 @@ finish_trait_expr (cp_trait_kind kind, tree type1, tree type2)
|
|||
case CPTK_IS_CLASS:
|
||||
case CPTK_IS_ENUM:
|
||||
case CPTK_IS_UNION:
|
||||
case CPTK_IS_SAME_AS:
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
}
|
||||
|
|
|
@ -2955,16 +2955,19 @@ cp_tree_equal (tree t1, tree t2)
|
|||
up for expressions that involve 'this' in a member function
|
||||
template. */
|
||||
|
||||
if (comparing_specializations)
|
||||
if (comparing_specializations && !CONSTRAINT_VAR_P (t1))
|
||||
/* When comparing hash table entries, only an exact match is
|
||||
good enough; we don't want to replace 'this' with the
|
||||
version from another function. */
|
||||
version from another function. But be more flexible
|
||||
with local parameters in a requires-expression. */
|
||||
return false;
|
||||
|
||||
if (same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
|
||||
{
|
||||
if (DECL_ARTIFICIAL (t1) ^ DECL_ARTIFICIAL (t2))
|
||||
return false;
|
||||
if (CONSTRAINT_VAR_P (t1) ^ CONSTRAINT_VAR_P (t2))
|
||||
return false;
|
||||
if (DECL_ARTIFICIAL (t1)
|
||||
|| (DECL_PARM_LEVEL (t1) == DECL_PARM_LEVEL (t2)
|
||||
&& DECL_PARM_INDEX (t1) == DECL_PARM_INDEX (t2)))
|
||||
|
@ -3000,6 +3003,10 @@ cp_tree_equal (tree t1, tree t2)
|
|||
return (cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0))
|
||||
&& cp_tree_equal (TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1)));
|
||||
|
||||
case CONSTRAINT_INFO:
|
||||
return cp_tree_equal (CI_ASSOCIATED_CONSTRAINTS (t1),
|
||||
CI_ASSOCIATED_CONSTRAINTS (t2));
|
||||
|
||||
case TREE_VEC:
|
||||
{
|
||||
unsigned ix;
|
||||
|
@ -3876,6 +3883,14 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, walk_tree_fn func,
|
|||
*walk_subtrees_p = 0;
|
||||
break;
|
||||
|
||||
case REQUIRES_EXPR:
|
||||
// Only recurse through the nested expression. Do not
|
||||
// walk the parameter list. Doing so causes false
|
||||
// positives in the pack expansion checker since the
|
||||
// requires parameters are introduced as pack expansions.
|
||||
WALK_SUBTREE (TREE_OPERAND (*tp, 1));
|
||||
*walk_subtrees_p = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
return NULL_TREE;
|
||||
|
|
|
@ -3474,6 +3474,25 @@ cp_build_function_call_vec (tree function, vec<tree, va_gc> **params,
|
|||
|
||||
if (TREE_CODE (function) == FUNCTION_DECL)
|
||||
{
|
||||
/* If the function is a non-template member function
|
||||
or a non-template friend, then we need to check the
|
||||
constraints.
|
||||
|
||||
Note that if overload resolution failed with a single
|
||||
candidate this function will be used to explicitly diagnose
|
||||
the failure for the single call expression. The check is
|
||||
technically redundant since we also would have failed in
|
||||
add_function_candidate. */
|
||||
if (flag_concepts
|
||||
&& (complain & tf_error)
|
||||
&& !constraints_satisfied_p (function))
|
||||
{
|
||||
error ("cannot call function %qD", function);
|
||||
location_t loc = DECL_SOURCE_LOCATION (function);
|
||||
diagnose_constraints (loc, function, NULL_TREE);
|
||||
return error_mark_node;
|
||||
}
|
||||
|
||||
if (!mark_used (function, complain) && !(complain & tf_error))
|
||||
return error_mark_node;
|
||||
fndecl = function;
|
||||
|
|
|
@ -19280,7 +19280,8 @@ Predefined Macros,cpp,The GNU C Preprocessor}).
|
|||
* C++ Attributes:: Variable, function, and type attributes for C++ only.
|
||||
* Function Multiversioning:: Declaring multiple function versions.
|
||||
* Namespace Association:: Strong using-directives for namespace association.
|
||||
* Type Traits:: Compiler support for type traits
|
||||
* Type Traits:: Compiler support for type traits.
|
||||
* C++ Concepts:: Improved support for generic programming.
|
||||
* Java Exceptions:: Tweaking exception handling to work with Java.
|
||||
* Deprecated Features:: Things will disappear from G++.
|
||||
* Backwards Compatibility:: Compatibilities with earlier definitions of C++.
|
||||
|
@ -20076,6 +20077,52 @@ an enumeration type ([dcl.enum]).
|
|||
|
||||
@end table
|
||||
|
||||
|
||||
@node C++ Concepts
|
||||
@section C++ Concepts
|
||||
|
||||
C++ concepts provide much-improved support for generic programming. In
|
||||
particular, they allow the specification of constraints on template arguments.
|
||||
The constraints are used to extend the usual overloading and partial
|
||||
specialization capabilities of the language, allowing generic data structures
|
||||
and algorithms to be ``refined'' based on their properties rather than their
|
||||
type names.
|
||||
|
||||
The following keywords are reserved for concepts.
|
||||
|
||||
@table @code
|
||||
@item assumes
|
||||
States an expression as an assumption, and if possible, verifies that the
|
||||
assumption is valid. For example, @code{assume(n > 0)}.
|
||||
|
||||
@item axiom
|
||||
Introduces an axiom definition. Axioms introduce requirements on values.
|
||||
|
||||
@item forall
|
||||
Introduces a universally quantified object in an axiom. For example,
|
||||
@code{forall (int n) n + 0 == n}).
|
||||
|
||||
@item concept
|
||||
Introduces a concept definition. Concepts are sets of syntactic and semantic
|
||||
requirements on types and their values.
|
||||
|
||||
@item requires
|
||||
Introduces constraints on template arguments or requirements for a member
|
||||
function of a class template.
|
||||
|
||||
@end table
|
||||
|
||||
The front end also exposes a number of internal mechanism that can be used
|
||||
to simplify the writing of type traits. Note that some of these traits are
|
||||
likely to be removed in the future.
|
||||
|
||||
@table @code
|
||||
@item __is_same (type1, type2)
|
||||
A binary type trait: true whenever the type arguments are the same.
|
||||
|
||||
@end table
|
||||
|
||||
|
||||
@node Java Exceptions
|
||||
@section Java Exceptions
|
||||
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
// { dg-options "-std=c++1z" }
|
||||
|
||||
template<typename T>
|
||||
concept bool C() { return __is_class(T); }
|
||||
|
||||
template<typename T>
|
||||
requires C<T>()
|
||||
using X = T*;
|
||||
|
||||
struct S { };
|
||||
|
||||
int main()
|
||||
{
|
||||
X<S> x1;
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
// { dg-options "-std=c++1z" }
|
||||
|
||||
template<typename T>
|
||||
concept bool C() { return __is_class(T); }
|
||||
|
||||
template<C T> using X = T*;
|
||||
|
||||
struct S { };
|
||||
|
||||
int main()
|
||||
{
|
||||
X<S> x1;
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
// { dg-options "-std=c++1z" }
|
||||
|
||||
template<typename T>
|
||||
concept bool C() { return __is_class(T); }
|
||||
|
||||
template<typename T>
|
||||
requires C<T>()
|
||||
using X = T*;
|
||||
|
||||
int main()
|
||||
{
|
||||
X<int> x1; // { dg-error "constraint|invalid" }
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
// { dg-options "-std=c++1z" }
|
||||
|
||||
template<typename T>
|
||||
concept bool C() { return __is_class(T); }
|
||||
|
||||
template<typename T>
|
||||
requires C<T>()
|
||||
using X = T*;
|
||||
|
||||
// BUG: Alias templates are expanded at the point of use, regardless
|
||||
// of whether or not they are dependent. This causes T* to be substituted
|
||||
// without acutally checking the constraints.
|
||||
template<typename T>
|
||||
using Y = X<T>;
|
||||
|
||||
int main()
|
||||
{
|
||||
Y<int> y1; // { dg-error "" "" { xfail *-*-* } }
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
// { dg-options "-std=c++1z" }
|
||||
|
||||
template<typename T>
|
||||
concept bool Class() { return __is_class(T); }
|
||||
|
||||
template<typename T>
|
||||
concept bool Union() { return __is_union(T); }
|
||||
|
||||
|
||||
// Check ordering of specializations
|
||||
template<typename T>
|
||||
concept bool One() { return sizeof(T) >= 4; }
|
||||
|
||||
template<typename T>
|
||||
concept bool Two() { return One<T>() && sizeof(T) >= 8; }
|
||||
|
||||
// Check non-overlapping specializations
|
||||
template<typename T>
|
||||
struct S1 { static const int value = 0; };
|
||||
|
||||
template<Class T>
|
||||
struct S1<T> { static const int value = 1; };
|
||||
|
||||
template<Union T>
|
||||
struct S1<T> { static const int value = 2; };
|
||||
|
||||
struct S { };
|
||||
union U { };
|
||||
|
||||
static_assert(S1<int>::value == 0, "");
|
||||
static_assert(S1<S>::value == 1, "");
|
||||
static_assert(S1<U>::value == 2, "");
|
||||
|
||||
|
||||
// Check ordering of partial specializaitons
|
||||
template<typename T>
|
||||
struct S2 { static const int value = 0; };
|
||||
|
||||
template<One T>
|
||||
struct S2<T> { static const int value = 1; };
|
||||
|
||||
template<Two T>
|
||||
struct S2<T> { static const int value = 2; };
|
||||
|
||||
struct one_type { char x[4]; };
|
||||
struct two_type { char x[8]; };
|
||||
|
||||
static_assert(S2<char>::value == 0, "");
|
||||
static_assert(S2<one_type>::value == 1, "");
|
||||
static_assert(S2<two_type>::value == 2, "");
|
||||
|
||||
int main() { }
|
|
@ -0,0 +1,14 @@
|
|||
// { dg-options "-std=c++1z" }
|
||||
|
||||
template<typename T>
|
||||
concept bool C() { return __is_class(T); }
|
||||
|
||||
template<typename T>
|
||||
requires C<T>()
|
||||
struct S { };
|
||||
|
||||
struct X { };
|
||||
|
||||
S<X> sx;
|
||||
|
||||
int main() { }
|
|
@ -0,0 +1,14 @@
|
|||
// { dg-options "-std=c++1z" }
|
||||
|
||||
template<typename T>
|
||||
concept bool C() { return __is_class(T); }
|
||||
|
||||
template<typename T>
|
||||
requires C<T>()
|
||||
struct S { };
|
||||
|
||||
struct X { };
|
||||
|
||||
S<int> sx; // { dg-error "constraint|invalid" }
|
||||
|
||||
int main() { }
|
|
@ -0,0 +1,14 @@
|
|||
// { dg-options "-std=c++1z" }
|
||||
|
||||
template<typename T>
|
||||
concept bool C() { return __is_class(T); }
|
||||
|
||||
// Check class redeclaration with alternative spellings.
|
||||
template<typename T> requires C<T>() struct S;
|
||||
template<C T> struct S { };
|
||||
|
||||
struct X { };
|
||||
|
||||
// S<X> sx;
|
||||
|
||||
int main() { }
|
|
@ -0,0 +1,21 @@
|
|||
// { dg-options "-std=c++1z" }
|
||||
|
||||
template<typename T>
|
||||
concept bool Class() { return __is_class(T); }
|
||||
|
||||
template<typename T>
|
||||
concept bool Union() { return __is_union(T); }
|
||||
|
||||
// Check non-overlapping specializations
|
||||
template<typename T> struct S1 { static const int value = 0; };
|
||||
template<Class T> struct S1<T> { static const int value = 1; };
|
||||
template<Union T> struct S1<T> { static const int value = 2; };
|
||||
|
||||
struct S { };
|
||||
union U { };
|
||||
|
||||
static_assert(S1<int>::value == 0, "");
|
||||
static_assert(S1<S>::value == 1, "");
|
||||
static_assert(S1<U>::value == 2, "");
|
||||
|
||||
int main() { }
|
|
@ -0,0 +1,26 @@
|
|||
// { dg-options "-std=c++1z" }
|
||||
|
||||
template<typename T>
|
||||
concept bool One() { return sizeof(T) >= 4; }
|
||||
|
||||
template<typename T>
|
||||
concept bool Two() { return One<T>() && sizeof(T) >= 8; }
|
||||
|
||||
// Check ordering of partial specializaitons
|
||||
template<typename T>
|
||||
struct S2 { static const int value = 0; };
|
||||
|
||||
template<One T>
|
||||
struct S2<T> { static const int value = 1; };
|
||||
|
||||
template<Two T>
|
||||
struct S2<T> { static const int value = 2; };
|
||||
|
||||
struct one_type { char x[4]; };
|
||||
struct two_type { char x[8]; };
|
||||
|
||||
static_assert(S2<char>::value == 0, "");
|
||||
static_assert(S2<one_type>::value == 1, "");
|
||||
static_assert(S2<two_type>::value == 2, "");
|
||||
|
||||
int main() { }
|
|
@ -0,0 +1,18 @@
|
|||
// { dg-options "-std=c++1z" }
|
||||
|
||||
template<typename T>
|
||||
concept bool One() { return sizeof(T) >= 4; }
|
||||
|
||||
template<typename T>
|
||||
concept bool Two() { return One<T>() && sizeof(T) >= 8; }
|
||||
|
||||
// Check that there is no ecsacpe hatch
|
||||
template<Two T> struct S4 { };
|
||||
template<One T> struct S4<T> { }; // { dg-error "does not specialize" }
|
||||
|
||||
struct one_type { char x[4]; };
|
||||
|
||||
// Constraints are checked even when decls are not instantiatied.
|
||||
S4<one_type>* x4b; // { dg-error "constraint|invalid" }
|
||||
|
||||
int main() { }
|
|
@ -0,0 +1,13 @@
|
|||
// { dg-options "-std=c++1z" }
|
||||
|
||||
template<typename T>
|
||||
concept bool C() { return __is_class(T); }
|
||||
|
||||
template<const C T> struct S1 { }; // { dg-error "cv-qualified" }
|
||||
template<volatile C T> struct S2 { }; // { dg-error "cv-qualified" }
|
||||
template<C* T> struct S3 { }; // { dg-error "invalid" }
|
||||
template<C const* T> struct S3a { }; // { dg-error "invalid" }
|
||||
template<C* const T> struct S3b { }; // { dg-error "invalid" }
|
||||
template<C& T> struct S4 { }; // { dg-error "invalid" }
|
||||
template<C[3] T> struct S4 { }; // { dg-error "invalid|expected" }
|
||||
template<C(*T)()> struct S5 { }; // { dg-error "invalid" }
|
|
@ -0,0 +1,32 @@
|
|||
// { dg-options "-std=c++1z" }
|
||||
|
||||
typedef concept int CINT; // { dg-error "'concept' cannot appear in a typedef declaration" }
|
||||
|
||||
void f(concept int); // { dg-error "a parameter cannot be declared 'concept'" }
|
||||
|
||||
template<typename T>
|
||||
concept int f2() { return 0; } // { dg-error "return type" }
|
||||
concept bool f3(); // { dg-error "no definition" }
|
||||
|
||||
struct X
|
||||
{
|
||||
template<typename T>
|
||||
concept int f4() { return 0; } // { dg-error "return type|member function" }
|
||||
concept bool f5() { return true; } // { dg-error "member function" }
|
||||
template<typename T>
|
||||
static concept bool f6() { return true; } // { dg-error "a concept cannot be a 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'" }
|
||||
concept X(); // { dg-error "a constructor cannot be 'concept'" }
|
||||
};
|
||||
|
||||
concept bool X2; // { dg-error "non-template variable" }
|
||||
|
||||
template<typename T>
|
||||
concept bool X3; // { dg-error "has no initializer" }
|
||||
|
||||
struct S {
|
||||
template<typename T>
|
||||
static concept bool C1 = true; // { dg-error "static data member" }
|
||||
};
|
|
@ -0,0 +1,12 @@
|
|||
// PR c++/67007
|
||||
// { dg-options -std=c++1z }
|
||||
|
||||
template <class U>
|
||||
concept bool A =
|
||||
requires (U u) { u; };
|
||||
|
||||
template <class T>
|
||||
concept bool B =
|
||||
requires (T t) { { t } -> A; };
|
||||
|
||||
void foo(B);
|
|
@ -0,0 +1,59 @@
|
|||
// PR c++/66962
|
||||
// { dg-options -std=c++1z }
|
||||
|
||||
template <typename> struct remove_cv;
|
||||
template <typename> struct is_reference;
|
||||
template <typename> void declval();
|
||||
template <typename> struct is_constructible;
|
||||
template <typename> struct is_nothrow_constructible;
|
||||
template <typename _Tp> using remove_cv_t = typename remove_cv<_Tp>::type;
|
||||
template <typename> struct Trans_NS_extension_apply_list;
|
||||
template <typename T> using _t = typename T::type;
|
||||
template <class> void ImplicitlyConvertibleTo();
|
||||
template <class> void Assignable();
|
||||
template <class T, class... Args> int ConstructibleObject = requires { T{}; };
|
||||
template <class T, class... Args>
|
||||
concept bool BindableReference =
|
||||
is_reference<T>::value &&is_constructible<T>::value;
|
||||
template <class T, class... Args> concept bool Constructible() {
|
||||
return ConstructibleObject<T> || BindableReference<T, Args...>;
|
||||
}
|
||||
template <class T> concept bool DefaultConstructible() {
|
||||
return Constructible<T>() && requires { new T[0]; };
|
||||
}
|
||||
template <class T> concept bool MoveConstructible() {
|
||||
return Constructible<T>() && ImplicitlyConvertibleTo<T>;
|
||||
}
|
||||
template <class T> concept bool Movable() {
|
||||
return MoveConstructible<T>() && Assignable<T &&>;
|
||||
}
|
||||
template <class, class> int Swappable_ = requires { 0; };
|
||||
template <class T, class U> int Swappable();
|
||||
template <class T> concept bool Dereferencable = requires{{0}};
|
||||
template <Dereferencable R> using RvalueReferenceType = decltype(0);
|
||||
template <class T> int IsValueType;
|
||||
template <class> struct value_type;
|
||||
template <class T>
|
||||
requires IsValueType<
|
||||
_t<value_type<remove_cv_t<T>>>> using ValueType =
|
||||
_t<value_type<remove_cv_t<T>>>;
|
||||
template <class I> concept bool Readable() {
|
||||
return Movable<I>() && DefaultConstructible<I>() &&
|
||||
Dereferencable<const I> && requires{{0}};
|
||||
}
|
||||
template <class Out, class T> concept bool MoveWritable() {
|
||||
return Movable<Out>() && DefaultConstructible<Out>() &&
|
||||
Dereferencable<Out>;
|
||||
}
|
||||
template <class In, class Out> concept bool IndirectlyMovable() {
|
||||
return Readable<In>() && Movable<ValueType<In>>() &&
|
||||
Constructible<ValueType<In>>() &&
|
||||
MoveWritable<Out, RvalueReferenceType<In>>() &&
|
||||
MoveWritable<Out, ValueType<In>>();
|
||||
}
|
||||
IndirectlyMovable { In, Out }
|
||||
int is_nothrow_indirectly_movable_v =
|
||||
is_nothrow_constructible<ValueType<In>>::value;
|
||||
template <Readable R1, Readable R2>
|
||||
requires IndirectlyMovable<R1, R2>() &&
|
||||
IndirectlyMovable<R2, R1>() void iter_swap2();
|
|
@ -0,0 +1,34 @@
|
|||
// PR c++/66092
|
||||
// { dg-options "-std=c++1z" }
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
template <typename T, typename U, typename... Args>
|
||||
requires (sizeof...(Args) == 0)
|
||||
constexpr decltype(auto) check()
|
||||
{
|
||||
return std::integral_constant<bool, __is_same_as(T, U)>();
|
||||
}
|
||||
|
||||
template <typename T, typename U, typename... Args>
|
||||
requires (sizeof...(Args) > 0)
|
||||
constexpr decltype(auto) check()
|
||||
{
|
||||
return std::integral_constant<bool, __is_same_as(T, U)
|
||||
&& decltype(check<U, Args...>())::value>();
|
||||
}
|
||||
|
||||
template <typename T, typename U, typename... Args>
|
||||
concept bool Same()
|
||||
{
|
||||
return decltype(check<T, U, Args...>())::value;
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
requires Same<Args...>() // { dg-error "concept" }
|
||||
void foo( Args... args ) {}
|
||||
|
||||
int main()
|
||||
{
|
||||
foo(1, 2, 3); // { dg-error "" }
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
// { dg-options "-std=c++1z" }
|
||||
|
||||
// Check equivalence of short- and longhand declarations.
|
||||
|
||||
template<typename T>
|
||||
concept bool C() { return __is_class(T); }
|
||||
|
||||
template<typename T>
|
||||
concept bool D() { return __is_empty(T); }
|
||||
|
||||
struct X { } x;
|
||||
|
||||
void f1(C x);
|
||||
template<C T> void f2(T x);
|
||||
void f3(C x);
|
||||
template<C T> void f4(T x) requires D<T>();
|
||||
template<C T> void f5(T x) requires D<T>();
|
||||
template<C T> void f6(T x) requires D<T>();
|
||||
|
||||
int main() {
|
||||
f1(x);
|
||||
f2(x);
|
||||
f3(x);
|
||||
f4(x);
|
||||
f5(x);
|
||||
f6(x);
|
||||
}
|
||||
|
||||
template<typename T> requires C<T>() void f1(T x) { }
|
||||
template<typename T> requires C<T>() void f2(T x) { }
|
||||
template<C T> void f3(T x) { }
|
||||
template<typename T> requires C<T>() void f4(T x) requires D<T>() { }
|
||||
template<typename T> requires C<T>() and D<T>() void f5(T x) { }
|
||||
template<typename T> void f6(T x) requires C<T>() and D<T>() { }
|
|
@ -0,0 +1,29 @@
|
|||
// { dg-do run }
|
||||
// { dg-options "-std=c++1z" }
|
||||
|
||||
|
||||
// template<typename T>
|
||||
// concept bool C() { return true; }
|
||||
|
||||
|
||||
template<typename T>
|
||||
concept bool C = true;
|
||||
|
||||
void f1(C, C);
|
||||
void f2(C, C);
|
||||
void f3(C, C);
|
||||
|
||||
int main() {
|
||||
f1(0, 0);
|
||||
f2(0, 0);
|
||||
f3(0, 0);
|
||||
}
|
||||
|
||||
void f1(C, C) { }
|
||||
|
||||
template<C T>
|
||||
void f2(T, T) { }
|
||||
|
||||
template<typename T>
|
||||
requires C<T>
|
||||
void f3(T, T) { }
|
|
@ -0,0 +1,21 @@
|
|||
// { dg-options "-std=c++1z" }
|
||||
|
||||
template<typename T>
|
||||
concept bool C() { return __is_class(T); }
|
||||
|
||||
template<typename T>
|
||||
concept bool D() { return C<T>() && __is_empty(T); }
|
||||
|
||||
struct X { };
|
||||
struct Y { int n; };
|
||||
|
||||
template<typename T> void g(T) { } // #1
|
||||
template<C T> void g(T) { } // #2
|
||||
template<D T> void g(T) { } // #3
|
||||
|
||||
// FIXME: How do I test that these generate the right symbols?
|
||||
template void g(int); // Instantiate #1
|
||||
template void g(X); // Instantitae #3
|
||||
template void g(Y); // Instantiate #2
|
||||
|
||||
int main() { }
|
|
@ -0,0 +1,24 @@
|
|||
// { dg-options "-std=c++1z" }
|
||||
|
||||
template<typename T>
|
||||
concept bool C() { return __is_class(T); }
|
||||
|
||||
template<typename T>
|
||||
concept bool D() { return C<T>() && __is_empty(T); }
|
||||
|
||||
struct X { };
|
||||
struct Y { int n; };
|
||||
|
||||
template<typename T> struct S { void f1() { } }; // #1
|
||||
template<C T> struct S<T> { void f2() { } }; // #2
|
||||
template<D T> struct S<T> { void f3() { } }; // #3
|
||||
|
||||
template struct S<int>; // Instantiate #1
|
||||
template struct S<X>; // Instantiate #2
|
||||
template struct S<Y>; // Instantiate #2
|
||||
|
||||
int main() {
|
||||
S<int> i; i.f1();
|
||||
S<X> x; x.f3();
|
||||
S<Y> y; y.f2();
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
// { dg-options "-std=c++1z" }
|
||||
|
||||
template<typename T>
|
||||
concept bool C() { return __is_class(T); }
|
||||
|
||||
template<typename T>
|
||||
concept bool D() { return C<T>() && __is_empty(T); }
|
||||
|
||||
struct X { };
|
||||
struct Y { int n; };
|
||||
|
||||
template<typename T>
|
||||
struct S {
|
||||
void f() { } // #1
|
||||
void f() requires C<T>() { } // #2
|
||||
|
||||
void g() requires C<T>() { } // #1
|
||||
void g() requires D<T>() { } // #2
|
||||
};
|
||||
|
||||
template void S<int>::f(); // #1
|
||||
template void S<X>::f(); // #2
|
||||
|
||||
template void S<X>::g(); // #2
|
||||
template void S<Y>::g(); // #1
|
||||
|
||||
int main() { }
|
|
@ -0,0 +1,17 @@
|
|||
// { dg-options "-std=c++1z" }
|
||||
|
||||
template<typename T>
|
||||
concept bool C() { return __is_class(T); }
|
||||
|
||||
template<typename T>
|
||||
concept bool D() { return C<T>() && __is_empty(T); }
|
||||
|
||||
template<typename T>
|
||||
struct S {
|
||||
void g() requires C<T>() { } // #1
|
||||
void g() requires D<T>() { } // #2
|
||||
};
|
||||
|
||||
template void S<int>::g(); // { dg-error "match" }
|
||||
|
||||
int main() { }
|
|
@ -0,0 +1,32 @@
|
|||
// { dg-do run }
|
||||
// { dg-options "-std=c++1z" }
|
||||
|
||||
#include <cassert>
|
||||
|
||||
template<typename T>
|
||||
concept bool C() { return __is_class(T); }
|
||||
|
||||
template<typename T>
|
||||
concept bool D() { return C<T>() && __is_empty(T); }
|
||||
|
||||
struct X { } x;
|
||||
struct Y { int n; } y;
|
||||
|
||||
template<typename T> void g(T) { } // #1
|
||||
template<C T> void g(T) { } // #2
|
||||
template<D T> void g(T) { } // #3
|
||||
|
||||
int called;
|
||||
|
||||
template<> void g(int) { called = 1; } // Specialization of #1
|
||||
template<> void g<X>(X) { called = 2; } // Specialization of #3
|
||||
template<> void g(Y) { called = 3; } // Specialization of #2
|
||||
|
||||
int main() {
|
||||
g(0);
|
||||
assert(called == 1);
|
||||
g(x);
|
||||
assert(called == 2);
|
||||
g(y);
|
||||
assert(called == 3);
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
// { dg-options "-std=c++1z" }
|
||||
|
||||
template<typename T>
|
||||
concept bool C() { return __is_class(T); }
|
||||
|
||||
struct X { };
|
||||
|
||||
template<C T> struct S;
|
||||
template<> struct S<X> { void f() { } };
|
||||
|
||||
int main() {
|
||||
S<X> x; x.f();
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
// { dg-options "-std=c++1z" }
|
||||
|
||||
template<typename T>
|
||||
concept bool C() { return __is_class(T); }
|
||||
|
||||
template<C T> struct S;
|
||||
|
||||
struct X { };
|
||||
|
||||
// Not a valid explicit specialization, int does not satisfy C.
|
||||
template<> struct S<int> { }; // { dg-error "constraint" }
|
||||
|
||||
int main() { }
|
|
@ -0,0 +1,51 @@
|
|||
// { dg-do run }
|
||||
// { dg-options "-std=c++1z" }
|
||||
|
||||
#include <cassert>
|
||||
|
||||
template<typename T>
|
||||
concept bool C() { return __is_class(T); }
|
||||
|
||||
template<typename T>
|
||||
concept bool D() { return C<T>() && __is_empty(T); }
|
||||
|
||||
struct X { } x;
|
||||
struct Y { int n; } y;
|
||||
|
||||
int called = 0;
|
||||
|
||||
template<typename T>
|
||||
struct S {
|
||||
void f() { called = 0; } // #1
|
||||
void f() requires C<T>() { called = 0; } // #2
|
||||
|
||||
void g() requires C<T>() { } // #1
|
||||
void g() requires D<T>() { } // #2
|
||||
};
|
||||
|
||||
template<> void S<int>::f() { called = 1; } // Spec of #1
|
||||
template<> void S<X>::f() { called = 2; } // Spec of #2
|
||||
|
||||
template<> void S<X>::g() { called = 3; } // Spec of #2
|
||||
template<> void S<Y>::g() { called = 4; } // Spec of #1
|
||||
|
||||
int main() {
|
||||
S<double> sd;
|
||||
S<int> si;
|
||||
S<X> sx;
|
||||
S<Y> sy;
|
||||
|
||||
sd.f();
|
||||
assert(called == 0);
|
||||
si.f();
|
||||
assert(called == 1);
|
||||
sx.f();
|
||||
assert(called == 2);
|
||||
sy.f();
|
||||
assert(called == 0);
|
||||
|
||||
sx.g();
|
||||
assert(called == 3);
|
||||
sy.g();
|
||||
assert(called == 4);
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
// { dg-options "-std=c++1z" }
|
||||
|
||||
#include <cassert>
|
||||
|
||||
template<typename T>
|
||||
concept bool C() { return __is_class(T); }
|
||||
|
||||
template<typename T>
|
||||
concept bool D() { return C<T>() && __is_empty(T); }
|
||||
|
||||
struct X { } x;
|
||||
struct Y { int n; } y;
|
||||
|
||||
int called = 0;
|
||||
|
||||
template<typename T>
|
||||
struct S {
|
||||
void f() requires C<T>();
|
||||
};
|
||||
|
||||
template<> void S<int>::f() { called = 1; } // { dg-error "match" }
|
|
@ -0,0 +1,18 @@
|
|||
// { dg-options "-std=c++1z" }
|
||||
|
||||
template<typename T>
|
||||
struct A {
|
||||
template<class T2> void f1(T, T2); // member template
|
||||
template<class T2> void f2(T, T2); // member template
|
||||
};
|
||||
|
||||
template<>
|
||||
template<class X1> void A<int>::f1(int, X1);
|
||||
|
||||
// Specialization with template-id
|
||||
template<>
|
||||
template<> void A<int>::f2<char>(int, char);
|
||||
|
||||
// Specialization with deduction
|
||||
template<>
|
||||
template<> void A<int>::f1(int, char);
|
|
@ -0,0 +1,20 @@
|
|||
// { dg-do run }
|
||||
// { dg-options "-std=c++1z" }
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
template<typename T>
|
||||
concept bool C1 = __is_class(T);
|
||||
|
||||
template<typename T>
|
||||
concept bool C2() { return __is_class(T); }
|
||||
|
||||
template<typename T>
|
||||
concept bool C3() { return requires (T a) { ++a; }; }
|
||||
|
||||
int main() {
|
||||
if (C1<int>) assert(false);
|
||||
if (C2<int>()) assert(false);
|
||||
if (!C3<int>()) assert(false);
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
// { dg-options "-std=c++1z" }
|
||||
|
||||
template<typename T>
|
||||
concept bool C1()
|
||||
{
|
||||
return requires (T t) { t.f(); };
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
concept bool C2()
|
||||
{
|
||||
return requires { typename T::type; };
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
requires C1<T>()
|
||||
void f1(T x) { }
|
||||
|
||||
template<typename T>
|
||||
requires C2<T>()
|
||||
void f2(T x) { }
|
||||
|
||||
// Note that these declarations are private and therefore
|
||||
// cannot satisify the constraints.
|
||||
class S
|
||||
{
|
||||
using type = int;
|
||||
void f() { }
|
||||
} s;
|
||||
|
||||
int main()
|
||||
{
|
||||
f1(s); // { dg-error "cannot call" }
|
||||
f2(s); // { dg-error "cannot call" }
|
||||
|
||||
// When used in non-SFINAE contexts, make sure that we fail
|
||||
// the constraint check before emitting the access check
|
||||
// failures. The context is being presented constistently
|
||||
// in both cases.
|
||||
static_assert(C1<S>(), ""); // { dg-error "failed" }
|
||||
static_assert(C2<S>(), ""); // { dg-error "failed" }
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
// { dg-options "-std=c++1z" }
|
||||
|
||||
template<typename T>
|
||||
concept bool C()
|
||||
{
|
||||
return requires (T& t) { t.~T(); };
|
||||
}
|
||||
|
||||
class S1
|
||||
{
|
||||
~S1() { }
|
||||
};
|
||||
|
||||
class S2
|
||||
{
|
||||
~S2() = delete;
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
static_assert(C<S1>(), ""); // { dg-error "failed" }
|
||||
static_assert(C<S2>(), ""); // { dg-error "failed" }
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
// { dg-options -std=c++1z }
|
||||
|
||||
#ifndef __cpp_concepts
|
||||
#error __cpp_concepts not defined
|
||||
#endif
|
|
@ -0,0 +1,9 @@
|
|||
// { dg-options "-std=c++1z" }
|
||||
|
||||
template<typename T>
|
||||
concept bool Tuple() { // { dg-error "multiple statements" }
|
||||
static_assert(T::value, "");
|
||||
return true;
|
||||
}
|
||||
|
||||
void f(Tuple&);
|
|
@ -0,0 +1,7 @@
|
|||
// { dg-options "-std=c++1z" }
|
||||
|
||||
template<typename T>
|
||||
concept auto C1() { return 0; } // { dg-error "deduced return type" }
|
||||
|
||||
template<typename T>
|
||||
concept int C2() { return 0; } // { dg-error "return type" }
|
|
@ -0,0 +1,25 @@
|
|||
// { dg-options "-std=c++1z" }
|
||||
|
||||
template<typename T>
|
||||
concept bool C() { return __is_class(T); }
|
||||
|
||||
struct S { } s;
|
||||
|
||||
template<typename T>
|
||||
requires C<T>()
|
||||
void f(T x) { }
|
||||
|
||||
// Calls are valid when arguments are dependent,
|
||||
template<typename T>
|
||||
void g(T x) { f(x); }
|
||||
|
||||
// Calls are checked when arguments are non-dependent.
|
||||
template<typename T>
|
||||
void h(T x) {
|
||||
f(s);
|
||||
}
|
||||
|
||||
int main() {
|
||||
f(s);
|
||||
g(s);
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
// { dg-do compile }
|
||||
// { dg-options "-std=c++1z" }
|
||||
|
||||
// Test that constraint satisfaction checks work even when
|
||||
// processing template declarations.
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
||||
struct ostream { };
|
||||
ostream cout;
|
||||
|
||||
template<typename T>
|
||||
auto begin(T& t) -> decltype(t.begin()) { return t.begin(); }
|
||||
|
||||
template<typename T>
|
||||
auto begin(T const& t) -> decltype(t.begin()) { return t.begin(); }
|
||||
|
||||
template<typename T>
|
||||
auto end(T& t) -> decltype(t.end()) { return t.end(); }
|
||||
|
||||
template<typename T>
|
||||
auto end(T const& t) -> decltype(t.end()) { return t.end(); }
|
||||
|
||||
} // namespace std
|
||||
|
||||
|
||||
template <typename T>
|
||||
concept bool Float()
|
||||
{
|
||||
return __is_same_as( T, float );
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr decltype(auto) project( T t )
|
||||
{
|
||||
return t;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
concept bool Concept()
|
||||
{
|
||||
return requires( T t ) {
|
||||
requires Float<decltype( project(t) )>();
|
||||
};
|
||||
}
|
||||
|
||||
template <Concept E, Concept F>
|
||||
constexpr decltype(auto) operator<<( E&& e, F&& f ) {}
|
||||
|
||||
template <Concept T>
|
||||
void foo( T t )
|
||||
{
|
||||
// Try to resolve operator<< from within a template context but
|
||||
// with non-dependent arguments. We need to ensure that template
|
||||
// processing is turned off whenever checking for satisfaction.
|
||||
std::cout << "OK"; // { dg-error "no match" }
|
||||
}
|
||||
|
||||
|
||||
template <typename R>
|
||||
concept bool Range()
|
||||
{
|
||||
return requires( R r ) {
|
||||
requires __is_same_as(
|
||||
decltype(std::begin(r)), decltype(std::end(r)) );
|
||||
};
|
||||
}
|
||||
|
||||
struct A
|
||||
{
|
||||
A() = default;
|
||||
A( const A& ) = default;
|
||||
|
||||
// Derivation from this class forces the instantiation of
|
||||
// this constructor, which results in the __is_same_as type
|
||||
// trait above to become error_mark_node in this declaration.
|
||||
template <Range R>
|
||||
explicit A( R&& r ) { }
|
||||
};
|
||||
|
||||
struct C : A
|
||||
{
|
||||
C() = default;
|
||||
C( const C& ) = default;
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
C c; // OK
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
// { dg-options "-std=c++1z" }
|
||||
|
||||
template<typename T>
|
||||
concept bool C() { return __is_class(T); }
|
||||
|
||||
template<typename T>
|
||||
requires C<T>()
|
||||
void f(T x) { }
|
||||
|
||||
// Non-dependent args are checked even in dependent scope.
|
||||
template<typename T>
|
||||
void h(T x) {
|
||||
f(0); // { dg-error "cannot call" }
|
||||
}
|
||||
|
||||
int main() {
|
||||
f(0); // { dg-error "cannot call" }
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
// { dg-do run }
|
||||
// { dg-options "-std=c++1z" }
|
||||
|
||||
#include <cassert>
|
||||
|
||||
// Check partial ordering during overload resolution.
|
||||
|
||||
template<typename T>
|
||||
concept bool C() { return __is_class(T); }
|
||||
|
||||
template<typename T>
|
||||
concept bool D() { return C<T>() and __is_empty(T); }
|
||||
|
||||
struct S1 { } s1;
|
||||
struct S2 { int n; } s2;
|
||||
|
||||
int called = 0;
|
||||
|
||||
template<C T> void f1(T x) { called = 1;}
|
||||
template<D T> void f1(T x) { called = 2;}
|
||||
|
||||
int main() {
|
||||
f1(s1); assert(called == 2);
|
||||
f1(s2); assert(called == 1);
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
// { dg-options "-std=c++1z" }
|
||||
|
||||
template<typename T>
|
||||
concept bool C() { return __is_class(T); }
|
||||
|
||||
template<typename T>
|
||||
concept bool D() { return C<T>() and __is_empty(T); }
|
||||
|
||||
struct S1 { } s1;
|
||||
struct S2 { int n; } s2;
|
||||
|
||||
template<C T> void f1(T x) { }
|
||||
template<D T> void f1(T x) { }
|
||||
|
||||
int main() {
|
||||
f1(0); // { dg-error "matching" }
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
// { dg-options "-std=c++1z" }
|
||||
|
||||
// Check shorthand notation.
|
||||
|
||||
template<typename T>
|
||||
concept bool Type() { return true; }
|
||||
|
||||
template<typename T, typename U>
|
||||
concept bool Same() { return __is_same_as(T, U); }
|
||||
|
||||
template<Same<int> T> struct S1 { };
|
||||
template<typename T, Same<T> U> struct S2 { };
|
||||
|
||||
void f(Same<int> q) { }
|
||||
void g(Type a, Same<decltype(a)> b) { }
|
||||
|
||||
int main() {
|
||||
S1<char> s1; // { dg-error "constraint|invalid" }
|
||||
S2<int, char> s2; // { dg-error "constraint|invalid" }
|
||||
|
||||
f('a'); // { dg-error "cannot" }
|
||||
g(0, 'a'); // { dg-error "cannot" }
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
// { dg-options "-std=c++1z" }
|
||||
|
||||
// Redefinition errors.
|
||||
|
||||
template<typename T>
|
||||
concept bool C() { return __is_class(T); }
|
||||
|
||||
template<typename T>
|
||||
concept bool D() { return C<T>() and __is_empty(T); }
|
||||
|
||||
template<C T> void f(T x) { }
|
||||
template<typename T>
|
||||
requires C<T>()
|
||||
void f(T x) { } // { dg-error "redefinition" }
|
||||
|
||||
int main() { }
|
|
@ -0,0 +1,8 @@
|
|||
// { dg-do link }
|
||||
// { dg-options "-std=c++1z" }
|
||||
|
||||
// FIXME: What is this actually testing?
|
||||
|
||||
void f() requires true { }
|
||||
|
||||
int main() { }
|
|
@ -0,0 +1,27 @@
|
|||
// { dg-options "-std=c++1z" }
|
||||
|
||||
template<typename T>
|
||||
concept bool Class() { return __is_class(T); }
|
||||
|
||||
template<Class T> void f(T) { }
|
||||
|
||||
template<typename T> void fn(T) { }
|
||||
|
||||
auto p1 = &f<int>; // { dg-error "no matches" }
|
||||
void (*p2)(int) = &f<int>; // { dg-error "no matches" }
|
||||
void (*p3)(int) = &f; // { dg-error "no matches" }
|
||||
|
||||
struct S {
|
||||
template<Class T> int f(T) { }
|
||||
};
|
||||
|
||||
auto p4 = &S::template f<int>; // { dg-error "no matches" }
|
||||
int (S::*p6)(int) = &S::template f<int>; // { dg-error "no matches" }
|
||||
int (S::*p7)(int) = &S::f; // { dg-error "no matches" }
|
||||
|
||||
template<typename T>
|
||||
void g(T x) { }
|
||||
|
||||
int main () {
|
||||
g(&f<int>); // { dg-error "no matches" }
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
// { dg-do run }
|
||||
// { dg-options "-std=c++1z" }
|
||||
|
||||
#include <cassert>
|
||||
|
||||
template<typename T>
|
||||
concept bool Class() { return __is_class(T); }
|
||||
|
||||
template<typename T>
|
||||
concept bool Empty() { return Class<T>() and __is_empty(T); }
|
||||
|
||||
template<Class T> int f(T) { return 1; }
|
||||
template<Empty T> int f(T) { return 2; }
|
||||
|
||||
struct S {
|
||||
template<Class T> int f(T) { return 1; }
|
||||
template<Empty T> int f(T) { return 2; }
|
||||
} s;
|
||||
|
||||
struct X { } x;
|
||||
struct Y { X x; } y;
|
||||
|
||||
int main () {
|
||||
auto p1 = &f<X>; // Empty f
|
||||
assert(p1(x) == 2);
|
||||
|
||||
auto p2 = &f<Y>; // Class f
|
||||
assert(p2(y) == 1);
|
||||
|
||||
auto p3 = &S::template f<X>; // Empty f
|
||||
assert((s.*p3)(x) == 2);
|
||||
|
||||
auto p4 = &S::template f<Y>; // Empty f
|
||||
assert((s.*p4)(y) == 1);
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
// { dg-options "-std=c++1z" }
|
||||
|
||||
template<typename T>
|
||||
concept bool Eq() { return requires(T t) { t == t; }; }
|
||||
|
||||
struct Nt {
|
||||
template<Eq T> friend void f(T) { }
|
||||
} nt;
|
||||
|
||||
template<typename T> struct S;
|
||||
|
||||
template<Eq T>
|
||||
void proc(S<T>*);
|
||||
|
||||
template<typename T>
|
||||
struct S {
|
||||
friend bool operator==(S, S) requires Eq<T>() { return true; }
|
||||
|
||||
friend void proc<>(S*); // { dg-error "does not match any template declaration" }
|
||||
};
|
||||
|
||||
struct X { } x;
|
||||
|
||||
int main() {
|
||||
// f(0); // OK
|
||||
f(nt); // { dg-error "cannot call" }
|
||||
f(x); // { dg-error "not declared" }
|
||||
|
||||
S<int> si;
|
||||
si == si; // OK
|
||||
|
||||
S<X> sx;
|
||||
sx == sx; // { dg-error "no match" }
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
// { dg-options "-std=c++1z" }
|
||||
|
||||
template<typename T>
|
||||
concept bool Eq() { return requires(T t) { t == t; }; }
|
||||
|
||||
template<Eq T> struct Foo { };
|
||||
|
||||
template<typename T>
|
||||
struct S { // { dg-error "constraint failure" }
|
||||
template<Eq U> friend class Bar;
|
||||
|
||||
friend class Foo<T>;
|
||||
};
|
||||
|
||||
struct X { };
|
||||
|
||||
int main() {
|
||||
S<int> si; // OK
|
||||
S<X> sx;
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
// { dg-options "-std=c++1z" }
|
||||
|
||||
template<typename T>
|
||||
concept bool C() { return __is_class(T); }
|
||||
|
||||
template<int N>
|
||||
concept bool Int() { return true; }
|
||||
|
||||
template<template<typename> class X>
|
||||
concept bool Template() { return true; }
|
||||
|
||||
struct S { };
|
||||
|
||||
void f1(Int) { } // { dg-error "invalid" }
|
||||
void f2(Template) { } // { dg-error "invalid" }
|
||||
|
||||
struct S1 {
|
||||
void f1(auto x) { }
|
||||
void f2(C x) { }
|
||||
|
||||
void f3(auto x) { }
|
||||
void f3(C x) { }
|
||||
};
|
||||
|
||||
template<C T>
|
||||
struct S2 {
|
||||
void f1(auto x) { }
|
||||
void f2(C x) { }
|
||||
|
||||
void h1(auto x);
|
||||
void h2(C x);
|
||||
|
||||
template<C U>
|
||||
void g(T t, U u) { }
|
||||
};
|
||||
|
||||
int main() {
|
||||
S s;
|
||||
|
||||
S1 s1;
|
||||
s1.f2(0); // { dg-error "matching" }
|
||||
|
||||
S2<S> s2;
|
||||
s2.f2(0); // { dg-error "matching" }
|
||||
s2.h2(0); // { dg-error "matching" }
|
||||
|
||||
s2.g(s, 0); // { dg-error "matching" }
|
||||
s2.g(0, s); // { dg-error "matching" }
|
||||
}
|
|
@ -0,0 +1,157 @@
|
|||
// { dg-do run }
|
||||
// { dg-options "-std=c++1z" }
|
||||
|
||||
#include <cassert>
|
||||
#include <type_traits>
|
||||
|
||||
template<typename T>
|
||||
concept bool C() { return __is_class(T); }
|
||||
|
||||
template<typename T>
|
||||
concept bool Type() { return true; }
|
||||
|
||||
struct S { };
|
||||
|
||||
int called;
|
||||
|
||||
// Basic terse notation
|
||||
void f(auto x) { called = 1; }
|
||||
void g(C x) { called = 2; }
|
||||
|
||||
// Overloading generic functions
|
||||
void h(auto x) { called = 1; }
|
||||
void h(C x) { called = 2; }
|
||||
|
||||
void p(auto x);
|
||||
void p(C x);
|
||||
|
||||
struct S1 {
|
||||
void f1(auto x) { called = 1; }
|
||||
void f2(C x) { called = 2; }
|
||||
|
||||
void f3(auto x) { called = 1; }
|
||||
void f3(C x) { called = 2; }
|
||||
};
|
||||
|
||||
template<C T>
|
||||
struct S2 {
|
||||
void f1(auto x) { called = 1; }
|
||||
void f2(C x) { called = 2; }
|
||||
|
||||
void f3(auto x) { called = 1; }
|
||||
void f3(C x) { called = 2; }
|
||||
|
||||
void h1(auto x);
|
||||
void h2(C x);
|
||||
|
||||
void h3(auto x);
|
||||
void h3(C x);
|
||||
|
||||
template<C U>
|
||||
void g1(T t, U u) { called = 1; }
|
||||
|
||||
template<C U>
|
||||
void g2(T t, U u);
|
||||
};
|
||||
|
||||
|
||||
void ptr(C*) { called = 1; }
|
||||
void ptr(const C*) { called = 2; }
|
||||
|
||||
void ref(C&) { called = 1; }
|
||||
void ref(const C&) { called = 2; }
|
||||
|
||||
void
|
||||
fwd_lvalue_ref(Type&& x) {
|
||||
using T = decltype(x);
|
||||
static_assert(std::is_lvalue_reference<T>::value, "not an lvlaue reference");
|
||||
}
|
||||
|
||||
void
|
||||
fwd_const_lvalue_ref(Type&& x) {
|
||||
using T = decltype(x);
|
||||
static_assert(std::is_lvalue_reference<T>::value, "not an lvalue reference");
|
||||
using U = typename std::remove_reference<T>::type;
|
||||
static_assert(std::is_const<U>::value, "not const-qualified");
|
||||
}
|
||||
|
||||
void fwd_rvalue_ref(Type&& x) {
|
||||
using T = decltype(x);
|
||||
static_assert(std::is_rvalue_reference<T>::value, "not an rvalue reference");
|
||||
}
|
||||
|
||||
// Make sure we can use nested names speicifers for concept names.
|
||||
namespace N {
|
||||
template<typename T>
|
||||
concept bool C() { return true; }
|
||||
} // namesspace N
|
||||
|
||||
void foo(N::C x) { }
|
||||
|
||||
int main() {
|
||||
S s;
|
||||
const S cs;
|
||||
|
||||
f(0); assert(called == 1);
|
||||
g(s); assert(called == 2);
|
||||
|
||||
h(0); assert(called == 1);
|
||||
h(s); assert(called == 2);
|
||||
|
||||
S1 s1;
|
||||
s1.f1(0); assert(called == 1);
|
||||
s1.f2(s); assert(called == 2);
|
||||
|
||||
s1.f3(0); assert(called == 1);
|
||||
s1.f3(s); assert(called == 2);
|
||||
|
||||
S2<S> s2;
|
||||
s2.f1(0); assert(called == 1);
|
||||
s2.f2(s); assert(called == 2);
|
||||
|
||||
s2.f3(0); assert(called == 1);
|
||||
s2.f3(s); assert(called == 2);
|
||||
|
||||
s2.h1(0); assert(called == 1);
|
||||
s2.h2(s); assert(called == 2);
|
||||
|
||||
s2.h3(0); assert(called == 1);
|
||||
s2.h3(s); assert(called == 2);
|
||||
|
||||
s2.g1(s, s); assert(called == 1);
|
||||
s2.g2(s, s); assert(called == 2);
|
||||
|
||||
ptr(&s); assert(called == 1);
|
||||
ptr(&cs); assert(called == 2);
|
||||
|
||||
ref(s); assert(called == 1);
|
||||
ref(cs); assert(called == 2);
|
||||
|
||||
// Check forwarding problems
|
||||
fwd_lvalue_ref(s);
|
||||
fwd_const_lvalue_ref(cs);
|
||||
fwd_rvalue_ref(S());
|
||||
|
||||
foo(0);
|
||||
}
|
||||
|
||||
// Test that decl/def matching works.
|
||||
|
||||
void p(auto x) { called = 1; }
|
||||
void p(C x) { called = 2; }
|
||||
|
||||
template<C T>
|
||||
void S2<T>::h1(auto x) { called = 1; }
|
||||
|
||||
template<C T>
|
||||
void S2<T>::h2(C x) { called = 2; }
|
||||
|
||||
template<C T>
|
||||
void S2<T>::h3(auto x) { called = 1; }
|
||||
|
||||
template<C T>
|
||||
void S2<T>::h3(C x) { called = 2; }
|
||||
|
||||
template<C T>
|
||||
template<C U>
|
||||
void S2<T>::g2(T t, U u) { called = 2; }
|
|
@ -0,0 +1,22 @@
|
|||
// { dg-options "-std=c++1z" }
|
||||
|
||||
template<typename T>
|
||||
concept bool C() { return __is_class(T); }
|
||||
|
||||
template<typename T>
|
||||
struct S1 { S1(double) requires C<T>() { } };
|
||||
|
||||
struct S2 : S1<int> {
|
||||
using S1<int>::S1;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct S3 : S1<T> {
|
||||
using S1<T>::S1;
|
||||
};
|
||||
|
||||
struct X { };
|
||||
|
||||
int main() {
|
||||
S3<X> s(0.0);
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
// { dg-options "-std=c++1z" }
|
||||
|
||||
template<typename T>
|
||||
concept bool C() { return __is_class(T); }
|
||||
|
||||
template<typename T>
|
||||
struct S1 {
|
||||
S1(double) requires C<T>() { }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct S2 : S1<T> { // { dg-error "matching" }
|
||||
using S1<T>::S1;
|
||||
};
|
||||
|
||||
int main() {
|
||||
S2<int> s; // { dg-error "deleted function" }
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
// { dg-options "-std=c++1z" }
|
||||
|
||||
template<typename T>
|
||||
concept bool C() { return __is_class(T); }
|
||||
|
||||
template<typename T>
|
||||
struct S1 {
|
||||
template<C U>
|
||||
S1(U x) { }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct S2 : S1<T> {
|
||||
using S1<T>::S1;
|
||||
};
|
||||
|
||||
struct X { } x;
|
||||
|
||||
int main() {
|
||||
S2<X> s = x;
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
// { dg-options "-std=c++1z" }
|
||||
|
||||
template<typename T>
|
||||
concept bool C() { return __is_class(T); }
|
||||
|
||||
template<typename T>
|
||||
struct S1 {
|
||||
template<C U> S1(U x) { }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct S2 : S1<T> {
|
||||
using S1<T>::S1;
|
||||
};
|
||||
|
||||
int main() {
|
||||
S2<int> s(0); // { dg-error "no matching function" }
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
// { dg-options "-std=c++1z" }
|
||||
|
||||
template<typename T>
|
||||
concept bool C = __is_class(T);
|
||||
|
||||
C{T} void f1();
|
||||
|
||||
struct S1
|
||||
{
|
||||
C{T} void f2();
|
||||
C{T} static void f3();
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
S1 s;
|
||||
|
||||
f1<S1>();
|
||||
s.f2<S1>();
|
||||
S1::f3<S1>();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void f1() requires C<T>
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void S1::f2() requires C<T>
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void S1::f3() requires C<T>
|
||||
{
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
// { dg-do run }
|
||||
// { dg-options "-std=c++1z" }
|
||||
|
||||
#include <cassert>
|
||||
|
||||
template<typename T>
|
||||
concept bool C() { return __is_class(T); }
|
||||
|
||||
template<int N>
|
||||
concept bool P() { return true; }
|
||||
|
||||
C{A} struct S1
|
||||
{
|
||||
P{B} int f1();
|
||||
};
|
||||
|
||||
struct S2 {};
|
||||
|
||||
int main()
|
||||
{
|
||||
S1<S2> s;
|
||||
|
||||
assert(s.f1<10>() == sizeof(S2) + 10);
|
||||
return 0;
|
||||
}
|
||||
|
||||
C{A} P{B} int S1<A>::f1() { return B + sizeof(A); }
|
|
@ -0,0 +1,17 @@
|
|||
// { dg-options "-std=c++1z" }
|
||||
|
||||
template<typename ... T>
|
||||
concept bool C1 = true;
|
||||
|
||||
template<int ... N>
|
||||
concept bool C2 = true;
|
||||
|
||||
C1{...A} void f1() {};
|
||||
C2{...A} void f2() {};
|
||||
|
||||
int main()
|
||||
{
|
||||
f1<int, short, char>();
|
||||
f2<1, 2, 3>();
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
// { dg-options "-std=c++1z" }
|
||||
|
||||
template<typename ... T>
|
||||
concept bool C1 = true;
|
||||
|
||||
template<int ... N>
|
||||
concept bool C2 = true;
|
||||
|
||||
template<typename T>
|
||||
concept bool C3 = __is_class(T);
|
||||
|
||||
template<typename ... T>
|
||||
concept bool C4() { return true; }
|
||||
template<int N>
|
||||
concept bool C4() { return true; }
|
||||
|
||||
template<typename T, typename U = int>
|
||||
concept bool C5() { return __is_class(U); }
|
||||
|
||||
C1{...A, B} void f1() {}; // { dg-error "no matching|wrong number" }
|
||||
C1{A} void f2() {} // { dg-error "cannot match pack|no matching concept" }
|
||||
C2{A, B} void f3() {}; // { dg-error "cannot match pack|no matching concept" }
|
||||
C3{...A} void f4() {}; // { dg-error "cannot match pack|no matching concept" }
|
||||
C4{A} void f5() {}; // { dg-error "no matching concept" }
|
||||
C5{A, B} void f6() {};
|
||||
|
||||
int main()
|
||||
{
|
||||
// Defaults should not transfer
|
||||
f6<int>(); // { dg-error "no matching" }
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
// { dg-options "-std=c++1z" }
|
||||
|
||||
template<typename T, typename U = int>
|
||||
concept bool C()
|
||||
{
|
||||
return sizeof(U) == sizeof(int);
|
||||
}
|
||||
|
||||
C{A} void f1() {}
|
||||
|
||||
int main()
|
||||
{
|
||||
f1<char>();
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
// PR c++/67003
|
||||
// { dg-options "-std=c++1z" }
|
||||
|
||||
namespace X {
|
||||
template<class>
|
||||
concept bool C = true;
|
||||
}
|
||||
|
||||
X::C{T}
|
||||
void foo() {}
|
||||
|
||||
int main() { foo<int>(); }
|
|
@ -0,0 +1,13 @@
|
|||
// PR c++/66985
|
||||
// { dg-options "-std=c++1z" }
|
||||
|
||||
template <template <class> class T>
|
||||
concept bool _Valid = requires { typename T<int>; };
|
||||
|
||||
template <template <class> class T>
|
||||
struct __defer { };
|
||||
|
||||
_Valid{T}
|
||||
struct __defer<T> {
|
||||
using type = T<int>;
|
||||
};
|
|
@ -0,0 +1,9 @@
|
|||
// { dg-options "-std=c++1z" }
|
||||
|
||||
struct Base {
|
||||
template<typename T>
|
||||
static concept bool D() { return __is_same_as(T, int); } // { dg-error "a concept cannot be a member function" }
|
||||
|
||||
template<typename T, typename U>
|
||||
static concept bool E() { return __is_same_as(T, U); } // { dg-error "a concept cannot be a member function" }
|
||||
};
|
|
@ -0,0 +1,37 @@
|
|||
// { dg-do run}
|
||||
// { dg-options "-std=c++1z" }
|
||||
|
||||
|
||||
template<typename T>
|
||||
concept bool C() { return __is_class(T); }
|
||||
|
||||
template<typename T>
|
||||
concept bool D() { return __is_empty(T); }
|
||||
|
||||
struct X { } x;
|
||||
struct Y { int n; } y;
|
||||
|
||||
int called = 0;
|
||||
|
||||
// Test constrained member definitions
|
||||
template<typename T>
|
||||
struct S1 {
|
||||
void f1() requires C<T>() { }
|
||||
void g1() requires C<T>() and true;
|
||||
template<C U> void h1(U u) { called = 1; }
|
||||
|
||||
void g2() requires C<T>(); // { dg-error "candidate" }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
void S1<T>::g2() requires D<T>() { } // { dg-error "prototype" }
|
||||
|
||||
int main() {
|
||||
S1<X> sx;
|
||||
S1<Y> sy;
|
||||
S1<int> si;
|
||||
|
||||
si.f1(); // { dg-error "matching" }
|
||||
si.g1(); // { dg-error "matching" }
|
||||
si.h1(0); // { dg-error "matching" }
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
// { dg-do run}
|
||||
// { dg-options "-std=c++1z" }
|
||||
|
||||
#include <cassert>
|
||||
|
||||
template<typename T>
|
||||
concept bool C() { return __is_class(T); }
|
||||
|
||||
template<typename T>
|
||||
concept bool D() { return __is_empty(T); }
|
||||
|
||||
struct X { } x;
|
||||
struct Y { int n; } y;
|
||||
|
||||
int called = 0;
|
||||
|
||||
// Test constrained member definitions
|
||||
template<typename T>
|
||||
struct S1 {
|
||||
void f1() requires C<T>() { }
|
||||
|
||||
void f2() requires C<T>() { called = 1; }
|
||||
void f2() requires not C<T>() { called = 2; }
|
||||
|
||||
void f3() { called = 1; }
|
||||
void f3() requires C<T>() { called = 2; }
|
||||
void f3() requires C<T>() and D<T>() { called = 3; }
|
||||
|
||||
void g1() requires C<T>() and true;
|
||||
|
||||
void g2() requires C<T>();
|
||||
void g2() requires not C<T>();
|
||||
|
||||
void g3();
|
||||
void g3() requires C<T>();
|
||||
void g3() requires C<T>() and D<T>();
|
||||
|
||||
template<C U> void h1(U u) { called = 1; }
|
||||
template<C U> void h2(U u);
|
||||
template<C U> void h3(U u) requires D<U>();
|
||||
};
|
||||
|
||||
template<C T>
|
||||
struct S2 {
|
||||
void f(T) requires D<T>();
|
||||
};
|
||||
|
||||
|
||||
int main() {
|
||||
S1<X> sx;
|
||||
S1<Y> sy;
|
||||
S1<int> si;
|
||||
|
||||
// Defined in-class
|
||||
sx.f1();
|
||||
sx.f2(); assert(called == 1);
|
||||
sx.f3(); assert(called == 3);
|
||||
|
||||
sy.f1();
|
||||
sy.f2(); assert(called == 1);
|
||||
sy.f3(); assert(called == 2);
|
||||
|
||||
si.f2(); assert(called == 2);
|
||||
si.f3(); assert(called == 1);
|
||||
|
||||
// Member function template tests
|
||||
S1<int> s1i;
|
||||
s1i.h1(x); assert(called == 1);
|
||||
s1i.h2(x); assert(called == 2);
|
||||
s1i.h3(x); assert(called == 3);
|
||||
|
||||
// Defined out of class.
|
||||
sx.g1();
|
||||
sx.g2(); assert(called == 1);
|
||||
sx.g3(); assert(called == 3);
|
||||
|
||||
sy.g1();
|
||||
sy.g2(); assert(called == 1);
|
||||
sy.g3(); assert(called == 2);
|
||||
|
||||
si.g2(); assert(called == 2);
|
||||
si.g3(); assert(called == 1);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void S1<T>::g1() requires C<T>() and true { }
|
||||
|
||||
template<typename T>
|
||||
void S1<T>::g2() requires C<T>() { called = 1; }
|
||||
|
||||
template<typename T>
|
||||
void S1<T>::g2() requires not C<T>() { called = 2; }
|
||||
|
||||
template<typename T>
|
||||
void S1<T>::g3() { called = 1; }
|
||||
|
||||
template<typename T>
|
||||
void S1<T>::g3() requires C<T>() { called = 2; }
|
||||
|
||||
template<typename T>
|
||||
void S1<T>::g3() requires C<T>() and D<T>() { called = 3; }
|
||||
|
||||
template<typename T>
|
||||
template<C U>
|
||||
void S1<T>::h2(U u) { called = 2; }
|
||||
|
||||
template<typename T>
|
||||
template<C U>
|
||||
void S1<T>::h3(U u) requires D<U>() { called = 3; }
|
||||
|
||||
template<C T>
|
||||
void S2<T>::f(T t) requires D<T>() { called = 4; }
|
|
@ -0,0 +1,33 @@
|
|||
// { dg-options "-std=c++1z" }
|
||||
|
||||
template<typename T>
|
||||
concept bool Type() { return true; }
|
||||
|
||||
template<typename T, typename U>
|
||||
concept bool Same() { return __is_same_as(T, U); }
|
||||
|
||||
template<typename T, typename U>
|
||||
concept bool C1() { return true; }
|
||||
|
||||
template<typename T, typename... Args>
|
||||
concept bool C2() { return true; }
|
||||
|
||||
template<Same<int> T> struct S1 { };
|
||||
template<typename T, Same<T> U> struct S2 { };
|
||||
|
||||
void f(Same<int> q) { }
|
||||
void g(Type a, Same<decltype(a)> b) { }
|
||||
|
||||
void h0(Same<int>* a) { }
|
||||
void h1(C1<int>* a) { }
|
||||
void h2(C2<char, short, int, long>* a) { }
|
||||
|
||||
int main() {
|
||||
S1<int> s1;
|
||||
S2<int, int> s2;
|
||||
f(0);
|
||||
g(0, 1);
|
||||
h0((int*)0);
|
||||
h1((int*)0);
|
||||
h2((int*)0);
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
// { dg-options "-std=c++1z" }
|
||||
|
||||
// Make sure that we check partial concept ids
|
||||
// with variable concepts.
|
||||
|
||||
template<class A, class B>
|
||||
concept bool C = true;
|
||||
|
||||
template<C<int> D>
|
||||
struct E
|
||||
{
|
||||
int f = 0;
|
||||
};
|
||||
|
||||
E<double> e;
|
|
@ -0,0 +1,15 @@
|
|||
// { dg-options "-std=c++1z" }
|
||||
|
||||
// Check that constraints don't break unconstrained partial
|
||||
// specializations.
|
||||
|
||||
template<typename T>
|
||||
struct S { };
|
||||
|
||||
template<typename T>
|
||||
struct S<T*> { };
|
||||
|
||||
template<>
|
||||
struct S<int> { };
|
||||
|
||||
int main() { }
|
|
@ -0,0 +1,32 @@
|
|||
// PR c++/67084
|
||||
// { dg-options -std=c++1z }
|
||||
|
||||
template <class T>
|
||||
constexpr bool p = false;
|
||||
|
||||
template <class T>
|
||||
constexpr bool p<T*> = false;
|
||||
|
||||
template <class T>
|
||||
requires true
|
||||
constexpr bool p<T*> = false;
|
||||
|
||||
template <class T>
|
||||
requires true && T() == 0
|
||||
constexpr bool p<T*> = true;
|
||||
|
||||
template <class T>
|
||||
constexpr bool q = false;
|
||||
|
||||
template <class T>
|
||||
constexpr bool q<T*> = true;
|
||||
|
||||
template <class T>
|
||||
requires false
|
||||
constexpr bool q<T*> = false;
|
||||
|
||||
template <class T>
|
||||
requires false && T() != 0
|
||||
constexpr bool q<T*> = false;
|
||||
|
||||
static_assert (p<int*>,"");
|
|
@ -0,0 +1,7 @@
|
|||
// { dg-options -std=c++1z }
|
||||
|
||||
template <class T> struct A { };
|
||||
template <class T> requires false struct A<T*> { };
|
||||
template <class T> struct A<T*> { static int i; };
|
||||
|
||||
int i = A<int*>::i;
|
|
@ -0,0 +1,49 @@
|
|||
// { dg-options -std=c++1z }
|
||||
|
||||
template <class T> concept bool is_int = __is_same_as(T,int);
|
||||
|
||||
template <class T> struct A { };
|
||||
template <is_int T> struct A<T*> {
|
||||
typedef int I1;
|
||||
static const A<T*>::I1 j1 = 0;
|
||||
static int f();
|
||||
};
|
||||
template <is_int T> int A<T*>::f()
|
||||
{ A<T*>::I1 i; return j1; }
|
||||
|
||||
template <class T> struct A<T*> {
|
||||
typedef int I2;
|
||||
static const A<T*>::I2 j2 = 0;
|
||||
static int f();
|
||||
};
|
||||
template <class T> int A<T*>::f()
|
||||
{ A<T*>::I2 i; return j2; }
|
||||
|
||||
const int i1 = A<int*>::j1;
|
||||
const int i2 = A<float*>::j2;
|
||||
|
||||
template <class T> struct B;
|
||||
|
||||
template <is_int T> struct B<T> {
|
||||
typedef int I4;
|
||||
static const B<T>::I4 j4 = 0;
|
||||
static int f();
|
||||
};
|
||||
template <is_int T> int B<T>::f()
|
||||
{ B<T>::I4 i; return j4; }
|
||||
|
||||
template <class T> struct B {
|
||||
typedef int I5;
|
||||
static const B<T>::I5 j5 = 0;
|
||||
static int f();
|
||||
};
|
||||
template <class T> int B<T>::f()
|
||||
{ B<T>::I5 i; return j5; }
|
||||
|
||||
int i4 = B<int>::j4;
|
||||
int i5 = B<float>::j5;
|
||||
int main()
|
||||
{
|
||||
B<int>::f();
|
||||
B<float>::f();
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue