Re: contracts library support (was Re: [PATCH] PING implement pre-c++20 contracts)
> Is just using std::terminate as the handler viable? Or if we're sure > contracts in some form will go into the IS eventually, and the > signature won't change, we could just add it in __cxxabiv1:: as you > suggested earlier. No, the handler needs to be configurable (at least quietly) in order to support experimentation by SG21. No idea if it will stay that way. Andrew
Re: [PATCH] PING implement pre-c++20 contracts
I think so, yes. On Fri, Jul 2, 2021 at 11:09 AM Jason Merrill wrote: > > On 7/1/21 12:27 PM, Andrew Sutton wrote: > >>> I think this version addresses most of your concerns. > >> > >> Thanks, looking good. I'll fuss with it a bit and commit it soon. > > Do you agree that this testcase should compile?
Re: [PATCH] PING implement pre-c++20 contracts
> > I think this version addresses most of your concerns. > > Thanks, looking good. I'll fuss with it a bit and commit it soon. Awesome! Andrew
Re: [PATCH] implement pre-c++20 contracts
> > > > Attached is a new squashed revision of the patch sans ChangeLogs. The > > current work is now being done on github: > > https://github.com/lock3/gcc/tree/contracts-jac-alt > > I'm starting to review this now, sorry for the delay. Is this still the > branch you want me to consider for GCC 11? I notice that the -constexpr > and -mangled-config branches are newer. I think so. Jeff can answer more authoritatively. I know we had one set of changes to the design (how contracts) work aimed at improving the debugging experience for violated contracts. I'm not sure if that's in the jac-alt branch though. The -constexpr branch checks for trivially satisfied contracts (e.g., [[assert: true]]) and issues warnings. It also preemptively checks preconditions against constant function arguments. It's probably worth reviewing that separately. I'm not sure the -manged-config branch is worth considering for merging at this point. It's trying to solve a problem that might not be worth solving. Out of curiosity, are you concerned that future versions of contracts might have considerably different syntax or configurability? I'd hope it wouldn't, but who knows where SG21 is going :) Andrew
Re: [PATCH] implement pre-c++20 contracts
Hi Jason, Sorry I haven't been able to get back to this. I've been swamped with other work, and we haven't had the resources to properly address this. Jeff Chapman will be working on cleaning this up for when master/trunk re-opens. > I find the proposed always_continue semantics kind of nonsensical, as > somewhat evidenced by the contortions the implementation gets into with > marking the violation handler as pure. The trick of assigning the > result to a local variable won't work with optimization. We tend to agree and think it's practically non-implementable. IIRC, later contracts proposals steered away from adding this as a concrete semantic. I suspect killing this would be fine. > > +/* Definitions for C++ contract levels > > + Copyright (C) 1987-2018 Free Software Foundation, Inc. > > Should just be 2019 for a new file. Probably 2020 now :) > > + Contributed by Michael Tiemann (tiem...@cygnus.com) > > This seems inaccurate. :) Indeed :) > This change to member function redeclaration seems undesirable; your > rationale in P1680 is "for generality", but member functions are already > stricter about redeclaration than non-member functions; I don't see a > reason to relax this rule just for contracts. With member functions, > there *is* always a canonical first declaration, and people expect the > class definition to have its complete interface, of which contracts are > a part. There was a proposal that gave more motivation than just "for generality". Apparently, I was a co-author -- I think I just helped write the wording. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1320r2.html > For non-member functions, we still need to complain if contracts are > added after we've seen an ODR-use of the function, just like with > explicit specializations. We could do that, but it doesn't seem necessary with this model. Whether the contracts have been seen or not doesn't affect which function is called. > > + /* TODO is there any way to relax this requirement? */ > > + if (DECL_VIRTUAL_P (olddecl) && !TYPE_BEING_DEFINED (DECL_CONTEXT > > (olddecl))) > > Relatedly, I don't think we want to relax this requirement. Probably. Virtual functions and contracts have complex interactions. There are going to be more EWG papers about this, I'm sure. > > + /* FIXME Is this right for friends? Can a friend refer to a static > > member? > > + Can a friend's contracts refer to our privates? Turning them into > > + [[assert]]s inside the body of the friend itself certainly lets them > > do > > + so. */ > > P0542 says contracts are limited to the accessibility of the function > itself, so a friend cannot refer to private members. That will almost certainly be changed. This was the proposal: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1289r0.pdf There was near-unanimous support for removing that (19 for, 1 against). Andrew
[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] 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++/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
[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
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] 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
[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] 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] 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
[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
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] 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
[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] 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
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.
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")
> > 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: [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 <mar...@trippelsdorf.de> 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
[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] 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
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 <andrew.n.sut...@gmail.com> * 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 <andrew.n.sut...@gmail.com> * 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 <andrew.n.sut...@gmail.com> 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 <ja...@redhat.com> wrote: >> >> On Wed, Jun 22, 2016 at 2:25 AM, Andrew Sutton >> <andrew.n.sut...@gmail.com> 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) +
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
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 Merrillwrote: > 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.
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(CT, ) 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 CT 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_function_call (tree t)
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: templatetypename T void f() { vectorint 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
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, vectree, va_gc **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). */ + if (p p-kind == cdk_function p-declarator-kind == cdk_id) I think you can use function_declarator_p here. +static inline bool +pending_expansion_p (tree t) +{ + return (TREE_CODE (t) == PARM_DECL
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
[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
+ // 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'm nervous about misusing these fields this way. Why is a constrained parameter represented as a TYPE_DECL? I think it was because
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
[c++-concepts]
Fixing issues reported by users. 2014-10-20 Andrew Sutton andrew.n.sut...@gmail.com 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] 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 andrew.n.sut...@gmail.com 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 andrew.n.sut...@gmail.com 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 andrew.n.sut...@gmail.com 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 andrew.n.sut...@gmail.com 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] function concepts with deduced return type
Do not allow. Return type deduction only happens during instantiation, and concepts are never instantiated. Therefore, we can't find the return type of a function concept until you try to normalize the return expression. 2014-09-25 Andrew Sutton andrew.n.sut...@gmail.com Explicitly disallow function concepts with deduced return types. * gcc/cp/constraint.cc (check_function_concept): Remove check for deduced return type. * gcc/cp/decl.c (check_concept_fn): Explicitly check for deduced return type. * gcc/testsuite/g++.dg/concepts/fn-concept2.C: New. Andrew Sutton Index: testsuite/g++.dg/concepts/fn-concept2.C === --- testsuite/g++.dg/concepts/fn-concept2.C (revision 0) +++ testsuite/g++.dg/concepts/fn-concept2.C (revision 0) @@ -0,0 +1,7 @@ +// { dg-options -std=c++1z } + +templatetypename T + concept auto C1() { return 0; } // { dg-error deduced return type } + +templatetypename T + concept int C2() { return 0; } // { dg-error return type } Index: cp/constraint.cc === --- cp/constraint.cc (revision 215718) +++ cp/constraint.cc (working copy) @@ -280,11 +280,6 @@ check_function_concept (tree fn) { location_t loc = DECL_SOURCE_LOCATION (fn); - // If fn was declared with auto, make sure the result type is bool. - if (FNDECL_USED_AUTO (fn) TREE_TYPE (fn) != boolean_type_node) -error_at (loc, deduced type of concept definition %qD is %qT and not %qT, - fn, TREE_TYPE (fn), boolean_type_node); - // Check that the function is comprised of only a single // return statement. tree body = DECL_SAVED_TREE (fn); Index: cp/decl.c === --- cp/decl.c (revision 215718) +++ cp/decl.c (working copy) @@ -7525,9 +7525,13 @@ check_concept_fn (tree fn) if (DECL_ARGUMENTS (fn)) error (concept %q#D declared with function parameters, fn); - // The result type must be convertible to bool. - if (!same_type_p (TREE_TYPE (TREE_TYPE (fn)), boolean_type_node)) -error (concept %q#D result must be bool, fn); + // The declared return type of the concept shall be bool, and + // it shall not be deduced from it definition. + tree type = TREE_TYPE (TREE_TYPE (fn)); + if (is_auto (type)) +error (concept %q#D declared with a deduced return type, fn); + else if (type != boolean_type_node) +error (concept %q#D with return type %qT, fn, type); } /* Helper function. Replace the temporary this parameter injected
[c++-concepts] Check function concept definitions
This fixes an ICE trying to normalize a function concept with multiple statements. That error will now be diagnosed at the point of definition. Jason, do you want to review this before I commit? This is a pretty small patch. 2014-09-01 Andrew Sutton andrew.n.sut...@gmail.com Check requirements on function concept definitions. * gcc/cp/decl.c (finish_function): Check properties of a function concept definition. * gcc/cp/constraint.cc (check_function_concept): New. Check for deduced return type and multiple statements. (normalize_misc): Don't normalize multiple statements. (normalize_stmt_list): Removed. * gcc/cp/cp-tree.h (check_function_concept): New. * gcc/testsuite/g++.dg/concepts/fn-concept1.C: New. Andrew Index: cp/cp-tree.h === --- cp/cp-tree.h (revision 214991) +++ cp/cp-tree.h (working copy) @@ -6444,6 +6444,7 @@ extern tree build_concept_check 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 check_function_concept (tree); extern tree finish_concept_introduction (tree, tree); extern tree finish_template_constraints (tree); Index: cp/decl.c === --- cp/decl.c (revision 214268) +++ cp/decl.c (working copy) @@ -14360,6 +14360,10 @@ finish_function (int flags) fntype = TREE_TYPE (fndecl); } + // If this is a concept, check that the definition is reasonable. + if (DECL_DECLARED_CONCEPT_P (fndecl)) +check_function_concept (fndecl); + /* Save constexpr function body before it gets munged by the NRV transformation. */ maybe_save_function_definition (fndecl); Index: cp/constraint.cc === --- cp/constraint.cc (revision 214991) +++ cp/constraint.cc (working copy) @@ -269,6 +269,35 @@ deduce_concept_introduction (tree expr) gcc_unreachable (); } + +// -- // +// Declarations + +// Check that FN satisfies the structural requirements of a +// function concept definition. +tree +check_function_concept (tree fn) +{ + location_t loc = DECL_SOURCE_LOCATION (fn); + + // If fn was declared with auto, make sure the result type is bool. + if (FNDECL_USED_AUTO (fn) TREE_TYPE (fn) != boolean_type_node) +error_at (loc, deduced type of concept definition %qD is not %qT, + fn, boolean_type_node); + + // Check that the function is comprised of only a single + // return statements. + tree body = DECL_SAVED_TREE (fn); + if (TREE_CODE (body) == BIND_EXPR) +body = BIND_EXPR_BODY (body); + if (TREE_CODE (body) != RETURN_EXPR) +error_at (loc, function concept definition %qD has multiple statements, + fn); + + return NULL_TREE; +} + + // -- // // Normalization // @@ -425,9 +454,10 @@ normalize_misc (tree t) case CONSTRUCTOR: return t; -case STATEMENT_LIST: - return normalize_stmt_list (t); - +// This should have been caught as an error. +case STATEMENT_LIST: + return NULL_TREE; + default: gcc_unreachable (); } @@ -630,28 +660,6 @@ normalize_requires (tree t) return t; } -// Reduction rules for the statement list STMTS. -// -// Recursively reduce each statement in the list, concatenating each -// reduced result into a conjunction of requirements. -// -// A constexpr function may include statements other than a return -// statement. The primary purpose of these rules is to filter those -// non-return statements from the constraints language. -tree -normalize_stmt_list (tree stmts) -{ - tree lhs = NULL_TREE; - tree_stmt_iterator i = tsi_start (stmts); - while (!tsi_end_p (i)) -{ - if (tree rhs = normalize_node (tsi_stmt (i))) -lhs = conjoin_constraints (lhs, rhs); - tsi_next (i); -} - return lhs; -} - // Normalize a cast expression. tree normalize_cast (tree t) @@ -686,6 +694,7 @@ normalize_constraints (tree reqs) ++processing_template_decl; tree expr = normalize_node (reqs); --processing_template_decl; + return expr; } Index: testsuite/g++.dg/concepts/fn-concept1.C === --- testsuite/g++.dg/concepts/fn-concept1.C (revision 0) +++ testsuite/g++.dg/concepts/fn-concept1.C (revision 0) @@ -0,0 +1,9 @@ +// { dg-options -std=c++1z } + +templatetypename T + concept bool Tuple() { // { dg-error multiple statements } +static_assert(T::value, ); +return true; + } + + void f(Tuple);
Re: [c++-concepts] Check function concept definitions
Hmm, have we actually discussed this in core review? I'm not seeing it on the wiki. Constexpr started out this way too, and allowing static_assert was added pretty fast. C++11 said its function-body shall be = delete, = default, or a compound-statement that contains only — null statements, — static_assert-declarations — typedef declarations and alias-declarations that do not define classes or enumerations, — using-declarations, — using-directives, — and exactly one return statement; Is there a reason we want to be more strict than this for concept functions? I don't remember much controversy on that particular limitation in either Rapperswil or the previous telecon review. The main reason for the restriction is that concept definitions are normalized into a single constraint-expression. And it's not obvious how things like using declarations and static-assertions should be interpreted within the constraint language. That said, having a static_assert inside a concept kind of defeats the purpose since it triggers a diagnostic when its condition isn't satisfied. That's not very SFINAE friendly :) Maybe the restriction can relaxed when we consider the TS for adoption in 17. Andrew
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 paolo.carl...@oracle.com 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 andrew.n.sut...@gmail.com 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 } + +templatetypename T + concept bool Eq() { return requires(T t) { t == t; }; } + +templateEq T struct Foo { }; + +templatetypename T + struct S { // { dg-error constraint failure } +templateEq U friend class Bar; + +friend class FooT; + }; + +struct X { }; + +int main() { + Sint si; // OK + SX 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 } + +templatetypename T + concept bool Eq() { return requires(T t) { t == t; }; } + +struct Nt { + templateEq T friend void f(T) { } +} nt; + +templatetypename T struct S; + +templateEq T + void proc(ST*); + +templatetypename T + struct S { +friend bool operator==(S, S) requires EqT() { 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 } + + Sint si; + si == si; // OK + + SX sx; + sx == sx; // { dg-error no match } +}
[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 andrew.n.sut...@gmail.com 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 %concept%); + 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 andrew.n.sut...@gmail.com 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)
[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 andrew.n.sut...@gmail.com 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 error_mark_node; return result; } @@ -574,6 +597,29 @@ normalize_stmt_list
[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 andrew.n.sut...@gmail.com * 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 andrew.n.sut...@gmail.com * 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 (type) == TYPE_DECL + DECL_SIZE_UNIT (type) + TREE_TYPE (type); +} + +// Returns true
Re: [c++-concepts] explicit instantiation and specialization
Just committed this patch, fixing the bootstrap. 2014-08-13 Andrew Sutton andrew.n.sut...@gmail.com 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 andrew.n.sut...@gmail.com 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)
Re: [c++-concepts] variable concepts
Committed. Andrew Sutton On Wed, Aug 13, 2014 at 3:24 AM, Braden Obrzut ad...@maniacsvault.net 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 ad...@maniacsvault.net * 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 andrew.n.sut...@gmail.com 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: + // + //templateC T + //struct S { + // templateD U void f(U); + //}; + // + //templateC T template D U void ST::f(U) { } + // + // In both decls, the constraint DU 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: + // + //templateC T void f(); + // + // Note that the constraint CT 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 above, when do I ever have leading
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: 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 ja...@redhat.com 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
[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 andrew.n.sut...@gmail.com * 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
* 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]
Rewrite the constraint-checking code so that it doesn't instantiate concept definitions. Instead of doing a simple constexpr evaluation on the associated constraints, this now iterates over the decomposed assumptions to determine satisfaction. 2014-08-06 Andrew Sutton andrew.n.sut...@gmail.com * gcc/cp/constraints.c (tsubst_requires_body, instantiate_requirements): Lift the unevaluated operand guard to the entire constraint expression. (check_satisfied, all_constraints_satisfied, any_conjunctions_satisfied): Rewrite constraint checking to use atomic constraints. Prevents instantiation of concepts. (check_diagnostic_constraints): Recursively decompose and check constraints for fine-grain diagnostics. (diagnose_*): Use new constraint checking function. Andrew Sutton Index: gcc/cp/constraint.cc === --- gcc/cp/constraint.cc (revision 213130) +++ gcc/cp/constraint.cc (working copy) @@ -1117,7 +1117,6 @@ tsubst_local_parms (tree t, tree tsubst_requirement_body (tree t, tree args, tree in_decl) { - cp_unevaluated guard; tree r = NULL_TREE; while (t) { @@ -1143,6 +1142,7 @@ 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) @@ -1207,6 +1207,7 @@ tsubst_nested_req (tree t, tree args, tr tree instantiate_requirements (tree reqs, tree args, bool do_not_fold) { + cp_unevaluated guard; if (do_not_fold) ++processing_template_decl; tree r = tsubst_expr (reqs, args, tf_none, NULL_TREE, false); @@ -1248,22 +1249,55 @@ tsubst_constraint_info (tree ci, tree ar // evaluation of constraints. namespace { -// Returns true if the requirements expression REQS is satisfied -// and false otherwise. The requirements are checked by simply -// evaluating REQS as a constant expression. -static inline bool -check_requirements (tree reqs) +// Returns true iff the atomic constraint, REQ, is satisfied. This +// is the case when substitution succeeds and the resulting expression +// evaluates to true. +static bool +check_satisfied (tree req, tree args) { + // Instantiate and evaluate the requirements. + req = instantiate_requirements (req, args, false); + if (req == error_mark_node) +return false; + // Reduce any remaining TRAIT_EXPR nodes before evaluating. - reqs = fold_non_dependent_expr (reqs); + req = fold_non_dependent_expr (req); // Requirements are satisfied when REQS evaluates to true. - return cxx_constant_value (reqs) == boolean_true_node; + tree result = cxx_constant_value (req); + + return result == boolean_true_node; +} + +// Returns true iff all atomic constraints in the list are satisfied. +static bool +all_constraints_satisfied (tree reqs, tree args) +{ + int n = TREE_VEC_LENGTH (reqs); + for (int i = 0; i n; ++i) +{ + tree req = TREE_VEC_ELT (reqs, i); + if (!check_satisfied (req, args)) +return false; +} + return true; } -// Returns true if the requirements expression REQS is satisfied -// and false otherwise. The requirements are checked by first -// instantiating REQS and then evaluating it as a constant expression. +// Returns true if any conjunction of assumed requirements are satisfied. +static bool +any_conjunctions_satisfied (tree reqs, tree args) +{ + int n = TREE_VEC_LENGTH (reqs); + for (int i = 0; i n; ++i) +{ + tree con = TREE_VEC_ELT (reqs, i); + if (all_constraints_satisfied (con, args)) +return true; +} + return false; +} + +// Returns true iff the assumptions in REQS are satisfied. static inline bool check_requirements (tree reqs, tree args) { @@ -1272,11 +1306,7 @@ check_requirements (tree reqs, tree args if (args uses_template_parms (args)) return true; - // Instantiate and evaluate the requirements. - reqs = instantiate_requirements (reqs, args, false); - if (reqs == error_mark_node) -return false; - return check_requirements (reqs); + return any_conjunctions_satisfied (reqs, args); } } // namespace @@ -1295,7 +1325,7 @@ check_constraints (tree cinfo) // all remaining expressions that are not constant expressions // (e.g., template-id expressions). else -return check_requirements (CI_ASSOCIATED_REQS (cinfo), NULL_TREE); +return check_requirements (CI_ASSUMPTIONS (cinfo), NULL_TREE); } // Check the constraints in CINFO against the given ARGS, returning @@ -1309,8 +1339,9 @@ check_constraints (tree cinfo, tree args // Invlaid requirements cannot be satisfied. else if (!valid_requirements_p (cinfo)) return false; - else -return check_requirements (CI_ASSOCIATED_REQS (cinfo), args); + else { +return check_requirements (CI_ASSUMPTIONS (cinfo), args); + } } // Check the constraints of the declaration or type T, against @@ -1322,6
Re: [c++-concepts] Allow function parameters to be referenced in trailing requires clauses
Applied an updated version of this patch. 2014-7-30 Braden Obrzut ad...@maniacsvault.net * gcc/cp/parser.c (cp_parser_trailing_requirements): Handle requires keyword manually so that we can push function parameters back into scope. * gcc/cp/decl.c (push_function_parms): New. Recovers and reopens function parameter scope from declarator. * gcc/testsuite/g++.dg/concepts/req*.C: New tests. 2014-07-30 Andrew Sutton andrew.n.sut...@gmail.com * gcc/testsuite/g++.dg/concepts/test.C: Removed. Andrew Sutton On Tue, Jun 17, 2014 at 5:06 AM, Braden Obrzut ad...@maniacsvault.net wrote: This patch allows function parameters to be referenced by trailing requires clauses. Typically this is used to refer to the type of an implicitly generated template. For example, the following should now be valid (where C is some previously defined concept): auto f1 (auto x) requires Cdecltype(x) (); Note that the test case trailing-requires-overload.C will fail to compile unless the previously submitted patch is applied first. 2014-06-17 Braden Obrzut ad...@maniacsvault.net * gcc/cp/parser.c (cp_parser_trailing_requirements): Handle requires keyword manually so that we can push function parameters back into scope. * gcc/cp/decl.c (push_function_parms): New. Recovers and reopens function parameter scope from declarator. * gcc/testsuite/g++.dg/concepts/trailing-requires.C: New tests. * gcc/testsuite/g++.dg/concepts/trailing-requires-overload.C: New tests. Index: gcc/testsuite/g++.dg/concepts/traits1.C === --- gcc/testsuite/g++.dg/concepts/traits1.C (revision 212456) +++ gcc/testsuite/g++.dg/concepts/traits1.C (working copy) @@ -79,21 +79,21 @@ void f18() requires Enumvoid(); int main() { - f1(); // { dg-error cannot } - f2(); // { dg-error cannot } - f3(); // { dg-error cannot } - f4(); // { dg-error cannot } - f5(); // { dg-error cannot } - f6(); // { dg-error cannot } - f7(); // { dg-error cannot } - f8(); // { dg-error cannot } - f9(); // { dg-error cannot } - f10(); // { dg-error cannot } - f11(); // { dg-error cannot } - f12(); // { dg-error cannot } - f13(); // { dg-error cannot } - f14(); // { dg-error cannot } - f15(); // { dg-error cannot } - f16(); // { dg-error cannot } - f17(); // { dg-error cannot } + f1(); // { dg-error cannot call } + f2(); // { dg-error cannot call } + f3(); // { dg-error cannot call } + f4(); // { dg-error cannot call } + f5(); // { dg-error cannot call } + f6(); // { dg-error cannot call } + f7(); // { dg-error cannot call } + f8(); // { dg-error cannot call } + f9(); // { dg-error cannot call } + f10(); // { dg-error cannot call } + f11(); // { dg-error cannot call } + f12(); // { dg-error cannot call } + f13(); // { dg-error cannot call } + f14(); // { dg-error cannot call } + f15(); // { dg-error cannot call } + f16(); // { dg-error cannot call } + f17(); // { dg-error cannot call } } Index: gcc/testsuite/g++.dg/concepts/req1.C === --- gcc/testsuite/g++.dg/concepts/req1.C (revision 0) +++ gcc/testsuite/g++.dg/concepts/req1.C (revision 0) @@ -0,0 +1,15 @@ +// { dg-do run } +// { dg-options -std=c++1z } + +templatetypename T + concept bool Class () { return __is_class(T); } + +void f1(auto a) requires Classdecltype(a)() { } +void f2(auto a) requires requires (decltype(a) x) { -x; } { } + +struct S { } s; + +int main() { + f1(s); + f2(0); +} Index: gcc/testsuite/g++.dg/concepts/req2.C === --- gcc/testsuite/g++.dg/concepts/req2.C (revision 0) +++ gcc/testsuite/g++.dg/concepts/req2.C (revision 0) @@ -0,0 +1,21 @@ +// { dg-options -std=c++1z } + +#include cassert + +templatetypename T + concept bool Class () { return __is_class(T); } + +void f1 (auto a) requires Classdecltype(a)() { } + + // FIXME: This is generating excess errors related to pretty + // printing the trailing requires expression. +void f2(auto a) + requires requires (decltype(a) x) { -x; } +{ } + +struct S { } s; + +int main() { + f1(0); // { dg-error matching } + f2((void*)0); // { dg-error matching } +} Index: gcc/testsuite/g++.dg/concepts/req3.C === --- gcc/testsuite/g++.dg/concepts/req3.C (revision 0) +++ gcc/testsuite/g++.dg/concepts/req3.C (revision 0) @@ -0,0 +1,18 @@ +// { dg-do run } +// { dg-options -std=c++1z } + +templatetypename T + concept bool Class () { return __is_class(T); } + +struct Test { + void f(auto a) requires Classdecltype(a)(); +} test; + +struct S { }s; + +int main() { + test.f(s); +} + +void Test::f(auto a) requires Classdecltype(a)() { } + Index: gcc/testsuite/g++.dg/concepts/test.C === --- gcc/testsuite/g++.dg/concepts/test.C
Re: Patch for constexpr variable templates
It sounds like GCC's behavior with auto in function parameters needs to be changed, but that definitely sounds like a separate patch to me. I think so. It's definitely a different patch. Agreed. I've been thinking about a simple way for your patch to add to the constraints for 'auto_is_implicit_function_template_parm_p' in 'cp_parser_parameter_declaration_clause' but this is happening incrementally at parse time and I can't see how to distinguish between the following 'auto' parameters: 1) auto f(auto);// generic function 'f'; transformed into template by 'auto' in parameter list. 2) auto (*f) (auto);// plain variable 'f' (should have an initializer for deduction of 'auto's. 3) auto (*f (auto)) (auto); // generic function 'f' constrained to returning a unary function pointer deduced from the return expression. Really? I've read the comment and I'm still not sure how to read this declaration. Ultimately, the last two would require the generalized 'auto' type deduction behavior. The difficulty is that there doesn't appear to be any existing means for determining, at parse time of the first (auto, whether we're forming a function or variable declaration. Maybe such state would fall out of a generalized 'auto' solution. I was wondering about this on the drive to work this morning. Maybe trying to pin down semantics at parse time isn't the right approach. That is, always parse declarations like variables, and then build up template parameters as needed during grorkdecl or grokfndecl. Or maybe that's too late. I don't know. Whatever the solution for auto, it will be the same for concepts. We'll just add constraints to the auto-type whenever we find a constrained-type-specifier. Andrew
[c++-concepts] overloading update
Update the overloading rules for constraints to bring them into line with the current wording. This handles overloads of member functions of class template specializations separately from function templates. Currently, functions that are not specializations of templates (or temploids) can only be overloaded by type. They are not ordered by their constraints. This patch also contains an uncommitted change fixing some small diagnostic issues. Unfortunately, they got lumped together. 2014-07-28 Andrew Sutton andrew.n.sut...@gmail.com * gcc/cp/cp-tree.h (more_constraints): Remove (subsumes_constraints): Renamed from more_constraints (more_constrained): Repurposed * gcc/cp/call-c (template_decl_for_candidates): Rename to get_temploid, only get template info for member functions of a class template specialization. (joust): Handle member functions of class template specializations separately from function templates. This matches the new wording in the TS. * gcc/cp/logic.cc (match_terms): Make inline. (subsumes_constraints): Rename to subsumes_constraints_nonnull. * gcc/cp/pt.c (is_compatible_template_arg): Use subsumes. (more_specialized_fn): Use usubsumes_constraints. (more_specialized_class): Use more_constrained. * gcc/cp/constraint.cc (more_constraints): Removed. (more_constrained): New. 2014-07-11 Andrew Sutton andrew.n.sut...@gmail.com * gcc/cp/typeck.c (cp_build_function_call_vec): Emit diagnostic at the input location. * gcc/cp/error.c (dump_template_decl): Constraints are never invalid in this way. Also fixes brace warning. Andrew Sutton Index: error.c === --- error.c (revision 212456) +++ error.c (working copy) @@ -1280,10 +1280,7 @@ dump_template_decl (cxx_pretty_printer * if (flag_concepts) if (tree ci = get_constraints (t)) -if (ci != error_mark_node) - pp_cxx_requires_clause (pp, CI_LEADING_REQS (ci)); -else - pp_cxx_ws_string (pp, invalid-constraints); + pp_cxx_requires_clause (pp, CI_LEADING_REQS (ci)); pp_cxx_whitespace (pp); } Index: typeck.c === --- typeck.c (revision 212456) +++ typeck.c (working copy) @@ -3463,8 +3463,8 @@ cp_build_function_call_vec (tree functio if (tree ci = get_constraints (function)) if (!check_constraints (ci)) { + error (cannot call function %qD, function); location_t loc = DECL_SOURCE_LOCATION (function); - error_at (loc, cannot call function %qD, function); diagnose_constraints (loc, function, NULL_TREE); return error_mark_node; } Index: cp-tree.h === --- cp-tree.h (revision 212456) +++ cp-tree.h (working copy) @@ -6423,8 +6423,8 @@ extern bool check_template_constraints extern tree subst_template_constraints (tree, tree); extern bool equivalent_constraints (tree, tree); extern bool equivalently_constrained(tree, tree); -extern bool more_constraints(tree, tree); -extern bool more_constrained(tree, tree); +extern bool subsumes_constraints(tree, tree); +extern int more_constrained (tree, tree); extern void diagnose_constraints(location_t, tree, tree); Index: call.c === --- call.c (revision 212456) +++ call.c (working copy) @@ -27,6 +27,7 @@ along with GCC; see the file COPYING3. #include coretypes.h #include tm.h #include tree.h +#include print-tree.h #include stor-layout.h #include trans-mem.h #include stringpool.h @@ -8731,20 +8732,22 @@ add_warning (struct z_candidate *winner, winner-warnings = cw; } -// Returns the template declaration associated with the candidate -// function. For actual templates, this is directly associated -// with the candidate. For temploids, we return the template -// associated with the specialization. +// 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 -template_decl_for_candidate (struct z_candidate *cand) +get_temploid (struct z_candidate *cand) { - tree r = cand-template_decl; - tree d = cand-fn; - if (!r DECL_P (d) DECL_USE_TEMPLATE (d)) -r = DECL_TI_TEMPLATE (d); - if (r TREE_CODE (r) == TEMPLATE_INFO) -r = TI_TEMPLATE (r); - return r; + gcc_assert (cand); + tree t = NULL_TREE; + if (!cand-template_decl) +{ + if (DECL_P (cand-fn) DECL_USE_TEMPLATE (cand-fn)) +t
Re: Patch for constexpr variable templates
In the 59638 case, the declarations void (*a)(auto); void (*b)(auto) = 0; are shorthand for template typename T void (*a)(T); template typename T void (*b)(T) = 0; which, unless there's some constraint with variable templates that I'm not aware of, ought to define two variable templates 'a' and 'b' to be ptr-to-function-taking-T. So I think it's correct that the variable template stuff should be triggering here. There isn't, but this interpretation isn't consistent with the use of auto in variable declarations. For example, this: const auto x = 0; does not mean: templatetypename T const T x = 0; So I would be surprised if any of: void (*p1)(auto); auto (*p2)(int); vectorauto x; did mean create a template instead of deduce the type of x. Also, if we did have this interpretation of auto for some (but not all?) variable declarations, we would have to know to write those as template-ids: void (*p)(auto); pint = some_f; since one cannot refer to a template specialization without arguments. I'm much, much happier if, for variable templates, we always deduce the type from the initializer.. Besides, that wording (or some approximation thereof) is already in the TS for concepts. A question came up during the CWG review as to whether we could declare function parameters as void (*p)(auto), and EWG said, sure, go for it. We also have the ability to declare function parameters as, e.g., vectorauto or pairconst auto, auto*. I applied that to variable templates as well, since it would have been a bit inconsistent, otherwise. Andrew
Re: Patch for constexpr variable templates
But someday we'll want non-constexpr too. I have only seen a sentence somewhere stating that non-constexpr variable templates are allowed but have seen no paper or wording anywhere. Does anyone know where such exists? When variable templates were proposed, EWG decided they wanted non-constexpr variable templates also. I think that the current draft reflects that, since I can't find anything that says variable templates shall be declared constexpr. There's also an implied requirement for partial specialization of variable templates (14.3.3p2), but no elaboration of that. Core issue 1711 specifically addresses this. A quick search shows that Clang already implements it. Andrew
[c++-concepts] fixes
Fix a couple of issues causing a test regression and boostrap build errors. 2014-07-11 Andrew Sutton andrew.n.sut...@gmail.com * gcc/cp/typeck.c (cp_build_function_call_vec): Emit diagnostic at the input location. * gcc/cp/error.c (dump_template_decl): Constraints are never invalid in this way. Also fixes brace warning. Andrew Sutton Index: gcc/cp/typeck.c === --- gcc/cp/typeck.c (revision 212456) +++ gcc/cp/typeck.c (working copy) @@ -3463,8 +3463,8 @@ cp_build_function_call_vec (tree functio if (tree ci = get_constraints (function)) if (!check_constraints (ci)) { + error (cannot call function %qD, function); location_t loc = DECL_SOURCE_LOCATION (function); - error_at (loc, cannot call function %qD, function); diagnose_constraints (loc, function, NULL_TREE); return error_mark_node; } Index: gcc/cp/error.c === --- gcc/cp/error.c (revision 212456) +++ gcc/cp/error.c (working copy) @@ -1280,10 +1280,7 @@ dump_template_decl (cxx_pretty_printer * if (flag_concepts) if (tree ci = get_constraints (t)) -if (ci != error_mark_node) - pp_cxx_requires_clause (pp, CI_LEADING_REQS (ci)); -else - pp_cxx_ws_string (pp, invalid-constraints); + pp_cxx_requires_clause (pp, CI_LEADING_REQS (ci)); pp_cxx_whitespace (pp); }
[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 andrew.n.sut...@gmail.com * 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_compatible_template_arg (tree parm, t
[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 andrew.n.sut...@gmail.com * 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] 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
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
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 ad...@maniacsvault.net 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 ad...@maniacsvault.net * 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 placeholder instead of a dump_expr error. 2014-06-24 Andrew Sutton andrew.n.sut...@gmail.com * 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, placeholder); + 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 andrew.n.sut...@gmail.com * 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 { + templatetypename T +static concept bool D() { return __is_same_as(T, int); } + + templatetypename T, typename U +static concept bool E() { return __is_same_as(T, U); } +}; + +void f1(Base::D) { } +void f2(Base::Edouble x) { } + +templatetypename T + struct S : Base { +void f1(Base::D) { } +void f2(Base::ET x) { } + }; + +int main() { + f1(0); + + f2(0.0); + + Sint 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 { + templatetypename T, typename U +bool C() const { return false; } // Not a concept! + + templatetypename T +static concept bool D() { return __is_same_as(T, int); } + + templatetypename T, typename U +static concept bool E() { return __is_same_as(T, U); } +}; + +void f1(Base::D) { } +void f2(Base::Edouble x) { } + +templatetypename T + struct S : Base { +void f0(Base::Cfloat x) { } // { dg-error expected|type } +void f1(Base::D) { } +void f2(Base::ET x) { } + }; + +int main() { + f1('a'); // { dg-error matching } + f2(0); // { dg-error matching } + + Sint 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?, ARGS // 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, type_decl)) Index: constraint.cc
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;
terse notation diagnostics
Adds additional checks and tests for ill-formed programs. 2014-06-12 Andrew Sutton andrew.n.sut...@gmail.com * 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 cassert +#include type_traits templatetypename T concept bool C() { return __is_class(T); } -struct S { } s; +templatetypename T + concept bool Type() { return true; } + +struct S { }; int called; @@ -50,7 +55,43 @@ templateC T }; +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_referenceT::value, not an lvlaue reference); +} + +void +fwd_const_lvalue_ref(Type x) { + using T = decltype(x); + static_assert(std::is_lvalue_referenceT::value, not an lvalue reference); + using U = typename std::remove_referenceT::type; + static_assert(std::is_constU::value, not const-qualified); +} + +void fwd_rvalue_ref(Type x) { + using T = decltype(x); + static_assert(std::is_rvalue_referenceT::value, not an rvalue reference); +} + +// Make sure we can use nested names speicifers for concept names. +namespace N { + templatetypename T +concept bool C() { return true; } +} // namesspace N + +void foo(N::C x) { } + int main() { + S s; + const S cs; + f(0); assert(called == 1); g(s); assert(called == 2); @@ -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() { S2S 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 cassert + +templatetypename T + concept bool C() { return __is_class(T); } + +templateint N + concept bool Int
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 andrew.n.sut...@gmail.com * 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?, ARGS +// where ? is a placeholder for any kind of template argument. If ARGS +// is NULL, then we try to form a concept check
[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: templateconst C // 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 andrew.n.sut...@gmail.com * 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 } + +templatetypename T + concept bool C() { return __is_class(T); } + +templateconst C T struct S1 { };// { dg-error cv-qualified } +templatevolatile C T struct S2 { }; // { dg-error cv-qualified } +templateC* T struct S3 { }; // { dg-error invalid } +templateC const* T struct S3a { }; // { dg-error invalid } +templateC* const T struct S3b { }; // { dg-error invalid } +templateC T struct S4 { }; // { dg-error invalid } +templateC[3] T struct S4 { }; // { dg-error invalid|expected } +templateC(*T)() 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 cassert + +templatetypename T + 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; } +}; + +templateC T + struct S2 { +void f1(auto x) { called = 1; } +void f2(C x) { called = 2; } + +void f3(auto x) { called = 1; } +void f3(C x) { called = 2; } + +void h1(auto x); +void h2(C x); + +void h3(auto x); +void h3(C x); + +templateC U + void g1(T t, U u) { called = 1; } + +templateC U + void g2(T t, U u
Re: [PATCH] [C++ RFC] Support named type capture for generic lambdas and generic functions as proposed by N3878
It's not clear that this feature will be part of concepts. It will not be included in the initial working paper, so the proposal will need to be re-evaluated. Andrew On Tue, Mar 25, 2014 at 3:03 AM, Adam Butcher a...@jessamine.co.uk wrote: * parser.c (cp_parser_simple_type_specifier): Lookahead for a braced identifier after a generic type ('auto') parameter and, if present, use that as the type identifier name. Otherwise generate one with make_generic_type_name. Pass the resulting identifier as the new second parameter ... (synthesize_implicit_template_parm): ... here. Synthesize the template type parm with the provided name rather than generating one. * g++.dg/cpp1y/generic-fn-typeid.C: New testcase. --- gcc/cp/parser.c| 55 +- gcc/testsuite/g++.dg/cpp1y/generic-fn-typeid.C | 42 2 files changed, 88 insertions(+), 9 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1y/generic-fn-typeid.C diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 49fb731..4d6f8fe 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -2128,8 +2128,10 @@ static tree cp_parser_late_parsing_omp_declare_simd static tree cp_parser_late_parsing_cilk_simd_fn_info (cp_parser *, tree); +static tree make_generic_type_name + (); static tree synthesize_implicit_template_parm - (cp_parser *); + (cp_parser *, tree); static tree finish_fully_implicit_template (cp_parser *, tree); @@ -14530,23 +14532,58 @@ cp_parser_simple_type_specifier (cp_parser* parser, maybe_warn_cpp0x (CPP0X_AUTO); if (parser-auto_is_implicit_function_template_parm_p) { - type = synthesize_implicit_template_parm (parser); + /* Synthesize an implicit template parameter named as specified by +the IDENTIFIER_NODE of a braced identifier (as proposed by section +2.2 of N3878). If no braced identifier is present then a name is +generated a via make_generic_type_name. */ + + if (cp_lexer_peek_nth_token + (parser-lexer, 2)-type == CPP_OPEN_BRACE) + { + /* The 'auto' has only been peeked and is expected to be consumed +later; parse the braced identifier leaving the closing brace as +the next token. */ + + cp_lexer_consume_token (parser-lexer); /* RID_AUTO */ + cp_lexer_consume_token (parser-lexer); /* CPP_OPEN_BRACE */ + + tree synth_id = cp_parser_identifier (parser); + if (synth_id != error_mark_node) + type = synthesize_implicit_template_parm (parser, synth_id); + + if (cp_parser_require + (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE) == 0 + || synth_id == error_mark_node) + { + error_at (input_location, +expected braced identifier for generic type capture); + return error_mark_node; + } + + /* Roll-back one token to allow for consume below. */ + cp_lexer_set_token_position (parser-lexer, + cp_lexer_previous_token_position + (parser-lexer)); + } + else + type = synthesize_implicit_template_parm + (parser, make_generic_type_name ()); if (current_class_type LAMBDA_TYPE_P (current_class_type)) { if (cxx_dialect cxx1y) - pedwarn (location_of (type), 0, + pedwarn (token-location, 0, use of %auto% in lambda parameter declaration only available with -std=c++1y or -std=gnu++1y); } else if (cxx_dialect cxx1y) - pedwarn (location_of (type), 0, + pedwarn (token-location, 0, use of %auto% in parameter declaration only available with -std=c++1y or -std=gnu++1y); else - pedwarn (location_of (type), OPT_Wpedantic, + pedwarn (token-location, OPT_Wpedantic, ISO C++ forbids use of %auto% in parameter declaration); } @@ -31957,11 +31994,12 @@ tree_type_is_auto_or_concept (const_tree t) } /* Add an implicit template type parameter to the CURRENT_TEMPLATE_PARMS - (creating a new template parameter list if necessary). Returns the newly - created template type parm. */ + (creating a new template parameter list if necessary). The template type + parameter is given the id SYNTH_ID. Returns the newly created template type + parm. */ tree -synthesize_implicit_template_parm (cp_parser *parser)
Fwd: [c++-concepts] Shorthand notation
I'm resending this patch for constrained template parameters for review. It's been languishing for a while without review and it has some interesting features in the implementation (namely, resolution mechanism or constrained template parameters). Andrew -- Forwarded message -- From: Andrew Sutton andrew.n.sut...@gmail.com Date: Wed, Oct 16, 2013 at 9:59 AM Subject: [c++-concepts] Shorthand notation To: gcc-patches@gcc.gnu.org, Jason Merrill ja...@redhat.com 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: templatetypename T, FunctionT 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: templateClass... Ts // ClassT() must be true for each T in Ts void f(); The transformation is: templatetypename... Ts requires ClassTs()... void f(); Where ClassTs()... expands to ClassT1() ClassT2() ... 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 andrew.n.sut...@gmail.com * 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
[c++-concepts] Constrained scope bugfix
Partially fixing a bug that caused lookup errors in valid programs. For example: templateInt T, Float U pairT, U::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: templatetypename T struct S { void f(); } templateInt T void ST::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 andrew.n.sut...@gmail.com * 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: +// +//templateObject T +// struct S { void f(); }; #1 +// +//templateObject T +// void ST::f() { } #2 +// +// We check, in #2, that ST 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 ST that is +// unconstrained, but this is not diagnosed here. +// +//templatetypename T +// void ST::f() { } +// +// We cannot diagnose this problem here since this function also matches +// qualified template names that are not part of a definition. For example: +// +//templateIntegral T, Floating_point U +// typename pairT, U::first_type void f(T, U); +// +// Here, it is unlikely that there is a partial specialization of +// pair constrained for for Integral and Floating_point arguments. +// +// The general rule is: if a constrained specialization with matching +// constraints is found return that type. 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 ville.voutilai...@gmail.com * 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 (%concept% cannot appear in a typedef declaration); + return error_mark_node; +} + if (constexpr_p typedef_p) { error (%constexpr% 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 %concept%); /* Function parameters cannot be constexpr. If we saw one, moan and pretend it wasn't there. */ - if (constexpr_p) + else if (constexpr_p) { error (a parameter cannot be declared %constexpr%); constexpr_p = 0; @@ -10619,6 +10628,11 @@ uqname, ctype); return error_mark_node; } +if (concept_p) + { +error (a destructor cannot be %concept%); +return error_mark_node; + } if (constexpr_p) { error (a destructor cannot be %constexpr%); @@ -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 %concept%); +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 %concept%, + 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 %concept%, + unqualified_id); +else if (constexpr_p) { error (non-static data member %qE declared %constexpr%, 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 %concept%, + 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' }
[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 andrew.n.sut...@gmail.com * 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
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 andrew.n.sut...@gmail.com * 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
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 andrew.n.sut...@gmail.com * 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
[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 andrew.n.sut...@gmail.com * 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] Shorthand notation
A small follow up change. This removes the sorry from concept name resolution. Committed in r203815. 2013-10-16 Andrew Sutton andrew.n.sut...@gmail.com * 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 andrew.n.sut...@gmail.com 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: templatetypename T, FunctionT 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: templateClass... Ts // ClassT() must be true for each T in Ts void f(); The transformation is: templatetypename... Ts requires ClassTs()... void f(); Where ClassTs()... expands to ClassT1() ClassT2() ... 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 andrew.n.sut...@gmail.com * 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 paolo.carl...@oracle.com 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 andrew.n.sut...@gmail.com * 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 andrew.n.sut...@gmail.com * 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] 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: templatetypename T, FunctionT 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: templateClass... Ts // ClassT() must be true for each T in Ts void f(); The transformation is: templatetypename... Ts requires ClassTs()... void f(); Where ClassTs()... expands to ClassT1() ClassT2() ... 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 andrew.n.sut...@gmail.com * 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] 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 ja...@redhat.com wrote: OK. If we have a friend declaration inside a constrained partial specialization, will that still get a false positive? Jason
[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 andrew.n.sut...@gmail.com * 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] 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 class T void f(); struct A { friend void fint(); // 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 templatetypename T struct X { friend void f(T x) requires CT; // 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] 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 andrew.n.sut...@gmail.com * 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
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 class T T f(T) requires Thing; template class T 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
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 andrew.n.sut...@gmail.com * 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
[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 andrew.n.sut...@gmail.com * 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 g...@axiomatics.org wrote: Andrew Sutton andrew.n.sut...@gmail.com 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 andrew.n.sut...@gmail.com | * 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
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 ja...@redhat.com 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