diff options
Diffstat (limited to 'gcc/cp/decl.c')
-rw-r--r-- | gcc/cp/decl.c | 267 |
1 files changed, 242 insertions, 25 deletions
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 208173a..e8ed472 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -72,7 +72,6 @@ enum bad_spec_place { BSP_FIELD /* field */ }; -static tree grokparms (tree parmlist, tree *); static const char *redeclaration_error_message (tree, tree); static int decl_jump_unsafe (tree); @@ -1079,8 +1078,10 @@ decls_match (tree newdecl, tree olddecl) } else if (TREE_CODE (newdecl) == TEMPLATE_DECL) { - if (TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) - != TREE_CODE (DECL_TEMPLATE_RESULT (olddecl))) + tree oldres = DECL_TEMPLATE_RESULT (olddecl); + tree newres = DECL_TEMPLATE_RESULT (newdecl); + + if (TREE_CODE (newres) != TREE_CODE (oldres)) return 0; if (!comp_template_parms (DECL_TEMPLATE_PARMS (newdecl), @@ -1088,11 +1089,12 @@ decls_match (tree newdecl, tree olddecl) return 0; if (TREE_CODE (DECL_TEMPLATE_RESULT (newdecl)) == TYPE_DECL) - types_match = same_type_p (TREE_TYPE (DECL_TEMPLATE_RESULT (olddecl)), - TREE_TYPE (DECL_TEMPLATE_RESULT (newdecl))); + types_match = (same_type_p (TREE_TYPE (oldres), TREE_TYPE (newres)) + && equivalently_constrained (olddecl, newdecl)); else - types_match = decls_match (DECL_TEMPLATE_RESULT (olddecl), - DECL_TEMPLATE_RESULT (newdecl)); + // We don't need to check equivalently_constrained for variable and + // function templates because we check it on the results. + types_match = decls_match (oldres, newres); } else { @@ -1120,6 +1122,11 @@ decls_match (tree newdecl, tree olddecl) COMPARE_REDECLARATION); } + // Normal functions can be constrained, as can variable partial + // specializations. + if (types_match && VAR_OR_FUNCTION_DECL_P (newdecl)) + types_match = equivalently_constrained (newdecl, olddecl); + return types_match; } @@ -1243,6 +1250,36 @@ validate_constexpr_redeclaration (tree old_decl, tree new_decl) return true; } +// If OLDDECL and NEWDECL are concept declarations with the same type +// (i.e., and template parameters), but different requirements, +// emit diagnostics and return true. Otherwise, return false. +static inline bool +check_concept_refinement (tree olddecl, tree newdecl) +{ + if (!DECL_DECLARED_CONCEPT_P (olddecl) || !DECL_DECLARED_CONCEPT_P (newdecl)) + return false; + + tree d1 = DECL_TEMPLATE_RESULT (olddecl); + tree d2 = DECL_TEMPLATE_RESULT (newdecl); + if (TREE_CODE (d1) != TREE_CODE (d2)) + return false; + + tree t1 = TREE_TYPE (d1); + tree t2 = TREE_TYPE (d2); + if (TREE_CODE (d1) == FUNCTION_DECL) + { + if (compparms (TYPE_ARG_TYPES (t1), TYPE_ARG_TYPES (t2)) + && comp_template_parms (DECL_TEMPLATE_PARMS (olddecl), + DECL_TEMPLATE_PARMS (newdecl)) + && !equivalently_constrained (olddecl, newdecl)) + { + error ("cannot specialize concept %q#D", olddecl); + return true; + } + } + return false; +} + /* DECL is a redeclaration of a function or function template. If it does have default arguments issue a diagnostic. Note: this function is used to enforce the requirements in C++11 8.3.6 about @@ -1571,12 +1608,17 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) /* Template functions can be disambiguated by return type. */ && same_type_p (TREE_TYPE (TREE_TYPE (newdecl)), - TREE_TYPE (TREE_TYPE (olddecl)))) + TREE_TYPE (TREE_TYPE (olddecl))) + // Template functions can also be disambiguated by + // constraints. + && equivalently_constrained (olddecl, newdecl)) { error ("ambiguating new declaration %q+#D", newdecl); inform (DECL_SOURCE_LOCATION (olddecl), "old declaration %q#D", olddecl); } + else if (check_concept_refinement (olddecl, newdecl)) + return error_mark_node; return NULL_TREE; } if (TREE_CODE (newdecl) == FUNCTION_DECL) @@ -1593,8 +1635,11 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) are not ambiguous. */ else if ((!DECL_FUNCTION_VERSIONED (newdecl) && !DECL_FUNCTION_VERSIONED (olddecl)) + // The functions have the same parameter types. && compparms (TYPE_ARG_TYPES (TREE_TYPE (newdecl)), - TYPE_ARG_TYPES (TREE_TYPE (olddecl)))) + TYPE_ARG_TYPES (TREE_TYPE (olddecl))) + // And the same constraints. + && equivalently_constrained (newdecl, olddecl)) { error ("ambiguating new declaration of %q+#D", newdecl); inform (DECL_SOURCE_LOCATION (olddecl), @@ -2576,6 +2621,12 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) if (snode) snode->remove (); } + + /* Remove the associated constraints for newdecl, if any, before + reclaiming memory. */ + if (flag_concepts) + remove_constraints (newdecl); + ggc_free (newdecl); return olddecl; @@ -3981,6 +4032,10 @@ cxx_init_decl_processing (void) /* Ensure attribs.c is initialized. */ init_attributes (); + + /* Ensure constraint.cc is initialized. */ + init_constraint_processing (); + extvisattr = build_tree_list (get_identifier ("externally_visible"), NULL_TREE); newattrs = tree_cons (get_identifier ("alloc_size"), @@ -6368,6 +6423,16 @@ value_dependent_init_p (tree init) return false; } +// Returns true if a DECL is VAR_DECL with the concept specifier. +static inline bool +is_concept_var (tree decl) +{ + return (VAR_P (decl) + // Not all variables have DECL_LANG_SPECIFIC. + && DECL_LANG_SPECIFIC (decl) + && DECL_DECLARED_CONCEPT_P (decl)); +} + /* Finish processing of a declaration; install its line number and initial value. If the length of an array type is not known before, @@ -6446,7 +6511,9 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, tf_warning_or_error); d_init = resolve_nondeduced_context (d_init); type = TREE_TYPE (decl) = do_auto_deduction (type, d_init, - auto_node); + auto_node, + tf_warning_or_error, + adc_variable_type); if (type == error_mark_node) return; cp_apply_type_quals_to_decl (cp_type_quals (type), decl); @@ -6544,6 +6611,8 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, init = NULL_TREE; release_tree_vector (cleanups); } + else if (!init && is_concept_var (decl)) + error ("variable concept has no initializer"); else if (!DECL_PRETTY_FUNCTION_P (decl)) { /* Deduce array size even if the initializer is dependent. */ @@ -7606,6 +7675,23 @@ check_static_quals (tree decl, cp_cv_quals quals) decl); } +// Check that FN takes no arguments and returns bool. +static void +check_concept_fn (tree fn) +{ + // A constraint is nullary. + if (DECL_ARGUMENTS (fn)) + error ("concept %q#D declared with function parameters", fn); + + // The declared return type of the concept shall be bool, and + // it shall not be deduced from it definition. + tree type = TREE_TYPE (TREE_TYPE (fn)); + if (is_auto (type)) + error ("concept %q#D declared with a deduced return type", fn); + else if (type != boolean_type_node) + error ("concept %q#D with non-%<bool%> return type %qT", fn, type); +} + /* Helper function. Replace the temporary this parameter injected during cp_finish_omp_declare_simd with the real this parameter. */ @@ -7646,6 +7732,7 @@ grokfndecl (tree ctype, tree declarator, tree parms, tree orig_declarator, + tree decl_reqs, int virtualp, enum overload_flags flags, cp_cv_quals quals, @@ -7667,6 +7754,16 @@ grokfndecl (tree ctype, int staticp = ctype && TREE_CODE (type) == FUNCTION_TYPE; tree t; + // Was the concept specifier present? + bool concept_p = inlinep & 4; + + // Concept declarations must have a corresponding definition. + if (concept_p && !funcdef_flag) + { + error ("concept %qD has no definition", declarator); + return NULL_TREE; + } + if (rqual) type = build_ref_qualified_type (type, rqual); if (raises) @@ -7674,6 +7771,21 @@ grokfndecl (tree ctype, decl = build_lang_decl (FUNCTION_DECL, declarator, type); + /* Set the constraints on the declaration. */ + if (flag_concepts) + { + tree tmpl_reqs = NULL_TREE; + if (processing_template_decl > template_class_depth (ctype)) + tmpl_reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms); + + /* Adjust the required expression into a constraint. */ + if (decl_reqs) + decl_reqs = make_predicate_constraint (decl_reqs); + + tree ci = build_constraints (tmpl_reqs, decl_reqs); + set_constraints (decl, ci); + } + /* If we have an explicit location, use it, otherwise use whatever build_lang_decl used (probably input_location). */ if (location != UNKNOWN_LOCATION) @@ -7848,6 +7960,14 @@ grokfndecl (tree ctype, if (inlinep & 2) DECL_DECLARED_CONSTEXPR_P (decl) = true; + // If the concept declaration specifier was found, check + // that the declaration satisfies the necessary requirements. + if (concept_p) + { + DECL_DECLARED_CONCEPT_P (decl) = true; + check_concept_fn (decl); + } + DECL_EXTERNAL (decl) = 1; if (TREE_CODE (type) == FUNCTION_TYPE) { @@ -7967,7 +8087,8 @@ grokfndecl (tree ctype, decl = check_explicit_specialization (orig_declarator, decl, template_count, 2 * funcdef_flag + - 4 * (friendp != 0)); + 4 * (friendp != 0) + + 8 * concept_p); if (decl == error_mark_node) return NULL_TREE; @@ -8125,7 +8246,7 @@ grokvardecl (tree type, tree orig_declarator, const cp_decl_specifier_seq *declspecs, int initialized, - int constp, + int flags, int template_count, tree scope) { @@ -8134,6 +8255,9 @@ grokvardecl (tree type, gcc_assert (!name || identifier_p (name)); + bool constp = flags&1; + bool conceptp = flags&2; + /* Compute the scope in which to place the variable, but remember whether or not that scope was explicitly specified by the user. */ explicit_scope = scope; @@ -8231,10 +8355,33 @@ grokvardecl (tree type, else DECL_INTERFACE_KNOWN (decl) = 1; + /* Check that the variable can be safely declared as a concept. + Note that this also forbids explicit specializations. */ + if (conceptp) + { + if (!processing_template_decl) + { + error ("a non-template variable cannot be %<concept%>"); + return NULL_TREE; + } + else + DECL_DECLARED_CONCEPT_P (decl) = true; + if (!same_type_ignoring_top_level_qualifiers_p (type, boolean_type_node)) + error_at (declspecs->locations[ds_type_spec], + "concept must have type %<bool%>"); + } + else if (flag_concepts + && processing_template_decl > template_class_depth (scope)) + { + tree reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms); + tree ci = build_constraints (reqs, NULL_TREE); + set_constraints (decl, ci); + } + // Handle explicit specializations and instantiations of variable templates. if (orig_declarator) decl = check_explicit_specialization (orig_declarator, decl, - template_count, 0); + template_count, conceptp * 8); return decl != error_mark_node ? decl : NULL_TREE; } @@ -8969,6 +9116,7 @@ grokdeclarator (const cp_declarator *declarator, bool array_parameter_p = false; source_location saved_loc = input_location; const char *errmsg; + tree reqs = NULL_TREE; signed_p = decl_spec_seq_has_spec_p (declspecs, ds_signed); unsigned_p = decl_spec_seq_has_spec_p (declspecs, ds_unsigned); @@ -8978,6 +9126,12 @@ grokdeclarator (const cp_declarator *declarator, explicit_intN = declspecs->explicit_intN_p; thread_p = decl_spec_seq_has_spec_p (declspecs, ds_thread); + // Was concept_p specified? Note that ds_concept + // implies ds_constexpr! + bool concept_p = decl_spec_seq_has_spec_p (declspecs, ds_concept); + if (concept_p) + constexpr_p = true; + if (decl_context == FUNCDEF) funcdef_flag = true, decl_context = NORMAL; else if (decl_context == MEMFUNCDEF) @@ -9220,6 +9374,12 @@ grokdeclarator (const cp_declarator *declarator, if (name == NULL) name = decl_context == PARM ? "parameter" : "type name"; + if (concept_p && typedef_p) + { + error ("%<concept%> cannot appear in a typedef declaration"); + return error_mark_node; + } + if (constexpr_p && typedef_p) { error ("%<constexpr%> cannot appear in a typedef declaration"); @@ -9548,9 +9708,12 @@ grokdeclarator (const cp_declarator *declarator, || thread_p) error ("storage class specifiers invalid in parameter declarations"); + /* Function parameters cannot be concept. */ + if (concept_p) + error ("a parameter cannot be declared %<concept%>"); /* Function parameters cannot be constexpr. If we saw one, moan and pretend it wasn't there. */ - if (constexpr_p) + else if (constexpr_p) { error ("a parameter cannot be declared %<constexpr%>"); constexpr_p = 0; @@ -9778,6 +9941,10 @@ grokdeclarator (const cp_declarator *declarator, if (raises == error_mark_node) raises = NULL_TREE; + if (reqs) + error_at (location_of (reqs), "requires-clause on return type"); + reqs = declarator->u.function.requires_clause; + /* Say it's a definition only for the CALL_EXPR closest to the identifier. */ funcdecl_p = inner_declarator && inner_declarator->kind == cdk_id; @@ -10373,6 +10540,9 @@ grokdeclarator (const cp_declarator *declarator, type = error_mark_node; } + if (reqs) + error_at (location_of (reqs), "requires-clause on typedef"); + if (decl_context == FIELD) decl = build_lang_decl (TYPE_DECL, unqualified_id, type); else @@ -10566,6 +10736,9 @@ grokdeclarator (const cp_declarator *declarator, error ("invalid qualifiers on non-member function type"); } + if (reqs) + error_at (location_of (reqs), "requires-clause on type-id"); + return type; } else if (unqualified_id == NULL_TREE && decl_context != PARM @@ -10587,6 +10760,13 @@ grokdeclarator (const cp_declarator *declarator, return error_mark_node; } + if (reqs + && TREE_CODE (type) != FUNCTION_TYPE + && TREE_CODE (type) != METHOD_TYPE) + error_at (location_of (reqs), + "requires-clause on declaration of non-function type %qT", + type); + /* We don't check parameter types here because we can emit a better error message later. */ if (decl_context != PARM) @@ -10744,6 +10924,11 @@ grokdeclarator (const cp_declarator *declarator, uqname, ctype); return error_mark_node; } + if (concept_p) + { + error ("a destructor cannot be %<concept%>"); + return error_mark_node; + } if (constexpr_p) { error ("a destructor cannot be %<constexpr%>"); @@ -10757,6 +10942,17 @@ grokdeclarator (const cp_declarator *declarator, id_declarator->u.id.unqualified_name); return error_mark_node; } + if (sfk == sfk_constructor) + if (concept_p) + { + error ("a constructor cannot be %<concept%>"); + return error_mark_node; + } + if (concept_p) + { + error ("a concept cannot be a member function"); + concept_p = false; + } if (TREE_CODE (unqualified_id) == TEMPLATE_ID_EXPR) { @@ -10785,9 +10981,10 @@ grokdeclarator (const cp_declarator *declarator, ? unqualified_id : dname, parms, unqualified_id, + reqs, virtualp, flags, memfn_quals, rqual, raises, friendp ? -1 : 0, friendp, publicp, - inlinep | (2 * constexpr_p), + inlinep | (2 * constexpr_p) | (4 * concept_p), initialized == SD_DELETED, sfk, funcdef_flag, template_count, in_namespace, attrlist, declarator->id_loc); @@ -10890,8 +11087,10 @@ grokdeclarator (const cp_declarator *declarator, if (declspecs->gnu_thread_keyword_p) SET_DECL_GNU_TLS_P (decl); } - - if (constexpr_p && !initialized) + if (concept_p) + error ("static data member %qE declared %<concept%>", + unqualified_id); + else if (constexpr_p && !initialized) { error ("constexpr static data member %qD must have an " "initializer", decl); @@ -10900,7 +11099,10 @@ grokdeclarator (const cp_declarator *declarator, } else { - if (constexpr_p) + if (concept_p) + error ("non-static data member %qE declared %<concept%>", + unqualified_id); + else if (constexpr_p) { error ("non-static data member %qE declared %<constexpr%>", unqualified_id); @@ -11010,10 +11212,12 @@ grokdeclarator (const cp_declarator *declarator, TYPE_HAS_LATE_RETURN_TYPE (type) = 1; decl = grokfndecl (ctype, type, original_name, parms, unqualified_id, - virtualp, flags, memfn_quals, rqual, raises, + reqs, virtualp, flags, memfn_quals, rqual, raises, 1, friendp, - publicp, inlinep | (2 * constexpr_p), - initialized == SD_DELETED, sfk, + publicp, + inlinep | (2 * constexpr_p) | (4 * concept_p), + initialized == SD_DELETED, + sfk, funcdef_flag, template_count, in_namespace, attrlist, declarator->id_loc); @@ -11054,7 +11258,7 @@ grokdeclarator (const cp_declarator *declarator, decl = grokvardecl (type, dname, unqualified_id, declspecs, initialized, - (type_quals & TYPE_QUAL_CONST) != 0, + ((type_quals & TYPE_QUAL_CONST) != 0) | (2 * concept_p), template_count, ctype ? ctype : in_namespace); if (decl == NULL_TREE) @@ -11304,7 +11508,7 @@ type_is_deprecated (tree type) *PARMS is set to the chain of PARM_DECLs created. */ -static tree +tree grokparms (tree parmlist, tree *parms) { tree result = NULL_TREE; @@ -12399,8 +12603,16 @@ xref_tag_1 (enum tag_types tag_code, tree name, { if (template_header_p && MAYBE_CLASS_TYPE_P (t)) { - if (!redeclare_class_template (t, current_template_parms)) - return error_mark_node; + /* Check that we aren't trying to overload a class with different + constraints. */ + tree constr = NULL_TREE; + if (current_template_parms) + { + tree reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms); + constr = build_constraints (reqs, NULL_TREE); + } + if (!redeclare_class_template (t, current_template_parms, constr)) + return error_mark_node; } else if (!processing_template_decl && CLASS_TYPE_P (t) @@ -14252,6 +14464,10 @@ finish_function (int flags) fntype = TREE_TYPE (fndecl); } + // If this is a concept, check that the definition is reasonable. + if (DECL_DECLARED_CONCEPT_P (fndecl)) + check_function_concept (fndecl); + /* Save constexpr function body before it gets munged by the NRV transformation. */ maybe_save_function_definition (fndecl); @@ -14742,6 +14958,7 @@ cp_tree_node_structure (union lang_tree_node * t) case TRAIT_EXPR: return TS_CP_TRAIT_EXPR; case LAMBDA_EXPR: return TS_CP_LAMBDA_EXPR; case TEMPLATE_INFO: return TS_CP_TEMPLATE_INFO; + case CONSTRAINT_INFO: return TS_CP_CONSTRAINT_INFO; case USERDEF_LITERAL: return TS_CP_USERDEF_LITERAL; default: return TS_CP_GENERIC; } |