xref: /dflybsd-src/contrib/gcc-8.0/gcc/cp/logic.cc (revision 38fd149817dfbff97799f62fcb70be98c4e32523)
1*38fd1498Szrj /* Derivation and subsumption rules for constraints.
2*38fd1498Szrj    Copyright (C) 2013-2018 Free Software Foundation, Inc.
3*38fd1498Szrj    Contributed by Andrew Sutton (andrew.n.sutton@gmail.com)
4*38fd1498Szrj 
5*38fd1498Szrj This file is part of GCC.
6*38fd1498Szrj 
7*38fd1498Szrj GCC is free software; you can redistribute it and/or modify
8*38fd1498Szrj it under the terms of the GNU General Public License as published by
9*38fd1498Szrj the Free Software Foundation; either version 3, or (at your option)
10*38fd1498Szrj any later version.
11*38fd1498Szrj 
12*38fd1498Szrj GCC is distributed in the hope that it will be useful,
13*38fd1498Szrj but WITHOUT ANY WARRANTY; without even the implied warranty of
14*38fd1498Szrj MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15*38fd1498Szrj GNU General Public License for more details.
16*38fd1498Szrj 
17*38fd1498Szrj You should have received a copy of the GNU General Public License
18*38fd1498Szrj along with GCC; see the file COPYING3.  If not see
19*38fd1498Szrj <http://www.gnu.org/licenses/>.  */
20*38fd1498Szrj 
21*38fd1498Szrj #include "config.h"
22*38fd1498Szrj #define INCLUDE_LIST
23*38fd1498Szrj #include "system.h"
24*38fd1498Szrj #include "coretypes.h"
25*38fd1498Szrj #include "tm.h"
26*38fd1498Szrj #include "timevar.h"
27*38fd1498Szrj #include "hash-set.h"
28*38fd1498Szrj #include "machmode.h"
29*38fd1498Szrj #include "vec.h"
30*38fd1498Szrj #include "double-int.h"
31*38fd1498Szrj #include "input.h"
32*38fd1498Szrj #include "alias.h"
33*38fd1498Szrj #include "symtab.h"
34*38fd1498Szrj #include "wide-int.h"
35*38fd1498Szrj #include "inchash.h"
36*38fd1498Szrj #include "tree.h"
37*38fd1498Szrj #include "stringpool.h"
38*38fd1498Szrj #include "attribs.h"
39*38fd1498Szrj #include "intl.h"
40*38fd1498Szrj #include "flags.h"
41*38fd1498Szrj #include "cp-tree.h"
42*38fd1498Szrj #include "c-family/c-common.h"
43*38fd1498Szrj #include "c-family/c-objc.h"
44*38fd1498Szrj #include "cp-objcp-common.h"
45*38fd1498Szrj #include "tree-inline.h"
46*38fd1498Szrj #include "decl.h"
47*38fd1498Szrj #include "toplev.h"
48*38fd1498Szrj #include "type-utils.h"
49*38fd1498Szrj 
50*38fd1498Szrj namespace {
51*38fd1498Szrj 
52*38fd1498Szrj // Helper algorithms
53*38fd1498Szrj 
54*38fd1498Szrj template<typename I>
55*38fd1498Szrj inline I
next(I iter)56*38fd1498Szrj next (I iter)
57*38fd1498Szrj {
58*38fd1498Szrj   return ++iter;
59*38fd1498Szrj }
60*38fd1498Szrj 
61*38fd1498Szrj template<typename I, typename P>
62*38fd1498Szrj inline bool
any_p(I first,I last,P pred)63*38fd1498Szrj any_p (I first, I last, P pred)
64*38fd1498Szrj {
65*38fd1498Szrj   while (first != last)
66*38fd1498Szrj     {
67*38fd1498Szrj       if (pred(*first))
68*38fd1498Szrj         return true;
69*38fd1498Szrj       ++first;
70*38fd1498Szrj     }
71*38fd1498Szrj   return false;
72*38fd1498Szrj }
73*38fd1498Szrj 
74*38fd1498Szrj bool prove_implication (tree, tree);
75*38fd1498Szrj 
76*38fd1498Szrj /*---------------------------------------------------------------------------
77*38fd1498Szrj                            Proof state
78*38fd1498Szrj ---------------------------------------------------------------------------*/
79*38fd1498Szrj 
80*38fd1498Szrj struct term_entry
81*38fd1498Szrj {
82*38fd1498Szrj   tree t;
83*38fd1498Szrj };
84*38fd1498Szrj 
85*38fd1498Szrj /* Hashing function and equality for constraint entries.  */
86*38fd1498Szrj 
87*38fd1498Szrj struct term_hasher : ggc_ptr_hash<term_entry>
88*38fd1498Szrj {
hash__anon26caefdf0111::term_hasher89*38fd1498Szrj   static hashval_t hash (term_entry *e)
90*38fd1498Szrj   {
91*38fd1498Szrj     return iterative_hash_template_arg (e->t, 0);
92*38fd1498Szrj   }
93*38fd1498Szrj 
equal__anon26caefdf0111::term_hasher94*38fd1498Szrj   static bool equal (term_entry *e1, term_entry *e2)
95*38fd1498Szrj   {
96*38fd1498Szrj     return cp_tree_equal (e1->t, e2->t);
97*38fd1498Szrj   }
98*38fd1498Szrj };
99*38fd1498Szrj 
100*38fd1498Szrj /* A term list is a list of atomic constraints. It is used
101*38fd1498Szrj    to maintain the lists of assumptions and conclusions in a
102*38fd1498Szrj    proof goal.
103*38fd1498Szrj 
104*38fd1498Szrj    Each term list maintains an iterator that refers to the current
105*38fd1498Szrj    term. This can be used by various tactics to support iteration
106*38fd1498Szrj    and stateful manipulation of the list. */
107*38fd1498Szrj struct term_list
108*38fd1498Szrj {
109*38fd1498Szrj   typedef std::list<tree>::iterator iterator;
110*38fd1498Szrj 
111*38fd1498Szrj   term_list ();
112*38fd1498Szrj   term_list (tree);
113*38fd1498Szrj 
114*38fd1498Szrj   bool includes (tree);
115*38fd1498Szrj   iterator insert (iterator, tree);
116*38fd1498Szrj   iterator push_back (tree);
117*38fd1498Szrj   iterator erase (iterator);
118*38fd1498Szrj   iterator replace (iterator, tree);
119*38fd1498Szrj   iterator replace (iterator, tree, tree);
120*38fd1498Szrj 
begin__anon26caefdf0111::term_list121*38fd1498Szrj   iterator begin() { return seq.begin(); }
end__anon26caefdf0111::term_list122*38fd1498Szrj   iterator end() { return seq.end(); }
123*38fd1498Szrj 
124*38fd1498Szrj   std::list<tree>         seq;
125*38fd1498Szrj   hash_table<term_hasher> tab;
126*38fd1498Szrj };
127*38fd1498Szrj 
128*38fd1498Szrj inline
term_list()129*38fd1498Szrj term_list::term_list ()
130*38fd1498Szrj   : seq(), tab (11)
131*38fd1498Szrj {
132*38fd1498Szrj }
133*38fd1498Szrj 
134*38fd1498Szrj /* Initialize a term list with an initial term. */
135*38fd1498Szrj 
136*38fd1498Szrj inline
term_list(tree t)137*38fd1498Szrj term_list::term_list (tree t)
138*38fd1498Szrj   : seq (), tab (11)
139*38fd1498Szrj {
140*38fd1498Szrj   push_back (t);
141*38fd1498Szrj }
142*38fd1498Szrj 
143*38fd1498Szrj /* Returns true if T is the in the tree. */
144*38fd1498Szrj 
145*38fd1498Szrj inline bool
includes(tree t)146*38fd1498Szrj term_list::includes (tree t)
147*38fd1498Szrj {
148*38fd1498Szrj   term_entry ent = {t};
149*38fd1498Szrj   return tab.find (&ent);
150*38fd1498Szrj }
151*38fd1498Szrj 
152*38fd1498Szrj /* Append a term to the list. */
153*38fd1498Szrj inline term_list::iterator
push_back(tree t)154*38fd1498Szrj term_list::push_back (tree t)
155*38fd1498Szrj {
156*38fd1498Szrj   return insert (end(), t);
157*38fd1498Szrj }
158*38fd1498Szrj 
159*38fd1498Szrj /* Insert a new (unseen) term T into the list before the proposition
160*38fd1498Szrj    indicated by ITER. Returns the iterator to the newly inserted
161*38fd1498Szrj    element.  */
162*38fd1498Szrj 
163*38fd1498Szrj term_list::iterator
insert(iterator iter,tree t)164*38fd1498Szrj term_list::insert (iterator iter, tree t)
165*38fd1498Szrj {
166*38fd1498Szrj   gcc_assert (!includes (t));
167*38fd1498Szrj   iter = seq.insert (iter, t);
168*38fd1498Szrj   term_entry ent = {t};
169*38fd1498Szrj   term_entry** slot = tab.find_slot (&ent, INSERT);
170*38fd1498Szrj   term_entry* ptr = ggc_alloc<term_entry> ();
171*38fd1498Szrj   *ptr = ent;
172*38fd1498Szrj   *slot = ptr;
173*38fd1498Szrj   return iter;
174*38fd1498Szrj }
175*38fd1498Szrj 
176*38fd1498Szrj /* Remove an existing term from the list. Returns an iterator referring
177*38fd1498Szrj    to the element after the removed term.  This may be end().  */
178*38fd1498Szrj 
179*38fd1498Szrj term_list::iterator
erase(iterator iter)180*38fd1498Szrj term_list::erase (iterator iter)
181*38fd1498Szrj {
182*38fd1498Szrj   gcc_assert (includes (*iter));
183*38fd1498Szrj   term_entry ent = {*iter};
184*38fd1498Szrj   tab.remove_elt (&ent);
185*38fd1498Szrj   iter = seq.erase (iter);
186*38fd1498Szrj   return iter;
187*38fd1498Szrj }
188*38fd1498Szrj 
189*38fd1498Szrj /* Replace the given term with that specified. If the term has
190*38fd1498Szrj    been previously seen, do not insert the term. Returns the
191*38fd1498Szrj    first iterator past the current term.  */
192*38fd1498Szrj 
193*38fd1498Szrj term_list::iterator
replace(iterator iter,tree t)194*38fd1498Szrj term_list::replace (iterator iter, tree t)
195*38fd1498Szrj {
196*38fd1498Szrj   iter = erase (iter);
197*38fd1498Szrj   if (!includes (t))
198*38fd1498Szrj     insert (iter, t);
199*38fd1498Szrj   return iter;
200*38fd1498Szrj }
201*38fd1498Szrj 
202*38fd1498Szrj 
203*38fd1498Szrj /* Replace the term at the given position by the supplied T1
204*38fd1498Szrj    followed by t2. This is used in certain logical operators to
205*38fd1498Szrj    load a list of assumptions or conclusions.  */
206*38fd1498Szrj 
207*38fd1498Szrj term_list::iterator
replace(iterator iter,tree t1,tree t2)208*38fd1498Szrj term_list::replace (iterator iter, tree t1, tree t2)
209*38fd1498Szrj {
210*38fd1498Szrj   iter = erase (iter);
211*38fd1498Szrj   if (!includes (t1))
212*38fd1498Szrj     insert (iter, t1);
213*38fd1498Szrj   if (!includes (t2))
214*38fd1498Szrj     insert (iter, t2);
215*38fd1498Szrj   return iter;
216*38fd1498Szrj }
217*38fd1498Szrj 
218*38fd1498Szrj /* A goal (or subgoal) models a sequent of the form
219*38fd1498Szrj    'A |- C' where A and C are lists of assumptions and
220*38fd1498Szrj    conclusions written as propositions in the constraint
221*38fd1498Szrj    language (i.e., lists of trees). */
222*38fd1498Szrj 
223*38fd1498Szrj struct proof_goal
224*38fd1498Szrj {
225*38fd1498Szrj   term_list assumptions;
226*38fd1498Szrj   term_list conclusions;
227*38fd1498Szrj };
228*38fd1498Szrj 
229*38fd1498Szrj /* A proof state owns a list of goals and tracks the
230*38fd1498Szrj    current sub-goal. The class also provides facilities
231*38fd1498Szrj    for managing subgoals and constructing term lists. */
232*38fd1498Szrj 
233*38fd1498Szrj struct proof_state : std::list<proof_goal>
234*38fd1498Szrj {
235*38fd1498Szrj   proof_state ();
236*38fd1498Szrj 
237*38fd1498Szrj   iterator branch (iterator i);
238*38fd1498Szrj   iterator discharge (iterator i);
239*38fd1498Szrj };
240*38fd1498Szrj 
241*38fd1498Szrj /* Initialize the state with a single empty goal, and set that goal
242*38fd1498Szrj    as the current subgoal.  */
243*38fd1498Szrj 
244*38fd1498Szrj inline
proof_state()245*38fd1498Szrj proof_state::proof_state ()
246*38fd1498Szrj   : std::list<proof_goal> (1)
247*38fd1498Szrj { }
248*38fd1498Szrj 
249*38fd1498Szrj 
250*38fd1498Szrj /* Branch the current goal by creating a new subgoal, returning a
251*38fd1498Szrj    reference to the new object. This does not update the current goal. */
252*38fd1498Szrj 
253*38fd1498Szrj inline proof_state::iterator
branch(iterator i)254*38fd1498Szrj proof_state::branch (iterator i)
255*38fd1498Szrj {
256*38fd1498Szrj   gcc_assert (i != end());
257*38fd1498Szrj   proof_goal& g = *i;
258*38fd1498Szrj   return insert (++i, g);
259*38fd1498Szrj }
260*38fd1498Szrj 
261*38fd1498Szrj /* Discharge the current goal, setting it equal to the
262*38fd1498Szrj    next non-satisfied goal. */
263*38fd1498Szrj 
264*38fd1498Szrj inline proof_state::iterator
discharge(iterator i)265*38fd1498Szrj proof_state::discharge (iterator i)
266*38fd1498Szrj {
267*38fd1498Szrj   gcc_assert (i != end());
268*38fd1498Szrj   return erase (i);
269*38fd1498Szrj }
270*38fd1498Szrj 
271*38fd1498Szrj 
272*38fd1498Szrj /*---------------------------------------------------------------------------
273*38fd1498Szrj                         Debugging
274*38fd1498Szrj ---------------------------------------------------------------------------*/
275*38fd1498Szrj 
276*38fd1498Szrj // void
277*38fd1498Szrj // debug (term_list& ts)
278*38fd1498Szrj // {
279*38fd1498Szrj //   for (term_list::iterator i = ts.begin(); i != ts.end(); ++i)
280*38fd1498Szrj //     verbatim ("  # %E", *i);
281*38fd1498Szrj // }
282*38fd1498Szrj //
283*38fd1498Szrj // void
284*38fd1498Szrj // debug (proof_goal& g)
285*38fd1498Szrj // {
286*38fd1498Szrj //   debug (g.assumptions);
287*38fd1498Szrj //   verbatim ("       |-");
288*38fd1498Szrj //   debug (g.conclusions);
289*38fd1498Szrj // }
290*38fd1498Szrj 
291*38fd1498Szrj /*---------------------------------------------------------------------------
292*38fd1498Szrj                         Atomicity of constraints
293*38fd1498Szrj ---------------------------------------------------------------------------*/
294*38fd1498Szrj 
295*38fd1498Szrj /* Returns true if T is not an atomic constraint.  */
296*38fd1498Szrj 
297*38fd1498Szrj bool
non_atomic_constraint_p(tree t)298*38fd1498Szrj non_atomic_constraint_p (tree t)
299*38fd1498Szrj {
300*38fd1498Szrj   switch (TREE_CODE (t))
301*38fd1498Szrj     {
302*38fd1498Szrj     case PRED_CONSTR:
303*38fd1498Szrj     case EXPR_CONSTR:
304*38fd1498Szrj     case TYPE_CONSTR:
305*38fd1498Szrj     case ICONV_CONSTR:
306*38fd1498Szrj     case DEDUCT_CONSTR:
307*38fd1498Szrj     case EXCEPT_CONSTR:
308*38fd1498Szrj       /* A pack expansion isn't atomic, but it can't decompose to prove an
309*38fd1498Szrj 	 atom, so it shouldn't cause analyze_atom to return undecided.  */
310*38fd1498Szrj     case EXPR_PACK_EXPANSION:
311*38fd1498Szrj       return false;
312*38fd1498Szrj     case CHECK_CONSTR:
313*38fd1498Szrj     case PARM_CONSTR:
314*38fd1498Szrj     case CONJ_CONSTR:
315*38fd1498Szrj     case DISJ_CONSTR:
316*38fd1498Szrj       return true;
317*38fd1498Szrj     default:
318*38fd1498Szrj       gcc_unreachable ();
319*38fd1498Szrj     }
320*38fd1498Szrj }
321*38fd1498Szrj 
322*38fd1498Szrj /* Returns true if any constraints in T are not atomic.  */
323*38fd1498Szrj 
324*38fd1498Szrj bool
any_non_atomic_constraints_p(term_list & t)325*38fd1498Szrj any_non_atomic_constraints_p (term_list& t)
326*38fd1498Szrj {
327*38fd1498Szrj   return any_p (t.begin(), t.end(), non_atomic_constraint_p);
328*38fd1498Szrj }
329*38fd1498Szrj 
330*38fd1498Szrj /*---------------------------------------------------------------------------
331*38fd1498Szrj                            Proof validations
332*38fd1498Szrj ---------------------------------------------------------------------------*/
333*38fd1498Szrj 
334*38fd1498Szrj enum proof_result
335*38fd1498Szrj {
336*38fd1498Szrj   invalid,
337*38fd1498Szrj   valid,
338*38fd1498Szrj   undecided
339*38fd1498Szrj };
340*38fd1498Szrj 
341*38fd1498Szrj proof_result check_term (term_list&, tree);
342*38fd1498Szrj 
343*38fd1498Szrj 
344*38fd1498Szrj proof_result
analyze_atom(term_list & ts,tree t)345*38fd1498Szrj analyze_atom (term_list& ts, tree t)
346*38fd1498Szrj {
347*38fd1498Szrj   /* FIXME: Hook into special cases, if any. */
348*38fd1498Szrj   /*
349*38fd1498Szrj   term_list::iterator iter = ts.begin();
350*38fd1498Szrj   term_list::iterator end = ts.end();
351*38fd1498Szrj   while (iter != end)
352*38fd1498Szrj     {
353*38fd1498Szrj       ++iter;
354*38fd1498Szrj     }
355*38fd1498Szrj   */
356*38fd1498Szrj 
357*38fd1498Szrj   if (non_atomic_constraint_p (t))
358*38fd1498Szrj     return undecided;
359*38fd1498Szrj   if (any_non_atomic_constraints_p (ts))
360*38fd1498Szrj     return undecided;
361*38fd1498Szrj   return invalid;
362*38fd1498Szrj }
363*38fd1498Szrj 
364*38fd1498Szrj /* Search for a pack expansion in the list of assumptions that would
365*38fd1498Szrj    make this expansion valid.  */
366*38fd1498Szrj 
367*38fd1498Szrj proof_result
analyze_pack(term_list & ts,tree t)368*38fd1498Szrj analyze_pack (term_list& ts, tree t)
369*38fd1498Szrj {
370*38fd1498Szrj   tree c1 = normalize_expression (PACK_EXPANSION_PATTERN (t));
371*38fd1498Szrj   term_list::iterator iter = ts.begin();
372*38fd1498Szrj   term_list::iterator end = ts.end();
373*38fd1498Szrj   while (iter != end)
374*38fd1498Szrj     {
375*38fd1498Szrj       if (TREE_CODE (*iter) == TREE_CODE (t))
376*38fd1498Szrj         {
377*38fd1498Szrj           tree c2 = normalize_expression (PACK_EXPANSION_PATTERN (*iter));
378*38fd1498Szrj           if (prove_implication (c2, c1))
379*38fd1498Szrj             return valid;
380*38fd1498Szrj           else
381*38fd1498Szrj             return invalid;
382*38fd1498Szrj         }
383*38fd1498Szrj       ++iter;
384*38fd1498Szrj     }
385*38fd1498Szrj   return invalid;
386*38fd1498Szrj }
387*38fd1498Szrj 
388*38fd1498Szrj /* Search for concept checks in TS that we know subsume T. */
389*38fd1498Szrj 
390*38fd1498Szrj proof_result
search_known_subsumptions(term_list & ts,tree t)391*38fd1498Szrj search_known_subsumptions (term_list& ts, tree t)
392*38fd1498Szrj {
393*38fd1498Szrj   for (term_list::iterator i = ts.begin(); i != ts.end(); ++i)
394*38fd1498Szrj     if (TREE_CODE (*i) == CHECK_CONSTR)
395*38fd1498Szrj       {
396*38fd1498Szrj         if (bool* b = lookup_subsumption_result (*i, t))
397*38fd1498Szrj           return *b ? valid : invalid;
398*38fd1498Szrj       }
399*38fd1498Szrj   return undecided;
400*38fd1498Szrj }
401*38fd1498Szrj 
402*38fd1498Szrj /* Determine if the terms in TS provide sufficient support for proving
403*38fd1498Szrj    the proposition T. If any term in TS is a concept check that is known
404*38fd1498Szrj    to subsume T, then the proof is valid. Otherwise, we have to expand T
405*38fd1498Szrj    and continue searching for support.  */
406*38fd1498Szrj 
407*38fd1498Szrj proof_result
analyze_check(term_list & ts,tree t)408*38fd1498Szrj analyze_check (term_list& ts, tree t)
409*38fd1498Szrj {
410*38fd1498Szrj   proof_result r = search_known_subsumptions (ts, t);
411*38fd1498Szrj   if (r != undecided)
412*38fd1498Szrj     return r;
413*38fd1498Szrj 
414*38fd1498Szrj   tree tmpl = CHECK_CONSTR_CONCEPT (t);
415*38fd1498Szrj   tree args = CHECK_CONSTR_ARGS (t);
416*38fd1498Szrj   tree c = expand_concept (tmpl, args);
417*38fd1498Szrj   return check_term (ts, c);
418*38fd1498Szrj }
419*38fd1498Szrj 
420*38fd1498Szrj /* Recursively check constraints of the parameterized constraint. */
421*38fd1498Szrj 
422*38fd1498Szrj proof_result
analyze_parameterized(term_list & ts,tree t)423*38fd1498Szrj analyze_parameterized (term_list& ts, tree t)
424*38fd1498Szrj {
425*38fd1498Szrj   return check_term (ts, PARM_CONSTR_OPERAND (t));
426*38fd1498Szrj }
427*38fd1498Szrj 
428*38fd1498Szrj proof_result
analyze_conjunction(term_list & ts,tree t)429*38fd1498Szrj analyze_conjunction (term_list& ts, tree t)
430*38fd1498Szrj {
431*38fd1498Szrj   proof_result r = check_term (ts, TREE_OPERAND (t, 0));
432*38fd1498Szrj   if (r == invalid || r == undecided)
433*38fd1498Szrj     return r;
434*38fd1498Szrj   return check_term (ts, TREE_OPERAND (t, 1));
435*38fd1498Szrj }
436*38fd1498Szrj 
437*38fd1498Szrj proof_result
analyze_disjunction(term_list & ts,tree t)438*38fd1498Szrj analyze_disjunction (term_list& ts, tree t)
439*38fd1498Szrj {
440*38fd1498Szrj   proof_result r = check_term (ts, TREE_OPERAND (t, 0));
441*38fd1498Szrj   if (r == valid)
442*38fd1498Szrj     return r;
443*38fd1498Szrj   return check_term (ts, TREE_OPERAND (t, 1));
444*38fd1498Szrj }
445*38fd1498Szrj 
446*38fd1498Szrj proof_result
analyze_term(term_list & ts,tree t)447*38fd1498Szrj analyze_term (term_list& ts, tree t)
448*38fd1498Szrj {
449*38fd1498Szrj   switch (TREE_CODE (t))
450*38fd1498Szrj     {
451*38fd1498Szrj     case CHECK_CONSTR:
452*38fd1498Szrj       return analyze_check (ts, t);
453*38fd1498Szrj 
454*38fd1498Szrj     case PARM_CONSTR:
455*38fd1498Szrj       return analyze_parameterized (ts, t);
456*38fd1498Szrj 
457*38fd1498Szrj     case CONJ_CONSTR:
458*38fd1498Szrj       return analyze_conjunction (ts, t);
459*38fd1498Szrj     case DISJ_CONSTR:
460*38fd1498Szrj       return analyze_disjunction (ts, t);
461*38fd1498Szrj 
462*38fd1498Szrj     case PRED_CONSTR:
463*38fd1498Szrj     case EXPR_CONSTR:
464*38fd1498Szrj     case TYPE_CONSTR:
465*38fd1498Szrj     case ICONV_CONSTR:
466*38fd1498Szrj     case DEDUCT_CONSTR:
467*38fd1498Szrj     case EXCEPT_CONSTR:
468*38fd1498Szrj       return analyze_atom (ts, t);
469*38fd1498Szrj 
470*38fd1498Szrj     case EXPR_PACK_EXPANSION:
471*38fd1498Szrj       return analyze_pack (ts, t);
472*38fd1498Szrj 
473*38fd1498Szrj     case ERROR_MARK:
474*38fd1498Szrj       /* Encountering an error anywhere in a constraint invalidates
475*38fd1498Szrj          the proof, since the constraint is ill-formed.  */
476*38fd1498Szrj       return invalid;
477*38fd1498Szrj     default:
478*38fd1498Szrj       gcc_unreachable ();
479*38fd1498Szrj     }
480*38fd1498Szrj }
481*38fd1498Szrj 
482*38fd1498Szrj /* Check if a single term can be proven from a set of assumptions.
483*38fd1498Szrj    If the proof is not valid, then it is incomplete when either
484*38fd1498Szrj    the given term is non-atomic or any term in the list of assumptions
485*38fd1498Szrj    is not-atomic.  */
486*38fd1498Szrj 
487*38fd1498Szrj proof_result
check_term(term_list & ts,tree t)488*38fd1498Szrj check_term (term_list& ts, tree t)
489*38fd1498Szrj {
490*38fd1498Szrj   /* Try the easy way; search for an equivalent term.  */
491*38fd1498Szrj   if (ts.includes (t))
492*38fd1498Szrj     return valid;
493*38fd1498Szrj 
494*38fd1498Szrj   /* The hard way; actually consider what the term means.  */
495*38fd1498Szrj   return analyze_term (ts, t);
496*38fd1498Szrj }
497*38fd1498Szrj 
498*38fd1498Szrj /* Check to see if any term is proven by the assumptions in the
499*38fd1498Szrj    proof goal. The proof is valid if the proof of any term is valid.
500*38fd1498Szrj    If validity cannot be determined, but any particular
501*38fd1498Szrj    check was undecided, then this goal is undecided.  */
502*38fd1498Szrj 
503*38fd1498Szrj proof_result
check_goal(proof_goal & g)504*38fd1498Szrj check_goal (proof_goal& g)
505*38fd1498Szrj {
506*38fd1498Szrj   term_list::iterator iter = g.conclusions.begin ();
507*38fd1498Szrj   term_list::iterator end = g.conclusions.end ();
508*38fd1498Szrj   bool incomplete = false;
509*38fd1498Szrj   while (iter != end)
510*38fd1498Szrj     {
511*38fd1498Szrj       proof_result r = check_term (g.assumptions, *iter);
512*38fd1498Szrj       if (r == valid)
513*38fd1498Szrj         return r;
514*38fd1498Szrj       if (r == undecided)
515*38fd1498Szrj         incomplete = true;
516*38fd1498Szrj       ++iter;
517*38fd1498Szrj     }
518*38fd1498Szrj 
519*38fd1498Szrj     /* Was the proof complete? */
520*38fd1498Szrj     if (incomplete)
521*38fd1498Szrj       return undecided;
522*38fd1498Szrj     else
523*38fd1498Szrj       return invalid;
524*38fd1498Szrj }
525*38fd1498Szrj 
526*38fd1498Szrj /* Check if the the proof is valid. This is the case when all
527*38fd1498Szrj    goals can be discharged. If any goal is invalid, then the
528*38fd1498Szrj    entire proof is invalid. Otherwise, the proof is undecided.  */
529*38fd1498Szrj 
530*38fd1498Szrj proof_result
check_proof(proof_state & p)531*38fd1498Szrj check_proof (proof_state& p)
532*38fd1498Szrj {
533*38fd1498Szrj   proof_state::iterator iter = p.begin();
534*38fd1498Szrj   proof_state::iterator end = p.end();
535*38fd1498Szrj   while (iter != end)
536*38fd1498Szrj     {
537*38fd1498Szrj       proof_result r = check_goal (*iter);
538*38fd1498Szrj       if (r == invalid)
539*38fd1498Szrj         return r;
540*38fd1498Szrj       if (r == valid)
541*38fd1498Szrj         iter = p.discharge (iter);
542*38fd1498Szrj       else
543*38fd1498Szrj         ++iter;
544*38fd1498Szrj     }
545*38fd1498Szrj 
546*38fd1498Szrj   /* If all goals are discharged, then the proof is valid.  */
547*38fd1498Szrj   if (p.empty())
548*38fd1498Szrj     return valid;
549*38fd1498Szrj   else
550*38fd1498Szrj     return undecided;
551*38fd1498Szrj }
552*38fd1498Szrj 
553*38fd1498Szrj /*---------------------------------------------------------------------------
554*38fd1498Szrj                            Left logical rules
555*38fd1498Szrj ---------------------------------------------------------------------------*/
556*38fd1498Szrj 
557*38fd1498Szrj term_list::iterator
load_check_assumption(term_list & ts,term_list::iterator i)558*38fd1498Szrj load_check_assumption (term_list& ts, term_list::iterator i)
559*38fd1498Szrj {
560*38fd1498Szrj   tree decl = CHECK_CONSTR_CONCEPT (*i);
561*38fd1498Szrj   tree tmpl = DECL_TI_TEMPLATE (decl);
562*38fd1498Szrj   tree args = CHECK_CONSTR_ARGS (*i);
563*38fd1498Szrj   return ts.replace(i, expand_concept (tmpl, args));
564*38fd1498Szrj }
565*38fd1498Szrj 
566*38fd1498Szrj term_list::iterator
load_parameterized_assumption(term_list & ts,term_list::iterator i)567*38fd1498Szrj load_parameterized_assumption (term_list& ts, term_list::iterator i)
568*38fd1498Szrj {
569*38fd1498Szrj   return ts.replace(i, PARM_CONSTR_OPERAND(*i));
570*38fd1498Szrj }
571*38fd1498Szrj 
572*38fd1498Szrj term_list::iterator
load_conjunction_assumption(term_list & ts,term_list::iterator i)573*38fd1498Szrj load_conjunction_assumption (term_list& ts, term_list::iterator i)
574*38fd1498Szrj {
575*38fd1498Szrj   tree t1 = TREE_OPERAND (*i, 0);
576*38fd1498Szrj   tree t2 = TREE_OPERAND (*i, 1);
577*38fd1498Szrj   return ts.replace(i, t1, t2);
578*38fd1498Szrj }
579*38fd1498Szrj 
580*38fd1498Szrj /* Examine the terms in the list, and apply left-logical rules to move
581*38fd1498Szrj    terms into the set of assumptions. */
582*38fd1498Szrj 
583*38fd1498Szrj void
load_assumptions(proof_goal & g)584*38fd1498Szrj load_assumptions (proof_goal& g)
585*38fd1498Szrj {
586*38fd1498Szrj   term_list::iterator iter = g.assumptions.begin();
587*38fd1498Szrj   term_list::iterator end = g.assumptions.end();
588*38fd1498Szrj   while (iter != end)
589*38fd1498Szrj     {
590*38fd1498Szrj       switch (TREE_CODE (*iter))
591*38fd1498Szrj         {
592*38fd1498Szrj         case CHECK_CONSTR:
593*38fd1498Szrj           iter = load_check_assumption (g.assumptions, iter);
594*38fd1498Szrj           break;
595*38fd1498Szrj         case PARM_CONSTR:
596*38fd1498Szrj           iter = load_parameterized_assumption (g.assumptions, iter);
597*38fd1498Szrj           break;
598*38fd1498Szrj         case CONJ_CONSTR:
599*38fd1498Szrj           iter = load_conjunction_assumption (g.assumptions, iter);
600*38fd1498Szrj           break;
601*38fd1498Szrj         default:
602*38fd1498Szrj           ++iter;
603*38fd1498Szrj           break;
604*38fd1498Szrj         }
605*38fd1498Szrj     }
606*38fd1498Szrj }
607*38fd1498Szrj 
608*38fd1498Szrj /* In each subgoal, load constraints into the assumption set.  */
609*38fd1498Szrj 
610*38fd1498Szrj void
load_assumptions(proof_state & p)611*38fd1498Szrj load_assumptions(proof_state& p)
612*38fd1498Szrj {
613*38fd1498Szrj   proof_state::iterator iter = p.begin();
614*38fd1498Szrj   while (iter != p.end())
615*38fd1498Szrj     {
616*38fd1498Szrj       load_assumptions (*iter);
617*38fd1498Szrj       ++iter;
618*38fd1498Szrj     }
619*38fd1498Szrj }
620*38fd1498Szrj 
621*38fd1498Szrj void
explode_disjunction(proof_state & p,proof_state::iterator gi,term_list::iterator ti1)622*38fd1498Szrj explode_disjunction (proof_state& p, proof_state::iterator gi, term_list::iterator ti1)
623*38fd1498Szrj {
624*38fd1498Szrj   tree t1 = TREE_OPERAND (*ti1, 0);
625*38fd1498Szrj   tree t2 = TREE_OPERAND (*ti1, 1);
626*38fd1498Szrj 
627*38fd1498Szrj   /* Erase the current term from the goal. */
628*38fd1498Szrj   proof_goal& g1 = *gi;
629*38fd1498Szrj   proof_goal& g2 = *p.branch (gi);
630*38fd1498Szrj 
631*38fd1498Szrj   /* Get an iterator to the equivalent position in th enew goal. */
632*38fd1498Szrj   int n = std::distance (g1.assumptions.begin (), ti1);
633*38fd1498Szrj   term_list::iterator ti2 = g2.assumptions.begin ();
634*38fd1498Szrj   std::advance (ti2, n);
635*38fd1498Szrj 
636*38fd1498Szrj   /* Replace the disjunction in both branches. */
637*38fd1498Szrj   g1.assumptions.replace (ti1, t1);
638*38fd1498Szrj   g2.assumptions.replace (ti2, t2);
639*38fd1498Szrj }
640*38fd1498Szrj 
641*38fd1498Szrj 
642*38fd1498Szrj /* Search the assumptions of the goal for the first disjunction. */
643*38fd1498Szrj 
644*38fd1498Szrj bool
explode_goal(proof_state & p,proof_state::iterator gi)645*38fd1498Szrj explode_goal (proof_state& p, proof_state::iterator gi)
646*38fd1498Szrj {
647*38fd1498Szrj   term_list& ts = gi->assumptions;
648*38fd1498Szrj   term_list::iterator ti = ts.begin();
649*38fd1498Szrj   term_list::iterator end = ts.end();
650*38fd1498Szrj   while (ti != end)
651*38fd1498Szrj     {
652*38fd1498Szrj       if (TREE_CODE (*ti) == DISJ_CONSTR)
653*38fd1498Szrj         {
654*38fd1498Szrj           explode_disjunction (p, gi, ti);
655*38fd1498Szrj           return true;
656*38fd1498Szrj         }
657*38fd1498Szrj       else ++ti;
658*38fd1498Szrj     }
659*38fd1498Szrj   return false;
660*38fd1498Szrj }
661*38fd1498Szrj 
662*38fd1498Szrj /* Search for the first goal with a disjunction, and then branch
663*38fd1498Szrj    creating a clone of that subgoal. */
664*38fd1498Szrj 
665*38fd1498Szrj void
explode_assumptions(proof_state & p)666*38fd1498Szrj explode_assumptions (proof_state& p)
667*38fd1498Szrj {
668*38fd1498Szrj   proof_state::iterator iter = p.begin();
669*38fd1498Szrj   proof_state::iterator end = p.end();
670*38fd1498Szrj   while (iter != end)
671*38fd1498Szrj     {
672*38fd1498Szrj       if (explode_goal (p, iter))
673*38fd1498Szrj         return;
674*38fd1498Szrj       ++iter;
675*38fd1498Szrj     }
676*38fd1498Szrj }
677*38fd1498Szrj 
678*38fd1498Szrj 
679*38fd1498Szrj /*---------------------------------------------------------------------------
680*38fd1498Szrj                            Right logical rules
681*38fd1498Szrj ---------------------------------------------------------------------------*/
682*38fd1498Szrj 
683*38fd1498Szrj term_list::iterator
load_disjunction_conclusion(term_list & g,term_list::iterator i)684*38fd1498Szrj load_disjunction_conclusion (term_list& g, term_list::iterator i)
685*38fd1498Szrj {
686*38fd1498Szrj   tree t1 = TREE_OPERAND (*i, 0);
687*38fd1498Szrj   tree t2 = TREE_OPERAND (*i, 1);
688*38fd1498Szrj   return g.replace(i, t1, t2);
689*38fd1498Szrj }
690*38fd1498Szrj 
691*38fd1498Szrj /* Apply logical rules to the right hand side. This will load the
692*38fd1498Szrj    conclusion set with all tpp-level disjunctions.  */
693*38fd1498Szrj 
694*38fd1498Szrj void
load_conclusions(proof_goal & g)695*38fd1498Szrj load_conclusions (proof_goal& g)
696*38fd1498Szrj {
697*38fd1498Szrj   term_list::iterator iter = g.conclusions.begin();
698*38fd1498Szrj   term_list::iterator end = g.conclusions.end();
699*38fd1498Szrj   while (iter != end)
700*38fd1498Szrj     {
701*38fd1498Szrj       if (TREE_CODE (*iter) == DISJ_CONSTR)
702*38fd1498Szrj         iter = load_disjunction_conclusion (g.conclusions, iter);
703*38fd1498Szrj       else
704*38fd1498Szrj         ++iter;
705*38fd1498Szrj     }
706*38fd1498Szrj }
707*38fd1498Szrj 
708*38fd1498Szrj void
load_conclusions(proof_state & p)709*38fd1498Szrj load_conclusions (proof_state& p)
710*38fd1498Szrj {
711*38fd1498Szrj   proof_state::iterator iter = p.begin();
712*38fd1498Szrj   while (iter != p.end())
713*38fd1498Szrj     {
714*38fd1498Szrj       load_conclusions (*iter);
715*38fd1498Szrj       ++iter;
716*38fd1498Szrj     }
717*38fd1498Szrj }
718*38fd1498Szrj 
719*38fd1498Szrj 
720*38fd1498Szrj /*---------------------------------------------------------------------------
721*38fd1498Szrj                           High-level proof tactics
722*38fd1498Szrj ---------------------------------------------------------------------------*/
723*38fd1498Szrj 
724*38fd1498Szrj /* Given two constraints A and C, try to derive a proof that
725*38fd1498Szrj    A implies C.  */
726*38fd1498Szrj 
727*38fd1498Szrj bool
prove_implication(tree a,tree c)728*38fd1498Szrj prove_implication (tree a, tree c)
729*38fd1498Szrj {
730*38fd1498Szrj   /* Quick accept. */
731*38fd1498Szrj   if (cp_tree_equal (a, c))
732*38fd1498Szrj     return true;
733*38fd1498Szrj 
734*38fd1498Szrj   /* Build the initial proof state. */
735*38fd1498Szrj   proof_state proof;
736*38fd1498Szrj   proof_goal& goal = proof.front();
737*38fd1498Szrj   goal.assumptions.push_back(a);
738*38fd1498Szrj   goal.conclusions.push_back(c);
739*38fd1498Szrj 
740*38fd1498Szrj   /* Perform an initial right-expansion in the off-chance that the right
741*38fd1498Szrj      hand side contains disjunctions. */
742*38fd1498Szrj   load_conclusions (proof);
743*38fd1498Szrj 
744*38fd1498Szrj   int step_max = 1 << 10;
745*38fd1498Szrj   int step_count = 0;              /* FIXME: We shouldn't have this. */
746*38fd1498Szrj   std::size_t branch_limit = 1024; /* FIXME: This needs to be configurable. */
747*38fd1498Szrj   while (step_count < step_max && proof.size() < branch_limit)
748*38fd1498Szrj     {
749*38fd1498Szrj       /* Determine if we can prove that the assumptions entail the
750*38fd1498Szrj          conclusions. If so, we're done. */
751*38fd1498Szrj       load_assumptions (proof);
752*38fd1498Szrj 
753*38fd1498Szrj       /* Can we solve the proof based on this? */
754*38fd1498Szrj       proof_result r = check_proof (proof);
755*38fd1498Szrj       if (r != undecided)
756*38fd1498Szrj         return r == valid;
757*38fd1498Szrj 
758*38fd1498Szrj       /* If not, then we need to dig into disjunctions.  */
759*38fd1498Szrj       explode_assumptions (proof);
760*38fd1498Szrj 
761*38fd1498Szrj       ++step_count;
762*38fd1498Szrj     }
763*38fd1498Szrj 
764*38fd1498Szrj   if (step_count == step_max)
765*38fd1498Szrj     error ("subsumption failed to resolve");
766*38fd1498Szrj 
767*38fd1498Szrj   if (proof.size() == branch_limit)
768*38fd1498Szrj     error ("exceeded maximum number of branches");
769*38fd1498Szrj 
770*38fd1498Szrj   return false;
771*38fd1498Szrj }
772*38fd1498Szrj 
773*38fd1498Szrj /* Returns true if the LEFT constraint subsume the RIGHT constraints.
774*38fd1498Szrj    This is done by deriving a proof of the conclusions on the RIGHT
775*38fd1498Szrj    from the assumptions on the LEFT assumptions.  */
776*38fd1498Szrj 
777*38fd1498Szrj bool
subsumes_constraints_nonnull(tree left,tree right)778*38fd1498Szrj subsumes_constraints_nonnull (tree left, tree right)
779*38fd1498Szrj {
780*38fd1498Szrj   gcc_assert (check_constraint_info (left));
781*38fd1498Szrj   gcc_assert (check_constraint_info (right));
782*38fd1498Szrj 
783*38fd1498Szrj   auto_timevar time (TV_CONSTRAINT_SUB);
784*38fd1498Szrj   tree a = CI_ASSOCIATED_CONSTRAINTS (left);
785*38fd1498Szrj   tree c = CI_ASSOCIATED_CONSTRAINTS (right);
786*38fd1498Szrj   return prove_implication (a, c);
787*38fd1498Szrj }
788*38fd1498Szrj 
789*38fd1498Szrj } /* namespace */
790*38fd1498Szrj 
791*38fd1498Szrj /* Returns true if the LEFT constraints subsume the RIGHT
792*38fd1498Szrj    constraints.  */
793*38fd1498Szrj 
794*38fd1498Szrj bool
subsumes(tree left,tree right)795*38fd1498Szrj subsumes (tree left, tree right)
796*38fd1498Szrj {
797*38fd1498Szrj   if (left == right)
798*38fd1498Szrj     return true;
799*38fd1498Szrj   if (!left)
800*38fd1498Szrj     return false;
801*38fd1498Szrj   if (!right)
802*38fd1498Szrj     return true;
803*38fd1498Szrj   return subsumes_constraints_nonnull (left, right);
804*38fd1498Szrj }
805