114110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne//===----- ABI.h - ABI related declarations ---------------------*- C++ -*-===// 214110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne// 314110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne// The LLVM Compiler Infrastructure 414110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne// 514110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne// This file is distributed under the University of Illinois Open Source 614110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne// License. See LICENSE.TXT for details. 714110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne// 814110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne//===----------------------------------------------------------------------===// 92f7f5b1f5ff023cb8c4008ae53a12b09e3ea2622James Dennett/// 102f7f5b1f5ff023cb8c4008ae53a12b09e3ea2622James Dennett/// \file 112f7f5b1f5ff023cb8c4008ae53a12b09e3ea2622James Dennett/// \brief Enums/classes describing ABI related information about constructors, 122f7f5b1f5ff023cb8c4008ae53a12b09e3ea2622James Dennett/// destructors and thunks. 132f7f5b1f5ff023cb8c4008ae53a12b09e3ea2622James Dennett/// 1414110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne//===----------------------------------------------------------------------===// 1514110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne 16176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines#ifndef LLVM_CLANG_BASIC_ABI_H 17176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines#define LLVM_CLANG_BASIC_ABI_H 1814110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne 19852f65beb12a7a735b17b60856e701be14d627d4Francois Pichet#include "llvm/Support/DataTypes.h" 203ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar#include <cstring> 2114110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne 2214110477887e3dc168ffc6c191e72d705051f99ePeter Collingbournenamespace clang { 2314110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne 24af50aab0c317462129d73ae8000c6394c718598dJames Dennett/// \brief C++ constructor types. 2514110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourneenum CXXCtorType { 263ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar Ctor_Complete, ///< Complete object ctor 273ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar Ctor_Base, ///< Base object ctor 283ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar Ctor_Comdat, ///< The COMDAT used for ctors 293ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar Ctor_CopyingClosure, ///< Copying closure variant of a ctor 303ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar Ctor_DefaultClosure, ///< Default closure variant of a ctor 3114110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne}; 3214110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne 33af50aab0c317462129d73ae8000c6394c718598dJames Dennett/// \brief C++ destructor types. 3414110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourneenum CXXDtorType { 35af50aab0c317462129d73ae8000c6394c718598dJames Dennett Dtor_Deleting, ///< Deleting dtor 36af50aab0c317462129d73ae8000c6394c718598dJames Dennett Dtor_Complete, ///< Complete object dtor 37176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines Dtor_Base, ///< Base object dtor 38176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines Dtor_Comdat ///< The COMDAT used for dtors 3914110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne}; 4014110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne 41af50aab0c317462129d73ae8000c6394c718598dJames Dennett/// \brief A return adjustment. 4214110477887e3dc168ffc6c191e72d705051f99ePeter Collingbournestruct ReturnAdjustment { 43af50aab0c317462129d73ae8000c6394c718598dJames Dennett /// \brief The non-virtual adjustment from the derived object to its 4414110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne /// nearest virtual base. 4514110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne int64_t NonVirtual; 46c70cc5d90403f99ccce5cab3a6c022ad9cdcb66cTimur Iskhodzhanov 47c70cc5d90403f99ccce5cab3a6c022ad9cdcb66cTimur Iskhodzhanov /// \brief Holds the ABI-specific information about the virtual return 48c70cc5d90403f99ccce5cab3a6c022ad9cdcb66cTimur Iskhodzhanov /// adjustment, if needed. 49c70cc5d90403f99ccce5cab3a6c022ad9cdcb66cTimur Iskhodzhanov union VirtualAdjustment { 50c70cc5d90403f99ccce5cab3a6c022ad9cdcb66cTimur Iskhodzhanov // Itanium ABI 51c70cc5d90403f99ccce5cab3a6c022ad9cdcb66cTimur Iskhodzhanov struct { 52c70cc5d90403f99ccce5cab3a6c022ad9cdcb66cTimur Iskhodzhanov /// \brief The offset (in bytes), relative to the address point 53c70cc5d90403f99ccce5cab3a6c022ad9cdcb66cTimur Iskhodzhanov /// of the virtual base class offset. 54c70cc5d90403f99ccce5cab3a6c022ad9cdcb66cTimur Iskhodzhanov int64_t VBaseOffsetOffset; 55c70cc5d90403f99ccce5cab3a6c022ad9cdcb66cTimur Iskhodzhanov } Itanium; 56c70cc5d90403f99ccce5cab3a6c022ad9cdcb66cTimur Iskhodzhanov 57c70cc5d90403f99ccce5cab3a6c022ad9cdcb66cTimur Iskhodzhanov // Microsoft ABI 58c70cc5d90403f99ccce5cab3a6c022ad9cdcb66cTimur Iskhodzhanov struct { 59c70cc5d90403f99ccce5cab3a6c022ad9cdcb66cTimur Iskhodzhanov /// \brief The offset (in bytes) of the vbptr, relative to the beginning 60c70cc5d90403f99ccce5cab3a6c022ad9cdcb66cTimur Iskhodzhanov /// of the derived class. 61c70cc5d90403f99ccce5cab3a6c022ad9cdcb66cTimur Iskhodzhanov uint32_t VBPtrOffset; 62c70cc5d90403f99ccce5cab3a6c022ad9cdcb66cTimur Iskhodzhanov 63c70cc5d90403f99ccce5cab3a6c022ad9cdcb66cTimur Iskhodzhanov /// \brief Index of the virtual base in the vbtable. 64c70cc5d90403f99ccce5cab3a6c022ad9cdcb66cTimur Iskhodzhanov uint32_t VBIndex; 65c70cc5d90403f99ccce5cab3a6c022ad9cdcb66cTimur Iskhodzhanov } Microsoft; 66c70cc5d90403f99ccce5cab3a6c022ad9cdcb66cTimur Iskhodzhanov 67c70cc5d90403f99ccce5cab3a6c022ad9cdcb66cTimur Iskhodzhanov VirtualAdjustment() { 68c70cc5d90403f99ccce5cab3a6c022ad9cdcb66cTimur Iskhodzhanov memset(this, 0, sizeof(*this)); 69c70cc5d90403f99ccce5cab3a6c022ad9cdcb66cTimur Iskhodzhanov } 70c70cc5d90403f99ccce5cab3a6c022ad9cdcb66cTimur Iskhodzhanov 71c70cc5d90403f99ccce5cab3a6c022ad9cdcb66cTimur Iskhodzhanov bool Equals(const VirtualAdjustment &Other) const { 72c70cc5d90403f99ccce5cab3a6c022ad9cdcb66cTimur Iskhodzhanov return memcmp(this, &Other, sizeof(Other)) == 0; 73c70cc5d90403f99ccce5cab3a6c022ad9cdcb66cTimur Iskhodzhanov } 74c70cc5d90403f99ccce5cab3a6c022ad9cdcb66cTimur Iskhodzhanov 75c70cc5d90403f99ccce5cab3a6c022ad9cdcb66cTimur Iskhodzhanov bool isEmpty() const { 76c70cc5d90403f99ccce5cab3a6c022ad9cdcb66cTimur Iskhodzhanov VirtualAdjustment Zero; 77c70cc5d90403f99ccce5cab3a6c022ad9cdcb66cTimur Iskhodzhanov return Equals(Zero); 78c70cc5d90403f99ccce5cab3a6c022ad9cdcb66cTimur Iskhodzhanov } 79c70cc5d90403f99ccce5cab3a6c022ad9cdcb66cTimur Iskhodzhanov 80c70cc5d90403f99ccce5cab3a6c022ad9cdcb66cTimur Iskhodzhanov bool Less(const VirtualAdjustment &RHS) const { 81c70cc5d90403f99ccce5cab3a6c022ad9cdcb66cTimur Iskhodzhanov return memcmp(this, &RHS, sizeof(RHS)) < 0; 82c70cc5d90403f99ccce5cab3a6c022ad9cdcb66cTimur Iskhodzhanov } 83c70cc5d90403f99ccce5cab3a6c022ad9cdcb66cTimur Iskhodzhanov } Virtual; 8414110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne 85c70cc5d90403f99ccce5cab3a6c022ad9cdcb66cTimur Iskhodzhanov ReturnAdjustment() : NonVirtual(0) {} 8614110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne 87c70cc5d90403f99ccce5cab3a6c022ad9cdcb66cTimur Iskhodzhanov bool isEmpty() const { return !NonVirtual && Virtual.isEmpty(); } 8814110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne 8914110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne friend bool operator==(const ReturnAdjustment &LHS, 9014110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne const ReturnAdjustment &RHS) { 91c70cc5d90403f99ccce5cab3a6c022ad9cdcb66cTimur Iskhodzhanov return LHS.NonVirtual == RHS.NonVirtual && LHS.Virtual.Equals(RHS.Virtual); 9214110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne } 9314110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne 942cb17a06befb61b1434aaa991652fea4338c95d7Timur Iskhodzhanov friend bool operator!=(const ReturnAdjustment &LHS, const ReturnAdjustment &RHS) { 952cb17a06befb61b1434aaa991652fea4338c95d7Timur Iskhodzhanov return !(LHS == RHS); 962cb17a06befb61b1434aaa991652fea4338c95d7Timur Iskhodzhanov } 972cb17a06befb61b1434aaa991652fea4338c95d7Timur Iskhodzhanov 9814110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne friend bool operator<(const ReturnAdjustment &LHS, 9914110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne const ReturnAdjustment &RHS) { 10014110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne if (LHS.NonVirtual < RHS.NonVirtual) 10114110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne return true; 102c70cc5d90403f99ccce5cab3a6c022ad9cdcb66cTimur Iskhodzhanov 103c70cc5d90403f99ccce5cab3a6c022ad9cdcb66cTimur Iskhodzhanov return LHS.NonVirtual == RHS.NonVirtual && LHS.Virtual.Less(RHS.Virtual); 10414110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne } 10514110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne}; 10614110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne 107af50aab0c317462129d73ae8000c6394c718598dJames Dennett/// \brief A \c this pointer adjustment. 10814110477887e3dc168ffc6c191e72d705051f99ePeter Collingbournestruct ThisAdjustment { 109af50aab0c317462129d73ae8000c6394c718598dJames Dennett /// \brief The non-virtual adjustment from the derived object to its 11014110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne /// nearest virtual base. 11114110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne int64_t NonVirtual; 11214110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne 11358b6db76adab8dee2e64fbc300360f9b46c561baTimur Iskhodzhanov /// \brief Holds the ABI-specific information about the virtual this 11458b6db76adab8dee2e64fbc300360f9b46c561baTimur Iskhodzhanov /// adjustment, if needed. 11558b6db76adab8dee2e64fbc300360f9b46c561baTimur Iskhodzhanov union VirtualAdjustment { 11658b6db76adab8dee2e64fbc300360f9b46c561baTimur Iskhodzhanov // Itanium ABI 11758b6db76adab8dee2e64fbc300360f9b46c561baTimur Iskhodzhanov struct { 11858b6db76adab8dee2e64fbc300360f9b46c561baTimur Iskhodzhanov /// \brief The offset (in bytes), relative to the address point, 11958b6db76adab8dee2e64fbc300360f9b46c561baTimur Iskhodzhanov /// of the virtual call offset. 12058b6db76adab8dee2e64fbc300360f9b46c561baTimur Iskhodzhanov int64_t VCallOffsetOffset; 12158b6db76adab8dee2e64fbc300360f9b46c561baTimur Iskhodzhanov } Itanium; 12258b6db76adab8dee2e64fbc300360f9b46c561baTimur Iskhodzhanov 12358b6db76adab8dee2e64fbc300360f9b46c561baTimur Iskhodzhanov struct { 12458b6db76adab8dee2e64fbc300360f9b46c561baTimur Iskhodzhanov /// \brief The offset of the vtordisp (in bytes), relative to the ECX. 12558b6db76adab8dee2e64fbc300360f9b46c561baTimur Iskhodzhanov int32_t VtordispOffset; 12658b6db76adab8dee2e64fbc300360f9b46c561baTimur Iskhodzhanov 12758b6db76adab8dee2e64fbc300360f9b46c561baTimur Iskhodzhanov /// \brief The offset of the vbptr of the derived class (in bytes), 12858b6db76adab8dee2e64fbc300360f9b46c561baTimur Iskhodzhanov /// relative to the ECX after vtordisp adjustment. 12958b6db76adab8dee2e64fbc300360f9b46c561baTimur Iskhodzhanov int32_t VBPtrOffset; 13058b6db76adab8dee2e64fbc300360f9b46c561baTimur Iskhodzhanov 13158b6db76adab8dee2e64fbc300360f9b46c561baTimur Iskhodzhanov /// \brief The offset (in bytes) of the vbase offset in the vbtable. 13258b6db76adab8dee2e64fbc300360f9b46c561baTimur Iskhodzhanov int32_t VBOffsetOffset; 13358b6db76adab8dee2e64fbc300360f9b46c561baTimur Iskhodzhanov } Microsoft; 13458b6db76adab8dee2e64fbc300360f9b46c561baTimur Iskhodzhanov 13558b6db76adab8dee2e64fbc300360f9b46c561baTimur Iskhodzhanov VirtualAdjustment() { 13658b6db76adab8dee2e64fbc300360f9b46c561baTimur Iskhodzhanov memset(this, 0, sizeof(*this)); 13758b6db76adab8dee2e64fbc300360f9b46c561baTimur Iskhodzhanov } 13858b6db76adab8dee2e64fbc300360f9b46c561baTimur Iskhodzhanov 13958b6db76adab8dee2e64fbc300360f9b46c561baTimur Iskhodzhanov bool Equals(const VirtualAdjustment &Other) const { 14058b6db76adab8dee2e64fbc300360f9b46c561baTimur Iskhodzhanov return memcmp(this, &Other, sizeof(Other)) == 0; 14158b6db76adab8dee2e64fbc300360f9b46c561baTimur Iskhodzhanov } 14258b6db76adab8dee2e64fbc300360f9b46c561baTimur Iskhodzhanov 14358b6db76adab8dee2e64fbc300360f9b46c561baTimur Iskhodzhanov bool isEmpty() const { 14458b6db76adab8dee2e64fbc300360f9b46c561baTimur Iskhodzhanov VirtualAdjustment Zero; 14558b6db76adab8dee2e64fbc300360f9b46c561baTimur Iskhodzhanov return Equals(Zero); 14658b6db76adab8dee2e64fbc300360f9b46c561baTimur Iskhodzhanov } 14758b6db76adab8dee2e64fbc300360f9b46c561baTimur Iskhodzhanov 14858b6db76adab8dee2e64fbc300360f9b46c561baTimur Iskhodzhanov bool Less(const VirtualAdjustment &RHS) const { 14958b6db76adab8dee2e64fbc300360f9b46c561baTimur Iskhodzhanov return memcmp(this, &RHS, sizeof(RHS)) < 0; 15058b6db76adab8dee2e64fbc300360f9b46c561baTimur Iskhodzhanov } 15158b6db76adab8dee2e64fbc300360f9b46c561baTimur Iskhodzhanov } Virtual; 15214110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne 15358b6db76adab8dee2e64fbc300360f9b46c561baTimur Iskhodzhanov ThisAdjustment() : NonVirtual(0) { } 15414110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne 15558b6db76adab8dee2e64fbc300360f9b46c561baTimur Iskhodzhanov bool isEmpty() const { return !NonVirtual && Virtual.isEmpty(); } 15614110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne 15714110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne friend bool operator==(const ThisAdjustment &LHS, 15814110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne const ThisAdjustment &RHS) { 15958b6db76adab8dee2e64fbc300360f9b46c561baTimur Iskhodzhanov return LHS.NonVirtual == RHS.NonVirtual && LHS.Virtual.Equals(RHS.Virtual); 16014110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne } 1612cb17a06befb61b1434aaa991652fea4338c95d7Timur Iskhodzhanov 1622cb17a06befb61b1434aaa991652fea4338c95d7Timur Iskhodzhanov friend bool operator!=(const ThisAdjustment &LHS, const ThisAdjustment &RHS) { 1632cb17a06befb61b1434aaa991652fea4338c95d7Timur Iskhodzhanov return !(LHS == RHS); 1642cb17a06befb61b1434aaa991652fea4338c95d7Timur Iskhodzhanov } 16514110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne 16614110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne friend bool operator<(const ThisAdjustment &LHS, 16714110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne const ThisAdjustment &RHS) { 16814110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne if (LHS.NonVirtual < RHS.NonVirtual) 16914110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne return true; 17014110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne 17158b6db76adab8dee2e64fbc300360f9b46c561baTimur Iskhodzhanov return LHS.NonVirtual == RHS.NonVirtual && LHS.Virtual.Less(RHS.Virtual); 17214110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne } 17314110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne}; 17414110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne 1752cb17a06befb61b1434aaa991652fea4338c95d7Timur Iskhodzhanovclass CXXMethodDecl; 1762cb17a06befb61b1434aaa991652fea4338c95d7Timur Iskhodzhanov 177af50aab0c317462129d73ae8000c6394c718598dJames Dennett/// \brief The \c this pointer adjustment as well as an optional return 17814110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne/// adjustment for a thunk. 17914110477887e3dc168ffc6c191e72d705051f99ePeter Collingbournestruct ThunkInfo { 180af50aab0c317462129d73ae8000c6394c718598dJames Dennett /// \brief The \c this pointer adjustment. 18114110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne ThisAdjustment This; 18214110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne 183af50aab0c317462129d73ae8000c6394c718598dJames Dennett /// \brief The return adjustment. 18414110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne ReturnAdjustment Return; 18514110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne 1862cb17a06befb61b1434aaa991652fea4338c95d7Timur Iskhodzhanov /// \brief Holds a pointer to the overridden method this thunk is for, 1872cb17a06befb61b1434aaa991652fea4338c95d7Timur Iskhodzhanov /// if needed by the ABI to distinguish different thunks with equal 1882cb17a06befb61b1434aaa991652fea4338c95d7Timur Iskhodzhanov /// adjustments. Otherwise, null. 1892cb17a06befb61b1434aaa991652fea4338c95d7Timur Iskhodzhanov /// CAUTION: In the unlikely event you need to sort ThunkInfos, consider using 1902cb17a06befb61b1434aaa991652fea4338c95d7Timur Iskhodzhanov /// an ABI-specific comparator. 1912cb17a06befb61b1434aaa991652fea4338c95d7Timur Iskhodzhanov const CXXMethodDecl *Method; 19214110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne 1936bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines ThunkInfo() : Method(nullptr) { } 19414110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne 1952cb17a06befb61b1434aaa991652fea4338c95d7Timur Iskhodzhanov ThunkInfo(const ThisAdjustment &This, const ReturnAdjustment &Return, 1966bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines const CXXMethodDecl *Method = nullptr) 1972cb17a06befb61b1434aaa991652fea4338c95d7Timur Iskhodzhanov : This(This), Return(Return), Method(Method) {} 1980ac66c03c01ae95bc34cca71067ba8dd65e06a1dTimur Iskhodzhanov 1992cb17a06befb61b1434aaa991652fea4338c95d7Timur Iskhodzhanov friend bool operator==(const ThunkInfo &LHS, const ThunkInfo &RHS) { 2002cb17a06befb61b1434aaa991652fea4338c95d7Timur Iskhodzhanov return LHS.This == RHS.This && LHS.Return == RHS.Return && 2012cb17a06befb61b1434aaa991652fea4338c95d7Timur Iskhodzhanov LHS.Method == RHS.Method; 20214110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne } 20314110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne 2046bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines bool isEmpty() const { 2056bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines return This.isEmpty() && Return.isEmpty() && Method == nullptr; 2066bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines } 20714110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne}; 20814110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne 20914110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne} // end namespace clang 21014110477887e3dc168ffc6c191e72d705051f99ePeter Collingbourne 211176edba5311f6eff0cad2631449885ddf4fbc9eaStephen Hines#endif 212