1193326Sed//===-- CGValue.h - LLVM CodeGen wrappers for llvm::Value* ------*- C++ -*-===//
2193326Sed//
3193326Sed//                     The LLVM Compiler Infrastructure
4193326Sed//
5193326Sed// This file is distributed under the University of Illinois Open Source
6193326Sed// License. See LICENSE.TXT for details.
7193326Sed//
8193326Sed//===----------------------------------------------------------------------===//
9193326Sed//
10193326Sed// These classes implement wrappers around llvm::Value in order to
11193326Sed// fully represent the range of values for C L- and R- values.
12193326Sed//
13193326Sed//===----------------------------------------------------------------------===//
14193326Sed
15193326Sed#ifndef CLANG_CODEGEN_CGVALUE_H
16193326Sed#define CLANG_CODEGEN_CGVALUE_H
17193326Sed
18212904Sdim#include "clang/AST/ASTContext.h"
19234353Sdim#include "clang/AST/CharUnits.h"
20193326Sed#include "clang/AST/Type.h"
21249423Sdim#include "llvm/IR/Value.h"
22193326Sed
23193326Sednamespace llvm {
24193326Sed  class Constant;
25249423Sdim  class MDNode;
26193326Sed}
27193326Sed
28193326Sednamespace clang {
29193326Sednamespace CodeGen {
30234353Sdim  class AggValueSlot;
31249423Sdim  struct CGBitFieldInfo;
32193326Sed
33193326Sed/// RValue - This trivial value class is used to represent the result of an
34193326Sed/// expression that is evaluated.  It can be one of three things: either a
35193326Sed/// simple LLVM SSA value, a pair of SSA values for complex numbers, or the
36193326Sed/// address of an aggregate value in memory.
37193326Sedclass RValue {
38207619Srdivacky  enum Flavor { Scalar, Complex, Aggregate };
39198092Srdivacky
40207619Srdivacky  // Stores first value and flavor.
41207619Srdivacky  llvm::PointerIntPair<llvm::Value *, 2, Flavor> V1;
42207619Srdivacky  // Stores second value and volatility.
43207619Srdivacky  llvm::PointerIntPair<llvm::Value *, 1, bool> V2;
44207619Srdivacky
45193326Sedpublic:
46207619Srdivacky  bool isScalar() const { return V1.getInt() == Scalar; }
47207619Srdivacky  bool isComplex() const { return V1.getInt() == Complex; }
48207619Srdivacky  bool isAggregate() const { return V1.getInt() == Aggregate; }
49198092Srdivacky
50207619Srdivacky  bool isVolatileQualified() const { return V2.getInt(); }
51198092Srdivacky
52198893Srdivacky  /// getScalarVal() - Return the Value* of this scalar value.
53193326Sed  llvm::Value *getScalarVal() const {
54193326Sed    assert(isScalar() && "Not a scalar!");
55207619Srdivacky    return V1.getPointer();
56193326Sed  }
57193326Sed
58193326Sed  /// getComplexVal - Return the real/imag components of this complex value.
59193326Sed  ///
60193326Sed  std::pair<llvm::Value *, llvm::Value *> getComplexVal() const {
61207619Srdivacky    return std::make_pair(V1.getPointer(), V2.getPointer());
62193326Sed  }
63198092Srdivacky
64193326Sed  /// getAggregateAddr() - Return the Value* of the address of the aggregate.
65193326Sed  llvm::Value *getAggregateAddr() const {
66193326Sed    assert(isAggregate() && "Not an aggregate!");
67207619Srdivacky    return V1.getPointer();
68193326Sed  }
69198092Srdivacky
70193326Sed  static RValue get(llvm::Value *V) {
71193326Sed    RValue ER;
72207619Srdivacky    ER.V1.setPointer(V);
73207619Srdivacky    ER.V1.setInt(Scalar);
74207619Srdivacky    ER.V2.setInt(false);
75193326Sed    return ER;
76193326Sed  }
77193326Sed  static RValue getComplex(llvm::Value *V1, llvm::Value *V2) {
78193326Sed    RValue ER;
79207619Srdivacky    ER.V1.setPointer(V1);
80207619Srdivacky    ER.V2.setPointer(V2);
81207619Srdivacky    ER.V1.setInt(Complex);
82207619Srdivacky    ER.V2.setInt(false);
83193326Sed    return ER;
84193326Sed  }
85193326Sed  static RValue getComplex(const std::pair<llvm::Value *, llvm::Value *> &C) {
86207619Srdivacky    return getComplex(C.first, C.second);
87193326Sed  }
88193326Sed  // FIXME: Aggregate rvalues need to retain information about whether they are
89193326Sed  // volatile or not.  Remove default to find all places that probably get this
90193326Sed  // wrong.
91207619Srdivacky  static RValue getAggregate(llvm::Value *V, bool Volatile = false) {
92193326Sed    RValue ER;
93207619Srdivacky    ER.V1.setPointer(V);
94207619Srdivacky    ER.V1.setInt(Aggregate);
95207619Srdivacky    ER.V2.setInt(Volatile);
96193326Sed    return ER;
97193326Sed  }
98193326Sed};
99193326Sed
100249423Sdim/// Does an ARC strong l-value have precise lifetime?
101249423Sdimenum ARCPreciseLifetime_t {
102249423Sdim  ARCImpreciseLifetime, ARCPreciseLifetime
103249423Sdim};
104193326Sed
105193326Sed/// LValue - This represents an lvalue references.  Because C/C++ allow
106193326Sed/// bitfields, this is not a simple LLVM pointer, it may be a pointer plus a
107193326Sed/// bitrange.
108193326Sedclass LValue {
109193326Sed  enum {
110193326Sed    Simple,       // This is a normal l-value, use getAddress().
111193326Sed    VectorElt,    // This is a vector element l-value (V[i]), use getVector*
112193326Sed    BitField,     // This is a bitfield l-value, use getBitfield*.
113234353Sdim    ExtVectorElt  // This is an extended vector subset, use getExtVectorComp
114193326Sed  } LVType;
115193326Sed
116193326Sed  llvm::Value *V;
117198092Srdivacky
118193326Sed  union {
119193326Sed    // Index into a vector subscript: V[i]
120193326Sed    llvm::Value *VectorIdx;
121193326Sed
122193326Sed    // ExtVector element subset: V.xyx
123193326Sed    llvm::Constant *VectorElts;
124198092Srdivacky
125193326Sed    // BitField start bit and size
126206275Srdivacky    const CGBitFieldInfo *BitFieldInfo;
127193326Sed  };
128193326Sed
129224145Sdim  QualType Type;
130224145Sdim
131198092Srdivacky  // 'const' is unused here
132198092Srdivacky  Qualifiers Quals;
133193326Sed
134234353Sdim  // The alignment to use when accessing this lvalue.  (For vector elements,
135234353Sdim  // this is the alignment of the whole vector.)
136239462Sdim  int64_t Alignment;
137212904Sdim
138193326Sed  // objective-c's ivar
139193326Sed  bool Ivar:1;
140193326Sed
141198092Srdivacky  // objective-c's ivar is an array
142198092Srdivacky  bool ObjIsArray:1;
143198092Srdivacky
144193326Sed  // LValue is non-gc'able for any reason, including being a parameter or local
145193326Sed  // variable.
146193326Sed  bool NonGC: 1;
147193326Sed
148193326Sed  // Lvalue is a global reference of an objective-c object
149193326Sed  bool GlobalObjCRef : 1;
150212904Sdim
151212904Sdim  // Lvalue is a thread local reference
152212904Sdim  bool ThreadLocalRef : 1;
153193326Sed
154249423Sdim  // Lvalue has ARC imprecise lifetime.  We store this inverted to try
155249423Sdim  // to make the default bitfield pattern all-zeroes.
156249423Sdim  bool ImpreciseLifetime : 1;
157249423Sdim
158198092Srdivacky  Expr *BaseIvarExp;
159218893Sdim
160249423Sdim  /// Used by struct-path-aware TBAA.
161249423Sdim  QualType TBAABaseType;
162249423Sdim  /// Offset relative to the base type.
163249423Sdim  uint64_t TBAAOffset;
164249423Sdim
165218893Sdim  /// TBAAInfo - TBAA information to attach to dereferences of this LValue.
166218893Sdim  llvm::MDNode *TBAAInfo;
167218893Sdim
168193326Sedprivate:
169234353Sdim  void Initialize(QualType Type, Qualifiers Quals,
170239462Sdim                  CharUnits Alignment,
171218893Sdim                  llvm::MDNode *TBAAInfo = 0) {
172224145Sdim    this->Type = Type;
173198092Srdivacky    this->Quals = Quals;
174234353Sdim    this->Alignment = Alignment.getQuantity();
175234353Sdim    assert(this->Alignment == Alignment.getQuantity() &&
176234353Sdim           "Alignment exceeds allowed max!");
177212904Sdim
178212904Sdim    // Initialize Objective-C flags.
179198092Srdivacky    this->Ivar = this->ObjIsArray = this->NonGC = this->GlobalObjCRef = false;
180249423Sdim    this->ImpreciseLifetime = false;
181212904Sdim    this->ThreadLocalRef = false;
182198092Srdivacky    this->BaseIvarExp = 0;
183249423Sdim
184249423Sdim    // Initialize fields for TBAA.
185249423Sdim    this->TBAABaseType = Type;
186249423Sdim    this->TBAAOffset = 0;
187218893Sdim    this->TBAAInfo = TBAAInfo;
188193326Sed  }
189198092Srdivacky
190193326Sedpublic:
191193326Sed  bool isSimple() const { return LVType == Simple; }
192193326Sed  bool isVectorElt() const { return LVType == VectorElt; }
193206275Srdivacky  bool isBitField() const { return LVType == BitField; }
194193326Sed  bool isExtVectorElt() const { return LVType == ExtVectorElt; }
195193326Sed
196198092Srdivacky  bool isVolatileQualified() const { return Quals.hasVolatile(); }
197198092Srdivacky  bool isRestrictQualified() const { return Quals.hasRestrict(); }
198198092Srdivacky  unsigned getVRQualifiers() const {
199198092Srdivacky    return Quals.getCVRQualifiers() & ~Qualifiers::Const;
200193326Sed  }
201198092Srdivacky
202224145Sdim  QualType getType() const { return Type; }
203224145Sdim
204224145Sdim  Qualifiers::ObjCLifetime getObjCLifetime() const {
205224145Sdim    return Quals.getObjCLifetime();
206224145Sdim  }
207224145Sdim
208193326Sed  bool isObjCIvar() const { return Ivar; }
209212904Sdim  void setObjCIvar(bool Value) { Ivar = Value; }
210212904Sdim
211198092Srdivacky  bool isObjCArray() const { return ObjIsArray; }
212212904Sdim  void setObjCArray(bool Value) { ObjIsArray = Value; }
213212904Sdim
214193326Sed  bool isNonGC () const { return NonGC; }
215212904Sdim  void setNonGC(bool Value) { NonGC = Value; }
216212904Sdim
217193326Sed  bool isGlobalObjCRef() const { return GlobalObjCRef; }
218212904Sdim  void setGlobalObjCRef(bool Value) { GlobalObjCRef = Value; }
219212904Sdim
220212904Sdim  bool isThreadLocalRef() const { return ThreadLocalRef; }
221212904Sdim  void setThreadLocalRef(bool Value) { ThreadLocalRef = Value;}
222212904Sdim
223249423Sdim  ARCPreciseLifetime_t isARCPreciseLifetime() const {
224249423Sdim    return ARCPreciseLifetime_t(!ImpreciseLifetime);
225249423Sdim  }
226249423Sdim  void setARCPreciseLifetime(ARCPreciseLifetime_t value) {
227249423Sdim    ImpreciseLifetime = (value == ARCImpreciseLifetime);
228249423Sdim  }
229249423Sdim
230212904Sdim  bool isObjCWeak() const {
231212904Sdim    return Quals.getObjCGCAttr() == Qualifiers::Weak;
232212904Sdim  }
233212904Sdim  bool isObjCStrong() const {
234212904Sdim    return Quals.getObjCGCAttr() == Qualifiers::Strong;
235212904Sdim  }
236224145Sdim
237224145Sdim  bool isVolatile() const {
238224145Sdim    return Quals.hasVolatile();
239224145Sdim  }
240193326Sed
241198092Srdivacky  Expr *getBaseIvarExp() const { return BaseIvarExp; }
242198092Srdivacky  void setBaseIvarExp(Expr *V) { BaseIvarExp = V; }
243198092Srdivacky
244249423Sdim  QualType getTBAABaseType() const { return TBAABaseType; }
245249423Sdim  void setTBAABaseType(QualType T) { TBAABaseType = T; }
246249423Sdim
247249423Sdim  uint64_t getTBAAOffset() const { return TBAAOffset; }
248249423Sdim  void setTBAAOffset(uint64_t O) { TBAAOffset = O; }
249249423Sdim
250218893Sdim  llvm::MDNode *getTBAAInfo() const { return TBAAInfo; }
251218893Sdim  void setTBAAInfo(llvm::MDNode *N) { TBAAInfo = N; }
252218893Sdim
253212904Sdim  const Qualifiers &getQuals() const { return Quals; }
254212904Sdim  Qualifiers &getQuals() { return Quals; }
255212904Sdim
256198092Srdivacky  unsigned getAddressSpace() const { return Quals.getAddressSpace(); }
257198092Srdivacky
258234353Sdim  CharUnits getAlignment() const { return CharUnits::fromQuantity(Alignment); }
259234353Sdim  void setAlignment(CharUnits A) { Alignment = A.getQuantity(); }
260198092Srdivacky
261193326Sed  // simple lvalue
262193326Sed  llvm::Value *getAddress() const { assert(isSimple()); return V; }
263224145Sdim  void setAddress(llvm::Value *address) {
264224145Sdim    assert(isSimple());
265224145Sdim    V = address;
266224145Sdim  }
267206275Srdivacky
268193326Sed  // vector elt lvalue
269193326Sed  llvm::Value *getVectorAddr() const { assert(isVectorElt()); return V; }
270193326Sed  llvm::Value *getVectorIdx() const { assert(isVectorElt()); return VectorIdx; }
271206275Srdivacky
272193326Sed  // extended vector elements.
273193326Sed  llvm::Value *getExtVectorAddr() const { assert(isExtVectorElt()); return V; }
274193326Sed  llvm::Constant *getExtVectorElts() const {
275193326Sed    assert(isExtVectorElt());
276193326Sed    return VectorElts;
277193326Sed  }
278206275Srdivacky
279193326Sed  // bitfield lvalue
280249423Sdim  llvm::Value *getBitFieldAddr() const {
281206275Srdivacky    assert(isBitField());
282206275Srdivacky    return V;
283193326Sed  }
284206275Srdivacky  const CGBitFieldInfo &getBitFieldInfo() const {
285206275Srdivacky    assert(isBitField());
286206275Srdivacky    return *BitFieldInfo;
287193326Sed  }
288206275Srdivacky
289224145Sdim  static LValue MakeAddr(llvm::Value *address, QualType type,
290234353Sdim                         CharUnits alignment, ASTContext &Context,
291218893Sdim                         llvm::MDNode *TBAAInfo = 0) {
292224145Sdim    Qualifiers qs = type.getQualifiers();
293224145Sdim    qs.setObjCGCAttr(Context.getObjCGCAttrKind(type));
294212904Sdim
295193326Sed    LValue R;
296193326Sed    R.LVType = Simple;
297224145Sdim    R.V = address;
298224145Sdim    R.Initialize(type, qs, alignment, TBAAInfo);
299193326Sed    return R;
300193326Sed  }
301198092Srdivacky
302193326Sed  static LValue MakeVectorElt(llvm::Value *Vec, llvm::Value *Idx,
303234353Sdim                              QualType type, CharUnits Alignment) {
304193326Sed    LValue R;
305193326Sed    R.LVType = VectorElt;
306193326Sed    R.V = Vec;
307193326Sed    R.VectorIdx = Idx;
308234353Sdim    R.Initialize(type, type.getQualifiers(), Alignment);
309193326Sed    return R;
310193326Sed  }
311198092Srdivacky
312193326Sed  static LValue MakeExtVectorElt(llvm::Value *Vec, llvm::Constant *Elts,
313234353Sdim                                 QualType type, CharUnits Alignment) {
314193326Sed    LValue R;
315193326Sed    R.LVType = ExtVectorElt;
316193326Sed    R.V = Vec;
317193326Sed    R.VectorElts = Elts;
318234353Sdim    R.Initialize(type, type.getQualifiers(), Alignment);
319193326Sed    return R;
320193326Sed  }
321193326Sed
322207619Srdivacky  /// \brief Create a new object to represent a bit-field access.
323207619Srdivacky  ///
324249423Sdim  /// \param Addr - The base address of the bit-field sequence this
325249423Sdim  /// bit-field refers to.
326207619Srdivacky  /// \param Info - The information describing how to perform the bit-field
327207619Srdivacky  /// access.
328249423Sdim  static LValue MakeBitfield(llvm::Value *Addr,
329224145Sdim                             const CGBitFieldInfo &Info,
330239462Sdim                             QualType type, CharUnits Alignment) {
331193326Sed    LValue R;
332193326Sed    R.LVType = BitField;
333249423Sdim    R.V = Addr;
334206275Srdivacky    R.BitFieldInfo = &Info;
335239462Sdim    R.Initialize(type, type.getQualifiers(), Alignment);
336193326Sed    return R;
337193326Sed  }
338193326Sed
339234353Sdim  RValue asAggregateRValue() const {
340234353Sdim    // FIMXE: Alignment
341234353Sdim    return RValue::getAggregate(getAddress(), isVolatileQualified());
342193326Sed  }
343218893Sdim};
344198092Srdivacky
345218893Sdim/// An aggregate value slot.
346218893Sdimclass AggValueSlot {
347218893Sdim  /// The address.
348218893Sdim  llvm::Value *Addr;
349224145Sdim
350224145Sdim  // Qualifiers
351224145Sdim  Qualifiers Quals;
352226633Sdim
353234353Sdim  unsigned short Alignment;
354234353Sdim
355226633Sdim  /// DestructedFlag - This is set to true if some external code is
356226633Sdim  /// responsible for setting up a destructor for the slot.  Otherwise
357226633Sdim  /// the code which constructs it should push the appropriate cleanup.
358226633Sdim  bool DestructedFlag : 1;
359226633Sdim
360226633Sdim  /// ObjCGCFlag - This is set to true if writing to the memory in the
361226633Sdim  /// slot might require calling an appropriate Objective-C GC
362226633Sdim  /// barrier.  The exact interaction here is unnecessarily mysterious.
363226633Sdim  bool ObjCGCFlag : 1;
364218893Sdim
365226633Sdim  /// ZeroedFlag - This is set to true if the memory in the slot is
366226633Sdim  /// known to be zero before the assignment into it.  This means that
367226633Sdim  /// zero fields don't need to be set.
368226633Sdim  bool ZeroedFlag : 1;
369218893Sdim
370226633Sdim  /// AliasedFlag - This is set to true if the slot might be aliased
371226633Sdim  /// and it's not undefined behavior to access it through such an
372226633Sdim  /// alias.  Note that it's always undefined behavior to access a C++
373226633Sdim  /// object that's under construction through an alias derived from
374226633Sdim  /// outside the construction process.
375226633Sdim  ///
376226633Sdim  /// This flag controls whether calls that produce the aggregate
377226633Sdim  /// value may be evaluated directly into the slot, or whether they
378226633Sdim  /// must be evaluated into an unaliased temporary and then memcpy'ed
379226633Sdim  /// over.  Since it's invalid in general to memcpy a non-POD C++
380226633Sdim  /// object, it's important that this flag never be set when
381226633Sdim  /// evaluating an expression which constructs such an object.
382226633Sdim  bool AliasedFlag : 1;
383226633Sdim
384218893Sdimpublic:
385226633Sdim  enum IsAliased_t { IsNotAliased, IsAliased };
386226633Sdim  enum IsDestructed_t { IsNotDestructed, IsDestructed };
387226633Sdim  enum IsZeroed_t { IsNotZeroed, IsZeroed };
388226633Sdim  enum NeedsGCBarriers_t { DoesNotNeedGCBarriers, NeedsGCBarriers };
389226633Sdim
390218893Sdim  /// ignored - Returns an aggregate value slot indicating that the
391218893Sdim  /// aggregate value is being ignored.
392218893Sdim  static AggValueSlot ignored() {
393234353Sdim    return forAddr(0, CharUnits(), Qualifiers(), IsNotDestructed,
394234353Sdim                   DoesNotNeedGCBarriers, IsNotAliased);
395193326Sed  }
396218893Sdim
397218893Sdim  /// forAddr - Make a slot for an aggregate value.
398218893Sdim  ///
399226633Sdim  /// \param quals - The qualifiers that dictate how the slot should
400226633Sdim  /// be initialied. Only 'volatile' and the Objective-C lifetime
401226633Sdim  /// qualifiers matter.
402224145Sdim  ///
403226633Sdim  /// \param isDestructed - true if something else is responsible
404226633Sdim  ///   for calling destructors on this object
405226633Sdim  /// \param needsGC - true if the slot is potentially located
406218893Sdim  ///   somewhere that ObjC GC calls should be emitted for
407234353Sdim  static AggValueSlot forAddr(llvm::Value *addr, CharUnits align,
408234353Sdim                              Qualifiers quals,
409226633Sdim                              IsDestructed_t isDestructed,
410226633Sdim                              NeedsGCBarriers_t needsGC,
411226633Sdim                              IsAliased_t isAliased,
412263508Sdim                              IsZeroed_t isZeroed = IsNotZeroed) {
413218893Sdim    AggValueSlot AV;
414226633Sdim    AV.Addr = addr;
415234353Sdim    AV.Alignment = align.getQuantity();
416226633Sdim    AV.Quals = quals;
417226633Sdim    AV.DestructedFlag = isDestructed;
418226633Sdim    AV.ObjCGCFlag = needsGC;
419226633Sdim    AV.ZeroedFlag = isZeroed;
420226633Sdim    AV.AliasedFlag = isAliased;
421218893Sdim    return AV;
422218893Sdim  }
423218893Sdim
424239462Sdim  static AggValueSlot forLValue(const LValue &LV,
425239462Sdim                                IsDestructed_t isDestructed,
426226633Sdim                                NeedsGCBarriers_t needsGC,
427226633Sdim                                IsAliased_t isAliased,
428263508Sdim                                IsZeroed_t isZeroed = IsNotZeroed) {
429234353Sdim    return forAddr(LV.getAddress(), LV.getAlignment(),
430263508Sdim                   LV.getQuals(), isDestructed, needsGC, isAliased, isZeroed);
431218893Sdim  }
432218893Sdim
433226633Sdim  IsDestructed_t isExternallyDestructed() const {
434226633Sdim    return IsDestructed_t(DestructedFlag);
435218893Sdim  }
436226633Sdim  void setExternallyDestructed(bool destructed = true) {
437226633Sdim    DestructedFlag = destructed;
438218893Sdim  }
439218893Sdim
440224145Sdim  Qualifiers getQualifiers() const { return Quals; }
441224145Sdim
442218893Sdim  bool isVolatile() const {
443224145Sdim    return Quals.hasVolatile();
444218893Sdim  }
445218893Sdim
446249423Sdim  void setVolatile(bool flag) {
447249423Sdim    Quals.setVolatile(flag);
448249423Sdim  }
449249423Sdim
450224145Sdim  Qualifiers::ObjCLifetime getObjCLifetime() const {
451224145Sdim    return Quals.getObjCLifetime();
452224145Sdim  }
453224145Sdim
454226633Sdim  NeedsGCBarriers_t requiresGCollection() const {
455226633Sdim    return NeedsGCBarriers_t(ObjCGCFlag);
456218893Sdim  }
457218893Sdim
458218893Sdim  llvm::Value *getAddr() const {
459218893Sdim    return Addr;
460218893Sdim  }
461218893Sdim
462218893Sdim  bool isIgnored() const {
463218893Sdim    return Addr == 0;
464218893Sdim  }
465218893Sdim
466234353Sdim  CharUnits getAlignment() const {
467234353Sdim    return CharUnits::fromQuantity(Alignment);
468234353Sdim  }
469234353Sdim
470226633Sdim  IsAliased_t isPotentiallyAliased() const {
471226633Sdim    return IsAliased_t(AliasedFlag);
472226633Sdim  }
473226633Sdim
474234353Sdim  // FIXME: Alignment?
475218893Sdim  RValue asRValue() const {
476218893Sdim    return RValue::getAggregate(getAddr(), isVolatile());
477218893Sdim  }
478234353Sdim
479226633Sdim  void setZeroed(bool V = true) { ZeroedFlag = V; }
480226633Sdim  IsZeroed_t isZeroed() const {
481226633Sdim    return IsZeroed_t(ZeroedFlag);
482218893Sdim  }
483193326Sed};
484193326Sed
485193326Sed}  // end namespace CodeGen
486193326Sed}  // end namespace clang
487193326Sed
488193326Sed#endif
489