[PATCH] Diagnose hard errors during constraint satisfaction
This changes the diagnostic of non-boolean constraints and rvalue conversion failures in constraint satisfaction into hard errors. I also cleaned up the satisfaction routines to reduce the number of functions involved. Jason, this is a squashed version of the patches I sent earlier today. This patch also fixes the crash PR92439, which was caused by not building the normalization tree in satisfy_constraint_expression. However, there are some other problems with that example that cause it to not compile (e.g., non-boolean atomic constraints). Andrew Sutton 0001-Diagnose-certain-constraint-errors-as-hard-errors.patch Description: Binary data
[PATCH] PR c++/92403
Suppress diagnostics when substituting into requires-expressions outside of concept definitions. This change broke one existing test, which I've updated to match the behavior of the current patch. Specifically, it changed the case below: template constexpr bool subst = true; template constexpr bool test() { if constexpr (requires { requires subst; }) // error? return true; else return false; } static_assert(!test()); Before, the program is ill-formed as a result of substituting void for U. After applying, the requirement is false. If you replace the requires-expression with a concept (either before or after the patch), you get false. So, this seems like the right behavior. Andrew Sutton 0001-Suppress-diagnostics-substituting-into-a-requires-ex.patch Description: Binary data
[c++-concepts] Class template constraints
Attached is a patch for constrained class templates. It's the 3rd time I've sent it. I added some fixes for bugs discovered after the previous send, and added support for matching constrained declarations in out-of-class member function definitions. 2013-08-02 Andrew Sutton * gcc/cp/pt.c (get_class_bindings): Pass the partial specialization for constraint evaluation. Evaluate constraints, resulting in deduction failure on error. (get_specializaing_template_decl), (get_specialization_constraints), (maybe_new_partial_specialization): New. (maybe_process_partial_specialization): Allow the creation of new types for constrained partial specializations. (process_partial_specialization): Modify the canonical type of constrained partial specializations. (resolve_template_scope): New. Match the template scope to a specialization with appropriate constraints. (lookup_template_class_1): Compare constraints when entering a template scope. Check constraints on lookup. Do not explicitly check alias constraints. (instantiate_class_template_1): Do not explicitly check constraints during class template instantiation. (tsubst_decl): Instantiate the constraints of template declarations. (more_specialized_class): Pass specializations to get_class_bindings(). Compare specialization constraints if the types are equivalent. (most_specialized_class): Pass specialization to get_class_bndings(). * gcc/cp/decl2.c (check_class_fn): Get the decl's requirements from either the current template reqs or from the template parameters. Allow overloading of constrained out-of-class member definitions. * gcc/cp/parser.c (cp_parser_parse_type_parameter): Attach requirements to the current template parameter list. (cp_parser_init_declarator): Parse requires clauses for out-of-class member definitions. Be sure to restore current constraints before exiting the function. (cp_parser_member_declarator): Restore the previous requirements in an early-exit branch. (cp_parser_late_parsing_for_member): Restore constraints after maybe_end_member_template_processing(). (cp_parser_template_declaration_after_exp): Attach constraints to the current template parameters. * gcc/cp/constraint.cc (reduce_template_id): Don't crash when omitting ()'s on constraint calls. (check_requirements): Don't evaluate dependent arguments. (check_constraints): Don't try to evaluate when arguments are dependent. (equivalent_constraints): Optimize the case when a and b are the same constraints. -- Andrew Sutton template.patch Description: Binary data
Re: [c++-concepts] Class template constraints
>> 1. Type constraints are checked on lookup rather than instantiation. > > > How is this different from function template constraints? Is this just a > difference in internal function name (instantiate_template vs > lookup_template_class)? It's not supposed to be different. Checking constraints in instantiate_template is actually too late. We want to check before instantiation, at the point of use. This also means we don't need complete types to check constraints. So this: template struct X; X* x; Should fail and does. This change also makes it impossible to have partial specializations that are more general than the primary template. Checking in lookup_class_template does not consult the specializations. Constraints on partial specializations are checked in most_specialized_class (or one of its subroutines). > >> +// Returns the type of a template specialization only if that >> +// specializaiton needs to defined. Otherwise (e.g., if the type has > > > specialization > >> + // Do the constraints match the most general template? Note that >> + // the absence of constraints will also match. >> + if (equivalent_constraints (cur_constr, DECL_CONSTRAINTS (tmpl))) > > > If absence matches, I think the name "equivalent" is misleading. But the > implementation seems to require subsumes in both directions. What's up > here? Subsumption is essentially computing an implication between constraints, so that if P subsumes Q, you could also say that P => Q. Checking in both directions gives P => Q and Q => P, or P <=> Q, which is logical equivalence. I think that the absence of constraints fits into those definition nicely, since it represents the empty set of propositions. >> + // 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 you're going to use this function from lookup_template_class_1, it can't > use current_template_*, since those are parser state which might be > something completely unrelated when we get here during instantiation. I was worried about that. I'm not sure how this gets invoked during instantiation. I'll look at it. -- Andrew Sutton andrew.n.sut...@gmail.com
Re: [c++-concepts] Class template constraints
>> It's not supposed to be different. Checking constraints in >> instantiate_template is actually too late. We want to check before >> instantiation, at the point of use. > > Right, what I was getting at is that instantiate_template actually only > instantiates the declaration of a function, not the definition, so it > corresponds to lookup_template_class for class templates. Ah. The goal is to check after we've deduced/coerced template arguments into a valid substitution. With functions, that's in fn_type_unification (hopefully called from instantiate_template), and for classes in lookup_template_class. There are some other places too: get_class_bindings for partial specializations, and determine_specialization for explicit specializations. > Oh, did the comment just mean that absence is equivalent to absence? I > thought the comment was saying that absence is considered equivalent to > anything else. Just tweak the comment, then. Sounds good. Andrew
Re: [c++-concepts] Class template constraints
Updated as per comments. I moved the resolve_template_scope function out to finish_template_type. I couldn't figure out how to get the parsed template parameter from the looked-up template in lookup_class_template. That information may not be available outside the parse state. Andrew Andrew Sutton On Wed, Sep 4, 2013 at 3:49 PM, Jason Merrill wrote: > On 09/04/2013 01:33 PM, Andrew Sutton wrote: >> >> Ah. The goal is to check after we've deduced/coerced template >> arguments into a valid substitution. With functions, that's in >> fn_type_unification (hopefully called from instantiate_template) > > > Actually fn_type_unification calls instantiate_template, but yep, we're on > the same page. > > Jason > templates.patch Description: Binary data
Re: [c++-concepts] Class template constraints
Ok to commit? Attached is the doc fix patch. I'll send the TREE_TYPE patch shortly. Andrew Andrew Sutton On Sat, Sep 7, 2013 at 1:00 PM, Jason Merrill wrote: > On 09/06/2013 12:03 PM, Andrew Sutton wrote: >> >> +// Returns the template type of the class scope being entered. If we're >> +// entering a constrained class scope. TMPL is the most general template >> +// of the scope being entered, and TYPE is its type. > > > TMPL is not part of the interface of fixup_template_type, so it should be > documented when it is declared rather than before the function. > > OK with that tweak. > >> + tree cur_constr = TREE_TYPE (parms); > > > In a separate patch, I'd like to use a different macro name for getting > constraints from template parms. > > Jason > templates-2.patch Description: Binary data
[c++-concepts] pretty print fix
The last merge didn't compile for me. Apparently some pretty printing functions have disappeared that were being called in the concept stuff. This patch just replaces the broken calls to pp_cxx_type_id with pp->type_id. Ok to commit? Andrew Sutton fix.patch Description: Binary data
[c++-concepts] template parameter constraints
I added a new macro to replace the use of TREE_TYPE to get constraints. It's called TEMPLATE_PARMS_CONSTRAINTS. Patch attached: 2013-09-10 Andrew Sutton * gcc/cp/cp-tree.h (TEMPLATE_PARMS_CONSTRAINTS): New. * gcc/cp/parser.c (cp_parser_template_declaration_after_export), (cp_parser_type_parameter): Use TEMPLATE_PARMS_CONSTRAINTS. * gcc/cp/semantics.c (fixup_template_scope): Use TEMPLATE_PARMS_CONSTRAINTS. Andrew Sutton template-parms.patch Description: Binary data
Re: [c++-concepts] template parameter constraints
Will amend and commit tomorrow morning! Andrew Andrew Sutton On Tue, Sep 10, 2013 at 7:54 PM, Gabriel Dos Reis wrote: > Andrew Sutton writes: > > | I added a new macro to replace the use of TREE_TYPE to get > | constraints. It's called TEMPLATE_PARMS_CONSTRAINTS. Patch attached: > | > | 2013-09-10 Andrew Sutton > | * gcc/cp/cp-tree.h (TEMPLATE_PARMS_CONSTRAINTS): New. > | * gcc/cp/parser.c (cp_parser_template_declaration_after_export), > | (cp_parser_type_parameter): Use TEMPLATE_PARMS_CONSTRAINTS. > | * gcc/cp/semantics.c (fixup_template_scope): Use > | TEMPLATE_PARMS_CONSTRAINTS. > > | +// Access template constraints associated with the template > | +// parameter lists. Template parameter constraints are stored in > | +// the TREE_TYPE of list. > > Hmm, we can have several levels of template parameter list. What about: > > // Logical constraints on the template parameters introduced at a > // given template parameter list level indicated by NODE. > > Patch OK with that change. > > Thanks, > > -- Gaby
[c++-concepts] Constrained friends
This patch implements semantics for constrained friend templates and classes. The only significant changes are in determine_specializaiton and check_constrained_friend. Unless a friend function is defined, a constraints on friend declarations are never actually checked. The checking happens during overload resolution against the actual (non-friend) declarations. The change to determine_specialization is interesting. We have cases where a programmer has written an explicit specialization and it's being matched to a template. Previously, if constraints were not satisfied, we would not record the template as a candidate. However, this causes errors in class template instantiation if there are constrained friend declarations whose constraints are not satisfied ("no matching template declaration"). With this patch, we defer constraints checks until we've selected the best template for the specialization. And then we only check the constraints if the declaration is a non-friend. 2013-09-13 Andrew Sutton * gcc/cp/cp-tree.h (check_constrained_friend): New. * gcc/cp/pt.c (determine_specialization): Only check constraints after determining which template the declaraiton is a specialization of. Don't check constraints for friends during class template instantiation. (fn_type_unification): New parameter to determine if constraints should be checked. (more_specialized_class): Update for interface change. (get_bindings): New parameter to determine if constraints should be checked during fn_type_unification. New overload that checks constraints by default. * gcc/cp/parser.c (cp_parser_member_declaration): Check constrained friends after parsing. * gcc/cp/class.c (resolve_address_of_overloaded_function): Update for interface change. * gcc/cp/call.c (is_non_template_friend): New. (add_function_candidate): Check constraints on constrained friend templates. (add_template_candidate_real): Update for interface change. * gcc/cp/constraint.c (check_constrained_friend): New. Andrew Sutton friends.patch Description: Binary data
Re: [c++-concepts] Constrained friends
I'm going to rewrite this patch tomorrow morning. The semantics aren't quite right --- they should be simpler. >> Previously, if constraints were not >> satisfied, we would not record the template as a candidate. However, >> this causes errors in class template instantiation if there are >> constrained friend declarations whose constraints are not satisfied >> ("no matching template declaration"). > > Is that wrong? We normally give errors about friend declarations that don't > match any template. Why don't we want this error when the friend > declaration is looking for a constrained template? It is wrong, but not for the reasons I gave. This only happens when you try to constrain a friend function that declares a specialization, which happens to be completely separate from the previously declared template. I'm going to disallow the ability to declare constrained friend specializations. They don't really make sense. >> + if (is_non_template_member_fn (fn) || is_non_template_friend (fn)) > > > Let's have one predicate instead of two; the condition here is a temploid > that is not a specialization of a primary template. Agreed. > >> + if (!check_template_constraints (tmpl, args) && (complain & >> tf_error)) >> { >>reason = template_constraint_failure (tmpl, args); >>viable = false; > > > Why add the complain check? A constraint failure should make a candidate > non-viable even in SFINAE context. What have I done? That's awful... >> + // If we're not instantiating a friend function, then we need to >> + // ensure the specialization of the best template satisfies its >> + // constraints. > > > Surely we need to check constraints in the earlier loop, so that we don't > treat as a candidate a template that doesn't satisfy the constraints; > otherwise if we have two templates > > template T f(T) requires Thing; > template T* f(T*); > > and our specialization requires Thing, we would select the second (because > it is otherwise more specialized) and then give an error about constraint > mismatch; I would think we want to select the first. I believe that's what the previous version did, and we'll go back to that. This change was part of the semantics that I didn't get right. >> +// If there is an overload with the same type and >> +// constraints, then this is a good declaration. >> +if (same_type_p (TREE_TYPE (fn), TREE_TYPE (f))) >> + if (equivalent_constraints (constr, get_constraints (f))) >> +return; > > > It seems that this will only allow friend declarations that match the > template exactly, not friend declarations that are more specialized than the > matching template. It looks like you're trying to implement a subset of > determine_specialization here, which I think is a mistake. I agree. It's a mistake. This is also related to the semantics that I got wrong. Effectively, the only changes needed for constrained friends are that: a) you can't constrain non-dependent friends b) you can't constraint non-template friend functions that declare a specialization and c) that we check non-template friends the same way as non-template member fns There should be no changes to any of the rules for determining specializations. Andrew
[c++-concepts] constrained friends redux
This patch implements constrained friends and disallows declarations of constrained friend template specialization. There was a previous question about whether I was doing the right thing in determine_specialization. I'm looking at that issue separately. 2013-10-01 Andrew Sutton * gcc/cp/parser.c (cp_parser_member_declaration): Check that a constrained friend definition is valid. * gcc/cp/decl.c (grokfndecl): Disallow constrained friend template specializations. * gcc/cp/constraints.cc (check_constrained_friend): New. * gcc/cp/typeck.c (cp_build_function_call_vec): Diagnose constraints in the presence of the failure of a single candidate. * gcc/cp/cp-tree.h (check_constrained_friend): New. * gcc/cp/call.c (is_non_template_member_fn): Make inline. (is_non_template_friend), (is_constrainable_non_template_fn): New. (add_function_candidate): Predicate check on is_constrainable_non_template_fn. Andrew Sutton friends-2.patch Description: Binary data
Re: [c++-concepts] constrained friends redux
>> + // Do not permit the declaration of constrained friend >> + // function declarations. They cannot be instantiated since >> + // the resulting declaration would never match the definition, >> + // which must be a non-template and cannot be constrained. > > > You're in the template-id code here, so "must be a non-template" is > confusing: > > template void f(); > > struct A { > friend void f(); // matches a template > }; > > Perhaps you mean that it must match a fully-instantiated function, so any > constraints on the templates were considered during > determine_specialization. This seems like a simple comment fix, but there's a longer explanation of what I want (see below). Would this be more appropriate? // Do not allow constrained friend template specializations. The intent is stronger than to say it must match something. I don't want to allow any declarations of the form template struct X { friend void f<>(T x) requires C; // Error. }; This should never even get to determine_specialization since the original declaration is never actually pushed. We could use those constraints to match the specialization to one of several constrained overloads, as you mentioned earlier, but I'd rather avoid that for now. Solving that problem in general would require that we allow constrained (explicit) specializations and define a method of matching instantiated constraints to dependent constraints, and that we do so as an alternative to the usual constraint checking during template argument deduction. Maybe it's a useful feature, but it's really hard to gauge how much use it would actually get. We can always revisit that in the future. Somebody else can write that paper :) Andrew
Re: [c++-concepts] constrained friends redux
>>> >Perhaps you mean that it must match a fully-instantiated function, so >>> > any >>> >constraints on the templates were considered during >>> >determine_specialization. > > >> This seems like a simple comment fix, but there's a longer explanation >> of what I want (see below). Would this be more appropriate? >> >>// Do not allow constrained friend template specializations. >> >> The intent is stronger than to say it must match something. > > > By "must" I meant that whatever it matches could only be a > fully-instantiated function. I see what you mean. I was caught up in the wrong part of the sentence.. But yes, that's right. > But I guess the main reason for disallowing constraints here is the same as > for explicit specializations and non-template functions; non-dependent > constraints don't really make any sense. That's the intent. Okay to commit? Andrew friends-3.patch Description: Binary data
[c++-concepts] friends regression
The last patch introduced a regression. This ensures that we don't generate false positives diagnosing errors in non-template contexts. 2013-10-07 Andrew Sutton * gcc/cp/cp-tree.h (check_constrained_friend): Take requirements as an argument. * gcc/cp/constraints.cc (check_constrained_friend): Do not diagnose errors in unconstrained friend declarations. * gcc/cp/parser.cc (cp_parser_member_declaration): Pass current requirements to check_constrained_friend. Andrew Sutton friends-4.patch Description: Binary data
Re: [c++-concepts] friends regression
No, any current_template_reqs are reset (set to null) before parsing any trailing requirements and restored after the fact. Andrew Sutton On Mon, Oct 7, 2013 at 3:05 PM, Jason Merrill wrote: > OK. > > If we have a friend declaration inside a constrained partial specialization, > will that still get a false positive? > > Jason
[c++-concepts] Shorthand notation
I've committed initial support for shorthand constraints. This patch adds support for parsing a concept-names as non-class names. When introducing a template parameter, the concept name is transformed into a constraint on the template parameter. Constrained parameters can introduce type, non-type and template template parameters. This has initial support for variadic constraints, but it's not well tested. This patch does not yet support default arguments for constrained template parameters, nor does it support the use of concept ids of this form: template F> void f(); There are a couple of interesting things in the patch. I'm using a PLACEHOLDER_EXPR as a template argument in order to resolve constraint names. Effectively, I deduce concepts by creating an expression like: Equality_comparable() where ? is a placeholder, and after coerce_template_arguments completes, I can extract the matched parameter from the placeholder. This works nicely when concepts are overloaded or have default arguments (although I'm not sure I'm testing that very thoroughly right now). With variadic constraints, I've had to add functionality to expand a pack as a conjunction of requirements. For example, if you declare: template // Class() must be true for each T in Ts void f(); The transformation is: template requires Class()... void f(); Where Class()... expands to Class() && Class() && ... etc. I feel like the current implementation is a bit hacky, and I'm wondering if I should introduce a new node for a pack conjunction. Change log follows. 2013-10-16 Andrew Sutton * gcc/cp/constraint.cc (conjoin_requiremens): New. (resolve_constraint_check): Filter non-concept candidates before coercing arguments. Perform deduction in a template-decl processing context to prevent errors during diagnosis. (finish_concept_name), (finish_shorthand_requirement), (get_shorthand_requirements): New. * gcc/cp/pt.c (template_parm_to_arg): Make non-static. (process_templat_parm): Build shorthand requirements from the parameter description. (end_templat_parm_list): New. (convert_placeholder_argument): New. (convert_template_argument): Match placeholder arguments against any template parameter. (tsubst_pack_conjuction): New. (tsubst_expr): Expand a pack as a conjunction. (type_dependent_expression_p): Placeholders are always type dependent. * gcc/cp/parser.c (cp_is_constrained_parameter), (cp_finish_template_type_parm), (cp_finish_template_template_parm) (cp_finish_non_type_template_parm), (cp_finish_constrined_parameter): New. (cp_parser_template_parameter): Handle constrained parameters. (cp_parser_nonclass_name): An identifier naming an overload set may declare a constrained parameter. (cp_parser_type_parameter), (cp_parser_template_declaration_after_exp): Get shorthand requirements from the tmeplate parameter list. * gcc/cp/cp-tree.h (TEMPLATE_PARM_CONSTRAINTS): New. Committed in 203704. Andrew Sutton
Re: [c++-concepts] Shorthand notation
A small follow up change. This removes the "sorry" from concept name resolution. Committed in r203815. 2013-10-16 Andrew Sutton * gcc/cp/constraint.cc (finish_concept_name): Allow functions with the same name as concepts to resolve as call expressions in the usual way. Andrew Sutton On Wed, Oct 16, 2013 at 9:59 AM, Andrew Sutton wrote: > I've committed initial support for shorthand constraints. This patch > adds support for parsing a concept-names as non-class names. When > introducing a template parameter, the concept name is transformed into > a constraint on the template parameter. Constrained parameters can > introduce type, non-type and template template parameters. > > This has initial support for variadic constraints, but it's not well tested. > > This patch does not yet support default arguments for constrained > template parameters, nor does it support the use of concept ids of > this form: > > template F> > void f(); > > There are a couple of interesting things in the patch. I'm using a > PLACEHOLDER_EXPR as a template argument in order to resolve constraint > names. Effectively, I deduce concepts by creating an expression like: > > Equality_comparable() > > where ? is a placeholder, and after coerce_template_arguments > completes, I can extract the matched parameter from the placeholder. > This works nicely when concepts are overloaded or have default > arguments (although I'm not sure I'm testing that very thoroughly > right now). > > With variadic constraints, I've had to add functionality to expand a > pack as a conjunction of requirements. For example, if you declare: > > template // Class() must be true for each T in Ts > void f(); > > The transformation is: > > template > requires Class()... > void f(); > > Where Class()... expands to Class() && Class() && ... etc. > I feel like the current implementation is a bit hacky, and I'm > wondering if I should introduce a new node for a pack conjunction. > > Change log follows. > > 2013-10-16 Andrew Sutton > * gcc/cp/constraint.cc (conjoin_requiremens): New. > (resolve_constraint_check): Filter non-concept candidates before > coercing arguments. Perform deduction in a template-decl processing > context to prevent errors during diagnosis. > (finish_concept_name), (finish_shorthand_requirement), > (get_shorthand_requirements): New. > * gcc/cp/pt.c (template_parm_to_arg): Make non-static. > (process_templat_parm): Build shorthand requirements from the > parameter description. > (end_templat_parm_list): New. > (convert_placeholder_argument): New. > (convert_template_argument): Match placeholder arguments against > any template parameter. > (tsubst_pack_conjuction): New. > (tsubst_expr): Expand a pack as a conjunction. > (type_dependent_expression_p): Placeholders are always type > dependent. > * gcc/cp/parser.c (cp_is_constrained_parameter), > (cp_finish_template_type_parm), (cp_finish_template_template_parm) > (cp_finish_non_type_template_parm), (cp_finish_constrined_parameter): > New. > (cp_parser_template_parameter): Handle constrained parameters. > (cp_parser_nonclass_name): An identifier naming an overload set > may declare a constrained parameter. > (cp_parser_type_parameter), > (cp_parser_template_declaration_after_exp): > Get shorthand requirements from the tmeplate parameter list. > * gcc/cp/cp-tree.h (TEMPLATE_PARM_CONSTRAINTS): New. > > Committed in 203704. > > Andrew Sutton short-2.patch Description: Binary data
Re: [c++-concepts] Shorthand notation
I know. When I started working on the project, Gaby asked that I keep all concept-related changes in the top-level Changelog.concepts with full paths for the file names. Andrew Sutton On Fri, Oct 18, 2013 at 8:53 AM, Paolo Carlini wrote: > Hi, > > > On 10/18/2013 02:23 PM, Andrew Sutton wrote: >> >> A small follow up change. This removes the "sorry" from concept name >> resolution. Committed in r203815. >> >> 2013-10-16 Andrew Sutton >> * gcc/cp/constraint.cc (finish_concept_name): Allow functions >> with >> the same name as concepts to resolve as call expressions in the >> usual way. > > Nit: normally this would be just * constraint.cc, because the paths are > relative to the location of the corresponding ChangeLog file (which is under > gcc/cp) > > Thanks! > Paolo.
[c++-concepts] Bugfix
Fixing 2 issues. A test for __is_convertible_to was missing in diagnose_trait, and *somehow* the logic for determining constraint ordering w.r.t. requires expressions was missing. Committed in 203826. 2013-10-16 Andrew Sutton * gcc/cp/logic.cc (left_requires), (decompose_left): Add decomposition rules for requires expressions. (subsumes_requires), (subsumes_prop): Add subsumption rules for requires expressions. * gcc/cp/constraint.cc (diagnose_trait): Diagnose failed conversion requirements. Andrew
[c++-concepts] bitfield reference bugfix
This fixes the longstanding problem with bitfield references. The default dialect was set to cxx1y, which was resulting different conversions for bitfield references. I'm not sure if there's a change in semantics for 1y or if that's a separate bug, but it's not related to concepts. Also prevent an ICE for invalid constrained friends. 2013-10-16 Andrew Sutton * gcc/c-family/c-common.c (cxx_dialect): Make the default language C++11. * gcc/cp/constraint.cc (check_constrained_friend): Don't assert on error_mark_node. Andrew bugfix-2.patch Description: Binary data
Re: [c++-concepts] small tidbits to get it to build
Hi Ed, It looks like we did reserve "assume" as a keyword, but it's not being used... By any chance, did you configure without --disable-bootstrap? I think it would be a better solution to remove the unused keywords -- there were a couple of others that we grabbed for some other concepts-related work, but which aren't included in Concepts Lite. I'll apply the typeck fix. Andrew Sutton On Tue, Oct 22, 2013 at 10:02 PM, Ed Smith-Rowland <3dw...@verizon.net> wrote: > I had to get past two small bugs to get c++-concepts to build. > Take a good look because I'm not sure if they're right. The solutions > should be harmless though. > > Ed >
[c++-concepts] Specialization of concepts
This patch disallows the explicit specialization of concepts, as required by the specification. It also fixes an ICE when comparing overloads of non-template members. 2013-10-23 Andrew Sutton * gcc/cp/class.c (get_member_fntemplate): New. (are_constrained_member_overloads): Only get a template declaration if the member function is, in fact, a template or temploid. * gcc/cp/pt.c (check_explicit_specialization): Do not allow explicit specializations to be declared 'concept', and do not allow an explicit specialization of a concept. * gcc/cp/decl.c (grokfndecl): Propagate the concept flag to check_explicit_specialization. Committed in r203970. Andrew bugfix-3.patch Description: Binary data
Re: [c++-concepts] small tidbits to get it to build
Hi Ed, I committed half of your patch (the unused variable part) in r204011 and removed the unused keywords as a resolution for the other half in r204012. Changelog/patch follow: 2013-10-24 Andrew Sutton * gcc/cp/c-common.c (c_common_r): Remove unused keywords "assume", "axiom", and "forall". * gcc/cp/c-common.h (rid): Removed unused reserved word ids. Andrew On Wed, Oct 23, 2013 at 8:05 PM, Ed Smith-Rowland <3dw...@verizon.net> wrote: > On 10/23/2013 08:36 AM, Andrew Sutton wrote: >> >> Hi Ed, >> >> It looks like we did reserve "assume" as a keyword, but it's not being >> used... By any chance, did you configure without --disable-bootstrap? >> >> I think it would be a better solution to remove the unused keywords -- >> there were a couple of others that we grabbed for some other >> concepts-related work, but which aren't included in Concepts Lite. >> >> I'll apply the typeck fix. >> >> Andrew Sutton >> >> >> On Tue, Oct 22, 2013 at 10:02 PM, Ed Smith-Rowland <3dw...@verizon.net> >> wrote: >>> >>> I had to get past two small bugs to get c++-concepts to build. >>> Take a good look because I'm not sure if they're right. The solutions >>> should be harmless though. >>> >>> Ed >>> > I did this: > $ ../gcc_concepts/configure --prefix=/home/ed/bin_concepts > --enable-languages=c,c++,lto > > This is pretty base bones - no special treatment configure and the branch > worked pretty well. > > Ed > keyword.patch Description: Binary data
[c++-concepts] Requires expr in non-templte
This patch prevents the use of requires expressions in non-template scopes. This restriction was relaxed in the most recent version of concepts lite, but the implementation requires some thought. For now, I am marking it an error to make it consistent with previous versions of the spec. 2013-10-25 Andrew Sutton * gcc/cp/parsre.c (cp_parser_requires_expression): Gracefully fail when parsing a requires expr outside a template. Andrew Sutton template-requires.patch Description: Binary data
[c++-concepts] Constrained scope bugfix
Partially fixing a bug that caused lookup errors in valid programs. For example: template pair::type void f(T, U); // Error, no such pair When entering a template scope, we tried to match the template to one having the same constraints. Obviously pair doesn't have Int and Float constraints, and it probably doesn't have a partial specialization with those constraints either. I relaxed the fixup_template_type function so that it would just return the looked-up type without emitting a diagnostic. This fix makes the following a legal, however: template struct S { void f(); } template void S::f() { } // Should be an error The right solution seems to be to diagnose the error only when defining an out-of-class member by verifying that each template scope in the qualified name matches a declaration with the same constraints. 2013-10-30 Andrew Sutton * gcc/cp/semantics.c (fixup_template_type): Don't emit errors when no templates can be found with matching constraints. Index: gcc/cp/semantics.c === --- gcc/cp/semantics.c (revision 203626) +++ gcc/cp/semantics.c (working copy) @@ -2847,8 +2847,35 @@ finish_template_decl (tree parms) // 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. If TYPE is not a class-type (e.g. a typename type), -// then no fixup is needed. +// scope being entered and we may need to match the intended type with +// a constrained specialization. For example: +// +//template +// struct S { void f(); }; #1 +// +//template +// void S::f() { } #2 +// +// We check, in #2, that S 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 that is +// unconstrained, but this is not diagnosed here. +// +//template +// void S::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 +// typename pair::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. Alos 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) { @@ -2866,14 +2893,8 @@ fixup_template_type (tree type) return type; tree cur_constr = TEMPLATE_PARMS_CONSTRAINTS (parms); - // Do the constraints match those of the most general template? - // If the constraints are NULL_TREE, this will match the most general - // template iff it is unconstrained. + // Search for a specialization whose constraints match. tree tmpl = CLASSTYPE_TI_TEMPLATE (type); - if (equivalent_constraints (cur_constr, DECL_CONSTRAINTS (tmpl))) -return type; - - // Can we find a specialization that matches? tree specs = DECL_TEMPLATE_SPECIALIZATIONS (tmpl); while (specs) { @@ -2883,10 +2904,8 @@ fixup_template_type (tree type) specs = TREE_CHAIN (specs); } - // Emit an error, but return the type to allow processing to continue. - // TODO: We should emit candidates since we've just scanned the - // list of template constraints. - error ("type %qT does not match any declarations", type); + // If no specialization matches, then must return the type + // previously found. return type; } @@ -2904,7 +2923,7 @@ finish_template_type (tree name, tree ar type = lookup_template_class (name, args, NULL_TREE, NULL_TREE, entering_scope, tf_warning_or_error | tf_user); - + // If entering a scope, correct the lookup to account for constraints. if (entering_scope) type = fixup_template_type (type);
[c++-concepts] Diagnostics patch
Applying a patch from Ville that adds diagnostics for the concept specifier. Thanks Ville! 2013-10-30 Ville Voutilainen * gcc/cp/decl.c (grokdeclarator): Reject concept keyword in typedefs, function parameters, data members, non-static member functions and variables. Allow static member functions to be concepts. Andrew Sutton Index: gcc/cp/decl.c === --- gcc/cp/decl.c (revision 204092) +++ gcc/cp/decl.c (working copy) @@ -9074,6 +9074,12 @@ if (name == NULL) name = decl_context == PARM ? "parameter" : "type name"; + if (concept_p && typedef_p) +{ + error ("% cannot appear in a typedef declaration"); + return error_mark_node; +} + if (constexpr_p && typedef_p) { error ("% cannot appear in a typedef declaration"); @@ -9387,9 +9393,12 @@ || thread_p) error ("storage class specifiers invalid in parameter declarations"); + /* Function parameters cannot be concept. */ + if (concept_p) + error ("a parameter cannot be declared %"); /* 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_p = 0; @@ -10619,6 +10628,11 @@ uqname, ctype); return error_mark_node; } +if (concept_p) + { +error ("a destructor cannot be %"); +return error_mark_node; + } if (constexpr_p) { error ("a destructor cannot be %"); @@ -10632,6 +10646,12 @@ id_declarator->u.id.unqualified_name); return error_mark_node; } + if (sfk == sfk_constructor) +if (concept_p) + { +error ("a constructor cannot be %"); +return error_mark_node; + } /* Tell grokfndecl if it needs to set TREE_PUBLIC on the node. */ function_context = (ctype != NULL_TREE) ? @@ -10645,7 +10665,7 @@ unqualified_id, virtualp, flags, memfn_quals, rqual, raises, friendp ? -1 : 0, friendp, publicp, - inlinep | (2 * constexpr_p), + inlinep | (2 * constexpr_p) | (4 * concept_p), sfk, funcdef_flag, template_count, in_namespace, attrlist, declarator->id_loc); @@ -10739,8 +10759,12 @@ if (declspecs->gnu_thread_keyword_p) DECL_GNU_TLS_P (decl) = true; } - - if (constexpr_p && !initialized) + if (concept_p) + // TODO: This needs to be revisited once variable + // templates are supported + error ("static data member %qE declared %", + unqualified_id); + else if (constexpr_p && !initialized) { error ("constexpr static data member %qD must have an " "initializer", decl); @@ -10749,7 +10773,10 @@ } else { -if (constexpr_p) + if (concept_p) + error ("non-static data member %qE declared %", + unqualified_id); +else if (constexpr_p) { error ("non-static data member %qE declared %", unqualified_id); @@ -10897,6 +10924,15 @@ { /* It's a variable. */ + // TODO: This needs to be revisited once variable + // templates are supported + if (concept_p) + { + error ("variable %qE declared %", + unqualified_id); + return error_mark_node; + } + /* An uninitialized decl with `extern' is a reference. */ decl = grokvardecl (type, unqualified_id, declspecs, Index: gcc/testsuite/g++.dg/concepts/decl-diagnose.C === --- gcc/testsuite/g++.dg/concepts/decl-diagnose.C (revision 0) +++ gcc/testsuite/g++.dg/concepts/decl-diagnose.C (working copy) @@ -0,0 +1,20 @@ +// { dg-options "-std=c++11" } +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'" } + +concept int f2(); // { dg-error "result must be bool" } +concept bool f3(); + +struct X +{ + concept int f4(); // { dg-error "result must be bool|declared with function parameters" } + concept bool f5(); // { dg-error "declared with function parameters" } + static concept bool f6(); + 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 "declared 'concept'" }
Re: C++ PATCH to implement fold-expressions
Fantastic. I've wanted to get back to this, but since school started back up, I haven't had any time to look at it. Thanks! Andrew On Thu, Sep 17, 2015 at 2:04 PM, Jason Merrill wrote: > Back in January Andrew mostly implemented C++1z fold-expressions > (https://isocpp.org/files/papers/n4295.html), but the patch broke bootstrap. > I've fixed it up now and am committing it to the trunk. > > Andrew: The main change I made was to drop tentative parsing in favor of > scanning the tokens ahead looking for an ellipsis next to a fold-operator. > I also tweaked some diagnostics, fixed handling of dependent expressions > with no TREE_TYPE, and corrected empty fold of modops. > > Tested x86_64-pc-linux-gnu, applying to trunk.
Re: C++ PATCH for non-type constrained-type-specifiers
> I started looking at allowing non-type constrained-type-specifiers in auto > deduction and then realized that we didn't handle them in function > parameters either. Fixing that brought home to me the oddity of having a > type-specifier stand in for a non-type. Mind weighing in on that on the > core reflector? That is a little weird. The non-type placeholders should be id-expressions that name a concept. And template placeholders would be template-names. I'll create an issue for it. I need to email Mike Miller and figure out how issues processing will work. But not until I'm out of the weeds for the semester. > I also wonder why we have two different ways of expressing a > constrained-type-specifier in the implementation: a constrained > template-parameter (TYPE_DECL, is_constrained_parameter) and a constrained > auto (TEMPLATE_TYPE_PARM). Why not represent them the same way? It's probably a historical distinction. We didn't get concepts as placeholders until much later in the standardization process. But with auto template parameters on the horizon, it might be worthwhile to maintain the distinction. That feature adds a wonderful little ambiguity: template struct S; would declare a non-type template parm whose type is deduced from a template argument. template concept bool C = true; template struct S; Is C a constrained placeholder (as per a reasonable interpretation of parameter-declarations), or does it declare a type parameter (as per the TS)? It's going to end up being the latter. Combining the representations might make it difficult to tease out intent later. But that's just me speculating. Andrew
[PATCH] concepts cleanups and subsumption caching
This patch finishes moving concepts-related functionality out of pt.c and into constraint.cc an logic.cc, and adds logic.cc to gtfiles. As part of that cleanup, I reimplemented and reenabled the subsumption caching. It's not clear if this provides any significant performance benefits, but it will prevent redundant and potentially costly comparisons of constraints. Tested on bootstrap and vs. cmcstl2. Andrew Sutton cleanup.patch Description: Binary data
[PATCH] diagnose hard errors in concept satisfaction
Certain errors encountered during constraint satisfaction render the program ill-formed. Emit those as errors during satisfaction and not when diagnosing constraint errors. The errors should include the full context for failure (i.e., when satisfying X, when satisfying Y, this failed), but we don't build that information until we know we need to diagnose an error. This patch does not include that context. Andrew Sutton errors.patch Description: Binary data
[PATCH] fix constrained auto parsing issue
This fixes a parsing bug with constrained placeholders uses as the first parameter of a constructor. Andrew Sutton 0001-Fix-a-bug-with-type-constraints-in-constructors.patch Description: Binary data
Re: [PATCH] fix constrained auto parsing issue
In cp_parser_simple_type_specifier: if (!type && flag_concepts && decl_specs) { /* Try for a type-constraint with template arguments. We check decl_specs here to avoid trying this for a functional cast. */ ... It's subtle. Andrew Sutton On Mon, Oct 21, 2019 at 2:22 PM Jason Merrill wrote: > > On 10/17/19 10:36 AM, Andrew Sutton wrote: > > This fixes a parsing bug with constrained placeholders uses as the > > first parameter of a constructor. > > > + Parse with an empty set of declaration specifiers since we're > > + trying to match a type-specifier of the first parameter. */ > > Why does that make a difference? > > Jason >
[PATCH] PR c++/92078 Add access specifiers to specializations
Fixes mentioned issue. Tested on bootstrap and cmcsstl2. gcc/cp/ * pt.c (maybe_new_partial_specialization): Apply access to newly created partial specializations. Update comment style. gcc/testsuite/ * g++.dg/cpp2a/concepts-pr92078.C: New. Andrew pr92078.patch Description: Binary data
[PATCH] Fixes PR c++/89913
Avoid ICE when the alias is ill-formed. gcc/cp/ * pt.c (get_underlying_template): Exit loop if the original type of the alias is null. gcc/testsuite/ * g++.dg/cpp2a/pr89913.C: New test. Andrew Sutton 0001-Don-t-segfault-on-error-PR-c-89913.patch Description: Binary data
[PATCH] Prevent recursive satisfaction (PR c++/88395)
This applies on top of the patch here: https://gcc.gnu.org/ml/gcc-patches/2019-11/msg01034.html Wrap satisfaction with push/pop_tinst_level to force termination on recursion. Andrew Sutton 0001-Prevent-recursive-satisfaction-PR-c-88395.patch Description: Binary data
Re: [PATCH] Prevent recursive satisfaction (PR c++/88395)
I forgot to mention a somewhat odd test included in the patch: concepts-recursive-sat3.C does not recurse. Code follows: template concept Fooable = requires(T t) { foo(t); }; template void foo(T t) { } void test() { foo(0); // { dg-error "unsatisfied constraints" } } It doesn't crash, but it doesn't diagnose also doesn't fail as a result of recursive instantiation. The recursive-sat2.C test is the same except that it instantiates foo with a class type. This seems like it might be related to ADL, but entirely certain. Andrew Sutton On Mon, Nov 18, 2019 at 10:13 AM Andrew Sutton wrote: > > This applies on top of the patch here: > https://gcc.gnu.org/ml/gcc-patches/2019-11/msg01034.html > > Wrap satisfaction with push/pop_tinst_level to force termination on recursion. > > Andrew Sutton
[PATCH] PR c++/92236: Improve static assertions of concepts
This patch builds on https://gcc.gnu.org/ml/gcc-patches/2019-11/msg01034.html. Tie static assertion diagnostics into constraint diagnostic. For example, this program: template concept iterator = requires (I i) { ++i; *i; }; static_assert(iterator); Yields these errors: x.cpp:11:15: error: static assertion failed 11 | static_assert(iterator); | ^ x.cpp:11:15: note: constraints not satisfied x.cpp:4:9: required by the constraints of ‘template concept iterator’ x.cpp:5:3: in requirements with ‘int i’ x.cpp:8:5: note: the required expression ‘* i’ is invalid 8 | *i; | ^~ Andrew Sutton 0001-Emit-detailed-diagnostics-for-static-assertion-failu.patch Description: Binary data
[PATCH] PR c++/92439: Improve diagnostics for ill-formed requires-clauses
This does a much better job identifying when an expression in a requires-clause needs parentheses. Andrew Sutton 0001-PR-c-92439.patch Description: Binary data
Re: [PATCH] Prevent recursive satisfaction (PR c++/88395)
> > + if (tmpl) > > + push_tinst_level (tmpl); > > Actually, why not pass 't' here? I thought it would matter if 't' was a non-template. Turns out it doesn't. Updated and committed.
[PATCH] PR C++/92739
Find attached. gcc/cp/ * parser.c (cp_parser_constraint_requires_parens): Exclude attributes as postfix expressions. gcc/testsuite/ * g++.dg/concepts-pr92739.C: New test. Andrew Sutton 0001-Fix-PR-c-92739.patch Description: Binary data
Re: Patch for constexpr variable templates
This patch prevents the initializer from being checked when it is dependent. It also sets the type of a dependent template-id referring to a variable template to be unknown, making such expressions type dependent. 2014-08-07 Andrew Sutton * pt.c (lookup_template_variable): Make the type unspecified if any template arguments are dependent. * decl.c (cp_finish_decl): Don't check the initializer if it is value-dependent. New test included. Andrew Sutton On Wed, Aug 6, 2014 at 9:34 PM, Jason Merrill wrote: > On 08/05/2014 04:06 PM, Paolo Carlini wrote: >> >> Great. I will double check but var-templ4.C fails for me with an ICE. > > > Hunh, I wonder how I missed that. > > Here's what I'm checking in; we want to unset DECL_COMDAT for variable > templates, too. > > Index: gcc/testsuite/g++.dg/cpp1y/var-templ6.C === --- gcc/testsuite/g++.dg/cpp1y/var-templ6.C (revision 0) +++ gcc/testsuite/g++.dg/cpp1y/var-templ6.C (revision 0) @@ -0,0 +1,12 @@ +// { dg-options "-std=c++1y" } + +template + constexpr bool Class = __is_class(T); + +template + constexpr bool Test = Class; + +struct S { }; + +static_assert(!Test, ""); +static_assert(Test, ""); Index: gcc/cp/decl.c === --- gcc/cp/decl.c (revision 213667) +++ gcc/cp/decl.c (working copy) @@ -6417,19 +6417,20 @@ cp_finish_decl (tree decl, tree init, bo DECL_INITIAL (decl) = NULL_TREE; } + bool value_dependent_p = init && value_dependent_init_p (init); + /* Generally, initializers in templates are expanded when the template is instantiated. But, if DECL is a variable constant then it can be used in future constant expressions, so its value must be available. */ - - if (!VAR_P (decl) || dependent_type_p (type)) + if (!VAR_P (decl) || type_dependent_p || value_dependent_p) /* We can't do anything if the decl has dependent type. */; else if (init && init_const_expr_p && !type_dependent_p && decl_maybe_constant_var_p (decl) && !type_dependent_init_p (init) - && !value_dependent_init_p (init)) + && !value_dependent_p) { /* This variable seems to be a non-dependent constant, so process its initializer. If check_initializer returns non-null the Index: gcc/cp/pt.c === --- gcc/cp/pt.c (revision 213667) +++ gcc/cp/pt.c (working copy) @@ -8260,13 +8260,23 @@ lookup_template_class (tree d1, tree arg return ret; } -/* Return a TEMPLATE_ID_EXPR for the given variable template and ARGLIST. */ +/* Return a TEMPLATE_ID_EXPR for the given variable template and ARGLIST. + If the ARGLIST refers to any template parameters, the type of the + expression is the unknown_type_node since the template-id could + refer to an explicit or partial specialization. +*/ tree lookup_template_variable (tree templ, tree arglist) { - return build2 (TEMPLATE_ID_EXPR, TREE_TYPE (templ), templ, arglist); + tree type; + if (uses_template_parms (arglist)) +type = unknown_type_node; + else +type = TREE_TYPE (templ); + return build2 (TEMPLATE_ID_EXPR, type, templ, arglist); } + struct pair_fn_data {
Re: Patch for constexpr variable templates
>> * decl.c (cp_finish_decl): Don't check the initializer if it is >> value-dependent. > > > Why is this needed? I thought that check_initializer was evaluating the constant expression, and was resulting in errors because a template-id referring to a variable template with a concrete type wasn't being marked as dependent. Taking a second look, this change doesn't appear to be needed. The change to lookup_template_variable seems to do enough. I just reran the tests and it seems to behave correctly without it. Andrew
[c++-concepts] constraints redux
This patch revisits the normalization and checking of constraints. In particular, it ensures that associated constraints are always normalized so that checking constraints will never instantiate a concept declaration. This also removes the constraint check from fn_type_unification as per discussion in Rapperswil. Candidates whose constraints are not satisfied are just marked non-viable in overload resolution. This also clears up an issue where constraints for function templates were being checked twice during overload resolution. I also ended up renaming a lot of functions to make them match the wording the specification. Basically, "requirements -> constraints". Updated all affected tests. 2014-08-08 Andrew Sutton * gcc/cp/logic.cc (subsumes_constraints_nonnull): Don't re-normalize constraints, it's already been done. * gcc/cp/cp-tree.h (*_requirement[s]): Renamed to *_constraint[s] to reflect wording in specification. Removed reduce_requirements. * gcc/cp/pt.c (process_template_parm, tsubst_pack_conjunction): Update from renaming. (fn_type_unification): Remove constraint check. * gcc/cp/parser.c (cp_parser_type_parameter, cp_parser_trailing_requirements, cp_parser_template_declaration_after_export, synthesize_implicit_template_parm): Update from renaming. * gcc/cp/constraint.cc: Renamed a lot of functions to reflect wording in specification. (finish_template_constraints): Normalize associated constraints. (tsubst_constraint_expr): Renamed from instantiate_requirements. Normalize associated constraints. (check_satisfied): Return true if the arguments refer to template parameters. (all_constraints_satisfied, any_conjunctions_satisfied, check_requirements): No longer needed. (check_diagnostic_constraints): Just normalize the expression, don't decompose it. Andrew Sutton Index: gcc/cp/cp-tree.h === --- gcc/cp/cp-tree.h (revision 213667) +++ gcc/cp/cp-tree.h (working copy) @@ -6079,10 +6079,6 @@ extern tree maybe_resolve_dummy (tree, extern tree nonlambda_method_basetype (void); extern void maybe_add_lambda_conv_op(tree); extern bool is_lambda_ignored_entity(tree); -extern tree finish_template_requirements(tree); -extern tree save_leading_requirements (tree); -extern tree save_trailing_requirements (tree); -extern bool valid_requirements_p(tree); /* in tree.c */ extern int cp_tree_operand_length (const_tree); @@ -6415,20 +6411,23 @@ extern void suggest_alternatives_for extern tree strip_using_decl(tree); /* in constraint.cc */ -extern tree conjoin_requirements(tree, tree); -extern tree conjoin_requirements(tree); -extern tree reduce_requirements (tree); +extern tree conjoin_constraints (tree, tree); +extern tree conjoin_constraints (tree); extern tree get_constraints (tree); extern void set_constraints (tree, tree); -extern tree get_shorthand_requirements (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 bool deduce_constrained_parameter(tree, tree&, tree&); extern tree resolve_constraint_check(tree); +extern tree finish_template_constraints (tree); +extern tree save_leading_constraints(tree); +extern tree save_trailing_constraints (tree); +extern bool valid_requirements_p(tree); extern tree finish_concept_name (tree); -extern tree finish_shorthand_requirement(tree, tree); +extern tree finish_shorthand_constraint (tree, tree); extern tree finish_requires_expr(tree, tree); extern tree finish_expr_requirement (tree, tree, tree); extern tree finish_expr_requirement (tree); @@ -6439,8 +6438,6 @@ extern tree finish_noexcept_requirement extern tree finish_validexpr_expr (tree); extern tree finish_validtype_expr (tree); extern tree finish_constexpr_expr (tree); -extern tree finish_concept_name (tree); -extern tree finish_shorthand_requirement(tree, tree); extern void check_constrained_friend(tree, tree); @@ -6452,8 +6449,8 @@ extern tree tsubst_expr_req extern tree tsubst_type_req (tree, tree, tree); extern tree tsubst_nested_req (tree, tree, tree); -extern tree instantiate_requirements(tree, tree, bool); extern tree tsubst_constraint_info
[c++-concepts] substitution fixes
Fixing some bugs substituting through constraints. In particular, when diagnosing an error, make sure that we use the right arguments. There was also a bug caused by substitution through a decltype-type. In particular, when folding a non-dependent expression containing a decltype-type, the inner type is not being resolved (because tsubst returns early when args == NULL_TREE). The second patch fixes a regression introduced by the first patch. 2014-08-11 Andrew Sutton * gcc/cp/pt.c (tsubst): Don't short circuit substitution into types when processing constraints. * gcc/cp/constraint.c (tsubst_constraint_expr): Indicate that constraint processing is happening. (tsubst_constraint_info): Just substitute directly into the normalized constraints instead of re-normalizing. (diagnose_constraints): Adjust template arguments when diagnosing template constraint failures. * gcc/cp/logic.cc (decompose_assumptions): Handle null assumptions. Andrew Sutton Index: pt.c === --- pt.c (revision 213758) +++ pt.c (working copy) @@ -11960,6 +11960,8 @@ tsubst_exception_specification (tree fnt return new_specs; } +extern int processing_constraint; + /* Take the tree structure T and replace template parameters used therein with the argument vector ARGS. IN_DECL is an associated decl for diagnostics. If an error occurs, returns ERROR_MARK_NODE. @@ -11994,7 +11996,7 @@ tsubst (tree t, tree args, tsubst_flags_ if (DECL_P (t)) return tsubst_decl (t, args, complain); - if (args == NULL_TREE) + if (args == NULL_TREE && !processing_constraint) return t; code = TREE_CODE (t); Index: semantics.c === --- semantics.c (revision 213758) +++ semantics.c (working copy) @@ -7011,6 +7011,7 @@ finish_decltype_type (tree expr, bool id return type; } + /* The type denoted by decltype(e) is defined as follows: */ expr = resolve_nondeduced_context (expr); @@ -7386,7 +7387,7 @@ finish_trait_expr (cp_trait_kind kind, t || kind == CPTK_IS_LITERAL_TYPE || kind == CPTK_IS_POD || kind == CPTK_IS_POLYMORPHIC -|| kind == CPTK_IS_SAME_AS + || kind == CPTK_IS_SAME_AS || kind == CPTK_IS_STD_LAYOUT || kind == CPTK_IS_TRIVIAL || kind == CPTK_IS_UNION); Index: constraint.cc === --- constraint.cc (revision 213758) +++ constraint.cc (working copy) @@ -241,7 +241,7 @@ tree normalize_stmt (tree); tree normalize_decl (tree); tree normalize_misc (tree); tree normalize_logical (tree); -tree normalize_call(tree); +tree normalize_call (tree); tree normalize_requires (tree); tree normalize_expr_req (tree); tree normalize_type_req (tree); @@ -1114,14 +1114,14 @@ tsubst_local_parms (tree t, } // Substitute ARGS into the requirement body (list of requirements), T. +// Note that if any substitutions fail, then this is equivalent to +// returning false. tree tsubst_requirement_body (tree t, tree args, tree in_decl) { tree r = NULL_TREE; while (t) { - // If any substitutions fail, then this is equivalent to - // returning false. tree e = tsubst_expr (TREE_VALUE (t), args, tf_none, in_decl, false); if (e == error_mark_node) e = boolean_false_node; @@ -1142,7 +1142,6 @@ tsubst_requires_expr (tree t, tree args, return finish_requires_expr (p, r); } - // Substitute ARGS into the valid-expr expression T. tree tsubst_validexpr_expr (tree t, tree args, tree in_decl) @@ -1197,6 +1196,12 @@ tsubst_nested_req (tree t, tree args, tr return tsubst_expr (TREE_OPERAND (t, 0), args, tf_none, in_decl, false); } +// Used in various contexts to control substitution. In particular, when +// non-zero, the substitution of NULL arguments into a type will still +// process the type as if passing non-NULL arguments, allowing type +// expressions to be fully elaborated during substitution. +int processing_constraint; + // Substitute the template arguments ARGS into the requirement // expression REQS. Errors resulting from substitution are not // diagnosed. @@ -1208,11 +1213,13 @@ tree tsubst_constraint_expr (tree reqs, tree args, bool do_not_fold) { cp_unevaluated guard; + ++processing_constraint; if (do_not_fold) ++processing_template_decl; tree r = tsubst_expr (reqs, args, tf_none, NULL_TREE, false); if (do_not_fold) --processing_template_decl; + --processing_constraint; return r; } @@ -1230,10 +1237,8 @@ tsubst_constraint_info (tree ci, tree ar result->leading_reqs = tsubst_constraint_expr (r, args, true); if (tree r = CI_TRAILING_REQS (ci)) result->trailing_reqs = tsubst_constraint_expr (r, args, true); - - // Build the normalized associated requiremnts. - tree r =
Re: Patch for constexpr variable templates
>> * pt.c (lookup_template_variable): Make the type unspecified if >> any template arguments are dependent. > > > This hunk is OK. Hi Jason, did you apply this hunk of the patch, or should I just resend this by itself? Andrew
Re: Patch for constexpr variable templates
Oohh... I can commit to trunk? I can do it tomorrow morning. Andrew Sutton On Tue, Aug 12, 2014 at 4:59 PM, Jason Merrill wrote: > On 08/12/2014 04:21 PM, Andrew Sutton wrote: >>>> >>>> * pt.c (lookup_template_variable): Make the type unspecified >>>> if >>>> any template arguments are dependent. >>> >>> >>> >>> This hunk is OK. >> >> >> Hi Jason, did you apply this hunk of the patch, or should I just >> resend this by itself? > > > I thought you would apply it, but I can if you'd rather. > > Jason >
Re: [c++-concepts] variable concepts
Committed. Andrew Sutton On Wed, Aug 13, 2014 at 3:24 AM, Braden Obrzut wrote: > This patch adds support for variable concepts. > > There is a known issue that prevents concept variables from having requires > expressions that have parameters. This issue is not within the scope of > this patch as it affects adhoc requires expressions as well. > > 2014-08-13 Braden Obrzut > > * gcc/cp/constraint.cc (deduce_constrained_parameter): Deduce concept > from variable concept template-id expressions. > (normalize_var): New. > (normalize_template_id): Identify variable concepts. > (build_concept_check): Handle variable concepts. > (finish_shorthand_requirement): Handle variable concepts. > (diagnose_var): New. > (diagnose_node): Identify variable concepts. > * gcc/cp/decl.c (grokvardecl): Pass concept flag through to > check_explicit_specialization. > (grokdeclarator): Allow variable concepts and pass concept flag through > grokvardecl. > * gcc/cp/parser.c (cp_is_constrained_parameter): Accept variable > concepts. > (cp_parser_nonclass_name): Accept variable concepts. > (get_concept_from_constraint): Handle variable concepts. > * gcc/cp/pt.c (tsubst_copy_and_build): Lookup variable templates. > (value_dependent_expression_p): Check requires expressions for value > dependence. > * gcc/cp/semantics.c (finish_call_expr): Don't instantiate variable > templates if processing a template declaration. > * gcc/testsuite/g++.dg/concepts/decl-diagnose.C: Change expected error > as variable concepts are now handled. > * gcc/testsuite/g++.dg/concepts/var-concepts1.C: New test. > * gcc/testsuite/g++.dg/concepts/var-concepts2.C: New test. >
Re: Patch for constexpr variable templates
>> Oohh... I can commit to trunk? > > Yes, you're on the write-after-approval list in MAINTAINERS. :) True, but it's my first commit to trunk :) Incidentally, that's committed now. Andrew
[c++-concepts] explicit instantiation and specialization
This patch re-implements explicit instantiation and specialization. The latter isn't fully tested just yet, but it's close. Constraints for explicit instantiations and specializations are deduced from their candidates, not explicitly specified as part of the declaration. 2014-08-13 Andrew Sutton Implement deduction-based explicit instantiation and specialization. * gcc/cp/call.c (joust): Allow all non-templates to be ordered by constraints. * gcc/cp/pt.c (get_class_bindings): Remove superfluous parameter and move constraint check into most_specialized_class. (most_constrained_function): Order functions with the same signatures by their constraints. (determine_specialization): Candidates must satisfy constraints. Also, order non-template candidates by constraints. Improve diagnostics for instances where candidates are rejected. (more_specialized_inst): New. Compare function templates. (most_specialized_instantiation): Refactor to use more_specialized_inst and order by constraints. (most_specialized_class): Candidates must satisfy constraints. * gcc/cp/decl.c (various) Cosmetic fixes. (adjust_fn_constraints): Rewrite so that class template constraints are not imposed on member function declarations. * gcc/testsuite/g++.dg/concepts: New tests. Andrew Sutton Index: gcc/cp/decl.c === --- gcc/cp/decl.c (revision 213909) +++ gcc/cp/decl.c (working copy) @@ -991,11 +991,6 @@ decls_match (tree newdecl, tree olddecl) if (t1 != t2) return 0; - // Normal functions can be constraind. Two functions with the - // same type and different constraints are different functions. - tree c1 = get_constraints (newdecl); - tree c2 = get_constraints (olddecl); - if (CP_DECL_CONTEXT (newdecl) != CP_DECL_CONTEXT (olddecl) && ! (DECL_EXTERN_C_P (newdecl) && DECL_EXTERN_C_P (olddecl))) @@ -1014,6 +1009,11 @@ decls_match (tree newdecl, tree olddecl) type for declaration matching. */ r2 = fndecl_declared_return_type (olddecl); + // Normal functions can be constraind. Two functions with the + // same type and different constraints are different functions. + tree c1 = get_constraints (newdecl); + tree c2 = get_constraints (olddecl); + if (same_type_p (TREE_TYPE (f1), r2)) { if (!prototype_p (f2) && DECL_EXTERN_C_P (olddecl) @@ -1041,7 +1041,7 @@ decls_match (tree newdecl, tree olddecl) TREE_TYPE (newdecl) = TREE_TYPE (olddecl); } #endif - else { + else types_match = compparms (p1, p2) && type_memfn_rqual (f1) == type_memfn_rqual (f2) @@ -1049,7 +1049,6 @@ decls_match (tree newdecl, tree olddecl) && (TYPE_ATTRIBUTES (TREE_TYPE (newdecl)) == NULL_TREE || comp_type_attributes (TREE_TYPE (newdecl), TREE_TYPE (olddecl)) != 0); - } } else types_match = 0; @@ -7564,24 +7563,54 @@ get_leading_constraints () // parameter list. The adjustment makes them part of the current // template requirements. static void -adjust_out_of_class_fn_requirements (tree ctype) +adjust_fn_constraints (tree ctype) { + // When grokking a member function template, we are processing + // template decl at a depth greater than that of the member's + // enclosing class. That is, this case corresponds to the + // following declarations: + // + //template + //struct S { + // template void f(U); + //}; + // + //template template void S::f(U) { } + // + // In both decls, the constraint D is not the current leading + // constraint. Make it so. + // + // Note that for normal member functions, there are no leading + // requirements we need to gather. if (ctype && processing_template_decl > template_class_depth (ctype)) { if (tree ci = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms)) { + // TODO: When do I ever have leading requirements for a + // member function template? tree reqs = CI_LEADING_REQS (ci); if (reqs && !get_leading_constraints ()) current_template_reqs = save_leading_constraints (reqs); } } - else if (current_template_parms) + + // Otherwise, this is just a regular function template. Like so: + // + //template void f(); + // + // Note that the constraint C is not the current leading requirement + // at this point; it was stashed before the declarator was parsed. + // Make it the leading constraint. + else if (!ctype && current_template_parms) { if (tree ci = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms)) { tree r1 = CI_LEADING_REQS (ci); if (current_template_reqs) { +// TODO: As with a
Re: [c++-concepts] explicit instantiation and specialization
Ah... sorry. Leftovers. I didn't have time to run a full bootstrap build before heading out for a few days. I'll try to get those out tomorrow afternoon-ish. Andrew On Wed, Aug 13, 2014 at 9:13 PM, Ed Smith-Rowland <3dw...@verizon.net> wrote: > I get build fail: > > ../../gcc_concepts/gcc/cp/call.c:8793:8: error: unused variable ‘m1’ > [-Werror=unused-variable] >tree m1 = get_temploid (cand1); > ^ > ../../gcc_concepts/gcc/cp/call.c:8794:8: error: unused variable ‘m2’ > [-Werror=unused-variable] >tree m2 = get_temploid (cand2); > ^ > cc1plus: all warnings being treated as errors > > Commenting the lines let the build finish. > > Ed >
Re: [c++-concepts] explicit instantiation and specialization
Just committed this patch, fixing the bootstrap. 2014-08-13 Andrew Sutton Fix regression in bootstrap. * gcc/cp/call.c (get_temploid): Removed. No longer called. (joust): Remove unused variable declarations. Andrew On Wed, Aug 13, 2014 at 9:50 PM, Andrew Sutton wrote: > Ah... sorry. Leftovers. I didn't have time to run a full bootstrap > build before heading out for a few days. I'll try to get those out > tomorrow afternoon-ish. > > Andrew > > > On Wed, Aug 13, 2014 at 9:13 PM, Ed Smith-Rowland <3dw...@verizon.net> wrote: >> I get build fail: >> >> ../../gcc_concepts/gcc/cp/call.c:8793:8: error: unused variable ‘m1’ >> [-Werror=unused-variable] >>tree m1 = get_temploid (cand1); >> ^ >> ../../gcc_concepts/gcc/cp/call.c:8794:8: error: unused variable ‘m2’ >> [-Werror=unused-variable] >>tree m2 = get_temploid (cand2); >> ^ >> cc1plus: all warnings being treated as errors >> >> Commenting the lines let the build finish. >> >> Ed >> Index: gcc/cp/call.c === --- gcc/cp/call.c (revision 213924) +++ gcc/cp/call.c (working copy) @@ -8755,24 +8755,6 @@ add_warning (struct z_candidate *winner, winner->warnings = cw; } -// When a CANDidate function is a member function of a class template -// specialization, return the temploid describing that function. -// Returns NULL_TREE otherwise. -static inline tree -get_temploid (struct z_candidate *cand) -{ - gcc_assert (cand); - tree t = NULL_TREE; - if (!cand->template_decl) -{ - if (DECL_P (cand->fn) && DECL_USE_TEMPLATE (cand->fn)) -t = DECL_TI_TEMPLATE (cand->fn); - if (t && TREE_CODE (t) == TEMPLATE_INFO) -t = TI_TEMPLATE (t); -} -return t; -} - /* Compare two candidates for overloading as described in [over.match.best]. Return values: @@ -8789,10 +8771,6 @@ joust (struct z_candidate *cand1, struct size_t i; size_t len; - // Try to get a temploid describing each candidate. - tree m1 = get_temploid (cand1); - tree m2 = get_temploid (cand2); - /* Candidates that involve bad conversions are always worse than those that don't. */ if (cand1->viable > cand2->viable)
[c++-concepts] 2 patches
The first improves support for shorthand concepts, and includes the ability to write default arguments. Also, no more ICE when omitting identifiers for template parameters. The second adds constraint checks when taking the address of an overloaded function. Corresponding change logs follow: 2014-08-13 Andrew Sutton * gcc/cp/class.c (resolve_address_of_overloaded_function): Check constraints. * gcc/cp/decl.c (grokfndecl): For now, disallow constrained non-template functions. * gcc/testsuite/g++.dg/concepts: New tests. 2014-08-13 Andrew Sutton * gcc/cp/parser.c (get_id_declarator, get_identifier): New helper functions.s (cp_check_constrained_type_parm): Don't fail on null declarators. (cp_finish_constrained_parameter): Remove redundant processing for checking declarations. (cp_maybe_type_parameter, cp_declares_type_parameter, cp_declares_type_template_parameter, cp_declares_template_template_parameter): New helper functions for determining when a parameter declaration is actually a constrained template parameter. (cp_parser_default_type_template_argument, cp_parser_default_template_template_argument): Parsing support for argument types of default arguments. (cp_parser_template_parameter): Finish constrained parameters after all variadic and default arg checks. (cp_parser_parameter_declaration): Parse default arguments differently if the parameter actually declares a type parameter. * gcc/testsuite/g++.dg/concepts: New tests. Andrew Sutton Index: gcc/cp/parser.c === --- gcc/cp/parser.c (revision 213909) +++ gcc/cp/parser.c (working copy) @@ -13221,6 +13221,29 @@ cp_parser_template_parameter_list (cp_pa return end_template_parm_list (parameter_list); } +// Given a declarator, get the declarator-id part, or NULL_TREE if this +// is an abstract declarator. +static inline cp_declarator* +cp_get_id_declarator (cp_declarator *declarator) +{ + cp_declarator *d = declarator; + while (d && d->kind != cdk_id) +d = d->declarator; + return d; +} + +// Get the declared name from the DECLARATOR or NULL_TREE if this is +// DECLARATOR is NULL +static inline tree +cp_get_identifier (cp_declarator *declarator) +{ + declarator = cp_get_id_declarator (declarator); + if (declarator) +return declarator->u.id.unqualified_name; + else +return NULL_TREE; +} + // Returns true if PARM declares a constrained-parameter. static inline bool cp_is_constrained_parameter (cp_parameter_declarator *parm) @@ -13242,8 +13265,9 @@ bool cp_check_constrained_type_parm (cp_parser *parser, cp_parameter_declarator *parm) { - // Don't ptr, ref, function, or array declarators for a constrained type - // or template template parameter. + if (!parm->declarator) +return true; + if (parm->declarator->kind != cdk_id) { cp_parser_error (parser, "invalid constrained type parameter"); @@ -13320,28 +13344,16 @@ cp_finish_constrained_parameter (cp_pars bool *is_parameter_pack) { tree decl = parmdecl->decl_specifiers.type; - tree id = parmdecl->declarator->u.id.unqualified_name; + tree id = cp_get_identifier (parmdecl->declarator); tree def = parmdecl->default_argument; tree proto = DECL_INITIAL (decl); - // Remember if the user declared this as a parameter pack and - // erase that flag on the annotation. Template packs are dealt - // with separately. - bool is_pack = parmdecl->declarator->parameter_pack_p; - if (is_pack) -parmdecl->declarator->parameter_pack_p = false; - - // Is the prototype a parameter pack? If so, but the declaration - // does not include "...", then emit an error. + // A templat parameter constrained by a variadic concept shall also + // be declared as a template parameter pack. bool is_variadic = template_parameter_pack_p (proto); - if (is_variadic && !is_pack) + if (is_variadic && !*is_parameter_pack) cp_parser_error (parser, "variadic constraint introduced without %<...%>"); - // The prototype is a template parameter pack, then the resulting - // parameter also needs to be a pack. - if (is_pack || is_variadic) -*is_parameter_pack = true; - // Build the parameter. Return an error if the declarator // was invalid. tree parm; @@ -13361,6 +13373,111 @@ cp_finish_constrained_parameter (cp_pars return parm; } +// Returns the type of the given TYPE may represent the declaration of +// a template type parameter. This is a helper function for the +// cp_declares_type* functions below. +static inline bool +cp_maybe_type_parameter (tree type) +{ + return type + && TREE_CODE (ty
[c++-concepts] normalization checks
This patch adds checks for user-defined logical operators during constraint normalization and ensures that all atomics can be converted to bool. 2014-08-14 Andrew Sutton Implement normalization checks. * gcc/cp/constraint.cc (normalize_expr): Delegate cast and atomic nodes to a dedicated function. (check_logical): Check that an && or || does not resolve to a user-defined function. (normalize_logical): Check operators and save the locaiton of the new expression. (normalize_call, normalize_var): Remove spurios error messages. (normalize_cast): New, delegates to normalize atom. (normalize_atom): Check that instantiated expressions can be converted to bool (tsubst_constraint_info): Re-normalize the associated constraints to check for post-substitution restrictions. * gcc/cp/cp-tree.h (xvalue_result_type): Add to header. Andrew Sutton Index: gcc/cp/constraint.cc === --- gcc/cp/constraint.cc (revision 213924) +++ gcc/cp/constraint.cc (working copy) @@ -264,6 +264,8 @@ tree normalize_nested_req (tree); tree normalize_var (tree); tree normalize_template_id (tree); tree normalize_stmt_list (tree); +tree normalize_cast (tree); +tree normalize_atom (tree); // Reduce the requirement T into a logical formula written in terms of // atomic propositions. @@ -328,7 +330,7 @@ normalize_expr (tree t) return normalize_template_id (t); case CAST_EXPR: - return normalize_node (TREE_VALUE (TREE_OPERAND (t, 0))); + return normalize_cast (t); case BIND_EXPR: return normalize_node (BIND_EXPR_BODY (t)); @@ -339,7 +341,7 @@ normalize_expr (tree t) // Everything else is atomic. default: - return t; + return normalize_atom (t); } } @@ -402,6 +404,34 @@ normalize_misc (tree t) return NULL_TREE; } +// Check that the logical expression is not a user-defined operator. +bool +check_logical (tree t) +{ + // We can't do much for type dependent expressions. + if (type_dependent_expression_p (t) || value_dependent_expression_p (t)) +return true; + + // Resolve the logical operator. Note that template processing is + // disabled so we get the actual call or target expression back. + // not_processing_template_sentinel sentinel; + tree arg1 = TREE_OPERAND (t, 0); + tree arg2 = TREE_OPERAND (t, 1); + + tree ovl = NULL_TREE; + tree expr = build_new_op (input_location, TREE_CODE (t), LOOKUP_NORMAL, +arg1, arg2, /*arg3*/NULL_TREE, +&ovl, tf_none); + if (TREE_CODE (expr) != TREE_CODE (t)) +{ + error ("user-defined operator %qs in constraint %qE", + operator_name_info[TREE_CODE (t)].name, t); + ; + return false; +} + return true; +} + // Reduction rules for the binary logical expression T (&& and ||). // // Generate a new expression from the reduced operands. If either operand @@ -409,14 +439,18 @@ normalize_misc (tree t) tree normalize_logical (tree t) { + if (!check_logical (t)) +return NULL_TREE; + tree l = normalize_expr (TREE_OPERAND (t, 0)); tree r = normalize_expr (TREE_OPERAND (t, 1)); if (l && r) { - t = copy_node (t); - TREE_OPERAND (t, 0) = l; - TREE_OPERAND (t, 1) = r; - return t; + tree result = copy_node (t); + SET_EXPR_LOCATION (result, EXPR_LOCATION (t)); + TREE_OPERAND (result, 0) = l; + TREE_OPERAND (result, 1) = r; + return result; } else return NULL_TREE; @@ -440,18 +474,13 @@ normalize_call (tree t) // Reduce the body of the function into the constriants language. tree body = normalize_constraints (DECL_SAVED_TREE (fn)); if (!body) -{ - error ("could not inline requirements from %qD", fn); - return error_mark_node; -} +return error_mark_node; // Instantiate the reduced results using the deduced args. tree result = tsubst_constraint_expr (body, args, false); if (result == error_mark_node) -{ - error ("could not instantiate requirements from %qD", fn); - return error_mark_node; -} +return error_mark_node; + return result; } @@ -469,18 +498,12 @@ normalize_var (tree t) // Reduce the initializer of the variable into the constriants language. tree body = normalize_constraints (DECL_INITIAL (decl)); if (!body) - { - error ("could not inline requirements from %qD", decl); - return error_mark_node; - } +return error_mark_node; // Instantiate the reduced results. tree result = tsubst_constraint_expr (body, TREE_OPERAND (t, 1), false); if (result == error_mark_node) -{ - error ("could not instantiate requirements from %qD", decl); - return error_mark_node; -} +return err
[c++-concepts] variable concept fixes
Add more diagnostics for variable concepts. Also fix a regression where non-template concepts variables were causing ICEs because they aren't being allocated via build_lang_decl. 2014-08-15 Andrew Sutton Additional declaration restrictions on variable concepts. * gcc/cp/decl.c (is_concept_var): New. (cp_finish_decl): Check for uninitialized variable concepts. (grokvardecl): Don't set the concept flag for non-template variables. * g++.dg/concepts/decl-diagnose.C: Add tests. Andrew Sutton Index: gcc/cp/decl.c === --- gcc/cp/decl.c (revision 214239) +++ gcc/cp/decl.c (working copy) @@ -6259,6 +6259,16 @@ value_dependent_init_p (tree init) return false; } +// Returns true if a DECL is VAR_DECL with the concept specifier. Note +// that not all variables are decl-lang-specific. +static inline bool +is_concept_var (tree decl) +{ + return VAR_P (decl) + && 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, @@ -6435,6 +6445,8 @@ cp_finish_decl (tree decl, tree init, bo 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. */ @@ -8264,9 +8276,17 @@ grokvardecl (tree type, else DECL_INTERFACE_KNOWN (decl) = 1; - // Mark the variable as a concept. + // Check that the variable can be safely declared as a concept. if (conceptp) -DECL_DECLARED_CONCEPT_P (decl) = true; +{ + if (!processing_template_decl) +{ + error ("a non-template variable cannot be %"); + return NULL_TREE; +} + else +DECL_DECLARED_CONCEPT_P (decl) = true; +} // Handle explicit specializations and instantiations of variable templates. if (orig_declarator)
Re: [c++-concepts] variable concept fixes
> On 08/20/2014 08:56 PM, Andrew Sutton wrote: >> >> + return VAR_P (decl) >> + && DECL_LANG_SPECIFIC (decl) >> + && DECL_DECLARED_CONCEPT_P (decl); > > this is brittle from the formatting point of view. Please double check in > detail what I'm going to say, but I think that in such cases you simply want > to wrap the whole thing in round parentheses. Sorry, did you just mean to wrap the entire conjunction in parens? I'm trying to find the formatting guidelines to check, but not succeeding at the moment. Andrew
[c++-concepts] template scoping error
Fixes a regression in lookup rules involving declarations with nested-name-specifiers. In particular, we don't actually want to execute these rules if we absolutely don't have to. 2014-08-15 Andrew Sutton Fixing regression in scoping rules for templates. * gcc/cp/semantics.c (fixup_tmeplate_type): Lift check to finish_template_type. (finish_template_type): Only do this when concepts are enabled, and also when the class is actually a template. For non-dependent types there are no actions to be taken. Andrew Sutton Index: gcc/cp/semantics.c === --- gcc/cp/semantics.c (revision 214228) +++ gcc/cp/semantics.c (working copy) @@ -3004,10 +3004,6 @@ finish_template_decl (tree parms) static tree fixup_template_type (tree type) { - // Don't try to fix non-class types. - if (!CLASS_TYPE_P (type)) -return type; - // Find the template parameter list at the a depth appropriate to // the scope we're trying to enter. tree parms = current_template_parms; @@ -3055,8 +3051,12 @@ finish_template_type (tree name, tree ar NULL_TREE, NULL_TREE, entering_scope, tf_warning_or_error | tf_user); - // If entering a scope, correct the lookup to account for constraints. - if (entering_scope) + // If entering a scope of a template, correct the lookup to + // account for constraints. + if (flag_concepts + && entering_scope + && CLASS_TYPE_P (type) + && CLASSTYPE_IS_TEMPLATE (type)) type = fixup_template_type (type); if (type == error_mark_node)
Re: [c++-concepts] variable concept fixes
Ah... thanks for the clarification. Fixed (and committed). Andrew On Thu, Aug 21, 2014 at 4:26 AM, Paolo Carlini wrote: > Hi Andrew, > > > On 08/20/2014 11:08 PM, Andrew Sutton wrote: >>> >>> On 08/20/2014 08:56 PM, Andrew Sutton wrote: >>>> >>>> + return VAR_P (decl) >>>> + && DECL_LANG_SPECIFIC (decl) >>>> + && DECL_DECLARED_CONCEPT_P (decl); >>> >>> this is brittle from the formatting point of view. Please double check in >>> detail what I'm going to say, but I think that in such cases you simply >>> want >>> to wrap the whole thing in round parentheses. >> >> Sorry, did you just mean to wrap the entire conjunction in parens? I'm >> trying to find the formatting guidelines to check, but not succeeding >> at the moment. > > Yes, I meant the whole conjunction, sorry about my sloppy language. In terms > of GNU coding standards: > > http://www.gnu.org/prep/standards/standards.html#Formatting > > toward the end of the section, for example. > > Paolo. Index: gcc/cp/decl.c === --- gcc/cp/decl.c (revision 214241) +++ gcc/cp/decl.c (working copy) @@ -6264,9 +6264,9 @@ value_dependent_init_p (tree init) static inline bool is_concept_var (tree decl) { - return VAR_P (decl) - && DECL_LANG_SPECIFIC (decl) - && DECL_DECLARED_CONCEPT_P (decl); + return (VAR_P (decl) + && DECL_LANG_SPECIFIC (decl) + && DECL_DECLARED_CONCEPT_P (decl)); } /* Finish processing of a declaration;
[c++-concepts] constrained friends
Added tests for constrained friends. No code, we already to the right thing. 2014-08-15 Andrew Sutton Add tests for constrained friends. * gcc/testsuite/g++.dg/concepts/friend1.C: New. * gcc/testsuite/g++.dg/concepts/friend2.C: New. Andrew Index: gcc/testsuite/g++.dg/concepts/friend2.C === --- gcc/testsuite/g++.dg/concepts/friend2.C (revision 0) +++ gcc/testsuite/g++.dg/concepts/friend2.C (revision 0) @@ -0,0 +1,20 @@ +// { dg-options "-std=c++1z" } + +template + concept bool Eq() { return requires(T t) { t == t; }; } + +template struct Foo { }; + +template + struct S { // { dg-error "constraint failure" } +template friend class Bar; + +friend class Foo; + }; + +struct X { }; + +int main() { + S si; // OK + S sx; +} Index: gcc/testsuite/g++.dg/concepts/friend1.C === --- gcc/testsuite/g++.dg/concepts/friend1.C (revision 0) +++ gcc/testsuite/g++.dg/concepts/friend1.C (revision 0) @@ -0,0 +1,33 @@ +// { dg-options "-std=c++1z" } + +template + concept bool Eq() { return requires(T t) { t == t; }; } + +struct Nt { + template friend void f(T) { } +} nt; + +template struct S; + +template + void proc(S*); + +template + struct S { +friend bool operator==(S, S) requires Eq() { return true; } + +friend void proc<>(S*); // { dg-error "does not match any template declaration" } + }; + +struct X { } x; + +int main() { + f(0); // OK + f(x); // { dg-error "cannot call" } + + S si; + si == si; // OK + + S sx; + sx == sx; // { dg-error "no match" } +}
[c++-concepts] cleanup expressions
Sometimes, cleanup_point_exprs are being added to concept definitions. This patch allows that to happen, but removes the cleanup point during normalization. 2014-10-13 Andrew Sutton Fix bug related to cleanup expressions in concept definitions. * gcc/cp/constraint.cc (check_function_concept): See through cleanup handlers when checking the body of a function. (normalize_cast): Removed. Handled in a default case. (normalize_cleanup_point): New. Normalize the expression without the cleanup handler. Andrew Sutton
Re: [c++-concepts] cleanup expressions
And here's the patch: Andrew Sutton On Mon, Oct 13, 2014 at 3:33 PM, Andrew Sutton wrote: > Sometimes, cleanup_point_exprs are being added to concept definitions. > This patch allows that to happen, but removes the cleanup point during > normalization. > > 2014-10-13 Andrew Sutton > > Fix bug related to cleanup expressions in concept definitions. > * gcc/cp/constraint.cc (check_function_concept): See through > cleanup handlers when checking the body of a function. > (normalize_cast): Removed. Handled in a default case. > (normalize_cleanup_point): New. Normalize the expression without > the cleanup handler. > > Andrew Sutton Index: constraint.cc === --- constraint.cc (revision 215720) +++ constraint.cc (working copy) @@ -285,6 +285,14 @@ check_function_concept (tree fn) tree body = DECL_SAVED_TREE (fn); if (TREE_CODE (body) == BIND_EXPR) body = BIND_EXPR_BODY (body); + + // Sometimes a funciton call results the creation of clean up + // points. Allow these to be preserved in the body of the + // constraint, as we might actually need them for some constexpr + // evaluations. + if (TREE_CODE (body) == CLEANUP_POINT_EXPR) +body = TREE_OPERAND(body, 0); + if (TREE_CODE (body) != RETURN_EXPR) error_at (loc, "function concept definition %qD has multiple statements", fn); @@ -316,9 +324,9 @@ tree normalize_expr_req (tree); tree normalize_type_req (tree); tree normalize_nested_req (tree); tree normalize_var (tree); +tree normalize_cleanup_point (tree); tree normalize_template_id (tree); tree normalize_stmt_list (tree); -tree normalize_cast (tree); tree normalize_atom (tree); // Reduce the requirement T into a logical formula written in terms of @@ -383,12 +391,12 @@ normalize_expr (tree t) case TEMPLATE_ID_EXPR: return normalize_template_id (t); -case CAST_EXPR: - return normalize_cast (t); - case BIND_EXPR: return normalize_node (BIND_EXPR_BODY (t)); +case CLEANUP_POINT_EXPR: + return normalize_cleanup_point (t); + // Do not recurse. case TAG_DEFN: return NULL_TREE; @@ -655,12 +663,11 @@ normalize_requires (tree t) return t; } -// Normalize a cast expression. +// Normalize a cleanup point by normalizing the underlying +// expression. tree -normalize_cast (tree t) -{ - // return normalize_node (TREE_VALUE (TREE_OPERAND (t, 0))); - return normalize_atom (t); +normalize_cleanup_point (tree t) { + return normalize_node (TREE_OPERAND (t, 0)); } // Normalize an atomic expression by performing some basic checks.
[c++-concepts] introduction syntax regression
The original patch for concept introductions was not popping a deferred access check. This fixes that problem, although I'm not sure if we need to defer access checks at all. 2014-10-13 Andrew Sutton Fix regression related to concept introductions. * gcc/cp/constraint.cc (cp_parser_template_declaration_after_exp): Pop deferred access checks afer parsing the introduction. Andrew Sutton Index: parser.c === --- parser.c (revision 214991) +++ parser.c (working copy) @@ -24409,19 +24409,21 @@ cp_parser_template_declaration_after_exp = current_template_reqs; } } - else if(flag_concepts) + else if (flag_concepts) { need_lang_pop = false; checks = NULL; saved_template_reqs = release (current_template_reqs); - push_deferring_access_checks (dk_deferred); // Scope may be changed by a nested-name-specifier. tree saved_scope = parser->scope; tree saved_qualifying_scope = parser->qualifying_scope; tree saved_object_scope = parser->object_scope; + push_deferring_access_checks (dk_deferred); parameter_list = cp_parser_template_introduction (parser); + pop_deferring_access_checks (); + if (parameter_list == error_mark_node) { // Restore template requirements before returning.
[c++-concepts]
Fixing issues reported by users. 2014-10-20 Andrew Sutton Fixing user-reported issues and regressions * gcc/cp/parser.c (cp_parser_template_declaration_after_exp): Only pop access checks on failed parsing. * gcc/cp/pt.cpp (type_dependent_expr_p): Always treat a requires-expr as if dependently typed. Otherwise, we try to evaluate these expressions when they have dependent types. * gcc/cp/constriant.cc (normalize_stmt_list): Remove unused function. (normalize_call): Don't fold constraints during normalization. * gcc/testsuite/g++.dg/concepts/decl-diagnose.C: Update diagnostics. Andrew Sutton Index: pt.c === --- pt.c (revision 214991) +++ pt.c (working copy) @@ -21646,6 +21646,16 @@ type_dependent_expression_p (tree expres return dependent_type_p (type); } + // A requires expression has type bool, but is always treated as if + // it were a dependent expression. + // + // FIXME: This could be improved. Perhaps the type of the requires + // expression depends on the satisfaction of its constraints. That + // is, its type is bool only if its substitution into its normalized + // constraints succeeds. + if (TREE_CODE (expression) == REQUIRES_EXPR) +return true; + if (TREE_CODE (expression) == SCOPE_REF) { tree scope = TREE_OPERAND (expression, 0); Index: constraint.cc === --- constraint.cc (revision 216159) +++ constraint.cc (working copy) @@ -326,7 +326,6 @@ tree normalize_nested_req (tree); tree normalize_var (tree); tree normalize_cleanup_point (tree); tree normalize_template_id (tree); -tree normalize_stmt_list (tree); tree normalize_atom (tree); // Reduce the requirement T into a logical formula written in terms of @@ -559,13 +558,13 @@ normalize_call (tree t) tree fn = TREE_VALUE (check); tree args = TREE_PURPOSE (check); - // Reduce the body of the function into the constriants language. + // Normalize the body of the function into the constriants language. tree body = normalize_constraints (DECL_SAVED_TREE (fn)); if (!body) return error_mark_node; // Instantiate the reduced results using the deduced args. - tree result = tsubst_constraint_expr (body, args, false); + tree result = tsubst_constraint_expr (body, args, true); if (result == error_mark_node) return error_mark_node; Index: testsuite/g++.dg/concepts/decl-diagnose.C === --- testsuite/g++.dg/concepts/decl-diagnose.C (revision 214241) +++ testsuite/g++.dg/concepts/decl-diagnose.C (working copy) @@ -4,12 +4,12 @@ typedef concept int CINT; // { dg-error void f(concept int); // { dg-error "a parameter cannot be declared 'concept'" } -concept int f2(); // { dg-error "result must be bool" } +concept int f2(); // { dg-error "return type" } concept bool f3(); struct X { - concept int f4(); // { dg-error "result must be bool|declared with function parameters" } + concept int f4(); // { dg-error "return type|function parameters" } concept bool f5(); // { dg-error "declared with function parameters" } static concept bool f6(); // { dg-error "a concept cannot be a static member function" } static concept bool x; // { dg-error "declared 'concept'" } Index: cp/parser.c === --- cp/parser.c (revision 216159) +++ cp/parser.c (working copy) @@ -24422,12 +24422,10 @@ cp_parser_template_declaration_after_exp push_deferring_access_checks (dk_deferred); parameter_list = cp_parser_template_introduction (parser); - pop_deferring_access_checks (); - if (parameter_list == error_mark_node) { - // Restore template requirements before returning. current_template_reqs = saved_template_reqs; + pop_deferring_access_checks (); return; }
[c++-concepts] Terse notation
Sorry if you receive multiple versions of this. The original message bounced (formatting). Attached is a patch that greatly improves terse notation support for generic functions and the use of concept names in constrained-type-specifiers. There are actually 2 patches. The second includes unit tests. Mostly, this is just cleaning up a previous (hacky) commit. Most of the work is done in the parser, since terse notation is largely syntactic. Generic functions can be declared with auto and concept names in namespace and class scope. Definitions can be matched to declarations, and overloading is supported. Various restrictions are put in place to prevent things like this: template // C constrains a type argument! That holds when C constrains a template template argument also. The patch also includes the initial parsing and semantic hooks for handling constrained-type-specifiers in compound requirements: {expr} -> const auto&; // unnamed result type must form a valid type {expr} -> C; // unnamed result type satisfies the concept C Semantics will come later. Changelog: 2014-06-11 Andrew Sutton * gcc/cp/cp-tree.h (build_constrained_parameter): Renamed fro describe_tempalte_parm. * gcc/cp/parser.c (cp_check_constrained_type_parm): New. Prevent declaration of cv-qualifed or non-id types. (cp_constrained_type_template_parm): Renamed, check for invalid specifiers. (cp_constrained_template_template_parm): Renamed, check for invalid specifiers. (cp_constrained_non_type_tmeplate_parm): Renamed. (cp_finish_constrained-parameter): Support checking of decarlarations. (cp_check_concept_name): Renamed. Add initial support for auto and constrained-type-specifiers in compound requirements. (cp_parser_nonclass_name): Only check for concept names if -fconcepts is on. (cp_manage_requirements): New RAII guard for managinging the current_template_reqs variable during declaration parsing. (cp_paresr_trailing_requirements): Refactored common parsing requirements from cp_parser_init_declarator and cp_parser_member_declarator. Take terse constraints from implicit parameter declarations. (cp_parser_init_declarator): Cleanup, refactor requirement logic. (cp_parser_type_id_1): Allow auto in compound requirements. (cp_parser_member_declaration): Cleanup, refactor requirement logic. (cp_parser_compound_requirement): Note parsing state for the trailing-type-id so we can get auto and constrained-type-specifiers. (cp_parser_function_definition_after_decl): Remove broken constraint association. * gcc/cp/parser.h (cp_parser): New member. * gcc/cp/constraint.cc (finish_validtype_expr): Initial (non-)handling of auto in type requirements. (finish_concept_name): Moved to cp_check_concept_name. * gcc/testuite/g++.dg/concepts/constrained-parm.C: New test. * gcc/testuite/g++.dg/concepts/generic-fn.C: New test. Andrew Sutton Index: constrained-parm.C === --- constrained-parm.C (revision 0) +++ constrained-parm.C (revision 0) @@ -0,0 +1,13 @@ +// { dg-options "-std=c++1y" } + +template + concept bool C() { return __is_class(T); } + +template struct S1 { };// { dg-error "cv-qualified" } +template struct S2 { }; // { dg-error "cv-qualified" } +template struct S3 { }; // { dg-error "invalid" } +template struct S3a { }; // { dg-error "invalid" } +template struct S3b { }; // { dg-error "invalid" } +template struct S4 { }; // { dg-error "invalid" } +template struct S4 { }; // { dg-error "invalid|expected" } +template struct S5 { }; // { dg-error "invalid" } Index: generic-fn.C === --- generic-fn.C (revision 0) +++ generic-fn.C (revision 0) @@ -0,0 +1,108 @@ +// { dg-options "-std=c++1y" } + +#include + +template + concept bool C() { return __is_class(T); } + +struct S { } 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 + 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 + void g1(T t, U u) { called = 1; } + +template + void g2(T t, U u); +
terse notation diagnostics
Adds additional checks and tests for ill-formed programs. 2014-06-12 Andrew Sutton * gcc/cp/parser.c (cp_check_type_concept): New. (cp_check_concept_name): Remove redundant condition from check. Diagnose misuse of non-type concepts in constrained type specifiers. * gcc/testuite/g++.dg/concepts/generic-fn.C: Add tests for non-simple constrained-type-specifiers and nested-name-specifiers in concept names. * gcc/testuite/g++.dg/concepts/generic-fn-err.C: New tests for diagnosing ill-formed programs. Committed in r211585. Andrew Sutton Index: parser.c === --- parser.c (revision 211476) +++ parser.c (working copy) @@ -15132,11 +15132,22 @@ cp_parser_type_name (cp_parser* parser) return type_decl; } - +/// Returns true if proto is a type parameter, but not a template template +/// parameter. +static bool +cp_check_type_concept (tree proto, tree fn) +{ + if (TREE_CODE (proto) != TYPE_DECL) +{ + error ("invalid use of non-type concept %qD", fn); + return false; +} + return true; +} // If DECL refers to a concept, return a TYPE_DECL representing the result // of using the constrained type specifier in the current context. - +// // DECL refers to a concept if // - it is an overload set containing a function concept taking a single // type argument, or @@ -15173,9 +15184,13 @@ cp_check_concept_name (cp_parser* parser // In template paramteer scope, this results in a constrained parameter. // Return a descriptor of that parm. - if (template_parm_scope_p () && processing_template_parmlist) + if (processing_template_parmlist) return build_constrained_parameter (proto, fn); + // In any other context, a concept must be a type concept. + if (!cp_check_type_concept (proto, fn)) +return error_mark_node; + // In a parameter-declaration-clause, constrained-type specifiers // result in invented template parameters. if (parser->auto_is_implicit_function_template_parm_p) Index: generic-fn.C === --- generic-fn.C (revision 211476) +++ generic-fn.C (working copy) @@ -1,11 +1,16 @@ +// { dg-do run } // { dg-options "-std=c++1y" } #include +#include template concept bool C() { return __is_class(T); } -struct S { } s; +template + concept bool Type() { return true; } + +struct S { }; int called; @@ -50,7 +55,43 @@ template }; +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::value, "not an lvlaue reference"); +} + +void +fwd_const_lvalue_ref(Type&& x) { + using T = decltype(x); + static_assert(std::is_lvalue_reference::value, "not an lvalue reference"); + using U = typename std::remove_reference::type; + static_assert(std::is_const::value, "not const-qualified"); +} + +void fwd_rvalue_ref(Type&& x) { + using T = decltype(x); + static_assert(std::is_rvalue_reference::value, "not an rvalue reference"); +} + +// Make sure we can use nested names speicifers for concept names. +namespace N { + template +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); @@ -60,7 +101,6 @@ int main() { S1 s1; s1.f1(0); assert(called == 1); s1.f2(s); assert(called == 2); - // s1.f2(0); // Error s1.f3(0); assert(called == 1); s1.f3(s); assert(called == 2); @@ -68,26 +108,35 @@ int main() { S2 s2; s2.f1(0); assert(called == 1); s2.f2(s); assert(called == 2); - // s2.f2(0); // Error 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.h2(0); // Error s2.h3(0); assert(called == 1); s2.h3(s); assert(called == 2); s2.g1(s, s); assert(called == 1); - // s2.g(s, 0); // Error - // s2.g(0, s); // Error - s2.g2(s, s); assert(called == 2); - // s2.g(s, 0); // Error + + 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; } Index: generic-fn-err.C === --- generic-fn-err.C (revision 0) +++ generic-fn-err.C (revision 0) @@ -0,0 +1,51 @@ +// { dg-options "-std=c++1y" } + +#include + +template + concept bool C() { return __is_cla
partial-concept-ids
Add support for partial concept ids. Mostly this just refactors the basic support for concept names to also allow a template and extra arguments. Also added the missing .exp file for the test suite. 2014-06-12 Andrew Sutton * gcc/cp/constraint.cc (deduce_constrained_parameter): Refactor common deduction framework into separate function. (build_call_check): New. (build_concept_check): Take additional arguments to support the creation of constrained-type-specifiers from partial-concept-ids. (build_constrained_parameter): Take arguments from a partial-concept-id. * gcc/cp/cp-tree.h (build_concept_check, biuld_constrained_parameter): Take a template argument list, defaulting to NULL_TREE. * gcc/cp/parser.c (cp_parser_template_id): Check to see if a template-id is a concept check. (cp_check_type_concept): Reorder arguments (cp_parser_allows_constrained_type_specifier): New. Check contexts where a constrained-type-specifier is allowed. (cp_maybe_constrained_type_specifier): New. Refactored common rules for concept name checks. (cp_maybe_partial_concept_id): New. Check for constrained-type-specifiers. * gcc/testuite/g++.dg/concepts/partial.C: New tests. * gcc/testuite/g++.dg/concepts/partial-err.C: New tests. * gcc/testuite/g++.dg/concepts/concepts.exp: Add missing test driver. Andrew Sutton Index: parser.c === --- parser.c (revision 211585) +++ parser.c (working copy) @@ -2523,7 +2523,10 @@ static tree cp_parser_make_typename_type static cp_declarator * cp_parser_make_indirect_declarator (enum tree_code, tree, cp_cv_quals, cp_declarator *, tree); +/* Concept-related syntactic transformations */ +static tree cp_maybe_concept_name (cp_parser *, tree); +static tree cp_maybe_partial_concept_id (cp_parser *, tree, tree); // -- // // Unevaluated Operand Guard @@ -13775,6 +13778,11 @@ cp_parser_template_id (cp_parser *parser || TREE_CODE (templ) == OVERLOAD || BASELINK_P (templ))); + // If the template + args designate a concept, then return + // something else. + if (tree id = cp_maybe_partial_concept_id (parser, templ, arguments)) +return id; + template_id = lookup_template_function (templ, arguments); } @@ -14995,7 +15003,8 @@ cp_parser_simple_type_specifier (cp_pars } /* Otherwise, look for a type-name. */ else - type = cp_parser_type_name (parser); +type = cp_parser_type_name (parser); + /* Keep track of all name-lookups performed in class scopes. */ if (type && !global_p @@ -15071,6 +15080,7 @@ cp_parser_simple_type_specifier (cp_pars type-name: concept-name + partial-concept-id concept-name: identifier @@ -15092,6 +15102,7 @@ cp_parser_type_name (cp_parser* parser) /*check_dependency_p=*/true, /*class_head_p=*/false, /*is_declaration=*/false); + /* If it's not a class-name, keep looking. */ if (!cp_parser_parse_definitely (parser)) { @@ -15107,6 +15118,7 @@ cp_parser_type_name (cp_parser* parser) /*check_dependency_p=*/true, none_type, /*is_declaration=*/false); + /* Note that this must be an instantiation of an alias template because [temp.names]/6 says: @@ -15135,7 +15147,7 @@ cp_parser_type_name (cp_parser* parser) /// Returns true if proto is a type parameter, but not a template template /// parameter. static bool -cp_check_type_concept (tree proto, tree fn) +cp_check_type_concept (tree fn, tree proto) { if (TREE_CODE (proto) != TYPE_DECL) { @@ -15145,57 +15157,58 @@ cp_check_type_concept (tree proto, tree return true; } -// If DECL refers to a concept, return a TYPE_DECL representing the result -// of using the constrained type specifier in the current context. -// -// DECL refers to a concept if -// - it is an overload set containing a function concept taking a single -// type argument, or -// - it is a variable concept taking a single type argument -// -// -// TODO: DECL could be a variable concept. +/// Returns true if the parser is in a context that allows the +/// use of a constrained type specifier. +static inline bool +cp_parser_allows_constrained_type_specifier (cp_parser *parser) +{ + return flag_concepts +&& (processing_template_parmlist +|| parser->auto_is_implicit_function_template_parm_p +|| parser->in_result_type_constraint_p); +} + +// Check if DECL and ARGS can form a constrained-type-specifier. If ARGS +// is non-null, we try to form a concept check of the form DECL +// where ? is a placeholder for any kind of template argument. If ARGS +// is NULL, then we try to form a concept che
Re: [c++-concepts] Fix assertion failure with cp_maybe_constrained_type_specifier
Braden, Did you have a specific test case that causes this breakage? I have a feeling that if we're missing base-link nodes in one place, we'll miss them in others too. Andrew On Tue, Jun 17, 2014 at 4:54 AM, Braden Obrzut wrote: > cp_maybe_constrained_type_specifier asserted that the decl passed in would > be of type OVERLOAD, however a clean build of the compiler was broken since > it could also be a BASELINK. I'm not entirely sure when this is the case, > except that it seems to happen with class member templates as it also caused > a test case in my next patch to fail. The solution is to check for a > BASELINK and extract the functions from it. > > The possibility of decl being a BASELINK is asserted near the call in > cp_parser_template_id (cp_maybe_partial_concept_id just calls the function > in question at this time). > > 2014-06-17 Braden Obrzut > * gcc/cp/parser.c (cp_maybe_constrained_type_specifier): Fix assertion > failure if baselink was passed in as decl. >
Re: [c++-concepts] Fix assertion failure with cp_maybe_constrained_type_specifier
Committed as r211935. I updated the patch to add a more appropriate comment and changelog entry. Andrew On Tue, Jun 24, 2014 at 8:07 AM, Ed Smith-Rowland <3dw...@verizon.net> wrote: > I saw this during bootstrap. I've verified that the patch works (I was > working on similar). > > Ed > Index: parser.c === --- parser.c (revision 211591) +++ parser.c (working copy) @@ -15175,9 +15175,15 @@ cp_parser_allows_constrained_type_specif static tree cp_maybe_constrained_type_specifier (cp_parser *parser, tree decl, tree args) { - gcc_assert (TREE_CODE (decl) == OVERLOAD); gcc_assert (args ? TREE_CODE (args) == TREE_VEC : true); + // If we get a reference to a member function, allow the referenced + // functions to participate in this resolution: the baselink may refer + // to a static member concept. + if (BASELINK_P (decl)) +decl = BASELINK_FUNCTIONS (decl); + gcc_assert (TREE_CODE (decl) == OVERLOAD); + // Don't do any heavy lifting if we know we're not in a context // where it could succeed. if (!cp_parser_allows_constrained_type_specifier (parser))
[c++-concepts] small pretty printing fix
This helps improve debug output. When pretty printing template args including a placeholder, show instead of a dump_expr error. 2014-06-24 Andrew Sutton * gcc/cp/error.C (dump_expr): Pretty print placeholder to improve debug output. Committed as r211942. Andrew Index: gcc/cp/error.c === --- gcc/cp/error.c (revision 211415) +++ gcc/cp/error.c (working copy) @@ -2656,6 +2656,10 @@ dump_expr (cxx_pretty_printer *pp, tree case CONSTEXPR_EXPR: pp_cxx_constexpr_expr (cxx_pp, t); +case PLACEHOLDER_EXPR: + pp_cxx_ws_string (cxx_pp, ""); + break; + /* This list is incomplete, but should suffice for now. It is very important that `sorry' does not call `report_error_function'. That could cause an infinite loop. */
[c++-concepts] member concepts
Actually allow member concepts in using shorthand notation. 2014-06-24 Andrew Sutton * gcc/cp/parser.c (cp_maybe_constrained_type_specifier): Defer handling the BASELINK check until concept-resolution in order to allow member conceps. (cp_parser_nonclass_name): Also Check for concept-names when the lookup finds a BASELINk. * gcc/cp/constraint.cc: (resolve_constraint_check) If the call target is a base-link, resolve against its overload set. (build_concept_check): Update comments and variable names to reflect actual processing. * gcc/testuite/g++.dg/concepts/mem-concept.C: New test. * gcc/testuite/g++.dg/concepts/mem-concept-err.C: New test. Committed as r211946. Andrew Sutton Index: mem-concept.C === --- mem-concept.C (revision 0) +++ mem-concept.C (revision 0) @@ -0,0 +1,28 @@ +// { dg-options "-std=c++1y" } + +struct Base { + template +static concept bool D() { return __is_same_as(T, int); } + + template +static concept bool E() { return __is_same_as(T, U); } +}; + +void f1(Base::D) { } +void f2(Base::E x) { } + +template + struct S : Base { +void f1(Base::D) { } +void f2(Base::E x) { } + }; + +int main() { + f1(0); + + f2(0.0); + + S s; + s.f1(0); + s.f2(0); +} Index: mem-concept-err.C === --- mem-concept-err.C (revision 0) +++ mem-concept-err.C (revision 0) @@ -0,0 +1,40 @@ +// { dg-options "-std=c++1y" } + + +// The following error is emitted without context. I'm not +// certain why that would be the case. It comes as a result +// of failing the declaration of S::f0(). +// +//cc1plus: error: expected ';' at end of member declaration + + +struct Base { + template +bool C() const { return false; } // Not a concept! + + template +static concept bool D() { return __is_same_as(T, int); } + + template +static concept bool E() { return __is_same_as(T, U); } +}; + +void f1(Base::D) { } +void f2(Base::E x) { } + +template + struct S : Base { +void f0(Base::C x) { } // { dg-error "expected|type" } +void f1(Base::D) { } +void f2(Base::E x) { } + }; + +int main() { + f1('a'); // { dg-error "matching" } + f2(0); // { dg-error "matching" } + + S s; + s.f1('a'); // { dg-error "matching" } + s.f2('a'); // { dg-error "matching" } +} + Index: pt.c === --- pt.c (revision 211415) +++ pt.c (working copy) @@ -29,6 +29,7 @@ along with GCC; see the file COPYING3. #include "coretypes.h" #include "tm.h" #include "tree.h" +#include "print-tree.h" #include "stringpool.h" #include "varasm.h" #include "attribs.h" Index: parser.c === --- parser.c (revision 211935) +++ parser.c (working copy) @@ -15168,6 +15168,7 @@ cp_parser_allows_constrained_type_specif || parser->in_result_type_constraint_p); } + // Check if DECL and ARGS can form a constrained-type-specifier. If ARGS // is non-null, we try to form a concept check of the form DECL // where ? is a placeholder for any kind of template argument. If ARGS @@ -15177,13 +15178,6 @@ cp_maybe_constrained_type_specifier (cp_ { gcc_assert (args ? TREE_CODE (args) == TREE_VEC : true); - // If we get a reference to a member function, allow the referenced - // functions to participate in this resolution: the baselink may refer - // to a static member concept. - if (BASELINK_P (decl)) -decl = BASELINK_FUNCTIONS (decl); - gcc_assert (TREE_CODE (decl) == OVERLOAD); - // Don't do any heavy lifting if we know we're not in a context // where it could succeed. if (!cp_parser_allows_constrained_type_specifier (parser)) @@ -15191,7 +15185,8 @@ cp_maybe_constrained_type_specifier (cp_ // Try to build a call expression that evaluates the concept. This // can fail if the overload set refers only to non-templates. - tree call = build_concept_check (decl, build_nt(PLACEHOLDER_EXPR), args); + tree placeholder = build_nt(PLACEHOLDER_EXPR); + tree call = build_concept_check (decl, placeholder, args); if (call == error_mark_node) return NULL_TREE; @@ -15291,7 +15286,8 @@ cp_parser_nonclass_name (cp_parser* pars // // TODO: The name could also refer to a variable template or an // introduction (if followed by '{'). - if (flag_concepts && TREE_CODE (type_decl) == OVERLOAD) + if (flag_concepts && +(TREE_CODE (type_decl) == OVERLOAD || BASELINK_P (type_decl))) { // Determine whether the overload refers to a concept. if (tree decl = cp_maybe_concept_name (parser, ty
Re: [c++-concepts] Fix assertion failure with cp_maybe_constrained_type_specifier
Weird. Any chance you're doing a bootstrap build? There was an earlier bootstrapping issue with this branch. We had turned on -std=c++1y by default, and it was causing some conversion errors with lvalue references to bitfields in libasan. This doesn't *look* like a regression caused by concepts -- I don't think I'm touching the initializer code at all. Andrew Sutton On Tue, Jun 24, 2014 at 11:42 AM, Ed Smith-Rowland <3dw...@verizon.net> wrote: > I'm not sure the warning is correct in any case... > > In i386.h > > struct stringop_algs > { > const enum stringop_alg unknown_size; > const struct stringop_strategy { > const int max; > const enum stringop_alg alg; > int noalign; > } size [MAX_STRINGOP_ALGS]; > }; > > in i386.c > --- > static stringop_algs ix86_size_memcpy[2] = { > {rep_prefix_1_byte, {{-1, rep_prefix_1_byte, false}}}, > {rep_prefix_1_byte, {{-1, rep_prefix_1_byte, false; > static stringop_algs ix86_size_memset[2] = { > {rep_prefix_1_byte, {{-1, rep_prefix_1_byte, false}}}, > {rep_prefix_1_byte, {{-1, rep_prefix_1_byte, false; >
Re: Re: [c++-concepts] Fix assertion failure with cp_maybe_constrained_type_specifier
> I did a full 3-stage bootstrap which is the default these days. > I'll try --disable-bootstrap and see what happens. I just did a full bootstrap build and got the same errors. The errors are correct for C++11, which was enabled by default in this branch. IIRC, aggregate initialization requires the initializer-clause to match the structure exactly (or at least not omit any const initializers?) I think this was something Gaby wanted when we created the branch, but I'm not sure it's worth keeping because of the bootstrapping errors. I could reset the default dialect to 98 and turn on concepts iff 1y is enabled, or I could turn on 1y if -fconcepts is enabled. Thoughts? Andrew
[c++-concepts] constraint folding
Updating constraint parsing to match changes to spec. Constraints must always left unfolded, even when non-dependent, until they are evaluated. 2014-06-25 Andrew Sutton * gcc/cp/parser.c (cp_parser_requires_clause): Don't fold expressions when parsing a requires-clause. * gcc/cp/constraint.cc (reduce_requirements): Don't fold expressions during constraint normalization. Andrew Sutton
Re: [c++-concepts] Change constraint equivalence
> Please drop gcc/ and gcc/testsuite/ prefixes (the former goes to > cp/ChangeLog, the latter to testsuite/ChangeLog). This is the format (and file) that Gaby requested when we started the project. We can certainly distribute the entries, but I don't know if its worthwhile right now. Andrew
[c++-concepts] constraint association
After merging from trunk this morning, I discovered that DECL_SIZE_UNIT is now being used to store lists of specializations. I had been using that to store template constraints. Oops. This patch moves constraints outside the usual tree structures into an association maintained in a hash table. It also lays the framework for allowing constraints to be associated with any _*DECL node (templates, functions, variables, types, etc). Changelog below; committed as 212103. 2014-06-28 Andrew Sutton * gcc/cp/cp-tree.h (DECL_CONSTRAINTS): Remove this macro; use get_constraints instead. (set_constraints): new. * gcc/cp/cxx-pretty-print.c (pp_cxx_template_declaration): Use get_constraints. * gcc/cp/pt.c (get_specialization_constraints): Use get_constraints. (build_template_decl): Use get_constraints. (process_partial_specialization): Use get_constraints. (add_inherited_template_parms): Use get_constraints. (redeclare_class_template): Use get_constraints. (is_compatible_template_arg): Use get_constraints. (tsubst_friend_class): Use get_constraints. (tsubst_decl): Uset get_constraints. * gcc/cp/semantics.c (finish_template_template_parm): Use get_constraints. (fixup_template_type): Use get_constraints. * gcc/cp/constraint.cc (constraints): New global association of declarations to constraints. (get_constraints): Return the associated constraints from the hash table. (set_constraints): New. Associate constraints with a declaration. (check_template_constraints): Use get_constraints. (equivalently_constrained): Use get_constraints. (more_constrained): Use get_constraints. (diagnose_constraints): Use get_constraints. * gcc/testsuite/g++.dg/concepts/partial-spec.C: New. Andrew Index: gcc/cp/cxx-pretty-print.c === --- gcc/cp/cxx-pretty-print.c (revision 212100) +++ gcc/cp/cxx-pretty-print.c (working copy) @@ -2220,7 +2220,7 @@ pp_cxx_template_declaration (cxx_pretty_ pp_newline_and_indent (pp, 3); } - if (tree c = DECL_CONSTRAINTS (t)) + if (tree c = get_constraints (t)) { pp_cxx_ws_string (pp, "requires"); pp->expression (CI_REQUIREMENTS (c)); Index: gcc/cp/pt.c === --- gcc/cp/pt.c (revision 212101) +++ gcc/cp/pt.c (working copy) @@ -846,7 +846,7 @@ get_specialization_constraints (tree typ // that type. If it is an explicit specialization, return null since // non-templates cannot be constrained. if (tree d = get_specializing_template_decl (type)) -return DECL_CONSTRAINTS (d); +return get_constraints (d); else return NULL_TREE; } @@ -4147,10 +4147,10 @@ build_template_decl (tree decl, tree par { tree tmpl = build_lang_decl (TEMPLATE_DECL, DECL_NAME (decl), NULL_TREE); DECL_TEMPLATE_PARMS (tmpl) = parms; - DECL_CONSTRAINTS (tmpl) = constr; DECL_CONTEXT (tmpl) = DECL_CONTEXT (decl); DECL_SOURCE_LOCATION (tmpl) = DECL_SOURCE_LOCATION (decl); DECL_MEMBER_TEMPLATE_P (tmpl) = member_template_p; + set_constraints (tmpl, constr); return tmpl; } @@ -4319,7 +4319,7 @@ process_partial_specialization (tree dec arguments but different constraints. */ tree main_type = TREE_TYPE (maintmpl); tree main_args = INNERMOST_TEMPLATE_ARGS (CLASSTYPE_TI_ARGS (main_type)); - tree main_constr = DECL_CONSTRAINTS (maintmpl); + tree main_constr = get_constraints (maintmpl); if (comp_template_args (inner_args, main_args) && equivalent_constraints (current_template_reqs, main_constr)) error ("partial specialization %qT does not specialize any " @@ -5229,13 +5229,13 @@ add_inherited_template_parms (tree fn, t // If the inherited constructor was constrained, then also // propagate the constraints to the new declaration by // rewriting them in terms of the local template parameters. - tree cons = DECL_CONSTRAINTS (inherited); + tree cons = get_constraints (inherited); if (cons) { ++processing_template_decl; tree reqs = instantiate_requirements (CI_REQUIREMENTS (cons), args); --processing_template_decl; - DECL_CONSTRAINTS (tmpl) = make_constraints (reqs); + set_constraints (tmpl, make_constraints (reqs)); } DECL_TEMPLATE_INFO (fn) = build_template_info (tmpl, args); @@ -5354,7 +5354,7 @@ redeclare_class_template (tree type, tre } // Cannot redeclare a class template with a different set of constraints. - if (!equivalent_constraints (DECL_CONSTRAINTS (tmpl), cons)) + if (!equivalent_constraints (get_constraints (tmpl), cons)) { error_at (input_location, "redeclaration %q#D with different " "constraints", tmpl); @@ -6586,8 +6586,8 @@ is_compati
[c++-concepts] Compiler options/bootstrap
This patch restores C++98 as the default language in this branch and disables -fconcepts by default. Using -std=c++1z will enable -fconcepts. I wanted to give an error if -fconcepts is used with dialect <= cxx11, but I didn't find the right place to put the check. This also adds a new format specifier ("Z") to the cxxdiag flags. That warning was turning into an error in the bootstrap build. FYI: The bootstrap builds cleanly for me now. Committed in r212105. 2014-06-28 Andrew Sutton * gcc/c-family/c.opt (flag_concepts): Don't enable by default. * gcc/c-family/c-opts.c (set_std_cxx1z): Enable concepts if -std=cxx1z is selected. * gcc/c-family/c-format.c (gcc_cxxdia): Add "Z" as format specifier. * gcc/cp/c-common.c (cxx_dialect): Make -std=c++98 the default language again. * gcc/cp/lex.c (cxx_init): Don't set flag_concepts explicitly. * gcc/testsuite/g++.dg/concepts/*.C: Updat build flags. Andrew
Re: [c++-concepts] code review
> It looks like things are coming together pretty well. What's your feeling > about readiness to merge into the trunk? Is the branch down to no > regressions? They are coming together pretty well. We have one major unit test failure involving template introductions (Braden is working on it), one involving constraint equivalence that I plan to tackle next week. Other than those issues, which I hope to clear up next week, I think it's ready. > See you on Monday! Unfortunately, I won't be attending. Andrew > >> @@ -4146,21 +4146,21 @@ build_new_function_call (tree fn, vec >> **args, bool koenig_p, >>if (TREE_CODE (fn) == TEMPLATE_ID_EXPR) >> { >>/* 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) >> + && !uses_template_parms (targs)) { >> +return evaluate_function_concept (decl, targs); > > > If processing_template_decl is false, uses_template_parms should always be > false as well. > >> +function_concept_check_p (tree t) > > >> + tree fn = CALL_EXPR_FN (t); >> + if (TREE_CODE (fn) == TEMPLATE_ID_EXPR >> + && TREE_CODE (TREE_OPERAND (fn, 0)) == OVERLOAD) >> +{ >> + tree f1 = OVL_FUNCTION (TREE_OPERAND (fn, 0)); > > > I think you want get_first_fn here. > >>if (TEMPLATE_PARM_CONSTRAINTS (current_template_parms)) >> -TYPE_CANONICAL (type) = type; >> +SET_TYPE_STRUCTURAL_EQUALITY (type); > > > This seems like papering over an underlying issue. What was the testcase > that motivated this change? > >> @@ -11854,7 +11854,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t >> complain) >> - if (!spec) >> + if (!spec && DECL_LANG_SPECIFIC (t)) >> - if (!local_p) >> + if (!local_p && DECL_LANG_SPECIFIC (r)) > > > What motivated these changes? From the testcase, it seems that you're > getting here with the decl for "using TD = int", which shouldn't happen. > >> @@ -1159,7 +1159,6 @@ check_noexcept_r (tree *tp, int * /*walk_subtrees*/, >> void * /*data*/) >> - tree type = TREE_TYPE (TREE_TYPE (fn)); >> - if (!TYPE_NOTHROW_P (type)) >> + if (!TYPE_NOTHROW_P (TREE_TYPE (fn))) > > > The old code was incorrectly assuming that CALL_EXPR_FN is always a function > pointer, but your new code seems to be incorrectly assuming that it's always > a function or an expression taking the address of a function; I think this > will break on a call to a function pointer variable. > >> @@ -3481,13 +3481,27 @@ cxx_eval_constant_expression (const constexpr_ctx >> *ctx, tree t, >> case REQUIRES_EXPR: >> + if (!processing_template_decl) >> +return evaluate_constraint_expression (t, NULL_TREE); >> + else >> +*non_constant_p = true; >> +return t; > > > We shouldn't get here with a dependent REQUIRES_EXPR (or any dependent > expression), so we shouldn't ever hit the else clause. > >> @@ -18063,18 +18063,41 @@ cp_parser_declarator (cp_parser* parser, >> + /* Function declarations may be followed by a trailing >> + requires-clause. Declarators for function declartions >> + are function declarators wrapping an id-declarator. >> + If the inner declarator is anything else, it does not >> + declare a function. These may also be reference or >> + pointer declarators enclosing such a function declarator. >> + In the declaration : >> + >> +int *f(args) >> + >> + the declarator is *f(args). >> + >> + Abstract declarators cannot have a requires-clauses >> + because they do not declare functions. Here: >> >> void f() -> int& requires false >> >> + The trailing return type contains an abstract declarator, >> + and the requires-clause applies to the function >> + declaration and not the abstract declarator. */ >> + if (flag_concepts && dcl_kind != CP_PARSER_DECLARATOR_ABSTRACT) >> { >> + /* We could have things like *f(args) or &f(args). >> + Look inside references and pointers. */ >> + cp_declarator* p = declarator; >> + if (p->kind == cdk_reference || p->kind == cdk_pointer) >> +p = p->declarator; >> + >> + /* Pointers or references with no name, or functions >> + with no name cannot have constraints. */ >> + if (!p || !p->declarator) >> +return declarator; >> + >> + /* Look for f(args) but not (*f)(args). */ >> +
Re: [c++-concepts] code review
Today is the first day I've had to look at these comments. >>if (TEMPLATE_PARM_CONSTRAINTS (current_template_parms)) >> -TYPE_CANONICAL (type) = type; >> +SET_TYPE_STRUCTURAL_EQUALITY (type); > > > This seems like papering over an underlying issue. What was the testcase > that motivated this change? It almost certainly is, but I haven't been able to find or write a minimal test case that reproduces the reason for failure. Basically, we end up with multiple specializations having the same type but different constraints (since constraints are attached to the declaration and not the type itself). I think that I'm running into the same problems with auto a placeholder in recent commits. >> @@ -11854,7 +11854,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t >> complain) >> - if (!spec) >> + if (!spec && DECL_LANG_SPECIFIC (t)) >> - if (!local_p) >> + if (!local_p && DECL_LANG_SPECIFIC (r)) > > > What motivated these changes? From the testcase, it seems that you're > getting here with the decl for "using TD = int", which shouldn't happen. That's the pretty much it... I suppose we could guard against substituting into these kinds of declarations from within tsubst_type_requirement and satisfy_type_constraint. To me it seems like tsubst should work, but just return the same thing. >> @@ -1159,7 +1159,6 @@ check_noexcept_r (tree *tp, int * /*walk_subtrees*/, >> void * /*data*/) >> - tree type = TREE_TYPE (TREE_TYPE (fn)); >> - if (!TYPE_NOTHROW_P (type)) >> + if (!TYPE_NOTHROW_P (TREE_TYPE (fn))) > > > The old code was incorrectly assuming that CALL_EXPR_FN is always a function > pointer, but your new code seems to be incorrectly assuming that it's always > a function or an expression taking the address of a function; I think this > will break on a call to a function pointer variable. I will experiment. >> @@ -3481,13 +3481,27 @@ cxx_eval_constant_expression (const constexpr_ctx >> *ctx, tree t, >> case REQUIRES_EXPR: >> + if (!processing_template_decl) >> +return evaluate_constraint_expression (t, NULL_TREE); >> + else >> +*non_constant_p = true; >> +return t; > > > We shouldn't get here with a dependent REQUIRES_EXPR (or any dependent > expression), so we shouldn't ever hit the else clause. IIRC we get here because of build_x_binary_op. It tries to build non-dependent operands when the operands are not type-dependent. requires-expressions have type bool, so they get run through the constexpr evaluator even when processing_template_decl is true. I've made requires-expressions instantiation dependent, but that doesn't help in this case. >> +static inline bool >> +pending_expansion_p (tree t) >> +{ >> + return (TREE_CODE (t) == PARM_DECL && CONSTRAINT_VAR_P (t) >> + && PACK_EXPANSION_P (TREE_TYPE (t))); >> +} > > > What's the difference between this and function_parameter_pack_p? Not a lot, except that replacing pending_expansion_p in one of the two places that it's used causes ICEs :) This function can almost certainly be removed. >> +check_implicit_conversion_constraint (tree t, tree args, >> + tsubst_flags_t complain, tree >> in_decl) >> +{ >> + tree expr = ICONV_CONSTR_EXPR (t); >> + >> + /* Don't tsubst as if we're processing a template. If we try >> + to we can end up generating template-like expressions >> + (e.g., modop-exprs) that aren't properly typed. */ >> + int saved_template_decl = processing_template_decl; >> + processing_template_decl = 0; > > > Why are we checking constraints when processing_template_decl is true? IIRC I allow constraints to be evaluated in any context because it lets us catch these kinds of errors: template void f() { vector v; // error: constraints not satisfied } >> + ++processing_template_decl; >> + tree constr = transform_expression (lift_function_definition (fn, >> args)); >> + --processing_template_decl; > > > Why do you need to set processing_template_decl here and in other calls to > transform_expression? I don't notice anything that would be helped, > especially now that you're using separate tree codes for constraints, though > there is this in check_logical_expr: > >> + /* Resolve the logical operator. Note that template processing is >> + disabled so we get the actual call or target expression back. >> + not_processing_template_sentinel sentinel. > > > I guess that isn't needed anymore? I've had problems in the past where substitution tries a little too eagerly to fold expressions into constants --- especially type traits. Those need to be preserved in the text for ordering. Although I think this really only matters when you're instantiating a class template whose members are constraints. Andrew
[c++-concepts] merge from trunk
I just merged the concepts branch with trunk, after fighting with the testing framework for the past hour. There was a change to gcc/testsuite/lib/prune.exp yesterday that doesn't appear to be compatible with *something* in this branch. It broke the entire test suite, giving the errors below for every .exp file. Using /home/faculty/asutton/local/share/dejagnu/baseboards/unix.exp as board description file for target. Using /home/faculty/asutton/local/share/dejagnu/config/unix.exp as generic interface file for target. Using /home/faculty/asutton/Code/gcc/c++-concepts/gcc/testsuite/config/default.exp as tool-and-target-specific interface file. Running /home/faculty/asutton/Code/gcc/c++-concepts/gcc/testsuite/gcc.c-torture/compile/compile.exp ... ERROR: tcl error sourcing /home/faculty/asutton/Code/gcc/c++-concepts/gcc/testsuite/gcc.c-torture/compile/compile.exp. ERROR: couldn't compile regular expression pattern: quantifier operand invalid while executing "regsub -all "$srcdir\/" $text "" text" (procedure "prune_gcc_output" line 50) invoked from within "prune_gcc_output $text" (procedure "gcc-dg-prune" line 8) invoked from within "${tool}-dg-prune $target_triplet $comp_output" (procedure "saved-dg-test" line 183) invoked from within "saved-dg-test /home/faculty/asutton/Code/gcc/c++-concepts/gcc/testsuite/gcc.c-torture/compile/2105-1.c { -O0 } -w" ("eval" body line 1) invoked from within "eval saved-dg-test $args " (procedure "dg-test" line 11) invoked from within "dg-test $test "$flags $flags_t" ${default-extra-flags}" (procedure "gcc-dg-runtest" line 33) invoked from within "gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cS\]]] "" "-w"" (file "/home/faculty/asutton/Code/gcc/c++-concepts/gcc/testsuite/gcc.c-torture/compile/compile.exp" line 30) invoked from within "source /home/faculty/asutton/Code/gcc/c++-concepts/gcc/testsuite/gcc.c-torture/compile/compile.exp" ("uplevel" body line 1) invoked from within "uplevel #0 source /home/faculty/asutton/Code/gcc/c++-concepts/gcc/testsuite/gcc.c-torture/compile/compile.exp" invoked from within "catch "uplevel #0 source $test_file_name"" I removed the offending line of code in this branch just to make the tests run. That change does not affect any other builds on my system, so something isn't being configured correctly. I just can't find what it is. Andrew
Re: Concepts code review
>>> +// Bring the parameters of a function declaration back into >>> +// scope without entering the function body. The declarator >>> +// must be a function declarator. The caller is responsible >>> +// for calling finish_scope. >>> +void >>> +push_function_parms (cp_declarator *declarator) >> >> I think if the caller is calling finish_scope, I'd prefer for the >> begin_scope call to be there as well. >> > Even though Andrew said that this will change later for other reasons, it's > a function I wrote so: I actually debated this with Andrew before. My > rationale for calling begin_scope in the function was that it feels > consistent with the semantics of the call. Specifically it can be seen as > reopening the function parameter scope. Thus the call is balanced by > calling finish_scope. Either way would work of course, but perhaps it just > needed a better name and/or comment? In the process of removing constraints from lang_decl nodes, I also ended up addressing a lot of the other constraint processing comments -- it made sense to do it at the same time. One of those was moving a requires-clause into a function declarator. I had thought that this would prevent me from having to re-open that scope, but it doesn't. The parameter scope is closed at a lower level in the parse :/ So this issue is still around. >>> + // Save the current template requirements. >>> + saved_template_reqs = release (current_template_reqs); >> >> >> It seems like a lot of places with saved_template_reqs variables could be >> converted to use cp_manage_requirements. >> > Probably. The instance you quoted isn't very trivial though. The > requirements are saved in two different branches and need to be restored > before a certain point in the function. Might just need to spend more time > looking over the code. I got rid of current_template_reqs in my current work. Constraints are associated directly with a template parameter list or a declarator. >>> + // FIXME: This could be improved. Perhaps the type of the requires >>> + // expression depends on the satisfaction of its constraints. That >>> + // is, its type is bool only if its substitution into its normalized >>> + // constraints succeeds. >> >> >> The requires-expression is not type-dependent, but it can be >> instantiation-dependent and value-dependent. >> > This is an interesting change. The REQUIRES_EXPR is currently marked as > value dependent. The ChangeLog indicates that Andrew loosened the > conditions for being value dependent for some cases, but then added it as > type dependent when something else failed. May require some time to pin > down exactly what needs to be done here. I think something may have changed since I made that change... If I'm remembering correctly, it used to be the case that build_x_binary_op would try to fold the resulting expression when the operands weren't type dependent. That happens in conjoin_constraints. Now it looks like it's calling build_non_dependent_expr, which does something a little different. I agree that requires-expressions are not type-dependent (they have type bool). Andrew
Re: Concepts code review
>> + // The constraint info maintains information about constraints >> + // associated with the declaration. >> + tree constraint_info; > > > We talked back at the end of June about moving this into a separate > hashtable; I'm still reluctant to add another pointer to most declarations > when only a minority will have constraints. As I was saying in the earlier > thread, I think the problem you were hitting should be resolved by looking > through clones with DECL_ORIGIN. This needs to be fixed before merge, since > it significantly affects non-concepts compiles. Agreed. I'll probably start looking at this on Friday morning. >> + // Zeroth, a constrained function is not viable if its constraints are >> not >> + // satisfied. > > As I suggested in the document review, I think we want to check this after > the number of parameters, to avoid unnecessary implicit template > instantiation in evaluating the constraints. Patch attached. Great. I'll apply that after I merge with trunk (which is going on right now). >> +resolve_constraint_check (tree call) >> +{ >> + gcc_assert (TREE_CODE (call) == CALL_EXPR); > > > Maybe also assert that the call has no function arguments? I'll have to look, but we might get regular calls to constexpr functions through this code path, which are then filtered out during processing. It might be better to not take this path if there are function arguments since that couldn't possibly be a constraint check. >> deduce_concept_introduction (tree expr) >> { >> if (TREE_CODE (expr) == TEMPLATE_ID_EXPR) >> { >> // Get the parameters from the template expression. >> tree decl = TREE_OPERAND (expr, 0); >> tree args = TREE_OPERAND (expr, 1); >> tree var = DECL_TEMPLATE_RESULT (decl); >> tree parms = TREE_VALUE (DECL_TEMPLATE_PARMS (decl)); >> >> parms = coerce_template_parms (parms, args, var); > > > Do you still need this coerce_template_parms now that I've added a call to > lookup_template_variable? Well, once my change is merged onto the branch or > the branch onto trunk. Maybe? I'm not sure what the call to lookup_template_variable is going to do :) I think we still need to instantiate default arguments in order to perform the match. > Can you reduce the code duplication between deduce_constrained_parameter and > deduce_concept_introduction? Yes. >> // Sometimes a function call results in the creation of clean up >> // points. Allow these to be preserved in the body of the >> // constraint, as we might actually need them for some constexpr >> // evaluations. > > > What need are you thinking of? CLEANUP_POINT_EXPR is ignored in constexpr > evaluation. > > Also, this function seems like reinventing massage_constexpr_body, can we > share code? I didn't know if the forthcoming generalized constexpr evaluator would act on those or not. We'll have a look at the massage_constexpr_body function. I wonder if we can apply that to both function and constexpr variables. >> + // Normalize the body of the function into the constriants language. >> + tree body = normalize_constraints (DECL_SAVED_TREE (fn)); >> + if (!body) >> +return error_mark_node; > ... >> >> + // Reduce the initializer of the variable into the constriants >> language. >> + tree body = normalize_constraints (DECL_INITIAL (decl)); > > > If we're normalizing before substitution, why wait until the point of use to > do it? At least we could cache the result of normalization. We should be normalizing and caching as soon as we can create a complete declaration (for some declaration of complete). For functions and function templates, for example, that's at the top of grokfndecl. Although, as I think about it, I seem to remember having to re-normalize a constraint in certain circumstances, but I can't remember what they are. I'll take a look at this. >> // Modify the declared parameters by removing their context (so they >> // don't refer to the enclosing scope), and marking them constant (so >> // we can actually check constexpr properties). > > > We don't check constexpr using these parms anymore, but rather the > substituted arguments, so we don't need to mark them constant, right? Is the > other (context) change still relevant? That will come out. >> + // TODO: Actually check that the expression can be constexpr >> + // evaluatd. >> + // >> + // return truth_node (potential_constant_expression (expr)); >> + sorry ("constexpr requirement"); > > > Pass it to maybe_constant_value and check whether the result is > TREE_CONSTANT? Or do we want to remove the constexpr requirement code now > that it's out of the proposal? This should come out. I think we'll get a non-language way of checking this in the not-so-distant future. >> DECL_INITIAL (decl) = proto; // Describing parameter >> DECL_SIZE_UNIT (decl) = fn; // Constraining function declaration >> DECL_SIZE (decl) = args; // Extra template arguments. > > > I'
Re: Concepts code review
>> Agreed. I'll probably start looking at this on Friday morning. > > > Note that end of stage 1 is Saturday, as I just realized today. So the > sooner the better. :) Ouch. Good thing my merge with trunk broke in unexpected ways this morning -- minimally, something in cgraph ended up missing a #include in the merge and I don't know how to fix it :/ Andrew
Re: [C++ Patch] PR 71140 ("[concepts] ill-formed nested-requirement lacking a semicolon not rejected")
> > BTW, I would discourage you from messing much with the concepts code > at this point, as a major overhaul should be coming soon. > Major overhaul: https://github.com/asutton/gcc (branch is concepts; we're about 2 weeks back from trunk). Unfortunately, I we haven't been following GCC commit discipline, and there's a bunch of dead/legacy code that I need to clean up. And of course some regressions. I wanted to spend the weekend on this and forward a cleaner version next week. But no time is as good as the present it seems. This fork reimplements concepts as currently specified in the WD (for the most part). It also preserves TS syntax (but not behavior), although there are certainly going to be some new bugs. -std=c++2a turns on concepts by default (sets -fconcepts) -fconcepts-ts can be additionally specified to enable TS extensions (abbreviated fn templates, etc). -fconcepts on its own gives you (should give you) TS syntax with C++20 semantics and no C++20 features. Here's what's changed: - new requires clause syntax as required in the WD (-fconcepts-ts will change this back to the TS syntax) - concept bool is now a warning, although (IIRC) disabled with -fconcepts-ts. Function and variable concepts live on. - concepts are now their own kind of declaration (CONCEPT_DECL). That was a big change. - now only 3 kinds of constraints: conj, disj, and pred (should be atomic, also needs a dead code cleanup). - constraints on declarations are represented as expressions -- no normalization until later - associated constraints are only instantiated when checked -- no premature substitution - new implementaiton of satisfaction, does not require ahead-of-time normalization - new implementation of normalization (fewer nodes, smaller impl) - atomic constraint comparison based on expr identity/parameter mapping - complete rewrite of subsumption (new comparison model invalidated some assumptions in the old impl) - constrained decls differentiated by syntax of constraints (not equivalence) - moved the concepts testsuite into c++2a directory as a vetting/curating process, new 2a tests, new ts-compatability tests There are some bugs and regressions. I know for a fact that we've broken partial specialization of variable templats, but I'm really not sure how. There's also probably a bug in the constraint comparison implementation that affects partial ordering. More testing is needed. I mostly ignored the TS support while updating to the WD semantics, so that's been a little buggy when I brought it back online. Also, sometimes diagnostics aren't emitted correctly. I'm not quite sure how to proceed with submitting this patch. Once I made the decision to make concepts their own kind of declaration, the idea of sending small patches went right out the window.
Re: [concepts] Update to match the working draft (and bit more)
Well,,that's unfortunate. Please forgive the alternative patch submission. https://github.com/asutton/gcc/blob/master/concepts.patch > Attached is a rework of the Concepts TS implementation to match the > Working Draft. It's a big patch -- I'd loved to make it smaller, but > it didn't work out that way. > > Here's a brief summary of changes: > > - Make concepts work with -std=c++2a; warn if -fconcepts is also supplied. > - Add a new flag -fconcepts-ts to enable TS syntax* when -std=c++2a is used. > - No more bool for concepts. They are their own kind of declaration. > - New grammar for requires clauses (unfortunately). This can be > overriden with -fconcepts-ts. > - Support "concept bool" with -fconcepts-ts. This includes both > variable and function concepts. > - Constraints are instantiated only at the point of use and properly > interleave substitution and evaluation. This should fix any issues > with "premature substitution" errors. > - Implement semantic comparison of atomic constraints (P0717). This > may be buggy. More testing with complex refinement hierarchies is > needed. > - Completely rewrite the subsumption algorithm in logic. The WD broke > a number of assumptions the previous version relied on, so a simple > fix wasn't possible. We haven't seen the performance issues related to > subsumption that showed up in the past. They're still there, but other > core changes minimize the likelihood of achieving worst case. > - Declaration matching is syntactic (P0716). > - Warnings are emitted for the use of TS syntax unless -fconcepts-ts > is specified. And if you do use -fconcepts, the same-type rule for > abbreviated function templates is dead. > - And just because... make template introduction semantics actually > conform to the TS. We weren't allowing the introduction of a fixed > series of template parameters for an introduced pack. We do now. > > This is not a perfect patch. > > - It somehow breaks partial template specializations of variable > templates (cpp2a/concepts pr80471.C). I have no idea how that > happened. It almost looks like a GC bug. > - There's a new regression in cpp2a/concepts-ts2.C) > - This breaks a lot of concepts TS support (the g++.dg/concepts dir). > - We've seen other errors in parts of GCC not even remotely related to > concepts**. > > My goals over the next few weeks are to clean up the regressions and > start working through the backlog of concepts issues. That includes > fixing new issues as they arise. > > * This patch does not preserve the Concepts TS semantics. Anybody > relying on e.g., subtleties of the partial ordering rules in the TS > will find themselves with broken code. This was a conscious choice. > there are serious design issues in the TS. > > ** Unfortunately, my testing effort before sending this patch is a bit > hampered by the fact that a clean bootstrap build ICEs here (bootstrap > build on Mac OS -- can give more details if needed). > > ../../isl/isl_tab_pip.c: In function ‘isl_tab_basic_set_non_trivial_lexmin’: > ../../isl/isl_tab_pip.c:5087:21: internal compiler error: in check, at > tree-vrp.c:155 > 5087 | __isl_give isl_vec *isl_tab_basic_set_non_trivial_lexmin( > | ^~~~ > > This one isn't my fault :) > > Enjoy, > >> Hi. This is the qmail-send program at sourceware.org. >> I'm afraid I wasn't able to deliver your message to the following addresses. >> This is a permanent error; I've given up. Sorry it didn't work out. >> >> : >> ezmlm-reject: fatal: Sorry, I don't accept messages larger than 40 bytes (#5.2.3) > Andrew Sutton
Re: [C++ Patch] PR 71140 ("[concepts] ill-formed nested-requirement lacking a semicolon not rejected")
Sorry for the slow reply. I've been stuck working on some other projects. > Can you say a bit about why that was better than continuing to use > VAR_DECL? > I wanted to make sure that we avoid normal VAR_DECL processing routines, so we don't e.g., slip into a function where we might try to generate an address for a concept. Yeah, don't worry about trying to send small patches. I don't mind > reviewing what's on the branch, though at least the final patch should > be sent to the list for archival. > > What feedback are you looking for at this point? > Mostly anything that would obviously prevent or cause problems merging in the near future. I'll try to keep the asutton/gcc fork on github rebased on trunk so there shouldn't be too many merge issues.
[PATCH] Add -std=c++2a
This adds a new C++ dialect, enabled by -std=c++2a. libcpp/ Add support for C++2a. * include/cpplib.h (c_lang): Add CXX2A and GNUCXX2A. * init.c (lang_defaults): Add rows for CXX2A and GNUCXX2A. (cpp_init_builtins): Set __cplusplus to 201707L for C++2x. gcc/c-family/ Add support for -std=c++2a. * c-common.h (cxx_dialect): Add cxx2a as a dialect. * opt.c: Add options for -std=c++2a and -std=gnu++2a. * c-opts.c (set_std_cxx2a): New. (c_common_handle_option): Set options when -std=c++2a is enabled. gcc/testsuite/ New test for -std=c++2a. * g++.dg/cpp2a/cplusplus.C: New. Andrew Sutton cxx2a.patch Description: Binary data
Re: [PATCH] Add -std=c++2a
For now, I think these two are incompatible. There are more features in -fconcepts than in C++20 (so far). There are also some changes in syntax and semantics that would be nice to diagnose. A good example would be 'concept' as a decl-specifier (TS) vs. 'concept' as a declaration introducer (WD). I was going to submit a followup that emits a warning when both -std=c++2a and -fconcepts are both enabled and then disables -fconcepts. Andrew Sutton On Thu, Jul 20, 2017 at 1:04 PM, Markus Trippelsdorf wrote: > On 2017.07.20 at 09:33 -0400, Andrew Sutton wrote: >> This adds a new C++ dialect, enabled by -std=c++2a. >> >> libcpp/ >> Add support for C++2a. >> * include/cpplib.h (c_lang): Add CXX2A and GNUCXX2A. >> * init.c (lang_defaults): Add rows for CXX2A and GNUCXX2A. >> (cpp_init_builtins): Set __cplusplus to 201707L for C++2x. >> >> gcc/c-family/ >> Add support for -std=c++2a. >> * c-common.h (cxx_dialect): Add cxx2a as a dialect. >> * opt.c: Add options for -std=c++2a and -std=gnu++2a. >> * c-opts.c (set_std_cxx2a): New. >> (c_common_handle_option): Set options when -std=c++2a is enabled. >> >> gcc/testsuite/ >> New test for -std=c++2a. >> * g++.dg/cpp2a/cplusplus.C: New. > > Perhaps you should enable -fconcepts by default? > > -- > Markus
Re: [PATCH] Giant concepts patch
I just tried building a fresh pull of cmcstl2, and I'm not seeing any errors as a result of not handling those missing codes in tsubst_constraint. At one point, I think it was not possible to get those other constraints in this context because they were nested in a parm_constr. But that seems obviously untrue now. But still... that gcc_unreachable isn't being triggered by any code in cmcstl. I attached a patch that adds tsubsts for the missing constraints. Unfortunately, I don't have time to test thoroughly today. I did find another bug building cmcstl2, hence the attached disable-opt patch. For some reason, the memoization of concept satisfaction is giving momoized results for concept + args that have not yet been evaluated. This is exactly the same problem that made me disable the lookup/memoize_constraint_sat optimizations. Somehow I'm getting the same hash code for different arguments, and they also happen to compare equal. This doesn't seem to affect memoization of concept satisfaction. At least I haven't seen it yet. Anyways, disabling that optimization lets me build cmcstl2 with concepts. Sort of; there's a bug in the library, which is why Casey is added to the mailing. You're missing a const overload of operator* for basic_operator. Patch forthcoming. Changelogs below. 2016-07-10 Andrew Sutton * constraint.cc (tsubst_type_constr, tsubst_implicit_conversion_constr, tsubst_argument_deduction_constr, tsubst_exception_constr): New. (tsubst_constraint): Add cases for missing constraints. 2016-07-10 Andrew Sutton * pt.c (lookup_concept_satisfaction, memoize_concept_satisfaction): Disable memoization of concept results. Andrew Sutton On Sat, Jul 9, 2016 at 11:24 AM, Andrew Sutton wrote: > Do we have a smaller test that reproduces this? One reason I didn't make > much progress was that I could never find a small test that triggers the > problem. I just pulled your branch and plan to do some digging tomorrow. > > > > On Fri, Jul 8, 2016 at 6:42 PM Jason Merrill wrote: >> >> On Wed, Jun 22, 2016 at 2:25 AM, Andrew Sutton >> wrote: >> >> > I've run into some trouble building cmcstl2: declarator requirements >> >> > on a function can lead to constraints that tsubst_constraint doesn't >> >> > handle. What was your theory of only handling a few _CONSTR codes >> >> > there? This is blocking me from checking in the patch. >> > >> > I wonder if those were the problems that I was running into, but hadn't >> > diagnosed. I had thought it shouldn't be possible to get the full set of >> > constraints in tsubst_constraint. I may have mis-analyzed the problem >> > for >> > function constraints. >> >> Any further thoughts? >> >> Jason > > -- > Andrew Sutton diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index 145ae1e..745cbbc 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -1625,12 +1625,70 @@ static tree tsubst_expr_constr (tree t, tree args, tsubst_flags_t complain, tree in_decl) { cp_unevaluated guard; - tree expr = EXPR_CONSTR_EXPR (t); - tree check = tsubst_expr (expr, args, complain, in_decl, false); - if (check == error_mark_node) + tree ret = tsubst_expr (expr, args, complain, in_decl, false); + if (ret == error_mark_node) +return error_mark_node; + return build_nt (EXPR_CONSTR, ret); +} + +static tree +tsubst_type_constr (tree t, tree args, tsubst_flags_t complain, tree in_decl) +{ + tree type = TYPE_CONSTR_TYPE (t); + tree ret = tsubst (type, args, complain, in_decl); + if (ret == error_mark_node) return error_mark_node; - return build_nt (EXPR_CONSTR, check); + return build_nt (TYPE_CONSTR, ret); +} + +static tree +tsubst_implicit_conversion_constr (tree t, tree args, tsubst_flags_t complain, + tree in_decl) +{ + cp_unevaluated guard; + tree expr = ICONV_CONSTR_EXPR (t); + tree type = ICONV_CONSTR_TYPE (t); + tree new_expr = tsubst_expr (expr, args, complain, in_decl, false); + if (new_expr == error_mark_node) +return error_mark_node; + tree new_type = tsubst (type, args, complain, in_decl); + if (new_type == error_mark_node) +return error_mark_node; + return build_nt (ICONV_CONSTR, new_expr, new_type); +} + +static tree +tsubst_argument_deduction_constr (tree t, tree args, tsubst_flags_t complain, + tree in_decl) +{ + cp_unevaluated guard; + tree expr = DEDUCT_CONSTR_EXPR (t); + tree pattern = DEDUCT_CONSTR_PATTERN (t); + tree autos = DEDUCT_CONSTR_PLACEHOLDER(t); + tree new_expr = tsubst_expr (expr, args, complain, in_decl, false); + if (new_expr == error_mark_node) +return error_mark_node; + /* It seems like substituting through the pattern will no
Re: [PATCH] Giant concepts patch
Ah sure. Jason has been vetting my post-Jacksonville concepts patch in the branch jason/concepts-rewrite. I just pulled this off the github GCC mirror this morning to look at an outstanding question. Resulted in the previous 2 patches. I tried building a fresh pull of your cmcstl2 and got an off-by const error. It looks like it's coming from counted_iterator. I'll post the repro instructions and the error on the bug report. Andrew
concept diagnostics
This is not a proper patch. I'm missing the usual changelog and I'm still running the regression tests, but I wanted to get some opinions before committing more time to it. This patch extends the diagnostics for concepts to report precise failures when constraints are not satisfied. It currently reports up to 7 errors and then elides the rest. That should probably be under control of a compiler option, but I'd like some suggestions on how to proceed. Also, diagnostics are currently emitted as notes against the location of the concept declaration. It would be better to diagnose the failure against location of each requirement, but we're not doing a very good job tracking source locations for those. Also, in a lot of cases, we probably just want to replay a substitution with tf_error to generate precise failures. Although that potentially generates *way* more information (e.g., candidate sets for failed overload resolution). I also started try to apply these diagnostics to static_if. The basic idea being: if you write static_if(C, "") where C is a concept, then you should get the full diagnostics for that concept. I suspect that this will be the most requested feature within a few months time. Unfortunately, I ran into a little problem that C is immediately folded into true/false and the original expression is unrecoverable from finish_static_if. I tinkered with parsing the condition as a non-constant expression and then folding it on demand, but that caused a number of regressions, so I had to back it out. Any thoughts on how to proceed? Andrew Index: cxx-pretty-print.c === --- cxx-pretty-print.c (revision 226937) +++ cxx-pretty-print.c (working copy) @@ -2600,6 +2600,7 @@ pp_cxx_compound_requirement (cxx_pretty_ pp_cxx_ws_string (pp, "->"); pp->type_id (type); } + pp_cxx_semicolon (pp); } /* nested requirement: @@ -2646,7 +2647,7 @@ pp_cxx_implicit_conversion_constraint (c pp_left_paren (pp); pp->expression (ICONV_CONSTR_EXPR (t)); pp_cxx_separate_with (pp, ','); - pp->expression (ICONV_CONSTR_TYPE (t)); + pp->type_id (ICONV_CONSTR_TYPE (t)); pp_right_paren (pp); } Index: cp-tree.h === --- cp-tree.h (revision 226937) +++ cp-tree.h (working copy) @@ -6680,6 +6680,8 @@ extern tree tsubst_requires_expr 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 bool variable_concept_check_p(tree); +extern bool concept_check_p (tree); extern tree evaluate_constraints(tree, tree); extern tree evaluate_function_concept (tree, tree); @@ -6687,6 +6689,7 @@ extern tree evaluate_variable_concept extern tree evaluate_constraint_expression (tree, tree); extern bool constraints_satisfied_p (tree); extern bool constraints_satisfied_p (tree, tree); +extern bool constraint_expression_satisfied_p (tree, tree); extern bool equivalent_constraints (tree, tree); extern bool equivalently_constrained(tree, tree); Index: constraint.cc === --- constraint.cc (revision 226937) +++ constraint.cc (working copy) @@ -32,6 +32,7 @@ along with GCC; see the file COPYING3. #include "wide-int.h" #include "inchash.h" #include "tree.h" +#include "print-tree.h" #include "stringpool.h" #include "attribs.h" #include "intl.h" @@ -113,13 +114,22 @@ conjoin_constraints (tree t) return r; } -/* Returns true if T is a call expression to a function - concept. */ +/* Returns true if T is an expression that would evaluate + a variable or function concept. */ + +bool +concept_check_p (tree t) +{ + return function_concept_check_p (t) || variable_concept_check_p (t); +} + +/* Returns true if T is a call to a function concept. */ bool function_concept_check_p (tree t) { - gcc_assert (TREE_CODE (t) == CALL_EXPR); + if (!t || t == error_mark_node || TREE_CODE (t) != CALL_EXPR) +return false; tree fn = CALL_EXPR_FN (t); if (TREE_CODE (fn) == TEMPLATE_ID_EXPR && TREE_CODE (TREE_OPERAND (fn, 0)) == OVERLOAD) @@ -132,6 +142,17 @@ function_concept_check_p (tree t) return false; } +/* Returns true if T is a template-id referring to a variable concept. */ + +bool +variable_concept_check_p (tree t) +{ + if (!t || t == error_mark_node || TREE_CODE (t) != TEMPLATE_ID_EXPR) +return false; + return variable_template_p (TREE_OPERAND (t, 0)); +} + + /*--- Resolution of qualified concept names ---*/ @@ -350,12 +371,12 @@ lift_func
Re: [c++-concepts]
> * Check against cxx11 dialect, not cxx0x. Let's talk about this tomorrow. I'm not quite sure how to do this. > * Any particular reason to use classes with operator() for the > parseers and the combinators? GCC can inline indirect calls to > functions with internal linkage. That should cut down on the > constructor boilerplates. This particular change can be addressed > after the commit. Some of the other combinators that I've built for the requires expression have data fields that act as arguments to the actual other cp_parser_* calls. I'll submit those with the relevant patch. This should be easy to refactor, though. > | +template > | +inline T* take(T*& p) > | +{ > | + T* q = p; > | + p = NULL; > | + return q; > | +} > | +} // namespace > | + > | + > > Call it 'release' -- following standard library terminology. Ah... yes. Good name. > Suggestion: nonnull_or_else? or assert_nonnull? or check_nonnull? > or validate? check_nonnull is a good name. > | - /* 1 spare bit */ > | + unsigned concept_p : 1; /* var or fn */ > | + /* 0 spare bit */ > | }; > > Hmm I don't understand the comment "var or fn". > If it is declared a concept, how can it it be a var? Copied from the other bits in the class. I think it means it applies to either variables or functions. I left it that way in anticipation of template variables.
Re: [c++-concepts]
I'll clean it up and commit tomorrow morning. > Once you've committed the patch, let me know so I can synchronize with > trunk -- or is there another patch coming in this week? I'm hoping to get all of the function-related functionality sent off by tomorrow or Saturday. I found a showstopper in the class template, and I think it will take some time to address. Andrew
Re: [c++-concepts]
I presented that at C++Now, so I hope so :) It lets me write: template requires Input_iterator // no parens! void f(T x); Walter Brown also suggested this usage in his object alias paper. In concepts lite, a concept is essentially an expression. Thus far, we've packaged those expressions in constexpr functions (using "concept" as a declaration specifier to impose additional restrictions). Variable templates fall easily into this same set of restrictions. Plus, no overloading. Andrew On Thu, May 30, 2013 at 3:34 PM, Jason Merrill wrote: > On 05/30/2013 03:17 PM, Andrew Sutton wrote: >>> >>> | - /* 1 spare bit */ >>> | + unsigned concept_p : 1; /* var or fn */ >>> | + /* 0 spare bit */ >>> | }; >>> >>> Hmm I don't understand the comment "var or fn". >>> If it is declared a concept, how can it it be a var? >> >> >> Copied from the other bits in the class. I think it means it applies >> to either variables or functions. I left it that way in anticipation >> of template variables. > > > Can template variables be concepts? > > Jason > -- Andrew Sutton andrew.n.sut...@gmail.com
Re: [c++-concepts]
> * Check against cxx11 dialect, not cxx0x. This check is actually all over parser.c, the reason it shows up in the patch is that I reverted a previous change that affected some code that included it. I'd feel better leaving it in, since its a change that could affect some other part of the compiler. Andrew
[c++-concepts] constraints
This patch adds constraint checking and overloading for function templates, class templates, and alias templates. This patch isn't as big as it seems, it just touches the compiler in a lot of different places. 2013-06-01 Andrew Sutton * gcc/cp/call.c (rejection_reason_code): Add rr_constraint_failure. (template_constraint_failure): New. (template_constraint_failure): Check declaration constraints before other viable function criteria. (add_template_candidate_real): Diagnose constraint failures, and attach constraints to instantiated candidates. (print_z_candidate): Diagnose constraint failures. (get_actual_template): New. (joust): Allow temploids to also participate in most specialied when they have constraints. * gcc/cp/constraint.cc (join_requirements): New (conjoin_requirements): Join expressions correctly. (disjoin_requirements): Join expressions correctly. (is_checkable): Rename from is_constraint, check vs. concept flag. (resolve_constraint_check): Fix. (get_type_constraints): New. (get_decl_constraints): New. (get_constraints): New. (suppress_template_processing): New. (check_requirements): New. (check_dependent_requirements): New. (check_constraints): New. (check_type_constraints): New. (check_decl_constraints): New. (check_template_constraints): New. (equivalent_constraints): New. (equivalently_constrained): New. (more_constraints): New. (more_constrianed): New. (diagnose_constraint_failure): New. * gcc/cp/class.c (are_constrained_member_overloads): New. (add_method): Allow overloading of constrained member functions. * gcc/cp/ptree.c (cxx_print_xnode): Print constraint info. * gcc/cp/pt.c (local_specialization_stack): New. (build_template_info): Incorporate template requirements (check_explicit_specialization): Instantiate requirements for template info. (push_template_decl_real): Include constraints in template info. (redeclare_class_template): Diagnose redeclaration with different constraints. (is_compatible_template_arg): New. (convert_template_argument): Check constraints on template template arguments. (lookup_template_class_1): Check constraints on alias templates. Keep constraints with instantiated types. (instantiate_class_template_1): Check constraints on class templates. (tsubst_decl): Instantiate and keep constraints with template info. Also, allow dependent pack arguments to produce neww parameter packs when instantiated. (tsubst_copy): Handle REAL_TYPE and BOOLEAN_TYPE. (tsubst_copy_and_build): PARM_DECLs can be instantiated as pack expansions (used with requires expression). (fn_type_unification): Check constraints for function templates. (more_specialized_fn): Determine which candidate is more constrained. (tsubst_constraint): New. (substitute_requirements): New. * gcc/cp/parser.c (cp_unevaluated): New. * gcc/cp/tree.h (cp_unevaluated): New. (local_specialization_stack): New. (get_constraints): New. (check_constraints): New. (check_constraints): New. (check_template_constraints): New. (subst_template_constraints): New. (equivalent_constraints): New. (equivalently_constrained): New. (more_constraints): New. (more_constrained): New. (diagnose_constraint_failure): New. * gcc/cp/decl.c: (are_constrained_overloads): New. (duplicate_decls): Allow constrained function overloads, and diagnose attempts to overload concepts. (grokfndecl): Supply empty constraints to build_template_info. (cp_tree_node_structure): Add entry for CONSTRAINT_INFO. (semantics.c): Create template_info for template template parameters as a place to house constraints. * gcc/cp/tree.c (bind_template_template_parm): Provide empty constraints for bound template template parameters. * gcc/cp/cxx-pretty-print.c (pp_cxx_template_declaration): Print the template requirements. reqs-2.patch Description: Binary data
Re: [c++-concepts] code review
Hi Jason, Thanks for the comments. I just went ahead and fixed all the editorial issues. Comments and questions below: >> * gcc/system.h (cstdlib): Include to avoid poisoned >> declaration errors. > > Poisoned declarations of what? This seems redundant with the #include > just below. I never did understand why this happens. Compiling with GCC-4.6, I get these errors originating in logic.cc from an include of . This is what I get: In file included from /usr/include/c++/4.6/bits/stl_algo.h:61:0, from /usr/include/c++/4.6/algorithm:63, from ../../c++-concepts/gcc/cp/logic.cc:45: /usr/include/c++/4.6/cstdlib:76:8: error: attempt to use poisoned "calloc" /usr/include/c++/4.6/cstdlib:83:8: error: attempt to use poisoned "malloc" /usr/include/c++/4.6/cstdlib:89:8: error: attempt to use poisoned "realloc" /usr/include/c++/4.6/cstdlib:112:11: error: attempt to use poisoned "calloc" /usr/include/c++/4.6/cstdlib:119:11: error: attempt to use poisoned "malloc" /usr/include/c++/4.6/cstdlib:127:11: error: attempt to use poisoned "realloc" >> + /* Concepts-related keywords */ >> + { "assume", RID_ASSUME, D_CXXONLY | D_CXX0X | D_CXXWARN }, >> + { "axiom", RID_AXIOM, D_CXXONLY | D_CXX0X | D_CXXWARN }, >> + { "concept", RID_CONCEPT,D_CXXONLY | D_CXX0X | D_CXXWARN }, >> + { "forall", RID_FORALL, D_CXXONLY | D_CXX0X | D_CXXWARN }, >> + { "requires",RID_REQUIRES, D_CXXONLY | D_CXX0X | D_CXXWARN }, > > > I don't see anything that limits these keywords to when concepts are > enabled. You probably want to add an additional mask that applies to these. Ok. I'll add D_CXX_CONCEPTS and set it for all of reserved words. >> +; Activate C++ concepts support. >> +Variable >> +bool flag_concepts > > You don't need to declare this separately. I'm not quite sure what you mean. Separately from what? >> +static tree >> +resolve_constraint_check (tree ovl, tree args) > > This function seems to be trying to model a subset of overload resolution, > which seems fragile to me; better to use the actual overload resolution code > to decide which function the constraint expression calls, or at least > resolve_nondeduced_context which handles SFINAE. It is. I was a little hesitant to use the actual overload resolution facility because of the restrictions for concepts. I think I was also doing something a little different in previous version. I'll take another look and see if either will work instead of my homebrew solution. > >> +case CAST_EXPR: >> + return reduce_node (TREE_VALUE (TREE_OPERAND (t, 0))); > > Are we assuming that constraint expressions can't involve objects of literal > class type? For now, I think it's a reasonable restriction. We can relax this as needed in the future. >> struct GTY(()) tree_template_info { >>struct tree_common common; >> + tree constraint; >>vec >> *typedefs_needing_access_checking; >> }; > > > Why do we need constraint information in template_info? I suppose this is > the issue you raised in your mail last month: > >> I had expected there to be a template decl associated with underlying >> class, but after print-bombing most of the instantiation, lookup, and >> specialization processing routines, I couldn't find that one was ever >> created for the type decl. > > This does seem like a shortcoming, that also led to the typedefs vec getting > stuck into the template_info inappropriately. I guess we should start > building TEMPLATE_DECLs for partial specializations. That's the long and short of it. Gaby suggested writing constraints here so that, for any instantiation, you would have easy access to the constraints for that declaration. >> +struct GTY(()) tree_constraint_info { >> + struct tree_base base; >> + tree spelling; >> + tree requirements; >> + tree assumptions; >> +}; > > > I'm confused by the relationship between the comment and the field names > here. Where do the conclusions come in? Is "requirements (as a constant > expression)" in the spelling or requirements field? I must have forgotten to update the comments. I probably need to re-think this structure a bit. The requirements field is the complete set of requirement (shorthand constraints + requires clause). The assumptions field is the analyzed requirements. I was using the "spelling" field specifically for diagnostics, so I could print exactly what was written. I think it might be better to hang that off the template parameter list rather than the constraint info. I don't think "spelling" is used in the current patch other than initialization. >> + DECL_DECLARED_CONCEPT_P (decl) = true; >> + if (!check_concept_fn (decl)) >> +return NULL_TREE; >> +} > > > I think I'd rather deal with an invalid concept by not marking it as a > concept, but still declaring it as a constexpr function. Sounds reasonable. >> +// Return the current list of assumed terms. >>
Re: [c++-concepts] code review
>> +C++ ObjC++ Var(flag_concepts, true) > > This line declares flag_concepts implicitly. Ah... I see. Fixed. >> That's the long and short of it. Gaby suggested writing constraints >> here so that, for any instantiation, you would have easy access to the >> constraints for that declaration. > > I'm not sure why you would care about the constraints for a particular > instantiation; constraints only apply to the template, right? In concepts lite, yes. Moving forward... I'm less certain. In the context of separate checking, instantiated requirements may carry lookup information into the current instantiation. But that's just speculation. I think I previously put constraint_info in lang_decl_min, right next to template_info no less. It was easy to manage there, and initialized as part of build_template_decl. But this obviously doesn't work for partial specializations unless they get template_decls. I'd be okay committing the current design with the caveat that it may need to be rewritten in the not-so-distant future. I've already written the other other way two or three times, so I'm familiar with those changes. >> branch_goal queues a copy of the current sub-goal, returning a >> reference to that new branch. The insertion of the operands are done >> on different sub-goals, giving the expected results. > > Right, I suppose I should have paid more attention to "This does not update > the current goal"... On the topic of logic.cc, I'm plan on rewriting this module to use a set instead of lists. There will be some pretty substantial changes to the internal interfaces. Would it be reasonable to commit this now (since it works correctly), and plan to rewrite it in the near future? > template > tree > extract_goals (proof_state& s) > ... > return extract_goals(s); > > but I suppose STL style is OK, too. Huh. I didn't realize that could be inlined. Neat. >> I was trying to write the parsing code a little more modularly so I >> could keep my parse functions as small as possible. I use the facility >> more heavily in the requires/validexpr code that's not included here. > > > Hmm, to me it seems more modular to keep all of the code for handling e.g. > "requires" in its own function rather than needing two different places to > know how a requires clause starts. I think I see where the problem is. cp_parser_requires_clause is parsed non-optionally in a requires expression, but that's not included in the patch. I factored out the explicit parsing (hence the assertion) from the optional parsing. I could remove the assertion. There's no path to that function that does not first check that 'requires' has been found. >>> Why don't you use 'release' and conjoin_requirements here? >> >> >> Because there is no template parameter list that can provide >> additional requirements in this declaration. > > > OK, please add a comment to that effect. On second thought, the absence of release() may actually have been a bug. Comment added. >>> The comment sounds more like tsubst_template_parms than >>> coerce_template_parms. >> >> >> It might be... I'll have to look. What I actually want to get is the >> set of actual arguments that will be substituted for template >> parameters given an initial set of arguments (lookup default >> arguments, generate pack arguments, etc). > > > Right, I think coerce_template_parms has the effect you want, I just don't > think of it as doing substitution, so the comment and name could use a > tweak. If the function doesn't go away, that is. Still looking at this. What is the main entry point to overload resolution? Andrew
Re: [c++-concepts] code review
>> I think I previously put constraint_info in lang_decl_min, right next >> to template_info no less. It was easy to manage there, and initialized >> as part of build_template_decl. But this obviously doesn't work for >> partial specializations unless they get template_decls. > > > Right. And we would want it to be specific to template_decls, not all decls > that use lang_decl_min. I'll have to check. I can't remember off the top of my head if non-template member functions have a corresponding template_decl. I think they do. auto declarations will also get constraints in the future. >> On the topic of logic.cc, I'm plan on rewriting this module to use a >> set instead of lists. There will be some pretty substantial changes to >> the internal interfaces. >> >> Would it be reasonable to commit this now (since it works correctly), >> and plan to rewrite it in the near future? > > > OK. I was experimenting with this over the weekend. I'm just going to rewrite it now, but without the optimizations I alluded to earlier. They didn't pan out the way I'd have liked. >> I think I see where the problem is. cp_parser_requires_clause is >> parsed non-optionally in a requires expression, but that's not >> included in the patch. I factored out the explicit parsing (hence the >> assertion) from the optional parsing. > > > The two situations seem pretty similar; you don't decide you're parsing a > requires expression until you see the keyword either, right? > > The usual pattern in the parser is for a function to try to parse a > particular construct and then return NULL_TREE if we're looking at something > else; it seems most straightforward to do that in this case as well. Yes, but I wasn't testing for the keyword prior to the call to cp_parser_requires_clause_opt. That's not quite true, I was in for member functions, but that was an oversight. Changing to test for requires won't be hard. >> What is the main entry point to overload resolution? > > > Perhaps finish_call_expr is what you want. After investigating, neither call_expr nor resolve_nondeduced_context do what I need. I need a resolution of a call expression that does not return overload sets, especially in the case where the initial call expression is already dependent. resolve_nondeduced_context looks like a good candidate to extend, but I hesitate to modify since it's used in a number of different places, and winnowing the overload set may not be appropriate in those contexts.
Re: [c++-concepts] code review
>> After investigating, neither call_expr nor resolve_nondeduced_context >> do what I need. I need a resolution of a call expression that does not >> return overload sets, especially in the case where the initial call >> expression is already dependent. > > > Does this have to do with restrictions on overloading of concept functions? Very much so. I need a single function because I'm inlining its body at the call site. Andrew