annotate gcc/cp/logic.cc @ 111:04ced10e8804

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