 |
|
 |
|
| Files: |
1 |
|
Branches Taken: |
67.3% |
33 / 49 |
| Generated: |
2010-02-10 01:31 |
|
Branches Executed: |
83.7% |
41 / 49 |
| |
|
Line Coverage: |
95.5% |
148 / 155 |
| |
 |
|
 |
1 : //===--- Ownership.h - Parser Ownership Helpers -----------------*- C++ -*-===//
2 : //
3 : // The LLVM Compiler Infrastructure
4 : //
5 : // This file is distributed under the University of Illinois Open Source
6 : // License. See LICENSE.TXT for details.
7 : //
8 : //===----------------------------------------------------------------------===//
9 : //
10 : // This file contains classes for managing ownership of Stmt and Expr nodes.
11 : //
12 : //===----------------------------------------------------------------------===//
13 :
14 : #ifndef LLVM_CLANG_PARSE_OWNERSHIP_H
15 : #define LLVM_CLANG_PARSE_OWNERSHIP_H
16 :
17 : #include "llvm/ADT/SmallVector.h"
18 : #include "llvm/ADT/PointerIntPair.h"
19 :
20 : //===----------------------------------------------------------------------===//
21 : // OpaquePtr
22 : //===----------------------------------------------------------------------===//
23 :
24 : namespace clang {
25 : class ActionBase;
26 :
27 : /// OpaquePtr - This is a very simple POD type that wraps a pointer that the
28 : /// Parser doesn't know about but that Sema or another client does. The UID
29 : /// template argument is used to make sure that "Decl" pointers are not
30 : /// compatible with "Type" pointers for example.
31 : template<int UID>
32 33437: class OpaquePtr {
33 : void *Ptr;
34 : public:
35 1580667: OpaquePtr() : Ptr(0) {}
36 :
37 : template <typename T>
38 280882: T* getAs() const {
39 280882: return llvm::PointerLikeTypeTraits<T*>::getFromVoidPointer(Ptr);
40 : }
41 :
42 : template <typename T>
43 36009: T getAsVal() const {
44 36009: return llvm::PointerLikeTypeTraits<T>::getFromVoidPointer(Ptr);
45 : }
46 :
47 165264: void *get() const { return Ptr; }
48 :
49 : template<typename T>
50 337802: static OpaquePtr make(T P) {
51 337802: OpaquePtr R; R.set(P); return R;
52 : }
53 :
54 : template<typename T>
55 337802: void set(T P) {
56 337802: Ptr = llvm::PointerLikeTypeTraits<T>::getAsVoidPointer(P);
57 337802: }
58 :
59 88440: operator bool() const { return Ptr != 0; }
60 : };
61 : }
62 :
63 : namespace llvm {
64 : template <int UID>
65 : class PointerLikeTypeTraits<clang::OpaquePtr<UID> > {
66 : public:
67 142008: static inline void *getAsVoidPointer(clang::OpaquePtr<UID> P) {
68 : // FIXME: Doesn't work? return P.getAs< void >();
69 142008: return P.get();
70 : }
71 60237: static inline clang::OpaquePtr<UID> getFromVoidPointer(void *P) {
72 60237: return clang::OpaquePtr<UID>::make(P);
73 : }
74 : enum { NumLowBitsAvailable = 3 };
75 : };
76 : }
77 :
78 :
79 :
80 : // -------------------------- About Move Emulation -------------------------- //
81 : // The smart pointer classes in this file attempt to emulate move semantics
82 : // as they appear in C++0x with rvalue references. Since C++03 doesn't have
83 : // rvalue references, some tricks are needed to get similar results.
84 : // Move semantics in C++0x have the following properties:
85 : // 1) "Moving" means transferring the value of an object to another object,
86 : // similar to copying, but without caring what happens to the old object.
87 : // In particular, this means that the new object can steal the old object's
88 : // resources instead of creating a copy.
89 : // 2) Since moving can modify the source object, it must either be explicitly
90 : // requested by the user, or the modifications must be unnoticeable.
91 : // 3) As such, C++0x moving is only allowed in three contexts:
92 : // * By explicitly using std::move() to request it.
93 : // * From a temporary object, since that object cannot be accessed
94 : // afterwards anyway, thus making the state unobservable.
95 : // * On function return, since the object is not observable afterwards.
96 : //
97 : // To sum up: moving from a named object should only be possible with an
98 : // explicit std::move(), or on function return. Moving from a temporary should
99 : // be implicitly done. Moving from a const object is forbidden.
100 : //
101 : // The emulation is not perfect, and has the following shortcomings:
102 : // * move() is not in namespace std.
103 : // * move() is required on function return.
104 : // * There are difficulties with implicit conversions.
105 : // * Microsoft's compiler must be given the /Za switch to successfully compile.
106 : //
107 : // -------------------------- Implementation -------------------------------- //
108 : // The move emulation relies on the peculiar reference binding semantics of
109 : // C++03: as a rule, a non-const reference may not bind to a temporary object,
110 : // except for the implicit object parameter in a member function call, which
111 : // can refer to a temporary even when not being const.
112 : // The moveable object has five important functions to facilitate moving:
113 : // * A private, unimplemented constructor taking a non-const reference to its
114 : // own class. This constructor serves a two-fold purpose.
115 : // - It prevents the creation of a copy constructor that takes a const
116 : // reference. Temporaries would be able to bind to the argument of such a
117 : // constructor, and that would be bad.
118 : // - Named objects will bind to the non-const reference, but since it's
119 : // private, this will fail to compile. This prevents implicit moving from
120 : // named objects.
121 : // There's also a copy assignment operator for the same purpose.
122 : // * An implicit, non-const conversion operator to a special mover type. This
123 : // type represents the rvalue reference of C++0x. Being a non-const member,
124 : // its implicit this parameter can bind to temporaries.
125 : // * A constructor that takes an object of this mover type. This constructor
126 : // performs the actual move operation. There is an equivalent assignment
127 : // operator.
128 : // There is also a free move() function that takes a non-const reference to
129 : // an object and returns a temporary. Internally, this function uses explicit
130 : // constructor calls to move the value from the referenced object to the return
131 : // value.
132 : //
133 : // There are now three possible scenarios of use.
134 : // * Copying from a const object. Constructor overload resolution will find the
135 : // non-const copy constructor, and the move constructor. The first is not
136 : // viable because the const object cannot be bound to the non-const reference.
137 : // The second fails because the conversion to the mover object is non-const.
138 : // Moving from a const object fails as intended.
139 : // * Copying from a named object. Constructor overload resolution will select
140 : // the non-const copy constructor, but fail as intended, because this
141 : // constructor is private.
142 : // * Copying from a temporary. Constructor overload resolution cannot select
143 : // the non-const copy constructor, because the temporary cannot be bound to
144 : // the non-const reference. It thus selects the move constructor. The
145 : // temporary can be bound to the implicit this parameter of the conversion
146 : // operator, because of the special binding rule. Construction succeeds.
147 : // Note that the Microsoft compiler, as an extension, allows binding
148 : // temporaries against non-const references. The compiler thus selects the
149 : // non-const copy constructor and fails, because the constructor is private.
150 : // Passing /Za (disable extensions) disables this behaviour.
151 : // The free move() function is used to move from a named object.
152 : //
153 : // Note that when passing an object of a different type (the classes below
154 : // have OwningResult and OwningPtr, which should be mixable), you get a problem.
155 : // Argument passing and function return use copy initialization rules. The
156 : // effect of this is that, when the source object is not already of the target
157 : // type, the compiler will first seek a way to convert the source object to the
158 : // target type, and only then attempt to copy the resulting object. This means
159 : // that when passing an OwningResult where an OwningPtr is expected, the
160 : // compiler will first seek a conversion from OwningResult to OwningPtr, then
161 : // copy the OwningPtr. The resulting conversion sequence is:
162 : // OwningResult object -> ResultMover -> OwningResult argument to
163 : // OwningPtr(OwningResult) -> OwningPtr -> PtrMover -> final OwningPtr
164 : // This conversion sequence is too complex to be allowed. Thus the special
165 : // move_* functions, which help the compiler out with some explicit
166 : // conversions.
167 :
168 : // Flip this switch to measure performance impact of the smart pointers.
169 : //#define DISABLE_SMART_POINTERS
170 :
171 : namespace llvm {
172 : template<>
173 : class PointerLikeTypeTraits<clang::ActionBase*> {
174 : typedef clang::ActionBase* PT;
175 : public:
176 422837: static inline void *getAsVoidPointer(PT P) { return P; }
177 4010: static inline PT getFromVoidPointer(void *P) {
178 4010: return static_cast<PT>(P);
179 : }
180 : enum { NumLowBitsAvailable = 2 };
181 : };
182 : }
183 :
184 : namespace clang {
185 : // Basic
186 : class DiagnosticBuilder;
187 :
188 : // Determines whether the low bit of the result pointer for the
189 : // given UID is always zero. If so, ActionResult will use that bit
190 : // for it's "invalid" flag.
191 : template<unsigned UID>
192 : struct IsResultPtrLowBitFree {
193 : static const bool value = false;
194 : };
195 :
196 : /// ActionBase - A small part split from Action because of the horrible
197 : /// definition order dependencies between Action and the smart pointers.
198 2251: class ActionBase {
199 : public:
200 : /// Out-of-line virtual destructor to provide home for this class.
201 : virtual ~ActionBase();
202 :
203 : // Types - Though these don't actually enforce strong typing, they document
204 : // what types are required to be identical for the actions.
205 : typedef OpaquePtr<0> DeclPtrTy;
206 : typedef OpaquePtr<1> DeclGroupPtrTy;
207 : typedef OpaquePtr<2> TemplateTy;
208 : typedef void AttrTy;
209 : typedef void BaseTy;
210 : typedef void MemInitTy;
211 : typedef void ExprTy;
212 : typedef void StmtTy;
213 : typedef void TemplateParamsTy;
214 : typedef void CXXScopeTy;
215 : typedef void TypeTy; // FIXME: Change TypeTy to use OpaquePtr<N>.
216 :
217 : /// ActionResult - This structure is used while parsing/acting on
218 : /// expressions, stmts, etc. It encapsulates both the object returned by
219 : /// the action, plus a sense of whether or not it is valid.
220 : /// When CompressInvalid is true, the "invalid" flag will be
221 : /// stored in the low bit of the Val pointer.
222 : template<unsigned UID,
223 : typename PtrTy = void*,
224 : bool CompressInvalid = IsResultPtrLowBitFree<UID>::value>
225 : class ActionResult {
226 : PtrTy Val;
227 : bool Invalid;
228 :
229 : public:
230 7453: ActionResult(bool Invalid = false) : Val(PtrTy()), Invalid(Invalid) {}
231 : template<typename ActualExprTy>
232 17369: ActionResult(ActualExprTy val) : Val(val), Invalid(false) {}
233 : ActionResult(const DiagnosticBuilder &) : Val(PtrTy()), Invalid(true) {}
234 :
235 17485: PtrTy get() const { return Val; }
236 : void set(PtrTy V) { Val = V; }
237 23966: bool isInvalid() const { return Invalid; }
238 :
239 : const ActionResult &operator=(PtrTy RHS) {
240 : Val = RHS;
241 : Invalid = false;
242 : return *this;
243 : }
244 : };
245 :
246 : // This ActionResult partial specialization places the "invalid"
247 : // flag into the low bit of the pointer.
248 : template<unsigned UID, typename PtrTy>
249 : class ActionResult<UID, PtrTy, true> {
250 : // A pointer whose low bit is 1 if this result is invalid, 0
251 : // otherwise.
252 : uintptr_t PtrWithInvalid;
253 : typedef llvm::PointerLikeTypeTraits<PtrTy> PtrTraits;
254 : public:
255 7233: ActionResult(bool Invalid = false)
256 7233: : PtrWithInvalid(static_cast<uintptr_t>(Invalid)) { }
257 :
258 : template<typename ActualExprTy>
259 3235: ActionResult(ActualExprTy *val) {
260 3235: PtrTy V(val);
261 3235: void *VP = PtrTraits::getAsVoidPointer(V);
262 3235: PtrWithInvalid = reinterpret_cast<uintptr_t>(VP);
0: branch 0 not taken
1964: branch 1 taken
0: branch 3 not taken
958: branch 4 taken
0: branch 6 not taken
7: branch 7 taken
0: branch 9 not taken
20: branch 10 taken
0: branch 12 not taken
40: branch 13 taken
0: branch 15 not taken
30: branch 16 taken
0: branch 18 not taken
216: branch 19 taken
263 3235: assert((PtrWithInvalid & 0x01) == 0 && "Badly aligned pointer");
264 3235: }
265 :
266 1607: ActionResult(PtrTy V) {
267 1607: void *VP = PtrTraits::getAsVoidPointer(V);
268 1607: PtrWithInvalid = reinterpret_cast<uintptr_t>(VP);
0: branch 0 not taken
1607: branch 1 taken
269 1607: assert((PtrWithInvalid & 0x01) == 0 && "Badly aligned pointer");
270 1607: }
271 :
272 12: ActionResult(const DiagnosticBuilder &) : PtrWithInvalid(0x01) { }
273 :
274 16458: PtrTy get() const {
275 16458: void *VP = reinterpret_cast<void *>(PtrWithInvalid & ~0x01);
276 16458: return PtrTraits::getFromVoidPointer(VP);
277 : }
278 :
279 : void set(PtrTy V) {
280 : void *VP = PtrTraits::getAsVoidPointer(V);
281 : PtrWithInvalid = reinterpret_cast<uintptr_t>(VP);
282 : assert((PtrWithInvalid & 0x01) == 0 && "Badly aligned pointer");
283 : }
284 :
285 10505: bool isInvalid() const { return PtrWithInvalid & 0x01; }
286 :
287 6653: const ActionResult &operator=(PtrTy RHS) {
288 6653: void *VP = PtrTraits::getAsVoidPointer(RHS);
289 6653: PtrWithInvalid = reinterpret_cast<uintptr_t>(VP);
0: branch 0 not taken
6653: branch 1 taken
290 6653: assert((PtrWithInvalid & 0x01) == 0 && "Badly aligned pointer");
291 6653: return *this;
292 : }
293 : };
294 :
295 : /// Deletion callbacks - Since the parser doesn't know the concrete types of
296 : /// the AST nodes being generated, it must do callbacks to delete objects
297 : /// when recovering from errors. These are in ActionBase because the smart
298 : /// pointers need access to them.
299 1: virtual void DeleteExpr(ExprTy *E) {}
300 0: virtual void DeleteStmt(StmtTy *S) {}
301 0: virtual void DeleteTemplateParams(TemplateParamsTy *P) {}
302 : };
303 :
304 : /// ASTDestroyer - The type of an AST node destruction function pointer.
305 : typedef void (ActionBase::*ASTDestroyer)(void *);
306 :
307 : /// For the transition phase: translate from an ASTDestroyer to its
308 : /// ActionResult UID.
309 : template <ASTDestroyer Destroyer> struct DestroyerToUID;
310 : template <> struct DestroyerToUID<&ActionBase::DeleteExpr> {
311 : static const unsigned UID = 0;
312 : };
313 : template <> struct DestroyerToUID<&ActionBase::DeleteStmt> {
314 : static const unsigned UID = 1;
315 : };
316 : /// ASTOwningResult - A moveable smart pointer for AST nodes that also
317 : /// has an extra flag to indicate an additional success status.
318 : template <ASTDestroyer Destroyer> class ASTOwningResult;
319 :
320 : /// ASTMultiPtr - A moveable smart pointer to multiple AST nodes. Only owns
321 : /// the individual pointers, not the array holding them.
322 : template <ASTDestroyer Destroyer> class ASTMultiPtr;
323 :
324 : #if !defined(DISABLE_SMART_POINTERS)
325 : namespace moving {
326 : /// Move emulation helper for ASTOwningResult. NEVER EVER use this class
327 : /// directly if you don't know what you're doing.
328 : template <ASTDestroyer Destroyer>
329 : class ASTResultMover {
330 : ASTOwningResult<Destroyer> &Moved;
331 :
332 : public:
333 2771589: ASTResultMover(ASTOwningResult<Destroyer> &moved) : Moved(moved) {}
334 :
335 8314767: ASTOwningResult<Destroyer> * operator ->() { return &Moved; }
336 : };
337 :
338 : /// Move emulation helper for ASTMultiPtr. NEVER EVER use this class
339 : /// directly if you don't know what you're doing.
340 : template <ASTDestroyer Destroyer>
341 : class ASTMultiMover {
342 : ASTMultiPtr<Destroyer> &Moved;
343 :
344 : public:
345 214005: ASTMultiMover(ASTMultiPtr<Destroyer> &moved) : Moved(moved) {}
346 :
347 642015: ASTMultiPtr<Destroyer> * operator ->() { return &Moved; }
348 :
349 : /// Reset the moved object's internal structures.
350 : void release();
351 : };
352 : }
353 : #else
354 :
355 : /// Kept only as a type-safe wrapper for a void pointer, when smart pointers
356 : /// are disabled. When they are enabled, ASTOwningResult takes over.
357 : template <ASTDestroyer Destroyer>
358 : class ASTOwningPtr {
359 : void *Node;
360 :
361 : public:
362 : explicit ASTOwningPtr(ActionBase &) : Node(0) {}
363 : ASTOwningPtr(ActionBase &, void *node) : Node(node) {}
364 : // Normal copying operators are defined implicitly.
365 : ASTOwningPtr(const ASTOwningResult<Destroyer> &o);
366 :
367 : ASTOwningPtr & operator =(void *raw) {
368 : Node = raw;
369 : return *this;
370 : }
371 :
372 : /// Access to the raw pointer.
373 : void * get() const { return Node; }
374 :
375 : /// Release the raw pointer.
376 : void * take() {
377 : return Node;
378 : }
379 :
380 : /// Take outside ownership of the raw pointer and cast it down.
381 : template<typename T>
382 : T *takeAs() {
383 : return static_cast<T*>(Node);
384 : }
385 :
386 : /// Alias for interface familiarity with unique_ptr.
387 : void * release() {
388 : return take();
389 : }
390 : };
391 : #endif
392 :
393 : // Important: There are two different implementations of
394 : // ASTOwningResult below, depending on whether
395 : // DISABLE_SMART_POINTERS is defined. If you make changes that
396 : // affect the interface, be sure to compile and test both ways!
397 :
398 : #if !defined(DISABLE_SMART_POINTERS)
399 : template <ASTDestroyer Destroyer>
400 : class ASTOwningResult {
401 : llvm::PointerIntPair<ActionBase*, 1, bool> ActionInv;
402 : void *Ptr;
403 :
404 : friend class moving::ASTResultMover<Destroyer>;
405 :
406 : ASTOwningResult(ASTOwningResult&); // DO NOT IMPLEMENT
407 : ASTOwningResult& operator =(ASTOwningResult&); // DO NOT IMPLEMENT
408 :
409 3194591: void destroy() {
2229: branch 0 taken
2851265: branch 1 taken
67: branch 2 taken
341612: branch 3 taken
410 3194591: if (Ptr) {
1938: branch 1 taken
0: branch 2 not taken
0: branch 6 not taken
0: branch 6 not taken
411 2005: assert(ActionInv.getPointer() &&
412 : "Smart pointer has node but no action.");
413 2005: (ActionInv.getPointer()->*Destroyer)(Ptr);
414 2005: Ptr = 0;
415 : }
416 3194591: }
417 :
418 : public:
419 : typedef ActionBase::ActionResult<DestroyerToUID<Destroyer>::UID> DumbResult;
420 :
421 174147: explicit ASTOwningResult(ActionBase &actions, bool invalid = false)
422 174147: : ActionInv(&actions, invalid), Ptr(0) {}
423 246695: ASTOwningResult(ActionBase &actions, void *node)
424 246695: : ActionInv(&actions, false), Ptr(node) {}
425 1995: ASTOwningResult(ActionBase &actions, const DumbResult &res)
426 1995: : ActionInv(&actions, res.isInvalid()), Ptr(res.get()) {}
427 : /// Move from another owning result
428 2554367: ASTOwningResult(moving::ASTResultMover<Destroyer> mover)
429 : : ActionInv(mover->ActionInv),
430 2554367: Ptr(mover->Ptr) {
431 2554367: mover->Ptr = 0;
432 2554367: }
433 :
434 2977204: ~ASTOwningResult() {
435 2977204: destroy();
436 2977204: }
437 :
438 : /// Move assignment from another owning result
439 217222: ASTOwningResult &operator=(moving::ASTResultMover<Destroyer> mover) {
440 217222: destroy();
441 217222: ActionInv = mover->ActionInv;
442 217222: Ptr = mover->Ptr;
443 217222: mover->Ptr = 0;
444 217222: return *this;
445 : }
446 :
447 : /// Assignment from a raw pointer. Takes ownership - beware!
448 165: ASTOwningResult &operator=(void *raw) {
449 165: destroy();
450 165: Ptr = raw;
451 165: ActionInv.setInt(false);
452 165: return *this;
453 : }
454 :
455 : /// Assignment from an ActionResult. Takes ownership - beware!
456 0: ASTOwningResult &operator=(const DumbResult &res) {
457 0: destroy();
458 0: Ptr = res.get();
459 0: ActionInv.setInt(res.isInvalid());
460 0: return *this;
461 : }
462 :
463 : /// Access to the raw pointer.
464 140714: void *get() const { return Ptr; }
465 :
466 554989: bool isInvalid() const { return ActionInv.getInt(); }
467 :
468 : /// Does this point to a usable AST node? To be usable, the node must be
469 : /// valid and non-null.
21713: branch 1 taken
899: branch 2 taken
21471: branch 4 taken
242: branch 5 taken
470 22612: bool isUsable() const { return !isInvalid() && get(); }
471 :
472 : /// Take outside ownership of the raw pointer.
473 231029: void *take() {
73: branch 2 taken
193855: branch 4 taken
0: branch 4 not taken
0: branch 5 not taken
474 231029: if (isInvalid())
475 163: return 0;
476 230866: void *tmp = Ptr;
477 230866: Ptr = 0;
478 230866: return tmp;
479 : }
480 :
481 : /// Take outside ownership of the raw pointer and cast it down.
482 : template<typename T>
483 120719: T *takeAs() {
484 120719: return static_cast<T*>(take());
485 : }
486 :
487 : /// Alias for interface familiarity with unique_ptr.
488 103741: void *release() { return take(); }
489 :
490 : /// Pass ownership to a classical ActionResult.
491 : DumbResult result() {
492 : if (isInvalid())
493 : return true;
494 : return take();
495 : }
496 :
497 : /// Move hook
498 2257719: operator moving::ASTResultMover<Destroyer>() {
499 2257719: return moving::ASTResultMover<Destroyer>(*this);
500 : }
501 : };
502 : #else
503 : template <ASTDestroyer Destroyer>
504 : class ASTOwningResult {
505 : public:
506 : typedef ActionBase::ActionResult<DestroyerToUID<Destroyer>::UID> DumbResult;
507 :
508 : private:
509 : DumbResult Result;
510 :
511 : public:
512 : explicit ASTOwningResult(ActionBase &actions, bool invalid = false)
513 : : Result(invalid) { }
514 : ASTOwningResult(ActionBase &actions, void *node) : Result(node) { }
515 : ASTOwningResult(ActionBase &actions, const DumbResult &res) : Result(res) { }
516 : // Normal copying semantics are defined implicitly.
517 : ASTOwningResult(const ASTOwningPtr<Destroyer> &o) : Result(o.get()) { }
518 :
519 : /// Assignment from a raw pointer. Takes ownership - beware!
520 : ASTOwningResult & operator =(void *raw) {
521 : Result = raw;
522 : return *this;
523 : }
524 :
525 : /// Assignment from an ActionResult. Takes ownership - beware!
526 : ASTOwningResult & operator =(const DumbResult &res) {
527 : Result = res;
528 : return *this;
529 : }
530 :
531 : /// Access to the raw pointer.
532 : void * get() const { return Result.get(); }
533 :
534 : bool isInvalid() const { return Result.isInvalid(); }
535 :
536 : /// Does this point to a usable AST node? To be usable, the node must be
537 : /// valid and non-null.
538 : bool isUsable() const { return !Result.isInvalid() && get(); }
539 :
540 : /// Take outside ownership of the raw pointer.
541 : void * take() {
542 : return Result.get();
543 : }
544 :
545 : /// Take outside ownership of the raw pointer and cast it down.
546 : template<typename T>
547 : T *takeAs() {
548 : return static_cast<T*>(take());
549 : }
550 :
551 : /// Alias for interface familiarity with unique_ptr.
552 : void * release() { return take(); }
553 :
554 : /// Pass ownership to a classical ActionResult.
555 : DumbResult result() { return Result; }
556 : };
557 : #endif
558 :
559 : template <ASTDestroyer Destroyer>
560 : class ASTMultiPtr {
561 : #if !defined(DISABLE_SMART_POINTERS)
562 : ActionBase &Actions;
563 : #endif
564 : void **Nodes;
565 : unsigned Count;
566 :
567 : #if !defined(DISABLE_SMART_POINTERS)
568 : friend class moving::ASTMultiMover<Destroyer>;
569 :
570 : #if defined(_MSC_VER)
571 : // Last tested with Visual Studio 2008.
572 : // Visual C++ appears to have a bug where it does not recognise
573 : // the return value from ASTMultiMover<Destroyer>::opeator-> as
574 : // being a pointer to ASTMultiPtr. However, the diagnostics
575 : // suggest it has the right name, simply that the pointer type
576 : // is not convertible to itself.
577 : // Either way, a classic C-style hard cast resolves any issue.
578 : static ASTMultiPtr* hack(moving::ASTMultiMover<Destroyer> & source) {
579 : return (ASTMultiPtr*)source.operator->();
580 : }
581 : #endif
582 :
583 : ASTMultiPtr(ASTMultiPtr&); // DO NOT IMPLEMENT
584 : // Reference member prevents copy assignment.
585 :
586 : void destroy() {
587 : assert((Count == 0 || Nodes) && "No nodes when count is not zero.");
588 : for (unsigned i = 0; i < Count; ++i) {
589 : if (Nodes[i])
590 : (Actions.*Destroyer)(Nodes[i]);
591 : }
592 : }
593 : #endif
594 :
595 : public:
596 : #if !defined(DISABLE_SMART_POINTERS)
597 26848: explicit ASTMultiPtr(ActionBase &actions)
598 26848: : Actions(actions), Nodes(0), Count(0) {}
599 61350: ASTMultiPtr(ActionBase &actions, void **nodes, unsigned count)
600 61350: : Actions(actions), Nodes(nodes), Count(count) {}
601 : /// Move constructor
602 214005: ASTMultiPtr(moving::ASTMultiMover<Destroyer> mover)
603 : #if defined(_MSC_VER)
604 : // Apply the visual C++ hack supplied above.
605 : // Last tested with Visual Studio 2008.
606 : : Actions(hack(mover)->Actions), Nodes(hack(mover)->Nodes), Count(hack(mover)->Count) {
607 : #else
608 214005: : Actions(mover->Actions), Nodes(mover->Nodes), Count(mover->Count) {
609 : #endif
610 214005: mover.release();
611 214005: }
612 : #else
613 : // Normal copying implicitly defined
614 : explicit ASTMultiPtr(ActionBase &) : Nodes(0), Count(0) {}
615 : ASTMultiPtr(ActionBase &, void **nodes, unsigned count)
616 : : Nodes(nodes), Count(count) {}
617 : // Fake mover in Parse/AstGuard.h needs this:
618 : ASTMultiPtr(void **nodes, unsigned count) : Nodes(nodes), Count(count) {}
619 : #endif
620 :
621 : #if !defined(DISABLE_SMART_POINTERS)
622 : /// Move assignment
623 : ASTMultiPtr & operator =(moving::ASTMultiMover<Destroyer> mover) {
624 : destroy();
625 : Nodes = mover->Nodes;
626 : Count = mover->Count;
627 : mover.release();
628 : return *this;
629 : }
630 : #endif
631 :
632 : /// Access to the raw pointers.
633 53227: void ** get() const { return Nodes; }
634 :
635 : /// Access to the count.
636 80241: unsigned size() const { return Count; }
637 :
638 28223: void ** release() {
639 : #if !defined(DISABLE_SMART_POINTERS)
640 28223: void **tmp = Nodes;
641 28223: Nodes = 0;
642 28223: Count = 0;
643 28223: return tmp;
644 : #else
645 : return Nodes;
646 : #endif
647 : }
648 :
649 : #if !defined(DISABLE_SMART_POINTERS)
650 : /// Move hook
651 177521: operator moving::ASTMultiMover<Destroyer>() {
652 177521: return moving::ASTMultiMover<Destroyer>(*this);
653 : }
654 : #endif
655 : };
656 :
657 : class ParsedTemplateArgument;
658 :
659 : class ASTTemplateArgsPtr {
660 : #if !defined(DISABLE_SMART_POINTERS)
661 : ActionBase &Actions;
662 : #endif
663 : ParsedTemplateArgument *Args;
664 : mutable unsigned Count;
665 :
666 : #if !defined(DISABLE_SMART_POINTERS)
667 : void destroy();
668 : #endif
669 :
670 : public:
671 : ASTTemplateArgsPtr(ActionBase &actions, ParsedTemplateArgument *args,
672 5064: unsigned count) :
673 : #if !defined(DISABLE_SMART_POINTERS)
674 : Actions(actions),
675 : #endif
676 5064: Args(args), Count(count) { }
677 :
678 : // FIXME: Lame, not-fully-type-safe emulation of 'move semantics'.
679 2301: ASTTemplateArgsPtr(ASTTemplateArgsPtr &Other) :
680 : #if !defined(DISABLE_SMART_POINTERS)
681 : Actions(Other.Actions),
682 : #endif
683 2301: Args(Other.Args), Count(Other.Count) {
684 : #if !defined(DISABLE_SMART_POINTERS)
685 2301: Other.Count = 0;
686 : #endif
687 2301: }
688 :
689 : // FIXME: Lame, not-fully-type-safe emulation of 'move semantics'.
690 : ASTTemplateArgsPtr& operator=(ASTTemplateArgsPtr &Other) {
691 : #if !defined(DISABLE_SMART_POINTERS)
692 : Actions = Other.Actions;
693 : #endif
694 : Args = Other.Args;
695 : Count = Other.Count;
696 : #if !defined(DISABLE_SMART_POINTERS)
697 : Other.Count = 0;
698 : #endif
699 : return *this;
700 : }
701 :
702 : #if !defined(DISABLE_SMART_POINTERS)
703 7365: ~ASTTemplateArgsPtr() { destroy(); }
704 : #endif
705 :
706 : ParsedTemplateArgument *getArgs() const { return Args; }
707 2527: unsigned size() const { return Count; }
708 :
709 : void reset(ParsedTemplateArgument *args, unsigned count) {
710 : #if !defined(DISABLE_SMART_POINTERS)
711 : destroy();
712 : #endif
713 : Args = args;
714 : Count = count;
715 : }
716 :
717 : const ParsedTemplateArgument &operator[](unsigned Arg) const;
718 :
719 5044: ParsedTemplateArgument *release() const {
720 : #if !defined(DISABLE_SMART_POINTERS)
721 5044: Count = 0;
722 : #endif
723 5044: return Args;
724 : }
725 : };
726 :
727 : /// \brief A small vector that owns a set of AST nodes.
728 : template <ASTDestroyer Destroyer, unsigned N = 8>
729 : class ASTOwningVector : public llvm::SmallVector<void *, N> {
730 : #if !defined(DISABLE_SMART_POINTERS)
731 : ActionBase &Actions;
732 : bool Owned;
733 : #endif
734 :
735 : ASTOwningVector(ASTOwningVector &); // do not implement
736 : ASTOwningVector &operator=(ASTOwningVector &); // do not implement
737 :
738 : public:
739 26333: explicit ASTOwningVector(ActionBase &Actions)
740 : #if !defined(DISABLE_SMART_POINTERS)
741 26333: : Actions(Actions), Owned(true)
742 : #endif
743 26333: { }
744 :
745 : #if !defined(DISABLE_SMART_POINTERS)
746 26333: ~ASTOwningVector() {
313: branch 2 taken
313: branch 3 taken
250: branch 3 taken
30: branch 4 taken
5: branch 5 taken
747 26333: if (!Owned)
748 25572: return;
749 :
88: branch 1 taken
462: branch 2 taken
0: branch 4 not taken
0: branch 5 not taken
17: branch 7 taken
5: branch 8 taken
750 872: for (unsigned I = 0, Last = this->size(); I != Last; ++I)
462: branch 3 taken
23254: branch 4 taken
5: branch 13 taken
30: branch 14 taken
751 52777: (Actions.*Destroyer)((*this)[I]);
752 26333: }
753 : #endif
754 :
755 25572: void **take() {
756 : #if !defined(DISABLE_SMART_POINTERS)
757 25572: Owned = false;
758 : #endif
759 25572: return &this->front();
760 : }
761 :
762 : template<typename T> T **takeAs() { return (T**)take(); }
763 :
764 : #if !defined(DISABLE_SMART_POINTERS)
765 22337: ActionBase &getActions() const { return Actions; }
766 : #endif
767 : };
768 :
769 : /// A SmallVector of statements, with stack size 32 (as that is the only one
770 : /// used.)
771 : typedef ASTOwningVector<&ActionBase::DeleteStmt, 32> StmtVector;
772 : /// A SmallVector of expressions, with stack size 12 (the maximum used.)
773 : typedef ASTOwningVector<&ActionBase::DeleteExpr, 12> ExprVector;
774 :
775 : template <ASTDestroyer Destroyer, unsigned N> inline
776 22337: ASTMultiPtr<Destroyer> move_arg(ASTOwningVector<Destroyer, N> &vec) {
777 : #if !defined(DISABLE_SMART_POINTERS)
778 22337: return ASTMultiPtr<Destroyer>(vec.getActions(), vec.take(), vec.size());
779 : #else
780 : return ASTMultiPtr<Destroyer>(vec.take(), vec.size());
781 : #endif
782 : }
783 :
784 : #if !defined(DISABLE_SMART_POINTERS)
785 :
786 : // Out-of-line implementations due to definition dependencies
787 :
788 : template <ASTDestroyer Destroyer> inline
789 214005: void moving::ASTMultiMover<Destroyer>::release() {
790 214005: Moved.Nodes = 0;
791 214005: Moved.Count = 0;
792 214005: }
793 :
794 : // Move overloads.
795 :
796 : template <ASTDestroyer Destroyer> inline
797 513870: ASTOwningResult<Destroyer> move(ASTOwningResult<Destroyer> &ptr) {
798 513870: return ASTOwningResult<Destroyer>(moving::ASTResultMover<Destroyer>(ptr));
799 : }
800 :
801 : template <ASTDestroyer Destroyer> inline
802 36484: ASTMultiPtr<Destroyer> move(ASTMultiPtr<Destroyer> &ptr) {
803 36484: return ASTMultiPtr<Destroyer>(moving::ASTMultiMover<Destroyer>(ptr));
804 : }
805 :
806 : #else
807 :
808 : template <ASTDestroyer Destroyer> inline
809 : ASTOwningPtr<Destroyer>::ASTOwningPtr(const ASTOwningResult<Destroyer> &o)
810 : : Node(o.get()) { }
811 :
812 : // These versions are hopefully no-ops.
813 : template <ASTDestroyer Destroyer> inline
814 : ASTOwningResult<Destroyer>& move(ASTOwningResult<Destroyer> &ptr) {
815 : return ptr;
816 : }
817 :
818 : template <ASTDestroyer Destroyer> inline
819 : ASTOwningPtr<Destroyer>& move(ASTOwningPtr<Destroyer> &ptr) {
820 : return ptr;
821 : }
822 :
823 : template <ASTDestroyer Destroyer> inline
824 : ASTMultiPtr<Destroyer>& move(ASTMultiPtr<Destroyer> &ptr) {
825 : return ptr;
826 : }
827 : #endif
828 : }
829 :
830 : #endif
Generated: 2010-02-10 01:31 by zcov