mirror of git://gcc.gnu.org/git/gcc.git
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>
|
2015-08-02 Patrick Palka <ppalka@gcc.gnu.org>
|
||||||
|
|
||||||
* c-indentation.c (should_warn_for_misleading_indentation):
|
* 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_literal_type", RID_IS_LITERAL_TYPE, D_CXXONLY },
|
||||||
{ "__is_pod", RID_IS_POD, D_CXXONLY },
|
{ "__is_pod", RID_IS_POD, D_CXXONLY },
|
||||||
{ "__is_polymorphic", RID_IS_POLYMORPHIC, 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_standard_layout", RID_IS_STD_LAYOUT, D_CXXONLY },
|
||||||
{ "__is_trivial", RID_IS_TRIVIAL, D_CXXONLY },
|
{ "__is_trivial", RID_IS_TRIVIAL, D_CXXONLY },
|
||||||
{ "__is_trivially_assignable", RID_IS_TRIVIALLY_ASSIGNABLE, 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 },
|
{ "volatile", RID_VOLATILE, 0 },
|
||||||
{ "wchar_t", RID_WCHAR, D_CXXONLY },
|
{ "wchar_t", RID_WCHAR, D_CXXONLY },
|
||||||
{ "while", RID_WHILE, 0 },
|
{ "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
|
/* These Objective-C keywords are recognized only immediately after
|
||||||
an '@'. */
|
an '@'. */
|
||||||
{ "compatibility_alias", RID_AT_ALIAS, D_OBJC },
|
{ "compatibility_alias", RID_AT_ALIAS, D_OBJC },
|
||||||
|
|
|
||||||
|
|
@ -142,6 +142,7 @@ enum rid
|
||||||
RID_IS_EMPTY, RID_IS_ENUM,
|
RID_IS_EMPTY, RID_IS_ENUM,
|
||||||
RID_IS_FINAL, RID_IS_LITERAL_TYPE,
|
RID_IS_FINAL, RID_IS_LITERAL_TYPE,
|
||||||
RID_IS_POD, RID_IS_POLYMORPHIC,
|
RID_IS_POD, RID_IS_POLYMORPHIC,
|
||||||
|
RID_IS_SAME_AS,
|
||||||
RID_IS_STD_LAYOUT, RID_IS_TRIVIAL,
|
RID_IS_STD_LAYOUT, RID_IS_TRIVIAL,
|
||||||
RID_IS_TRIVIALLY_ASSIGNABLE, RID_IS_TRIVIALLY_CONSTRUCTIBLE,
|
RID_IS_TRIVIALLY_ASSIGNABLE, RID_IS_TRIVIALLY_CONSTRUCTIBLE,
|
||||||
RID_IS_TRIVIALLY_COPYABLE,
|
RID_IS_TRIVIALLY_COPYABLE,
|
||||||
|
|
@ -150,6 +151,9 @@ enum rid
|
||||||
/* C++11 */
|
/* C++11 */
|
||||||
RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
|
RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
|
||||||
|
|
||||||
|
/* C++ concepts */
|
||||||
|
RID_CONCEPT, RID_REQUIRES,
|
||||||
|
|
||||||
/* Cilk Plus keywords. */
|
/* Cilk Plus keywords. */
|
||||||
RID_CILK_SPAWN, RID_CILK_SYNC, RID_CILK_FOR,
|
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_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_CXX_OBJC 0x100 /* In Objective C, and C++, but not C. */
|
||||||
#define D_CXXWARN 0x200 /* In C warn with -Wcxx-compat. */
|
#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. */
|
/* The reserved keyword table. */
|
||||||
extern const struct c_common_resword c_common_reswords[];
|
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_variable_templates=201304");
|
||||||
cpp_define (pfile, "__cpp_digit_separators=201309");
|
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)
|
if (flag_sized_deallocation)
|
||||||
cpp_define (pfile, "__cpp_sized_deallocation=201309");
|
cpp_define (pfile, "__cpp_sized_deallocation=201309");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1558,6 +1558,8 @@ set_std_cxx1z (int iso)
|
||||||
/* C++11 includes the C99 standard library. */
|
/* C++11 includes the C99 standard library. */
|
||||||
flag_isoc94 = 1;
|
flag_isoc94 = 1;
|
||||||
flag_isoc99 = 1;
|
flag_isoc99 = 1;
|
||||||
|
/* Enable concepts by default. */
|
||||||
|
flag_concepts = 1;
|
||||||
flag_isoc11 = 1;
|
flag_isoc11 = 1;
|
||||||
cxx_dialect = cxx1z;
|
cxx_dialect = cxx1z;
|
||||||
lang_hooks.name = "GNU C++14"; /* Pretend C++14 till standarization. */
|
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)
|
C ObjC C++ ObjC++ LTO Report Var(flag_cilkplus) Init(0)
|
||||||
Enable Cilk Plus
|
Enable Cilk Plus
|
||||||
|
|
||||||
|
fconcepts
|
||||||
|
C++ ObjC++ Var(flag_concepts)
|
||||||
|
Enable support for C++ concepts
|
||||||
|
|
||||||
fcond-mismatch
|
fcond-mismatch
|
||||||
C ObjC C++ ObjC++
|
C ObjC C++ ObjC++
|
||||||
Allow the arguments of the '?' operator to have different types
|
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>
|
2015-08-06 Jason Merrill <jason@redhat.com>
|
||||||
|
|
||||||
PR c++/66533
|
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/mangle.o cp/cp-objcp-common.o cp/name-lookup.o cp/cxx-pretty-print.o \
|
||||||
cp/cp-cilkplus.o \
|
cp/cp-cilkplus.o \
|
||||||
cp/cp-gimplify.o cp/cp-array-notation.o cp/lambda.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++.
|
# Language-specific object files for C++.
|
||||||
CXX_OBJS = cp/cp-lang.o c-family/stub-objc.o $(CXX_AND_OBJCXX_OBJS)
|
CXX_OBJS = cp/cp-lang.o c-family/stub-objc.o $(CXX_AND_OBJCXX_OBJS)
|
||||||
|
|
@ -131,7 +132,7 @@ c++.srcinfo:
|
||||||
c++.srcextra:
|
c++.srcextra:
|
||||||
|
|
||||||
c++.tags: force
|
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; \
|
--regex='/DEFTREECODE [(]\([A-Z_]+\)/\1/' cp-tree.def; \
|
||||||
etags --include TAGS.sub --include ../TAGS.sub
|
etags --include TAGS.sub --include ../TAGS.sub
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -425,7 +425,8 @@ enum rejection_reason_code {
|
||||||
rr_arg_conversion,
|
rr_arg_conversion,
|
||||||
rr_bad_arg_conversion,
|
rr_bad_arg_conversion,
|
||||||
rr_template_unification,
|
rr_template_unification,
|
||||||
rr_invalid_copy
|
rr_invalid_copy,
|
||||||
|
rr_constraint_failure
|
||||||
};
|
};
|
||||||
|
|
||||||
struct conversion_info {
|
struct conversion_info {
|
||||||
|
|
@ -688,6 +689,27 @@ invalid_copy_with_fn_template_rejection (void)
|
||||||
return r;
|
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. */
|
/* Dynamically allocate a conversion. */
|
||||||
|
|
||||||
static conversion *
|
static conversion *
|
||||||
|
|
@ -1957,10 +1979,20 @@ add_function_candidate (struct z_candidate **candidates,
|
||||||
viable = 0;
|
viable = 0;
|
||||||
reason = arity_rejection (first_arg, i + remaining, len);
|
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
|
/* When looking for a function from a subobject from an implicit
|
||||||
copy/move constructor/operator=, don't consider anything that takes (a
|
copy/move constructor/operator=, don't consider anything that takes (a
|
||||||
reference to) an unrelated type. See c++/44909 and core 1092. */
|
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))
|
if (DECL_CONSTRUCTOR_P (fn))
|
||||||
i = 1;
|
i = 1;
|
||||||
|
|
@ -1984,7 +2016,7 @@ add_function_candidate (struct z_candidate **candidates,
|
||||||
if (! viable)
|
if (! viable)
|
||||||
goto out;
|
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
|
argument an implicit conversion sequence that converts that argument
|
||||||
to the corresponding parameter of F. */
|
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 "
|
" a constructor taking a single argument of its own "
|
||||||
"class type is invalid");
|
"class type is invalid");
|
||||||
break;
|
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:
|
case rr_none:
|
||||||
default:
|
default:
|
||||||
/* This candidate didn't have any issues or we failed to
|
/* 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 (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
|
if (!any_viable_p && candidates && ! candidates->next
|
||||||
&& (TREE_CODE (candidates->fn) == FUNCTION_DECL))
|
&& (TREE_CODE (candidates->fn) == FUNCTION_DECL))
|
||||||
return cp_build_function_call_vec (candidates->fn, args, complain);
|
return cp_build_function_call_vec (candidates->fn, args, complain);
|
||||||
|
|
||||||
|
// Otherwise, emit notes for non-viable candidates.
|
||||||
if (TREE_CODE (fn) == TEMPLATE_ID_EXPR)
|
if (TREE_CODE (fn) == TEMPLATE_ID_EXPR)
|
||||||
fn = TREE_OPERAND (fn, 0);
|
fn = TREE_OPERAND (fn, 0);
|
||||||
print_error_for_call_failure (fn, *args, candidates);
|
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
|
through flags so that later we can use it to decide whether to warn
|
||||||
about peculiar null pointer conversion. */
|
about peculiar null pointer conversion. */
|
||||||
if (TREE_CODE (fn) == TEMPLATE_ID_EXPR)
|
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);
|
result = build_over_call (cand, flags, complain);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -9095,6 +9157,15 @@ joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn,
|
||||||
return winner;
|
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
|
/* Check whether we can discard a builtin candidate, either because we
|
||||||
have two identical ones or matching builtin and non-builtin candidates.
|
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)
|
if (compparms (parms1, parms2)
|
||||||
&& (!DECL_CONV_FN_P (fn)
|
&& (!DECL_CONV_FN_P (fn)
|
||||||
|| same_type_p (TREE_TYPE (fn_type),
|
|| 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
|
/* For function versions, their parms and types match
|
||||||
but they are not duplicates. Record function versions
|
but they are not duplicates. Record function versions
|
||||||
|
|
@ -4602,6 +4603,14 @@ build_clone (tree fn, tree name)
|
||||||
TREE_TYPE (clone) = TREE_TYPE (result);
|
TREE_TYPE (clone) = TREE_TYPE (result);
|
||||||
return clone;
|
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);
|
SET_DECL_ASSEMBLER_NAME (clone, NULL_TREE);
|
||||||
DECL_CLONED_FUNCTION (clone) = fn;
|
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
|
/* 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)
|
currently_open_class (tree t)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (!CLASS_TYPE_P (t))
|
if (!CLASS_TYPE_P (t))
|
||||||
return false;
|
return NULL_TREE;
|
||||||
|
|
||||||
t = TYPE_MAIN_VARIANT (t);
|
t = TYPE_MAIN_VARIANT (t);
|
||||||
|
|
||||||
|
|
@ -7309,9 +7320,9 @@ currently_open_class (tree t)
|
||||||
if (!c)
|
if (!c)
|
||||||
continue;
|
continue;
|
||||||
if (same_type_p (c, t))
|
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
|
/* 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. */
|
/* Instantiation failed. */
|
||||||
continue;
|
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. */
|
/* And now force instantiation to do return type deduction. */
|
||||||
if (undeduced_auto_decl (instantiation))
|
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);
|
non_constant_p, overflow_p, jump_target);
|
||||||
break;
|
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:
|
default:
|
||||||
if (STATEMENT_CODE_P (TREE_CODE (t)))
|
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 PLACEHOLDER_EXPR:
|
||||||
case BREAK_STMT:
|
case BREAK_STMT:
|
||||||
case CONTINUE_STMT:
|
case CONTINUE_STMT:
|
||||||
|
case REQUIRES_EXPR:
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case AGGR_INIT_EXPR:
|
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 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 USERDEF_LITERAL: return sizeof (struct tree_userdef_literal);
|
||||||
|
|
||||||
case TEMPLATE_DECL: return sizeof (struct tree_template_decl);
|
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_NON_COMMON (USING_DECL);
|
||||||
MARK_TS_DECL_COMMON (TEMPLATE_DECL);
|
MARK_TS_DECL_COMMON (TEMPLATE_DECL);
|
||||||
|
MARK_TS_DECL_COMMON (WILDCARD_DECL);
|
||||||
|
|
||||||
MARK_TS_COMMON (TEMPLATE_TEMPLATE_PARM);
|
MARK_TS_COMMON (TEMPLATE_TEMPLATE_PARM);
|
||||||
MARK_TS_COMMON (TEMPLATE_TYPE_PARM);
|
MARK_TS_COMMON (TEMPLATE_TYPE_PARM);
|
||||||
|
|
@ -311,6 +314,7 @@ cp_common_init_ts (void)
|
||||||
MARK_TS_TYPED (LAMBDA_EXPR);
|
MARK_TS_TYPED (LAMBDA_EXPR);
|
||||||
MARK_TS_TYPED (CTOR_INITIALIZER);
|
MARK_TS_TYPED (CTOR_INITIALIZER);
|
||||||
MARK_TS_TYPED (ARRAY_NOTATION_REF);
|
MARK_TS_TYPED (ARRAY_NOTATION_REF);
|
||||||
|
MARK_TS_TYPED (REQUIRES_EXPR);
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "gt-cp-cp-objcp-common.h"
|
#include "gt-cp-cp-objcp-common.h"
|
||||||
|
|
|
||||||
|
|
@ -475,6 +475,94 @@ DEFTREECODE (BASES, "bases", tcc_type, 0)
|
||||||
instantiation time. */
|
instantiation time. */
|
||||||
DEFTREECODE (TEMPLATE_INFO, "template_info", tcc_exceptional, 0)
|
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:
|
Local variables:
|
||||||
mode:c
|
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)
|
PACK_EXPANSION_LOCAL_P (in *_PACK_EXPANSION)
|
||||||
TINFO_HAS_ACCESS_ERRORS (in TEMPLATE_INFO)
|
TINFO_HAS_ACCESS_ERRORS (in TEMPLATE_INFO)
|
||||||
SIZEOF_EXPR_TYPE_P (in SIZEOF_EXPR)
|
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)
|
BLOCK_OUTER_CURLY_BRACE_P (in BLOCK)
|
||||||
1: IDENTIFIER_VIRTUAL_P (in IDENTIFIER_NODE)
|
1: IDENTIFIER_VIRTUAL_P (in IDENTIFIER_NODE)
|
||||||
TI_PENDING_TEMPLATE_FLAG.
|
TI_PENDING_TEMPLATE_FLAG.
|
||||||
|
|
@ -154,6 +156,7 @@ c-common.h, not after.
|
||||||
LABEL_DECL_CONTINUE (in LABEL_DECL)
|
LABEL_DECL_CONTINUE (in LABEL_DECL)
|
||||||
2: DECL_THIS_EXTERN (in VAR_DECL or FUNCTION_DECL).
|
2: DECL_THIS_EXTERN (in VAR_DECL or FUNCTION_DECL).
|
||||||
DECL_IMPLICIT_TYPEDEF_P (in a TYPE_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)
|
TEMPLATE_DECL_COMPLEX_ALIAS_P (in TEMPLATE_DECL)
|
||||||
DECL_INSTANTIATING_NSDMI_P (in a FIELD_DECL)
|
DECL_INSTANTIATING_NSDMI_P (in a FIELD_DECL)
|
||||||
3: DECL_IN_AGGR_P.
|
3: DECL_IN_AGGR_P.
|
||||||
|
|
@ -660,6 +663,7 @@ typedef enum cp_trait_kind
|
||||||
CPTK_IS_LITERAL_TYPE,
|
CPTK_IS_LITERAL_TYPE,
|
||||||
CPTK_IS_POD,
|
CPTK_IS_POD,
|
||||||
CPTK_IS_POLYMORPHIC,
|
CPTK_IS_POLYMORPHIC,
|
||||||
|
CPTK_IS_SAME_AS,
|
||||||
CPTK_IS_STD_LAYOUT,
|
CPTK_IS_STD_LAYOUT,
|
||||||
CPTK_IS_TRIVIAL,
|
CPTK_IS_TRIVIAL,
|
||||||
CPTK_IS_TRIVIALLY_ASSIGNABLE,
|
CPTK_IS_TRIVIALLY_ASSIGNABLE,
|
||||||
|
|
@ -812,6 +816,154 @@ struct GTY(()) tree_template_info {
|
||||||
vec<qualified_typedef_usage_t, va_gc> *typedefs_needing_access_checking;
|
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 {
|
enum cp_tree_node_structure_enum {
|
||||||
TS_CP_GENERIC,
|
TS_CP_GENERIC,
|
||||||
TS_CP_IDENTIFIER,
|
TS_CP_IDENTIFIER,
|
||||||
|
|
@ -829,6 +981,7 @@ enum cp_tree_node_structure_enum {
|
||||||
TS_CP_TRAIT_EXPR,
|
TS_CP_TRAIT_EXPR,
|
||||||
TS_CP_LAMBDA_EXPR,
|
TS_CP_LAMBDA_EXPR,
|
||||||
TS_CP_TEMPLATE_INFO,
|
TS_CP_TEMPLATE_INFO,
|
||||||
|
TS_CP_CONSTRAINT_INFO,
|
||||||
TS_CP_USERDEF_LITERAL,
|
TS_CP_USERDEF_LITERAL,
|
||||||
LAST_TS_CP_ENUM
|
LAST_TS_CP_ENUM
|
||||||
};
|
};
|
||||||
|
|
@ -856,6 +1009,8 @@ union GTY((desc ("cp_tree_node_structure (&%h)"),
|
||||||
lambda_expression;
|
lambda_expression;
|
||||||
struct tree_template_info GTY ((tag ("TS_CP_TEMPLATE_INFO")))
|
struct tree_template_info GTY ((tag ("TS_CP_TEMPLATE_INFO")))
|
||||||
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")))
|
struct tree_userdef_literal GTY ((tag ("TS_CP_USERDEF_LITERAL")))
|
||||||
userdef_literal;
|
userdef_literal;
|
||||||
};
|
};
|
||||||
|
|
@ -2021,7 +2176,8 @@ struct GTY(()) lang_decl_base {
|
||||||
unsigned template_conv_p : 1; /* var or template */
|
unsigned template_conv_p : 1; /* var or template */
|
||||||
unsigned odr_used : 1; /* var or fn */
|
unsigned odr_used : 1; /* var or fn */
|
||||||
unsigned u2sel : 1;
|
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. */
|
/* True for DECL codes which have template info and access. */
|
||||||
|
|
@ -2569,6 +2725,12 @@ struct GTY(()) lang_decl {
|
||||||
#define DECL_DECLARED_CONSTEXPR_P(DECL) \
|
#define DECL_DECLARED_CONSTEXPR_P(DECL) \
|
||||||
DECL_LANG_FLAG_8 (VAR_OR_FUNCTION_DECL_CHECK (STRIP_TEMPLATE (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
|
/* Nonzero if this DECL is the __PRETTY_FUNCTION__ variable in a
|
||||||
template function. */
|
template function. */
|
||||||
#define DECL_PRETTY_FUNCTION_P(NODE) \
|
#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. */
|
/* True iff this pack expansion is within a function context. */
|
||||||
#define PACK_EXPANSION_LOCAL_P(NODE) TREE_LANG_FLAG_0 (NODE)
|
#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. */
|
/* Determine if this is an argument pack. */
|
||||||
#define ARGUMENT_PACK_P(NODE) \
|
#define ARGUMENT_PACK_P(NODE) \
|
||||||
(TREE_CODE (NODE) == TYPE_ARGUMENT_PACK \
|
(TREE_CODE (NODE) == TYPE_ARGUMENT_PACK \
|
||||||
|
|
@ -4504,6 +4669,15 @@ extern int comparing_specializations;
|
||||||
|
|
||||||
extern int cp_unevaluated_operand;
|
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 */
|
/* in pt.c */
|
||||||
|
|
||||||
/* These values are used for the `STRICT' parameter to type_unification and
|
/* These values are used for the `STRICT' parameter to type_unification and
|
||||||
|
|
@ -4516,6 +4690,17 @@ typedef enum unification_kind_t {
|
||||||
DEDUCE_EXACT
|
DEDUCE_EXACT
|
||||||
} unification_kind_t;
|
} 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 */
|
/* in class.c */
|
||||||
|
|
||||||
extern int current_class_depth;
|
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) \
|
#define TEMPLATE_TYPE_PARAMETER_PACK(NODE) \
|
||||||
(TEMPLATE_PARM_PARAMETER_PACK (TEMPLATE_TYPE_PARM_INDEX (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). */
|
/* True iff this TEMPLATE_TYPE_PARM represents decltype(auto). */
|
||||||
#define AUTO_IS_DECLTYPE(NODE) \
|
#define AUTO_IS_DECLTYPE(NODE) \
|
||||||
(TYPE_LANG_FLAG_5 (TEMPLATE_TYPE_PARM_CHECK (NODE)))
|
(TYPE_LANG_FLAG_5 (TEMPLATE_TYPE_PARM_CHECK (NODE)))
|
||||||
|
|
@ -4963,6 +5159,7 @@ typedef enum cp_decl_spec {
|
||||||
ds_std_attribute,
|
ds_std_attribute,
|
||||||
ds_storage_class,
|
ds_storage_class,
|
||||||
ds_long_long,
|
ds_long_long,
|
||||||
|
ds_concept,
|
||||||
ds_last /* This enumerator must always be the last one. */
|
ds_last /* This enumerator must always be the last one. */
|
||||||
} cp_decl_spec;
|
} cp_decl_spec;
|
||||||
|
|
||||||
|
|
@ -5092,6 +5289,8 @@ struct cp_declarator {
|
||||||
tree exception_specification;
|
tree exception_specification;
|
||||||
/* The late-specified return type, if any. */
|
/* The late-specified return type, if any. */
|
||||||
tree late_return_type;
|
tree late_return_type;
|
||||||
|
/* The trailing requires-clause, if any. */
|
||||||
|
tree requires_clause;
|
||||||
} function;
|
} function;
|
||||||
/* For arrays. */
|
/* For arrays. */
|
||||||
struct {
|
struct {
|
||||||
|
|
@ -5157,7 +5356,7 @@ class_of_this_parm (const_tree fntype)
|
||||||
return TREE_TYPE (type_of_this_parm (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
|
inline bool
|
||||||
variable_template_p (tree t)
|
variable_template_p (tree t)
|
||||||
{
|
{
|
||||||
|
|
@ -5170,6 +5369,30 @@ variable_template_p (tree t)
|
||||||
return false;
|
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,
|
/* A parameter list indicating for a function with no parameters,
|
||||||
e.g "int f(void)". */
|
e.g "int f(void)". */
|
||||||
extern cp_parameter_declarator *no_parameters;
|
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 *,
|
extern void resort_type_method_vec (void *, void *,
|
||||||
gt_pointer_operator, void *);
|
gt_pointer_operator, void *);
|
||||||
extern bool add_method (tree, tree, tree);
|
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 currently_open_derived_class (tree);
|
||||||
extern tree outermost_open_class (void);
|
extern tree outermost_open_class (void);
|
||||||
extern tree current_nonlambda_class_type (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);
|
extern tree build_ptrmem_type (tree, tree);
|
||||||
/* the grokdeclarator prototype is in decl.h */
|
/* the grokdeclarator prototype is in decl.h */
|
||||||
extern tree build_this_parm (tree, cp_cv_quals);
|
extern tree build_this_parm (tree, cp_cv_quals);
|
||||||
|
extern tree grokparms (tree, tree *);
|
||||||
extern int copy_fn_p (const_tree);
|
extern int copy_fn_p (const_tree);
|
||||||
extern bool move_fn_p (const_tree);
|
extern bool move_fn_p (const_tree);
|
||||||
extern bool move_signature_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 void check_template_variable (tree);
|
||||||
extern tree make_auto (void);
|
extern tree make_auto (void);
|
||||||
extern tree make_decltype_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 (tree);
|
||||||
extern tree type_uses_auto_or_concept (tree);
|
extern tree type_uses_auto_or_concept (tree);
|
||||||
extern void append_type_to_template_for_access_check (tree, tree, 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,
|
extern tree process_template_parm (tree, location_t, tree,
|
||||||
bool, bool);
|
bool, bool);
|
||||||
extern tree end_template_parm_list (tree);
|
extern tree end_template_parm_list (tree);
|
||||||
|
extern void end_template_parm_list (void);
|
||||||
extern void end_template_decl (void);
|
extern void end_template_decl (void);
|
||||||
extern tree maybe_update_decl_type (tree, tree);
|
extern tree maybe_update_decl_type (tree, tree);
|
||||||
extern bool check_default_tmpl_args (tree, tree, bool, bool, int);
|
extern bool check_default_tmpl_args (tree, tree, bool, bool, int);
|
||||||
extern tree push_template_decl (tree);
|
extern tree push_template_decl (tree);
|
||||||
extern tree push_template_decl_real (tree, bool);
|
extern tree push_template_decl_real (tree, bool);
|
||||||
extern tree add_inherited_template_parms (tree, tree);
|
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,
|
extern tree lookup_template_class (tree, tree, tree, tree,
|
||||||
int, tsubst_flags_t);
|
int, tsubst_flags_t);
|
||||||
extern tree lookup_template_function (tree, tree);
|
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 (tree, tree, tsubst_flags_t, tree);
|
||||||
extern tree tsubst_copy_and_build (tree, tree, tsubst_flags_t,
|
extern tree tsubst_copy_and_build (tree, tree, tsubst_flags_t,
|
||||||
tree, bool, bool);
|
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 most_general_template (tree);
|
||||||
extern tree get_mostly_instantiated_function_type (tree);
|
extern tree get_mostly_instantiated_function_type (tree);
|
||||||
extern bool problematic_instantiation_changed (void);
|
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 get_function_template_decl (const_tree);
|
||||||
extern tree resolve_nondeduced_context (tree);
|
extern tree resolve_nondeduced_context (tree);
|
||||||
extern hashval_t iterative_hash_template_arg (tree arg, hashval_t val);
|
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 */
|
/* in repo.c */
|
||||||
extern void init_repo (void);
|
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_deferred_access_checks (tsubst_flags_t);
|
||||||
extern bool perform_or_defer_access_check (tree, tree, tree,
|
extern bool perform_or_defer_access_check (tree, tree, tree,
|
||||||
tsubst_flags_t);
|
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 int stmts_are_full_exprs_p (void);
|
||||||
extern void init_cp_semantics (void);
|
extern void init_cp_semantics (void);
|
||||||
extern tree do_poplevel (tree);
|
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 void suggest_alternatives_for (location_t, tree);
|
||||||
extern tree strip_using_decl (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 */
|
/* in vtable-class-hierarchy.c */
|
||||||
extern void vtv_compute_class_hierarchy_transitive_closure (void);
|
extern void vtv_compute_class_hierarchy_transitive_closure (void);
|
||||||
extern void vtv_generate_init_routine (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);
|
pp_cxx_offsetof_expression (this, t);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case REQUIRES_EXPR:
|
||||||
|
pp_cxx_requires_expr (this, t);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
c_pretty_printer::primary_expression (t);
|
c_pretty_printer::primary_expression (t);
|
||||||
break;
|
break;
|
||||||
|
|
@ -1064,6 +1068,7 @@ cxx_pretty_printer::expression (tree t)
|
||||||
case TEMPLATE_PARM_INDEX:
|
case TEMPLATE_PARM_INDEX:
|
||||||
case TEMPLATE_TEMPLATE_PARM:
|
case TEMPLATE_TEMPLATE_PARM:
|
||||||
case STMT_EXPR:
|
case STMT_EXPR:
|
||||||
|
case REQUIRES_EXPR:
|
||||||
primary_expression (t);
|
primary_expression (t);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -1158,6 +1163,22 @@ cxx_pretty_printer::expression (tree t)
|
||||||
pp_cxx_ws_string (this, "<lambda>");
|
pp_cxx_ws_string (this, "<lambda>");
|
||||||
break;
|
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:
|
case PAREN_EXPR:
|
||||||
pp_cxx_left_paren (this);
|
pp_cxx_left_paren (this);
|
||||||
expression (TREE_OPERAND (t, 0));
|
expression (TREE_OPERAND (t, 0));
|
||||||
|
|
@ -1423,10 +1444,26 @@ pp_cxx_parameter_declaration (cxx_pretty_printer *pp, tree t)
|
||||||
static void
|
static void
|
||||||
pp_cxx_parameter_declaration_clause (cxx_pretty_printer *pp, tree t)
|
pp_cxx_parameter_declaration_clause (cxx_pretty_printer *pp, tree t)
|
||||||
{
|
{
|
||||||
tree args = TYPE_P (t) ? NULL : FUNCTION_FIRST_USER_PARM (t);
|
tree args;
|
||||||
tree types =
|
tree types;
|
||||||
TYPE_P (t) ? TYPE_ARG_TYPES (t) : FUNCTION_FIRST_USER_PARMTYPE (t);
|
bool abstract;
|
||||||
const bool abstract = args == NULL || pp->flags & pp_c_flag_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;
|
bool first = true;
|
||||||
|
|
||||||
/* Skip artificial parameter for nonstatic member functions. */
|
/* Skip artificial parameter for nonstatic member functions. */
|
||||||
|
|
@ -1574,6 +1611,12 @@ void
|
||||||
cxx_pretty_printer::declarator (tree t)
|
cxx_pretty_printer::declarator (tree t)
|
||||||
{
|
{
|
||||||
direct_declarator (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:
|
/* ctor-initializer:
|
||||||
|
|
@ -2154,7 +2197,13 @@ pp_cxx_canonical_template_parameter (cxx_pretty_printer *pp, tree parm)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
template-declaration:
|
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
|
static void
|
||||||
pp_cxx_template_declaration (cxx_pretty_printer *pp, tree t)
|
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_cxx_end_template_argument_list (pp);
|
||||||
pp_newline_and_indent (pp, 3);
|
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))
|
if (TREE_CODE (t) == FUNCTION_DECL && DECL_SAVED_TREE (t))
|
||||||
pp_cxx_function_definition (pp, t);
|
pp_cxx_function_definition (pp, t);
|
||||||
else
|
else
|
||||||
|
|
@ -2387,6 +2445,9 @@ pp_cxx_trait_expression (cxx_pretty_printer *pp, tree t)
|
||||||
case CPTK_IS_POLYMORPHIC:
|
case CPTK_IS_POLYMORPHIC:
|
||||||
pp_cxx_ws_string (pp, "__is_polymorphic");
|
pp_cxx_ws_string (pp, "__is_polymorphic");
|
||||||
break;
|
break;
|
||||||
|
case CPTK_IS_SAME_AS:
|
||||||
|
pp_cxx_ws_string (pp, "__is_same_as");
|
||||||
|
break;
|
||||||
case CPTK_IS_STD_LAYOUT:
|
case CPTK_IS_STD_LAYOUT:
|
||||||
pp_cxx_ws_string (pp, "__is_std_layout");
|
pp_cxx_ws_string (pp, "__is_std_layout");
|
||||||
break;
|
break;
|
||||||
|
|
@ -2416,7 +2477,7 @@ pp_cxx_trait_expression (cxx_pretty_printer *pp, tree t)
|
||||||
pp_cxx_left_paren (pp);
|
pp_cxx_left_paren (pp);
|
||||||
pp->type_id (TRAIT_EXPR_TYPE1 (t));
|
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_cxx_separate_with (pp, ',');
|
||||||
pp->type_id (TRAIT_EXPR_TYPE2 (t));
|
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);
|
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;
|
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_va_arg_expression (cxx_pretty_printer *, tree);
|
||||||
void pp_cxx_offsetof_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_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 */
|
#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 */
|
BSP_FIELD /* field */
|
||||||
};
|
};
|
||||||
|
|
||||||
static tree grokparms (tree parmlist, tree *);
|
|
||||||
static const char *redeclaration_error_message (tree, tree);
|
static const char *redeclaration_error_message (tree, tree);
|
||||||
|
|
||||||
static int decl_jump_unsafe (tree);
|
static int decl_jump_unsafe (tree);
|
||||||
|
|
@ -1079,8 +1078,10 @@ decls_match (tree newdecl, tree olddecl)
|
||||||
}
|
}
|
||||||
else if (TREE_CODE (newdecl) == TEMPLATE_DECL)
|
else if (TREE_CODE (newdecl) == TEMPLATE_DECL)
|
||||||
{
|
{
|
||||||
if (TREE_CODE (DECL_TEMPLATE_RESULT (newdecl))
|
tree oldres = DECL_TEMPLATE_RESULT (olddecl);
|
||||||
!= TREE_CODE (DECL_TEMPLATE_RESULT (olddecl)))
|
tree newres = DECL_TEMPLATE_RESULT (newdecl);
|
||||||
|
|
||||||
|
if (TREE_CODE (newres) != TREE_CODE (oldres))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!comp_template_parms (DECL_TEMPLATE_PARMS (newdecl),
|
if (!comp_template_parms (DECL_TEMPLATE_PARMS (newdecl),
|
||||||
|
|
@ -1088,11 +1089,12 @@ decls_match (tree newdecl, tree olddecl)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == TYPE_DECL)
|
if (TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == TYPE_DECL)
|
||||||
types_match = same_type_p (TREE_TYPE (DECL_TEMPLATE_RESULT (olddecl)),
|
types_match = (same_type_p (TREE_TYPE (oldres), TREE_TYPE (newres))
|
||||||
TREE_TYPE (DECL_TEMPLATE_RESULT (newdecl)));
|
&& equivalently_constrained (olddecl, newdecl));
|
||||||
else
|
else
|
||||||
types_match = decls_match (DECL_TEMPLATE_RESULT (olddecl),
|
// We don't need to check equivalently_constrained for variable and
|
||||||
DECL_TEMPLATE_RESULT (newdecl));
|
// function templates because we check it on the results.
|
||||||
|
types_match = decls_match (oldres, newres);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -1120,6 +1122,11 @@ decls_match (tree newdecl, tree olddecl)
|
||||||
COMPARE_REDECLARATION);
|
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;
|
return types_match;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1243,6 +1250,36 @@ validate_constexpr_redeclaration (tree old_decl, tree new_decl)
|
||||||
return true;
|
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
|
/* DECL is a redeclaration of a function or function template. If
|
||||||
it does have default arguments issue a diagnostic. Note: this
|
it does have default arguments issue a diagnostic. Note: this
|
||||||
function is used to enforce the requirements in C++11 8.3.6 about
|
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
|
/* Template functions can be disambiguated by
|
||||||
return type. */
|
return type. */
|
||||||
&& same_type_p (TREE_TYPE (TREE_TYPE (newdecl)),
|
&& 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);
|
error ("ambiguating new declaration %q+#D", newdecl);
|
||||||
inform (DECL_SOURCE_LOCATION (olddecl),
|
inform (DECL_SOURCE_LOCATION (olddecl),
|
||||||
"old declaration %q#D", olddecl);
|
"old declaration %q#D", olddecl);
|
||||||
}
|
}
|
||||||
|
else if (check_concept_refinement (olddecl, newdecl))
|
||||||
|
return error_mark_node;
|
||||||
return NULL_TREE;
|
return NULL_TREE;
|
||||||
}
|
}
|
||||||
if (TREE_CODE (newdecl) == FUNCTION_DECL)
|
if (TREE_CODE (newdecl) == FUNCTION_DECL)
|
||||||
|
|
@ -1593,8 +1635,11 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
|
||||||
are not ambiguous. */
|
are not ambiguous. */
|
||||||
else if ((!DECL_FUNCTION_VERSIONED (newdecl)
|
else if ((!DECL_FUNCTION_VERSIONED (newdecl)
|
||||||
&& !DECL_FUNCTION_VERSIONED (olddecl))
|
&& !DECL_FUNCTION_VERSIONED (olddecl))
|
||||||
|
// The functions have the same parameter types.
|
||||||
&& compparms (TYPE_ARG_TYPES (TREE_TYPE (newdecl)),
|
&& 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);
|
error ("ambiguating new declaration of %q+#D", newdecl);
|
||||||
inform (DECL_SOURCE_LOCATION (olddecl),
|
inform (DECL_SOURCE_LOCATION (olddecl),
|
||||||
|
|
@ -2576,6 +2621,12 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
|
||||||
if (snode)
|
if (snode)
|
||||||
snode->remove ();
|
snode->remove ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Remove the associated constraints for newdecl, if any, before
|
||||||
|
reclaiming memory. */
|
||||||
|
if (flag_concepts)
|
||||||
|
remove_constraints (newdecl);
|
||||||
|
|
||||||
ggc_free (newdecl);
|
ggc_free (newdecl);
|
||||||
|
|
||||||
return olddecl;
|
return olddecl;
|
||||||
|
|
@ -3981,6 +4032,10 @@ cxx_init_decl_processing (void)
|
||||||
|
|
||||||
/* Ensure attribs.c is initialized. */
|
/* Ensure attribs.c is initialized. */
|
||||||
init_attributes ();
|
init_attributes ();
|
||||||
|
|
||||||
|
/* Ensure constraint.cc is initialized. */
|
||||||
|
init_constraint_processing ();
|
||||||
|
|
||||||
extvisattr = build_tree_list (get_identifier ("externally_visible"),
|
extvisattr = build_tree_list (get_identifier ("externally_visible"),
|
||||||
NULL_TREE);
|
NULL_TREE);
|
||||||
newattrs = tree_cons (get_identifier ("alloc_size"),
|
newattrs = tree_cons (get_identifier ("alloc_size"),
|
||||||
|
|
@ -6368,6 +6423,16 @@ value_dependent_init_p (tree init)
|
||||||
return false;
|
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;
|
/* Finish processing of a declaration;
|
||||||
install its line number and initial value.
|
install its line number and initial value.
|
||||||
If the length of an array type is not known before,
|
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);
|
tf_warning_or_error);
|
||||||
d_init = resolve_nondeduced_context (d_init);
|
d_init = resolve_nondeduced_context (d_init);
|
||||||
type = TREE_TYPE (decl) = do_auto_deduction (type, 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)
|
if (type == error_mark_node)
|
||||||
return;
|
return;
|
||||||
cp_apply_type_quals_to_decl (cp_type_quals (type), decl);
|
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;
|
init = NULL_TREE;
|
||||||
release_tree_vector (cleanups);
|
release_tree_vector (cleanups);
|
||||||
}
|
}
|
||||||
|
else if (!init && is_concept_var (decl))
|
||||||
|
error ("variable concept has no initializer");
|
||||||
else if (!DECL_PRETTY_FUNCTION_P (decl))
|
else if (!DECL_PRETTY_FUNCTION_P (decl))
|
||||||
{
|
{
|
||||||
/* Deduce array size even if the initializer is dependent. */
|
/* Deduce array size even if the initializer is dependent. */
|
||||||
|
|
@ -7606,6 +7675,23 @@ check_static_quals (tree decl, cp_cv_quals quals)
|
||||||
decl);
|
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
|
/* Helper function. Replace the temporary this parameter injected
|
||||||
during cp_finish_omp_declare_simd with the real this parameter. */
|
during cp_finish_omp_declare_simd with the real this parameter. */
|
||||||
|
|
||||||
|
|
@ -7646,6 +7732,7 @@ grokfndecl (tree ctype,
|
||||||
tree declarator,
|
tree declarator,
|
||||||
tree parms,
|
tree parms,
|
||||||
tree orig_declarator,
|
tree orig_declarator,
|
||||||
|
tree decl_reqs,
|
||||||
int virtualp,
|
int virtualp,
|
||||||
enum overload_flags flags,
|
enum overload_flags flags,
|
||||||
cp_cv_quals quals,
|
cp_cv_quals quals,
|
||||||
|
|
@ -7667,6 +7754,16 @@ grokfndecl (tree ctype,
|
||||||
int staticp = ctype && TREE_CODE (type) == FUNCTION_TYPE;
|
int staticp = ctype && TREE_CODE (type) == FUNCTION_TYPE;
|
||||||
tree t;
|
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)
|
if (rqual)
|
||||||
type = build_ref_qualified_type (type, rqual);
|
type = build_ref_qualified_type (type, rqual);
|
||||||
if (raises)
|
if (raises)
|
||||||
|
|
@ -7674,6 +7771,21 @@ grokfndecl (tree ctype,
|
||||||
|
|
||||||
decl = build_lang_decl (FUNCTION_DECL, declarator, type);
|
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
|
/* If we have an explicit location, use it, otherwise use whatever
|
||||||
build_lang_decl used (probably input_location). */
|
build_lang_decl used (probably input_location). */
|
||||||
if (location != UNKNOWN_LOCATION)
|
if (location != UNKNOWN_LOCATION)
|
||||||
|
|
@ -7848,6 +7960,14 @@ grokfndecl (tree ctype,
|
||||||
if (inlinep & 2)
|
if (inlinep & 2)
|
||||||
DECL_DECLARED_CONSTEXPR_P (decl) = true;
|
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;
|
DECL_EXTERNAL (decl) = 1;
|
||||||
if (TREE_CODE (type) == FUNCTION_TYPE)
|
if (TREE_CODE (type) == FUNCTION_TYPE)
|
||||||
{
|
{
|
||||||
|
|
@ -7967,7 +8087,8 @@ grokfndecl (tree ctype,
|
||||||
decl = check_explicit_specialization (orig_declarator, decl,
|
decl = check_explicit_specialization (orig_declarator, decl,
|
||||||
template_count,
|
template_count,
|
||||||
2 * funcdef_flag +
|
2 * funcdef_flag +
|
||||||
4 * (friendp != 0));
|
4 * (friendp != 0) +
|
||||||
|
8 * concept_p);
|
||||||
if (decl == error_mark_node)
|
if (decl == error_mark_node)
|
||||||
return NULL_TREE;
|
return NULL_TREE;
|
||||||
|
|
||||||
|
|
@ -8125,7 +8246,7 @@ grokvardecl (tree type,
|
||||||
tree orig_declarator,
|
tree orig_declarator,
|
||||||
const cp_decl_specifier_seq *declspecs,
|
const cp_decl_specifier_seq *declspecs,
|
||||||
int initialized,
|
int initialized,
|
||||||
int constp,
|
int flags,
|
||||||
int template_count,
|
int template_count,
|
||||||
tree scope)
|
tree scope)
|
||||||
{
|
{
|
||||||
|
|
@ -8134,6 +8255,9 @@ grokvardecl (tree type,
|
||||||
|
|
||||||
gcc_assert (!name || identifier_p (name));
|
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
|
/* Compute the scope in which to place the variable, but remember
|
||||||
whether or not that scope was explicitly specified by the user. */
|
whether or not that scope was explicitly specified by the user. */
|
||||||
explicit_scope = scope;
|
explicit_scope = scope;
|
||||||
|
|
@ -8231,10 +8355,33 @@ grokvardecl (tree type,
|
||||||
else
|
else
|
||||||
DECL_INTERFACE_KNOWN (decl) = 1;
|
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.
|
// Handle explicit specializations and instantiations of variable templates.
|
||||||
if (orig_declarator)
|
if (orig_declarator)
|
||||||
decl = check_explicit_specialization (orig_declarator, decl,
|
decl = check_explicit_specialization (orig_declarator, decl,
|
||||||
template_count, 0);
|
template_count, conceptp * 8);
|
||||||
|
|
||||||
return decl != error_mark_node ? decl : NULL_TREE;
|
return decl != error_mark_node ? decl : NULL_TREE;
|
||||||
}
|
}
|
||||||
|
|
@ -8969,6 +9116,7 @@ grokdeclarator (const cp_declarator *declarator,
|
||||||
bool array_parameter_p = false;
|
bool array_parameter_p = false;
|
||||||
source_location saved_loc = input_location;
|
source_location saved_loc = input_location;
|
||||||
const char *errmsg;
|
const char *errmsg;
|
||||||
|
tree reqs = NULL_TREE;
|
||||||
|
|
||||||
signed_p = decl_spec_seq_has_spec_p (declspecs, ds_signed);
|
signed_p = decl_spec_seq_has_spec_p (declspecs, ds_signed);
|
||||||
unsigned_p = decl_spec_seq_has_spec_p (declspecs, ds_unsigned);
|
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;
|
explicit_intN = declspecs->explicit_intN_p;
|
||||||
thread_p = decl_spec_seq_has_spec_p (declspecs, ds_thread);
|
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)
|
if (decl_context == FUNCDEF)
|
||||||
funcdef_flag = true, decl_context = NORMAL;
|
funcdef_flag = true, decl_context = NORMAL;
|
||||||
else if (decl_context == MEMFUNCDEF)
|
else if (decl_context == MEMFUNCDEF)
|
||||||
|
|
@ -9220,6 +9374,12 @@ grokdeclarator (const cp_declarator *declarator,
|
||||||
if (name == NULL)
|
if (name == NULL)
|
||||||
name = decl_context == PARM ? "parameter" : "type name";
|
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)
|
if (constexpr_p && typedef_p)
|
||||||
{
|
{
|
||||||
error ("%<constexpr%> cannot appear in a typedef declaration");
|
error ("%<constexpr%> cannot appear in a typedef declaration");
|
||||||
|
|
@ -9548,9 +9708,12 @@ grokdeclarator (const cp_declarator *declarator,
|
||||||
|| thread_p)
|
|| thread_p)
|
||||||
error ("storage class specifiers invalid in parameter declarations");
|
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
|
/* Function parameters cannot be constexpr. If we saw one, moan
|
||||||
and pretend it wasn't there. */
|
and pretend it wasn't there. */
|
||||||
if (constexpr_p)
|
else if (constexpr_p)
|
||||||
{
|
{
|
||||||
error ("a parameter cannot be declared %<constexpr%>");
|
error ("a parameter cannot be declared %<constexpr%>");
|
||||||
constexpr_p = 0;
|
constexpr_p = 0;
|
||||||
|
|
@ -9778,6 +9941,10 @@ grokdeclarator (const cp_declarator *declarator,
|
||||||
if (raises == error_mark_node)
|
if (raises == error_mark_node)
|
||||||
raises = NULL_TREE;
|
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
|
/* Say it's a definition only for the CALL_EXPR
|
||||||
closest to the identifier. */
|
closest to the identifier. */
|
||||||
funcdecl_p = inner_declarator && inner_declarator->kind == cdk_id;
|
funcdecl_p = inner_declarator && inner_declarator->kind == cdk_id;
|
||||||
|
|
@ -10373,6 +10540,9 @@ grokdeclarator (const cp_declarator *declarator,
|
||||||
type = error_mark_node;
|
type = error_mark_node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (reqs)
|
||||||
|
error_at (location_of (reqs), "requires-clause on typedef");
|
||||||
|
|
||||||
if (decl_context == FIELD)
|
if (decl_context == FIELD)
|
||||||
decl = build_lang_decl (TYPE_DECL, unqualified_id, type);
|
decl = build_lang_decl (TYPE_DECL, unqualified_id, type);
|
||||||
else
|
else
|
||||||
|
|
@ -10566,6 +10736,9 @@ grokdeclarator (const cp_declarator *declarator,
|
||||||
error ("invalid qualifiers on non-member function type");
|
error ("invalid qualifiers on non-member function type");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (reqs)
|
||||||
|
error_at (location_of (reqs), "requires-clause on type-id");
|
||||||
|
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
else if (unqualified_id == NULL_TREE && decl_context != PARM
|
else if (unqualified_id == NULL_TREE && decl_context != PARM
|
||||||
|
|
@ -10587,6 +10760,13 @@ grokdeclarator (const cp_declarator *declarator,
|
||||||
return error_mark_node;
|
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
|
/* We don't check parameter types here because we can emit a better
|
||||||
error message later. */
|
error message later. */
|
||||||
if (decl_context != PARM)
|
if (decl_context != PARM)
|
||||||
|
|
@ -10744,6 +10924,11 @@ grokdeclarator (const cp_declarator *declarator,
|
||||||
uqname, ctype);
|
uqname, ctype);
|
||||||
return error_mark_node;
|
return error_mark_node;
|
||||||
}
|
}
|
||||||
|
if (concept_p)
|
||||||
|
{
|
||||||
|
error ("a destructor cannot be %<concept%>");
|
||||||
|
return error_mark_node;
|
||||||
|
}
|
||||||
if (constexpr_p)
|
if (constexpr_p)
|
||||||
{
|
{
|
||||||
error ("a destructor cannot be %<constexpr%>");
|
error ("a destructor cannot be %<constexpr%>");
|
||||||
|
|
@ -10757,6 +10942,17 @@ grokdeclarator (const cp_declarator *declarator,
|
||||||
id_declarator->u.id.unqualified_name);
|
id_declarator->u.id.unqualified_name);
|
||||||
return error_mark_node;
|
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)
|
if (TREE_CODE (unqualified_id) == TEMPLATE_ID_EXPR)
|
||||||
{
|
{
|
||||||
|
|
@ -10785,9 +10981,10 @@ grokdeclarator (const cp_declarator *declarator,
|
||||||
? unqualified_id : dname,
|
? unqualified_id : dname,
|
||||||
parms,
|
parms,
|
||||||
unqualified_id,
|
unqualified_id,
|
||||||
|
reqs,
|
||||||
virtualp, flags, memfn_quals, rqual, raises,
|
virtualp, flags, memfn_quals, rqual, raises,
|
||||||
friendp ? -1 : 0, friendp, publicp,
|
friendp ? -1 : 0, friendp, publicp,
|
||||||
inlinep | (2 * constexpr_p),
|
inlinep | (2 * constexpr_p) | (4 * concept_p),
|
||||||
initialized == SD_DELETED, sfk,
|
initialized == SD_DELETED, sfk,
|
||||||
funcdef_flag, template_count, in_namespace,
|
funcdef_flag, template_count, in_namespace,
|
||||||
attrlist, declarator->id_loc);
|
attrlist, declarator->id_loc);
|
||||||
|
|
@ -10890,8 +11087,10 @@ grokdeclarator (const cp_declarator *declarator,
|
||||||
if (declspecs->gnu_thread_keyword_p)
|
if (declspecs->gnu_thread_keyword_p)
|
||||||
SET_DECL_GNU_TLS_P (decl);
|
SET_DECL_GNU_TLS_P (decl);
|
||||||
}
|
}
|
||||||
|
if (concept_p)
|
||||||
if (constexpr_p && !initialized)
|
error ("static data member %qE declared %<concept%>",
|
||||||
|
unqualified_id);
|
||||||
|
else if (constexpr_p && !initialized)
|
||||||
{
|
{
|
||||||
error ("constexpr static data member %qD must have an "
|
error ("constexpr static data member %qD must have an "
|
||||||
"initializer", decl);
|
"initializer", decl);
|
||||||
|
|
@ -10900,7 +11099,10 @@ grokdeclarator (const cp_declarator *declarator,
|
||||||
}
|
}
|
||||||
else
|
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%>",
|
error ("non-static data member %qE declared %<constexpr%>",
|
||||||
unqualified_id);
|
unqualified_id);
|
||||||
|
|
@ -11010,10 +11212,12 @@ grokdeclarator (const cp_declarator *declarator,
|
||||||
TYPE_HAS_LATE_RETURN_TYPE (type) = 1;
|
TYPE_HAS_LATE_RETURN_TYPE (type) = 1;
|
||||||
|
|
||||||
decl = grokfndecl (ctype, type, original_name, parms, unqualified_id,
|
decl = grokfndecl (ctype, type, original_name, parms, unqualified_id,
|
||||||
virtualp, flags, memfn_quals, rqual, raises,
|
reqs, virtualp, flags, memfn_quals, rqual, raises,
|
||||||
1, friendp,
|
1, friendp,
|
||||||
publicp, inlinep | (2 * constexpr_p),
|
publicp,
|
||||||
initialized == SD_DELETED, sfk,
|
inlinep | (2 * constexpr_p) | (4 * concept_p),
|
||||||
|
initialized == SD_DELETED,
|
||||||
|
sfk,
|
||||||
funcdef_flag,
|
funcdef_flag,
|
||||||
template_count, in_namespace, attrlist,
|
template_count, in_namespace, attrlist,
|
||||||
declarator->id_loc);
|
declarator->id_loc);
|
||||||
|
|
@ -11054,7 +11258,7 @@ grokdeclarator (const cp_declarator *declarator,
|
||||||
decl = grokvardecl (type, dname, unqualified_id,
|
decl = grokvardecl (type, dname, unqualified_id,
|
||||||
declspecs,
|
declspecs,
|
||||||
initialized,
|
initialized,
|
||||||
(type_quals & TYPE_QUAL_CONST) != 0,
|
((type_quals & TYPE_QUAL_CONST) != 0) | (2 * concept_p),
|
||||||
template_count,
|
template_count,
|
||||||
ctype ? ctype : in_namespace);
|
ctype ? ctype : in_namespace);
|
||||||
if (decl == NULL_TREE)
|
if (decl == NULL_TREE)
|
||||||
|
|
@ -11304,7 +11508,7 @@ type_is_deprecated (tree type)
|
||||||
|
|
||||||
*PARMS is set to the chain of PARM_DECLs created. */
|
*PARMS is set to the chain of PARM_DECLs created. */
|
||||||
|
|
||||||
static tree
|
tree
|
||||||
grokparms (tree parmlist, tree *parms)
|
grokparms (tree parmlist, tree *parms)
|
||||||
{
|
{
|
||||||
tree result = NULL_TREE;
|
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 (template_header_p && MAYBE_CLASS_TYPE_P (t))
|
||||||
{
|
{
|
||||||
if (!redeclare_class_template (t, current_template_parms))
|
/* Check that we aren't trying to overload a class with different
|
||||||
return error_mark_node;
|
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
|
else if (!processing_template_decl
|
||||||
&& CLASS_TYPE_P (t)
|
&& CLASS_TYPE_P (t)
|
||||||
|
|
@ -14252,6 +14464,10 @@ finish_function (int flags)
|
||||||
fntype = TREE_TYPE (fndecl);
|
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
|
/* Save constexpr function body before it gets munged by
|
||||||
the NRV transformation. */
|
the NRV transformation. */
|
||||||
maybe_save_function_definition (fndecl);
|
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 TRAIT_EXPR: return TS_CP_TRAIT_EXPR;
|
||||||
case LAMBDA_EXPR: return TS_CP_LAMBDA_EXPR;
|
case LAMBDA_EXPR: return TS_CP_LAMBDA_EXPR;
|
||||||
case TEMPLATE_INFO: return TS_CP_TEMPLATE_INFO;
|
case TEMPLATE_INFO: return TS_CP_TEMPLATE_INFO;
|
||||||
|
case CONSTRAINT_INFO: return TS_CP_CONSTRAINT_INFO;
|
||||||
case USERDEF_LITERAL: return TS_CP_USERDEF_LITERAL;
|
case USERDEF_LITERAL: return TS_CP_USERDEF_LITERAL;
|
||||||
default: return TS_CP_GENERIC;
|
default: return TS_CP_GENERIC;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -714,6 +714,10 @@ check_classfn (tree ctype, tree function, tree template_parms)
|
||||||
!= type_memfn_rqual (TREE_TYPE (fndecl)))
|
!= type_memfn_rqual (TREE_TYPE (fndecl)))
|
||||||
continue;
|
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
|
/* While finding a match, same types and params are not enough
|
||||||
if the function is versioned. Also check version ("target")
|
if the function is versioned. Also check version ("target")
|
||||||
attributes. */
|
attributes. */
|
||||||
|
|
@ -724,6 +728,7 @@ check_classfn (tree ctype, tree function, tree template_parms)
|
||||||
&& (!is_template
|
&& (!is_template
|
||||||
|| comp_template_parms (template_parms,
|
|| comp_template_parms (template_parms,
|
||||||
DECL_TEMPLATE_PARMS (fndecl)))
|
DECL_TEMPLATE_PARMS (fndecl)))
|
||||||
|
&& equivalent_constraints (c1, c2)
|
||||||
&& (DECL_TEMPLATE_SPECIALIZATION (function)
|
&& (DECL_TEMPLATE_SPECIALIZATION (function)
|
||||||
== DECL_TEMPLATE_SPECIALIZATION (fndecl))
|
== DECL_TEMPLATE_SPECIALIZATION (fndecl))
|
||||||
&& (!DECL_TEMPLATE_SPECIALIZATION (function)
|
&& (!DECL_TEMPLATE_SPECIALIZATION (function)
|
||||||
|
|
@ -5081,6 +5086,7 @@ mark_used (tree decl, tsubst_flags_t complain)
|
||||||
|| (TREE_CODE (decl) == FUNCTION_DECL
|
|| (TREE_CODE (decl) == FUNCTION_DECL
|
||||||
&& DECL_OMP_DECLARE_REDUCTION_P (decl))
|
&& DECL_OMP_DECLARE_REDUCTION_P (decl))
|
||||||
|| undeduced_auto_decl (decl))
|
|| undeduced_auto_decl (decl))
|
||||||
|
&& !DECL_DECLARED_CONCEPT_P (decl)
|
||||||
&& !uses_template_parms (DECL_TI_ARGS (decl)))
|
&& !uses_template_parms (DECL_TI_ARGS (decl)))
|
||||||
{
|
{
|
||||||
/* Instantiating a function will result in garbage collection. We
|
/* 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)
|
else if (VAR_OR_FUNCTION_DECL_P (decl)
|
||||||
&& DECL_TEMPLATE_INFO (decl)
|
&& DECL_TEMPLATE_INFO (decl)
|
||||||
|
&& !DECL_DECLARED_CONCEPT_P (decl)
|
||||||
&& (!DECL_EXPLICIT_INSTANTIATION (decl)
|
&& (!DECL_EXPLICIT_INSTANTIATION (decl)
|
||||||
|| always_instantiate_p (decl)))
|
|| always_instantiate_p (decl)))
|
||||||
/* If this is a function or variable that is an instance of some
|
/* 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))
|
if (DECL_CLASS_TEMPLATE_P (t))
|
||||||
dump_type (pp, TREE_TYPE (t),
|
dump_type (pp, TREE_TYPE (t),
|
||||||
((flags & ~TFF_CLASS_KEY_OR_ENUM) | TFF_TEMPLATE_NAME
|
((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)
|
if (show_return)
|
||||||
dump_type_suffix (pp, TREE_TYPE (fntype), flags);
|
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);
|
dump_substitution (pp, t, template_parms, template_args, flags);
|
||||||
}
|
}
|
||||||
else if (template_args)
|
else if (template_args)
|
||||||
|
|
@ -2689,6 +2703,38 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags)
|
||||||
pp_cxx_right_paren (pp);
|
pp_cxx_right_paren (pp);
|
||||||
break;
|
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:
|
case PLACEHOLDER_EXPR:
|
||||||
pp_string (pp, M_("*this"));
|
pp_string (pp, M_("*this"));
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -174,6 +174,8 @@ init_reswords (void)
|
||||||
|
|
||||||
if (cxx_dialect < cxx11)
|
if (cxx_dialect < cxx11)
|
||||||
mask |= D_CXX11;
|
mask |= D_CXX11;
|
||||||
|
if (!flag_concepts)
|
||||||
|
mask |= D_CXX_CONCEPTS;
|
||||||
if (flag_no_asm)
|
if (flag_no_asm)
|
||||||
mask |= D_ASM | D_EXT;
|
mask |= D_ASM | D_EXT;
|
||||||
if (flag_no_gnu_keywords)
|
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);
|
rest_of_decl_compilation (fn, toplevel_bindings_p (), at_eof);
|
||||||
gcc_assert (!TREE_USED (fn));
|
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. */
|
/* Restore PROCESSING_TEMPLATE_DECL. */
|
||||||
processing_template_decl = saved_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. */
|
member definition using a generic type, it is the sk_class scope. */
|
||||||
cp_binding_level* implicit_template_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;
|
} cp_parser;
|
||||||
|
|
||||||
/* In parser.c */
|
/* 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");
|
fprintf (file, "pending_template");
|
||||||
}
|
}
|
||||||
break;
|
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:
|
case ARGUMENT_PACK_SELECT:
|
||||||
print_node (file, "pack", ARGUMENT_PACK_SELECT_FROM_PACK (node),
|
print_node (file, "pack", ARGUMENT_PACK_SELECT_FROM_PACK (node),
|
||||||
indent+4);
|
indent+4);
|
||||||
|
|
|
||||||
|
|
@ -1203,6 +1203,12 @@ lookup_member (tree xbasetype, tree name, int protect, bool want_type,
|
||||||
}
|
}
|
||||||
|
|
||||||
type = complete_type (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)
|
if (!basetype_path)
|
||||||
basetype_path = TYPE_BINFO (type);
|
basetype_path = TYPE_BINFO (type);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2710,10 +2710,18 @@ finish_template_template_parm (tree aggr, tree identifier)
|
||||||
{
|
{
|
||||||
tree decl = build_decl (input_location,
|
tree decl = build_decl (input_location,
|
||||||
TYPE_DECL, identifier, NULL_TREE);
|
TYPE_DECL, identifier, NULL_TREE);
|
||||||
|
|
||||||
tree tmpl = build_lang_decl (TEMPLATE_DECL, identifier, NULL_TREE);
|
tree tmpl = build_lang_decl (TEMPLATE_DECL, identifier, NULL_TREE);
|
||||||
DECL_TEMPLATE_PARMS (tmpl) = current_template_parms;
|
DECL_TEMPLATE_PARMS (tmpl) = current_template_parms;
|
||||||
DECL_TEMPLATE_RESULT (tmpl) = decl;
|
DECL_TEMPLATE_RESULT (tmpl) = decl;
|
||||||
DECL_ARTIFICIAL (decl) = 1;
|
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 ();
|
end_template_decl ();
|
||||||
|
|
||||||
gcc_assert (DECL_TEMPLATE_PARMS (tmpl));
|
gcc_assert (DECL_TEMPLATE_PARMS (tmpl));
|
||||||
|
|
@ -2977,6 +2985,72 @@ finish_template_decl (tree parms)
|
||||||
end_specialization ();
|
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
|
/* Finish processing a template-id (which names a type) of the form
|
||||||
NAME < ARGS >. Return the TYPE_DECL for the type named by the
|
NAME < ARGS >. Return the TYPE_DECL for the type named by the
|
||||||
template-id. If ENTERING_SCOPE is nonzero we are about to enter
|
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,
|
type = lookup_template_class (name, args,
|
||||||
NULL_TREE, NULL_TREE, entering_scope,
|
NULL_TREE, NULL_TREE, entering_scope,
|
||||||
tf_warning_or_error | tf_user);
|
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)
|
if (type == error_mark_node)
|
||||||
return type;
|
return type;
|
||||||
else if (CLASS_TYPE_P (type) && !alias_type_or_template_p (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:
|
case CPTK_IS_POLYMORPHIC:
|
||||||
return (CLASS_TYPE_P (type1) && TYPE_POLYMORPHIC_P (type1));
|
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:
|
case CPTK_IS_STD_LAYOUT:
|
||||||
return (std_layout_type_p (type1));
|
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_CLASS:
|
||||||
case CPTK_IS_ENUM:
|
case CPTK_IS_ENUM:
|
||||||
case CPTK_IS_UNION:
|
case CPTK_IS_UNION:
|
||||||
|
case CPTK_IS_SAME_AS:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
gcc_unreachable ();
|
gcc_unreachable ();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2955,16 +2955,19 @@ cp_tree_equal (tree t1, tree t2)
|
||||||
up for expressions that involve 'this' in a member function
|
up for expressions that involve 'this' in a member function
|
||||||
template. */
|
template. */
|
||||||
|
|
||||||
if (comparing_specializations)
|
if (comparing_specializations && !CONSTRAINT_VAR_P (t1))
|
||||||
/* When comparing hash table entries, only an exact match is
|
/* When comparing hash table entries, only an exact match is
|
||||||
good enough; we don't want to replace 'this' with the
|
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;
|
return false;
|
||||||
|
|
||||||
if (same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
|
if (same_type_p (TREE_TYPE (t1), TREE_TYPE (t2)))
|
||||||
{
|
{
|
||||||
if (DECL_ARTIFICIAL (t1) ^ DECL_ARTIFICIAL (t2))
|
if (DECL_ARTIFICIAL (t1) ^ DECL_ARTIFICIAL (t2))
|
||||||
return false;
|
return false;
|
||||||
|
if (CONSTRAINT_VAR_P (t1) ^ CONSTRAINT_VAR_P (t2))
|
||||||
|
return false;
|
||||||
if (DECL_ARTIFICIAL (t1)
|
if (DECL_ARTIFICIAL (t1)
|
||||||
|| (DECL_PARM_LEVEL (t1) == DECL_PARM_LEVEL (t2)
|
|| (DECL_PARM_LEVEL (t1) == DECL_PARM_LEVEL (t2)
|
||||||
&& DECL_PARM_INDEX (t1) == DECL_PARM_INDEX (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))
|
return (cp_tree_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0))
|
||||||
&& cp_tree_equal (TREE_OPERAND (t1, 1), TREE_OPERAND (t2, 1)));
|
&& 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:
|
case TREE_VEC:
|
||||||
{
|
{
|
||||||
unsigned ix;
|
unsigned ix;
|
||||||
|
|
@ -3876,6 +3883,14 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, walk_tree_fn func,
|
||||||
*walk_subtrees_p = 0;
|
*walk_subtrees_p = 0;
|
||||||
break;
|
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:
|
default:
|
||||||
return NULL_TREE;
|
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 (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))
|
if (!mark_used (function, complain) && !(complain & tf_error))
|
||||||
return error_mark_node;
|
return error_mark_node;
|
||||||
fndecl = function;
|
fndecl = function;
|
||||||
|
|
|
||||||
|
|
@ -19280,7 +19280,8 @@ Predefined Macros,cpp,The GNU C Preprocessor}).
|
||||||
* C++ Attributes:: Variable, function, and type attributes for C++ only.
|
* C++ Attributes:: Variable, function, and type attributes for C++ only.
|
||||||
* Function Multiversioning:: Declaring multiple function versions.
|
* Function Multiversioning:: Declaring multiple function versions.
|
||||||
* Namespace Association:: Strong using-directives for namespace association.
|
* 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.
|
* Java Exceptions:: Tweaking exception handling to work with Java.
|
||||||
* Deprecated Features:: Things will disappear from G++.
|
* Deprecated Features:: Things will disappear from G++.
|
||||||
* Backwards Compatibility:: Compatibilities with earlier definitions of C++.
|
* Backwards Compatibility:: Compatibilities with earlier definitions of C++.
|
||||||
|
|
@ -20076,6 +20077,52 @@ an enumeration type ([dcl.enum]).
|
||||||
|
|
||||||
@end table
|
@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
|
@node Java Exceptions
|
||||||
@section 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