diff options
Diffstat (limited to 'clang/include/clang')
369 files changed, 124617 insertions, 0 deletions
diff --git a/clang/include/clang/ARCMigrate/ARCMT.h b/clang/include/clang/ARCMigrate/ARCMT.h new file mode 100644 index 0000000..86a6cbb --- /dev/null +++ b/clang/include/clang/ARCMigrate/ARCMT.h @@ -0,0 +1,122 @@ +//===-- ARCMT.h - ARC Migration Rewriter ------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ARCMIGRATE_ARCMT_H +#define LLVM_CLANG_ARCMIGRATE_ARCMT_H + +#include "clang/ARCMigrate/FileRemapper.h" +#include "clang/Frontend/CompilerInvocation.h" + +namespace clang { + class ASTContext; + class DiagnosticConsumer; + +namespace arcmt { + class MigrationPass; + +/// \brief Creates an AST with the provided CompilerInvocation but with these +/// changes: +/// -if a PCH/PTH is set, the original header is used instead +/// -Automatic Reference Counting mode is enabled +/// +/// It then checks the AST and produces errors/warning for ARC migration issues +/// that the user needs to handle manually. +/// +/// \param emitPremigrationARCErrors if true all ARC errors will get emitted +/// even if the migrator can fix them, but the function will still return false +/// if all ARC errors can be fixed. +/// +/// \param plistOut if non-empty, it is the file path to store the plist with +/// the pre-migration ARC diagnostics. +/// +/// \returns false if no error is produced, true otherwise. +bool checkForManualIssues(CompilerInvocation &CI, + const FrontendInputFile &Input, + DiagnosticConsumer *DiagClient, + bool emitPremigrationARCErrors = false, + StringRef plistOut = StringRef()); + +/// \brief Works similar to checkForManualIssues but instead of checking, it +/// applies automatic modifications to source files to conform to ARC. +/// +/// \returns false if no error is produced, true otherwise. +bool applyTransformations(CompilerInvocation &origCI, + const FrontendInputFile &Input, + DiagnosticConsumer *DiagClient); + +/// \brief Applies automatic modifications and produces temporary files +/// and metadata into the \arg outputDir path. +/// +/// \param emitPremigrationARCErrors if true all ARC errors will get emitted +/// even if the migrator can fix them, but the function will still return false +/// if all ARC errors can be fixed. +/// +/// \param plistOut if non-empty, it is the file path to store the plist with +/// the pre-migration ARC diagnostics. +/// +/// \returns false if no error is produced, true otherwise. +bool migrateWithTemporaryFiles(CompilerInvocation &origCI, + const FrontendInputFile &Input, + DiagnosticConsumer *DiagClient, + StringRef outputDir, + bool emitPremigrationARCErrors, + StringRef plistOut); + +/// \brief Get the set of file remappings from the \arg outputDir path that +/// migrateWithTemporaryFiles produced. +/// +/// \returns false if no error is produced, true otherwise. +bool getFileRemappings(std::vector<std::pair<std::string,std::string> > &remap, + StringRef outputDir, + DiagnosticConsumer *DiagClient); + +/// \brief Get the set of file remappings from a list of files with remapping +/// info. +/// +/// \returns false if no error is produced, true otherwise. +bool getFileRemappingsFromFileList( + std::vector<std::pair<std::string,std::string> > &remap, + ArrayRef<StringRef> remapFiles, + DiagnosticConsumer *DiagClient); + +typedef void (*TransformFn)(MigrationPass &pass); + +std::vector<TransformFn> getAllTransformations(LangOptions::GCMode OrigGCMode, + bool NoFinalizeRemoval); + +class MigrationProcess { + CompilerInvocation OrigCI; + DiagnosticConsumer *DiagClient; + FileRemapper Remapper; + +public: + MigrationProcess(const CompilerInvocation &CI, DiagnosticConsumer *diagClient, + StringRef outputDir = StringRef()); + + class RewriteListener { + public: + virtual ~RewriteListener(); + + virtual void start(ASTContext &Ctx) { } + virtual void finish() { } + + virtual void insert(SourceLocation loc, StringRef text) { } + virtual void remove(CharSourceRange range) { } + }; + + bool applyTransform(TransformFn trans, RewriteListener *listener = 0); + + FileRemapper &getRemapper() { return Remapper; } +}; + +} // end namespace arcmt + +} // end namespace clang + +#endif diff --git a/clang/include/clang/ARCMigrate/ARCMTActions.h b/clang/include/clang/ARCMigrate/ARCMTActions.h new file mode 100644 index 0000000..e075252 --- /dev/null +++ b/clang/include/clang/ARCMigrate/ARCMTActions.h @@ -0,0 +1,77 @@ +//===--- ARCMTActions.h - ARC Migrate Tool Frontend Actions -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ARCMIGRATE_ARCMT_ACTION_H +#define LLVM_CLANG_ARCMIGRATE_ARCMT_ACTION_H + +#include "clang/Frontend/FrontendAction.h" +#include "clang/ARCMigrate/FileRemapper.h" +#include "llvm/ADT/OwningPtr.h" + +namespace clang { +namespace arcmt { + +class CheckAction : public WrapperFrontendAction { +protected: + virtual bool BeginInvocation(CompilerInstance &CI); + +public: + CheckAction(FrontendAction *WrappedAction); +}; + +class ModifyAction : public WrapperFrontendAction { +protected: + virtual bool BeginInvocation(CompilerInstance &CI); + +public: + ModifyAction(FrontendAction *WrappedAction); +}; + +class MigrateSourceAction : public ASTFrontendAction { + FileRemapper Remapper; +protected: + virtual bool BeginInvocation(CompilerInstance &CI); + virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, + StringRef InFile); +}; + +class MigrateAction : public WrapperFrontendAction { + std::string MigrateDir; + std::string PlistOut; + bool EmitPremigrationARCErros; +protected: + virtual bool BeginInvocation(CompilerInstance &CI); + +public: + MigrateAction(FrontendAction *WrappedAction, StringRef migrateDir, + StringRef plistOut, + bool emitPremigrationARCErrors); +}; + +/// \brief Migrates to modern ObjC syntax. +class ObjCMigrateAction : public WrapperFrontendAction { + std::string MigrateDir; + bool MigrateLiterals; + bool MigrateSubscripting; + FileRemapper Remapper; + CompilerInstance *CompInst; +public: + ObjCMigrateAction(FrontendAction *WrappedAction, StringRef migrateDir, + bool migrateLiterals, + bool migrateSubscripting); + +protected: + virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,StringRef InFile); + virtual bool BeginInvocation(CompilerInstance &CI); +}; + +} +} + +#endif diff --git a/clang/include/clang/ARCMigrate/FileRemapper.h b/clang/include/clang/ARCMigrate/FileRemapper.h new file mode 100644 index 0000000..fe7cfad --- /dev/null +++ b/clang/include/clang/ARCMigrate/FileRemapper.h @@ -0,0 +1,80 @@ +//===-- FileRemapper.h - File Remapping Helper ------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ARCMIGRATE_FILEREMAPPER_H +#define LLVM_CLANG_ARCMIGRATE_FILEREMAPPER_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringRef.h" + +namespace llvm { + class MemoryBuffer; +} + +namespace clang { + class FileManager; + class FileEntry; + class DiagnosticsEngine; + class PreprocessorOptions; + +namespace arcmt { + +class FileRemapper { + // FIXME: Reuse the same FileManager for multiple ASTContexts. + OwningPtr<FileManager> FileMgr; + + typedef llvm::PointerUnion<const FileEntry *, llvm::MemoryBuffer *> Target; + typedef llvm::DenseMap<const FileEntry *, Target> MappingsTy; + MappingsTy FromToMappings; + + llvm::DenseMap<const FileEntry *, const FileEntry *> ToFromMappings; + +public: + FileRemapper(); + ~FileRemapper(); + + bool initFromDisk(StringRef outputDir, DiagnosticsEngine &Diag, + bool ignoreIfFilesChanged); + bool initFromFile(StringRef filePath, DiagnosticsEngine &Diag, + bool ignoreIfFilesChanged); + bool flushToDisk(StringRef outputDir, DiagnosticsEngine &Diag); + bool flushToFile(StringRef outputPath, DiagnosticsEngine &Diag); + + bool overwriteOriginal(DiagnosticsEngine &Diag, + StringRef outputDir = StringRef()); + + void remap(StringRef filePath, llvm::MemoryBuffer *memBuf); + void remap(StringRef filePath, StringRef newPath); + + void applyMappings(PreprocessorOptions &PPOpts) const; + + void transferMappingsAndClear(PreprocessorOptions &PPOpts); + + void clear(StringRef outputDir = StringRef()); + +private: + void remap(const FileEntry *file, llvm::MemoryBuffer *memBuf); + void remap(const FileEntry *file, const FileEntry *newfile); + + const FileEntry *getOriginalFile(StringRef filePath); + void resetTarget(Target &targ); + + bool report(const Twine &err, DiagnosticsEngine &Diag); + + std::string getRemapInfoFile(StringRef outputDir); +}; + +} // end namespace arcmt + +} // end namespace clang + +#endif diff --git a/clang/include/clang/AST/.#Expr_flymake.h b/clang/include/clang/AST/.#Expr_flymake.h new file mode 120000 index 0000000..235903b --- /dev/null +++ b/clang/include/clang/AST/.#Expr_flymake.h @@ -0,0 +1 @@ +carlo@pc-4w14-0.cs.usyd.edu.au.1585:1347012043
\ No newline at end of file diff --git a/clang/include/clang/AST/APValue.h b/clang/include/clang/AST/APValue.h new file mode 100644 index 0000000..1b6e90c --- /dev/null +++ b/clang/include/clang/AST/APValue.h @@ -0,0 +1,446 @@ +//===--- APValue.h - Union class for APFloat/APSInt/Complex -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the APValue class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_APVALUE_H +#define LLVM_CLANG_AST_APVALUE_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/APSInt.h" +#include "llvm/ADT/APFloat.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/PointerUnion.h" + +namespace clang { + class AddrLabelExpr; + class ASTContext; + class CharUnits; + class DiagnosticBuilder; + class Expr; + class FieldDecl; + class Decl; + class ValueDecl; + class CXXRecordDecl; + class QualType; + +/// APValue - This class implements a discriminated union of [uninitialized] +/// [APSInt] [APFloat], [Complex APSInt] [Complex APFloat], [Expr + Offset], +/// [Vector: N * APValue], [Array: N * APValue] +class APValue { + typedef llvm::APSInt APSInt; + typedef llvm::APFloat APFloat; +public: + enum ValueKind { + Uninitialized, + Int, + Float, + ComplexInt, + ComplexFloat, + LValue, + Vector, + Array, + Struct, + Union, + MemberPointer, + AddrLabelDiff + }; + typedef llvm::PointerUnion<const ValueDecl *, const Expr *> LValueBase; + typedef llvm::PointerIntPair<const Decl *, 1, bool> BaseOrMemberType; + union LValuePathEntry { + /// BaseOrMember - The FieldDecl or CXXRecordDecl indicating the next item + /// in the path. An opaque value of type BaseOrMemberType. + void *BaseOrMember; + /// ArrayIndex - The array index of the next item in the path. + uint64_t ArrayIndex; + }; + struct NoLValuePath {}; + struct UninitArray {}; + struct UninitStruct {}; +private: + ValueKind Kind; + + struct ComplexAPSInt { + APSInt Real, Imag; + ComplexAPSInt() : Real(1), Imag(1) {} + }; + struct ComplexAPFloat { + APFloat Real, Imag; + ComplexAPFloat() : Real(0.0), Imag(0.0) {} + }; + struct LV; + struct Vec { + APValue *Elts; + unsigned NumElts; + Vec() : Elts(0), NumElts(0) {} + ~Vec() { delete[] Elts; } + }; + struct Arr { + APValue *Elts; + unsigned NumElts, ArrSize; + Arr(unsigned NumElts, unsigned ArrSize); + ~Arr(); + }; + struct StructData { + APValue *Elts; + unsigned NumBases; + unsigned NumFields; + StructData(unsigned NumBases, unsigned NumFields); + ~StructData(); + }; + struct UnionData { + const FieldDecl *Field; + APValue *Value; + UnionData(); + ~UnionData(); + }; + struct AddrLabelDiffData { + const AddrLabelExpr* LHSExpr; + const AddrLabelExpr* RHSExpr; + }; + struct MemberPointerData; + + enum { + MaxSize = (sizeof(ComplexAPSInt) > sizeof(ComplexAPFloat) ? + sizeof(ComplexAPSInt) : sizeof(ComplexAPFloat)) + }; + + union { + void *Aligner; + char Data[MaxSize]; + }; + +public: + APValue() : Kind(Uninitialized) {} + explicit APValue(const APSInt &I) : Kind(Uninitialized) { + MakeInt(); setInt(I); + } + explicit APValue(const APFloat &F) : Kind(Uninitialized) { + MakeFloat(); setFloat(F); + } + explicit APValue(const APValue *E, unsigned N) : Kind(Uninitialized) { + MakeVector(); setVector(E, N); + } + APValue(const APSInt &R, const APSInt &I) : Kind(Uninitialized) { + MakeComplexInt(); setComplexInt(R, I); + } + APValue(const APFloat &R, const APFloat &I) : Kind(Uninitialized) { + MakeComplexFloat(); setComplexFloat(R, I); + } + APValue(const APValue &RHS); + APValue(LValueBase B, const CharUnits &O, NoLValuePath N, unsigned CallIndex) + : Kind(Uninitialized) { + MakeLValue(); setLValue(B, O, N, CallIndex); + } + APValue(LValueBase B, const CharUnits &O, ArrayRef<LValuePathEntry> Path, + bool OnePastTheEnd, unsigned CallIndex) + : Kind(Uninitialized) { + MakeLValue(); setLValue(B, O, Path, OnePastTheEnd, CallIndex); + } + APValue(UninitArray, unsigned InitElts, unsigned Size) : Kind(Uninitialized) { + MakeArray(InitElts, Size); + } + APValue(UninitStruct, unsigned B, unsigned M) : Kind(Uninitialized) { + MakeStruct(B, M); + } + explicit APValue(const FieldDecl *D, const APValue &V = APValue()) + : Kind(Uninitialized) { + MakeUnion(); setUnion(D, V); + } + APValue(const ValueDecl *Member, bool IsDerivedMember, + ArrayRef<const CXXRecordDecl*> Path) : Kind(Uninitialized) { + MakeMemberPointer(Member, IsDerivedMember, Path); + } + APValue(const AddrLabelExpr* LHSExpr, const AddrLabelExpr* RHSExpr) + : Kind(Uninitialized) { + MakeAddrLabelDiff(); setAddrLabelDiff(LHSExpr, RHSExpr); + } + + ~APValue() { + MakeUninit(); + } + + /// \brief Swaps the contents of this and the given APValue. + void swap(APValue &RHS); + + ValueKind getKind() const { return Kind; } + bool isUninit() const { return Kind == Uninitialized; } + bool isInt() const { return Kind == Int; } + bool isFloat() const { return Kind == Float; } + bool isComplexInt() const { return Kind == ComplexInt; } + bool isComplexFloat() const { return Kind == ComplexFloat; } + bool isLValue() const { return Kind == LValue; } + bool isVector() const { return Kind == Vector; } + bool isArray() const { return Kind == Array; } + bool isStruct() const { return Kind == Struct; } + bool isUnion() const { return Kind == Union; } + bool isMemberPointer() const { return Kind == MemberPointer; } + bool isAddrLabelDiff() const { return Kind == AddrLabelDiff; } + + void dump() const; + void dump(raw_ostream &OS) const; + + void printPretty(raw_ostream &OS, ASTContext &Ctx, QualType Ty) const; + std::string getAsString(ASTContext &Ctx, QualType Ty) const; + + APSInt &getInt() { + assert(isInt() && "Invalid accessor"); + return *(APSInt*)(char*)Data; + } + const APSInt &getInt() const { + return const_cast<APValue*>(this)->getInt(); + } + + APFloat &getFloat() { + assert(isFloat() && "Invalid accessor"); + return *(APFloat*)(char*)Data; + } + const APFloat &getFloat() const { + return const_cast<APValue*>(this)->getFloat(); + } + + APSInt &getComplexIntReal() { + assert(isComplexInt() && "Invalid accessor"); + return ((ComplexAPSInt*)(char*)Data)->Real; + } + const APSInt &getComplexIntReal() const { + return const_cast<APValue*>(this)->getComplexIntReal(); + } + + APSInt &getComplexIntImag() { + assert(isComplexInt() && "Invalid accessor"); + return ((ComplexAPSInt*)(char*)Data)->Imag; + } + const APSInt &getComplexIntImag() const { + return const_cast<APValue*>(this)->getComplexIntImag(); + } + + APFloat &getComplexFloatReal() { + assert(isComplexFloat() && "Invalid accessor"); + return ((ComplexAPFloat*)(char*)Data)->Real; + } + const APFloat &getComplexFloatReal() const { + return const_cast<APValue*>(this)->getComplexFloatReal(); + } + + APFloat &getComplexFloatImag() { + assert(isComplexFloat() && "Invalid accessor"); + return ((ComplexAPFloat*)(char*)Data)->Imag; + } + const APFloat &getComplexFloatImag() const { + return const_cast<APValue*>(this)->getComplexFloatImag(); + } + + const LValueBase getLValueBase() const; + CharUnits &getLValueOffset(); + const CharUnits &getLValueOffset() const { + return const_cast<APValue*>(this)->getLValueOffset(); + } + bool isLValueOnePastTheEnd() const; + bool hasLValuePath() const; + ArrayRef<LValuePathEntry> getLValuePath() const; + unsigned getLValueCallIndex() const; + + APValue &getVectorElt(unsigned I) { + assert(isVector() && "Invalid accessor"); + assert(I < getVectorLength() && "Index out of range"); + return ((Vec*)(char*)Data)->Elts[I]; + } + const APValue &getVectorElt(unsigned I) const { + return const_cast<APValue*>(this)->getVectorElt(I); + } + unsigned getVectorLength() const { + assert(isVector() && "Invalid accessor"); + return ((const Vec*)(const void *)Data)->NumElts; + } + + APValue &getArrayInitializedElt(unsigned I) { + assert(isArray() && "Invalid accessor"); + assert(I < getArrayInitializedElts() && "Index out of range"); + return ((Arr*)(char*)Data)->Elts[I]; + } + const APValue &getArrayInitializedElt(unsigned I) const { + return const_cast<APValue*>(this)->getArrayInitializedElt(I); + } + bool hasArrayFiller() const { + return getArrayInitializedElts() != getArraySize(); + } + APValue &getArrayFiller() { + assert(isArray() && "Invalid accessor"); + assert(hasArrayFiller() && "No array filler"); + return ((Arr*)(char*)Data)->Elts[getArrayInitializedElts()]; + } + const APValue &getArrayFiller() const { + return const_cast<APValue*>(this)->getArrayFiller(); + } + unsigned getArrayInitializedElts() const { + assert(isArray() && "Invalid accessor"); + return ((const Arr*)(const void *)Data)->NumElts; + } + unsigned getArraySize() const { + assert(isArray() && "Invalid accessor"); + return ((const Arr*)(const void *)Data)->ArrSize; + } + + unsigned getStructNumBases() const { + assert(isStruct() && "Invalid accessor"); + return ((const StructData*)(const char*)Data)->NumBases; + } + unsigned getStructNumFields() const { + assert(isStruct() && "Invalid accessor"); + return ((const StructData*)(const char*)Data)->NumFields; + } + APValue &getStructBase(unsigned i) { + assert(isStruct() && "Invalid accessor"); + return ((StructData*)(char*)Data)->Elts[i]; + } + APValue &getStructField(unsigned i) { + assert(isStruct() && "Invalid accessor"); + return ((StructData*)(char*)Data)->Elts[getStructNumBases() + i]; + } + const APValue &getStructBase(unsigned i) const { + return const_cast<APValue*>(this)->getStructBase(i); + } + const APValue &getStructField(unsigned i) const { + return const_cast<APValue*>(this)->getStructField(i); + } + + const FieldDecl *getUnionField() const { + assert(isUnion() && "Invalid accessor"); + return ((const UnionData*)(const char*)Data)->Field; + } + APValue &getUnionValue() { + assert(isUnion() && "Invalid accessor"); + return *((UnionData*)(char*)Data)->Value; + } + const APValue &getUnionValue() const { + return const_cast<APValue*>(this)->getUnionValue(); + } + + const ValueDecl *getMemberPointerDecl() const; + bool isMemberPointerToDerivedMember() const; + ArrayRef<const CXXRecordDecl*> getMemberPointerPath() const; + + const AddrLabelExpr* getAddrLabelDiffLHS() const { + assert(isAddrLabelDiff() && "Invalid accessor"); + return ((const AddrLabelDiffData*)(const char*)Data)->LHSExpr; + } + const AddrLabelExpr* getAddrLabelDiffRHS() const { + assert(isAddrLabelDiff() && "Invalid accessor"); + return ((const AddrLabelDiffData*)(const char*)Data)->RHSExpr; + } + + void setInt(const APSInt &I) { + assert(isInt() && "Invalid accessor"); + *(APSInt*)(char*)Data = I; + } + void setFloat(const APFloat &F) { + assert(isFloat() && "Invalid accessor"); + *(APFloat*)(char*)Data = F; + } + void setVector(const APValue *E, unsigned N) { + assert(isVector() && "Invalid accessor"); + ((Vec*)(char*)Data)->Elts = new APValue[N]; + ((Vec*)(char*)Data)->NumElts = N; + for (unsigned i = 0; i != N; ++i) + ((Vec*)(char*)Data)->Elts[i] = E[i]; + } + void setComplexInt(const APSInt &R, const APSInt &I) { + assert(R.getBitWidth() == I.getBitWidth() && + "Invalid complex int (type mismatch)."); + assert(isComplexInt() && "Invalid accessor"); + ((ComplexAPSInt*)(char*)Data)->Real = R; + ((ComplexAPSInt*)(char*)Data)->Imag = I; + } + void setComplexFloat(const APFloat &R, const APFloat &I) { + assert(&R.getSemantics() == &I.getSemantics() && + "Invalid complex float (type mismatch)."); + assert(isComplexFloat() && "Invalid accessor"); + ((ComplexAPFloat*)(char*)Data)->Real = R; + ((ComplexAPFloat*)(char*)Data)->Imag = I; + } + void setLValue(LValueBase B, const CharUnits &O, NoLValuePath, + unsigned CallIndex); + void setLValue(LValueBase B, const CharUnits &O, + ArrayRef<LValuePathEntry> Path, bool OnePastTheEnd, + unsigned CallIndex); + void setUnion(const FieldDecl *Field, const APValue &Value) { + assert(isUnion() && "Invalid accessor"); + ((UnionData*)(char*)Data)->Field = Field; + *((UnionData*)(char*)Data)->Value = Value; + } + void setAddrLabelDiff(const AddrLabelExpr* LHSExpr, + const AddrLabelExpr* RHSExpr) { + ((AddrLabelDiffData*)(char*)Data)->LHSExpr = LHSExpr; + ((AddrLabelDiffData*)(char*)Data)->RHSExpr = RHSExpr; + } + + /// Assign by swapping from a copy of the RHS. + APValue &operator=(APValue RHS) { + swap(RHS); + return *this; + } + +private: + void DestroyDataAndMakeUninit(); + void MakeUninit() { + if (Kind != Uninitialized) + DestroyDataAndMakeUninit(); + } + void MakeInt() { + assert(isUninit() && "Bad state change"); + new ((void*)Data) APSInt(1); + Kind = Int; + } + void MakeFloat() { + assert(isUninit() && "Bad state change"); + new ((void*)(char*)Data) APFloat(0.0); + Kind = Float; + } + void MakeVector() { + assert(isUninit() && "Bad state change"); + new ((void*)(char*)Data) Vec(); + Kind = Vector; + } + void MakeComplexInt() { + assert(isUninit() && "Bad state change"); + new ((void*)(char*)Data) ComplexAPSInt(); + Kind = ComplexInt; + } + void MakeComplexFloat() { + assert(isUninit() && "Bad state change"); + new ((void*)(char*)Data) ComplexAPFloat(); + Kind = ComplexFloat; + } + void MakeLValue(); + void MakeArray(unsigned InitElts, unsigned Size); + void MakeStruct(unsigned B, unsigned M) { + assert(isUninit() && "Bad state change"); + new ((void*)(char*)Data) StructData(B, M); + Kind = Struct; + } + void MakeUnion() { + assert(isUninit() && "Bad state change"); + new ((void*)(char*)Data) UnionData(); + Kind = Union; + } + void MakeMemberPointer(const ValueDecl *Member, bool IsDerivedMember, + ArrayRef<const CXXRecordDecl*> Path); + void MakeAddrLabelDiff() { + assert(isUninit() && "Bad state change"); + new ((void*)(char*)Data) AddrLabelDiffData(); + Kind = AddrLabelDiff; + } +}; + +} // end namespace clang. + +#endif diff --git a/clang/include/clang/AST/AST.h b/clang/include/clang/AST/AST.h new file mode 100644 index 0000000..164c5fb --- /dev/null +++ b/clang/include/clang/AST/AST.h @@ -0,0 +1,28 @@ +//===--- AST.h - "Umbrella" header for AST library --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the interface to the AST classes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_AST_H +#define LLVM_CLANG_AST_AST_H + +// This header exports all AST interfaces. +#include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprObjC.h" +#include "clang/AST/Type.h" +#include "clang/AST/StmtVisitor.h" + +#endif diff --git a/clang/include/clang/AST/ASTConsumer.h b/clang/include/clang/AST/ASTConsumer.h new file mode 100644 index 0000000..69a3866 --- /dev/null +++ b/clang/include/clang/AST/ASTConsumer.h @@ -0,0 +1,128 @@ +//===--- ASTConsumer.h - Abstract interface for reading ASTs ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ASTConsumer class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_ASTCONSUMER_H +#define LLVM_CLANG_AST_ASTCONSUMER_H + +namespace clang { + class ASTContext; + class CXXRecordDecl; + class DeclGroupRef; + class HandleTagDeclDefinition; + class ASTMutationListener; + class ASTDeserializationListener; // layering violation because void* is ugly + class SemaConsumer; // layering violation required for safe SemaConsumer + class TagDecl; + class VarDecl; + class FunctionDecl; + +/// ASTConsumer - This is an abstract interface that should be implemented by +/// clients that read ASTs. This abstraction layer allows the client to be +/// independent of the AST producer (e.g. parser vs AST dump file reader, etc). +class ASTConsumer { + /// \brief Whether this AST consumer also requires information about + /// semantic analysis. + bool SemaConsumer; + + friend class SemaConsumer; + +public: + ASTConsumer() : SemaConsumer(false) { } + + virtual ~ASTConsumer() {} + + /// Initialize - This is called to initialize the consumer, providing the + /// ASTContext. + virtual void Initialize(ASTContext &Context) {} + + /// HandleTopLevelDecl - Handle the specified top-level declaration. This is + /// called by the parser to process every top-level Decl*. Note that D can be + /// the head of a chain of Decls (e.g. for `int a, b` the chain will have two + /// elements). Use Decl::getNextDeclarator() to walk the chain. + /// + /// \returns true to continue parsing, or false to abort parsing. + virtual bool HandleTopLevelDecl(DeclGroupRef D); + + /// HandleInterestingDecl - Handle the specified interesting declaration. This + /// is called by the AST reader when deserializing things that might interest + /// the consumer. The default implementation forwards to HandleTopLevelDecl. + virtual void HandleInterestingDecl(DeclGroupRef D); + + /// HandleTranslationUnit - This method is called when the ASTs for entire + /// translation unit have been parsed. + virtual void HandleTranslationUnit(ASTContext &Ctx) {} + + /// HandleTagDeclDefinition - This callback is invoked each time a TagDecl + /// (e.g. struct, union, enum, class) is completed. This allows the client to + /// hack on the type, which can occur at any point in the file (because these + /// can be defined in declspecs). + virtual void HandleTagDeclDefinition(TagDecl *D) {} + + /// \brief Invoked when a function is implicitly instantiated. + /// Note that at this point point it does not have a body, its body is + /// instantiated at the end of the translation unit and passed to + /// HandleTopLevelDecl. + virtual void HandleCXXImplicitFunctionInstantiation(FunctionDecl *D) {} + + /// \brief Handle the specified top-level declaration that occurred inside + /// and ObjC container. + /// The default implementation ignored them. + virtual void HandleTopLevelDeclInObjCContainer(DeclGroupRef D); + + /// CompleteTentativeDefinition - Callback invoked at the end of a translation + /// unit to notify the consumer that the given tentative definition should be + /// completed. + /// + /// The variable declaration itself will be a tentative + /// definition. If it had an incomplete array type, its type will + /// have already been changed to an array of size 1. However, the + /// declaration remains a tentative definition and has not been + /// modified by the introduction of an implicit zero initializer. + virtual void CompleteTentativeDefinition(VarDecl *D) {} + + /// HandleCXXStaticMemberVarInstantiation - Tell the consumer that this + // variable has been instantiated. + virtual void HandleCXXStaticMemberVarInstantiation(VarDecl *D) {} + + /// \brief Callback involved at the end of a translation unit to + /// notify the consumer that a vtable for the given C++ class is + /// required. + /// + /// \param RD The class whose vtable was used. + /// + /// \param DefinitionRequired Whether a definition of this vtable is + /// required in this translation unit; otherwise, it is only needed if + /// it was actually used. + virtual void HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired) {} + + /// \brief If the consumer is interested in entities getting modified after + /// their initial creation, it should return a pointer to + /// an ASTMutationListener here. + virtual ASTMutationListener *GetASTMutationListener() { return 0; } + + /// \brief If the consumer is interested in entities being deserialized from + /// AST files, it should return a pointer to a ASTDeserializationListener here + virtual ASTDeserializationListener *GetASTDeserializationListener() { + return 0; + } + + /// PrintStats - If desired, print any statistics. + virtual void PrintStats() {} + + // Support isa/cast/dyn_cast + static bool classof(const ASTConsumer *) { return true; } +}; + +} // end namespace clang. + +#endif diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h new file mode 100644 index 0000000..96e41c5 --- /dev/null +++ b/clang/include/clang/AST/ASTContext.h @@ -0,0 +1,1998 @@ +//===--- ASTContext.h - Context to hold long-lived AST nodes ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ASTContext interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_ASTCONTEXT_H +#define LLVM_CLANG_AST_ASTCONTEXT_H + +#include "clang/Basic/AddressSpaces.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/OperatorKinds.h" +#include "clang/Basic/PartialDiagnostic.h" +#include "clang/Basic/VersionTuple.h" +#include "clang/AST/Decl.h" +#include "clang/AST/LambdaMangleContext.h" +#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/PrettyPrinter.h" +#include "clang/AST/TemplateName.h" +#include "clang/AST/Type.h" +#include "clang/AST/CanonicalType.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/TinyPtrVector.h" +#include "llvm/Support/Allocator.h" +#include <vector> + +namespace llvm { + struct fltSemantics; +} + +namespace clang { + class FileManager; + class ASTRecordLayout; + class BlockExpr; + class CharUnits; + class DiagnosticsEngine; + class Expr; + class ExternalASTSource; + class ASTMutationListener; + class IdentifierTable; + class SelectorTable; + class SourceManager; + class TargetInfo; + class CXXABI; + // Decls + class DeclContext; + class CXXConversionDecl; + class CXXMethodDecl; + class CXXRecordDecl; + class Decl; + class FieldDecl; + class MangleContext; + class ObjCIvarDecl; + class ObjCIvarRefExpr; + class ObjCPropertyDecl; + class ParmVarDecl; + class RecordDecl; + class StoredDeclsMap; + class TagDecl; + class TemplateTemplateParmDecl; + class TemplateTypeParmDecl; + class TranslationUnitDecl; + class TypeDecl; + class TypedefNameDecl; + class UsingDecl; + class UsingShadowDecl; + class UnresolvedSetIterator; + + namespace Builtin { class Context; } + +/// ASTContext - This class holds long-lived AST nodes (such as types and +/// decls) that can be referred to throughout the semantic analysis of a file. +class ASTContext : public RefCountedBase<ASTContext> { + ASTContext &this_() { return *this; } + + mutable std::vector<Type*> Types; + mutable llvm::FoldingSet<ExtQuals> ExtQualNodes; + mutable llvm::FoldingSet<ComplexType> ComplexTypes; + mutable llvm::FoldingSet<PointerType> PointerTypes; + mutable llvm::FoldingSet<BlockPointerType> BlockPointerTypes; + mutable llvm::FoldingSet<LValueReferenceType> LValueReferenceTypes; + mutable llvm::FoldingSet<RValueReferenceType> RValueReferenceTypes; + mutable llvm::FoldingSet<MemberPointerType> MemberPointerTypes; + mutable llvm::FoldingSet<ConstantArrayType> ConstantArrayTypes; + mutable llvm::FoldingSet<IncompleteArrayType> IncompleteArrayTypes; + mutable std::vector<VariableArrayType*> VariableArrayTypes; + mutable llvm::FoldingSet<DependentSizedArrayType> DependentSizedArrayTypes; + mutable llvm::FoldingSet<DependentSizedExtVectorType> + DependentSizedExtVectorTypes; + mutable llvm::FoldingSet<VectorType> VectorTypes; + mutable llvm::FoldingSet<FunctionNoProtoType> FunctionNoProtoTypes; + mutable llvm::ContextualFoldingSet<FunctionProtoType, ASTContext&> + FunctionProtoTypes; + mutable llvm::FoldingSet<DependentTypeOfExprType> DependentTypeOfExprTypes; + mutable llvm::FoldingSet<DependentDecltypeType> DependentDecltypeTypes; + mutable llvm::FoldingSet<TemplateTypeParmType> TemplateTypeParmTypes; + mutable llvm::FoldingSet<SubstTemplateTypeParmType> + SubstTemplateTypeParmTypes; + mutable llvm::FoldingSet<SubstTemplateTypeParmPackType> + SubstTemplateTypeParmPackTypes; + mutable llvm::ContextualFoldingSet<TemplateSpecializationType, ASTContext&> + TemplateSpecializationTypes; + mutable llvm::FoldingSet<ParenType> ParenTypes; + mutable llvm::FoldingSet<ElaboratedType> ElaboratedTypes; + mutable llvm::FoldingSet<DependentNameType> DependentNameTypes; + mutable llvm::ContextualFoldingSet<DependentTemplateSpecializationType, + ASTContext&> + DependentTemplateSpecializationTypes; + llvm::FoldingSet<PackExpansionType> PackExpansionTypes; + mutable llvm::FoldingSet<ObjCObjectTypeImpl> ObjCObjectTypes; + mutable llvm::FoldingSet<ObjCObjectPointerType> ObjCObjectPointerTypes; + mutable llvm::FoldingSet<AutoType> AutoTypes; + mutable llvm::FoldingSet<AtomicType> AtomicTypes; + llvm::FoldingSet<AttributedType> AttributedTypes; + + mutable llvm::FoldingSet<QualifiedTemplateName> QualifiedTemplateNames; + mutable llvm::FoldingSet<DependentTemplateName> DependentTemplateNames; + mutable llvm::FoldingSet<SubstTemplateTemplateParmStorage> + SubstTemplateTemplateParms; + mutable llvm::ContextualFoldingSet<SubstTemplateTemplateParmPackStorage, + ASTContext&> + SubstTemplateTemplateParmPacks; + + /// \brief The set of nested name specifiers. + /// + /// This set is managed by the NestedNameSpecifier class. + mutable llvm::FoldingSet<NestedNameSpecifier> NestedNameSpecifiers; + mutable NestedNameSpecifier *GlobalNestedNameSpecifier; + friend class NestedNameSpecifier; + + /// ASTRecordLayouts - A cache mapping from RecordDecls to ASTRecordLayouts. + /// This is lazily created. This is intentionally not serialized. + mutable llvm::DenseMap<const RecordDecl*, const ASTRecordLayout*> + ASTRecordLayouts; + mutable llvm::DenseMap<const ObjCContainerDecl*, const ASTRecordLayout*> + ObjCLayouts; + + /// TypeInfoMap - A cache from types to size and alignment information. + typedef llvm::DenseMap<const Type*, + std::pair<uint64_t, unsigned> > TypeInfoMap; + mutable TypeInfoMap MemoizedTypeInfo; + + /// KeyFunctions - A cache mapping from CXXRecordDecls to key functions. + llvm::DenseMap<const CXXRecordDecl*, const CXXMethodDecl*> KeyFunctions; + + /// \brief Mapping from ObjCContainers to their ObjCImplementations. + llvm::DenseMap<ObjCContainerDecl*, ObjCImplDecl*> ObjCImpls; + + /// \brief Mapping from ObjCMethod to its duplicate declaration in the same + /// interface. + llvm::DenseMap<const ObjCMethodDecl*,const ObjCMethodDecl*> ObjCMethodRedecls; + + /// \brief Mapping from __block VarDecls to their copy initialization expr. + llvm::DenseMap<const VarDecl*, Expr*> BlockVarCopyInits; + + /// \brief Mapping from class scope functions specialization to their + /// template patterns. + llvm::DenseMap<const FunctionDecl*, FunctionDecl*> + ClassScopeSpecializationPattern; + + /// \brief Representation of a "canonical" template template parameter that + /// is used in canonical template names. + class CanonicalTemplateTemplateParm : public llvm::FoldingSetNode { + TemplateTemplateParmDecl *Parm; + + public: + CanonicalTemplateTemplateParm(TemplateTemplateParmDecl *Parm) + : Parm(Parm) { } + + TemplateTemplateParmDecl *getParam() const { return Parm; } + + void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, Parm); } + + static void Profile(llvm::FoldingSetNodeID &ID, + TemplateTemplateParmDecl *Parm); + }; + mutable llvm::FoldingSet<CanonicalTemplateTemplateParm> + CanonTemplateTemplateParms; + + TemplateTemplateParmDecl * + getCanonicalTemplateTemplateParmDecl(TemplateTemplateParmDecl *TTP) const; + + /// \brief The typedef for the __int128_t type. + mutable TypedefDecl *Int128Decl; + + /// \brief The typedef for the __uint128_t type. + mutable TypedefDecl *UInt128Decl; + + /// BuiltinVaListType - built-in va list type. + /// This is initially null and set by Sema::LazilyCreateBuiltin when + /// a builtin that takes a valist is encountered. + QualType BuiltinVaListType; + + /// \brief The typedef for the predefined 'id' type. + mutable TypedefDecl *ObjCIdDecl; + + /// \brief The typedef for the predefined 'SEL' type. + mutable TypedefDecl *ObjCSelDecl; + + /// \brief The typedef for the predefined 'Class' type. + mutable TypedefDecl *ObjCClassDecl; + + /// \brief The typedef for the predefined 'Protocol' class in Objective-C. + mutable ObjCInterfaceDecl *ObjCProtocolClassDecl; + + // Typedefs which may be provided defining the structure of Objective-C + // pseudo-builtins + QualType ObjCIdRedefinitionType; + QualType ObjCClassRedefinitionType; + QualType ObjCSelRedefinitionType; + + QualType ObjCConstantStringType; + mutable RecordDecl *CFConstantStringTypeDecl; + + QualType ObjCNSStringType; + + /// \brief The typedef declaration for the Objective-C "instancetype" type. + TypedefDecl *ObjCInstanceTypeDecl; + + /// \brief The type for the C FILE type. + TypeDecl *FILEDecl; + + /// \brief The type for the C jmp_buf type. + TypeDecl *jmp_bufDecl; + + /// \brief The type for the C sigjmp_buf type. + TypeDecl *sigjmp_bufDecl; + + /// \brief The type for the C ucontext_t type. + TypeDecl *ucontext_tDecl; + + /// \brief Type for the Block descriptor for Blocks CodeGen. + /// + /// Since this is only used for generation of debug info, it is not + /// serialized. + mutable RecordDecl *BlockDescriptorType; + + /// \brief Type for the Block descriptor for Blocks CodeGen. + /// + /// Since this is only used for generation of debug info, it is not + /// serialized. + mutable RecordDecl *BlockDescriptorExtendedType; + + /// \brief Declaration for the CUDA cudaConfigureCall function. + FunctionDecl *cudaConfigureCallDecl; + + TypeSourceInfo NullTypeSourceInfo; + + /// \brief Keeps track of all declaration attributes. + /// + /// Since so few decls have attrs, we keep them in a hash map instead of + /// wasting space in the Decl class. + llvm::DenseMap<const Decl*, AttrVec*> DeclAttrs; + + /// \brief Keeps track of the static data member templates from which + /// static data members of class template specializations were instantiated. + /// + /// This data structure stores the mapping from instantiations of static + /// data members to the static data member representations within the + /// class template from which they were instantiated along with the kind + /// of instantiation or specialization (a TemplateSpecializationKind - 1). + /// + /// Given the following example: + /// + /// \code + /// template<typename T> + /// struct X { + /// static T value; + /// }; + /// + /// template<typename T> + /// T X<T>::value = T(17); + /// + /// int *x = &X<int>::value; + /// \endcode + /// + /// This mapping will contain an entry that maps from the VarDecl for + /// X<int>::value to the corresponding VarDecl for X<T>::value (within the + /// class template X) and will be marked TSK_ImplicitInstantiation. + llvm::DenseMap<const VarDecl *, MemberSpecializationInfo *> + InstantiatedFromStaticDataMember; + + /// \brief Keeps track of the declaration from which a UsingDecl was + /// created during instantiation. The source declaration is always + /// a UsingDecl, an UnresolvedUsingValueDecl, or an + /// UnresolvedUsingTypenameDecl. + /// + /// For example: + /// \code + /// template<typename T> + /// struct A { + /// void f(); + /// }; + /// + /// template<typename T> + /// struct B : A<T> { + /// using A<T>::f; + /// }; + /// + /// template struct B<int>; + /// \endcode + /// + /// This mapping will contain an entry that maps from the UsingDecl in + /// B<int> to the UnresolvedUsingDecl in B<T>. + llvm::DenseMap<UsingDecl *, NamedDecl *> InstantiatedFromUsingDecl; + + llvm::DenseMap<UsingShadowDecl*, UsingShadowDecl*> + InstantiatedFromUsingShadowDecl; + + llvm::DenseMap<FieldDecl *, FieldDecl *> InstantiatedFromUnnamedFieldDecl; + + /// \brief Mapping that stores the methods overridden by a given C++ + /// member function. + /// + /// Since most C++ member functions aren't virtual and therefore + /// don't override anything, we store the overridden functions in + /// this map on the side rather than within the CXXMethodDecl structure. + typedef llvm::TinyPtrVector<const CXXMethodDecl*> CXXMethodVector; + llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector> OverriddenMethods; + + /// \brief Mapping from each declaration context to its corresponding lambda + /// mangling context. + llvm::DenseMap<const DeclContext *, LambdaMangleContext> LambdaMangleContexts; + + /// \brief Mapping that stores parameterIndex values for ParmVarDecls + /// when that value exceeds the bitfield size of + /// ParmVarDeclBits.ParameterIndex. + typedef llvm::DenseMap<const VarDecl *, unsigned> ParameterIndexTable; + ParameterIndexTable ParamIndices; + + ImportDecl *FirstLocalImport; + ImportDecl *LastLocalImport; + + TranslationUnitDecl *TUDecl; + + /// SourceMgr - The associated SourceManager object. + SourceManager &SourceMgr; + + /// LangOpts - The language options used to create the AST associated with + /// this ASTContext object. + LangOptions &LangOpts; + + /// \brief The allocator used to create AST objects. + /// + /// AST objects are never destructed; rather, all memory associated with the + /// AST objects will be released when the ASTContext itself is destroyed. + mutable llvm::BumpPtrAllocator BumpAlloc; + + /// \brief Allocator for partial diagnostics. + PartialDiagnostic::StorageAllocator DiagAllocator; + + /// \brief The current C++ ABI. + OwningPtr<CXXABI> ABI; + CXXABI *createCXXABI(const TargetInfo &T); + + /// \brief The logical -> physical address space map. + const LangAS::Map *AddrSpaceMap; + + friend class ASTDeclReader; + friend class ASTReader; + friend class ASTWriter; + friend class CXXRecordDecl; + + const TargetInfo *Target; + clang::PrintingPolicy PrintingPolicy; + +public: + IdentifierTable &Idents; + SelectorTable &Selectors; + Builtin::Context &BuiltinInfo; + mutable DeclarationNameTable DeclarationNames; + OwningPtr<ExternalASTSource> ExternalSource; + ASTMutationListener *Listener; + + clang::PrintingPolicy getPrintingPolicy() const { return PrintingPolicy; } + + void setPrintingPolicy(clang::PrintingPolicy Policy) { + PrintingPolicy = Policy; + } + + SourceManager& getSourceManager() { return SourceMgr; } + const SourceManager& getSourceManager() const { return SourceMgr; } + void *Allocate(unsigned Size, unsigned Align = 8) const { + return BumpAlloc.Allocate(Size, Align); + } + void Deallocate(void *Ptr) const { } + + /// Return the total amount of physical memory allocated for representing + /// AST nodes and type information. + size_t getASTAllocatedMemory() const { + return BumpAlloc.getTotalMemory(); + } + /// Return the total memory used for various side tables. + size_t getSideTableAllocatedMemory() const; + + PartialDiagnostic::StorageAllocator &getDiagAllocator() { + return DiagAllocator; + } + + const TargetInfo &getTargetInfo() const { return *Target; } + + const LangOptions& getLangOpts() const { return LangOpts; } + + DiagnosticsEngine &getDiagnostics() const; + + FullSourceLoc getFullLoc(SourceLocation Loc) const { + return FullSourceLoc(Loc,SourceMgr); + } + + /// \brief Retrieve the attributes for the given declaration. + AttrVec& getDeclAttrs(const Decl *D); + + /// \brief Erase the attributes corresponding to the given declaration. + void eraseDeclAttrs(const Decl *D); + + /// \brief If this variable is an instantiated static data member of a + /// class template specialization, returns the templated static data member + /// from which it was instantiated. + MemberSpecializationInfo *getInstantiatedFromStaticDataMember( + const VarDecl *Var); + + FunctionDecl *getClassScopeSpecializationPattern(const FunctionDecl *FD); + + void setClassScopeSpecializationPattern(FunctionDecl *FD, + FunctionDecl *Pattern); + + /// \brief Note that the static data member \p Inst is an instantiation of + /// the static data member template \p Tmpl of a class template. + void setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl, + TemplateSpecializationKind TSK, + SourceLocation PointOfInstantiation = SourceLocation()); + + /// \brief If the given using decl is an instantiation of a + /// (possibly unresolved) using decl from a template instantiation, + /// return it. + NamedDecl *getInstantiatedFromUsingDecl(UsingDecl *Inst); + + /// \brief Remember that the using decl \p Inst is an instantiation + /// of the using decl \p Pattern of a class template. + void setInstantiatedFromUsingDecl(UsingDecl *Inst, NamedDecl *Pattern); + + void setInstantiatedFromUsingShadowDecl(UsingShadowDecl *Inst, + UsingShadowDecl *Pattern); + UsingShadowDecl *getInstantiatedFromUsingShadowDecl(UsingShadowDecl *Inst); + + FieldDecl *getInstantiatedFromUnnamedFieldDecl(FieldDecl *Field); + + void setInstantiatedFromUnnamedFieldDecl(FieldDecl *Inst, FieldDecl *Tmpl); + + /// ZeroBitfieldFollowsNonBitfield - return 'true" if 'FD' is a zero-length + /// bitfield which follows the non-bitfield 'LastFD'. + bool ZeroBitfieldFollowsNonBitfield(const FieldDecl *FD, + const FieldDecl *LastFD) const; + + /// ZeroBitfieldFollowsBitfield - return 'true" if 'FD' is a zero-length + /// bitfield which follows the bitfield 'LastFD'. + bool ZeroBitfieldFollowsBitfield(const FieldDecl *FD, + const FieldDecl *LastFD) const; + + /// BitfieldFollowsBitfield - return 'true" if 'FD' is a + /// bitfield which follows the bitfield 'LastFD'. + bool BitfieldFollowsBitfield(const FieldDecl *FD, + const FieldDecl *LastFD) const; + + /// NonBitfieldFollowsBitfield - return 'true" if 'FD' is not a + /// bitfield which follows the bitfield 'LastFD'. + bool NonBitfieldFollowsBitfield(const FieldDecl *FD, + const FieldDecl *LastFD) const; + + /// BitfieldFollowsNonBitfield - return 'true" if 'FD' is a + /// bitfield which follows the none bitfield 'LastFD'. + bool BitfieldFollowsNonBitfield(const FieldDecl *FD, + const FieldDecl *LastFD) const; + + // Access to the set of methods overridden by the given C++ method. + typedef CXXMethodVector::const_iterator overridden_cxx_method_iterator; + overridden_cxx_method_iterator + overridden_methods_begin(const CXXMethodDecl *Method) const; + + overridden_cxx_method_iterator + overridden_methods_end(const CXXMethodDecl *Method) const; + + unsigned overridden_methods_size(const CXXMethodDecl *Method) const; + + /// \brief Note that the given C++ \p Method overrides the given \p + /// Overridden method. + void addOverriddenMethod(const CXXMethodDecl *Method, + const CXXMethodDecl *Overridden); + + /// \brief Notify the AST context that a new import declaration has been + /// parsed or implicitly created within this translation unit. + void addedLocalImportDecl(ImportDecl *Import); + + static ImportDecl *getNextLocalImport(ImportDecl *Import) { + return Import->NextLocalImport; + } + + /// \brief Iterator that visits import declarations. + class import_iterator { + ImportDecl *Import; + + public: + typedef ImportDecl *value_type; + typedef ImportDecl *reference; + typedef ImportDecl *pointer; + typedef int difference_type; + typedef std::forward_iterator_tag iterator_category; + + import_iterator() : Import() { } + explicit import_iterator(ImportDecl *Import) : Import(Import) { } + + reference operator*() const { return Import; } + pointer operator->() const { return Import; } + + import_iterator &operator++() { + Import = ASTContext::getNextLocalImport(Import); + return *this; + } + + import_iterator operator++(int) { + import_iterator Other(*this); + ++(*this); + return Other; + } + + friend bool operator==(import_iterator X, import_iterator Y) { + return X.Import == Y.Import; + } + + friend bool operator!=(import_iterator X, import_iterator Y) { + return X.Import != Y.Import; + } + }; + + import_iterator local_import_begin() const { + return import_iterator(FirstLocalImport); + } + import_iterator local_import_end() const { return import_iterator(); } + + TranslationUnitDecl *getTranslationUnitDecl() const { return TUDecl; } + + + // Builtin Types. + CanQualType VoidTy; + CanQualType BoolTy; + CanQualType CharTy; + CanQualType WCharTy; // [C++ 3.9.1p5], integer type in C99. + CanQualType Char16Ty; // [C++0x 3.9.1p5], integer type in C99. + CanQualType Char32Ty; // [C++0x 3.9.1p5], integer type in C99. + CanQualType SignedCharTy, ShortTy, IntTy, LongTy, LongLongTy, Int128Ty; + CanQualType UnsignedCharTy, UnsignedShortTy, UnsignedIntTy, UnsignedLongTy; + CanQualType UnsignedLongLongTy, UnsignedInt128Ty; + CanQualType FloatTy, DoubleTy, LongDoubleTy; + CanQualType HalfTy; // [OpenCL 6.1.1.1], ARM NEON + CanQualType FloatComplexTy, DoubleComplexTy, LongDoubleComplexTy; + CanQualType VoidPtrTy, NullPtrTy; + CanQualType DependentTy, OverloadTy, BoundMemberTy, UnknownAnyTy; + CanQualType PseudoObjectTy, ARCUnbridgedCastTy; + CanQualType ObjCBuiltinIdTy, ObjCBuiltinClassTy, ObjCBuiltinSelTy; + CanQualType ObjCBuiltinBoolTy; + + // Types for deductions in C++0x [stmt.ranged]'s desugaring. Built on demand. + mutable QualType AutoDeductTy; // Deduction against 'auto'. + mutable QualType AutoRRefDeductTy; // Deduction against 'auto &&'. + + ASTContext(LangOptions& LOpts, SourceManager &SM, const TargetInfo *t, + IdentifierTable &idents, SelectorTable &sels, + Builtin::Context &builtins, + unsigned size_reserve, + bool DelayInitialization = false); + + ~ASTContext(); + + /// \brief Attach an external AST source to the AST context. + /// + /// The external AST source provides the ability to load parts of + /// the abstract syntax tree as needed from some external storage, + /// e.g., a precompiled header. + void setExternalSource(OwningPtr<ExternalASTSource> &Source); + + /// \brief Retrieve a pointer to the external AST source associated + /// with this AST context, if any. + ExternalASTSource *getExternalSource() const { return ExternalSource.get(); } + + /// \brief Attach an AST mutation listener to the AST context. + /// + /// The AST mutation listener provides the ability to track modifications to + /// the abstract syntax tree entities committed after they were initially + /// created. + void setASTMutationListener(ASTMutationListener *Listener) { + this->Listener = Listener; + } + + /// \brief Retrieve a pointer to the AST mutation listener associated + /// with this AST context, if any. + ASTMutationListener *getASTMutationListener() const { return Listener; } + + void PrintStats() const; + const std::vector<Type*>& getTypes() const { return Types; } + + /// \brief Retrieve the declaration for the 128-bit signed integer type. + TypedefDecl *getInt128Decl() const; + + /// \brief Retrieve the declaration for the 128-bit unsigned integer type. + TypedefDecl *getUInt128Decl() const; + + //===--------------------------------------------------------------------===// + // Type Constructors + //===--------------------------------------------------------------------===// + +private: + /// getExtQualType - Return a type with extended qualifiers. + QualType getExtQualType(const Type *Base, Qualifiers Quals) const; + + QualType getTypeDeclTypeSlow(const TypeDecl *Decl) const; + +public: + /// getAddSpaceQualType - Return the uniqued reference to the type for an + /// address space qualified type with the specified type and address space. + /// The resulting type has a union of the qualifiers from T and the address + /// space. If T already has an address space specifier, it is silently + /// replaced. + QualType getAddrSpaceQualType(QualType T, unsigned AddressSpace) const; + + /// getObjCGCQualType - Returns the uniqued reference to the type for an + /// objc gc qualified type. The retulting type has a union of the qualifiers + /// from T and the gc attribute. + QualType getObjCGCQualType(QualType T, Qualifiers::GC gcAttr) const; + + /// getRestrictType - Returns the uniqued reference to the type for a + /// 'restrict' qualified type. The resulting type has a union of the + /// qualifiers from T and 'restrict'. + QualType getRestrictType(QualType T) const { + return T.withFastQualifiers(Qualifiers::Restrict); + } + + /// getVolatileType - Returns the uniqued reference to the type for a + /// 'volatile' qualified type. The resulting type has a union of the + /// qualifiers from T and 'volatile'. + QualType getVolatileType(QualType T) const { + return T.withFastQualifiers(Qualifiers::Volatile); + } + + /// getConstType - Returns the uniqued reference to the type for a + /// 'const' qualified type. The resulting type has a union of the + /// qualifiers from T and 'const'. + /// + /// It can be reasonably expected that this will always be + /// equivalent to calling T.withConst(). + QualType getConstType(QualType T) const { return T.withConst(); } + + /// adjustFunctionType - Change the ExtInfo on a function type. + const FunctionType *adjustFunctionType(const FunctionType *Fn, + FunctionType::ExtInfo EInfo); + + /// getComplexType - Return the uniqued reference to the type for a complex + /// number with the specified element type. + QualType getComplexType(QualType T) const; + CanQualType getComplexType(CanQualType T) const { + return CanQualType::CreateUnsafe(getComplexType((QualType) T)); + } + + /// getPointerType - Return the uniqued reference to the type for a pointer to + /// the specified type. + QualType getPointerType(QualType T) const; + CanQualType getPointerType(CanQualType T) const { + return CanQualType::CreateUnsafe(getPointerType((QualType) T)); + } + + /// getAtomicType - Return the uniqued reference to the atomic type for + /// the specified type. + QualType getAtomicType(QualType T) const; + + /// getBlockPointerType - Return the uniqued reference to the type for a block + /// of the specified type. + QualType getBlockPointerType(QualType T) const; + + /// This gets the struct used to keep track of the descriptor for pointer to + /// blocks. + QualType getBlockDescriptorType() const; + + /// This gets the struct used to keep track of the extended descriptor for + /// pointer to blocks. + QualType getBlockDescriptorExtendedType() const; + + void setcudaConfigureCallDecl(FunctionDecl *FD) { + cudaConfigureCallDecl = FD; + } + FunctionDecl *getcudaConfigureCallDecl() { + return cudaConfigureCallDecl; + } + + /// This builds the struct used for __block variables. + QualType BuildByRefType(StringRef DeclName, QualType Ty) const; + + /// Returns true iff we need copy/dispose helpers for the given type. + bool BlockRequiresCopying(QualType Ty) const; + + /// getLValueReferenceType - Return the uniqued reference to the type for an + /// lvalue reference to the specified type. + QualType getLValueReferenceType(QualType T, bool SpelledAsLValue = true) + const; + + /// getRValueReferenceType - Return the uniqued reference to the type for an + /// rvalue reference to the specified type. + QualType getRValueReferenceType(QualType T) const; + + /// getMemberPointerType - Return the uniqued reference to the type for a + /// member pointer to the specified type in the specified class. The class + /// is a Type because it could be a dependent name. + QualType getMemberPointerType(QualType T, const Type *Cls) const; + + /// getVariableArrayType - Returns a non-unique reference to the type for a + /// variable array of the specified element type. + QualType getVariableArrayType(QualType EltTy, Expr *NumElts, + ArrayType::ArraySizeModifier ASM, + unsigned IndexTypeQuals, + SourceRange Brackets) const; + + /// getDependentSizedArrayType - Returns a non-unique reference to + /// the type for a dependently-sized array of the specified element + /// type. FIXME: We will need these to be uniqued, or at least + /// comparable, at some point. + QualType getDependentSizedArrayType(QualType EltTy, Expr *NumElts, + ArrayType::ArraySizeModifier ASM, + unsigned IndexTypeQuals, + SourceRange Brackets) const; + + /// getIncompleteArrayType - Returns a unique reference to the type for a + /// incomplete array of the specified element type. + QualType getIncompleteArrayType(QualType EltTy, + ArrayType::ArraySizeModifier ASM, + unsigned IndexTypeQuals) const; + + /// getConstantArrayType - Return the unique reference to the type for a + /// constant array of the specified element type. + QualType getConstantArrayType(QualType EltTy, const llvm::APInt &ArySize, + ArrayType::ArraySizeModifier ASM, + unsigned IndexTypeQuals) const; + + /// getVariableArrayDecayedType - Returns a vla type where known sizes + /// are replaced with [*]. + QualType getVariableArrayDecayedType(QualType Ty) const; + + /// getVectorType - Return the unique reference to a vector type of + /// the specified element type and size. VectorType must be a built-in type. + QualType getVectorType(QualType VectorType, unsigned NumElts, + VectorType::VectorKind VecKind) const; + + /// getExtVectorType - Return the unique reference to an extended vector type + /// of the specified element type and size. VectorType must be a built-in + /// type. + QualType getExtVectorType(QualType VectorType, unsigned NumElts) const; + + /// getDependentSizedExtVectorType - Returns a non-unique reference to + /// the type for a dependently-sized vector of the specified element + /// type. FIXME: We will need these to be uniqued, or at least + /// comparable, at some point. + QualType getDependentSizedExtVectorType(QualType VectorType, + Expr *SizeExpr, + SourceLocation AttrLoc) const; + + /// getFunctionNoProtoType - Return a K&R style C function type like 'int()'. + /// + QualType getFunctionNoProtoType(QualType ResultTy, + const FunctionType::ExtInfo &Info) const; + + QualType getFunctionNoProtoType(QualType ResultTy) const { + return getFunctionNoProtoType(ResultTy, FunctionType::ExtInfo()); + } + + /// getFunctionType - Return a normal function type with a typed + /// argument list. + QualType getFunctionType(QualType ResultTy, + const QualType *Args, unsigned NumArgs, + const FunctionProtoType::ExtProtoInfo &EPI) const; + + /// getTypeDeclType - Return the unique reference to the type for + /// the specified type declaration. + QualType getTypeDeclType(const TypeDecl *Decl, + const TypeDecl *PrevDecl = 0) const { + assert(Decl && "Passed null for Decl param"); + if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0); + + if (PrevDecl) { + assert(PrevDecl->TypeForDecl && "previous decl has no TypeForDecl"); + Decl->TypeForDecl = PrevDecl->TypeForDecl; + return QualType(PrevDecl->TypeForDecl, 0); + } + + return getTypeDeclTypeSlow(Decl); + } + + /// getTypedefType - Return the unique reference to the type for the + /// specified typedef-name decl. + QualType getTypedefType(const TypedefNameDecl *Decl, + QualType Canon = QualType()) const; + + QualType getRecordType(const RecordDecl *Decl) const; + + QualType getEnumType(const EnumDecl *Decl) const; + + QualType getInjectedClassNameType(CXXRecordDecl *Decl, QualType TST) const; + + QualType getAttributedType(AttributedType::Kind attrKind, + QualType modifiedType, + QualType equivalentType); + + QualType getSubstTemplateTypeParmType(const TemplateTypeParmType *Replaced, + QualType Replacement) const; + QualType getSubstTemplateTypeParmPackType( + const TemplateTypeParmType *Replaced, + const TemplateArgument &ArgPack); + + QualType getTemplateTypeParmType(unsigned Depth, unsigned Index, + bool ParameterPack, + TemplateTypeParmDecl *ParmDecl = 0) const; + + QualType getTemplateSpecializationType(TemplateName T, + const TemplateArgument *Args, + unsigned NumArgs, + QualType Canon = QualType()) const; + + QualType getCanonicalTemplateSpecializationType(TemplateName T, + const TemplateArgument *Args, + unsigned NumArgs) const; + + QualType getTemplateSpecializationType(TemplateName T, + const TemplateArgumentListInfo &Args, + QualType Canon = QualType()) const; + + TypeSourceInfo * + getTemplateSpecializationTypeInfo(TemplateName T, SourceLocation TLoc, + const TemplateArgumentListInfo &Args, + QualType Canon = QualType()) const; + + QualType getParenType(QualType NamedType) const; + + QualType getElaboratedType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier *NNS, + QualType NamedType) const; + QualType getDependentNameType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier *NNS, + const IdentifierInfo *Name, + QualType Canon = QualType()) const; + + QualType getDependentTemplateSpecializationType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier *NNS, + const IdentifierInfo *Name, + const TemplateArgumentListInfo &Args) const; + QualType getDependentTemplateSpecializationType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier *NNS, + const IdentifierInfo *Name, + unsigned NumArgs, + const TemplateArgument *Args) const; + + QualType getPackExpansionType(QualType Pattern, + llvm::Optional<unsigned> NumExpansions); + + QualType getObjCInterfaceType(const ObjCInterfaceDecl *Decl, + ObjCInterfaceDecl *PrevDecl = 0) const; + + QualType getObjCObjectType(QualType Base, + ObjCProtocolDecl * const *Protocols, + unsigned NumProtocols) const; + + /// getObjCObjectPointerType - Return a ObjCObjectPointerType type + /// for the given ObjCObjectType. + QualType getObjCObjectPointerType(QualType OIT) const; + + /// getTypeOfType - GCC extension. + QualType getTypeOfExprType(Expr *e) const; + QualType getTypeOfType(QualType t) const; + + /// getDecltypeType - C++0x decltype. + QualType getDecltypeType(Expr *e, QualType UnderlyingType) const; + + /// getUnaryTransformType - unary type transforms + QualType getUnaryTransformType(QualType BaseType, QualType UnderlyingType, + UnaryTransformType::UTTKind UKind) const; + + /// getAutoType - C++0x deduced auto type. + QualType getAutoType(QualType DeducedType) const; + + /// getAutoDeductType - C++0x deduction pattern for 'auto' type. + QualType getAutoDeductType() const; + + /// getAutoRRefDeductType - C++0x deduction pattern for 'auto &&' type. + QualType getAutoRRefDeductType() const; + + /// getTagDeclType - Return the unique reference to the type for the + /// specified TagDecl (struct/union/class/enum) decl. + QualType getTagDeclType(const TagDecl *Decl) const; + + /// getSizeType - Return the unique type for "size_t" (C99 7.17), defined + /// in <stddef.h>. The sizeof operator requires this (C99 6.5.3.4p4). + CanQualType getSizeType() const; + + /// getIntMaxType - Return the unique type for "intmax_t" (C99 7.18.1.5), + /// defined in <stdint.h>. + CanQualType getIntMaxType() const; + + /// getUIntMaxType - Return the unique type for "uintmax_t" (C99 7.18.1.5), + /// defined in <stdint.h>. + CanQualType getUIntMaxType() const; + + /// getWCharType - In C++, this returns the unique wchar_t type. In C99, this + /// returns a type compatible with the type defined in <stddef.h> as defined + /// by the target. + QualType getWCharType() const { return WCharTy; } + + /// getSignedWCharType - Return the type of "signed wchar_t". + /// Used when in C++, as a GCC extension. + QualType getSignedWCharType() const; + + /// getUnsignedWCharType - Return the type of "unsigned wchar_t". + /// Used when in C++, as a GCC extension. + QualType getUnsignedWCharType() const; + + /// getPointerDiffType - Return the unique type for "ptrdiff_t" (C99 7.17) + /// defined in <stddef.h>. Pointer - pointer requires this (C99 6.5.6p9). + QualType getPointerDiffType() const; + + // getCFConstantStringType - Return the C structure type used to represent + // constant CFStrings. + QualType getCFConstantStringType() const; + + /// Get the structure type used to representation CFStrings, or NULL + /// if it hasn't yet been built. + QualType getRawCFConstantStringType() const { + if (CFConstantStringTypeDecl) + return getTagDeclType(CFConstantStringTypeDecl); + return QualType(); + } + void setCFConstantStringType(QualType T); + + // This setter/getter represents the ObjC type for an NSConstantString. + void setObjCConstantStringInterface(ObjCInterfaceDecl *Decl); + QualType getObjCConstantStringInterface() const { + return ObjCConstantStringType; + } + + QualType getObjCNSStringType() const { + return ObjCNSStringType; + } + + void setObjCNSStringType(QualType T) { + ObjCNSStringType = T; + } + + /// \brief Retrieve the type that 'id' has been defined to, which may be + /// different from the built-in 'id' if 'id' has been typedef'd. + QualType getObjCIdRedefinitionType() const { + if (ObjCIdRedefinitionType.isNull()) + return getObjCIdType(); + return ObjCIdRedefinitionType; + } + + /// \brief Set the user-written type that redefines 'id'. + void setObjCIdRedefinitionType(QualType RedefType) { + ObjCIdRedefinitionType = RedefType; + } + + /// \brief Retrieve the type that 'Class' has been defined to, which may be + /// different from the built-in 'Class' if 'Class' has been typedef'd. + QualType getObjCClassRedefinitionType() const { + if (ObjCClassRedefinitionType.isNull()) + return getObjCClassType(); + return ObjCClassRedefinitionType; + } + + /// \brief Set the user-written type that redefines 'SEL'. + void setObjCClassRedefinitionType(QualType RedefType) { + ObjCClassRedefinitionType = RedefType; + } + + /// \brief Retrieve the type that 'SEL' has been defined to, which may be + /// different from the built-in 'SEL' if 'SEL' has been typedef'd. + QualType getObjCSelRedefinitionType() const { + if (ObjCSelRedefinitionType.isNull()) + return getObjCSelType(); + return ObjCSelRedefinitionType; + } + + + /// \brief Set the user-written type that redefines 'SEL'. + void setObjCSelRedefinitionType(QualType RedefType) { + ObjCSelRedefinitionType = RedefType; + } + + /// \brief Retrieve the Objective-C "instancetype" type, if already known; + /// otherwise, returns a NULL type; + QualType getObjCInstanceType() { + return getTypeDeclType(getObjCInstanceTypeDecl()); + } + + /// \brief Retrieve the typedef declaration corresponding to the Objective-C + /// "instancetype" type. + TypedefDecl *getObjCInstanceTypeDecl(); + + /// \brief Set the type for the C FILE type. + void setFILEDecl(TypeDecl *FILEDecl) { this->FILEDecl = FILEDecl; } + + /// \brief Retrieve the C FILE type. + QualType getFILEType() const { + if (FILEDecl) + return getTypeDeclType(FILEDecl); + return QualType(); + } + + /// \brief Set the type for the C jmp_buf type. + void setjmp_bufDecl(TypeDecl *jmp_bufDecl) { + this->jmp_bufDecl = jmp_bufDecl; + } + + /// \brief Retrieve the C jmp_buf type. + QualType getjmp_bufType() const { + if (jmp_bufDecl) + return getTypeDeclType(jmp_bufDecl); + return QualType(); + } + + /// \brief Set the type for the C sigjmp_buf type. + void setsigjmp_bufDecl(TypeDecl *sigjmp_bufDecl) { + this->sigjmp_bufDecl = sigjmp_bufDecl; + } + + /// \brief Retrieve the C sigjmp_buf type. + QualType getsigjmp_bufType() const { + if (sigjmp_bufDecl) + return getTypeDeclType(sigjmp_bufDecl); + return QualType(); + } + + /// \brief Set the type for the C ucontext_t type. + void setucontext_tDecl(TypeDecl *ucontext_tDecl) { + this->ucontext_tDecl = ucontext_tDecl; + } + + /// \brief Retrieve the C ucontext_t type. + QualType getucontext_tType() const { + if (ucontext_tDecl) + return getTypeDeclType(ucontext_tDecl); + return QualType(); + } + + /// \brief The result type of logical operations, '<', '>', '!=', etc. + QualType getLogicalOperationType() const { + return getLangOpts().CPlusPlus ? BoolTy : IntTy; + } + + /// getObjCEncodingForType - Emit the ObjC type encoding for the + /// given type into \arg S. If \arg NameFields is specified then + /// record field names are also encoded. + void getObjCEncodingForType(QualType t, std::string &S, + const FieldDecl *Field=0) const; + + void getLegacyIntegralTypeEncoding(QualType &t) const; + + // Put the string version of type qualifiers into S. + void getObjCEncodingForTypeQualifier(Decl::ObjCDeclQualifier QT, + std::string &S) const; + + /// getObjCEncodingForFunctionDecl - Returns the encoded type for this + /// function. This is in the same format as Objective-C method encodings. + /// + /// \returns true if an error occurred (e.g., because one of the parameter + /// types is incomplete), false otherwise. + bool getObjCEncodingForFunctionDecl(const FunctionDecl *Decl, std::string& S); + + /// getObjCEncodingForMethodDecl - Return the encoded type for this method + /// declaration. + /// + /// \returns true if an error occurred (e.g., because one of the parameter + /// types is incomplete), false otherwise. + bool getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, std::string &S, + bool Extended = false) + const; + + /// getObjCEncodingForBlock - Return the encoded type for this block + /// declaration. + std::string getObjCEncodingForBlock(const BlockExpr *blockExpr) const; + + /// getObjCEncodingForPropertyDecl - Return the encoded type for + /// this method declaration. If non-NULL, Container must be either + /// an ObjCCategoryImplDecl or ObjCImplementationDecl; it should + /// only be NULL when getting encodings for protocol properties. + void getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD, + const Decl *Container, + std::string &S) const; + + bool ProtocolCompatibleWithProtocol(ObjCProtocolDecl *lProto, + ObjCProtocolDecl *rProto) const; + + /// getObjCEncodingTypeSize returns size of type for objective-c encoding + /// purpose in characters. + CharUnits getObjCEncodingTypeSize(QualType t) const; + + /// \brief Retrieve the typedef corresponding to the predefined 'id' type + /// in Objective-C. + TypedefDecl *getObjCIdDecl() const; + + /// This setter/getter represents the ObjC 'id' type. It is setup lazily, by + /// Sema. id is always a (typedef for a) pointer type, a pointer to a struct. + QualType getObjCIdType() const { + return getTypeDeclType(getObjCIdDecl()); + } + + /// \brief Retrieve the typedef corresponding to the predefined 'SEL' type + /// in Objective-C. + TypedefDecl *getObjCSelDecl() const; + + /// \brief Retrieve the type that corresponds to the predefined Objective-C + /// 'SEL' type. + QualType getObjCSelType() const { + return getTypeDeclType(getObjCSelDecl()); + } + + /// \brief Retrieve the typedef declaration corresponding to the predefined + /// Objective-C 'Class' type. + TypedefDecl *getObjCClassDecl() const; + + /// This setter/getter repreents the ObjC 'Class' type. It is setup lazily, by + /// Sema. 'Class' is always a (typedef for a) pointer type, a pointer to a + /// struct. + QualType getObjCClassType() const { + return getTypeDeclType(getObjCClassDecl()); + } + + /// \brief Retrieve the Objective-C class declaration corresponding to + /// the predefined 'Protocol' class. + ObjCInterfaceDecl *getObjCProtocolDecl() const; + + /// \brief Retrieve the type of the Objective-C "Protocol" class. + QualType getObjCProtoType() const { + return getObjCInterfaceType(getObjCProtocolDecl()); + } + + void setBuiltinVaListType(QualType T); + QualType getBuiltinVaListType() const { return BuiltinVaListType; } + + /// getCVRQualifiedType - Returns a type with additional const, + /// volatile, or restrict qualifiers. + QualType getCVRQualifiedType(QualType T, unsigned CVR) const { + return getQualifiedType(T, Qualifiers::fromCVRMask(CVR)); + } + + /// getQualifiedType - Un-split a SplitQualType. + QualType getQualifiedType(SplitQualType split) const { + return getQualifiedType(split.Ty, split.Quals); + } + + /// getQualifiedType - Returns a type with additional qualifiers. + QualType getQualifiedType(QualType T, Qualifiers Qs) const { + if (!Qs.hasNonFastQualifiers()) + return T.withFastQualifiers(Qs.getFastQualifiers()); + QualifierCollector Qc(Qs); + const Type *Ptr = Qc.strip(T); + return getExtQualType(Ptr, Qc); + } + + /// getQualifiedType - Returns a type with additional qualifiers. + QualType getQualifiedType(const Type *T, Qualifiers Qs) const { + if (!Qs.hasNonFastQualifiers()) + return QualType(T, Qs.getFastQualifiers()); + return getExtQualType(T, Qs); + } + + /// getLifetimeQualifiedType - Returns a type with the given + /// lifetime qualifier. + QualType getLifetimeQualifiedType(QualType type, + Qualifiers::ObjCLifetime lifetime) { + assert(type.getObjCLifetime() == Qualifiers::OCL_None); + assert(lifetime != Qualifiers::OCL_None); + + Qualifiers qs; + qs.addObjCLifetime(lifetime); + return getQualifiedType(type, qs); + } + + DeclarationNameInfo getNameForTemplate(TemplateName Name, + SourceLocation NameLoc) const; + + TemplateName getOverloadedTemplateName(UnresolvedSetIterator Begin, + UnresolvedSetIterator End) const; + + TemplateName getQualifiedTemplateName(NestedNameSpecifier *NNS, + bool TemplateKeyword, + TemplateDecl *Template) const; + + TemplateName getDependentTemplateName(NestedNameSpecifier *NNS, + const IdentifierInfo *Name) const; + TemplateName getDependentTemplateName(NestedNameSpecifier *NNS, + OverloadedOperatorKind Operator) const; + TemplateName getSubstTemplateTemplateParm(TemplateTemplateParmDecl *param, + TemplateName replacement) const; + TemplateName getSubstTemplateTemplateParmPack(TemplateTemplateParmDecl *Param, + const TemplateArgument &ArgPack) const; + + enum GetBuiltinTypeError { + GE_None, //< No error + GE_Missing_stdio, //< Missing a type from <stdio.h> + GE_Missing_setjmp, //< Missing a type from <setjmp.h> + GE_Missing_ucontext //< Missing a type from <ucontext.h> + }; + + /// GetBuiltinType - Return the type for the specified builtin. If + /// IntegerConstantArgs is non-null, it is filled in with a bitmask of + /// arguments to the builtin that are required to be integer constant + /// expressions. + QualType GetBuiltinType(unsigned ID, GetBuiltinTypeError &Error, + unsigned *IntegerConstantArgs = 0) const; + +private: + CanQualType getFromTargetType(unsigned Type) const; + std::pair<uint64_t, unsigned> getTypeInfoImpl(const Type *T) const; + + //===--------------------------------------------------------------------===// + // Type Predicates. + //===--------------------------------------------------------------------===// + +public: + /// getObjCGCAttr - Returns one of GCNone, Weak or Strong objc's + /// garbage collection attribute. + /// + Qualifiers::GC getObjCGCAttrKind(QualType Ty) const; + + /// areCompatibleVectorTypes - Return true if the given vector types + /// are of the same unqualified type or if they are equivalent to the same + /// GCC vector type, ignoring whether they are target-specific (AltiVec or + /// Neon) types. + bool areCompatibleVectorTypes(QualType FirstVec, QualType SecondVec); + + /// isObjCNSObjectType - Return true if this is an NSObject object with + /// its NSObject attribute set. + static bool isObjCNSObjectType(QualType Ty) { + return Ty->isObjCNSObjectType(); + } + + //===--------------------------------------------------------------------===// + // Type Sizing and Analysis + //===--------------------------------------------------------------------===// + + /// getFloatTypeSemantics - Return the APFloat 'semantics' for the specified + /// scalar floating point type. + const llvm::fltSemantics &getFloatTypeSemantics(QualType T) const; + + /// getTypeInfo - Get the size and alignment of the specified complete type in + /// bits. + std::pair<uint64_t, unsigned> getTypeInfo(const Type *T) const; + std::pair<uint64_t, unsigned> getTypeInfo(QualType T) const { + return getTypeInfo(T.getTypePtr()); + } + + /// getTypeSize - Return the size of the specified type, in bits. This method + /// does not work on incomplete types. + uint64_t getTypeSize(QualType T) const { + return getTypeInfo(T).first; + } + uint64_t getTypeSize(const Type *T) const { + return getTypeInfo(T).first; + } + + /// getCharWidth - Return the size of the character type, in bits + uint64_t getCharWidth() const { + return getTypeSize(CharTy); + } + + /// toCharUnitsFromBits - Convert a size in bits to a size in characters. + CharUnits toCharUnitsFromBits(int64_t BitSize) const; + + /// toBits - Convert a size in characters to a size in bits. + int64_t toBits(CharUnits CharSize) const; + + /// getTypeSizeInChars - Return the size of the specified type, in characters. + /// This method does not work on incomplete types. + CharUnits getTypeSizeInChars(QualType T) const; + CharUnits getTypeSizeInChars(const Type *T) const; + + /// getTypeAlign - Return the ABI-specified alignment of a type, in bits. + /// This method does not work on incomplete types. + unsigned getTypeAlign(QualType T) const { + return getTypeInfo(T).second; + } + unsigned getTypeAlign(const Type *T) const { + return getTypeInfo(T).second; + } + + /// getTypeAlignInChars - Return the ABI-specified alignment of a type, in + /// characters. This method does not work on incomplete types. + CharUnits getTypeAlignInChars(QualType T) const; + CharUnits getTypeAlignInChars(const Type *T) const; + + std::pair<CharUnits, CharUnits> getTypeInfoInChars(const Type *T) const; + std::pair<CharUnits, CharUnits> getTypeInfoInChars(QualType T) const; + + /// getPreferredTypeAlign - Return the "preferred" alignment of the specified + /// type for the current target in bits. This can be different than the ABI + /// alignment in cases where it is beneficial for performance to overalign + /// a data type. + unsigned getPreferredTypeAlign(const Type *T) const; + + /// getDeclAlign - Return a conservative estimate of the alignment of + /// the specified decl. Note that bitfields do not have a valid alignment, so + /// this method will assert on them. + /// If @p RefAsPointee, references are treated like their underlying type + /// (for alignof), else they're treated like pointers (for CodeGen). + CharUnits getDeclAlign(const Decl *D, bool RefAsPointee = false) const; + + /// getASTRecordLayout - Get or compute information about the layout of the + /// specified record (struct/union/class), which indicates its size and field + /// position information. + const ASTRecordLayout &getASTRecordLayout(const RecordDecl *D) const; + + /// getASTObjCInterfaceLayout - Get or compute information about the + /// layout of the specified Objective-C interface. + const ASTRecordLayout &getASTObjCInterfaceLayout(const ObjCInterfaceDecl *D) + const; + + void DumpRecordLayout(const RecordDecl *RD, raw_ostream &OS, + bool Simple = false) const; + + /// getASTObjCImplementationLayout - Get or compute information about + /// the layout of the specified Objective-C implementation. This may + /// differ from the interface if synthesized ivars are present. + const ASTRecordLayout & + getASTObjCImplementationLayout(const ObjCImplementationDecl *D) const; + + /// getKeyFunction - Get the key function for the given record decl, or NULL + /// if there isn't one. The key function is, according to the Itanium C++ ABI + /// section 5.2.3: + /// + /// ...the first non-pure virtual function that is not inline at the point + /// of class definition. + const CXXMethodDecl *getKeyFunction(const CXXRecordDecl *RD); + + /// Get the offset of a FieldDecl or IndirectFieldDecl, in bits. + uint64_t getFieldOffset(const ValueDecl *FD) const; + + bool isNearlyEmpty(const CXXRecordDecl *RD) const; + + MangleContext *createMangleContext(); + + void DeepCollectObjCIvars(const ObjCInterfaceDecl *OI, bool leafClass, + SmallVectorImpl<const ObjCIvarDecl*> &Ivars) const; + + unsigned CountNonClassIvars(const ObjCInterfaceDecl *OI) const; + void CollectInheritedProtocols(const Decl *CDecl, + llvm::SmallPtrSet<ObjCProtocolDecl*, 8> &Protocols); + + //===--------------------------------------------------------------------===// + // Type Operators + //===--------------------------------------------------------------------===// + + /// getCanonicalType - Return the canonical (structural) type corresponding to + /// the specified potentially non-canonical type. The non-canonical version + /// of a type may have many "decorated" versions of types. Decorators can + /// include typedefs, 'typeof' operators, etc. The returned type is guaranteed + /// to be free of any of these, allowing two canonical types to be compared + /// for exact equality with a simple pointer comparison. + CanQualType getCanonicalType(QualType T) const { + return CanQualType::CreateUnsafe(T.getCanonicalType()); + } + + const Type *getCanonicalType(const Type *T) const { + return T->getCanonicalTypeInternal().getTypePtr(); + } + + /// getCanonicalParamType - Return the canonical parameter type + /// corresponding to the specific potentially non-canonical one. + /// Qualifiers are stripped off, functions are turned into function + /// pointers, and arrays decay one level into pointers. + CanQualType getCanonicalParamType(QualType T) const; + + /// \brief Determine whether the given types are equivalent. + bool hasSameType(QualType T1, QualType T2) const { + return getCanonicalType(T1) == getCanonicalType(T2); + } + + /// \brief Returns this type as a completely-unqualified array type, + /// capturing the qualifiers in Quals. This will remove the minimal amount of + /// sugaring from the types, similar to the behavior of + /// QualType::getUnqualifiedType(). + /// + /// \param T is the qualified type, which may be an ArrayType + /// + /// \param Quals will receive the full set of qualifiers that were + /// applied to the array. + /// + /// \returns if this is an array type, the completely unqualified array type + /// that corresponds to it. Otherwise, returns T.getUnqualifiedType(). + QualType getUnqualifiedArrayType(QualType T, Qualifiers &Quals); + + /// \brief Determine whether the given types are equivalent after + /// cvr-qualifiers have been removed. + bool hasSameUnqualifiedType(QualType T1, QualType T2) const { + return getCanonicalType(T1).getTypePtr() == + getCanonicalType(T2).getTypePtr(); + } + + bool UnwrapSimilarPointerTypes(QualType &T1, QualType &T2); + + /// \brief Retrieves the "canonical" nested name specifier for a + /// given nested name specifier. + /// + /// The canonical nested name specifier is a nested name specifier + /// that uniquely identifies a type or namespace within the type + /// system. For example, given: + /// + /// \code + /// namespace N { + /// struct S { + /// template<typename T> struct X { typename T* type; }; + /// }; + /// } + /// + /// template<typename T> struct Y { + /// typename N::S::X<T>::type member; + /// }; + /// \endcode + /// + /// Here, the nested-name-specifier for N::S::X<T>:: will be + /// S::X<template-param-0-0>, since 'S' and 'X' are uniquely defined + /// by declarations in the type system and the canonical type for + /// the template type parameter 'T' is template-param-0-0. + NestedNameSpecifier * + getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const; + + /// \brief Retrieves the default calling convention to use for + /// C++ instance methods. + CallingConv getDefaultMethodCallConv(); + + /// \brief Retrieves the canonical representation of the given + /// calling convention. + CallingConv getCanonicalCallConv(CallingConv CC) const { + if (!LangOpts.MRTD && CC == CC_C) + return CC_Default; + return CC; + } + + /// \brief Determines whether two calling conventions name the same + /// calling convention. + bool isSameCallConv(CallingConv lcc, CallingConv rcc) { + return (getCanonicalCallConv(lcc) == getCanonicalCallConv(rcc)); + } + + /// \brief Retrieves the "canonical" template name that refers to a + /// given template. + /// + /// The canonical template name is the simplest expression that can + /// be used to refer to a given template. For most templates, this + /// expression is just the template declaration itself. For example, + /// the template std::vector can be referred to via a variety of + /// names---std::vector, ::std::vector, vector (if vector is in + /// scope), etc.---but all of these names map down to the same + /// TemplateDecl, which is used to form the canonical template name. + /// + /// Dependent template names are more interesting. Here, the + /// template name could be something like T::template apply or + /// std::allocator<T>::template rebind, where the nested name + /// specifier itself is dependent. In this case, the canonical + /// template name uses the shortest form of the dependent + /// nested-name-specifier, which itself contains all canonical + /// types, values, and templates. + TemplateName getCanonicalTemplateName(TemplateName Name) const; + + /// \brief Determine whether the given template names refer to the same + /// template. + bool hasSameTemplateName(TemplateName X, TemplateName Y); + + /// \brief Retrieve the "canonical" template argument. + /// + /// The canonical template argument is the simplest template argument + /// (which may be a type, value, expression, or declaration) that + /// expresses the value of the argument. + TemplateArgument getCanonicalTemplateArgument(const TemplateArgument &Arg) + const; + + /// Type Query functions. If the type is an instance of the specified class, + /// return the Type pointer for the underlying maximally pretty type. This + /// is a member of ASTContext because this may need to do some amount of + /// canonicalization, e.g. to move type qualifiers into the element type. + const ArrayType *getAsArrayType(QualType T) const; + const ConstantArrayType *getAsConstantArrayType(QualType T) const { + return dyn_cast_or_null<ConstantArrayType>(getAsArrayType(T)); + } + const VariableArrayType *getAsVariableArrayType(QualType T) const { + return dyn_cast_or_null<VariableArrayType>(getAsArrayType(T)); + } + const IncompleteArrayType *getAsIncompleteArrayType(QualType T) const { + return dyn_cast_or_null<IncompleteArrayType>(getAsArrayType(T)); + } + const DependentSizedArrayType *getAsDependentSizedArrayType(QualType T) + const { + return dyn_cast_or_null<DependentSizedArrayType>(getAsArrayType(T)); + } + + /// getBaseElementType - Returns the innermost element type of an array type. + /// For example, will return "int" for int[m][n] + QualType getBaseElementType(const ArrayType *VAT) const; + + /// getBaseElementType - Returns the innermost element type of a type + /// (which needn't actually be an array type). + QualType getBaseElementType(QualType QT) const; + + /// getConstantArrayElementCount - Returns number of constant array elements. + uint64_t getConstantArrayElementCount(const ConstantArrayType *CA) const; + + /// \brief Perform adjustment on the parameter type of a function. + /// + /// This routine adjusts the given parameter type @p T to the actual + /// parameter type used by semantic analysis (C99 6.7.5.3p[7,8], + /// C++ [dcl.fct]p3). The adjusted parameter type is returned. + QualType getAdjustedParameterType(QualType T); + + /// \brief Retrieve the parameter type as adjusted for use in the signature + /// of a function, decaying array and function types and removing top-level + /// cv-qualifiers. + QualType getSignatureParameterType(QualType T); + + /// getArrayDecayedType - Return the properly qualified result of decaying the + /// specified array type to a pointer. This operation is non-trivial when + /// handling typedefs etc. The canonical type of "T" must be an array type, + /// this returns a pointer to a properly qualified element of the array. + /// + /// See C99 6.7.5.3p7 and C99 6.3.2.1p3. + QualType getArrayDecayedType(QualType T) const; + + /// getPromotedIntegerType - Returns the type that Promotable will + /// promote to: C99 6.3.1.1p2, assuming that Promotable is a promotable + /// integer type. + QualType getPromotedIntegerType(QualType PromotableType) const; + + /// \brief Recurses in pointer/array types until it finds an objc retainable + /// type and returns its ownership. + Qualifiers::ObjCLifetime getInnerObjCOwnership(QualType T) const; + + /// \brief Whether this is a promotable bitfield reference according + /// to C99 6.3.1.1p2, bullet 2 (and GCC extensions). + /// + /// \returns the type this bit-field will promote to, or NULL if no + /// promotion occurs. + QualType isPromotableBitField(Expr *E) const; + + /// getIntegerTypeOrder - Returns the highest ranked integer type: + /// C99 6.3.1.8p1. If LHS > RHS, return 1. If LHS == RHS, return 0. If + /// LHS < RHS, return -1. + int getIntegerTypeOrder(QualType LHS, QualType RHS) const; + + /// getFloatingTypeOrder - Compare the rank of the two specified floating + /// point types, ignoring the domain of the type (i.e. 'double' == + /// '_Complex double'). If LHS > RHS, return 1. If LHS == RHS, return 0. If + /// LHS < RHS, return -1. + int getFloatingTypeOrder(QualType LHS, QualType RHS) const; + + /// getFloatingTypeOfSizeWithinDomain - Returns a real floating + /// point or a complex type (based on typeDomain/typeSize). + /// 'typeDomain' is a real floating point or complex type. + /// 'typeSize' is a real floating point or complex type. + QualType getFloatingTypeOfSizeWithinDomain(QualType typeSize, + QualType typeDomain) const; + + unsigned getTargetAddressSpace(QualType T) const { + return getTargetAddressSpace(T.getQualifiers()); + } + + unsigned getTargetAddressSpace(Qualifiers Q) const { + return getTargetAddressSpace(Q.getAddressSpace()); + } + + unsigned getTargetAddressSpace(unsigned AS) const { + if (AS < LangAS::Offset || AS >= LangAS::Offset + LangAS::Count) + return AS; + else + return (*AddrSpaceMap)[AS - LangAS::Offset]; + } + +private: + // Helper for integer ordering + unsigned getIntegerRank(const Type *T) const; + +public: + + //===--------------------------------------------------------------------===// + // Type Compatibility Predicates + //===--------------------------------------------------------------------===// + + /// Compatibility predicates used to check assignment expressions. + bool typesAreCompatible(QualType T1, QualType T2, + bool CompareUnqualified = false); // C99 6.2.7p1 + + bool propertyTypesAreCompatible(QualType, QualType); + bool typesAreBlockPointerCompatible(QualType, QualType); + + bool isObjCIdType(QualType T) const { + return T == getObjCIdType(); + } + bool isObjCClassType(QualType T) const { + return T == getObjCClassType(); + } + bool isObjCSelType(QualType T) const { + return T == getObjCSelType(); + } + bool QualifiedIdConformsQualifiedId(QualType LHS, QualType RHS); + bool ObjCQualifiedIdTypesAreCompatible(QualType LHS, QualType RHS, + bool ForCompare); + + bool ObjCQualifiedClassTypesAreCompatible(QualType LHS, QualType RHS); + + // Check the safety of assignment from LHS to RHS + bool canAssignObjCInterfaces(const ObjCObjectPointerType *LHSOPT, + const ObjCObjectPointerType *RHSOPT); + bool canAssignObjCInterfaces(const ObjCObjectType *LHS, + const ObjCObjectType *RHS); + bool canAssignObjCInterfacesInBlockPointer( + const ObjCObjectPointerType *LHSOPT, + const ObjCObjectPointerType *RHSOPT, + bool BlockReturnType); + bool areComparableObjCPointerTypes(QualType LHS, QualType RHS); + QualType areCommonBaseCompatible(const ObjCObjectPointerType *LHSOPT, + const ObjCObjectPointerType *RHSOPT); + bool canBindObjCObjectType(QualType To, QualType From); + + // Functions for calculating composite types + QualType mergeTypes(QualType, QualType, bool OfBlockPointer=false, + bool Unqualified = false, bool BlockReturnType = false); + QualType mergeFunctionTypes(QualType, QualType, bool OfBlockPointer=false, + bool Unqualified = false); + QualType mergeFunctionArgumentTypes(QualType, QualType, + bool OfBlockPointer=false, + bool Unqualified = false); + QualType mergeTransparentUnionType(QualType, QualType, + bool OfBlockPointer=false, + bool Unqualified = false); + + QualType mergeObjCGCQualifiers(QualType, QualType); + + bool FunctionTypesMatchOnNSConsumedAttrs( + const FunctionProtoType *FromFunctionType, + const FunctionProtoType *ToFunctionType); + + void ResetObjCLayout(const ObjCContainerDecl *CD) { + ObjCLayouts[CD] = 0; + } + + //===--------------------------------------------------------------------===// + // Integer Predicates + //===--------------------------------------------------------------------===// + + // The width of an integer, as defined in C99 6.2.6.2. This is the number + // of bits in an integer type excluding any padding bits. + unsigned getIntWidth(QualType T) const; + + // Per C99 6.2.5p6, for every signed integer type, there is a corresponding + // unsigned integer type. This method takes a signed type, and returns the + // corresponding unsigned integer type. + QualType getCorrespondingUnsignedType(QualType T); + + //===--------------------------------------------------------------------===// + // Type Iterators. + //===--------------------------------------------------------------------===// + + typedef std::vector<Type*>::iterator type_iterator; + typedef std::vector<Type*>::const_iterator const_type_iterator; + + type_iterator types_begin() { return Types.begin(); } + type_iterator types_end() { return Types.end(); } + const_type_iterator types_begin() const { return Types.begin(); } + const_type_iterator types_end() const { return Types.end(); } + + //===--------------------------------------------------------------------===// + // Integer Values + //===--------------------------------------------------------------------===// + + /// MakeIntValue - Make an APSInt of the appropriate width and + /// signedness for the given \arg Value and integer \arg Type. + llvm::APSInt MakeIntValue(uint64_t Value, QualType Type) const { + llvm::APSInt Res(getIntWidth(Type), + !Type->isSignedIntegerOrEnumerationType()); + Res = Value; + return Res; + } + + bool isSentinelNullExpr(const Expr *E); + + /// \brief Get the implementation of ObjCInterfaceDecl,or NULL if none exists. + ObjCImplementationDecl *getObjCImplementation(ObjCInterfaceDecl *D); + /// \brief Get the implementation of ObjCCategoryDecl, or NULL if none exists. + ObjCCategoryImplDecl *getObjCImplementation(ObjCCategoryDecl *D); + + /// \brief returns true if there is at lease one @implementation in TU. + bool AnyObjCImplementation() { + return !ObjCImpls.empty(); + } + + /// \brief Set the implementation of ObjCInterfaceDecl. + void setObjCImplementation(ObjCInterfaceDecl *IFaceD, + ObjCImplementationDecl *ImplD); + /// \brief Set the implementation of ObjCCategoryDecl. + void setObjCImplementation(ObjCCategoryDecl *CatD, + ObjCCategoryImplDecl *ImplD); + + /// \brief Get the duplicate declaration of a ObjCMethod in the same + /// interface, or null if non exists. + const ObjCMethodDecl *getObjCMethodRedeclaration( + const ObjCMethodDecl *MD) const { + llvm::DenseMap<const ObjCMethodDecl*, const ObjCMethodDecl*>::const_iterator + I = ObjCMethodRedecls.find(MD); + if (I == ObjCMethodRedecls.end()) + return 0; + return I->second; + } + + void setObjCMethodRedeclaration(const ObjCMethodDecl *MD, + const ObjCMethodDecl *Redecl) { + ObjCMethodRedecls[MD] = Redecl; + } + + /// \brief Returns the objc interface that \arg ND belongs to if it is a + /// objc method/property/ivar etc. that is part of an interface, + /// otherwise returns null. + ObjCInterfaceDecl *getObjContainingInterface(NamedDecl *ND) const; + + /// \brief Set the copy inialization expression of a block var decl. + void setBlockVarCopyInits(VarDecl*VD, Expr* Init); + /// \brief Get the copy initialization expression of VarDecl,or NULL if + /// none exists. + Expr *getBlockVarCopyInits(const VarDecl*VD); + + /// \brief Allocate an uninitialized TypeSourceInfo. + /// + /// The caller should initialize the memory held by TypeSourceInfo using + /// the TypeLoc wrappers. + /// + /// \param T the type that will be the basis for type source info. This type + /// should refer to how the declarator was written in source code, not to + /// what type semantic analysis resolved the declarator to. + /// + /// \param Size the size of the type info to create, or 0 if the size + /// should be calculated based on the type. + TypeSourceInfo *CreateTypeSourceInfo(QualType T, unsigned Size = 0) const; + + /// \brief Allocate a TypeSourceInfo where all locations have been + /// initialized to a given location, which defaults to the empty + /// location. + TypeSourceInfo * + getTrivialTypeSourceInfo(QualType T, + SourceLocation Loc = SourceLocation()) const; + + TypeSourceInfo *getNullTypeSourceInfo() { return &NullTypeSourceInfo; } + + /// \brief Add a deallocation callback that will be invoked when the + /// ASTContext is destroyed. + /// + /// \brief Callback A callback function that will be invoked on destruction. + /// + /// \brief Data Pointer data that will be provided to the callback function + /// when it is called. + void AddDeallocation(void (*Callback)(void*), void *Data); + + GVALinkage GetGVALinkageForFunction(const FunctionDecl *FD); + GVALinkage GetGVALinkageForVariable(const VarDecl *VD); + + /// \brief Determines if the decl can be CodeGen'ed or deserialized from PCH + /// lazily, only when used; this is only relevant for function or file scoped + /// var definitions. + /// + /// \returns true if the function/var must be CodeGen'ed/deserialized even if + /// it is not used. + bool DeclMustBeEmitted(const Decl *D); + + /// \brief Retrieve the lambda mangling number for a lambda expression. + unsigned getLambdaManglingNumber(CXXMethodDecl *CallOperator); + + /// \brief Used by ParmVarDecl to store on the side the + /// index of the parameter when it exceeds the size of the normal bitfield. + void setParameterIndex(const ParmVarDecl *D, unsigned index); + + /// \brief Used by ParmVarDecl to retrieve on the side the + /// index of the parameter when it exceeds the size of the normal bitfield. + unsigned getParameterIndex(const ParmVarDecl *D) const; + + //===--------------------------------------------------------------------===// + // Statistics + //===--------------------------------------------------------------------===// + + /// \brief The number of implicitly-declared default constructors. + static unsigned NumImplicitDefaultConstructors; + + /// \brief The number of implicitly-declared default constructors for + /// which declarations were built. + static unsigned NumImplicitDefaultConstructorsDeclared; + + /// \brief The number of implicitly-declared copy constructors. + static unsigned NumImplicitCopyConstructors; + + /// \brief The number of implicitly-declared copy constructors for + /// which declarations were built. + static unsigned NumImplicitCopyConstructorsDeclared; + + /// \brief The number of implicitly-declared move constructors. + static unsigned NumImplicitMoveConstructors; + + /// \brief The number of implicitly-declared move constructors for + /// which declarations were built. + static unsigned NumImplicitMoveConstructorsDeclared; + + /// \brief The number of implicitly-declared copy assignment operators. + static unsigned NumImplicitCopyAssignmentOperators; + + /// \brief The number of implicitly-declared copy assignment operators for + /// which declarations were built. + static unsigned NumImplicitCopyAssignmentOperatorsDeclared; + + /// \brief The number of implicitly-declared move assignment operators. + static unsigned NumImplicitMoveAssignmentOperators; + + /// \brief The number of implicitly-declared move assignment operators for + /// which declarations were built. + static unsigned NumImplicitMoveAssignmentOperatorsDeclared; + + /// \brief The number of implicitly-declared destructors. + static unsigned NumImplicitDestructors; + + /// \brief The number of implicitly-declared destructors for which + /// declarations were built. + static unsigned NumImplicitDestructorsDeclared; + +private: + ASTContext(const ASTContext&); // DO NOT IMPLEMENT + void operator=(const ASTContext&); // DO NOT IMPLEMENT + +public: + /// \brief Initialize built-in types. + /// + /// This routine may only be invoked once for a given ASTContext object. + /// It is normally invoked by the ASTContext constructor. However, the + /// constructor can be asked to delay initialization, which places the burden + /// of calling this function on the user of that object. + /// + /// \param Target The target + void InitBuiltinTypes(const TargetInfo &Target); + +private: + void InitBuiltinType(CanQualType &R, BuiltinType::Kind K); + + // Return the ObjC type encoding for a given type. + void getObjCEncodingForTypeImpl(QualType t, std::string &S, + bool ExpandPointedToStructures, + bool ExpandStructures, + const FieldDecl *Field, + bool OutermostType = false, + bool EncodingProperty = false, + bool StructField = false, + bool EncodeBlockParameters = false, + bool EncodeClassNames = false) const; + + // Adds the encoding of the structure's members. + void getObjCEncodingForStructureImpl(RecordDecl *RD, std::string &S, + const FieldDecl *Field, + bool includeVBases = true) const; + + // Adds the encoding of a method parameter or return type. + void getObjCEncodingForMethodParameter(Decl::ObjCDeclQualifier QT, + QualType T, std::string& S, + bool Extended) const; + + const ASTRecordLayout & + getObjCLayout(const ObjCInterfaceDecl *D, + const ObjCImplementationDecl *Impl) const; + +private: + /// \brief A set of deallocations that should be performed when the + /// ASTContext is destroyed. + SmallVector<std::pair<void (*)(void*), void *>, 16> Deallocations; + + // FIXME: This currently contains the set of StoredDeclMaps used + // by DeclContext objects. This probably should not be in ASTContext, + // but we include it here so that ASTContext can quickly deallocate them. + llvm::PointerIntPair<StoredDeclsMap*,1> LastSDM; + + /// \brief A counter used to uniquely identify "blocks". + mutable unsigned int UniqueBlockByRefTypeID; + + friend class DeclContext; + friend class DeclarationNameTable; + void ReleaseDeclContextMaps(); +}; + +/// @brief Utility function for constructing a nullary selector. +static inline Selector GetNullarySelector(StringRef name, ASTContext& Ctx) { + IdentifierInfo* II = &Ctx.Idents.get(name); + return Ctx.Selectors.getSelector(0, &II); +} + +/// @brief Utility function for constructing an unary selector. +static inline Selector GetUnarySelector(StringRef name, ASTContext& Ctx) { + IdentifierInfo* II = &Ctx.Idents.get(name); + return Ctx.Selectors.getSelector(1, &II); +} + +} // end namespace clang + +// operator new and delete aren't allowed inside namespaces. + +/// @brief Placement new for using the ASTContext's allocator. +/// +/// This placement form of operator new uses the ASTContext's allocator for +/// obtaining memory. +/// +/// IMPORTANT: These are also declared in clang/AST/Attr.h! Any changes here +/// need to also be made there. +/// +/// We intentionally avoid using a nothrow specification here so that the calls +/// to this operator will not perform a null check on the result -- the +/// underlying allocator never returns null pointers. +/// +/// Usage looks like this (assuming there's an ASTContext 'Context' in scope): +/// @code +/// // Default alignment (8) +/// IntegerLiteral *Ex = new (Context) IntegerLiteral(arguments); +/// // Specific alignment +/// IntegerLiteral *Ex2 = new (Context, 4) IntegerLiteral(arguments); +/// @endcode +/// Please note that you cannot use delete on the pointer; it must be +/// deallocated using an explicit destructor call followed by +/// @c Context.Deallocate(Ptr). +/// +/// @param Bytes The number of bytes to allocate. Calculated by the compiler. +/// @param C The ASTContext that provides the allocator. +/// @param Alignment The alignment of the allocated memory (if the underlying +/// allocator supports it). +/// @return The allocated memory. Could be NULL. +inline void *operator new(size_t Bytes, const clang::ASTContext &C, + size_t Alignment) { + return C.Allocate(Bytes, Alignment); +} +/// @brief Placement delete companion to the new above. +/// +/// This operator is just a companion to the new above. There is no way of +/// invoking it directly; see the new operator for more details. This operator +/// is called implicitly by the compiler if a placement new expression using +/// the ASTContext throws in the object constructor. +inline void operator delete(void *Ptr, const clang::ASTContext &C, size_t) { + C.Deallocate(Ptr); +} + +/// This placement form of operator new[] uses the ASTContext's allocator for +/// obtaining memory. +/// +/// We intentionally avoid using a nothrow specification here so that the calls +/// to this operator will not perform a null check on the result -- the +/// underlying allocator never returns null pointers. +/// +/// Usage looks like this (assuming there's an ASTContext 'Context' in scope): +/// @code +/// // Default alignment (8) +/// char *data = new (Context) char[10]; +/// // Specific alignment +/// char *data = new (Context, 4) char[10]; +/// @endcode +/// Please note that you cannot use delete on the pointer; it must be +/// deallocated using an explicit destructor call followed by +/// @c Context.Deallocate(Ptr). +/// +/// @param Bytes The number of bytes to allocate. Calculated by the compiler. +/// @param C The ASTContext that provides the allocator. +/// @param Alignment The alignment of the allocated memory (if the underlying +/// allocator supports it). +/// @return The allocated memory. Could be NULL. +inline void *operator new[](size_t Bytes, const clang::ASTContext& C, + size_t Alignment = 8) { + return C.Allocate(Bytes, Alignment); +} + +/// @brief Placement delete[] companion to the new[] above. +/// +/// This operator is just a companion to the new[] above. There is no way of +/// invoking it directly; see the new[] operator for more details. This operator +/// is called implicitly by the compiler if a placement new[] expression using +/// the ASTContext throws in the object constructor. +inline void operator delete[](void *Ptr, const clang::ASTContext &C, size_t) { + C.Deallocate(Ptr); +} + +#endif diff --git a/clang/include/clang/AST/ASTDiagnostic.h b/clang/include/clang/AST/ASTDiagnostic.h new file mode 100644 index 0000000..64e955e --- /dev/null +++ b/clang/include/clang/AST/ASTDiagnostic.h @@ -0,0 +1,50 @@ +//===--- ASTDiagnostic.h - Diagnostics for the AST library ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_DIAGNOSTICAST_H +#define LLVM_CLANG_DIAGNOSTICAST_H + +#include "clang/Basic/Diagnostic.h" + +namespace clang { + namespace diag { + enum { +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\ + SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM, +#define ASTSTART +#include "clang/Basic/DiagnosticASTKinds.inc" +#undef DIAG + NUM_BUILTIN_AST_DIAGNOSTICS + }; + } // end namespace diag + + /// \brief DiagnosticsEngine argument formatting function for diagnostics that + /// involve AST nodes. + /// + /// This function formats diagnostic arguments for various AST nodes, + /// including types, declaration names, nested name specifiers, and + /// declaration contexts, into strings that can be printed as part of + /// diagnostics. It is meant to be used as the argument to + /// \c DiagnosticsEngine::SetArgToStringFn(), where the cookie is an \c + /// ASTContext pointer. + void FormatASTNodeDiagnosticArgument( + DiagnosticsEngine::ArgumentKind Kind, + intptr_t Val, + const char *Modifier, + unsigned ModLen, + const char *Argument, + unsigned ArgLen, + const DiagnosticsEngine::ArgumentValue *PrevArgs, + unsigned NumPrevArgs, + SmallVectorImpl<char> &Output, + void *Cookie, + ArrayRef<intptr_t> QualTypeVals); +} // end namespace clang + +#endif diff --git a/clang/include/clang/AST/ASTImporter.h b/clang/include/clang/AST/ASTImporter.h new file mode 100644 index 0000000..7157efe --- /dev/null +++ b/clang/include/clang/AST/ASTImporter.h @@ -0,0 +1,278 @@ +//===--- ASTImporter.h - Importing ASTs from other Contexts -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ASTImporter class which imports AST nodes from one +// context into another context. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_AST_ASTIMPORTER_H +#define LLVM_CLANG_AST_ASTIMPORTER_H + +#include "clang/AST/DeclarationName.h" +#include "clang/AST/Type.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SmallVector.h" + +namespace clang { + class ASTContext; + class Decl; + class DeclContext; + class DiagnosticsEngine; + class Expr; + class FileManager; + class IdentifierInfo; + class NestedNameSpecifier; + class Stmt; + class TypeSourceInfo; + + /// \brief Imports selected nodes from one AST context into another context, + /// merging AST nodes where appropriate. + class ASTImporter { + public: + typedef llvm::DenseSet<std::pair<Decl *, Decl *> > NonEquivalentDeclSet; + + private: + /// \brief The contexts we're importing to and from. + ASTContext &ToContext, &FromContext; + + /// \brief The file managers we're importing to and from. + FileManager &ToFileManager, &FromFileManager; + + /// \brief Whether to perform a minimal import. + bool Minimal; + + /// \brief Mapping from the already-imported types in the "from" context + /// to the corresponding types in the "to" context. + llvm::DenseMap<const Type *, const Type *> ImportedTypes; + + /// \brief Mapping from the already-imported declarations in the "from" + /// context to the corresponding declarations in the "to" context. + llvm::DenseMap<Decl *, Decl *> ImportedDecls; + + /// \brief Mapping from the already-imported statements in the "from" + /// context to the corresponding statements in the "to" context. + llvm::DenseMap<Stmt *, Stmt *> ImportedStmts; + + /// \brief Mapping from the already-imported FileIDs in the "from" source + /// manager to the corresponding FileIDs in the "to" source manager. + llvm::DenseMap<FileID, FileID> ImportedFileIDs; + + /// \brief Imported, anonymous tag declarations that are missing their + /// corresponding typedefs. + SmallVector<TagDecl *, 4> AnonTagsWithPendingTypedefs; + + /// \brief Declaration (from, to) pairs that are known not to be equivalent + /// (which we have already complained about). + NonEquivalentDeclSet NonEquivalentDecls; + + public: + /// \brief Create a new AST importer. + /// + /// \param ToContext The context we'll be importing into. + /// + /// \param ToFileManager The file manager we'll be importing into. + /// + /// \param FromContext The context we'll be importing from. + /// + /// \param FromFileManager The file manager we'll be importing into. + /// + /// \param MinimalImport If true, the importer will attempt to import + /// as little as it can, e.g., by importing declarations as forward + /// declarations that can be completed at a later point. + ASTImporter(ASTContext &ToContext, FileManager &ToFileManager, + ASTContext &FromContext, FileManager &FromFileManager, + bool MinimalImport); + + virtual ~ASTImporter(); + + /// \brief Whether the importer will perform a minimal import, creating + /// to-be-completed forward declarations when possible. + bool isMinimalImport() const { return Minimal; } + + /// \brief Import the given type from the "from" context into the "to" + /// context. + /// + /// \returns the equivalent type in the "to" context, or a NULL type if + /// an error occurred. + QualType Import(QualType FromT); + + /// \brief Import the given type source information from the + /// "from" context into the "to" context. + /// + /// \returns the equivalent type source information in the "to" + /// context, or NULL if an error occurred. + TypeSourceInfo *Import(TypeSourceInfo *FromTSI); + + /// \brief Import the given declaration from the "from" context into the + /// "to" context. + /// + /// \returns the equivalent declaration in the "to" context, or a NULL type + /// if an error occurred. + Decl *Import(Decl *FromD); + + /// \brief Import the given declaration context from the "from" + /// AST context into the "to" AST context. + /// + /// \returns the equivalent declaration context in the "to" + /// context, or a NULL type if an error occurred. + DeclContext *ImportContext(DeclContext *FromDC); + + /// \brief Import the given expression from the "from" context into the + /// "to" context. + /// + /// \returns the equivalent expression in the "to" context, or NULL if + /// an error occurred. + Expr *Import(Expr *FromE); + + /// \brief Import the given statement from the "from" context into the + /// "to" context. + /// + /// \returns the equivalent statement in the "to" context, or NULL if + /// an error occurred. + Stmt *Import(Stmt *FromS); + + /// \brief Import the given nested-name-specifier from the "from" + /// context into the "to" context. + /// + /// \returns the equivalent nested-name-specifier in the "to" + /// context, or NULL if an error occurred. + NestedNameSpecifier *Import(NestedNameSpecifier *FromNNS); + + /// \brief Import the given nested-name-specifier from the "from" + /// context into the "to" context. + /// + /// \returns the equivalent nested-name-specifier in the "to" + /// context. + NestedNameSpecifierLoc Import(NestedNameSpecifierLoc FromNNS); + + /// \brief Import the goven template name from the "from" context into the + /// "to" context. + TemplateName Import(TemplateName From); + + /// \brief Import the given source location from the "from" context into + /// the "to" context. + /// + /// \returns the equivalent source location in the "to" context, or an + /// invalid source location if an error occurred. + SourceLocation Import(SourceLocation FromLoc); + + /// \brief Import the given source range from the "from" context into + /// the "to" context. + /// + /// \returns the equivalent source range in the "to" context, or an + /// invalid source location if an error occurred. + SourceRange Import(SourceRange FromRange); + + /// \brief Import the given declaration name from the "from" + /// context into the "to" context. + /// + /// \returns the equivalent declaration name in the "to" context, + /// or an empty declaration name if an error occurred. + DeclarationName Import(DeclarationName FromName); + + /// \brief Import the given identifier from the "from" context + /// into the "to" context. + /// + /// \returns the equivalent identifier in the "to" context. + IdentifierInfo *Import(const IdentifierInfo *FromId); + + /// \brief Import the given Objective-C selector from the "from" + /// context into the "to" context. + /// + /// \returns the equivalent selector in the "to" context. + Selector Import(Selector FromSel); + + /// \brief Import the given file ID from the "from" context into the + /// "to" context. + /// + /// \returns the equivalent file ID in the source manager of the "to" + /// context. + FileID Import(FileID); + + /// \brief Import the definition of the given declaration, including all of + /// the declarations it contains. + /// + /// This routine is intended to be used + void ImportDefinition(Decl *From); + + /// \brief Cope with a name conflict when importing a declaration into the + /// given context. + /// + /// This routine is invoked whenever there is a name conflict while + /// importing a declaration. The returned name will become the name of the + /// imported declaration. By default, the returned name is the same as the + /// original name, leaving the conflict unresolve such that name lookup + /// for this name is likely to find an ambiguity later. + /// + /// Subclasses may override this routine to resolve the conflict, e.g., by + /// renaming the declaration being imported. + /// + /// \param Name the name of the declaration being imported, which conflicts + /// with other declarations. + /// + /// \param DC the declaration context (in the "to" AST context) in which + /// the name is being imported. + /// + /// \param IDNS the identifier namespace in which the name will be found. + /// + /// \param Decls the set of declarations with the same name as the + /// declaration being imported. + /// + /// \param NumDecls the number of conflicting declarations in \p Decls. + /// + /// \returns the name that the newly-imported declaration should have. + virtual DeclarationName HandleNameConflict(DeclarationName Name, + DeclContext *DC, + unsigned IDNS, + NamedDecl **Decls, + unsigned NumDecls); + + /// \brief Retrieve the context that AST nodes are being imported into. + ASTContext &getToContext() const { return ToContext; } + + /// \brief Retrieve the context that AST nodes are being imported from. + ASTContext &getFromContext() const { return FromContext; } + + /// \brief Retrieve the file manager that AST nodes are being imported into. + FileManager &getToFileManager() const { return ToFileManager; } + + /// \brief Retrieve the file manager that AST nodes are being imported from. + FileManager &getFromFileManager() const { return FromFileManager; } + + /// \brief Report a diagnostic in the "to" context. + DiagnosticBuilder ToDiag(SourceLocation Loc, unsigned DiagID); + + /// \brief Report a diagnostic in the "from" context. + DiagnosticBuilder FromDiag(SourceLocation Loc, unsigned DiagID); + + /// \brief Return the set of declarations that we know are not equivalent. + NonEquivalentDeclSet &getNonEquivalentDecls() { return NonEquivalentDecls; } + + /// \brief Called for ObjCInterfaceDecl, ObjCProtocolDecl, and TagDecl. + /// Mark the Decl as complete, filling it in as much as possible. + /// + /// \param D A declaration in the "to" context. + virtual void CompleteDecl(Decl* D); + + /// \brief Note that we have imported the "from" declaration by mapping it + /// to the (potentially-newly-created) "to" declaration. + /// + /// Subclasses can override this function to observe all of the \c From -> + /// \c To declaration mappings as they are imported. + virtual Decl *Imported(Decl *From, Decl *To); + + /// \brief Determine whether the given types are structurally + /// equivalent. + bool IsStructurallyEquivalent(QualType From, QualType To); + }; +} + +#endif // LLVM_CLANG_AST_ASTIMPORTER_H diff --git a/clang/include/clang/AST/ASTMutationListener.h b/clang/include/clang/AST/ASTMutationListener.h new file mode 100644 index 0000000..cb038a0 --- /dev/null +++ b/clang/include/clang/AST/ASTMutationListener.h @@ -0,0 +1,84 @@ +//===--- ASTMutationListener.h - AST Mutation Interface --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ASTMutationListener interface. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_AST_ASTMUTATIONLISTENER_H +#define LLVM_CLANG_AST_ASTMUTATIONLISTENER_H + +namespace clang { + class Decl; + class DeclContext; + class TagDecl; + class CXXRecordDecl; + class ClassTemplateDecl; + class ClassTemplateSpecializationDecl; + class FunctionDecl; + class FunctionTemplateDecl; + class ObjCCategoryDecl; + class ObjCInterfaceDecl; + class ObjCContainerDecl; + class ObjCPropertyDecl; + +/// \brief An abstract interface that should be implemented by listeners +/// that want to be notified when an AST entity gets modified after its +/// initial creation. +class ASTMutationListener { +public: + virtual ~ASTMutationListener(); + + /// \brief A new TagDecl definition was completed. + virtual void CompletedTagDefinition(const TagDecl *D) { } + + /// \brief A new declaration with name has been added to a DeclContext. + virtual void AddedVisibleDecl(const DeclContext *DC, const Decl *D) {} + + /// \brief An implicit member was added after the definition was completed. + virtual void AddedCXXImplicitMember(const CXXRecordDecl *RD, const Decl *D) {} + + /// \brief A template specialization (or partial one) was added to the + /// template declaration. + virtual void AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD, + const ClassTemplateSpecializationDecl *D) {} + + /// \brief A template specialization (or partial one) was added to the + /// template declaration. + virtual void AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD, + const FunctionDecl *D) {} + + /// \brief An implicit member got a definition. + virtual void CompletedImplicitDefinition(const FunctionDecl *D) {} + + /// \brief A static data member was implicitly instantiated. + virtual void StaticDataMemberInstantiated(const VarDecl *D) {} + + /// \brief A new objc category class was added for an interface. + virtual void AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD, + const ObjCInterfaceDecl *IFD) {} + + /// \brief A objc class extension redeclared or introduced a property. + /// + /// \param Prop the property in the class extension + /// + /// \param OrigProp the property from the original interface that was declared + /// or null if the property was introduced. + /// + /// \param ClassExt the class extension. + virtual void AddedObjCPropertyInClassExtension(const ObjCPropertyDecl *Prop, + const ObjCPropertyDecl *OrigProp, + const ObjCCategoryDecl *ClassExt) {} + + // NOTE: If new methods are added they should also be added to + // MultiplexASTMutationListener. +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/AST/ASTVector.h b/clang/include/clang/AST/ASTVector.h new file mode 100644 index 0000000..217dfad --- /dev/null +++ b/clang/include/clang/AST/ASTVector.h @@ -0,0 +1,397 @@ +//===- ASTVector.h - Vector that uses ASTContext for allocation --*- C++ -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides ASTVector, a vector ADT whose contents are +// allocated using the allocator associated with an ASTContext.. +// +//===----------------------------------------------------------------------===// + +// FIXME: Most of this is copy-and-paste from BumpVector.h and SmallVector.h. +// We can refactor this core logic into something common. + +#ifndef LLVM_CLANG_AST_VECTOR +#define LLVM_CLANG_AST_VECTOR + +#include "llvm/Support/type_traits.h" +#include "llvm/Support/Allocator.h" +#include "llvm/ADT/PointerIntPair.h" +#include <algorithm> +#include <memory> +#include <cstring> + +#ifdef _MSC_VER +namespace std { +#if _MSC_VER <= 1310 + // Work around flawed VC++ implementation of std::uninitialized_copy. Define + // additional overloads so that elements with pointer types are recognized as + // scalars and not objects, causing bizarre type conversion errors. + template<class T1, class T2> + inline _Scalar_ptr_iterator_tag _Ptr_cat(T1 **, T2 **) { + _Scalar_ptr_iterator_tag _Cat; + return _Cat; + } + + template<class T1, class T2> + inline _Scalar_ptr_iterator_tag _Ptr_cat(T1* const *, T2 **) { + _Scalar_ptr_iterator_tag _Cat; + return _Cat; + } +#else + // FIXME: It is not clear if the problem is fixed in VS 2005. What is clear + // is that the above hack won't work if it wasn't fixed. +#endif +} +#endif + +namespace clang { + +template<typename T> +class ASTVector { + T *Begin, *End, *Capacity; + + void setEnd(T *P) { this->End = P; } + +public: + // Default ctor - Initialize to empty. + explicit ASTVector(ASTContext &C, unsigned N = 0) + : Begin(NULL), End(NULL), Capacity(NULL) { + reserve(C, N); + } + + ~ASTVector() { + if (llvm::is_class<T>::value) { + // Destroy the constructed elements in the vector. + destroy_range(Begin, End); + } + } + + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef T value_type; + typedef T* iterator; + typedef const T* const_iterator; + + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + typedef std::reverse_iterator<iterator> reverse_iterator; + + typedef T& reference; + typedef const T& const_reference; + typedef T* pointer; + typedef const T* const_pointer; + + // forward iterator creation methods. + iterator begin() { return Begin; } + const_iterator begin() const { return Begin; } + iterator end() { return End; } + const_iterator end() const { return End; } + + // reverse iterator creation methods. + reverse_iterator rbegin() { return reverse_iterator(end()); } + const_reverse_iterator rbegin() const{ return const_reverse_iterator(end()); } + reverse_iterator rend() { return reverse_iterator(begin()); } + const_reverse_iterator rend() const { return const_reverse_iterator(begin());} + + bool empty() const { return Begin == End; } + size_type size() const { return End-Begin; } + + reference operator[](unsigned idx) { + assert(Begin + idx < End); + return Begin[idx]; + } + const_reference operator[](unsigned idx) const { + assert(Begin + idx < End); + return Begin[idx]; + } + + reference front() { + return begin()[0]; + } + const_reference front() const { + return begin()[0]; + } + + reference back() { + return end()[-1]; + } + const_reference back() const { + return end()[-1]; + } + + void pop_back() { + --End; + End->~T(); + } + + T pop_back_val() { + T Result = back(); + pop_back(); + return Result; + } + + void clear() { + if (llvm::is_class<T>::value) { + destroy_range(Begin, End); + } + End = Begin; + } + + /// data - Return a pointer to the vector's buffer, even if empty(). + pointer data() { + return pointer(Begin); + } + + /// data - Return a pointer to the vector's buffer, even if empty(). + const_pointer data() const { + return const_pointer(Begin); + } + + void push_back(const_reference Elt, ASTContext &C) { + if (End < Capacity) { + Retry: + new (End) T(Elt); + ++End; + return; + } + grow(C); + goto Retry; + } + + void reserve(ASTContext &C, unsigned N) { + if (unsigned(Capacity-Begin) < N) + grow(C, N); + } + + /// capacity - Return the total number of elements in the currently allocated + /// buffer. + size_t capacity() const { return Capacity - Begin; } + + /// append - Add the specified range to the end of the SmallVector. + /// + template<typename in_iter> + void append(ASTContext &C, in_iter in_start, in_iter in_end) { + size_type NumInputs = std::distance(in_start, in_end); + + if (NumInputs == 0) + return; + + // Grow allocated space if needed. + if (NumInputs > size_type(this->capacity_ptr()-this->end())) + this->grow(C, this->size()+NumInputs); + + // Copy the new elements over. + // TODO: NEED To compile time dispatch on whether in_iter is a random access + // iterator to use the fast uninitialized_copy. + std::uninitialized_copy(in_start, in_end, this->end()); + this->setEnd(this->end() + NumInputs); + } + + /// append - Add the specified range to the end of the SmallVector. + /// + void append(ASTContext &C, size_type NumInputs, const T &Elt) { + // Grow allocated space if needed. + if (NumInputs > size_type(this->capacity_ptr()-this->end())) + this->grow(C, this->size()+NumInputs); + + // Copy the new elements over. + std::uninitialized_fill_n(this->end(), NumInputs, Elt); + this->setEnd(this->end() + NumInputs); + } + + /// uninitialized_copy - Copy the range [I, E) onto the uninitialized memory + /// starting with "Dest", constructing elements into it as needed. + template<typename It1, typename It2> + static void uninitialized_copy(It1 I, It1 E, It2 Dest) { + std::uninitialized_copy(I, E, Dest); + } + + iterator insert(ASTContext &C, iterator I, const T &Elt) { + if (I == this->end()) { // Important special case for empty vector. + push_back(Elt); + return this->end()-1; + } + + if (this->EndX < this->CapacityX) { + Retry: + new (this->end()) T(this->back()); + this->setEnd(this->end()+1); + // Push everything else over. + std::copy_backward(I, this->end()-1, this->end()); + *I = Elt; + return I; + } + size_t EltNo = I-this->begin(); + this->grow(C); + I = this->begin()+EltNo; + goto Retry; + } + + iterator insert(ASTContext &C, iterator I, size_type NumToInsert, + const T &Elt) { + if (I == this->end()) { // Important special case for empty vector. + append(C, NumToInsert, Elt); + return this->end()-1; + } + + // Convert iterator to elt# to avoid invalidating iterator when we reserve() + size_t InsertElt = I - this->begin(); + + // Ensure there is enough space. + reserve(C, static_cast<unsigned>(this->size() + NumToInsert)); + + // Uninvalidate the iterator. + I = this->begin()+InsertElt; + + // If there are more elements between the insertion point and the end of the + // range than there are being inserted, we can use a simple approach to + // insertion. Since we already reserved space, we know that this won't + // reallocate the vector. + if (size_t(this->end()-I) >= NumToInsert) { + T *OldEnd = this->end(); + append(C, this->end()-NumToInsert, this->end()); + + // Copy the existing elements that get replaced. + std::copy_backward(I, OldEnd-NumToInsert, OldEnd); + + std::fill_n(I, NumToInsert, Elt); + return I; + } + + // Otherwise, we're inserting more elements than exist already, and we're + // not inserting at the end. + + // Copy over the elements that we're about to overwrite. + T *OldEnd = this->end(); + this->setEnd(this->end() + NumToInsert); + size_t NumOverwritten = OldEnd-I; + this->uninitialized_copy(I, OldEnd, this->end()-NumOverwritten); + + // Replace the overwritten part. + std::fill_n(I, NumOverwritten, Elt); + + // Insert the non-overwritten middle part. + std::uninitialized_fill_n(OldEnd, NumToInsert-NumOverwritten, Elt); + return I; + } + + template<typename ItTy> + iterator insert(ASTContext &C, iterator I, ItTy From, ItTy To) { + if (I == this->end()) { // Important special case for empty vector. + append(C, From, To); + return this->end()-1; + } + + size_t NumToInsert = std::distance(From, To); + // Convert iterator to elt# to avoid invalidating iterator when we reserve() + size_t InsertElt = I - this->begin(); + + // Ensure there is enough space. + reserve(C, static_cast<unsigned>(this->size() + NumToInsert)); + + // Uninvalidate the iterator. + I = this->begin()+InsertElt; + + // If there are more elements between the insertion point and the end of the + // range than there are being inserted, we can use a simple approach to + // insertion. Since we already reserved space, we know that this won't + // reallocate the vector. + if (size_t(this->end()-I) >= NumToInsert) { + T *OldEnd = this->end(); + append(C, this->end()-NumToInsert, this->end()); + + // Copy the existing elements that get replaced. + std::copy_backward(I, OldEnd-NumToInsert, OldEnd); + + std::copy(From, To, I); + return I; + } + + // Otherwise, we're inserting more elements than exist already, and we're + // not inserting at the end. + + // Copy over the elements that we're about to overwrite. + T *OldEnd = this->end(); + this->setEnd(this->end() + NumToInsert); + size_t NumOverwritten = OldEnd-I; + this->uninitialized_copy(I, OldEnd, this->end()-NumOverwritten); + + // Replace the overwritten part. + for (; NumOverwritten > 0; --NumOverwritten) { + *I = *From; + ++I; ++From; + } + + // Insert the non-overwritten middle part. + this->uninitialized_copy(From, To, OldEnd); + return I; + } + + void resize(ASTContext &C, unsigned N, const T &NV) { + if (N < this->size()) { + this->destroy_range(this->begin()+N, this->end()); + this->setEnd(this->begin()+N); + } else if (N > this->size()) { + if (this->capacity() < N) + this->grow(C, N); + construct_range(this->end(), this->begin()+N, NV); + this->setEnd(this->begin()+N); + } + } + +private: + /// grow - double the size of the allocated memory, guaranteeing space for at + /// least one more element or MinSize if specified. + void grow(ASTContext &C, size_type MinSize = 1); + + void construct_range(T *S, T *E, const T &Elt) { + for (; S != E; ++S) + new (S) T(Elt); + } + + void destroy_range(T *S, T *E) { + while (S != E) { + --E; + E->~T(); + } + } + +protected: + iterator capacity_ptr() { return (iterator)this->Capacity; } +}; + +// Define this out-of-line to dissuade the C++ compiler from inlining it. +template <typename T> +void ASTVector<T>::grow(ASTContext &C, size_t MinSize) { + size_t CurCapacity = Capacity-Begin; + size_t CurSize = size(); + size_t NewCapacity = 2*CurCapacity; + if (NewCapacity < MinSize) + NewCapacity = MinSize; + + // Allocate the memory from the ASTContext. + T *NewElts = new (C) T[NewCapacity]; + + // Copy the elements over. + if (llvm::is_class<T>::value) { + std::uninitialized_copy(Begin, End, NewElts); + // Destroy the original elements. + destroy_range(Begin, End); + } + else { + // Use memcpy for PODs (std::uninitialized_copy optimizes to memmove). + memcpy(NewElts, Begin, CurSize * sizeof(T)); + } + + C.Deallocate(Begin); + Begin = NewElts; + End = NewElts+CurSize; + Capacity = Begin+NewCapacity; +} + +} // end: clang namespace +#endif diff --git a/clang/include/clang/AST/Attr.h b/clang/include/clang/AST/Attr.h new file mode 100644 index 0000000..ef1aa25 --- /dev/null +++ b/clang/include/clang/AST/Attr.h @@ -0,0 +1,254 @@ +//===--- Attr.h - Classes for representing expressions ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Attr interface and subclasses. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_ATTR_H +#define LLVM_CLANG_AST_ATTR_H + +#include "clang/Basic/LLVM.h" +#include "clang/Basic/AttrKinds.h" +#include "clang/AST/Type.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/VersionTuple.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include <cassert> +#include <cstring> +#include <algorithm> + +namespace clang { + class ASTContext; + class IdentifierInfo; + class ObjCInterfaceDecl; + class Expr; + class QualType; + class FunctionDecl; + class TypeSourceInfo; +} + +// Defined in ASTContext.h +void *operator new(size_t Bytes, const clang::ASTContext &C, + size_t Alignment = 16); +// FIXME: Being forced to not have a default argument here due to redeclaration +// rules on default arguments sucks +void *operator new[](size_t Bytes, const clang::ASTContext &C, + size_t Alignment); + +// It is good practice to pair new/delete operators. Also, MSVC gives many +// warnings if a matching delete overload is not declared, even though the +// throw() spec guarantees it will not be implicitly called. +void operator delete(void *Ptr, const clang::ASTContext &C, size_t); +void operator delete[](void *Ptr, const clang::ASTContext &C, size_t); + +namespace clang { + +/// Attr - This represents one attribute. +class Attr { +private: + SourceRange Range; + unsigned AttrKind : 16; + +protected: + bool Inherited : 1; + + virtual ~Attr(); + + void* operator new(size_t bytes) throw() { + llvm_unreachable("Attrs cannot be allocated with regular 'new'."); + } + void operator delete(void* data) throw() { + llvm_unreachable("Attrs cannot be released with regular 'delete'."); + } + +public: + // Forward so that the regular new and delete do not hide global ones. + void* operator new(size_t Bytes, ASTContext &C, + size_t Alignment = 16) throw() { + return ::operator new(Bytes, C, Alignment); + } + void operator delete(void *Ptr, ASTContext &C, + size_t Alignment) throw() { + return ::operator delete(Ptr, C, Alignment); + } + +protected: + Attr(attr::Kind AK, SourceRange R) + : Range(R), AttrKind(AK), Inherited(false) {} + +public: + + attr::Kind getKind() const { + return static_cast<attr::Kind>(AttrKind); + } + + SourceLocation getLocation() const { return Range.getBegin(); } + SourceRange getRange() const { return Range; } + void setRange(SourceRange R) { Range = R; } + + bool isInherited() const { return Inherited; } + + // Clone this attribute. + virtual Attr* clone(ASTContext &C) const = 0; + + virtual bool isLateParsed() const { return false; } + + // Pretty print this attribute. + virtual void printPretty(llvm::raw_ostream &OS, ASTContext &C) const = 0; + + // Implement isa/cast/dyncast/etc. + static bool classof(const Attr *) { return true; } +}; + +class InheritableAttr : public Attr { + virtual void anchor(); +protected: + InheritableAttr(attr::Kind AK, SourceRange R) + : Attr(AK, R) {} + +public: + void setInherited(bool I) { Inherited = I; } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Attr *A) { + return A->getKind() <= attr::LAST_INHERITABLE; + } + static bool classof(const InheritableAttr *) { return true; } +}; + +class InheritableParamAttr : public InheritableAttr { + virtual void anchor(); +protected: + InheritableParamAttr(attr::Kind AK, SourceRange R) + : InheritableAttr(AK, R) {} + +public: + // Implement isa/cast/dyncast/etc. + static bool classof(const Attr *A) { + return A->getKind() <= attr::LAST_INHERITABLE_PARAM; + } + static bool classof(const InheritableParamAttr *) { return true; } +}; + +#include "clang/AST/Attrs.inc" + +/// AttrVec - A vector of Attr, which is how they are stored on the AST. +typedef SmallVector<Attr*, 2> AttrVec; +typedef SmallVector<const Attr*, 2> ConstAttrVec; + +/// DestroyAttrs - Destroy the contents of an AttrVec. +inline void DestroyAttrs (AttrVec& V, ASTContext &C) { +} + +/// specific_attr_iterator - Iterates over a subrange of an AttrVec, only +/// providing attributes that are of a specifc type. +template <typename SpecificAttr> +class specific_attr_iterator { + /// Current - The current, underlying iterator. + /// In order to ensure we don't dereference an invalid iterator unless + /// specifically requested, we don't necessarily advance this all the + /// way. Instead, we advance it when an operation is requested; if the + /// operation is acting on what should be a past-the-end iterator, + /// then we offer no guarantees, but this way we do not dererence a + /// past-the-end iterator when we move to a past-the-end position. + mutable AttrVec::const_iterator Current; + + void AdvanceToNext() const { + while (!isa<SpecificAttr>(*Current)) + ++Current; + } + + void AdvanceToNext(AttrVec::const_iterator I) const { + while (Current != I && !isa<SpecificAttr>(*Current)) + ++Current; + } + +public: + typedef SpecificAttr* value_type; + typedef SpecificAttr* reference; + typedef SpecificAttr* pointer; + typedef std::forward_iterator_tag iterator_category; + typedef std::ptrdiff_t difference_type; + + specific_attr_iterator() : Current() { } + explicit specific_attr_iterator(AttrVec::const_iterator i) : Current(i) { } + + reference operator*() const { + AdvanceToNext(); + return cast<SpecificAttr>(*Current); + } + pointer operator->() const { + AdvanceToNext(); + return cast<SpecificAttr>(*Current); + } + + specific_attr_iterator& operator++() { + ++Current; + return *this; + } + specific_attr_iterator operator++(int) { + specific_attr_iterator Tmp(*this); + ++(*this); + return Tmp; + } + + friend bool operator==(specific_attr_iterator Left, + specific_attr_iterator Right) { + if (Left.Current < Right.Current) + Left.AdvanceToNext(Right.Current); + else + Right.AdvanceToNext(Left.Current); + return Left.Current == Right.Current; + } + friend bool operator!=(specific_attr_iterator Left, + specific_attr_iterator Right) { + return !(Left == Right); + } +}; + +template <typename T> +inline specific_attr_iterator<T> specific_attr_begin(const AttrVec& vec) { + return specific_attr_iterator<T>(vec.begin()); +} +template <typename T> +inline specific_attr_iterator<T> specific_attr_end(const AttrVec& vec) { + return specific_attr_iterator<T>(vec.end()); +} + +template <typename T> +inline bool hasSpecificAttr(const AttrVec& vec) { + return specific_attr_begin<T>(vec) != specific_attr_end<T>(vec); +} +template <typename T> +inline T *getSpecificAttr(const AttrVec& vec) { + specific_attr_iterator<T> i = specific_attr_begin<T>(vec); + if (i != specific_attr_end<T>(vec)) + return *i; + else + return 0; +} + +/// getMaxAlignment - Returns the highest alignment value found among +/// AlignedAttrs in an AttrVec, or 0 if there are none. +inline unsigned getMaxAttrAlignment(const AttrVec& V, ASTContext &Ctx) { + unsigned Align = 0; + specific_attr_iterator<AlignedAttr> i(V.begin()), e(V.end()); + for(; i != e; ++i) + Align = std::max(Align, i->getAlignment(Ctx)); + return Align; +} + +} // end namespace clang + +#endif diff --git a/clang/include/clang/AST/BaseSubobject.h b/clang/include/clang/AST/BaseSubobject.h new file mode 100644 index 0000000..6a036bb --- /dev/null +++ b/clang/include/clang/AST/BaseSubobject.h @@ -0,0 +1,87 @@ +//===--- BaseSubobject.h - BaseSubobject class ----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides a definition of the BaseSubobject class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_BASESUBOBJECT_H +#define LLVM_CLANG_AST_BASESUBOBJECT_H + +#include "clang/AST/CharUnits.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/type_traits.h" + +namespace clang { + class CXXRecordDecl; + +// BaseSubobject - Uniquely identifies a direct or indirect base class. +// Stores both the base class decl and the offset from the most derived class to +// the base class. Used for vtable and VTT generation. +class BaseSubobject { + /// Base - The base class declaration. + const CXXRecordDecl *Base; + + /// BaseOffset - The offset from the most derived class to the base class. + CharUnits BaseOffset; + +public: + BaseSubobject() { } + BaseSubobject(const CXXRecordDecl *Base, CharUnits BaseOffset) + : Base(Base), BaseOffset(BaseOffset) { } + + /// getBase - Returns the base class declaration. + const CXXRecordDecl *getBase() const { return Base; } + + /// getBaseOffset - Returns the base class offset. + CharUnits getBaseOffset() const { return BaseOffset; } + + friend bool operator==(const BaseSubobject &LHS, const BaseSubobject &RHS) { + return LHS.Base == RHS.Base && LHS.BaseOffset == RHS.BaseOffset; + } +}; + +} // end namespace clang + +namespace llvm { + +template<> struct DenseMapInfo<clang::BaseSubobject> { + static clang::BaseSubobject getEmptyKey() { + return clang::BaseSubobject( + DenseMapInfo<const clang::CXXRecordDecl *>::getEmptyKey(), + clang::CharUnits::fromQuantity(DenseMapInfo<int64_t>::getEmptyKey())); + } + + static clang::BaseSubobject getTombstoneKey() { + return clang::BaseSubobject( + DenseMapInfo<const clang::CXXRecordDecl *>::getTombstoneKey(), + clang::CharUnits::fromQuantity(DenseMapInfo<int64_t>::getTombstoneKey())); + } + + static unsigned getHashValue(const clang::BaseSubobject &Base) { + return + DenseMapInfo<const clang::CXXRecordDecl *>::getHashValue(Base.getBase()) ^ + DenseMapInfo<int64_t>::getHashValue(Base.getBaseOffset().getQuantity()); + } + + static bool isEqual(const clang::BaseSubobject &LHS, + const clang::BaseSubobject &RHS) { + return LHS == RHS; + } +}; + +// It's OK to treat BaseSubobject as a POD type. +template <> struct isPodLike<clang::BaseSubobject> { + static const bool value = true; +}; + +} + +#endif diff --git a/clang/include/clang/AST/BuiltinTypes.def b/clang/include/clang/AST/BuiltinTypes.def new file mode 100644 index 0000000..34e6fc5 --- /dev/null +++ b/clang/include/clang/AST/BuiltinTypes.def @@ -0,0 +1,224 @@ +//===-- BuiltinTypeNodes.def - Metadata about BuiltinTypes ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the database about various builtin singleton types. +// +// BuiltinType::Id is the enumerator defining the type. +// +// Context.SingletonId is the global singleton of this type. Some global +// singletons are shared by multiple types. +// +// BUILTIN_TYPE(Id, SingletonId) - A builtin type that has not been +// covered by any other #define. Defining this macro covers all +// the builtins. +// +// SIGNED_TYPE(Id, SingletonId) - A signed integral type. +// +// UNSIGNED_TYPE(Id, SingletonId) - An unsigned integral type. +// +// FLOATING_TYPE(Id, SingletonId) - A floating-point type. +// +// PLACEHOLDER_TYPE(Id, SingletonId) - A placeholder type. Placeholder +// types are used to perform context-sensitive checking of specific +// forms of expression. +// +// SHARED_SINGLETON_TYPE(Expansion) - The given expansion corresponds +// to a builtin which uses a shared singleton type. +// +//===----------------------------------------------------------------------===// + +#ifndef SIGNED_TYPE +#define SIGNED_TYPE(Id, SingletonId) BUILTIN_TYPE(Id, SingletonId) +#endif + +#ifndef UNSIGNED_TYPE +#define UNSIGNED_TYPE(Id, SingletonId) BUILTIN_TYPE(Id, SingletonId) +#endif + +#ifndef FLOATING_TYPE +#define FLOATING_TYPE(Id, SingletonId) BUILTIN_TYPE(Id, SingletonId) +#endif + +#ifndef PLACEHOLDER_TYPE +#define PLACEHOLDER_TYPE(Id, SingletonId) BUILTIN_TYPE(Id, SingletonId) +#endif + +#ifndef SHARED_SINGLETON_TYPE +#define SHARED_SINGLETON_TYPE(Expansion) Expansion +#endif + +//===- Builtin Types ------------------------------------------------------===// + +// void +BUILTIN_TYPE(Void, VoidTy) + +//===- Unsigned Types -----------------------------------------------------===// + +// 'bool' in C++, '_Bool' in C99 +UNSIGNED_TYPE(Bool, BoolTy) + +// 'char' for targets where it's unsigned +SHARED_SINGLETON_TYPE(UNSIGNED_TYPE(Char_U, CharTy)) + +// 'unsigned char', explicitly qualified +UNSIGNED_TYPE(UChar, UnsignedCharTy) + +// 'wchar_t' for targets where it's unsigned +SHARED_SINGLETON_TYPE(UNSIGNED_TYPE(WChar_U, WCharTy)) + +// 'char16_t' in C++ +UNSIGNED_TYPE(Char16, Char16Ty) + +// 'char32_t' in C++ +UNSIGNED_TYPE(Char32, Char32Ty) + +// 'unsigned short' +UNSIGNED_TYPE(UShort, UnsignedShortTy) + +// 'unsigned int' +UNSIGNED_TYPE(UInt, UnsignedIntTy) + +// 'unsigned long' +UNSIGNED_TYPE(ULong, UnsignedLongTy) + +// 'unsigned long long' +UNSIGNED_TYPE(ULongLong, UnsignedLongLongTy) + +// '__uint128_t' +UNSIGNED_TYPE(UInt128, UnsignedInt128Ty) + +//===- Signed Types -------------------------------------------------------===// + +// 'char' for targets where it's signed +SHARED_SINGLETON_TYPE(SIGNED_TYPE(Char_S, CharTy)) + +// 'signed char', explicitly qualified +SIGNED_TYPE(SChar, SignedCharTy) + +// 'wchar_t' for targets where it's signed +SHARED_SINGLETON_TYPE(SIGNED_TYPE(WChar_S, WCharTy)) + +// 'short' or 'signed short' +SIGNED_TYPE(Short, ShortTy) + +// 'int' or 'signed int' +SIGNED_TYPE(Int, IntTy) + +// 'long' or 'signed long' +SIGNED_TYPE(Long, LongTy) + +// 'long long' or 'signed long long' +SIGNED_TYPE(LongLong, LongLongTy) + +// '__int128_t' +SIGNED_TYPE(Int128, Int128Ty) + +//===- Floating point types -----------------------------------------------===// + +// 'half' in OpenCL, '__fp16' in ARM NEON. +FLOATING_TYPE(Half, HalfTy) + +// 'float' +FLOATING_TYPE(Float, FloatTy) + +// 'double' +FLOATING_TYPE(Double, DoubleTy) + +// 'long double' +FLOATING_TYPE(LongDouble, LongDoubleTy) + +//===- Language-specific types --------------------------------------------===// + +// This is the type of C++0x 'nullptr'. +BUILTIN_TYPE(NullPtr, NullPtrTy) + +// The primitive Objective C 'id' type. The user-visible 'id' +// type is a typedef of an ObjCObjectPointerType to an +// ObjCObjectType with this as its base. In fact, this only ever +// shows up in an AST as the base type of an ObjCObjectType. +BUILTIN_TYPE(ObjCId, ObjCBuiltinIdTy) + +// The primitive Objective C 'Class' type. The user-visible +// 'Class' type is a typedef of an ObjCObjectPointerType to an +// ObjCObjectType with this as its base. In fact, this only ever +// shows up in an AST as the base type of an ObjCObjectType. +BUILTIN_TYPE(ObjCClass, ObjCBuiltinClassTy) + +// The primitive Objective C 'SEL' type. The user-visible 'SEL' +// type is a typedef of a PointerType to this. +BUILTIN_TYPE(ObjCSel, ObjCBuiltinSelTy) + +// This represents the type of an expression whose type is +// totally unknown, e.g. 'T::foo'. It is permitted for this to +// appear in situations where the structure of the type is +// theoretically deducible. +BUILTIN_TYPE(Dependent, DependentTy) + +// The type of an unresolved overload set. A placeholder type. +// Expressions with this type have one of the following basic +// forms, with parentheses generally permitted: +// foo # possibly qualified, not if an implicit access +// foo # possibly qualified, not if an implicit access +// &foo # possibly qualified, not if an implicit access +// x->foo # only if might be a static member function +// &x->foo # only if might be a static member function +// &Class::foo # when a pointer-to-member; sub-expr also has this type +// OverloadExpr::find can be used to analyze the expression. +// +// Overload should be the first placeholder type, or else change +// BuiltinType::isNonOverloadPlaceholderType() +PLACEHOLDER_TYPE(Overload, OverloadTy) + +// The type of a bound C++ non-static member function. +// A placeholder type. Expressions with this type have one of the +// following basic forms: +// foo # if an implicit access +// x->foo # if only contains non-static members +PLACEHOLDER_TYPE(BoundMember, BoundMemberTy) + +// The type of an expression which refers to a pseudo-object, +// such as those introduced by Objective C's @property or +// VS.NET's __property declarations. A placeholder type. The +// pseudo-object is actually accessed by emitting a call to +// some sort of function or method; typically there is a pair +// of a setter and a getter, with the setter used if the +// pseudo-object reference is used syntactically as the +// left-hand-side of an assignment operator. +// +// A pseudo-object reference naming an Objective-C @property is +// always a dot access with a base of object-pointer type, +// e.g. 'x.foo'. +// +// In VS.NET, a __property declaration creates an implicit +// member with an associated name, which can then be named +// in any of the normal ways an ordinary member could be. +PLACEHOLDER_TYPE(PseudoObject, PseudoObjectTy) + +// __builtin_any_type. A placeholder type. Useful for clients +// like debuggers that don't know what type to give something. +// Only a small number of operations are valid on expressions of +// unknown type, most notably explicit casts. +PLACEHOLDER_TYPE(UnknownAny, UnknownAnyTy) + +// The type of a cast which, in ARC, would normally require a +// __bridge, but which might be okay depending on the immediate +// context. +PLACEHOLDER_TYPE(ARCUnbridgedCast, ARCUnbridgedCastTy) + +#ifdef LAST_BUILTIN_TYPE +LAST_BUILTIN_TYPE(ARCUnbridgedCast) +#undef LAST_BUILTIN_TYPE +#endif + +#undef SHARED_SINGLETON_TYPE +#undef PLACEHOLDER_TYPE +#undef FLOATING_TYPE +#undef SIGNED_TYPE +#undef UNSIGNED_TYPE +#undef BUILTIN_TYPE diff --git a/clang/include/clang/AST/CMakeLists.txt b/clang/include/clang/AST/CMakeLists.txt new file mode 100644 index 0000000..c10cda8 --- /dev/null +++ b/clang/include/clang/AST/CMakeLists.txt @@ -0,0 +1,17 @@ +clang_tablegen(Attrs.inc -gen-clang-attr-classes + -I ${CMAKE_CURRENT_SOURCE_DIR}/../../ + SOURCE ../Basic/Attr.td + TARGET ClangAttrClasses) + +clang_tablegen(AttrImpl.inc -gen-clang-attr-impl + -I ${CMAKE_CURRENT_SOURCE_DIR}/../../ + SOURCE ../Basic/Attr.td + TARGET ClangAttrImpl) + +clang_tablegen(StmtNodes.inc -gen-clang-stmt-nodes + SOURCE ../Basic/StmtNodes.td + TARGET ClangStmtNodes) + +clang_tablegen(DeclNodes.inc -gen-clang-decl-nodes + SOURCE ../Basic/DeclNodes.td + TARGET ClangDeclNodes) diff --git a/clang/include/clang/AST/CXXInheritance.h b/clang/include/clang/AST/CXXInheritance.h new file mode 100644 index 0000000..44c554b --- /dev/null +++ b/clang/include/clang/AST/CXXInheritance.h @@ -0,0 +1,370 @@ +//===------ CXXInheritance.h - C++ Inheritance ------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides routines that help analyzing C++ inheritance hierarchies. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_CXXINHERITANCE_H +#define LLVM_CLANG_AST_CXXINHERITANCE_H + +#include "clang/AST/DeclarationName.h" +#include "clang/AST/DeclBase.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/Type.h" +#include "clang/AST/TypeOrdering.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/SmallVector.h" +#include <list> +#include <map> +#include <cassert> + +namespace clang { + +class CXXBaseSpecifier; +class CXXMethodDecl; +class CXXRecordDecl; +class NamedDecl; + +/// \brief Represents an element in a path from a derived class to a +/// base class. +/// +/// Each step in the path references the link from a +/// derived class to one of its direct base classes, along with a +/// base "number" that identifies which base subobject of the +/// original derived class we are referencing. +struct CXXBasePathElement { + /// \brief The base specifier that states the link from a derived + /// class to a base class, which will be followed by this base + /// path element. + const CXXBaseSpecifier *Base; + + /// \brief The record decl of the class that the base is a base of. + const CXXRecordDecl *Class; + + /// \brief Identifies which base class subobject (of type + /// \c Base->getType()) this base path element refers to. + /// + /// This value is only valid if \c !Base->isVirtual(), because there + /// is no base numbering for the zero or one virtual bases of a + /// given type. + int SubobjectNumber; +}; + +/// \brief Represents a path from a specific derived class +/// (which is not represented as part of the path) to a particular +/// (direct or indirect) base class subobject. +/// +/// Individual elements in the path are described by the \c CXXBasePathElement +/// structure, which captures both the link from a derived class to one of its +/// direct bases and identification describing which base class +/// subobject is being used. +class CXXBasePath : public SmallVector<CXXBasePathElement, 4> { +public: + CXXBasePath() : Access(AS_public) {} + + /// \brief The access along this inheritance path. This is only + /// calculated when recording paths. AS_none is a special value + /// used to indicate a path which permits no legal access. + AccessSpecifier Access; + + /// \brief The set of declarations found inside this base class + /// subobject. + DeclContext::lookup_result Decls; + + void clear() { + SmallVectorImpl<CXXBasePathElement>::clear(); + Access = AS_public; + } +}; + +/// BasePaths - Represents the set of paths from a derived class to +/// one of its (direct or indirect) bases. For example, given the +/// following class hierarchy: +/// +/// @code +/// class A { }; +/// class B : public A { }; +/// class C : public A { }; +/// class D : public B, public C{ }; +/// @endcode +/// +/// There are two potential BasePaths to represent paths from D to a +/// base subobject of type A. One path is (D,0) -> (B,0) -> (A,0) +/// and another is (D,0)->(C,0)->(A,1). These two paths actually +/// refer to two different base class subobjects of the same type, +/// so the BasePaths object refers to an ambiguous path. On the +/// other hand, consider the following class hierarchy: +/// +/// @code +/// class A { }; +/// class B : public virtual A { }; +/// class C : public virtual A { }; +/// class D : public B, public C{ }; +/// @endcode +/// +/// Here, there are two potential BasePaths again, (D, 0) -> (B, 0) +/// -> (A,v) and (D, 0) -> (C, 0) -> (A, v), but since both of them +/// refer to the same base class subobject of type A (the virtual +/// one), there is no ambiguity. +class CXXBasePaths { + /// \brief The type from which this search originated. + CXXRecordDecl *Origin; + + /// Paths - The actual set of paths that can be taken from the + /// derived class to the same base class. + std::list<CXXBasePath> Paths; + + /// ClassSubobjects - Records the class subobjects for each class + /// type that we've seen. The first element in the pair says + /// whether we found a path to a virtual base for that class type, + /// while the element contains the number of non-virtual base + /// class subobjects for that class type. The key of the map is + /// the cv-unqualified canonical type of the base class subobject. + std::map<QualType, std::pair<bool, unsigned>, QualTypeOrdering> + ClassSubobjects; + + /// FindAmbiguities - Whether Sema::IsDerivedFrom should try find + /// ambiguous paths while it is looking for a path from a derived + /// type to a base type. + bool FindAmbiguities; + + /// RecordPaths - Whether Sema::IsDerivedFrom should record paths + /// while it is determining whether there are paths from a derived + /// type to a base type. + bool RecordPaths; + + /// DetectVirtual - Whether Sema::IsDerivedFrom should abort the search + /// if it finds a path that goes across a virtual base. The virtual class + /// is also recorded. + bool DetectVirtual; + + /// ScratchPath - A BasePath that is used by Sema::lookupInBases + /// to help build the set of paths. + CXXBasePath ScratchPath; + + /// DetectedVirtual - The base class that is virtual. + const RecordType *DetectedVirtual; + + /// \brief Array of the declarations that have been found. This + /// array is constructed only if needed, e.g., to iterate over the + /// results within LookupResult. + NamedDecl **DeclsFound; + unsigned NumDeclsFound; + + friend class CXXRecordDecl; + + void ComputeDeclsFound(); + + bool lookupInBases(ASTContext &Context, + const CXXRecordDecl *Record, + CXXRecordDecl::BaseMatchesCallback *BaseMatches, + void *UserData); +public: + typedef std::list<CXXBasePath>::iterator paths_iterator; + typedef std::list<CXXBasePath>::const_iterator const_paths_iterator; + typedef NamedDecl **decl_iterator; + + /// BasePaths - Construct a new BasePaths structure to record the + /// paths for a derived-to-base search. + explicit CXXBasePaths(bool FindAmbiguities = true, + bool RecordPaths = true, + bool DetectVirtual = true) + : FindAmbiguities(FindAmbiguities), RecordPaths(RecordPaths), + DetectVirtual(DetectVirtual), DetectedVirtual(0), DeclsFound(0), + NumDeclsFound(0) { } + + ~CXXBasePaths() { delete [] DeclsFound; } + + paths_iterator begin() { return Paths.begin(); } + paths_iterator end() { return Paths.end(); } + const_paths_iterator begin() const { return Paths.begin(); } + const_paths_iterator end() const { return Paths.end(); } + + CXXBasePath& front() { return Paths.front(); } + const CXXBasePath& front() const { return Paths.front(); } + + decl_iterator found_decls_begin(); + decl_iterator found_decls_end(); + + /// \brief Determine whether the path from the most-derived type to the + /// given base type is ambiguous (i.e., it refers to multiple subobjects of + /// the same base type). + bool isAmbiguous(CanQualType BaseType); + + /// \brief Whether we are finding multiple paths to detect ambiguities. + bool isFindingAmbiguities() const { return FindAmbiguities; } + + /// \brief Whether we are recording paths. + bool isRecordingPaths() const { return RecordPaths; } + + /// \brief Specify whether we should be recording paths or not. + void setRecordingPaths(bool RP) { RecordPaths = RP; } + + /// \brief Whether we are detecting virtual bases. + bool isDetectingVirtual() const { return DetectVirtual; } + + /// \brief The virtual base discovered on the path (if we are merely + /// detecting virtuals). + const RecordType* getDetectedVirtual() const { + return DetectedVirtual; + } + + /// \brief Retrieve the type from which this base-paths search + /// began + CXXRecordDecl *getOrigin() const { return Origin; } + void setOrigin(CXXRecordDecl *Rec) { Origin = Rec; } + + /// \brief Clear the base-paths results. + void clear(); + + /// \brief Swap this data structure's contents with another CXXBasePaths + /// object. + void swap(CXXBasePaths &Other); +}; + +/// \brief Uniquely identifies a virtual method within a class +/// hierarchy by the method itself and a class subobject number. +struct UniqueVirtualMethod { + UniqueVirtualMethod() : Method(0), Subobject(0), InVirtualSubobject(0) { } + + UniqueVirtualMethod(CXXMethodDecl *Method, unsigned Subobject, + const CXXRecordDecl *InVirtualSubobject) + : Method(Method), Subobject(Subobject), + InVirtualSubobject(InVirtualSubobject) { } + + /// \brief The overriding virtual method. + CXXMethodDecl *Method; + + /// \brief The subobject in which the overriding virtual method + /// resides. + unsigned Subobject; + + /// \brief The virtual base class subobject of which this overridden + /// virtual method is a part. Note that this records the closest + /// derived virtual base class subobject. + const CXXRecordDecl *InVirtualSubobject; + + friend bool operator==(const UniqueVirtualMethod &X, + const UniqueVirtualMethod &Y) { + return X.Method == Y.Method && X.Subobject == Y.Subobject && + X.InVirtualSubobject == Y.InVirtualSubobject; + } + + friend bool operator!=(const UniqueVirtualMethod &X, + const UniqueVirtualMethod &Y) { + return !(X == Y); + } +}; + +/// \brief The set of methods that override a given virtual method in +/// each subobject where it occurs. +/// +/// The first part of the pair is the subobject in which the +/// overridden virtual function occurs, while the second part of the +/// pair is the virtual method that overrides it (including the +/// subobject in which that virtual function occurs). +class OverridingMethods { + llvm::DenseMap<unsigned, SmallVector<UniqueVirtualMethod, 4> > + Overrides; + +public: + // Iterate over the set of subobjects that have overriding methods. + typedef llvm::DenseMap<unsigned, SmallVector<UniqueVirtualMethod, 4> > + ::iterator iterator; + typedef llvm::DenseMap<unsigned, SmallVector<UniqueVirtualMethod, 4> > + ::const_iterator const_iterator; + iterator begin() { return Overrides.begin(); } + const_iterator begin() const { return Overrides.begin(); } + iterator end() { return Overrides.end(); } + const_iterator end() const { return Overrides.end(); } + unsigned size() const { return Overrides.size(); } + + // Iterate over the set of overriding virtual methods in a given + // subobject. + typedef SmallVector<UniqueVirtualMethod, 4>::iterator + overriding_iterator; + typedef SmallVector<UniqueVirtualMethod, 4>::const_iterator + overriding_const_iterator; + + // Add a new overriding method for a particular subobject. + void add(unsigned OverriddenSubobject, UniqueVirtualMethod Overriding); + + // Add all of the overriding methods from "other" into overrides for + // this method. Used when merging the overrides from multiple base + // class subobjects. + void add(const OverridingMethods &Other); + + // Replace all overriding virtual methods in all subobjects with the + // given virtual method. + void replaceAll(UniqueVirtualMethod Overriding); +}; + +/// \brief A mapping from each virtual member function to its set of +/// final overriders. +/// +/// Within a class hierarchy for a given derived class, each virtual +/// member function in that hierarchy has one or more "final +/// overriders" (C++ [class.virtual]p2). A final overrider for a +/// virtual function "f" is the virtual function that will actually be +/// invoked when dispatching a call to "f" through the +/// vtable. Well-formed classes have a single final overrider for each +/// virtual function; in abstract classes, the final overrider for at +/// least one virtual function is a pure virtual function. Due to +/// multiple, virtual inheritance, it is possible for a class to have +/// more than one final overrider. Athough this is an error (per C++ +/// [class.virtual]p2), it is not considered an error here: the final +/// overrider map can represent multiple final overriders for a +/// method, and it is up to the client to determine whether they are +/// problem. For example, the following class \c D has two final +/// overriders for the virtual function \c A::f(), one in \c C and one +/// in \c D: +/// +/// \code +/// struct A { virtual void f(); }; +/// struct B : virtual A { virtual void f(); }; +/// struct C : virtual A { virtual void f(); }; +/// struct D : B, C { }; +/// \endcode +/// +/// This data structure contaings a mapping from every virtual +/// function *that does not override an existing virtual function* and +/// in every subobject where that virtual function occurs to the set +/// of virtual functions that override it. Thus, the same virtual +/// function \c A::f can actually occur in multiple subobjects of type +/// \c A due to multiple inheritance, and may be overriden by +/// different virtual functions in each, as in the following example: +/// +/// \code +/// struct A { virtual void f(); }; +/// struct B : A { virtual void f(); }; +/// struct C : A { virtual void f(); }; +/// struct D : B, C { }; +/// \endcode +/// +/// Unlike in the previous example, where the virtual functions \c +/// B::f and \c C::f both overrode \c A::f in the same subobject of +/// type \c A, in this example the two virtual functions both override +/// \c A::f but in *different* subobjects of type A. This is +/// represented by numbering the subobjects in which the overridden +/// and the overriding virtual member functions are located. Subobject +/// 0 represents the virtua base class subobject of that type, while +/// subobject numbers greater than 0 refer to non-virtual base class +/// subobjects of that type. +class CXXFinalOverriderMap + : public llvm::DenseMap<const CXXMethodDecl *, OverridingMethods> { }; + +/// \brief A set of all the primary bases for a class. +class CXXIndirectPrimaryBaseSet + : public llvm::SmallSet<const CXXRecordDecl*, 32> { }; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/AST/CanonicalType.h b/clang/include/clang/AST/CanonicalType.h new file mode 100644 index 0000000..6cce888 --- /dev/null +++ b/clang/include/clang/AST/CanonicalType.h @@ -0,0 +1,778 @@ +//===-- CanonicalType.h - C Language Family Type Representation -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the CanQual class template, which provides access to +// canonical types. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_CANONICAL_TYPE_H +#define LLVM_CLANG_AST_CANONICAL_TYPE_H + +#include "clang/AST/Type.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/type_traits.h" +#include <iterator> + +namespace clang { + +template<typename T> class CanProxy; +template<typename T> struct CanProxyAdaptor; + +//----------------------------------------------------------------------------// +// Canonical, qualified type template +//----------------------------------------------------------------------------// + +/// \brief Represents a canonical, potentially-qualified type. +/// +/// The CanQual template is a lightweight smart pointer that provides access +/// to the canonical representation of a type, where all typedefs and other +/// syntactic sugar has been eliminated. A CanQualType may also have various +/// qualifiers (const, volatile, restrict) attached to it. +/// +/// The template type parameter @p T is one of the Type classes (PointerType, +/// BuiltinType, etc.). The type stored within @c CanQual<T> will be of that +/// type (or some subclass of that type). The typedef @c CanQualType is just +/// a shorthand for @c CanQual<Type>. +/// +/// An instance of @c CanQual<T> can be implicitly converted to a +/// @c CanQual<U> when T is derived from U, which essentially provides an +/// implicit upcast. For example, @c CanQual<LValueReferenceType> can be +/// converted to @c CanQual<ReferenceType>. Note that any @c CanQual type can +/// be implicitly converted to a QualType, but the reverse operation requires +/// a call to ASTContext::getCanonicalType(). +/// +/// +template<typename T = Type> +class CanQual { + /// \brief The actual, canonical type. + QualType Stored; + +public: + /// \brief Constructs a NULL canonical type. + CanQual() : Stored() { } + + /// \brief Converting constructor that permits implicit upcasting of + /// canonical type pointers. + template<typename U> + CanQual(const CanQual<U>& Other, + typename llvm::enable_if<llvm::is_base_of<T, U>, int>::type = 0); + + /// \brief Retrieve the underlying type pointer, which refers to a + /// canonical type. + /// + /// The underlying pointer must not be NULL. + const T *getTypePtr() const { return cast<T>(Stored.getTypePtr()); } + + /// \brief Retrieve the underlying type pointer, which refers to a + /// canonical type, or NULL. + /// + const T *getTypePtrOrNull() const { + return cast_or_null<T>(Stored.getTypePtrOrNull()); + } + + /// \brief Implicit conversion to a qualified type. + operator QualType() const { return Stored; } + + /// \brief Implicit conversion to bool. + operator bool() const { return !isNull(); } + + bool isNull() const { + return Stored.isNull(); + } + + SplitQualType split() const { return Stored.split(); } + + /// \brief Retrieve a canonical type pointer with a different static type, + /// upcasting or downcasting as needed. + /// + /// The getAs() function is typically used to try to downcast to a + /// more specific (canonical) type in the type system. For example: + /// + /// @code + /// void f(CanQual<Type> T) { + /// if (CanQual<PointerType> Ptr = T->getAs<PointerType>()) { + /// // look at Ptr's pointee type + /// } + /// } + /// @endcode + /// + /// \returns A proxy pointer to the same type, but with the specified + /// static type (@p U). If the dynamic type is not the specified static type + /// or a derived class thereof, a NULL canonical type. + template<typename U> CanProxy<U> getAs() const; + + template<typename U> CanProxy<U> castAs() const; + + /// \brief Overloaded arrow operator that produces a canonical type + /// proxy. + CanProxy<T> operator->() const; + + /// \brief Retrieve all qualifiers. + Qualifiers getQualifiers() const { return Stored.getLocalQualifiers(); } + + /// \brief Retrieve the const/volatile/restrict qualifiers. + unsigned getCVRQualifiers() const { return Stored.getLocalCVRQualifiers(); } + + /// \brief Determines whether this type has any qualifiers + bool hasQualifiers() const { return Stored.hasLocalQualifiers(); } + + bool isConstQualified() const { + return Stored.isLocalConstQualified(); + } + bool isVolatileQualified() const { + return Stored.isLocalVolatileQualified(); + } + bool isRestrictQualified() const { + return Stored.isLocalRestrictQualified(); + } + + /// \brief Determines if this canonical type is furthermore + /// canonical as a parameter. The parameter-canonicalization + /// process decays arrays to pointers and drops top-level qualifiers. + bool isCanonicalAsParam() const { + return Stored.isCanonicalAsParam(); + } + + /// \brief Retrieve the unqualified form of this type. + CanQual<T> getUnqualifiedType() const; + + /// \brief Retrieves a version of this type with const applied. + /// Note that this does not always yield a canonical type. + QualType withConst() const { + return Stored.withConst(); + } + + /// \brief Determines whether this canonical type is more qualified than + /// the @p Other canonical type. + bool isMoreQualifiedThan(CanQual<T> Other) const { + return Stored.isMoreQualifiedThan(Other.Stored); + } + + /// \brief Determines whether this canonical type is at least as qualified as + /// the @p Other canonical type. + bool isAtLeastAsQualifiedAs(CanQual<T> Other) const { + return Stored.isAtLeastAsQualifiedAs(Other.Stored); + } + + /// \brief If the canonical type is a reference type, returns the type that + /// it refers to; otherwise, returns the type itself. + CanQual<Type> getNonReferenceType() const; + + /// \brief Retrieve the internal representation of this canonical type. + void *getAsOpaquePtr() const { return Stored.getAsOpaquePtr(); } + + /// \brief Construct a canonical type from its internal representation. + static CanQual<T> getFromOpaquePtr(void *Ptr); + + /// \brief Builds a canonical type from a QualType. + /// + /// This routine is inherently unsafe, because it requires the user to + /// ensure that the given type is a canonical type with the correct + // (dynamic) type. + static CanQual<T> CreateUnsafe(QualType Other); + + void dump() const { Stored.dump(); } + + void Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddPointer(getAsOpaquePtr()); + } +}; + +template<typename T, typename U> +inline bool operator==(CanQual<T> x, CanQual<U> y) { + return x.getAsOpaquePtr() == y.getAsOpaquePtr(); +} + +template<typename T, typename U> +inline bool operator!=(CanQual<T> x, CanQual<U> y) { + return x.getAsOpaquePtr() != y.getAsOpaquePtr(); +} + +/// \brief Represents a canonical, potentially-qualified type. +typedef CanQual<Type> CanQualType; + +inline CanQualType Type::getCanonicalTypeUnqualified() const { + return CanQualType::CreateUnsafe(getCanonicalTypeInternal()); +} + +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + CanQualType T) { + DB << static_cast<QualType>(T); + return DB; +} + +//----------------------------------------------------------------------------// +// Internal proxy classes used by canonical types +//----------------------------------------------------------------------------// + +#define LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(Accessor) \ +CanQualType Accessor() const { \ +return CanQualType::CreateUnsafe(this->getTypePtr()->Accessor()); \ +} + +#define LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Type, Accessor) \ +Type Accessor() const { return this->getTypePtr()->Accessor(); } + +/// \brief Base class of all canonical proxy types, which is responsible for +/// storing the underlying canonical type and providing basic conversions. +template<typename T> +class CanProxyBase { +protected: + CanQual<T> Stored; + +public: + /// \brief Retrieve the pointer to the underlying Type + const T *getTypePtr() const { return Stored.getTypePtr(); } + + /// \brief Implicit conversion to the underlying pointer. + /// + /// Also provides the ability to use canonical type proxies in a Boolean + // context,e.g., + /// @code + /// if (CanQual<PointerType> Ptr = T->getAs<PointerType>()) { ... } + /// @endcode + operator const T*() const { return this->Stored.getTypePtrOrNull(); } + + /// \brief Try to convert the given canonical type to a specific structural + /// type. + template<typename U> CanProxy<U> getAs() const { + return this->Stored.template getAs<U>(); + } + + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Type::TypeClass, getTypeClass) + + // Type predicates + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjectType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isIncompleteType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isIncompleteOrObjectType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isVariablyModifiedType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isIntegerType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isEnumeralType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isBooleanType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isCharType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isWideCharType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isIntegralType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isIntegralOrEnumerationType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isRealFloatingType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isComplexType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isAnyComplexType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isFloatingType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isRealType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isArithmeticType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isVoidType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isDerivedType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isScalarType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isAggregateType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isAnyPointerType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isVoidPointerType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isFunctionPointerType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isMemberFunctionPointerType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isClassType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isStructureType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isStructureOrClassType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isUnionType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isComplexIntegerType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isNullPtrType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isDependentType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isOverloadableType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isArrayType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasPointerRepresentation) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasObjCPointerRepresentation) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasIntegerRepresentation) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasSignedIntegerRepresentation) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasUnsignedIntegerRepresentation) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasFloatingRepresentation) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isPromotableIntegerType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isSignedIntegerType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isUnsignedIntegerType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isSignedIntegerOrEnumerationType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isUnsignedIntegerOrEnumerationType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isConstantSizeType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isSpecifierType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(CXXRecordDecl*, getAsCXXRecordDecl) + + /// \brief Retrieve the proxy-adaptor type. + /// + /// This arrow operator is used when CanProxyAdaptor has been specialized + /// for the given type T. In that case, we reference members of the + /// CanProxyAdaptor specialization. Otherwise, this operator will be hidden + /// by the arrow operator in the primary CanProxyAdaptor template. + const CanProxyAdaptor<T> *operator->() const { + return static_cast<const CanProxyAdaptor<T> *>(this); + } +}; + +/// \brief Replacable canonical proxy adaptor class that provides the link +/// between a canonical type and the accessors of the type. +/// +/// The CanProxyAdaptor is a replaceable class template that is instantiated +/// as part of each canonical proxy type. The primary template merely provides +/// redirection to the underlying type (T), e.g., @c PointerType. One can +/// provide specializations of this class template for each underlying type +/// that provide accessors returning canonical types (@c CanQualType) rather +/// than the more typical @c QualType, to propagate the notion of "canonical" +/// through the system. +template<typename T> +struct CanProxyAdaptor : CanProxyBase<T> { }; + +/// \brief Canonical proxy type returned when retrieving the members of a +/// canonical type or as the result of the @c CanQual<T>::getAs member +/// function. +/// +/// The CanProxy type mainly exists as a proxy through which operator-> will +/// look to either map down to a raw T* (e.g., PointerType*) or to a proxy +/// type that provides canonical-type access to the fields of the type. +template<typename T> +class CanProxy : public CanProxyAdaptor<T> { +public: + /// \brief Build a NULL proxy. + CanProxy() { } + + /// \brief Build a proxy to the given canonical type. + CanProxy(CanQual<T> Stored) { this->Stored = Stored; } + + /// \brief Implicit conversion to the stored canonical type. + operator CanQual<T>() const { return this->Stored; } +}; + +} // end namespace clang + +namespace llvm { + +/// Implement simplify_type for CanQual<T>, so that we can dyn_cast from +/// CanQual<T> to a specific Type class. We're prefer isa/dyn_cast/cast/etc. +/// to return smart pointer (proxies?). +template<typename T> +struct simplify_type<const ::clang::CanQual<T> > { + typedef const T *SimpleType; + static SimpleType getSimplifiedValue(const ::clang::CanQual<T> &Val) { + return Val.getTypePtr(); + } +}; +template<typename T> +struct simplify_type< ::clang::CanQual<T> > +: public simplify_type<const ::clang::CanQual<T> > {}; + +// Teach SmallPtrSet that CanQual<T> is "basically a pointer". +template<typename T> +class PointerLikeTypeTraits<clang::CanQual<T> > { +public: + static inline void *getAsVoidPointer(clang::CanQual<T> P) { + return P.getAsOpaquePtr(); + } + static inline clang::CanQual<T> getFromVoidPointer(void *P) { + return clang::CanQual<T>::getFromOpaquePtr(P); + } + // qualifier information is encoded in the low bits. + enum { NumLowBitsAvailable = 0 }; +}; + +} // end namespace llvm + +namespace clang { + +//----------------------------------------------------------------------------// +// Canonical proxy adaptors for canonical type nodes. +//----------------------------------------------------------------------------// + +/// \brief Iterator adaptor that turns an iterator over canonical QualTypes +/// into an iterator over CanQualTypes. +template<typename InputIterator> +class CanTypeIterator { + InputIterator Iter; + +public: + typedef CanQualType value_type; + typedef value_type reference; + typedef CanProxy<Type> pointer; + typedef typename std::iterator_traits<InputIterator>::difference_type + difference_type; + typedef typename std::iterator_traits<InputIterator>::iterator_category + iterator_category; + + CanTypeIterator() : Iter() { } + explicit CanTypeIterator(InputIterator Iter) : Iter(Iter) { } + + // Input iterator + reference operator*() const { + return CanQualType::CreateUnsafe(*Iter); + } + + pointer operator->() const; + + CanTypeIterator &operator++() { + ++Iter; + return *this; + } + + CanTypeIterator operator++(int) { + CanTypeIterator Tmp(*this); + ++Iter; + return Tmp; + } + + friend bool operator==(const CanTypeIterator& X, const CanTypeIterator &Y) { + return X.Iter == Y.Iter; + } + friend bool operator!=(const CanTypeIterator& X, const CanTypeIterator &Y) { + return X.Iter != Y.Iter; + } + + // Bidirectional iterator + CanTypeIterator &operator--() { + --Iter; + return *this; + } + + CanTypeIterator operator--(int) { + CanTypeIterator Tmp(*this); + --Iter; + return Tmp; + } + + // Random access iterator + reference operator[](difference_type n) const { + return CanQualType::CreateUnsafe(Iter[n]); + } + + CanTypeIterator &operator+=(difference_type n) { + Iter += n; + return *this; + } + + CanTypeIterator &operator-=(difference_type n) { + Iter -= n; + return *this; + } + + friend CanTypeIterator operator+(CanTypeIterator X, difference_type n) { + X += n; + return X; + } + + friend CanTypeIterator operator+(difference_type n, CanTypeIterator X) { + X += n; + return X; + } + + friend CanTypeIterator operator-(CanTypeIterator X, difference_type n) { + X -= n; + return X; + } + + friend difference_type operator-(const CanTypeIterator &X, + const CanTypeIterator &Y) { + return X - Y; + } +}; + +template<> +struct CanProxyAdaptor<ComplexType> : public CanProxyBase<ComplexType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType) +}; + +template<> +struct CanProxyAdaptor<PointerType> : public CanProxyBase<PointerType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType) +}; + +template<> +struct CanProxyAdaptor<BlockPointerType> + : public CanProxyBase<BlockPointerType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType) +}; + +template<> +struct CanProxyAdaptor<ReferenceType> : public CanProxyBase<ReferenceType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType) +}; + +template<> +struct CanProxyAdaptor<LValueReferenceType> + : public CanProxyBase<LValueReferenceType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType) +}; + +template<> +struct CanProxyAdaptor<RValueReferenceType> + : public CanProxyBase<RValueReferenceType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType) +}; + +template<> +struct CanProxyAdaptor<MemberPointerType> + : public CanProxyBase<MemberPointerType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(const Type *, getClass) +}; + +template<> +struct CanProxyAdaptor<ArrayType> : public CanProxyBase<ArrayType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(ArrayType::ArraySizeModifier, + getSizeModifier) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Qualifiers, getIndexTypeQualifiers) +}; + +template<> +struct CanProxyAdaptor<ConstantArrayType> + : public CanProxyBase<ConstantArrayType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(ArrayType::ArraySizeModifier, + getSizeModifier) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Qualifiers, getIndexTypeQualifiers) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(const llvm::APInt &, getSize) +}; + +template<> +struct CanProxyAdaptor<IncompleteArrayType> + : public CanProxyBase<IncompleteArrayType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(ArrayType::ArraySizeModifier, + getSizeModifier) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Qualifiers, getIndexTypeQualifiers) +}; + +template<> +struct CanProxyAdaptor<VariableArrayType> + : public CanProxyBase<VariableArrayType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(ArrayType::ArraySizeModifier, + getSizeModifier) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Qualifiers, getIndexTypeQualifiers) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Expr *, getSizeExpr) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceRange, getBracketsRange) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceLocation, getLBracketLoc) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceLocation, getRBracketLoc) +}; + +template<> +struct CanProxyAdaptor<DependentSizedArrayType> + : public CanProxyBase<DependentSizedArrayType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Expr *, getSizeExpr) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceRange, getBracketsRange) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceLocation, getLBracketLoc) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceLocation, getRBracketLoc) +}; + +template<> +struct CanProxyAdaptor<DependentSizedExtVectorType> + : public CanProxyBase<DependentSizedExtVectorType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(const Expr *, getSizeExpr) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(SourceLocation, getAttributeLoc) +}; + +template<> +struct CanProxyAdaptor<VectorType> : public CanProxyBase<VectorType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getNumElements) +}; + +template<> +struct CanProxyAdaptor<ExtVectorType> : public CanProxyBase<ExtVectorType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getElementType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getNumElements) +}; + +template<> +struct CanProxyAdaptor<FunctionType> : public CanProxyBase<FunctionType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getResultType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(FunctionType::ExtInfo, getExtInfo) +}; + +template<> +struct CanProxyAdaptor<FunctionNoProtoType> + : public CanProxyBase<FunctionNoProtoType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getResultType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(FunctionType::ExtInfo, getExtInfo) +}; + +template<> +struct CanProxyAdaptor<FunctionProtoType> + : public CanProxyBase<FunctionProtoType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getResultType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(FunctionType::ExtInfo, getExtInfo) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getNumArgs) + CanQualType getArgType(unsigned i) const { + return CanQualType::CreateUnsafe(this->getTypePtr()->getArgType(i)); + } + + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isVariadic) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getTypeQuals) + + typedef CanTypeIterator<FunctionProtoType::arg_type_iterator> + arg_type_iterator; + + arg_type_iterator arg_type_begin() const { + return arg_type_iterator(this->getTypePtr()->arg_type_begin()); + } + + arg_type_iterator arg_type_end() const { + return arg_type_iterator(this->getTypePtr()->arg_type_end()); + } + + // Note: canonical function types never have exception specifications +}; + +template<> +struct CanProxyAdaptor<TypeOfType> : public CanProxyBase<TypeOfType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getUnderlyingType) +}; + +template<> +struct CanProxyAdaptor<DecltypeType> : public CanProxyBase<DecltypeType> { + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(Expr *, getUnderlyingExpr) + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getUnderlyingType) +}; + +template <> +struct CanProxyAdaptor<UnaryTransformType> + : public CanProxyBase<UnaryTransformType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getBaseType) + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getUnderlyingType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(UnaryTransformType::UTTKind, getUTTKind) +}; + +template<> +struct CanProxyAdaptor<TagType> : public CanProxyBase<TagType> { + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(TagDecl *, getDecl) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isBeingDefined) +}; + +template<> +struct CanProxyAdaptor<RecordType> : public CanProxyBase<RecordType> { + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(RecordDecl *, getDecl) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isBeingDefined) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, hasConstFields) +}; + +template<> +struct CanProxyAdaptor<EnumType> : public CanProxyBase<EnumType> { + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(EnumDecl *, getDecl) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isBeingDefined) +}; + +template<> +struct CanProxyAdaptor<TemplateTypeParmType> + : public CanProxyBase<TemplateTypeParmType> { + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getDepth) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getIndex) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isParameterPack) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(TemplateTypeParmDecl *, getDecl) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(IdentifierInfo *, getIdentifier) +}; + +template<> +struct CanProxyAdaptor<ObjCObjectType> + : public CanProxyBase<ObjCObjectType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getBaseType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(const ObjCInterfaceDecl *, + getInterface) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCUnqualifiedId) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCUnqualifiedClass) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCQualifiedId) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCQualifiedClass) + + typedef ObjCObjectPointerType::qual_iterator qual_iterator; + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(qual_iterator, qual_begin) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(qual_iterator, qual_end) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, qual_empty) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getNumProtocols) +}; + +template<> +struct CanProxyAdaptor<ObjCObjectPointerType> + : public CanProxyBase<ObjCObjectPointerType> { + LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(const ObjCInterfaceType *, + getInterfaceType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCIdType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCClassType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCQualifiedIdType) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isObjCQualifiedClassType) + + typedef ObjCObjectPointerType::qual_iterator qual_iterator; + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(qual_iterator, qual_begin) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(qual_iterator, qual_end) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, qual_empty) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(unsigned, getNumProtocols) +}; + +//----------------------------------------------------------------------------// +// Method and function definitions +//----------------------------------------------------------------------------// +template<typename T> +inline CanQual<T> CanQual<T>::getUnqualifiedType() const { + return CanQual<T>::CreateUnsafe(Stored.getLocalUnqualifiedType()); +} + +template<typename T> +inline CanQual<Type> CanQual<T>::getNonReferenceType() const { + if (CanQual<ReferenceType> RefType = getAs<ReferenceType>()) + return RefType->getPointeeType(); + else + return *this; +} + +template<typename T> +CanQual<T> CanQual<T>::getFromOpaquePtr(void *Ptr) { + CanQual<T> Result; + Result.Stored = QualType::getFromOpaquePtr(Ptr); + assert((!Result || Result.Stored.getAsOpaquePtr() == (void*)-1 || + Result.Stored.isCanonical()) && "Type is not canonical!"); + return Result; +} + +template<typename T> +CanQual<T> CanQual<T>::CreateUnsafe(QualType Other) { + assert((Other.isNull() || Other.isCanonical()) && "Type is not canonical!"); + assert((Other.isNull() || isa<T>(Other.getTypePtr())) && + "Dynamic type does not meet the static type's requires"); + CanQual<T> Result; + Result.Stored = Other; + return Result; +} + +template<typename T> +template<typename U> +CanProxy<U> CanQual<T>::getAs() const { + if (Stored.isNull()) + return CanProxy<U>(); + + if (isa<U>(Stored.getTypePtr())) + return CanQual<U>::CreateUnsafe(Stored); + + return CanProxy<U>(); +} + +template<typename T> +template<typename U> +CanProxy<U> CanQual<T>::castAs() const { + assert(!Stored.isNull() && isa<U>(Stored.getTypePtr())); + return CanQual<U>::CreateUnsafe(Stored); +} + +template<typename T> +CanProxy<T> CanQual<T>::operator->() const { + return CanProxy<T>(*this); +} + +template<typename InputIterator> +typename CanTypeIterator<InputIterator>::pointer +CanTypeIterator<InputIterator>::operator->() const { + return CanProxy<Type>(*this); +} + +} + + +#endif // LLVM_CLANG_AST_CANONICAL_TYPE_H diff --git a/clang/include/clang/AST/CharUnits.h b/clang/include/clang/AST/CharUnits.h new file mode 100644 index 0000000..5be3582 --- /dev/null +++ b/clang/include/clang/AST/CharUnits.h @@ -0,0 +1,217 @@ +//===--- CharUnits.h - Character units for sizes and offsets ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the CharUnits class +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_CHARUNITS_H +#define LLVM_CLANG_AST_CHARUNITS_H + +#include "llvm/ADT/DenseMapInfo.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/MathExtras.h" + +namespace clang { + + /// CharUnits - This is an opaque type for sizes expressed in character units. + /// Instances of this type represent a quantity as a multiple of the size + /// of the standard C type, char, on the target architecture. As an opaque + /// type, CharUnits protects you from accidentally combining operations on + /// quantities in bit units and character units. + /// + /// It should be noted that characters and bytes are distinct concepts. Bytes + /// refer to addressable units of data storage on the target machine, and + /// characters are members of a set of elements used for the organization, + /// control, or representation of data. According to C99, bytes are allowed + /// to exceed characters in size, although currently, clang only supports + /// architectures where the two are the same size. + /// + /// For portability, never assume that a target character is 8 bits wide. Use + /// CharUnit values wherever you calculate sizes, offsets, or alignments + /// in character units. + class CharUnits { + public: + typedef int64_t QuantityType; + + private: + QuantityType Quantity; + + explicit CharUnits(QuantityType C) : Quantity(C) {} + + public: + + /// CharUnits - A default constructor. + CharUnits() : Quantity(0) {} + + /// Zero - Construct a CharUnits quantity of zero. + static CharUnits Zero() { + return CharUnits(0); + } + + /// One - Construct a CharUnits quantity of one. + static CharUnits One() { + return CharUnits(1); + } + + /// fromQuantity - Construct a CharUnits quantity from a raw integer type. + static CharUnits fromQuantity(QuantityType Quantity) { + return CharUnits(Quantity); + } + + // Compound assignment. + CharUnits& operator+= (const CharUnits &Other) { + Quantity += Other.Quantity; + return *this; + } + CharUnits& operator++ () { + ++Quantity; + return *this; + } + CharUnits operator++ (int) { + return CharUnits(Quantity++); + } + CharUnits& operator-= (const CharUnits &Other) { + Quantity -= Other.Quantity; + return *this; + } + CharUnits& operator-- () { + --Quantity; + return *this; + } + CharUnits operator-- (int) { + return CharUnits(Quantity--); + } + + // Comparison operators. + bool operator== (const CharUnits &Other) const { + return Quantity == Other.Quantity; + } + bool operator!= (const CharUnits &Other) const { + return Quantity != Other.Quantity; + } + + // Relational operators. + bool operator< (const CharUnits &Other) const { + return Quantity < Other.Quantity; + } + bool operator<= (const CharUnits &Other) const { + return Quantity <= Other.Quantity; + } + bool operator> (const CharUnits &Other) const { + return Quantity > Other.Quantity; + } + bool operator>= (const CharUnits &Other) const { + return Quantity >= Other.Quantity; + } + + // Other predicates. + + /// isZero - Test whether the quantity equals zero. + bool isZero() const { return Quantity == 0; } + + /// isOne - Test whether the quantity equals one. + bool isOne() const { return Quantity == 1; } + + /// isPositive - Test whether the quantity is greater than zero. + bool isPositive() const { return Quantity > 0; } + + /// isNegative - Test whether the quantity is less than zero. + bool isNegative() const { return Quantity < 0; } + + /// isPowerOfTwo - Test whether the quantity is a power of two. + /// Zero is not a power of two. + bool isPowerOfTwo() const { + return (Quantity & -Quantity) == Quantity; + } + + // Arithmetic operators. + CharUnits operator* (QuantityType N) const { + return CharUnits(Quantity * N); + } + CharUnits operator/ (QuantityType N) const { + return CharUnits(Quantity / N); + } + QuantityType operator/ (const CharUnits &Other) const { + return Quantity / Other.Quantity; + } + CharUnits operator% (QuantityType N) const { + return CharUnits(Quantity % N); + } + QuantityType operator% (const CharUnits &Other) const { + return Quantity % Other.Quantity; + } + CharUnits operator+ (const CharUnits &Other) const { + return CharUnits(Quantity + Other.Quantity); + } + CharUnits operator- (const CharUnits &Other) const { + return CharUnits(Quantity - Other.Quantity); + } + CharUnits operator- () const { + return CharUnits(-Quantity); + } + + + // Conversions. + + /// getQuantity - Get the raw integer representation of this quantity. + QuantityType getQuantity() const { return Quantity; } + + /// RoundUpToAlignment - Returns the next integer (mod 2**64) that is + /// greater than or equal to this quantity and is a multiple of \arg + /// Align. Align must be non-zero. + CharUnits RoundUpToAlignment(const CharUnits &Align) { + return CharUnits(llvm::RoundUpToAlignment(Quantity, + Align.Quantity)); + } + + + }; // class CharUnit +} // namespace clang + +inline clang::CharUnits operator* (clang::CharUnits::QuantityType Scale, + const clang::CharUnits &CU) { + return CU * Scale; +} + +namespace llvm { + +template<> struct DenseMapInfo<clang::CharUnits> { + static clang::CharUnits getEmptyKey() { + clang::CharUnits::QuantityType Quantity = + DenseMapInfo<clang::CharUnits::QuantityType>::getEmptyKey(); + + return clang::CharUnits::fromQuantity(Quantity); + } + + static clang::CharUnits getTombstoneKey() { + clang::CharUnits::QuantityType Quantity = + DenseMapInfo<clang::CharUnits::QuantityType>::getTombstoneKey(); + + return clang::CharUnits::fromQuantity(Quantity); + } + + static unsigned getHashValue(const clang::CharUnits &CU) { + clang::CharUnits::QuantityType Quantity = CU.getQuantity(); + return DenseMapInfo<clang::CharUnits::QuantityType>::getHashValue(Quantity); + } + + static bool isEqual(const clang::CharUnits &LHS, + const clang::CharUnits &RHS) { + return LHS == RHS; + } +}; + +template <> struct isPodLike<clang::CharUnits> { + static const bool value = true; +}; + +} // end namespace llvm + +#endif // LLVM_CLANG_AST_CHARUNITS_H diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h new file mode 100644 index 0000000..0c47f2e --- /dev/null +++ b/clang/include/clang/AST/Decl.h @@ -0,0 +1,3339 @@ +//===--- Decl.h - Classes for representing declarations ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Decl subclasses. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_DECL_H +#define LLVM_CLANG_AST_DECL_H + +#include "clang/AST/APValue.h" +#include "clang/AST/DeclBase.h" +#include "clang/AST/Redeclarable.h" +#include "clang/AST/DeclarationName.h" +#include "clang/AST/ExternalASTSource.h" +#include "clang/Basic/Linkage.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/Optional.h" +#include "llvm/Support/Compiler.h" + +namespace clang { +class CXXTemporary; +class Expr; +class FunctionTemplateDecl; +class Stmt; +class CompoundStmt; +class StringLiteral; +class NestedNameSpecifier; +class TemplateParameterList; +class TemplateArgumentList; +struct ASTTemplateArgumentListInfo; +class MemberSpecializationInfo; +class FunctionTemplateSpecializationInfo; +class DependentFunctionTemplateSpecializationInfo; +class TypeLoc; +class UnresolvedSetImpl; +class LabelStmt; +class Module; + +/// \brief A container of type source information. +/// +/// A client can read the relevant info using TypeLoc wrappers, e.g: +/// @code +/// TypeLoc TL = TypeSourceInfo->getTypeLoc(); +/// if (PointerLoc *PL = dyn_cast<PointerLoc>(&TL)) +/// PL->getStarLoc().print(OS, SrcMgr); +/// @endcode +/// +class TypeSourceInfo { + QualType Ty; + // Contains a memory block after the class, used for type source information, + // allocated by ASTContext. + friend class ASTContext; + TypeSourceInfo(QualType ty) : Ty(ty) { } +public: + /// \brief Return the type wrapped by this type source info. + QualType getType() const { return Ty; } + + /// \brief Return the TypeLoc wrapper for the type source info. + TypeLoc getTypeLoc() const; // implemented in TypeLoc.h +}; + +/// TranslationUnitDecl - The top declaration context. +class TranslationUnitDecl : public Decl, public DeclContext { + virtual void anchor(); + ASTContext &Ctx; + + /// The (most recently entered) anonymous namespace for this + /// translation unit, if one has been created. + NamespaceDecl *AnonymousNamespace; + + explicit TranslationUnitDecl(ASTContext &ctx) + : Decl(TranslationUnit, 0, SourceLocation()), + DeclContext(TranslationUnit), + Ctx(ctx), AnonymousNamespace(0) {} +public: + ASTContext &getASTContext() const { return Ctx; } + + NamespaceDecl *getAnonymousNamespace() const { return AnonymousNamespace; } + void setAnonymousNamespace(NamespaceDecl *D) { AnonymousNamespace = D; } + + static TranslationUnitDecl *Create(ASTContext &C); + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const TranslationUnitDecl *D) { return true; } + static bool classofKind(Kind K) { return K == TranslationUnit; } + static DeclContext *castToDeclContext(const TranslationUnitDecl *D) { + return static_cast<DeclContext *>(const_cast<TranslationUnitDecl*>(D)); + } + static TranslationUnitDecl *castFromDeclContext(const DeclContext *DC) { + return static_cast<TranslationUnitDecl *>(const_cast<DeclContext*>(DC)); + } +}; + +/// NamedDecl - This represents a decl with a name. Many decls have names such +/// as ObjCMethodDecl, but not @class, etc. +class NamedDecl : public Decl { + virtual void anchor(); + /// Name - The name of this declaration, which is typically a normal + /// identifier but may also be a special kind of name (C++ + /// constructor, Objective-C selector, etc.) + DeclarationName Name; + +private: + NamedDecl *getUnderlyingDeclImpl(); + +protected: + NamedDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName N) + : Decl(DK, DC, L), Name(N) { } + +public: + /// getIdentifier - Get the identifier that names this declaration, + /// if there is one. This will return NULL if this declaration has + /// no name (e.g., for an unnamed class) or if the name is a special + /// name (C++ constructor, Objective-C selector, etc.). + IdentifierInfo *getIdentifier() const { return Name.getAsIdentifierInfo(); } + + /// getName - Get the name of identifier for this declaration as a StringRef. + /// This requires that the declaration have a name and that it be a simple + /// identifier. + StringRef getName() const { + assert(Name.isIdentifier() && "Name is not a simple identifier"); + return getIdentifier() ? getIdentifier()->getName() : ""; + } + + /// getNameAsString - Get a human-readable name for the declaration, even if + /// it is one of the special kinds of names (C++ constructor, Objective-C + /// selector, etc). Creating this name requires expensive string + /// manipulation, so it should be called only when performance doesn't matter. + /// For simple declarations, getNameAsCString() should suffice. + // + // FIXME: This function should be renamed to indicate that it is not just an + // alternate form of getName(), and clients should move as appropriate. + // + // FIXME: Deprecated, move clients to getName(). + std::string getNameAsString() const { return Name.getAsString(); } + + void printName(raw_ostream &os) const { return Name.printName(os); } + + /// getDeclName - Get the actual, stored name of the declaration, + /// which may be a special name. + DeclarationName getDeclName() const { return Name; } + + /// \brief Set the name of this declaration. + void setDeclName(DeclarationName N) { Name = N; } + + /// getQualifiedNameAsString - Returns human-readable qualified name for + /// declaration, like A::B::i, for i being member of namespace A::B. + /// If declaration is not member of context which can be named (record, + /// namespace), it will return same result as getNameAsString(). + /// Creating this name is expensive, so it should be called only when + /// performance doesn't matter. + std::string getQualifiedNameAsString() const; + std::string getQualifiedNameAsString(const PrintingPolicy &Policy) const; + + /// getNameForDiagnostic - Appends a human-readable name for this + /// declaration into the given string. + /// + /// This is the method invoked by Sema when displaying a NamedDecl + /// in a diagnostic. It does not necessarily produce the same + /// result as getNameAsString(); for example, class template + /// specializations are printed with their template arguments. + /// + /// TODO: use an API that doesn't require so many temporary strings + virtual void getNameForDiagnostic(std::string &S, + const PrintingPolicy &Policy, + bool Qualified) const { + if (Qualified) + S += getQualifiedNameAsString(Policy); + else + S += getNameAsString(); + } + + /// declarationReplaces - Determine whether this declaration, if + /// known to be well-formed within its context, will replace the + /// declaration OldD if introduced into scope. A declaration will + /// replace another declaration if, for example, it is a + /// redeclaration of the same variable or function, but not if it is + /// a declaration of a different kind (function vs. class) or an + /// overloaded function. + bool declarationReplaces(NamedDecl *OldD) const; + + /// \brief Determine whether this declaration has linkage. + bool hasLinkage() const; + + using Decl::isModulePrivate; + using Decl::setModulePrivate; + + /// \brief Determine whether this declaration is hidden from name lookup. + bool isHidden() const { return Hidden; } + + /// \brief Determine whether this declaration is a C++ class member. + bool isCXXClassMember() const { + const DeclContext *DC = getDeclContext(); + + // C++0x [class.mem]p1: + // The enumerators of an unscoped enumeration defined in + // the class are members of the class. + // FIXME: support C++0x scoped enumerations. + if (isa<EnumDecl>(DC)) + DC = DC->getParent(); + + return DC->isRecord(); + } + + /// \brief Determine whether the given declaration is an instance member of + /// a C++ class. + bool isCXXInstanceMember() const; + + class LinkageInfo { + Linkage linkage_; + Visibility visibility_; + bool explicit_; + + public: + LinkageInfo() : linkage_(ExternalLinkage), visibility_(DefaultVisibility), + explicit_(false) {} + LinkageInfo(Linkage L, Visibility V, bool E) + : linkage_(L), visibility_(V), explicit_(E) {} + + static LinkageInfo external() { + return LinkageInfo(); + } + static LinkageInfo internal() { + return LinkageInfo(InternalLinkage, DefaultVisibility, false); + } + static LinkageInfo uniqueExternal() { + return LinkageInfo(UniqueExternalLinkage, DefaultVisibility, false); + } + static LinkageInfo none() { + return LinkageInfo(NoLinkage, DefaultVisibility, false); + } + + Linkage linkage() const { return linkage_; } + Visibility visibility() const { return visibility_; } + bool visibilityExplicit() const { return explicit_; } + + void setLinkage(Linkage L) { linkage_ = L; } + void setVisibility(Visibility V, bool E) { visibility_ = V; explicit_ = E; } + + void mergeLinkage(Linkage L) { + setLinkage(minLinkage(linkage(), L)); + } + void mergeLinkage(LinkageInfo Other) { + mergeLinkage(Other.linkage()); + } + + // Merge the visibility V giving preference to explicit ones. + // This is used, for example, when merging the visibility of a class + // down to one of its members. If the member has no explicit visibility, + // the class visibility wins. + void mergeVisibility(Visibility V, bool E = false) { + // If one has explicit visibility and the other doesn't, keep the + // explicit one. + if (visibilityExplicit() && !E) + return; + if (!visibilityExplicit() && E) + setVisibility(V, E); + + // If both are explicit or both are implicit, keep the minimum. + setVisibility(minVisibility(visibility(), V), visibilityExplicit() || E); + } + // Merge the visibility V, keeping the most restrictive one. + // This is used for cases like merging the visibility of a template + // argument to an instantiation. If we already have a hidden class, + // no argument should give it default visibility. + void mergeVisibilityWithMin(Visibility V, bool E = false) { + // Never increase the visibility + if (visibility() < V) + return; + + // If this visibility is explicit, keep it. + if (visibilityExplicit() && !E) + return; + setVisibility(V, E); + } + void mergeVisibility(LinkageInfo Other) { + mergeVisibility(Other.visibility(), Other.visibilityExplicit()); + } + void mergeVisibilityWithMin(LinkageInfo Other) { + mergeVisibilityWithMin(Other.visibility(), Other.visibilityExplicit()); + } + + void merge(LinkageInfo Other) { + mergeLinkage(Other); + mergeVisibility(Other); + } + void mergeWithMin(LinkageInfo Other) { + mergeLinkage(Other); + mergeVisibilityWithMin(Other); + } + + friend LinkageInfo merge(LinkageInfo L, LinkageInfo R) { + L.merge(R); + return L; + } + }; + + /// \brief Determine what kind of linkage this entity has. + Linkage getLinkage() const; + + /// \brief Determines the visibility of this entity. + Visibility getVisibility() const { + return getLinkageAndVisibility().visibility(); + } + + /// \brief Determines the linkage and visibility of this entity. + LinkageInfo getLinkageAndVisibility() const; + + /// \brief If visibility was explicitly specified for this + /// declaration, return that visibility. + llvm::Optional<Visibility> getExplicitVisibility() const; + + /// \brief Clear the linkage cache in response to a change + /// to the declaration. + void ClearLinkageCache(); + + /// \brief Looks through UsingDecls and ObjCCompatibleAliasDecls for + /// the underlying named decl. + NamedDecl *getUnderlyingDecl() { + // Fast-path the common case. + if (this->getKind() != UsingShadow && + this->getKind() != ObjCCompatibleAlias) + return this; + + return getUnderlyingDeclImpl(); + } + const NamedDecl *getUnderlyingDecl() const { + return const_cast<NamedDecl*>(this)->getUnderlyingDecl(); + } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const NamedDecl *D) { return true; } + static bool classofKind(Kind K) { return K >= firstNamed && K <= lastNamed; } +}; + +inline raw_ostream &operator<<(raw_ostream &OS, const NamedDecl &ND) { + ND.printName(OS); + return OS; +} + +/// LabelDecl - Represents the declaration of a label. Labels also have a +/// corresponding LabelStmt, which indicates the position that the label was +/// defined at. For normal labels, the location of the decl is the same as the +/// location of the statement. For GNU local labels (__label__), the decl +/// location is where the __label__ is. +class LabelDecl : public NamedDecl { + virtual void anchor(); + LabelStmt *TheStmt; + /// LocStart - For normal labels, this is the same as the main declaration + /// label, i.e., the location of the identifier; for GNU local labels, + /// this is the location of the __label__ keyword. + SourceLocation LocStart; + + LabelDecl(DeclContext *DC, SourceLocation IdentL, IdentifierInfo *II, + LabelStmt *S, SourceLocation StartL) + : NamedDecl(Label, DC, IdentL, II), TheStmt(S), LocStart(StartL) {} + +public: + static LabelDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation IdentL, IdentifierInfo *II); + static LabelDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation IdentL, IdentifierInfo *II, + SourceLocation GnuLabelL); + static LabelDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + LabelStmt *getStmt() const { return TheStmt; } + void setStmt(LabelStmt *T) { TheStmt = T; } + + bool isGnuLocal() const { return LocStart != getLocation(); } + void setLocStart(SourceLocation L) { LocStart = L; } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(LocStart, getLocation()); + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const LabelDecl *D) { return true; } + static bool classofKind(Kind K) { return K == Label; } +}; + +/// NamespaceDecl - Represent a C++ namespace. +class NamespaceDecl : public NamedDecl, public DeclContext, + public Redeclarable<NamespaceDecl> +{ + virtual void anchor(); + + /// LocStart - The starting location of the source range, pointing + /// to either the namespace or the inline keyword. + SourceLocation LocStart; + /// RBraceLoc - The ending location of the source range. + SourceLocation RBraceLoc; + + /// \brief A pointer to either the anonymous namespace that lives just inside + /// this namespace or to the first namespace in the chain (the latter case + /// only when this is not the first in the chain), along with a + /// boolean value indicating whether this is an inline namespace. + llvm::PointerIntPair<NamespaceDecl *, 1, bool> AnonOrFirstNamespaceAndInline; + + NamespaceDecl(DeclContext *DC, bool Inline, SourceLocation StartLoc, + SourceLocation IdLoc, IdentifierInfo *Id, + NamespaceDecl *PrevDecl); + + typedef Redeclarable<NamespaceDecl> redeclarable_base; + virtual NamespaceDecl *getNextRedeclaration() { + return RedeclLink.getNext(); + } + virtual NamespaceDecl *getPreviousDeclImpl() { + return getPreviousDecl(); + } + virtual NamespaceDecl *getMostRecentDeclImpl() { + return getMostRecentDecl(); + } + +public: + static NamespaceDecl *Create(ASTContext &C, DeclContext *DC, + bool Inline, SourceLocation StartLoc, + SourceLocation IdLoc, IdentifierInfo *Id, + NamespaceDecl *PrevDecl); + + static NamespaceDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + typedef redeclarable_base::redecl_iterator redecl_iterator; + using redeclarable_base::redecls_begin; + using redeclarable_base::redecls_end; + using redeclarable_base::getPreviousDecl; + using redeclarable_base::getMostRecentDecl; + + /// \brief Returns true if this is an anonymous namespace declaration. + /// + /// For example: + /// \code + /// namespace { + /// ... + /// }; + /// \endcode + /// q.v. C++ [namespace.unnamed] + bool isAnonymousNamespace() const { + return !getIdentifier(); + } + + /// \brief Returns true if this is an inline namespace declaration. + bool isInline() const { + return AnonOrFirstNamespaceAndInline.getInt(); + } + + /// \brief Set whether this is an inline namespace declaration. + void setInline(bool Inline) { + AnonOrFirstNamespaceAndInline.setInt(Inline); + } + + /// \brief Get the original (first) namespace declaration. + NamespaceDecl *getOriginalNamespace() { + if (isFirstDeclaration()) + return this; + + return AnonOrFirstNamespaceAndInline.getPointer(); + } + + /// \brief Get the original (first) namespace declaration. + const NamespaceDecl *getOriginalNamespace() const { + if (isFirstDeclaration()) + return this; + + return AnonOrFirstNamespaceAndInline.getPointer(); + } + + /// \brief Return true if this declaration is an original (first) declaration + /// of the namespace. This is false for non-original (subsequent) namespace + /// declarations and anonymous namespaces. + bool isOriginalNamespace() const { + return isFirstDeclaration(); + } + + /// \brief Retrieve the anonymous namespace nested inside this namespace, + /// if any. + NamespaceDecl *getAnonymousNamespace() const { + return getOriginalNamespace()->AnonOrFirstNamespaceAndInline.getPointer(); + } + + void setAnonymousNamespace(NamespaceDecl *D) { + getOriginalNamespace()->AnonOrFirstNamespaceAndInline.setPointer(D); + } + + /// Retrieves the canonical declaration of this namespace. + NamespaceDecl *getCanonicalDecl() { + return getOriginalNamespace(); + } + const NamespaceDecl *getCanonicalDecl() const { + return getOriginalNamespace(); + } + + virtual SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(LocStart, RBraceLoc); + } + + SourceLocation getLocStart() const LLVM_READONLY { return LocStart; } + SourceLocation getRBraceLoc() const { return RBraceLoc; } + void setLocStart(SourceLocation L) { LocStart = L; } + void setRBraceLoc(SourceLocation L) { RBraceLoc = L; } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const NamespaceDecl *D) { return true; } + static bool classofKind(Kind K) { return K == Namespace; } + static DeclContext *castToDeclContext(const NamespaceDecl *D) { + return static_cast<DeclContext *>(const_cast<NamespaceDecl*>(D)); + } + static NamespaceDecl *castFromDeclContext(const DeclContext *DC) { + return static_cast<NamespaceDecl *>(const_cast<DeclContext*>(DC)); + } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +/// ValueDecl - Represent the declaration of a variable (in which case it is +/// an lvalue) a function (in which case it is a function designator) or +/// an enum constant. +class ValueDecl : public NamedDecl { + virtual void anchor(); + QualType DeclType; + +protected: + ValueDecl(Kind DK, DeclContext *DC, SourceLocation L, + DeclarationName N, QualType T) + : NamedDecl(DK, DC, L, N), DeclType(T) {} +public: + QualType getType() const { return DeclType; } + void setType(QualType newType) { DeclType = newType; } + + /// \brief Determine whether this symbol is weakly-imported, + /// or declared with the weak or weak-ref attr. + bool isWeak() const { + return hasAttr<WeakAttr>() || hasAttr<WeakRefAttr>() || isWeakImported(); + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const ValueDecl *D) { return true; } + static bool classofKind(Kind K) { return K >= firstValue && K <= lastValue; } +}; + +/// QualifierInfo - A struct with extended info about a syntactic +/// name qualifier, to be used for the case of out-of-line declarations. +struct QualifierInfo { + NestedNameSpecifierLoc QualifierLoc; + + /// NumTemplParamLists - The number of "outer" template parameter lists. + /// The count includes all of the template parameter lists that were matched + /// against the template-ids occurring into the NNS and possibly (in the + /// case of an explicit specialization) a final "template <>". + unsigned NumTemplParamLists; + + /// TemplParamLists - A new-allocated array of size NumTemplParamLists, + /// containing pointers to the "outer" template parameter lists. + /// It includes all of the template parameter lists that were matched + /// against the template-ids occurring into the NNS and possibly (in the + /// case of an explicit specialization) a final "template <>". + TemplateParameterList** TemplParamLists; + + /// Default constructor. + QualifierInfo() : QualifierLoc(), NumTemplParamLists(0), TemplParamLists(0) {} + + /// setTemplateParameterListsInfo - Sets info about "outer" template + /// parameter lists. + void setTemplateParameterListsInfo(ASTContext &Context, + unsigned NumTPLists, + TemplateParameterList **TPLists); + +private: + // Copy constructor and copy assignment are disabled. + QualifierInfo(const QualifierInfo&); + QualifierInfo& operator=(const QualifierInfo&); +}; + +/// \brief Represents a ValueDecl that came out of a declarator. +/// Contains type source information through TypeSourceInfo. +class DeclaratorDecl : public ValueDecl { + // A struct representing both a TInfo and a syntactic qualifier, + // to be used for the (uncommon) case of out-of-line declarations. + struct ExtInfo : public QualifierInfo { + TypeSourceInfo *TInfo; + }; + + llvm::PointerUnion<TypeSourceInfo*, ExtInfo*> DeclInfo; + + /// InnerLocStart - The start of the source range for this declaration, + /// ignoring outer template declarations. + SourceLocation InnerLocStart; + + bool hasExtInfo() const { return DeclInfo.is<ExtInfo*>(); } + ExtInfo *getExtInfo() { return DeclInfo.get<ExtInfo*>(); } + const ExtInfo *getExtInfo() const { return DeclInfo.get<ExtInfo*>(); } + +protected: + DeclaratorDecl(Kind DK, DeclContext *DC, SourceLocation L, + DeclarationName N, QualType T, TypeSourceInfo *TInfo, + SourceLocation StartL) + : ValueDecl(DK, DC, L, N, T), DeclInfo(TInfo), InnerLocStart(StartL) { + } + +public: + TypeSourceInfo *getTypeSourceInfo() const { + return hasExtInfo() + ? getExtInfo()->TInfo + : DeclInfo.get<TypeSourceInfo*>(); + } + void setTypeSourceInfo(TypeSourceInfo *TI) { + if (hasExtInfo()) + getExtInfo()->TInfo = TI; + else + DeclInfo = TI; + } + + /// getInnerLocStart - Return SourceLocation representing start of source + /// range ignoring outer template declarations. + SourceLocation getInnerLocStart() const { return InnerLocStart; } + void setInnerLocStart(SourceLocation L) { InnerLocStart = L; } + + /// getOuterLocStart - Return SourceLocation representing start of source + /// range taking into account any outer template declarations. + SourceLocation getOuterLocStart() const; + + virtual SourceRange getSourceRange() const LLVM_READONLY; + SourceLocation getLocStart() const LLVM_READONLY { + return getOuterLocStart(); + } + + /// \brief Retrieve the nested-name-specifier that qualifies the name of this + /// declaration, if it was present in the source. + NestedNameSpecifier *getQualifier() const { + return hasExtInfo() ? getExtInfo()->QualifierLoc.getNestedNameSpecifier() + : 0; + } + + /// \brief Retrieve the nested-name-specifier (with source-location + /// information) that qualifies the name of this declaration, if it was + /// present in the source. + NestedNameSpecifierLoc getQualifierLoc() const { + return hasExtInfo() ? getExtInfo()->QualifierLoc + : NestedNameSpecifierLoc(); + } + + void setQualifierInfo(NestedNameSpecifierLoc QualifierLoc); + + unsigned getNumTemplateParameterLists() const { + return hasExtInfo() ? getExtInfo()->NumTemplParamLists : 0; + } + TemplateParameterList *getTemplateParameterList(unsigned index) const { + assert(index < getNumTemplateParameterLists()); + return getExtInfo()->TemplParamLists[index]; + } + void setTemplateParameterListsInfo(ASTContext &Context, unsigned NumTPLists, + TemplateParameterList **TPLists); + + SourceLocation getTypeSpecStartLoc() const; + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const DeclaratorDecl *D) { return true; } + static bool classofKind(Kind K) { + return K >= firstDeclarator && K <= lastDeclarator; + } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +/// \brief Structure used to store a statement, the constant value to +/// which it was evaluated (if any), and whether or not the statement +/// is an integral constant expression (if known). +struct EvaluatedStmt { + EvaluatedStmt() : WasEvaluated(false), IsEvaluating(false), CheckedICE(false), + CheckingICE(false), IsICE(false) { } + + /// \brief Whether this statement was already evaluated. + bool WasEvaluated : 1; + + /// \brief Whether this statement is being evaluated. + bool IsEvaluating : 1; + + /// \brief Whether we already checked whether this statement was an + /// integral constant expression. + bool CheckedICE : 1; + + /// \brief Whether we are checking whether this statement is an + /// integral constant expression. + bool CheckingICE : 1; + + /// \brief Whether this statement is an integral constant expression, + /// or in C++11, whether the statement is a constant expression. Only + /// valid if CheckedICE is true. + bool IsICE : 1; + + Stmt *Value; + APValue Evaluated; +}; + +/// VarDecl - An instance of this class is created to represent a variable +/// declaration or definition. +class VarDecl : public DeclaratorDecl, public Redeclarable<VarDecl> { +public: + typedef clang::StorageClass StorageClass; + + /// getStorageClassSpecifierString - Return the string used to + /// specify the storage class \arg SC. + /// + /// It is illegal to call this function with SC == None. + static const char *getStorageClassSpecifierString(StorageClass SC); + + /// \brief Initialization styles. + enum InitializationStyle { + CInit, ///< C-style initialization with assignment + CallInit, ///< Call-style initialization (C++98) + ListInit ///< Direct list-initialization (C++11) + }; + +protected: + /// \brief Placeholder type used in Init to denote an unparsed C++ default + /// argument. + struct UnparsedDefaultArgument; + + /// \brief Placeholder type used in Init to denote an uninstantiated C++ + /// default argument. + struct UninstantiatedDefaultArgument; + + typedef llvm::PointerUnion4<Stmt *, EvaluatedStmt *, + UnparsedDefaultArgument *, + UninstantiatedDefaultArgument *> InitType; + + /// \brief The initializer for this variable or, for a ParmVarDecl, the + /// C++ default argument. + mutable InitType Init; + +private: + class VarDeclBitfields { + friend class VarDecl; + friend class ASTDeclReader; + + unsigned SClass : 3; + unsigned SClassAsWritten : 3; + unsigned ThreadSpecified : 1; + unsigned InitStyle : 2; + + /// \brief Whether this variable is the exception variable in a C++ catch + /// or an Objective-C @catch statement. + unsigned ExceptionVar : 1; + + /// \brief Whether this local variable could be allocated in the return + /// slot of its function, enabling the named return value optimization + /// (NRVO). + unsigned NRVOVariable : 1; + + /// \brief Whether this variable is the for-range-declaration in a C++0x + /// for-range statement. + unsigned CXXForRangeDecl : 1; + + /// \brief Whether this variable is an ARC pseudo-__strong + /// variable; see isARCPseudoStrong() for details. + unsigned ARCPseudoStrong : 1; + + /// \brief Whether this variable is (C++0x) constexpr. + unsigned IsConstexpr : 1; + }; + enum { NumVarDeclBits = 14 }; + + friend class ASTDeclReader; + friend class StmtIteratorBase; + +protected: + enum { NumParameterIndexBits = 8 }; + + class ParmVarDeclBitfields { + friend class ParmVarDecl; + friend class ASTDeclReader; + + unsigned : NumVarDeclBits; + + /// Whether this parameter inherits a default argument from a + /// prior declaration. + unsigned HasInheritedDefaultArg : 1; + + /// Whether this parameter undergoes K&R argument promotion. + unsigned IsKNRPromoted : 1; + + /// Whether this parameter is an ObjC method parameter or not. + unsigned IsObjCMethodParam : 1; + + /// If IsObjCMethodParam, a Decl::ObjCDeclQualifier. + /// Otherwise, the number of function parameter scopes enclosing + /// the function parameter scope in which this parameter was + /// declared. + unsigned ScopeDepthOrObjCQuals : 7; + + /// The number of parameters preceding this parameter in the + /// function parameter scope in which it was declared. + unsigned ParameterIndex : NumParameterIndexBits; + }; + + union { + unsigned AllBits; + VarDeclBitfields VarDeclBits; + ParmVarDeclBitfields ParmVarDeclBits; + }; + + VarDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, IdentifierInfo *Id, + QualType T, TypeSourceInfo *TInfo, StorageClass SC, + StorageClass SCAsWritten) + : DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc), Init() { + assert(sizeof(VarDeclBitfields) <= sizeof(unsigned)); + assert(sizeof(ParmVarDeclBitfields) <= sizeof(unsigned)); + AllBits = 0; + VarDeclBits.SClass = SC; + VarDeclBits.SClassAsWritten = SCAsWritten; + // Everything else is implicitly initialized to false. + } + + typedef Redeclarable<VarDecl> redeclarable_base; + virtual VarDecl *getNextRedeclaration() { return RedeclLink.getNext(); } + virtual VarDecl *getPreviousDeclImpl() { + return getPreviousDecl(); + } + virtual VarDecl *getMostRecentDeclImpl() { + return getMostRecentDecl(); + } + +public: + typedef redeclarable_base::redecl_iterator redecl_iterator; + using redeclarable_base::redecls_begin; + using redeclarable_base::redecls_end; + using redeclarable_base::getPreviousDecl; + using redeclarable_base::getMostRecentDecl; + + static VarDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, SourceLocation IdLoc, + IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, + StorageClass S, StorageClass SCAsWritten); + + static VarDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + virtual SourceRange getSourceRange() const LLVM_READONLY; + + StorageClass getStorageClass() const { + return (StorageClass) VarDeclBits.SClass; + } + StorageClass getStorageClassAsWritten() const { + return (StorageClass) VarDeclBits.SClassAsWritten; + } + void setStorageClass(StorageClass SC); + void setStorageClassAsWritten(StorageClass SC) { + assert(isLegalForVariable(SC)); + VarDeclBits.SClassAsWritten = SC; + } + + void setThreadSpecified(bool T) { VarDeclBits.ThreadSpecified = T; } + bool isThreadSpecified() const { + return VarDeclBits.ThreadSpecified; + } + + /// hasLocalStorage - Returns true if a variable with function scope + /// is a non-static local variable. + bool hasLocalStorage() const { + if (getStorageClass() == SC_None) + return !isFileVarDecl(); + + // Return true for: Auto, Register. + // Return false for: Extern, Static, PrivateExtern, OpenCLWorkGroupLocal. + + return getStorageClass() >= SC_Auto; + } + + /// isStaticLocal - Returns true if a variable with function scope is a + /// static local variable. + bool isStaticLocal() const { + return getStorageClass() == SC_Static && !isFileVarDecl(); + } + + /// hasExternStorage - Returns true if a variable has extern or + /// __private_extern__ storage. + bool hasExternalStorage() const { + return getStorageClass() == SC_Extern || + getStorageClass() == SC_PrivateExtern; + } + + /// hasGlobalStorage - Returns true for all variables that do not + /// have local storage. This includs all global variables as well + /// as static variables declared within a function. + bool hasGlobalStorage() const { return !hasLocalStorage(); } + + /// \brief Determines whether this variable is a variable with + /// external, C linkage. + bool isExternC() const; + + /// isLocalVarDecl - Returns true for local variable declarations + /// other than parameters. Note that this includes static variables + /// inside of functions. It also includes variables inside blocks. + /// + /// void foo() { int x; static int y; extern int z; } + /// + bool isLocalVarDecl() const { + if (getKind() != Decl::Var) + return false; + if (const DeclContext *DC = getDeclContext()) + return DC->getRedeclContext()->isFunctionOrMethod(); + return false; + } + + /// isFunctionOrMethodVarDecl - Similar to isLocalVarDecl, but + /// excludes variables declared in blocks. + bool isFunctionOrMethodVarDecl() const { + if (getKind() != Decl::Var) + return false; + const DeclContext *DC = getDeclContext()->getRedeclContext(); + return DC->isFunctionOrMethod() && DC->getDeclKind() != Decl::Block; + } + + /// \brief Determines whether this is a static data member. + /// + /// This will only be true in C++, and applies to, e.g., the + /// variable 'x' in: + /// \code + /// struct S { + /// static int x; + /// }; + /// \endcode + bool isStaticDataMember() const { + // If it wasn't static, it would be a FieldDecl. + return getKind() != Decl::ParmVar && getDeclContext()->isRecord(); + } + + virtual VarDecl *getCanonicalDecl(); + const VarDecl *getCanonicalDecl() const { + return const_cast<VarDecl*>(this)->getCanonicalDecl(); + } + + enum DefinitionKind { + DeclarationOnly, ///< This declaration is only a declaration. + TentativeDefinition, ///< This declaration is a tentative definition. + Definition ///< This declaration is definitely a definition. + }; + + /// \brief Check whether this declaration is a definition. If this could be + /// a tentative definition (in C), don't check whether there's an overriding + /// definition. + DefinitionKind isThisDeclarationADefinition(ASTContext &) const; + DefinitionKind isThisDeclarationADefinition() const { + return isThisDeclarationADefinition(getASTContext()); + } + + /// \brief Check whether this variable is defined in this + /// translation unit. + DefinitionKind hasDefinition(ASTContext &) const; + DefinitionKind hasDefinition() const { + return hasDefinition(getASTContext()); + } + + /// \brief Get the tentative definition that acts as the real definition in + /// a TU. Returns null if there is a proper definition available. + VarDecl *getActingDefinition(); + const VarDecl *getActingDefinition() const { + return const_cast<VarDecl*>(this)->getActingDefinition(); + } + + /// \brief Determine whether this is a tentative definition of a + /// variable in C. + bool isTentativeDefinitionNow() const; + + /// \brief Get the real (not just tentative) definition for this declaration. + VarDecl *getDefinition(ASTContext &); + const VarDecl *getDefinition(ASTContext &C) const { + return const_cast<VarDecl*>(this)->getDefinition(C); + } + VarDecl *getDefinition() { + return getDefinition(getASTContext()); + } + const VarDecl *getDefinition() const { + return const_cast<VarDecl*>(this)->getDefinition(); + } + + /// \brief Determine whether this is or was instantiated from an out-of-line + /// definition of a static data member. + virtual bool isOutOfLine() const; + + /// \brief If this is a static data member, find its out-of-line definition. + VarDecl *getOutOfLineDefinition(); + + /// isFileVarDecl - Returns true for file scoped variable declaration. + bool isFileVarDecl() const { + if (getKind() != Decl::Var) + return false; + + if (getDeclContext()->getRedeclContext()->isFileContext()) + return true; + + if (isStaticDataMember()) + return true; + + return false; + } + + /// getAnyInitializer - Get the initializer for this variable, no matter which + /// declaration it is attached to. + const Expr *getAnyInitializer() const { + const VarDecl *D; + return getAnyInitializer(D); + } + + /// getAnyInitializer - Get the initializer for this variable, no matter which + /// declaration it is attached to. Also get that declaration. + const Expr *getAnyInitializer(const VarDecl *&D) const; + + bool hasInit() const { + return !Init.isNull() && (Init.is<Stmt *>() || Init.is<EvaluatedStmt *>()); + } + const Expr *getInit() const { + if (Init.isNull()) + return 0; + + const Stmt *S = Init.dyn_cast<Stmt *>(); + if (!S) { + if (EvaluatedStmt *ES = Init.dyn_cast<EvaluatedStmt*>()) + S = ES->Value; + } + return (const Expr*) S; + } + Expr *getInit() { + if (Init.isNull()) + return 0; + + Stmt *S = Init.dyn_cast<Stmt *>(); + if (!S) { + if (EvaluatedStmt *ES = Init.dyn_cast<EvaluatedStmt*>()) + S = ES->Value; + } + + return (Expr*) S; + } + + /// \brief Retrieve the address of the initializer expression. + Stmt **getInitAddress() { + if (EvaluatedStmt *ES = Init.dyn_cast<EvaluatedStmt*>()) + return &ES->Value; + + // This union hack tip-toes around strict-aliasing rules. + union { + InitType *InitPtr; + Stmt **StmtPtr; + }; + + InitPtr = &Init; + return StmtPtr; + } + + void setInit(Expr *I); + + /// \brief Determine whether this variable is a reference that + /// extends the lifetime of its temporary initializer. + /// + /// A reference extends the lifetime of its temporary initializer if + /// it's initializer is an rvalue that would normally go out of scope + /// at the end of the initializer (a full expression). In such cases, + /// the reference itself takes ownership of the temporary, which will + /// be destroyed when the reference goes out of scope. For example: + /// + /// \code + /// const int &r = 1.0; // creates a temporary of type 'int' + /// \endcode + bool extendsLifetimeOfTemporary() const; + + /// \brief Determine whether this variable's value can be used in a + /// constant expression, according to the relevant language standard. + /// This only checks properties of the declaration, and does not check + /// whether the initializer is in fact a constant expression. + bool isUsableInConstantExpressions(ASTContext &C) const; + + EvaluatedStmt *ensureEvaluatedStmt() const; + + /// \brief Attempt to evaluate the value of the initializer attached to this + /// declaration, and produce notes explaining why it cannot be evaluated or is + /// not a constant expression. Returns a pointer to the value if evaluation + /// succeeded, 0 otherwise. + APValue *evaluateValue() const; + APValue *evaluateValue( + llvm::SmallVectorImpl<PartialDiagnosticAt> &Notes) const; + + /// \brief Return the already-evaluated value of this variable's + /// initializer, or NULL if the value is not yet known. Returns pointer + /// to untyped APValue if the value could not be evaluated. + APValue *getEvaluatedValue() const { + if (EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>()) + if (Eval->WasEvaluated) + return &Eval->Evaluated; + + return 0; + } + + /// \brief Determines whether it is already known whether the + /// initializer is an integral constant expression or not. + bool isInitKnownICE() const { + if (EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>()) + return Eval->CheckedICE; + + return false; + } + + /// \brief Determines whether the initializer is an integral constant + /// expression, or in C++11, whether the initializer is a constant + /// expression. + /// + /// \pre isInitKnownICE() + bool isInitICE() const { + assert(isInitKnownICE() && + "Check whether we already know that the initializer is an ICE"); + return Init.get<EvaluatedStmt *>()->IsICE; + } + + /// \brief Determine whether the value of the initializer attached to this + /// declaration is an integral constant expression. + bool checkInitIsICE() const; + + void setInitStyle(InitializationStyle Style) { + VarDeclBits.InitStyle = Style; + } + + /// \brief The style of initialization for this declaration. + /// + /// C-style initialization is "int x = 1;". Call-style initialization is + /// a C++98 direct-initializer, e.g. "int x(1);". The Init expression will be + /// the expression inside the parens or a "ClassType(a,b,c)" class constructor + /// expression for class types. List-style initialization is C++11 syntax, + /// e.g. "int x{1};". Clients can distinguish between different forms of + /// initialization by checking this value. In particular, "int x = {1};" is + /// C-style, "int x({1})" is call-style, and "int x{1};" is list-style; the + /// Init expression in all three cases is an InitListExpr. + InitializationStyle getInitStyle() const { + return static_cast<InitializationStyle>(VarDeclBits.InitStyle); + } + + /// \brief Whether the initializer is a direct-initializer (list or call). + bool isDirectInit() const { + return getInitStyle() != CInit; + } + + /// \brief Determine whether this variable is the exception variable in a + /// C++ catch statememt or an Objective-C @catch statement. + bool isExceptionVariable() const { + return VarDeclBits.ExceptionVar; + } + void setExceptionVariable(bool EV) { VarDeclBits.ExceptionVar = EV; } + + /// \brief Determine whether this local variable can be used with the named + /// return value optimization (NRVO). + /// + /// The named return value optimization (NRVO) works by marking certain + /// non-volatile local variables of class type as NRVO objects. These + /// locals can be allocated within the return slot of their containing + /// function, in which case there is no need to copy the object to the + /// return slot when returning from the function. Within the function body, + /// each return that returns the NRVO object will have this variable as its + /// NRVO candidate. + bool isNRVOVariable() const { return VarDeclBits.NRVOVariable; } + void setNRVOVariable(bool NRVO) { VarDeclBits.NRVOVariable = NRVO; } + + /// \brief Determine whether this variable is the for-range-declaration in + /// a C++0x for-range statement. + bool isCXXForRangeDecl() const { return VarDeclBits.CXXForRangeDecl; } + void setCXXForRangeDecl(bool FRD) { VarDeclBits.CXXForRangeDecl = FRD; } + + /// \brief Determine whether this variable is an ARC pseudo-__strong + /// variable. A pseudo-__strong variable has a __strong-qualified + /// type but does not actually retain the object written into it. + /// Generally such variables are also 'const' for safety. + bool isARCPseudoStrong() const { return VarDeclBits.ARCPseudoStrong; } + void setARCPseudoStrong(bool ps) { VarDeclBits.ARCPseudoStrong = ps; } + + /// Whether this variable is (C++0x) constexpr. + bool isConstexpr() const { return VarDeclBits.IsConstexpr; } + void setConstexpr(bool IC) { VarDeclBits.IsConstexpr = IC; } + + /// \brief If this variable is an instantiated static data member of a + /// class template specialization, returns the templated static data member + /// from which it was instantiated. + VarDecl *getInstantiatedFromStaticDataMember() const; + + /// \brief If this variable is a static data member, determine what kind of + /// template specialization or instantiation this is. + TemplateSpecializationKind getTemplateSpecializationKind() const; + + /// \brief If this variable is an instantiation of a static data member of a + /// class template specialization, retrieves the member specialization + /// information. + MemberSpecializationInfo *getMemberSpecializationInfo() const; + + /// \brief For a static data member that was instantiated from a static + /// data member of a class template, set the template specialiation kind. + void setTemplateSpecializationKind(TemplateSpecializationKind TSK, + SourceLocation PointOfInstantiation = SourceLocation()); + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const VarDecl *D) { return true; } + static bool classofKind(Kind K) { return K >= firstVar && K <= lastVar; } +}; + +class ImplicitParamDecl : public VarDecl { + virtual void anchor(); +public: + static ImplicitParamDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation IdLoc, IdentifierInfo *Id, + QualType T); + + static ImplicitParamDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + ImplicitParamDecl(DeclContext *DC, SourceLocation IdLoc, + IdentifierInfo *Id, QualType Type) + : VarDecl(ImplicitParam, DC, IdLoc, IdLoc, Id, Type, + /*tinfo*/ 0, SC_None, SC_None) { + setImplicit(); + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const ImplicitParamDecl *D) { return true; } + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == ImplicitParam; } +}; + +/// ParmVarDecl - Represents a parameter to a function. +class ParmVarDecl : public VarDecl { +public: + enum { MaxFunctionScopeDepth = 255 }; + enum { MaxFunctionScopeIndex = 255 }; + +protected: + ParmVarDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, IdentifierInfo *Id, + QualType T, TypeSourceInfo *TInfo, + StorageClass S, StorageClass SCAsWritten, Expr *DefArg) + : VarDecl(DK, DC, StartLoc, IdLoc, Id, T, TInfo, S, SCAsWritten) { + assert(ParmVarDeclBits.HasInheritedDefaultArg == false); + assert(ParmVarDeclBits.IsKNRPromoted == false); + assert(ParmVarDeclBits.IsObjCMethodParam == false); + setDefaultArg(DefArg); + } + +public: + static ParmVarDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, + SourceLocation IdLoc, IdentifierInfo *Id, + QualType T, TypeSourceInfo *TInfo, + StorageClass S, StorageClass SCAsWritten, + Expr *DefArg); + + static ParmVarDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + virtual SourceRange getSourceRange() const LLVM_READONLY; + + void setObjCMethodScopeInfo(unsigned parameterIndex) { + ParmVarDeclBits.IsObjCMethodParam = true; + setParameterIndex(parameterIndex); + } + + void setScopeInfo(unsigned scopeDepth, unsigned parameterIndex) { + assert(!ParmVarDeclBits.IsObjCMethodParam); + + ParmVarDeclBits.ScopeDepthOrObjCQuals = scopeDepth; + assert(ParmVarDeclBits.ScopeDepthOrObjCQuals == scopeDepth + && "truncation!"); + + setParameterIndex(parameterIndex); + } + + bool isObjCMethodParameter() const { + return ParmVarDeclBits.IsObjCMethodParam; + } + + unsigned getFunctionScopeDepth() const { + if (ParmVarDeclBits.IsObjCMethodParam) return 0; + return ParmVarDeclBits.ScopeDepthOrObjCQuals; + } + + /// Returns the index of this parameter in its prototype or method scope. + unsigned getFunctionScopeIndex() const { + return getParameterIndex(); + } + + ObjCDeclQualifier getObjCDeclQualifier() const { + if (!ParmVarDeclBits.IsObjCMethodParam) return OBJC_TQ_None; + return ObjCDeclQualifier(ParmVarDeclBits.ScopeDepthOrObjCQuals); + } + void setObjCDeclQualifier(ObjCDeclQualifier QTVal) { + assert(ParmVarDeclBits.IsObjCMethodParam); + ParmVarDeclBits.ScopeDepthOrObjCQuals = QTVal; + } + + /// True if the value passed to this parameter must undergo + /// K&R-style default argument promotion: + /// + /// C99 6.5.2.2. + /// If the expression that denotes the called function has a type + /// that does not include a prototype, the integer promotions are + /// performed on each argument, and arguments that have type float + /// are promoted to double. + bool isKNRPromoted() const { + return ParmVarDeclBits.IsKNRPromoted; + } + void setKNRPromoted(bool promoted) { + ParmVarDeclBits.IsKNRPromoted = promoted; + } + + Expr *getDefaultArg(); + const Expr *getDefaultArg() const { + return const_cast<ParmVarDecl *>(this)->getDefaultArg(); + } + + void setDefaultArg(Expr *defarg) { + Init = reinterpret_cast<Stmt *>(defarg); + } + + /// \brief Retrieve the source range that covers the entire default + /// argument. + SourceRange getDefaultArgRange() const; + void setUninstantiatedDefaultArg(Expr *arg) { + Init = reinterpret_cast<UninstantiatedDefaultArgument *>(arg); + } + Expr *getUninstantiatedDefaultArg() { + return (Expr *)Init.get<UninstantiatedDefaultArgument *>(); + } + const Expr *getUninstantiatedDefaultArg() const { + return (const Expr *)Init.get<UninstantiatedDefaultArgument *>(); + } + + /// hasDefaultArg - Determines whether this parameter has a default argument, + /// either parsed or not. + bool hasDefaultArg() const { + return getInit() || hasUnparsedDefaultArg() || + hasUninstantiatedDefaultArg(); + } + + /// hasUnparsedDefaultArg - Determines whether this parameter has a + /// default argument that has not yet been parsed. This will occur + /// during the processing of a C++ class whose member functions have + /// default arguments, e.g., + /// @code + /// class X { + /// public: + /// void f(int x = 17); // x has an unparsed default argument now + /// }; // x has a regular default argument now + /// @endcode + bool hasUnparsedDefaultArg() const { + return Init.is<UnparsedDefaultArgument*>(); + } + + bool hasUninstantiatedDefaultArg() const { + return Init.is<UninstantiatedDefaultArgument*>(); + } + + /// setUnparsedDefaultArg - Specify that this parameter has an + /// unparsed default argument. The argument will be replaced with a + /// real default argument via setDefaultArg when the class + /// definition enclosing the function declaration that owns this + /// default argument is completed. + void setUnparsedDefaultArg() { + Init = (UnparsedDefaultArgument *)0; + } + + bool hasInheritedDefaultArg() const { + return ParmVarDeclBits.HasInheritedDefaultArg; + } + + void setHasInheritedDefaultArg(bool I = true) { + ParmVarDeclBits.HasInheritedDefaultArg = I; + } + + QualType getOriginalType() const { + if (getTypeSourceInfo()) + return getTypeSourceInfo()->getType(); + return getType(); + } + + /// \brief Determine whether this parameter is actually a function + /// parameter pack. + bool isParameterPack() const; + + /// setOwningFunction - Sets the function declaration that owns this + /// ParmVarDecl. Since ParmVarDecls are often created before the + /// FunctionDecls that own them, this routine is required to update + /// the DeclContext appropriately. + void setOwningFunction(DeclContext *FD) { setDeclContext(FD); } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const ParmVarDecl *D) { return true; } + static bool classofKind(Kind K) { return K == ParmVar; } + +private: + enum { ParameterIndexSentinel = (1 << NumParameterIndexBits) - 1 }; + + void setParameterIndex(unsigned parameterIndex) { + if (parameterIndex >= ParameterIndexSentinel) { + setParameterIndexLarge(parameterIndex); + return; + } + + ParmVarDeclBits.ParameterIndex = parameterIndex; + assert(ParmVarDeclBits.ParameterIndex == parameterIndex && "truncation!"); + } + unsigned getParameterIndex() const { + unsigned d = ParmVarDeclBits.ParameterIndex; + return d == ParameterIndexSentinel ? getParameterIndexLarge() : d; + } + + void setParameterIndexLarge(unsigned parameterIndex); + unsigned getParameterIndexLarge() const; +}; + +/// FunctionDecl - An instance of this class is created to represent a +/// function declaration or definition. +/// +/// Since a given function can be declared several times in a program, +/// there may be several FunctionDecls that correspond to that +/// function. Only one of those FunctionDecls will be found when +/// traversing the list of declarations in the context of the +/// FunctionDecl (e.g., the translation unit); this FunctionDecl +/// contains all of the information known about the function. Other, +/// previous declarations of the function are available via the +/// getPreviousDecl() chain. +class FunctionDecl : public DeclaratorDecl, public DeclContext, + public Redeclarable<FunctionDecl> { +public: + typedef clang::StorageClass StorageClass; + + /// \brief The kind of templated function a FunctionDecl can be. + enum TemplatedKind { + TK_NonTemplate, + TK_FunctionTemplate, + TK_MemberSpecialization, + TK_FunctionTemplateSpecialization, + TK_DependentFunctionTemplateSpecialization + }; + +private: + /// ParamInfo - new[]'d array of pointers to VarDecls for the formal + /// parameters of this function. This is null if a prototype or if there are + /// no formals. + ParmVarDecl **ParamInfo; + + /// DeclsInPrototypeScope - Array of pointers to NamedDecls for + /// decls defined in the function prototype that are not parameters. E.g. + /// 'enum Y' in 'void f(enum Y {AA} x) {}'. + llvm::ArrayRef<NamedDecl*> DeclsInPrototypeScope; + + LazyDeclStmtPtr Body; + + // FIXME: This can be packed into the bitfields in Decl. + // NOTE: VC++ treats enums as signed, avoid using the StorageClass enum + unsigned SClass : 2; + unsigned SClassAsWritten : 2; + bool IsInline : 1; + bool IsInlineSpecified : 1; + bool IsVirtualAsWritten : 1; + bool IsPure : 1; + bool HasInheritedPrototype : 1; + bool HasWrittenPrototype : 1; + bool IsDeleted : 1; + bool IsTrivial : 1; // sunk from CXXMethodDecl + bool IsDefaulted : 1; // sunk from CXXMethoDecl + bool IsExplicitlyDefaulted : 1; //sunk from CXXMethodDecl + bool HasImplicitReturnZero : 1; + bool IsLateTemplateParsed : 1; + bool IsConstexpr : 1; + + /// \brief End part of this FunctionDecl's source range. + /// + /// We could compute the full range in getSourceRange(). However, when we're + /// dealing with a function definition deserialized from a PCH/AST file, + /// we can only compute the full range once the function body has been + /// de-serialized, so it's far better to have the (sometimes-redundant) + /// EndRangeLoc. + SourceLocation EndRangeLoc; + + /// \brief The template or declaration that this declaration + /// describes or was instantiated from, respectively. + /// + /// For non-templates, this value will be NULL. For function + /// declarations that describe a function template, this will be a + /// pointer to a FunctionTemplateDecl. For member functions + /// of class template specializations, this will be a MemberSpecializationInfo + /// pointer containing information about the specialization. + /// For function template specializations, this will be a + /// FunctionTemplateSpecializationInfo, which contains information about + /// the template being specialized and the template arguments involved in + /// that specialization. + llvm::PointerUnion4<FunctionTemplateDecl *, + MemberSpecializationInfo *, + FunctionTemplateSpecializationInfo *, + DependentFunctionTemplateSpecializationInfo *> + TemplateOrSpecialization; + + /// DNLoc - Provides source/type location info for the + /// declaration name embedded in the DeclaratorDecl base class. + DeclarationNameLoc DNLoc; + + /// \brief Specify that this function declaration is actually a function + /// template specialization. + /// + /// \param C the ASTContext. + /// + /// \param Template the function template that this function template + /// specialization specializes. + /// + /// \param TemplateArgs the template arguments that produced this + /// function template specialization from the template. + /// + /// \param InsertPos If non-NULL, the position in the function template + /// specialization set where the function template specialization data will + /// be inserted. + /// + /// \param TSK the kind of template specialization this is. + /// + /// \param TemplateArgsAsWritten location info of template arguments. + /// + /// \param PointOfInstantiation point at which the function template + /// specialization was first instantiated. + void setFunctionTemplateSpecialization(ASTContext &C, + FunctionTemplateDecl *Template, + const TemplateArgumentList *TemplateArgs, + void *InsertPos, + TemplateSpecializationKind TSK, + const TemplateArgumentListInfo *TemplateArgsAsWritten, + SourceLocation PointOfInstantiation); + + /// \brief Specify that this record is an instantiation of the + /// member function FD. + void setInstantiationOfMemberFunction(ASTContext &C, FunctionDecl *FD, + TemplateSpecializationKind TSK); + + void setParams(ASTContext &C, llvm::ArrayRef<ParmVarDecl *> NewParamInfo); + +protected: + FunctionDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc, + const DeclarationNameInfo &NameInfo, + QualType T, TypeSourceInfo *TInfo, + StorageClass S, StorageClass SCAsWritten, bool isInlineSpecified, + bool isConstexprSpecified) + : DeclaratorDecl(DK, DC, NameInfo.getLoc(), NameInfo.getName(), T, TInfo, + StartLoc), + DeclContext(DK), + ParamInfo(0), Body(), + SClass(S), SClassAsWritten(SCAsWritten), + IsInline(isInlineSpecified), IsInlineSpecified(isInlineSpecified), + IsVirtualAsWritten(false), IsPure(false), HasInheritedPrototype(false), + HasWrittenPrototype(true), IsDeleted(false), IsTrivial(false), + IsDefaulted(false), IsExplicitlyDefaulted(false), + HasImplicitReturnZero(false), IsLateTemplateParsed(false), + IsConstexpr(isConstexprSpecified), EndRangeLoc(NameInfo.getEndLoc()), + TemplateOrSpecialization(), + DNLoc(NameInfo.getInfo()) {} + + typedef Redeclarable<FunctionDecl> redeclarable_base; + virtual FunctionDecl *getNextRedeclaration() { return RedeclLink.getNext(); } + virtual FunctionDecl *getPreviousDeclImpl() { + return getPreviousDecl(); + } + virtual FunctionDecl *getMostRecentDeclImpl() { + return getMostRecentDecl(); + } + +public: + typedef redeclarable_base::redecl_iterator redecl_iterator; + using redeclarable_base::redecls_begin; + using redeclarable_base::redecls_end; + using redeclarable_base::getPreviousDecl; + using redeclarable_base::getMostRecentDecl; + + static FunctionDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, SourceLocation NLoc, + DeclarationName N, QualType T, + TypeSourceInfo *TInfo, + StorageClass SC = SC_None, + StorageClass SCAsWritten = SC_None, + bool isInlineSpecified = false, + bool hasWrittenPrototype = true, + bool isConstexprSpecified = false) { + DeclarationNameInfo NameInfo(N, NLoc); + return FunctionDecl::Create(C, DC, StartLoc, NameInfo, T, TInfo, + SC, SCAsWritten, + isInlineSpecified, hasWrittenPrototype, + isConstexprSpecified); + } + + static FunctionDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, + const DeclarationNameInfo &NameInfo, + QualType T, TypeSourceInfo *TInfo, + StorageClass SC = SC_None, + StorageClass SCAsWritten = SC_None, + bool isInlineSpecified = false, + bool hasWrittenPrototype = true, + bool isConstexprSpecified = false); + + static FunctionDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + DeclarationNameInfo getNameInfo() const { + return DeclarationNameInfo(getDeclName(), getLocation(), DNLoc); + } + + virtual void getNameForDiagnostic(std::string &S, + const PrintingPolicy &Policy, + bool Qualified) const; + + void setRangeEnd(SourceLocation E) { EndRangeLoc = E; } + + virtual SourceRange getSourceRange() const LLVM_READONLY; + + /// \brief Returns true if the function has a body (definition). The + /// function body might be in any of the (re-)declarations of this + /// function. The variant that accepts a FunctionDecl pointer will + /// set that function declaration to the actual declaration + /// containing the body (if there is one). + bool hasBody(const FunctionDecl *&Definition) const; + + virtual bool hasBody() const { + const FunctionDecl* Definition; + return hasBody(Definition); + } + + /// hasTrivialBody - Returns whether the function has a trivial body that does + /// not require any specific codegen. + bool hasTrivialBody() const; + + /// isDefined - Returns true if the function is defined at all, including + /// a deleted definition. Except for the behavior when the function is + /// deleted, behaves like hasBody. + bool isDefined(const FunctionDecl *&Definition) const; + + virtual bool isDefined() const { + const FunctionDecl* Definition; + return isDefined(Definition); + } + + /// getBody - Retrieve the body (definition) of the function. The + /// function body might be in any of the (re-)declarations of this + /// function. The variant that accepts a FunctionDecl pointer will + /// set that function declaration to the actual declaration + /// containing the body (if there is one). + /// NOTE: For checking if there is a body, use hasBody() instead, to avoid + /// unnecessary AST de-serialization of the body. + Stmt *getBody(const FunctionDecl *&Definition) const; + + virtual Stmt *getBody() const { + const FunctionDecl* Definition; + return getBody(Definition); + } + + /// isThisDeclarationADefinition - Returns whether this specific + /// declaration of the function is also a definition. This does not + /// determine whether the function has been defined (e.g., in a + /// previous definition); for that information, use isDefined. Note + /// that this returns false for a defaulted function unless that function + /// has been implicitly defined (possibly as deleted). + bool isThisDeclarationADefinition() const { + return IsDeleted || Body || IsLateTemplateParsed; + } + + /// doesThisDeclarationHaveABody - Returns whether this specific + /// declaration of the function has a body - that is, if it is a non- + /// deleted definition. + bool doesThisDeclarationHaveABody() const { + return Body || IsLateTemplateParsed; + } + + void setBody(Stmt *B); + void setLazyBody(uint64_t Offset) { Body = Offset; } + + /// Whether this function is variadic. + bool isVariadic() const; + + /// Whether this function is marked as virtual explicitly. + bool isVirtualAsWritten() const { return IsVirtualAsWritten; } + void setVirtualAsWritten(bool V) { IsVirtualAsWritten = V; } + + /// Whether this virtual function is pure, i.e. makes the containing class + /// abstract. + bool isPure() const { return IsPure; } + void setPure(bool P = true); + + /// Whether this templated function will be late parsed. + bool isLateTemplateParsed() const { return IsLateTemplateParsed; } + void setLateTemplateParsed(bool ILT = true) { IsLateTemplateParsed = ILT; } + + /// Whether this function is "trivial" in some specialized C++ senses. + /// Can only be true for default constructors, copy constructors, + /// copy assignment operators, and destructors. Not meaningful until + /// the class has been fully built by Sema. + bool isTrivial() const { return IsTrivial; } + void setTrivial(bool IT) { IsTrivial = IT; } + + /// Whether this function is defaulted per C++0x. Only valid for + /// special member functions. + bool isDefaulted() const { return IsDefaulted; } + void setDefaulted(bool D = true) { IsDefaulted = D; } + + /// Whether this function is explicitly defaulted per C++0x. Only valid + /// for special member functions. + bool isExplicitlyDefaulted() const { return IsExplicitlyDefaulted; } + void setExplicitlyDefaulted(bool ED = true) { IsExplicitlyDefaulted = ED; } + + /// Whether falling off this function implicitly returns null/zero. + /// If a more specific implicit return value is required, front-ends + /// should synthesize the appropriate return statements. + bool hasImplicitReturnZero() const { return HasImplicitReturnZero; } + void setHasImplicitReturnZero(bool IRZ) { HasImplicitReturnZero = IRZ; } + + /// \brief Whether this function has a prototype, either because one + /// was explicitly written or because it was "inherited" by merging + /// a declaration without a prototype with a declaration that has a + /// prototype. + bool hasPrototype() const { + return HasWrittenPrototype || HasInheritedPrototype; + } + + bool hasWrittenPrototype() const { return HasWrittenPrototype; } + + /// \brief Whether this function inherited its prototype from a + /// previous declaration. + bool hasInheritedPrototype() const { return HasInheritedPrototype; } + void setHasInheritedPrototype(bool P = true) { HasInheritedPrototype = P; } + + /// Whether this is a (C++0x) constexpr function or constexpr constructor. + bool isConstexpr() const { return IsConstexpr; } + void setConstexpr(bool IC) { IsConstexpr = IC; } + + /// \brief Whether this function has been deleted. + /// + /// A function that is "deleted" (via the C++0x "= delete" syntax) + /// acts like a normal function, except that it cannot actually be + /// called or have its address taken. Deleted functions are + /// typically used in C++ overload resolution to attract arguments + /// whose type or lvalue/rvalue-ness would permit the use of a + /// different overload that would behave incorrectly. For example, + /// one might use deleted functions to ban implicit conversion from + /// a floating-point number to an Integer type: + /// + /// @code + /// struct Integer { + /// Integer(long); // construct from a long + /// Integer(double) = delete; // no construction from float or double + /// Integer(long double) = delete; // no construction from long double + /// }; + /// @endcode + // If a function is deleted, its first declaration must be. + bool isDeleted() const { return getCanonicalDecl()->IsDeleted; } + bool isDeletedAsWritten() const { return IsDeleted && !IsDefaulted; } + void setDeletedAsWritten(bool D = true) { IsDeleted = D; } + + /// \brief Determines whether this function is "main", which is the + /// entry point into an executable program. + bool isMain() const; + + /// \brief Determines whether this operator new or delete is one + /// of the reserved global placement operators: + /// void *operator new(size_t, void *); + /// void *operator new[](size_t, void *); + /// void operator delete(void *, void *); + /// void operator delete[](void *, void *); + /// These functions have special behavior under [new.delete.placement]: + /// These functions are reserved, a C++ program may not define + /// functions that displace the versions in the Standard C++ library. + /// The provisions of [basic.stc.dynamic] do not apply to these + /// reserved placement forms of operator new and operator delete. + /// + /// This function must be an allocation or deallocation function. + bool isReservedGlobalPlacementOperator() const; + + /// \brief Determines whether this function is a function with + /// external, C linkage. + bool isExternC() const; + + /// \brief Determines whether this is a global function. + bool isGlobal() const; + + void setPreviousDeclaration(FunctionDecl * PrevDecl); + + virtual const FunctionDecl *getCanonicalDecl() const; + virtual FunctionDecl *getCanonicalDecl(); + + unsigned getBuiltinID() const; + + // Iterator access to formal parameters. + unsigned param_size() const { return getNumParams(); } + typedef ParmVarDecl **param_iterator; + typedef ParmVarDecl * const *param_const_iterator; + + param_iterator param_begin() { return ParamInfo; } + param_iterator param_end() { return ParamInfo+param_size(); } + + param_const_iterator param_begin() const { return ParamInfo; } + param_const_iterator param_end() const { return ParamInfo+param_size(); } + + /// getNumParams - Return the number of parameters this function must have + /// based on its FunctionType. This is the length of the ParamInfo array + /// after it has been created. + unsigned getNumParams() const; + + const ParmVarDecl *getParamDecl(unsigned i) const { + assert(i < getNumParams() && "Illegal param #"); + return ParamInfo[i]; + } + ParmVarDecl *getParamDecl(unsigned i) { + assert(i < getNumParams() && "Illegal param #"); + return ParamInfo[i]; + } + void setParams(llvm::ArrayRef<ParmVarDecl *> NewParamInfo) { + setParams(getASTContext(), NewParamInfo); + } + + const llvm::ArrayRef<NamedDecl*> &getDeclsInPrototypeScope() const { + return DeclsInPrototypeScope; + } + void setDeclsInPrototypeScope(llvm::ArrayRef<NamedDecl *> NewDecls); + + /// getMinRequiredArguments - Returns the minimum number of arguments + /// needed to call this function. This may be fewer than the number of + /// function parameters, if some of the parameters have default + /// arguments (in C++). + unsigned getMinRequiredArguments() const; + + QualType getResultType() const { + return getType()->getAs<FunctionType>()->getResultType(); + } + + /// \brief Determine the type of an expression that calls this function. + QualType getCallResultType() const { + return getType()->getAs<FunctionType>()->getCallResultType(getASTContext()); + } + + StorageClass getStorageClass() const { return StorageClass(SClass); } + void setStorageClass(StorageClass SC); + + StorageClass getStorageClassAsWritten() const { + return StorageClass(SClassAsWritten); + } + + /// \brief Determine whether the "inline" keyword was specified for this + /// function. + bool isInlineSpecified() const { return IsInlineSpecified; } + + /// Set whether the "inline" keyword was specified for this function. + void setInlineSpecified(bool I) { + IsInlineSpecified = I; + IsInline = I; + } + + /// Flag that this function is implicitly inline. + void setImplicitlyInline() { + IsInline = true; + } + + /// \brief Determine whether this function should be inlined, because it is + /// either marked "inline" or "constexpr" or is a member function of a class + /// that was defined in the class body. + bool isInlined() const; + + bool isInlineDefinitionExternallyVisible() const; + + bool doesDeclarationForceExternallyVisibleDefinition() const; + + /// isOverloadedOperator - Whether this function declaration + /// represents an C++ overloaded operator, e.g., "operator+". + bool isOverloadedOperator() const { + return getOverloadedOperator() != OO_None; + } + + OverloadedOperatorKind getOverloadedOperator() const; + + const IdentifierInfo *getLiteralIdentifier() const; + + /// \brief If this function is an instantiation of a member function + /// of a class template specialization, retrieves the function from + /// which it was instantiated. + /// + /// This routine will return non-NULL for (non-templated) member + /// functions of class templates and for instantiations of function + /// templates. For example, given: + /// + /// \code + /// template<typename T> + /// struct X { + /// void f(T); + /// }; + /// \endcode + /// + /// The declaration for X<int>::f is a (non-templated) FunctionDecl + /// whose parent is the class template specialization X<int>. For + /// this declaration, getInstantiatedFromFunction() will return + /// the FunctionDecl X<T>::A. When a complete definition of + /// X<int>::A is required, it will be instantiated from the + /// declaration returned by getInstantiatedFromMemberFunction(). + FunctionDecl *getInstantiatedFromMemberFunction() const; + + /// \brief What kind of templated function this is. + TemplatedKind getTemplatedKind() const; + + /// \brief If this function is an instantiation of a member function of a + /// class template specialization, retrieves the member specialization + /// information. + MemberSpecializationInfo *getMemberSpecializationInfo() const; + + /// \brief Specify that this record is an instantiation of the + /// member function FD. + void setInstantiationOfMemberFunction(FunctionDecl *FD, + TemplateSpecializationKind TSK) { + setInstantiationOfMemberFunction(getASTContext(), FD, TSK); + } + + /// \brief Retrieves the function template that is described by this + /// function declaration. + /// + /// Every function template is represented as a FunctionTemplateDecl + /// and a FunctionDecl (or something derived from FunctionDecl). The + /// former contains template properties (such as the template + /// parameter lists) while the latter contains the actual + /// description of the template's + /// contents. FunctionTemplateDecl::getTemplatedDecl() retrieves the + /// FunctionDecl that describes the function template, + /// getDescribedFunctionTemplate() retrieves the + /// FunctionTemplateDecl from a FunctionDecl. + FunctionTemplateDecl *getDescribedFunctionTemplate() const { + return TemplateOrSpecialization.dyn_cast<FunctionTemplateDecl*>(); + } + + void setDescribedFunctionTemplate(FunctionTemplateDecl *Template) { + TemplateOrSpecialization = Template; + } + + /// \brief Determine whether this function is a function template + /// specialization. + bool isFunctionTemplateSpecialization() const { + return getPrimaryTemplate() != 0; + } + + /// \brief Retrieve the class scope template pattern that this function + /// template specialization is instantiated from. + FunctionDecl *getClassScopeSpecializationPattern() const; + + /// \brief If this function is actually a function template specialization, + /// retrieve information about this function template specialization. + /// Otherwise, returns NULL. + FunctionTemplateSpecializationInfo *getTemplateSpecializationInfo() const { + return TemplateOrSpecialization. + dyn_cast<FunctionTemplateSpecializationInfo*>(); + } + + /// \brief Determines whether this function is a function template + /// specialization or a member of a class template specialization that can + /// be implicitly instantiated. + bool isImplicitlyInstantiable() const; + + /// \brief Determines if the given function was instantiated from a + /// function template. + bool isTemplateInstantiation() const; + + /// \brief Retrieve the function declaration from which this function could + /// be instantiated, if it is an instantiation (rather than a non-template + /// or a specialization, for example). + FunctionDecl *getTemplateInstantiationPattern() const; + + /// \brief Retrieve the primary template that this function template + /// specialization either specializes or was instantiated from. + /// + /// If this function declaration is not a function template specialization, + /// returns NULL. + FunctionTemplateDecl *getPrimaryTemplate() const; + + /// \brief Retrieve the template arguments used to produce this function + /// template specialization from the primary template. + /// + /// If this function declaration is not a function template specialization, + /// returns NULL. + const TemplateArgumentList *getTemplateSpecializationArgs() const; + + /// \brief Retrieve the template argument list as written in the sources, + /// if any. + /// + /// If this function declaration is not a function template specialization + /// or if it had no explicit template argument list, returns NULL. + /// Note that it an explicit template argument list may be written empty, + /// e.g., template<> void foo<>(char* s); + const ASTTemplateArgumentListInfo* + getTemplateSpecializationArgsAsWritten() const; + + /// \brief Specify that this function declaration is actually a function + /// template specialization. + /// + /// \param Template the function template that this function template + /// specialization specializes. + /// + /// \param TemplateArgs the template arguments that produced this + /// function template specialization from the template. + /// + /// \param InsertPos If non-NULL, the position in the function template + /// specialization set where the function template specialization data will + /// be inserted. + /// + /// \param TSK the kind of template specialization this is. + /// + /// \param TemplateArgsAsWritten location info of template arguments. + /// + /// \param PointOfInstantiation point at which the function template + /// specialization was first instantiated. + void setFunctionTemplateSpecialization(FunctionTemplateDecl *Template, + const TemplateArgumentList *TemplateArgs, + void *InsertPos, + TemplateSpecializationKind TSK = TSK_ImplicitInstantiation, + const TemplateArgumentListInfo *TemplateArgsAsWritten = 0, + SourceLocation PointOfInstantiation = SourceLocation()) { + setFunctionTemplateSpecialization(getASTContext(), Template, TemplateArgs, + InsertPos, TSK, TemplateArgsAsWritten, + PointOfInstantiation); + } + + /// \brief Specifies that this function declaration is actually a + /// dependent function template specialization. + void setDependentTemplateSpecialization(ASTContext &Context, + const UnresolvedSetImpl &Templates, + const TemplateArgumentListInfo &TemplateArgs); + + DependentFunctionTemplateSpecializationInfo * + getDependentSpecializationInfo() const { + return TemplateOrSpecialization. + dyn_cast<DependentFunctionTemplateSpecializationInfo*>(); + } + + /// \brief Determine what kind of template instantiation this function + /// represents. + TemplateSpecializationKind getTemplateSpecializationKind() const; + + /// \brief Determine what kind of template instantiation this function + /// represents. + void setTemplateSpecializationKind(TemplateSpecializationKind TSK, + SourceLocation PointOfInstantiation = SourceLocation()); + + /// \brief Retrieve the (first) point of instantiation of a function template + /// specialization or a member of a class template specialization. + /// + /// \returns the first point of instantiation, if this function was + /// instantiated from a template; otherwise, returns an invalid source + /// location. + SourceLocation getPointOfInstantiation() const; + + /// \brief Determine whether this is or was instantiated from an out-of-line + /// definition of a member function. + virtual bool isOutOfLine() const; + + /// \brief Identify a memory copying or setting function. + /// If the given function is a memory copy or setting function, returns + /// the corresponding Builtin ID. If the function is not a memory function, + /// returns 0. + unsigned getMemoryFunctionKind() const; + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const FunctionDecl *D) { return true; } + static bool classofKind(Kind K) { + return K >= firstFunction && K <= lastFunction; + } + static DeclContext *castToDeclContext(const FunctionDecl *D) { + return static_cast<DeclContext *>(const_cast<FunctionDecl*>(D)); + } + static FunctionDecl *castFromDeclContext(const DeclContext *DC) { + return static_cast<FunctionDecl *>(const_cast<DeclContext*>(DC)); + } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + + +/// FieldDecl - An instance of this class is created by Sema::ActOnField to +/// represent a member of a struct/union/class. +class FieldDecl : public DeclaratorDecl { + // FIXME: This can be packed into the bitfields in Decl. + bool Mutable : 1; + mutable unsigned CachedFieldIndex : 31; + + /// \brief A pointer to either the in-class initializer for this field (if + /// the boolean value is false), or the bit width expression for this bit + /// field (if the boolean value is true). + /// + /// We can safely combine these two because in-class initializers are not + /// permitted for bit-fields. + /// + /// If the boolean is false and the initializer is null, then this field has + /// an in-class initializer which has not yet been parsed and attached. + llvm::PointerIntPair<Expr *, 1, bool> InitializerOrBitWidth; +protected: + FieldDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, IdentifierInfo *Id, + QualType T, TypeSourceInfo *TInfo, Expr *BW, bool Mutable, + bool HasInit) + : DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc), + Mutable(Mutable), CachedFieldIndex(0), + InitializerOrBitWidth(BW, !HasInit) { + assert(!(BW && HasInit) && "got initializer for bitfield"); + } + +public: + static FieldDecl *Create(const ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, SourceLocation IdLoc, + IdentifierInfo *Id, QualType T, + TypeSourceInfo *TInfo, Expr *BW, bool Mutable, + bool HasInit); + + static FieldDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + /// getFieldIndex - Returns the index of this field within its record, + /// as appropriate for passing to ASTRecordLayout::getFieldOffset. + unsigned getFieldIndex() const; + + /// isMutable - Determines whether this field is mutable (C++ only). + bool isMutable() const { return Mutable; } + + /// \brief Set whether this field is mutable (C++ only). + void setMutable(bool M) { Mutable = M; } + + /// isBitfield - Determines whether this field is a bitfield. + bool isBitField() const { + return InitializerOrBitWidth.getInt() && InitializerOrBitWidth.getPointer(); + } + + /// @brief Determines whether this is an unnamed bitfield. + bool isUnnamedBitfield() const { return isBitField() && !getDeclName(); } + + /// isAnonymousStructOrUnion - Determines whether this field is a + /// representative for an anonymous struct or union. Such fields are + /// unnamed and are implicitly generated by the implementation to + /// store the data for the anonymous union or struct. + bool isAnonymousStructOrUnion() const; + + Expr *getBitWidth() const { + return isBitField() ? InitializerOrBitWidth.getPointer() : 0; + } + unsigned getBitWidthValue(const ASTContext &Ctx) const; + void setBitWidth(Expr *BW) { + assert(!InitializerOrBitWidth.getPointer() && + "bit width or initializer already set"); + InitializerOrBitWidth.setPointer(BW); + InitializerOrBitWidth.setInt(1); + } + /// removeBitWidth - Remove the bitfield width from this member. + void removeBitWidth() { + assert(isBitField() && "no bit width to remove"); + InitializerOrBitWidth.setPointer(0); + } + + /// hasInClassInitializer - Determine whether this member has a C++0x in-class + /// initializer. + bool hasInClassInitializer() const { + return !InitializerOrBitWidth.getInt(); + } + /// getInClassInitializer - Get the C++0x in-class initializer for this + /// member, or null if one has not been set. If a valid declaration has an + /// in-class initializer, but this returns null, then we have not parsed and + /// attached it yet. + Expr *getInClassInitializer() const { + return hasInClassInitializer() ? InitializerOrBitWidth.getPointer() : 0; + } + /// setInClassInitializer - Set the C++0x in-class initializer for this + /// member. + void setInClassInitializer(Expr *Init); + /// removeInClassInitializer - Remove the C++0x in-class initializer from this + /// member. + void removeInClassInitializer() { + assert(!InitializerOrBitWidth.getInt() && "no initializer to remove"); + InitializerOrBitWidth.setPointer(0); + InitializerOrBitWidth.setInt(1); + } + + /// getParent - Returns the parent of this field declaration, which + /// is the struct in which this method is defined. + const RecordDecl *getParent() const { + return cast<RecordDecl>(getDeclContext()); + } + + RecordDecl *getParent() { + return cast<RecordDecl>(getDeclContext()); + } + + SourceRange getSourceRange() const LLVM_READONLY; + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const FieldDecl *D) { return true; } + static bool classofKind(Kind K) { return K >= firstField && K <= lastField; } +}; + +/// EnumConstantDecl - An instance of this object exists for each enum constant +/// that is defined. For example, in "enum X {a,b}", each of a/b are +/// EnumConstantDecl's, X is an instance of EnumDecl, and the type of a/b is a +/// TagType for the X EnumDecl. +class EnumConstantDecl : public ValueDecl { + Stmt *Init; // an integer constant expression + llvm::APSInt Val; // The value. +protected: + EnumConstantDecl(DeclContext *DC, SourceLocation L, + IdentifierInfo *Id, QualType T, Expr *E, + const llvm::APSInt &V) + : ValueDecl(EnumConstant, DC, L, Id, T), Init((Stmt*)E), Val(V) {} + +public: + + static EnumConstantDecl *Create(ASTContext &C, EnumDecl *DC, + SourceLocation L, IdentifierInfo *Id, + QualType T, Expr *E, + const llvm::APSInt &V); + static EnumConstantDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + const Expr *getInitExpr() const { return (const Expr*) Init; } + Expr *getInitExpr() { return (Expr*) Init; } + const llvm::APSInt &getInitVal() const { return Val; } + + void setInitExpr(Expr *E) { Init = (Stmt*) E; } + void setInitVal(const llvm::APSInt &V) { Val = V; } + + SourceRange getSourceRange() const LLVM_READONLY; + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const EnumConstantDecl *D) { return true; } + static bool classofKind(Kind K) { return K == EnumConstant; } + + friend class StmtIteratorBase; +}; + +/// IndirectFieldDecl - An instance of this class is created to represent a +/// field injected from an anonymous union/struct into the parent scope. +/// IndirectFieldDecl are always implicit. +class IndirectFieldDecl : public ValueDecl { + virtual void anchor(); + NamedDecl **Chaining; + unsigned ChainingSize; + + IndirectFieldDecl(DeclContext *DC, SourceLocation L, + DeclarationName N, QualType T, + NamedDecl **CH, unsigned CHS) + : ValueDecl(IndirectField, DC, L, N, T), Chaining(CH), ChainingSize(CHS) {} + +public: + static IndirectFieldDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id, + QualType T, NamedDecl **CH, unsigned CHS); + + static IndirectFieldDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + typedef NamedDecl * const *chain_iterator; + chain_iterator chain_begin() const { return Chaining; } + chain_iterator chain_end() const { return Chaining+ChainingSize; } + + unsigned getChainingSize() const { return ChainingSize; } + + FieldDecl *getAnonField() const { + assert(ChainingSize >= 2); + return cast<FieldDecl>(Chaining[ChainingSize - 1]); + } + + VarDecl *getVarDecl() const { + assert(ChainingSize >= 2); + return dyn_cast<VarDecl>(*chain_begin()); + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const IndirectFieldDecl *D) { return true; } + static bool classofKind(Kind K) { return K == IndirectField; } + friend class ASTDeclReader; +}; + +/// TypeDecl - Represents a declaration of a type. +/// +class TypeDecl : public NamedDecl { + virtual void anchor(); + /// TypeForDecl - This indicates the Type object that represents + /// this TypeDecl. It is a cache maintained by + /// ASTContext::getTypedefType, ASTContext::getTagDeclType, and + /// ASTContext::getTemplateTypeParmType, and TemplateTypeParmDecl. + mutable const Type *TypeForDecl; + /// LocStart - The start of the source range for this declaration. + SourceLocation LocStart; + friend class ASTContext; + friend class DeclContext; + friend class TagDecl; + friend class TemplateTypeParmDecl; + friend class TagType; + friend class ASTReader; + +protected: + TypeDecl(Kind DK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, + SourceLocation StartL = SourceLocation()) + : NamedDecl(DK, DC, L, Id), TypeForDecl(0), LocStart(StartL) {} + +public: + // Low-level accessor + const Type *getTypeForDecl() const { return TypeForDecl; } + void setTypeForDecl(const Type *TD) { TypeForDecl = TD; } + + SourceLocation getLocStart() const LLVM_READONLY { return LocStart; } + void setLocStart(SourceLocation L) { LocStart = L; } + virtual SourceRange getSourceRange() const LLVM_READONLY { + if (LocStart.isValid()) + return SourceRange(LocStart, getLocation()); + else + return SourceRange(getLocation()); + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const TypeDecl *D) { return true; } + static bool classofKind(Kind K) { return K >= firstType && K <= lastType; } +}; + + +/// Base class for declarations which introduce a typedef-name. +class TypedefNameDecl : public TypeDecl, public Redeclarable<TypedefNameDecl> { + virtual void anchor(); + /// UnderlyingType - This is the type the typedef is set to. + TypeSourceInfo *TInfo; + +protected: + TypedefNameDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, IdentifierInfo *Id, + TypeSourceInfo *TInfo) + : TypeDecl(DK, DC, IdLoc, Id, StartLoc), TInfo(TInfo) {} + + typedef Redeclarable<TypedefNameDecl> redeclarable_base; + virtual TypedefNameDecl *getNextRedeclaration() { + return RedeclLink.getNext(); + } + virtual TypedefNameDecl *getPreviousDeclImpl() { + return getPreviousDecl(); + } + virtual TypedefNameDecl *getMostRecentDeclImpl() { + return getMostRecentDecl(); + } + +public: + typedef redeclarable_base::redecl_iterator redecl_iterator; + using redeclarable_base::redecls_begin; + using redeclarable_base::redecls_end; + using redeclarable_base::getPreviousDecl; + using redeclarable_base::getMostRecentDecl; + + TypeSourceInfo *getTypeSourceInfo() const { + return TInfo; + } + + /// Retrieves the canonical declaration of this typedef-name. + TypedefNameDecl *getCanonicalDecl() { + return getFirstDeclaration(); + } + const TypedefNameDecl *getCanonicalDecl() const { + return getFirstDeclaration(); + } + + QualType getUnderlyingType() const { + return TInfo->getType(); + } + void setTypeSourceInfo(TypeSourceInfo *newType) { + TInfo = newType; + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const TypedefNameDecl *D) { return true; } + static bool classofKind(Kind K) { + return K >= firstTypedefName && K <= lastTypedefName; + } +}; + +/// TypedefDecl - Represents the declaration of a typedef-name via the 'typedef' +/// type specifier. +class TypedefDecl : public TypedefNameDecl { + TypedefDecl(DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, + IdentifierInfo *Id, TypeSourceInfo *TInfo) + : TypedefNameDecl(Typedef, DC, StartLoc, IdLoc, Id, TInfo) {} + +public: + static TypedefDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, SourceLocation IdLoc, + IdentifierInfo *Id, TypeSourceInfo *TInfo); + static TypedefDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + SourceRange getSourceRange() const LLVM_READONLY; + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const TypedefDecl *D) { return true; } + static bool classofKind(Kind K) { return K == Typedef; } +}; + +/// TypeAliasDecl - Represents the declaration of a typedef-name via a C++0x +/// alias-declaration. +class TypeAliasDecl : public TypedefNameDecl { + TypeAliasDecl(DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, + IdentifierInfo *Id, TypeSourceInfo *TInfo) + : TypedefNameDecl(TypeAlias, DC, StartLoc, IdLoc, Id, TInfo) {} + +public: + static TypeAliasDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, SourceLocation IdLoc, + IdentifierInfo *Id, TypeSourceInfo *TInfo); + static TypeAliasDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + SourceRange getSourceRange() const LLVM_READONLY; + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const TypeAliasDecl *D) { return true; } + static bool classofKind(Kind K) { return K == TypeAlias; } +}; + +/// TagDecl - Represents the declaration of a struct/union/class/enum. +class TagDecl + : public TypeDecl, public DeclContext, public Redeclarable<TagDecl> { +public: + // This is really ugly. + typedef TagTypeKind TagKind; + +private: + // FIXME: This can be packed into the bitfields in Decl. + /// TagDeclKind - The TagKind enum. + unsigned TagDeclKind : 2; + + /// IsCompleteDefinition - True if this is a definition ("struct foo + /// {};"), false if it is a declaration ("struct foo;"). It is not + /// a definition until the definition has been fully processed. + bool IsCompleteDefinition : 1; + +protected: + /// IsBeingDefined - True if this is currently being defined. + bool IsBeingDefined : 1; + +private: + /// IsEmbeddedInDeclarator - True if this tag declaration is + /// "embedded" (i.e., defined or declared for the very first time) + /// in the syntax of a declarator. + bool IsEmbeddedInDeclarator : 1; + + /// \brief True if this tag is free standing, e.g. "struct foo;". + bool IsFreeStanding : 1; + +protected: + // These are used by (and only defined for) EnumDecl. + unsigned NumPositiveBits : 8; + unsigned NumNegativeBits : 8; + + /// IsScoped - True if this tag declaration is a scoped enumeration. Only + /// possible in C++11 mode. + bool IsScoped : 1; + /// IsScopedUsingClassTag - If this tag declaration is a scoped enum, + /// then this is true if the scoped enum was declared using the class + /// tag, false if it was declared with the struct tag. No meaning is + /// associated if this tag declaration is not a scoped enum. + bool IsScopedUsingClassTag : 1; + + /// IsFixed - True if this is an enumeration with fixed underlying type. Only + /// possible in C++11 or Microsoft extensions mode. + bool IsFixed : 1; + +private: + SourceLocation RBraceLoc; + + // A struct representing syntactic qualifier info, + // to be used for the (uncommon) case of out-of-line declarations. + typedef QualifierInfo ExtInfo; + + /// TypedefNameDeclOrQualifier - If the (out-of-line) tag declaration name + /// is qualified, it points to the qualifier info (nns and range); + /// otherwise, if the tag declaration is anonymous and it is part of + /// a typedef or alias, it points to the TypedefNameDecl (used for mangling); + /// otherwise, it is a null (TypedefNameDecl) pointer. + llvm::PointerUnion<TypedefNameDecl*, ExtInfo*> TypedefNameDeclOrQualifier; + + bool hasExtInfo() const { return TypedefNameDeclOrQualifier.is<ExtInfo*>(); } + ExtInfo *getExtInfo() { return TypedefNameDeclOrQualifier.get<ExtInfo*>(); } + const ExtInfo *getExtInfo() const { + return TypedefNameDeclOrQualifier.get<ExtInfo*>(); + } + +protected: + TagDecl(Kind DK, TagKind TK, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id, + TagDecl *PrevDecl, SourceLocation StartL) + : TypeDecl(DK, DC, L, Id, StartL), DeclContext(DK), + TypedefNameDeclOrQualifier((TypedefNameDecl*) 0) { + assert((DK != Enum || TK == TTK_Enum) && + "EnumDecl not matched with TTK_Enum"); + TagDeclKind = TK; + IsCompleteDefinition = false; + IsBeingDefined = false; + IsEmbeddedInDeclarator = false; + IsFreeStanding = false; + setPreviousDeclaration(PrevDecl); + } + + typedef Redeclarable<TagDecl> redeclarable_base; + virtual TagDecl *getNextRedeclaration() { return RedeclLink.getNext(); } + virtual TagDecl *getPreviousDeclImpl() { + return getPreviousDecl(); + } + virtual TagDecl *getMostRecentDeclImpl() { + return getMostRecentDecl(); + } + + /// @brief Completes the definition of this tag declaration. + /// + /// This is a helper function for derived classes. + void completeDefinition(); + +public: + typedef redeclarable_base::redecl_iterator redecl_iterator; + using redeclarable_base::redecls_begin; + using redeclarable_base::redecls_end; + using redeclarable_base::getPreviousDecl; + using redeclarable_base::getMostRecentDecl; + + SourceLocation getRBraceLoc() const { return RBraceLoc; } + void setRBraceLoc(SourceLocation L) { RBraceLoc = L; } + + /// getInnerLocStart - Return SourceLocation representing start of source + /// range ignoring outer template declarations. + SourceLocation getInnerLocStart() const { return getLocStart(); } + + /// getOuterLocStart - Return SourceLocation representing start of source + /// range taking into account any outer template declarations. + SourceLocation getOuterLocStart() const; + virtual SourceRange getSourceRange() const LLVM_READONLY; + + virtual TagDecl* getCanonicalDecl(); + const TagDecl* getCanonicalDecl() const { + return const_cast<TagDecl*>(this)->getCanonicalDecl(); + } + + /// isThisDeclarationADefinition() - Return true if this declaration + /// is a completion definintion of the type. Provided for consistency. + bool isThisDeclarationADefinition() const { + return isCompleteDefinition(); + } + + /// isCompleteDefinition - Return true if this decl has its body + /// fully specified. + bool isCompleteDefinition() const { + return IsCompleteDefinition; + } + + /// isBeingDefined - Return true if this decl is currently being defined. + bool isBeingDefined() const { + return IsBeingDefined; + } + + bool isEmbeddedInDeclarator() const { + return IsEmbeddedInDeclarator; + } + void setEmbeddedInDeclarator(bool isInDeclarator) { + IsEmbeddedInDeclarator = isInDeclarator; + } + + bool isFreeStanding() const { return IsFreeStanding; } + void setFreeStanding(bool isFreeStanding = true) { + IsFreeStanding = isFreeStanding; + } + + /// \brief Whether this declaration declares a type that is + /// dependent, i.e., a type that somehow depends on template + /// parameters. + bool isDependentType() const { return isDependentContext(); } + + /// @brief Starts the definition of this tag declaration. + /// + /// This method should be invoked at the beginning of the definition + /// of this tag declaration. It will set the tag type into a state + /// where it is in the process of being defined. + void startDefinition(); + + /// getDefinition - Returns the TagDecl that actually defines this + /// struct/union/class/enum. When determining whether or not a + /// struct/union/class/enum has a definition, one should use this + /// method as opposed to 'isDefinition'. 'isDefinition' indicates + /// whether or not a specific TagDecl is defining declaration, not + /// whether or not the struct/union/class/enum type is defined. + /// This method returns NULL if there is no TagDecl that defines + /// the struct/union/class/enum. + TagDecl *getDefinition() const; + + void setCompleteDefinition(bool V) { IsCompleteDefinition = V; } + + const char *getKindName() const { + return TypeWithKeyword::getTagTypeKindName(getTagKind()); + } + + TagKind getTagKind() const { + return TagKind(TagDeclKind); + } + + void setTagKind(TagKind TK) { TagDeclKind = TK; } + + bool isStruct() const { return getTagKind() == TTK_Struct; } + bool isClass() const { return getTagKind() == TTK_Class; } + bool isUnion() const { return getTagKind() == TTK_Union; } + bool isEnum() const { return getTagKind() == TTK_Enum; } + + TypedefNameDecl *getTypedefNameForAnonDecl() const { + return hasExtInfo() ? 0 : + TypedefNameDeclOrQualifier.get<TypedefNameDecl*>(); + } + + void setTypedefNameForAnonDecl(TypedefNameDecl *TDD); + + /// \brief Retrieve the nested-name-specifier that qualifies the name of this + /// declaration, if it was present in the source. + NestedNameSpecifier *getQualifier() const { + return hasExtInfo() ? getExtInfo()->QualifierLoc.getNestedNameSpecifier() + : 0; + } + + /// \brief Retrieve the nested-name-specifier (with source-location + /// information) that qualifies the name of this declaration, if it was + /// present in the source. + NestedNameSpecifierLoc getQualifierLoc() const { + return hasExtInfo() ? getExtInfo()->QualifierLoc + : NestedNameSpecifierLoc(); + } + + void setQualifierInfo(NestedNameSpecifierLoc QualifierLoc); + + unsigned getNumTemplateParameterLists() const { + return hasExtInfo() ? getExtInfo()->NumTemplParamLists : 0; + } + TemplateParameterList *getTemplateParameterList(unsigned i) const { + assert(i < getNumTemplateParameterLists()); + return getExtInfo()->TemplParamLists[i]; + } + void setTemplateParameterListsInfo(ASTContext &Context, unsigned NumTPLists, + TemplateParameterList **TPLists); + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const TagDecl *D) { return true; } + static bool classofKind(Kind K) { return K >= firstTag && K <= lastTag; } + + static DeclContext *castToDeclContext(const TagDecl *D) { + return static_cast<DeclContext *>(const_cast<TagDecl*>(D)); + } + static TagDecl *castFromDeclContext(const DeclContext *DC) { + return static_cast<TagDecl *>(const_cast<DeclContext*>(DC)); + } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +/// EnumDecl - Represents an enum. In C++11, enums can be forward-declared +/// with a fixed underlying type, and in C we allow them to be forward-declared +/// with no underlying type as an extension. +class EnumDecl : public TagDecl { + virtual void anchor(); + /// IntegerType - This represent the integer type that the enum corresponds + /// to for code generation purposes. Note that the enumerator constants may + /// have a different type than this does. + /// + /// If the underlying integer type was explicitly stated in the source + /// code, this is a TypeSourceInfo* for that type. Otherwise this type + /// was automatically deduced somehow, and this is a Type*. + /// + /// Normally if IsFixed(), this would contain a TypeSourceInfo*, but in + /// some cases it won't. + /// + /// The underlying type of an enumeration never has any qualifiers, so + /// we can get away with just storing a raw Type*, and thus save an + /// extra pointer when TypeSourceInfo is needed. + + llvm::PointerUnion<const Type*, TypeSourceInfo*> IntegerType; + + /// PromotionType - The integer type that values of this type should + /// promote to. In C, enumerators are generally of an integer type + /// directly, but gcc-style large enumerators (and all enumerators + /// in C++) are of the enum type instead. + QualType PromotionType; + + /// \brief If this enumeration is an instantiation of a member enumeration + /// of a class template specialization, this is the member specialization + /// information. + MemberSpecializationInfo *SpecializationInfo; + + EnumDecl(DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, + IdentifierInfo *Id, EnumDecl *PrevDecl, + bool Scoped, bool ScopedUsingClassTag, bool Fixed) + : TagDecl(Enum, TTK_Enum, DC, IdLoc, Id, PrevDecl, StartLoc), + SpecializationInfo(0) { + assert(Scoped || !ScopedUsingClassTag); + IntegerType = (const Type*)0; + NumNegativeBits = 0; + NumPositiveBits = 0; + IsScoped = Scoped; + IsScopedUsingClassTag = ScopedUsingClassTag; + IsFixed = Fixed; + } + + void setInstantiationOfMemberEnum(ASTContext &C, EnumDecl *ED, + TemplateSpecializationKind TSK); +public: + EnumDecl *getCanonicalDecl() { + return cast<EnumDecl>(TagDecl::getCanonicalDecl()); + } + const EnumDecl *getCanonicalDecl() const { + return cast<EnumDecl>(TagDecl::getCanonicalDecl()); + } + + const EnumDecl *getPreviousDecl() const { + return cast_or_null<EnumDecl>(TagDecl::getPreviousDecl()); + } + EnumDecl *getPreviousDecl() { + return cast_or_null<EnumDecl>(TagDecl::getPreviousDecl()); + } + + const EnumDecl *getMostRecentDecl() const { + return cast<EnumDecl>(TagDecl::getMostRecentDecl()); + } + EnumDecl *getMostRecentDecl() { + return cast<EnumDecl>(TagDecl::getMostRecentDecl()); + } + + EnumDecl *getDefinition() const { + return cast_or_null<EnumDecl>(TagDecl::getDefinition()); + } + + static EnumDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, SourceLocation IdLoc, + IdentifierInfo *Id, EnumDecl *PrevDecl, + bool IsScoped, bool IsScopedUsingClassTag, + bool IsFixed); + static EnumDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + /// completeDefinition - When created, the EnumDecl corresponds to a + /// forward-declared enum. This method is used to mark the + /// declaration as being defined; it's enumerators have already been + /// added (via DeclContext::addDecl). NewType is the new underlying + /// type of the enumeration type. + void completeDefinition(QualType NewType, + QualType PromotionType, + unsigned NumPositiveBits, + unsigned NumNegativeBits); + + // enumerator_iterator - Iterates through the enumerators of this + // enumeration. + typedef specific_decl_iterator<EnumConstantDecl> enumerator_iterator; + + enumerator_iterator enumerator_begin() const { + const EnumDecl *E = getDefinition(); + if (!E) + E = this; + return enumerator_iterator(E->decls_begin()); + } + + enumerator_iterator enumerator_end() const { + const EnumDecl *E = getDefinition(); + if (!E) + E = this; + return enumerator_iterator(E->decls_end()); + } + + /// getPromotionType - Return the integer type that enumerators + /// should promote to. + QualType getPromotionType() const { return PromotionType; } + + /// \brief Set the promotion type. + void setPromotionType(QualType T) { PromotionType = T; } + + /// getIntegerType - Return the integer type this enum decl corresponds to. + /// This returns a null qualtype for an enum forward definition. + QualType getIntegerType() const { + if (!IntegerType) + return QualType(); + if (const Type* T = IntegerType.dyn_cast<const Type*>()) + return QualType(T, 0); + return IntegerType.get<TypeSourceInfo*>()->getType(); + } + + /// \brief Set the underlying integer type. + void setIntegerType(QualType T) { IntegerType = T.getTypePtrOrNull(); } + + /// \brief Set the underlying integer type source info. + void setIntegerTypeSourceInfo(TypeSourceInfo* TInfo) { IntegerType = TInfo; } + + /// \brief Return the type source info for the underlying integer type, + /// if no type source info exists, return 0. + TypeSourceInfo* getIntegerTypeSourceInfo() const { + return IntegerType.dyn_cast<TypeSourceInfo*>(); + } + + /// \brief Returns the width in bits required to store all the + /// non-negative enumerators of this enum. + unsigned getNumPositiveBits() const { + return NumPositiveBits; + } + void setNumPositiveBits(unsigned Num) { + NumPositiveBits = Num; + assert(NumPositiveBits == Num && "can't store this bitcount"); + } + + /// \brief Returns the width in bits required to store all the + /// negative enumerators of this enum. These widths include + /// the rightmost leading 1; that is: + /// + /// MOST NEGATIVE ENUMERATOR PATTERN NUM NEGATIVE BITS + /// ------------------------ ------- ----------------- + /// -1 1111111 1 + /// -10 1110110 5 + /// -101 1001011 8 + unsigned getNumNegativeBits() const { + return NumNegativeBits; + } + void setNumNegativeBits(unsigned Num) { + NumNegativeBits = Num; + } + + /// \brief Returns true if this is a C++0x scoped enumeration. + bool isScoped() const { + return IsScoped; + } + + /// \brief Returns true if this is a C++0x scoped enumeration. + bool isScopedUsingClassTag() const { + return IsScopedUsingClassTag; + } + + /// \brief Returns true if this is a C++0x enumeration with fixed underlying + /// type. + bool isFixed() const { + return IsFixed; + } + + /// \brief Returns true if this can be considered a complete type. + bool isComplete() const { + return isCompleteDefinition() || isFixed(); + } + + /// \brief Returns the enumeration (declared within the template) + /// from which this enumeration type was instantiated, or NULL if + /// this enumeration was not instantiated from any template. + EnumDecl *getInstantiatedFromMemberEnum() const; + + /// \brief If this enumeration is a member of a specialization of a + /// templated class, determine what kind of template specialization + /// or instantiation this is. + TemplateSpecializationKind getTemplateSpecializationKind() const; + + /// \brief For an enumeration member that was instantiated from a member + /// enumeration of a templated class, set the template specialiation kind. + void setTemplateSpecializationKind(TemplateSpecializationKind TSK, + SourceLocation PointOfInstantiation = SourceLocation()); + + /// \brief If this enumeration is an instantiation of a member enumeration of + /// a class template specialization, retrieves the member specialization + /// information. + MemberSpecializationInfo *getMemberSpecializationInfo() const { + return SpecializationInfo; + } + + /// \brief Specify that this enumeration is an instantiation of the + /// member enumeration ED. + void setInstantiationOfMemberEnum(EnumDecl *ED, + TemplateSpecializationKind TSK) { + setInstantiationOfMemberEnum(getASTContext(), ED, TSK); + } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const EnumDecl *D) { return true; } + static bool classofKind(Kind K) { return K == Enum; } + + friend class ASTDeclReader; +}; + + +/// RecordDecl - Represents a struct/union/class. For example: +/// struct X; // Forward declaration, no "body". +/// union Y { int A, B; }; // Has body with members A and B (FieldDecls). +/// This decl will be marked invalid if *any* members are invalid. +/// +class RecordDecl : public TagDecl { + // FIXME: This can be packed into the bitfields in Decl. + /// HasFlexibleArrayMember - This is true if this struct ends with a flexible + /// array member (e.g. int X[]) or if this union contains a struct that does. + /// If so, this cannot be contained in arrays or other structs as a member. + bool HasFlexibleArrayMember : 1; + + /// AnonymousStructOrUnion - Whether this is the type of an anonymous struct + /// or union. + bool AnonymousStructOrUnion : 1; + + /// HasObjectMember - This is true if this struct has at least one member + /// containing an Objective-C object pointer type. + bool HasObjectMember : 1; + + /// \brief Whether the field declarations of this record have been loaded + /// from external storage. To avoid unnecessary deserialization of + /// methods/nested types we allow deserialization of just the fields + /// when needed. + mutable bool LoadedFieldsFromExternalStorage : 1; + friend class DeclContext; + +protected: + RecordDecl(Kind DK, TagKind TK, DeclContext *DC, + SourceLocation StartLoc, SourceLocation IdLoc, + IdentifierInfo *Id, RecordDecl *PrevDecl); + +public: + static RecordDecl *Create(const ASTContext &C, TagKind TK, DeclContext *DC, + SourceLocation StartLoc, SourceLocation IdLoc, + IdentifierInfo *Id, RecordDecl* PrevDecl = 0); + static RecordDecl *CreateDeserialized(const ASTContext &C, unsigned ID); + + const RecordDecl *getPreviousDecl() const { + return cast_or_null<RecordDecl>(TagDecl::getPreviousDecl()); + } + RecordDecl *getPreviousDecl() { + return cast_or_null<RecordDecl>(TagDecl::getPreviousDecl()); + } + + const RecordDecl *getMostRecentDecl() const { + return cast<RecordDecl>(TagDecl::getMostRecentDecl()); + } + RecordDecl *getMostRecentDecl() { + return cast<RecordDecl>(TagDecl::getMostRecentDecl()); + } + + bool hasFlexibleArrayMember() const { return HasFlexibleArrayMember; } + void setHasFlexibleArrayMember(bool V) { HasFlexibleArrayMember = V; } + + /// isAnonymousStructOrUnion - Whether this is an anonymous struct + /// or union. To be an anonymous struct or union, it must have been + /// declared without a name and there must be no objects of this + /// type declared, e.g., + /// @code + /// union { int i; float f; }; + /// @endcode + /// is an anonymous union but neither of the following are: + /// @code + /// union X { int i; float f; }; + /// union { int i; float f; } obj; + /// @endcode + bool isAnonymousStructOrUnion() const { return AnonymousStructOrUnion; } + void setAnonymousStructOrUnion(bool Anon) { + AnonymousStructOrUnion = Anon; + } + + bool hasObjectMember() const { return HasObjectMember; } + void setHasObjectMember (bool val) { HasObjectMember = val; } + + /// \brief Determines whether this declaration represents the + /// injected class name. + /// + /// The injected class name in C++ is the name of the class that + /// appears inside the class itself. For example: + /// + /// \code + /// struct C { + /// // C is implicitly declared here as a synonym for the class name. + /// }; + /// + /// C::C c; // same as "C c;" + /// \endcode + bool isInjectedClassName() const; + + /// getDefinition - Returns the RecordDecl that actually defines + /// this struct/union/class. When determining whether or not a + /// struct/union/class is completely defined, one should use this + /// method as opposed to 'isCompleteDefinition'. + /// 'isCompleteDefinition' indicates whether or not a specific + /// RecordDecl is a completed definition, not whether or not the + /// record type is defined. This method returns NULL if there is + /// no RecordDecl that defines the struct/union/tag. + RecordDecl *getDefinition() const { + return cast_or_null<RecordDecl>(TagDecl::getDefinition()); + } + + // Iterator access to field members. The field iterator only visits + // the non-static data members of this class, ignoring any static + // data members, functions, constructors, destructors, etc. + typedef specific_decl_iterator<FieldDecl> field_iterator; + + field_iterator field_begin() const; + + field_iterator field_end() const { + return field_iterator(decl_iterator()); + } + + // field_empty - Whether there are any fields (non-static data + // members) in this record. + bool field_empty() const { + return field_begin() == field_end(); + } + + /// completeDefinition - Notes that the definition of this type is + /// now complete. + virtual void completeDefinition(); + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const RecordDecl *D) { return true; } + static bool classofKind(Kind K) { + return K >= firstRecord && K <= lastRecord; + } + +private: + /// \brief Deserialize just the fields. + void LoadFieldsFromExternalStorage() const; +}; + +class FileScopeAsmDecl : public Decl { + virtual void anchor(); + StringLiteral *AsmString; + SourceLocation RParenLoc; + FileScopeAsmDecl(DeclContext *DC, StringLiteral *asmstring, + SourceLocation StartL, SourceLocation EndL) + : Decl(FileScopeAsm, DC, StartL), AsmString(asmstring), RParenLoc(EndL) {} +public: + static FileScopeAsmDecl *Create(ASTContext &C, DeclContext *DC, + StringLiteral *Str, SourceLocation AsmLoc, + SourceLocation RParenLoc); + + static FileScopeAsmDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + SourceLocation getAsmLoc() const { return getLocation(); } + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(getAsmLoc(), getRParenLoc()); + } + + const StringLiteral *getAsmString() const { return AsmString; } + StringLiteral *getAsmString() { return AsmString; } + void setAsmString(StringLiteral *Asm) { AsmString = Asm; } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const FileScopeAsmDecl *D) { return true; } + static bool classofKind(Kind K) { return K == FileScopeAsm; } +}; + +/// BlockDecl - This represents a block literal declaration, which is like an +/// unnamed FunctionDecl. For example: +/// ^{ statement-body } or ^(int arg1, float arg2){ statement-body } +/// +class BlockDecl : public Decl, public DeclContext { +public: + /// A class which contains all the information about a particular + /// captured value. + class Capture { + enum { + flag_isByRef = 0x1, + flag_isNested = 0x2 + }; + + /// The variable being captured. + llvm::PointerIntPair<VarDecl*, 2> VariableAndFlags; + + /// The copy expression, expressed in terms of a DeclRef (or + /// BlockDeclRef) to the captured variable. Only required if the + /// variable has a C++ class type. + Expr *CopyExpr; + + public: + Capture(VarDecl *variable, bool byRef, bool nested, Expr *copy) + : VariableAndFlags(variable, + (byRef ? flag_isByRef : 0) | (nested ? flag_isNested : 0)), + CopyExpr(copy) {} + + /// The variable being captured. + VarDecl *getVariable() const { return VariableAndFlags.getPointer(); } + + /// Whether this is a "by ref" capture, i.e. a capture of a __block + /// variable. + bool isByRef() const { return VariableAndFlags.getInt() & flag_isByRef; } + + /// Whether this is a nested capture, i.e. the variable captured + /// is not from outside the immediately enclosing function/block. + bool isNested() const { return VariableAndFlags.getInt() & flag_isNested; } + + bool hasCopyExpr() const { return CopyExpr != 0; } + Expr *getCopyExpr() const { return CopyExpr; } + void setCopyExpr(Expr *e) { CopyExpr = e; } + }; + +private: + // FIXME: This can be packed into the bitfields in Decl. + bool IsVariadic : 1; + bool CapturesCXXThis : 1; + bool BlockMissingReturnType : 1; + bool IsConversionFromLambda : 1; + /// ParamInfo - new[]'d array of pointers to ParmVarDecls for the formal + /// parameters of this function. This is null if a prototype or if there are + /// no formals. + ParmVarDecl **ParamInfo; + unsigned NumParams; + + Stmt *Body; + TypeSourceInfo *SignatureAsWritten; + + Capture *Captures; + unsigned NumCaptures; + +protected: + BlockDecl(DeclContext *DC, SourceLocation CaretLoc) + : Decl(Block, DC, CaretLoc), DeclContext(Block), + IsVariadic(false), CapturesCXXThis(false), + BlockMissingReturnType(true), IsConversionFromLambda(false), + ParamInfo(0), NumParams(0), Body(0), + SignatureAsWritten(0), Captures(0), NumCaptures(0) {} + +public: + static BlockDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L); + static BlockDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + SourceLocation getCaretLocation() const { return getLocation(); } + + bool isVariadic() const { return IsVariadic; } + void setIsVariadic(bool value) { IsVariadic = value; } + + CompoundStmt *getCompoundBody() const { return (CompoundStmt*) Body; } + Stmt *getBody() const { return (Stmt*) Body; } + void setBody(CompoundStmt *B) { Body = (Stmt*) B; } + + void setSignatureAsWritten(TypeSourceInfo *Sig) { SignatureAsWritten = Sig; } + TypeSourceInfo *getSignatureAsWritten() const { return SignatureAsWritten; } + + // Iterator access to formal parameters. + unsigned param_size() const { return getNumParams(); } + typedef ParmVarDecl **param_iterator; + typedef ParmVarDecl * const *param_const_iterator; + + bool param_empty() const { return NumParams == 0; } + param_iterator param_begin() { return ParamInfo; } + param_iterator param_end() { return ParamInfo+param_size(); } + + param_const_iterator param_begin() const { return ParamInfo; } + param_const_iterator param_end() const { return ParamInfo+param_size(); } + + unsigned getNumParams() const { return NumParams; } + const ParmVarDecl *getParamDecl(unsigned i) const { + assert(i < getNumParams() && "Illegal param #"); + return ParamInfo[i]; + } + ParmVarDecl *getParamDecl(unsigned i) { + assert(i < getNumParams() && "Illegal param #"); + return ParamInfo[i]; + } + void setParams(llvm::ArrayRef<ParmVarDecl *> NewParamInfo); + + /// hasCaptures - True if this block (or its nested blocks) captures + /// anything of local storage from its enclosing scopes. + bool hasCaptures() const { return NumCaptures != 0 || CapturesCXXThis; } + + /// getNumCaptures - Returns the number of captured variables. + /// Does not include an entry for 'this'. + unsigned getNumCaptures() const { return NumCaptures; } + + typedef const Capture *capture_iterator; + typedef const Capture *capture_const_iterator; + capture_iterator capture_begin() { return Captures; } + capture_iterator capture_end() { return Captures + NumCaptures; } + capture_const_iterator capture_begin() const { return Captures; } + capture_const_iterator capture_end() const { return Captures + NumCaptures; } + + bool capturesCXXThis() const { return CapturesCXXThis; } + bool blockMissingReturnType() const { return BlockMissingReturnType; } + void setBlockMissingReturnType(bool val) { BlockMissingReturnType = val; } + + bool isConversionFromLambda() const { return IsConversionFromLambda; } + void setIsConversionFromLambda(bool val) { IsConversionFromLambda = val; } + + bool capturesVariable(const VarDecl *var) const; + + void setCaptures(ASTContext &Context, + const Capture *begin, + const Capture *end, + bool capturesCXXThis); + + virtual SourceRange getSourceRange() const LLVM_READONLY; + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const BlockDecl *D) { return true; } + static bool classofKind(Kind K) { return K == Block; } + static DeclContext *castToDeclContext(const BlockDecl *D) { + return static_cast<DeclContext *>(const_cast<BlockDecl*>(D)); + } + static BlockDecl *castFromDeclContext(const DeclContext *DC) { + return static_cast<BlockDecl *>(const_cast<DeclContext*>(DC)); + } +}; + +/// \brief Describes a module import declaration, which makes the contents +/// of the named module visible in the current translation unit. +/// +/// An import declaration imports the named module (or submodule). For example: +/// \code +/// @__experimental_modules_import std.vector; +/// \endcode +/// +/// Import declarations can also be implicitly generated from #include/#import +/// directives. +class ImportDecl : public Decl { + /// \brief The imported module, along with a bit that indicates whether + /// we have source-location information for each identifier in the module + /// name. + /// + /// When the bit is false, we only have a single source location for the + /// end of the import declaration. + llvm::PointerIntPair<Module *, 1, bool> ImportedAndComplete; + + /// \brief The next import in the list of imports local to the translation + /// unit being parsed (not loaded from an AST file). + ImportDecl *NextLocalImport; + + friend class ASTReader; + friend class ASTDeclReader; + friend class ASTContext; + + ImportDecl(DeclContext *DC, SourceLocation StartLoc, Module *Imported, + ArrayRef<SourceLocation> IdentifierLocs); + + ImportDecl(DeclContext *DC, SourceLocation StartLoc, Module *Imported, + SourceLocation EndLoc); + + ImportDecl(EmptyShell Empty) : Decl(Import, Empty), NextLocalImport() { } + +public: + /// \brief Create a new module import declaration. + static ImportDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, Module *Imported, + ArrayRef<SourceLocation> IdentifierLocs); + + /// \brief Create a new module import declaration for an implicitly-generated + /// import. + static ImportDecl *CreateImplicit(ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, Module *Imported, + SourceLocation EndLoc); + + /// \brief Create a new, deserialized module import declaration. + static ImportDecl *CreateDeserialized(ASTContext &C, unsigned ID, + unsigned NumLocations); + + /// \brief Retrieve the module that was imported by the import declaration. + Module *getImportedModule() const { return ImportedAndComplete.getPointer(); } + + /// \brief Retrieves the locations of each of the identifiers that make up + /// the complete module name in the import declaration. + /// + /// This will return an empty array if the locations of the individual + /// identifiers aren't available. + ArrayRef<SourceLocation> getIdentifierLocs() const; + + virtual SourceRange getSourceRange() const LLVM_READONLY; + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const ImportDecl *D) { return true; } + static bool classofKind(Kind K) { return K == Import; } +}; + + +/// Insertion operator for diagnostics. This allows sending NamedDecl's +/// into a diagnostic with <<. +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + const NamedDecl* ND) { + DB.AddTaggedVal(reinterpret_cast<intptr_t>(ND), + DiagnosticsEngine::ak_nameddecl); + return DB; +} +inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, + const NamedDecl* ND) { + PD.AddTaggedVal(reinterpret_cast<intptr_t>(ND), + DiagnosticsEngine::ak_nameddecl); + return PD; +} + +template<typename decl_type> +void Redeclarable<decl_type>::setPreviousDeclaration(decl_type *PrevDecl) { + // Note: This routine is implemented here because we need both NamedDecl + // and Redeclarable to be defined. + + decl_type *First; + + if (PrevDecl) { + // Point to previous. Make sure that this is actually the most recent + // redeclaration, or we can build invalid chains. If the most recent + // redeclaration is invalid, it won't be PrevDecl, but we want it anyway. + RedeclLink = PreviousDeclLink( + llvm::cast<decl_type>(PrevDecl->getMostRecentDecl())); + First = PrevDecl->getFirstDeclaration(); + assert(First->RedeclLink.NextIsLatest() && "Expected first"); + } else { + // Make this first. + First = static_cast<decl_type*>(this); + } + + // First one will point to this one as latest. + First->RedeclLink = LatestDeclLink(static_cast<decl_type*>(this)); + if (NamedDecl *ND = dyn_cast<NamedDecl>(static_cast<decl_type*>(this))) + ND->ClearLinkageCache(); +} + +// Inline function definitions. + +/// \brief Check if the given decl is complete. +/// +/// We use this function to break a cycle between the inline definitions in +/// Type.h and Decl.h. +inline bool IsEnumDeclComplete(EnumDecl *ED) { + return ED->isComplete(); +} + +/// \brief Check if the given decl is scoped. +/// +/// We use this function to break a cycle between the inline definitions in +/// Type.h and Decl.h. +inline bool IsEnumDeclScoped(EnumDecl *ED) { + return ED->isScoped(); +} + +} // end namespace clang + +#endif diff --git a/clang/include/clang/AST/DeclAccessPair.h b/clang/include/clang/AST/DeclAccessPair.h new file mode 100644 index 0000000..7ecd8f8 --- /dev/null +++ b/clang/include/clang/AST/DeclAccessPair.h @@ -0,0 +1,72 @@ +//===--- DeclAccessPair.h - A decl bundled with its path access -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the DeclAccessPair class, which provides an +// efficient representation of a pair of a NamedDecl* and an +// AccessSpecifier. Generally the access specifier gives the +// natural access of a declaration when named in a class, as +// defined in C++ [class.access.base]p1. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_DECLACCESSPAIR_H +#define LLVM_CLANG_AST_DECLACCESSPAIR_H + +#include "clang/Basic/Specifiers.h" + +namespace clang { + +class NamedDecl; + +/// A POD class for pairing a NamedDecl* with an access specifier. +/// Can be put into unions. +class DeclAccessPair { + NamedDecl *Ptr; // we'd use llvm::PointerUnion, but it isn't trivial + + enum { Mask = 0x3 }; + +public: + static DeclAccessPair make(NamedDecl *D, AccessSpecifier AS) { + DeclAccessPair p; + p.set(D, AS); + return p; + } + + NamedDecl *getDecl() const { + return (NamedDecl*) (~Mask & (uintptr_t) Ptr); + } + AccessSpecifier getAccess() const { + return AccessSpecifier(Mask & (uintptr_t) Ptr); + } + + void setDecl(NamedDecl *D) { + set(D, getAccess()); + } + void setAccess(AccessSpecifier AS) { + set(getDecl(), AS); + } + void set(NamedDecl *D, AccessSpecifier AS) { + Ptr = reinterpret_cast<NamedDecl*>(uintptr_t(AS) | + reinterpret_cast<uintptr_t>(D)); + } + + operator NamedDecl*() const { return getDecl(); } + NamedDecl *operator->() const { return getDecl(); } +}; +} + +// Take a moment to tell SmallVector that DeclAccessPair is POD. +namespace llvm { +template<typename> struct isPodLike; +template<> struct isPodLike<clang::DeclAccessPair> { + static const bool value = true; +}; +} + +#endif diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h new file mode 100644 index 0000000..2232891 --- /dev/null +++ b/clang/include/clang/AST/DeclBase.h @@ -0,0 +1,1636 @@ +//===-- DeclBase.h - Base Classes for representing declarations -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Decl and DeclContext interfaces. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_DECLBASE_H +#define LLVM_CLANG_AST_DECLBASE_H + +#include "clang/AST/Attr.h" +#include "clang/AST/Type.h" +#include "clang/Basic/Specifiers.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/PrettyStackTrace.h" + +namespace clang { +class DeclContext; +class TranslationUnitDecl; +class NamespaceDecl; +class UsingDirectiveDecl; +class NamedDecl; +class FunctionDecl; +class CXXRecordDecl; +class EnumDecl; +class ObjCMethodDecl; +class ObjCContainerDecl; +class ObjCInterfaceDecl; +class ObjCCategoryDecl; +class ObjCProtocolDecl; +class ObjCImplementationDecl; +class ObjCCategoryImplDecl; +class ObjCImplDecl; +class LinkageSpecDecl; +class BlockDecl; +class DeclarationName; +class CompoundStmt; +class StoredDeclsMap; +class DependentDiagnostic; +class ASTMutationListener; +} + +namespace llvm { +// DeclContext* is only 4-byte aligned on 32-bit systems. +template<> + class PointerLikeTypeTraits<clang::DeclContext*> { + typedef clang::DeclContext* PT; +public: + static inline void *getAsVoidPointer(PT P) { return P; } + static inline PT getFromVoidPointer(void *P) { + return static_cast<PT>(P); + } + enum { NumLowBitsAvailable = 2 }; +}; +} + +namespace clang { + + /// \brief Captures the result of checking the availability of a + /// declaration. + enum AvailabilityResult { + AR_Available = 0, + AR_NotYetIntroduced, + AR_Deprecated, + AR_Unavailable + }; + +/// Decl - This represents one declaration (or definition), e.g. a variable, +/// typedef, function, struct, etc. +/// +class Decl { +public: + /// \brief Lists the kind of concrete classes of Decl. + enum Kind { +#define DECL(DERIVED, BASE) DERIVED, +#define ABSTRACT_DECL(DECL) +#define DECL_RANGE(BASE, START, END) \ + first##BASE = START, last##BASE = END, +#define LAST_DECL_RANGE(BASE, START, END) \ + first##BASE = START, last##BASE = END +#include "clang/AST/DeclNodes.inc" + }; + + /// \brief A placeholder type used to construct an empty shell of a + /// decl-derived type that will be filled in later (e.g., by some + /// deserialization method). + struct EmptyShell { }; + + /// IdentifierNamespace - The different namespaces in which + /// declarations may appear. According to C99 6.2.3, there are + /// four namespaces, labels, tags, members and ordinary + /// identifiers. C++ describes lookup completely differently: + /// certain lookups merely "ignore" certain kinds of declarations, + /// usually based on whether the declaration is of a type, etc. + /// + /// These are meant as bitmasks, so that searches in + /// C++ can look into the "tag" namespace during ordinary lookup. + /// + /// Decl currently provides 15 bits of IDNS bits. + enum IdentifierNamespace { + /// Labels, declared with 'x:' and referenced with 'goto x'. + IDNS_Label = 0x0001, + + /// Tags, declared with 'struct foo;' and referenced with + /// 'struct foo'. All tags are also types. This is what + /// elaborated-type-specifiers look for in C. + IDNS_Tag = 0x0002, + + /// Types, declared with 'struct foo', typedefs, etc. + /// This is what elaborated-type-specifiers look for in C++, + /// but note that it's ill-formed to find a non-tag. + IDNS_Type = 0x0004, + + /// Members, declared with object declarations within tag + /// definitions. In C, these can only be found by "qualified" + /// lookup in member expressions. In C++, they're found by + /// normal lookup. + IDNS_Member = 0x0008, + + /// Namespaces, declared with 'namespace foo {}'. + /// Lookup for nested-name-specifiers find these. + IDNS_Namespace = 0x0010, + + /// Ordinary names. In C, everything that's not a label, tag, + /// or member ends up here. + IDNS_Ordinary = 0x0020, + + /// Objective C @protocol. + IDNS_ObjCProtocol = 0x0040, + + /// This declaration is a friend function. A friend function + /// declaration is always in this namespace but may also be in + /// IDNS_Ordinary if it was previously declared. + IDNS_OrdinaryFriend = 0x0080, + + /// This declaration is a friend class. A friend class + /// declaration is always in this namespace but may also be in + /// IDNS_Tag|IDNS_Type if it was previously declared. + IDNS_TagFriend = 0x0100, + + /// This declaration is a using declaration. A using declaration + /// *introduces* a number of other declarations into the current + /// scope, and those declarations use the IDNS of their targets, + /// but the actual using declarations go in this namespace. + IDNS_Using = 0x0200, + + /// This declaration is a C++ operator declared in a non-class + /// context. All such operators are also in IDNS_Ordinary. + /// C++ lexical operator lookup looks for these. + IDNS_NonMemberOperator = 0x0400 + }; + + /// ObjCDeclQualifier - 'Qualifiers' written next to the return and + /// parameter types in method declarations. Other than remembering + /// them and mangling them into the method's signature string, these + /// are ignored by the compiler; they are consumed by certain + /// remote-messaging frameworks. + /// + /// in, inout, and out are mutually exclusive and apply only to + /// method parameters. bycopy and byref are mutually exclusive and + /// apply only to method parameters (?). oneway applies only to + /// results. All of these expect their corresponding parameter to + /// have a particular type. None of this is currently enforced by + /// clang. + /// + /// This should be kept in sync with ObjCDeclSpec::ObjCDeclQualifier. + enum ObjCDeclQualifier { + OBJC_TQ_None = 0x0, + OBJC_TQ_In = 0x1, + OBJC_TQ_Inout = 0x2, + OBJC_TQ_Out = 0x4, + OBJC_TQ_Bycopy = 0x8, + OBJC_TQ_Byref = 0x10, + OBJC_TQ_Oneway = 0x20 + }; + +protected: + // Enumeration values used in the bits stored in NextInContextAndBits. + enum { + /// \brief Whether this declaration is a top-level declaration (function, + /// global variable, etc.) that is lexically inside an objc container + /// definition. + TopLevelDeclInObjCContainerFlag = 0x01, + + /// \brief Whether this declaration is private to the module in which it was + /// defined. + ModulePrivateFlag = 0x02 + }; + + /// \brief The next declaration within the same lexical + /// DeclContext. These pointers form the linked list that is + /// traversed via DeclContext's decls_begin()/decls_end(). + /// + /// The extra two bits are used for the TopLevelDeclInObjCContainer and + /// ModulePrivate bits. + llvm::PointerIntPair<Decl *, 2, unsigned> NextInContextAndBits; + +private: + friend class DeclContext; + + struct MultipleDC { + DeclContext *SemanticDC; + DeclContext *LexicalDC; + }; + + + /// DeclCtx - Holds either a DeclContext* or a MultipleDC*. + /// For declarations that don't contain C++ scope specifiers, it contains + /// the DeclContext where the Decl was declared. + /// For declarations with C++ scope specifiers, it contains a MultipleDC* + /// with the context where it semantically belongs (SemanticDC) and the + /// context where it was lexically declared (LexicalDC). + /// e.g.: + /// + /// namespace A { + /// void f(); // SemanticDC == LexicalDC == 'namespace A' + /// } + /// void A::f(); // SemanticDC == namespace 'A' + /// // LexicalDC == global namespace + llvm::PointerUnion<DeclContext*, MultipleDC*> DeclCtx; + + inline bool isInSemaDC() const { return DeclCtx.is<DeclContext*>(); } + inline bool isOutOfSemaDC() const { return DeclCtx.is<MultipleDC*>(); } + inline MultipleDC *getMultipleDC() const { + return DeclCtx.get<MultipleDC*>(); + } + inline DeclContext *getSemanticDC() const { + return DeclCtx.get<DeclContext*>(); + } + + /// Loc - The location of this decl. + SourceLocation Loc; + + /// DeclKind - This indicates which class this is. + unsigned DeclKind : 8; + + /// InvalidDecl - This indicates a semantic error occurred. + unsigned InvalidDecl : 1; + + /// HasAttrs - This indicates whether the decl has attributes or not. + unsigned HasAttrs : 1; + + /// Implicit - Whether this declaration was implicitly generated by + /// the implementation rather than explicitly written by the user. + unsigned Implicit : 1; + + /// \brief Whether this declaration was "used", meaning that a definition is + /// required. + unsigned Used : 1; + + /// \brief Whether this declaration was "referenced". + /// The difference with 'Used' is whether the reference appears in a + /// evaluated context or not, e.g. functions used in uninstantiated templates + /// are regarded as "referenced" but not "used". + unsigned Referenced : 1; + + /// \brief Whether statistic collection is enabled. + static bool StatisticsEnabled; + +protected: + /// Access - Used by C++ decls for the access specifier. + // NOTE: VC++ treats enums as signed, avoid using the AccessSpecifier enum + unsigned Access : 2; + friend class CXXClassMemberWrapper; + + /// \brief Whether this declaration was loaded from an AST file. + unsigned FromASTFile : 1; + + /// \brief Whether this declaration is hidden from normal name lookup, e.g., + /// because it is was loaded from an AST file is either module-private or + /// because its submodule has not been made visible. + unsigned Hidden : 1; + + /// IdentifierNamespace - This specifies what IDNS_* namespace this lives in. + unsigned IdentifierNamespace : 12; + + /// \brief Whether the \c CachedLinkage field is active. + /// + /// This field is only valid for NamedDecls subclasses. + mutable unsigned HasCachedLinkage : 1; + + /// \brief If \c HasCachedLinkage, the linkage of this declaration. + /// + /// This field is only valid for NamedDecls subclasses. + mutable unsigned CachedLinkage : 2; + + friend class ASTDeclWriter; + friend class ASTDeclReader; + friend class ASTReader; + +private: + void CheckAccessDeclContext() const; + +protected: + + Decl(Kind DK, DeclContext *DC, SourceLocation L) + : NextInContextAndBits(), DeclCtx(DC), + Loc(L), DeclKind(DK), InvalidDecl(0), + HasAttrs(false), Implicit(false), Used(false), Referenced(false), + Access(AS_none), FromASTFile(0), Hidden(0), + IdentifierNamespace(getIdentifierNamespaceForKind(DK)), + HasCachedLinkage(0) + { + if (StatisticsEnabled) add(DK); + } + + Decl(Kind DK, EmptyShell Empty) + : NextInContextAndBits(), DeclKind(DK), InvalidDecl(0), + HasAttrs(false), Implicit(false), Used(false), Referenced(false), + Access(AS_none), FromASTFile(0), Hidden(0), + IdentifierNamespace(getIdentifierNamespaceForKind(DK)), + HasCachedLinkage(0) + { + if (StatisticsEnabled) add(DK); + } + + virtual ~Decl(); + + /// \brief Allocate memory for a deserialized declaration. + /// + /// This routine must be used to allocate memory for any declaration that is + /// deserialized from a module file. + /// + /// \param Context The context in which we will allocate memory. + /// \param ID The global ID of the deserialized declaration. + /// \param Size The size of the allocated object. + static void *AllocateDeserializedDecl(const ASTContext &Context, + unsigned ID, + unsigned Size); + +public: + + /// \brief Source range that this declaration covers. + virtual SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(getLocation(), getLocation()); + } + SourceLocation getLocStart() const LLVM_READONLY { + return getSourceRange().getBegin(); + } + SourceLocation getLocEnd() const LLVM_READONLY { + return getSourceRange().getEnd(); + } + + SourceLocation getLocation() const { return Loc; } + void setLocation(SourceLocation L) { Loc = L; } + + Kind getKind() const { return static_cast<Kind>(DeclKind); } + const char *getDeclKindName() const; + + Decl *getNextDeclInContext() { return NextInContextAndBits.getPointer(); } + const Decl *getNextDeclInContext() const {return NextInContextAndBits.getPointer();} + + DeclContext *getDeclContext() { + if (isInSemaDC()) + return getSemanticDC(); + return getMultipleDC()->SemanticDC; + } + const DeclContext *getDeclContext() const { + return const_cast<Decl*>(this)->getDeclContext(); + } + + /// Finds the innermost non-closure context of this declaration. + /// That is, walk out the DeclContext chain, skipping any blocks. + DeclContext *getNonClosureContext(); + const DeclContext *getNonClosureContext() const { + return const_cast<Decl*>(this)->getNonClosureContext(); + } + + TranslationUnitDecl *getTranslationUnitDecl(); + const TranslationUnitDecl *getTranslationUnitDecl() const { + return const_cast<Decl*>(this)->getTranslationUnitDecl(); + } + + bool isInAnonymousNamespace() const; + + ASTContext &getASTContext() const LLVM_READONLY; + + void setAccess(AccessSpecifier AS) { + Access = AS; +#ifndef NDEBUG + CheckAccessDeclContext(); +#endif + } + + AccessSpecifier getAccess() const { +#ifndef NDEBUG + CheckAccessDeclContext(); +#endif + return AccessSpecifier(Access); + } + + bool hasAttrs() const { return HasAttrs; } + void setAttrs(const AttrVec& Attrs) { + return setAttrsImpl(Attrs, getASTContext()); + } + AttrVec &getAttrs() { + return const_cast<AttrVec&>(const_cast<const Decl*>(this)->getAttrs()); + } + const AttrVec &getAttrs() const; + void swapAttrs(Decl *D); + void dropAttrs(); + + void addAttr(Attr *A) { + if (hasAttrs()) + getAttrs().push_back(A); + else + setAttrs(AttrVec(1, A)); + } + + typedef AttrVec::const_iterator attr_iterator; + + // FIXME: Do not rely on iterators having comparable singular values. + // Note that this should error out if they do not. + attr_iterator attr_begin() const { + return hasAttrs() ? getAttrs().begin() : 0; + } + attr_iterator attr_end() const { + return hasAttrs() ? getAttrs().end() : 0; + } + + template <typename T> + void dropAttr() { + if (!HasAttrs) return; + + AttrVec &Attrs = getAttrs(); + for (unsigned i = 0, e = Attrs.size(); i != e; /* in loop */) { + if (isa<T>(Attrs[i])) { + Attrs.erase(Attrs.begin() + i); + --e; + } + else + ++i; + } + if (Attrs.empty()) + HasAttrs = false; + } + + template <typename T> + specific_attr_iterator<T> specific_attr_begin() const { + return specific_attr_iterator<T>(attr_begin()); + } + template <typename T> + specific_attr_iterator<T> specific_attr_end() const { + return specific_attr_iterator<T>(attr_end()); + } + + template<typename T> T *getAttr() const { + return hasAttrs() ? getSpecificAttr<T>(getAttrs()) : 0; + } + template<typename T> bool hasAttr() const { + return hasAttrs() && hasSpecificAttr<T>(getAttrs()); + } + + /// getMaxAlignment - return the maximum alignment specified by attributes + /// on this decl, 0 if there are none. + unsigned getMaxAlignment() const { + return hasAttrs() ? getMaxAttrAlignment(getAttrs(), getASTContext()) : 0; + } + + /// setInvalidDecl - Indicates the Decl had a semantic error. This + /// allows for graceful error recovery. + void setInvalidDecl(bool Invalid = true); + bool isInvalidDecl() const { return (bool) InvalidDecl; } + + /// isImplicit - Indicates whether the declaration was implicitly + /// generated by the implementation. If false, this declaration + /// was written explicitly in the source code. + bool isImplicit() const { return Implicit; } + void setImplicit(bool I = true) { Implicit = I; } + + /// \brief Whether this declaration was used, meaning that a definition + /// is required. + /// + /// \param CheckUsedAttr When true, also consider the "used" attribute + /// (in addition to the "used" bit set by \c setUsed()) when determining + /// whether the function is used. + bool isUsed(bool CheckUsedAttr = true) const; + + void setUsed(bool U = true) { Used = U; } + + /// \brief Whether this declaration was referenced. + bool isReferenced() const; + + void setReferenced(bool R = true) { Referenced = R; } + + /// \brief Whether this declaration is a top-level declaration (function, + /// global variable, etc.) that is lexically inside an objc container + /// definition. + bool isTopLevelDeclInObjCContainer() const { + return NextInContextAndBits.getInt() & TopLevelDeclInObjCContainerFlag; + } + + void setTopLevelDeclInObjCContainer(bool V = true) { + unsigned Bits = NextInContextAndBits.getInt(); + if (V) + Bits |= TopLevelDeclInObjCContainerFlag; + else + Bits &= ~TopLevelDeclInObjCContainerFlag; + NextInContextAndBits.setInt(Bits); + } + +protected: + /// \brief Whether this declaration was marked as being private to the + /// module in which it was defined. + bool isModulePrivate() const { + return NextInContextAndBits.getInt() & ModulePrivateFlag; + } + + /// \brief Specify whether this declaration was marked as being private + /// to the module in which it was defined. + void setModulePrivate(bool MP = true) { + unsigned Bits = NextInContextAndBits.getInt(); + if (MP) + Bits |= ModulePrivateFlag; + else + Bits &= ~ModulePrivateFlag; + NextInContextAndBits.setInt(Bits); + } + + /// \brief Set the owning module ID. + void setOwningModuleID(unsigned ID) { + assert(isFromASTFile() && "Only works on a deserialized declaration"); + *((unsigned*)this - 2) = ID; + } + +public: + + /// \brief Determine the availability of the given declaration. + /// + /// This routine will determine the most restrictive availability of + /// the given declaration (e.g., preferring 'unavailable' to + /// 'deprecated'). + /// + /// \param Message If non-NULL and the result is not \c + /// AR_Available, will be set to a (possibly empty) message + /// describing why the declaration has not been introduced, is + /// deprecated, or is unavailable. + AvailabilityResult getAvailability(std::string *Message = 0) const; + + /// \brief Determine whether this declaration is marked 'deprecated'. + /// + /// \param Message If non-NULL and the declaration is deprecated, + /// this will be set to the message describing why the declaration + /// was deprecated (which may be empty). + bool isDeprecated(std::string *Message = 0) const { + return getAvailability(Message) == AR_Deprecated; + } + + /// \brief Determine whether this declaration is marked 'unavailable'. + /// + /// \param Message If non-NULL and the declaration is unavailable, + /// this will be set to the message describing why the declaration + /// was made unavailable (which may be empty). + bool isUnavailable(std::string *Message = 0) const { + return getAvailability(Message) == AR_Unavailable; + } + + /// \brief Determine whether this is a weak-imported symbol. + /// + /// Weak-imported symbols are typically marked with the + /// 'weak_import' attribute, but may also be marked with an + /// 'availability' attribute where we're targing a platform prior to + /// the introduction of this feature. + bool isWeakImported() const; + + /// \brief Determines whether this symbol can be weak-imported, + /// e.g., whether it would be well-formed to add the weak_import + /// attribute. + /// + /// \param IsDefinition Set to \c true to indicate that this + /// declaration cannot be weak-imported because it has a definition. + bool canBeWeakImported(bool &IsDefinition) const; + + /// \brief Determine whether this declaration came from an AST file (such as + /// a precompiled header or module) rather than having been parsed. + bool isFromASTFile() const { return FromASTFile; } + + /// \brief Retrieve the global declaration ID associated with this + /// declaration, which specifies where in the + unsigned getGlobalID() const { + if (isFromASTFile()) + return *((const unsigned*)this - 1); + return 0; + } + + /// \brief Retrieve the global ID of the module that owns this particular + /// declaration. + unsigned getOwningModuleID() const { + if (isFromASTFile()) + return *((const unsigned*)this - 2); + + return 0; + } + + unsigned getIdentifierNamespace() const { + return IdentifierNamespace; + } + bool isInIdentifierNamespace(unsigned NS) const { + return getIdentifierNamespace() & NS; + } + static unsigned getIdentifierNamespaceForKind(Kind DK); + + bool hasTagIdentifierNamespace() const { + return isTagIdentifierNamespace(getIdentifierNamespace()); + } + static bool isTagIdentifierNamespace(unsigned NS) { + // TagDecls have Tag and Type set and may also have TagFriend. + return (NS & ~IDNS_TagFriend) == (IDNS_Tag | IDNS_Type); + } + + /// getLexicalDeclContext - The declaration context where this Decl was + /// lexically declared (LexicalDC). May be different from + /// getDeclContext() (SemanticDC). + /// e.g.: + /// + /// namespace A { + /// void f(); // SemanticDC == LexicalDC == 'namespace A' + /// } + /// void A::f(); // SemanticDC == namespace 'A' + /// // LexicalDC == global namespace + DeclContext *getLexicalDeclContext() { + if (isInSemaDC()) + return getSemanticDC(); + return getMultipleDC()->LexicalDC; + } + const DeclContext *getLexicalDeclContext() const { + return const_cast<Decl*>(this)->getLexicalDeclContext(); + } + + virtual bool isOutOfLine() const { + return getLexicalDeclContext() != getDeclContext(); + } + + /// setDeclContext - Set both the semantic and lexical DeclContext + /// to DC. + void setDeclContext(DeclContext *DC); + + void setLexicalDeclContext(DeclContext *DC); + + /// isDefinedOutsideFunctionOrMethod - This predicate returns true if this + /// scoped decl is defined outside the current function or method. This is + /// roughly global variables and functions, but also handles enums (which + /// could be defined inside or outside a function etc). + bool isDefinedOutsideFunctionOrMethod() const { + return getParentFunctionOrMethod() == 0; + } + + /// \brief If this decl is defined inside a function/method/block it returns + /// the corresponding DeclContext, otherwise it returns null. + const DeclContext *getParentFunctionOrMethod() const; + DeclContext *getParentFunctionOrMethod() { + return const_cast<DeclContext*>( + const_cast<const Decl*>(this)->getParentFunctionOrMethod()); + } + + /// \brief Retrieves the "canonical" declaration of the given declaration. + virtual Decl *getCanonicalDecl() { return this; } + const Decl *getCanonicalDecl() const { + return const_cast<Decl*>(this)->getCanonicalDecl(); + } + + /// \brief Whether this particular Decl is a canonical one. + bool isCanonicalDecl() const { return getCanonicalDecl() == this; } + +protected: + /// \brief Returns the next redeclaration or itself if this is the only decl. + /// + /// Decl subclasses that can be redeclared should override this method so that + /// Decl::redecl_iterator can iterate over them. + virtual Decl *getNextRedeclaration() { return this; } + + /// \brief Implementation of getPreviousDecl(), to be overridden by any + /// subclass that has a redeclaration chain. + virtual Decl *getPreviousDeclImpl() { return 0; } + + /// \brief Implementation of getMostRecentDecl(), to be overridden by any + /// subclass that has a redeclaration chain. + virtual Decl *getMostRecentDeclImpl() { return this; } + +public: + /// \brief Iterates through all the redeclarations of the same decl. + class redecl_iterator { + /// Current - The current declaration. + Decl *Current; + Decl *Starter; + + public: + typedef Decl* value_type; + typedef Decl* reference; + typedef Decl* pointer; + typedef std::forward_iterator_tag iterator_category; + typedef std::ptrdiff_t difference_type; + + redecl_iterator() : Current(0) { } + explicit redecl_iterator(Decl *C) : Current(C), Starter(C) { } + + reference operator*() const { return Current; } + pointer operator->() const { return Current; } + + redecl_iterator& operator++() { + assert(Current && "Advancing while iterator has reached end"); + // Get either previous decl or latest decl. + Decl *Next = Current->getNextRedeclaration(); + assert(Next && "Should return next redeclaration or itself, never null!"); + Current = (Next != Starter ? Next : 0); + return *this; + } + + redecl_iterator operator++(int) { + redecl_iterator tmp(*this); + ++(*this); + return tmp; + } + + friend bool operator==(redecl_iterator x, redecl_iterator y) { + return x.Current == y.Current; + } + friend bool operator!=(redecl_iterator x, redecl_iterator y) { + return x.Current != y.Current; + } + }; + + /// \brief Returns iterator for all the redeclarations of the same decl. + /// It will iterate at least once (when this decl is the only one). + redecl_iterator redecls_begin() const { + return redecl_iterator(const_cast<Decl*>(this)); + } + redecl_iterator redecls_end() const { return redecl_iterator(); } + + /// \brief Retrieve the previous declaration that declares the same entity + /// as this declaration, or NULL if there is no previous declaration. + Decl *getPreviousDecl() { return getPreviousDeclImpl(); } + + /// \brief Retrieve the most recent declaration that declares the same entity + /// as this declaration, or NULL if there is no previous declaration. + const Decl *getPreviousDecl() const { + return const_cast<Decl *>(this)->getPreviousDeclImpl(); + } + + /// \brief Retrieve the most recent declaration that declares the same entity + /// as this declaration (which may be this declaration). + Decl *getMostRecentDecl() { return getMostRecentDeclImpl(); } + + /// \brief Retrieve the most recent declaration that declares the same entity + /// as this declaration (which may be this declaration). + const Decl *getMostRecentDecl() const { + return const_cast<Decl *>(this)->getMostRecentDeclImpl(); + } + + /// getBody - If this Decl represents a declaration for a body of code, + /// such as a function or method definition, this method returns the + /// top-level Stmt* of that body. Otherwise this method returns null. + virtual Stmt* getBody() const { return 0; } + + /// \brief Returns true if this Decl represents a declaration for a body of + /// code, such as a function or method definition. + virtual bool hasBody() const { return getBody() != 0; } + + /// getBodyRBrace - Gets the right brace of the body, if a body exists. + /// This works whether the body is a CompoundStmt or a CXXTryStmt. + SourceLocation getBodyRBrace() const; + + // global temp stats (until we have a per-module visitor) + static void add(Kind k); + static void EnableStatistics(); + static void PrintStats(); + + /// isTemplateParameter - Determines whether this declaration is a + /// template parameter. + bool isTemplateParameter() const; + + /// isTemplateParameter - Determines whether this declaration is a + /// template parameter pack. + bool isTemplateParameterPack() const; + + /// \brief Whether this declaration is a parameter pack. + bool isParameterPack() const; + + /// \brief returns true if this declaration is a template + bool isTemplateDecl() const; + + /// \brief Whether this declaration is a function or function template. + bool isFunctionOrFunctionTemplate() const; + + /// \brief Changes the namespace of this declaration to reflect that it's + /// the object of a friend declaration. + /// + /// These declarations appear in the lexical context of the friending + /// class, but in the semantic context of the actual entity. This property + /// applies only to a specific decl object; other redeclarations of the + /// same entity may not (and probably don't) share this property. + void setObjectOfFriendDecl(bool PreviouslyDeclared) { + unsigned OldNS = IdentifierNamespace; + assert((OldNS & (IDNS_Tag | IDNS_Ordinary | + IDNS_TagFriend | IDNS_OrdinaryFriend)) && + "namespace includes neither ordinary nor tag"); + assert(!(OldNS & ~(IDNS_Tag | IDNS_Ordinary | IDNS_Type | + IDNS_TagFriend | IDNS_OrdinaryFriend)) && + "namespace includes other than ordinary or tag"); + + IdentifierNamespace = 0; + if (OldNS & (IDNS_Tag | IDNS_TagFriend)) { + IdentifierNamespace |= IDNS_TagFriend; + if (PreviouslyDeclared) IdentifierNamespace |= IDNS_Tag | IDNS_Type; + } + + if (OldNS & (IDNS_Ordinary | IDNS_OrdinaryFriend)) { + IdentifierNamespace |= IDNS_OrdinaryFriend; + if (PreviouslyDeclared) IdentifierNamespace |= IDNS_Ordinary; + } + } + + enum FriendObjectKind { + FOK_None, // not a friend object + FOK_Declared, // a friend of a previously-declared entity + FOK_Undeclared // a friend of a previously-undeclared entity + }; + + /// \brief Determines whether this declaration is the object of a + /// friend declaration and, if so, what kind. + /// + /// There is currently no direct way to find the associated FriendDecl. + FriendObjectKind getFriendObjectKind() const { + unsigned mask + = (IdentifierNamespace & (IDNS_TagFriend | IDNS_OrdinaryFriend)); + if (!mask) return FOK_None; + return (IdentifierNamespace & (IDNS_Tag | IDNS_Ordinary) ? + FOK_Declared : FOK_Undeclared); + } + + /// Specifies that this declaration is a C++ overloaded non-member. + void setNonMemberOperator() { + assert(getKind() == Function || getKind() == FunctionTemplate); + assert((IdentifierNamespace & IDNS_Ordinary) && + "visible non-member operators should be in ordinary namespace"); + IdentifierNamespace |= IDNS_NonMemberOperator; + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *) { return true; } + static bool classofKind(Kind K) { return true; } + static DeclContext *castToDeclContext(const Decl *); + static Decl *castFromDeclContext(const DeclContext *); + + void print(raw_ostream &Out, unsigned Indentation = 0, + bool PrintInstantiation = false) const; + void print(raw_ostream &Out, const PrintingPolicy &Policy, + unsigned Indentation = 0, bool PrintInstantiation = false) const; + static void printGroup(Decl** Begin, unsigned NumDecls, + raw_ostream &Out, const PrintingPolicy &Policy, + unsigned Indentation = 0); + LLVM_ATTRIBUTE_USED void dump() const; + LLVM_ATTRIBUTE_USED void dumpXML() const; + void dumpXML(raw_ostream &OS) const; + +private: + void setAttrsImpl(const AttrVec& Attrs, ASTContext &Ctx); + void setDeclContextsImpl(DeclContext *SemaDC, DeclContext *LexicalDC, + ASTContext &Ctx); + +protected: + ASTMutationListener *getASTMutationListener() const; +}; + +/// \brief Determine whether two declarations declare the same entity. +inline bool declaresSameEntity(const Decl *D1, const Decl *D2) { + if (!D1 || !D2) + return false; + + if (D1 == D2) + return true; + + return D1->getCanonicalDecl() == D2->getCanonicalDecl(); +} + +/// PrettyStackTraceDecl - If a crash occurs, indicate that it happened when +/// doing something to a specific decl. +class PrettyStackTraceDecl : public llvm::PrettyStackTraceEntry { + const Decl *TheDecl; + SourceLocation Loc; + SourceManager &SM; + const char *Message; +public: + PrettyStackTraceDecl(const Decl *theDecl, SourceLocation L, + SourceManager &sm, const char *Msg) + : TheDecl(theDecl), Loc(L), SM(sm), Message(Msg) {} + + virtual void print(raw_ostream &OS) const; +}; + +class DeclContextLookupResult + : public std::pair<NamedDecl**,NamedDecl**> { +public: + DeclContextLookupResult(NamedDecl **I, NamedDecl **E) + : std::pair<NamedDecl**,NamedDecl**>(I, E) {} + DeclContextLookupResult() + : std::pair<NamedDecl**,NamedDecl**>() {} + + using std::pair<NamedDecl**,NamedDecl**>::operator=; +}; + +class DeclContextLookupConstResult + : public std::pair<NamedDecl*const*, NamedDecl*const*> { +public: + DeclContextLookupConstResult(std::pair<NamedDecl**,NamedDecl**> R) + : std::pair<NamedDecl*const*, NamedDecl*const*>(R) {} + DeclContextLookupConstResult(NamedDecl * const *I, NamedDecl * const *E) + : std::pair<NamedDecl*const*, NamedDecl*const*>(I, E) {} + DeclContextLookupConstResult() + : std::pair<NamedDecl*const*, NamedDecl*const*>() {} + + using std::pair<NamedDecl*const*,NamedDecl*const*>::operator=; +}; + +/// DeclContext - This is used only as base class of specific decl types that +/// can act as declaration contexts. These decls are (only the top classes +/// that directly derive from DeclContext are mentioned, not their subclasses): +/// +/// TranslationUnitDecl +/// NamespaceDecl +/// FunctionDecl +/// TagDecl +/// ObjCMethodDecl +/// ObjCContainerDecl +/// LinkageSpecDecl +/// BlockDecl +/// +class DeclContext { + /// DeclKind - This indicates which class this is. + unsigned DeclKind : 8; + + /// \brief Whether this declaration context also has some external + /// storage that contains additional declarations that are lexically + /// part of this context. + mutable unsigned ExternalLexicalStorage : 1; + + /// \brief Whether this declaration context also has some external + /// storage that contains additional declarations that are visible + /// in this context. + mutable unsigned ExternalVisibleStorage : 1; + + /// \brief Pointer to the data structure used to lookup declarations + /// within this context (or a DependentStoredDeclsMap if this is a + /// dependent context), and a bool indicating whether we have lazily + /// omitted any declarations from the map. We maintain the invariant + /// that, if the map contains an entry for a DeclarationName, then it + /// contains all relevant entries for that name. + mutable llvm::PointerIntPair<StoredDeclsMap*, 1, bool> LookupPtr; + +protected: + /// FirstDecl - The first declaration stored within this declaration + /// context. + mutable Decl *FirstDecl; + + /// LastDecl - The last declaration stored within this declaration + /// context. FIXME: We could probably cache this value somewhere + /// outside of the DeclContext, to reduce the size of DeclContext by + /// another pointer. + mutable Decl *LastDecl; + + friend class ExternalASTSource; + friend class ASTWriter; + + /// \brief Build up a chain of declarations. + /// + /// \returns the first/last pair of declarations. + static std::pair<Decl *, Decl *> + BuildDeclChain(ArrayRef<Decl*> Decls, bool FieldsAlreadyLoaded); + + DeclContext(Decl::Kind K) + : DeclKind(K), ExternalLexicalStorage(false), + ExternalVisibleStorage(false), LookupPtr(0, false), FirstDecl(0), + LastDecl(0) { } + +public: + ~DeclContext(); + + Decl::Kind getDeclKind() const { + return static_cast<Decl::Kind>(DeclKind); + } + const char *getDeclKindName() const; + + /// getParent - Returns the containing DeclContext. + DeclContext *getParent() { + return cast<Decl>(this)->getDeclContext(); + } + const DeclContext *getParent() const { + return const_cast<DeclContext*>(this)->getParent(); + } + + /// getLexicalParent - Returns the containing lexical DeclContext. May be + /// different from getParent, e.g.: + /// + /// namespace A { + /// struct S; + /// } + /// struct A::S {}; // getParent() == namespace 'A' + /// // getLexicalParent() == translation unit + /// + DeclContext *getLexicalParent() { + return cast<Decl>(this)->getLexicalDeclContext(); + } + const DeclContext *getLexicalParent() const { + return const_cast<DeclContext*>(this)->getLexicalParent(); + } + + DeclContext *getLookupParent(); + + const DeclContext *getLookupParent() const { + return const_cast<DeclContext*>(this)->getLookupParent(); + } + + ASTContext &getParentASTContext() const { + return cast<Decl>(this)->getASTContext(); + } + + bool isClosure() const { + return DeclKind == Decl::Block; + } + + bool isObjCContainer() const { + switch (DeclKind) { + case Decl::ObjCCategory: + case Decl::ObjCCategoryImpl: + case Decl::ObjCImplementation: + case Decl::ObjCInterface: + case Decl::ObjCProtocol: + return true; + } + return false; + } + + bool isFunctionOrMethod() const { + switch (DeclKind) { + case Decl::Block: + case Decl::ObjCMethod: + return true; + default: + return DeclKind >= Decl::firstFunction && DeclKind <= Decl::lastFunction; + } + } + + bool isFileContext() const { + return DeclKind == Decl::TranslationUnit || DeclKind == Decl::Namespace; + } + + bool isTranslationUnit() const { + return DeclKind == Decl::TranslationUnit; + } + + bool isRecord() const { + return DeclKind >= Decl::firstRecord && DeclKind <= Decl::lastRecord; + } + + bool isNamespace() const { + return DeclKind == Decl::Namespace; + } + + bool isInlineNamespace() const; + + /// \brief Determines whether this context is dependent on a + /// template parameter. + bool isDependentContext() const; + + /// isTransparentContext - Determines whether this context is a + /// "transparent" context, meaning that the members declared in this + /// context are semantically declared in the nearest enclosing + /// non-transparent (opaque) context but are lexically declared in + /// this context. For example, consider the enumerators of an + /// enumeration type: + /// @code + /// enum E { + /// Val1 + /// }; + /// @endcode + /// Here, E is a transparent context, so its enumerator (Val1) will + /// appear (semantically) that it is in the same context of E. + /// Examples of transparent contexts include: enumerations (except for + /// C++0x scoped enums), and C++ linkage specifications. + bool isTransparentContext() const; + + /// \brief Determines whether this context is, or is nested within, + /// a C++ extern "C" linkage spec. + bool isExternCContext() const; + + /// \brief Determine whether this declaration context is equivalent + /// to the declaration context DC. + bool Equals(const DeclContext *DC) const { + return DC && this->getPrimaryContext() == DC->getPrimaryContext(); + } + + /// \brief Determine whether this declaration context encloses the + /// declaration context DC. + bool Encloses(const DeclContext *DC) const; + + /// \brief Find the nearest non-closure ancestor of this context, + /// i.e. the innermost semantic parent of this context which is not + /// a closure. A context may be its own non-closure ancestor. + DeclContext *getNonClosureAncestor(); + const DeclContext *getNonClosureAncestor() const { + return const_cast<DeclContext*>(this)->getNonClosureAncestor(); + } + + /// getPrimaryContext - There may be many different + /// declarations of the same entity (including forward declarations + /// of classes, multiple definitions of namespaces, etc.), each with + /// a different set of declarations. This routine returns the + /// "primary" DeclContext structure, which will contain the + /// information needed to perform name lookup into this context. + DeclContext *getPrimaryContext(); + const DeclContext *getPrimaryContext() const { + return const_cast<DeclContext*>(this)->getPrimaryContext(); + } + + /// getRedeclContext - Retrieve the context in which an entity conflicts with + /// other entities of the same name, or where it is a redeclaration if the + /// two entities are compatible. This skips through transparent contexts. + DeclContext *getRedeclContext(); + const DeclContext *getRedeclContext() const { + return const_cast<DeclContext *>(this)->getRedeclContext(); + } + + /// \brief Retrieve the nearest enclosing namespace context. + DeclContext *getEnclosingNamespaceContext(); + const DeclContext *getEnclosingNamespaceContext() const { + return const_cast<DeclContext *>(this)->getEnclosingNamespaceContext(); + } + + /// \brief Test if this context is part of the enclosing namespace set of + /// the context NS, as defined in C++0x [namespace.def]p9. If either context + /// isn't a namespace, this is equivalent to Equals(). + /// + /// The enclosing namespace set of a namespace is the namespace and, if it is + /// inline, its enclosing namespace, recursively. + bool InEnclosingNamespaceSetOf(const DeclContext *NS) const; + + /// \\brief Collects all of the declaration contexts that are semantically + /// connected to this declaration context. + /// + /// For declaration contexts that have multiple semantically connected but + /// syntactically distinct contexts, such as C++ namespaces, this routine + /// retrieves the complete set of such declaration contexts in source order. + /// For example, given: + /// + /// \code + /// namespace N { + /// int x; + /// } + /// namespace N { + /// int y; + /// } + /// \endcode + /// + /// The \c Contexts parameter will contain both definitions of N. + /// + /// \param Contexts Will be cleared and set to the set of declaration + /// contexts that are semanticaly connected to this declaration context, + /// in source order, including this context (which may be the only result, + /// for non-namespace contexts). + void collectAllContexts(llvm::SmallVectorImpl<DeclContext *> &Contexts); + + /// decl_iterator - Iterates through the declarations stored + /// within this context. + class decl_iterator { + /// Current - The current declaration. + Decl *Current; + + public: + typedef Decl* value_type; + typedef Decl* reference; + typedef Decl* pointer; + typedef std::forward_iterator_tag iterator_category; + typedef std::ptrdiff_t difference_type; + + decl_iterator() : Current(0) { } + explicit decl_iterator(Decl *C) : Current(C) { } + + reference operator*() const { return Current; } + pointer operator->() const { return Current; } + + decl_iterator& operator++() { + Current = Current->getNextDeclInContext(); + return *this; + } + + decl_iterator operator++(int) { + decl_iterator tmp(*this); + ++(*this); + return tmp; + } + + friend bool operator==(decl_iterator x, decl_iterator y) { + return x.Current == y.Current; + } + friend bool operator!=(decl_iterator x, decl_iterator y) { + return x.Current != y.Current; + } + }; + + /// decls_begin/decls_end - Iterate over the declarations stored in + /// this context. + decl_iterator decls_begin() const; + decl_iterator decls_end() const; + bool decls_empty() const; + + /// noload_decls_begin/end - Iterate over the declarations stored in this + /// context that are currently loaded; don't attempt to retrieve anything + /// from an external source. + decl_iterator noload_decls_begin() const; + decl_iterator noload_decls_end() const; + + /// specific_decl_iterator - Iterates over a subrange of + /// declarations stored in a DeclContext, providing only those that + /// are of type SpecificDecl (or a class derived from it). This + /// iterator is used, for example, to provide iteration over just + /// the fields within a RecordDecl (with SpecificDecl = FieldDecl). + template<typename SpecificDecl> + class specific_decl_iterator { + /// Current - The current, underlying declaration iterator, which + /// will either be NULL or will point to a declaration of + /// type SpecificDecl. + DeclContext::decl_iterator Current; + + /// SkipToNextDecl - Advances the current position up to the next + /// declaration of type SpecificDecl that also meets the criteria + /// required by Acceptable. + void SkipToNextDecl() { + while (*Current && !isa<SpecificDecl>(*Current)) + ++Current; + } + + public: + typedef SpecificDecl* value_type; + typedef SpecificDecl* reference; + typedef SpecificDecl* pointer; + typedef std::iterator_traits<DeclContext::decl_iterator>::difference_type + difference_type; + typedef std::forward_iterator_tag iterator_category; + + specific_decl_iterator() : Current() { } + + /// specific_decl_iterator - Construct a new iterator over a + /// subset of the declarations the range [C, + /// end-of-declarations). If A is non-NULL, it is a pointer to a + /// member function of SpecificDecl that should return true for + /// all of the SpecificDecl instances that will be in the subset + /// of iterators. For example, if you want Objective-C instance + /// methods, SpecificDecl will be ObjCMethodDecl and A will be + /// &ObjCMethodDecl::isInstanceMethod. + explicit specific_decl_iterator(DeclContext::decl_iterator C) : Current(C) { + SkipToNextDecl(); + } + + reference operator*() const { return cast<SpecificDecl>(*Current); } + pointer operator->() const { return cast<SpecificDecl>(*Current); } + + specific_decl_iterator& operator++() { + ++Current; + SkipToNextDecl(); + return *this; + } + + specific_decl_iterator operator++(int) { + specific_decl_iterator tmp(*this); + ++(*this); + return tmp; + } + + friend bool operator==(const specific_decl_iterator& x, + const specific_decl_iterator& y) { + return x.Current == y.Current; + } + + friend bool operator!=(const specific_decl_iterator& x, + const specific_decl_iterator& y) { + return x.Current != y.Current; + } + }; + + /// \brief Iterates over a filtered subrange of declarations stored + /// in a DeclContext. + /// + /// This iterator visits only those declarations that are of type + /// SpecificDecl (or a class derived from it) and that meet some + /// additional run-time criteria. This iterator is used, for + /// example, to provide access to the instance methods within an + /// Objective-C interface (with SpecificDecl = ObjCMethodDecl and + /// Acceptable = ObjCMethodDecl::isInstanceMethod). + template<typename SpecificDecl, bool (SpecificDecl::*Acceptable)() const> + class filtered_decl_iterator { + /// Current - The current, underlying declaration iterator, which + /// will either be NULL or will point to a declaration of + /// type SpecificDecl. + DeclContext::decl_iterator Current; + + /// SkipToNextDecl - Advances the current position up to the next + /// declaration of type SpecificDecl that also meets the criteria + /// required by Acceptable. + void SkipToNextDecl() { + while (*Current && + (!isa<SpecificDecl>(*Current) || + (Acceptable && !(cast<SpecificDecl>(*Current)->*Acceptable)()))) + ++Current; + } + + public: + typedef SpecificDecl* value_type; + typedef SpecificDecl* reference; + typedef SpecificDecl* pointer; + typedef std::iterator_traits<DeclContext::decl_iterator>::difference_type + difference_type; + typedef std::forward_iterator_tag iterator_category; + + filtered_decl_iterator() : Current() { } + + /// specific_decl_iterator - Construct a new iterator over a + /// subset of the declarations the range [C, + /// end-of-declarations). If A is non-NULL, it is a pointer to a + /// member function of SpecificDecl that should return true for + /// all of the SpecificDecl instances that will be in the subset + /// of iterators. For example, if you want Objective-C instance + /// methods, SpecificDecl will be ObjCMethodDecl and A will be + /// &ObjCMethodDecl::isInstanceMethod. + explicit filtered_decl_iterator(DeclContext::decl_iterator C) : Current(C) { + SkipToNextDecl(); + } + + reference operator*() const { return cast<SpecificDecl>(*Current); } + pointer operator->() const { return cast<SpecificDecl>(*Current); } + + filtered_decl_iterator& operator++() { + ++Current; + SkipToNextDecl(); + return *this; + } + + filtered_decl_iterator operator++(int) { + filtered_decl_iterator tmp(*this); + ++(*this); + return tmp; + } + + friend bool operator==(const filtered_decl_iterator& x, + const filtered_decl_iterator& y) { + return x.Current == y.Current; + } + + friend bool operator!=(const filtered_decl_iterator& x, + const filtered_decl_iterator& y) { + return x.Current != y.Current; + } + }; + + /// @brief Add the declaration D into this context. + /// + /// This routine should be invoked when the declaration D has first + /// been declared, to place D into the context where it was + /// (lexically) defined. Every declaration must be added to one + /// (and only one!) context, where it can be visited via + /// [decls_begin(), decls_end()). Once a declaration has been added + /// to its lexical context, the corresponding DeclContext owns the + /// declaration. + /// + /// If D is also a NamedDecl, it will be made visible within its + /// semantic context via makeDeclVisibleInContext. + void addDecl(Decl *D); + + /// @brief Add the declaration D into this context, but suppress + /// searches for external declarations with the same name. + /// + /// Although analogous in function to addDecl, this removes an + /// important check. This is only useful if the Decl is being + /// added in response to an external search; in all other cases, + /// addDecl() is the right function to use. + /// See the ASTImporter for use cases. + void addDeclInternal(Decl *D); + + /// @brief Add the declaration D to this context without modifying + /// any lookup tables. + /// + /// This is useful for some operations in dependent contexts where + /// the semantic context might not be dependent; this basically + /// only happens with friends. + void addHiddenDecl(Decl *D); + + /// @brief Removes a declaration from this context. + void removeDecl(Decl *D); + + /// lookup_iterator - An iterator that provides access to the results + /// of looking up a name within this context. + typedef NamedDecl **lookup_iterator; + + /// lookup_const_iterator - An iterator that provides non-mutable + /// access to the results of lookup up a name within this context. + typedef NamedDecl * const * lookup_const_iterator; + + typedef DeclContextLookupResult lookup_result; + typedef DeclContextLookupConstResult lookup_const_result; + + /// lookup - Find the declarations (if any) with the given Name in + /// this context. Returns a range of iterators that contains all of + /// the declarations with this name, with object, function, member, + /// and enumerator names preceding any tag name. Note that this + /// routine will not look into parent contexts. + lookup_result lookup(DeclarationName Name); + lookup_const_result lookup(DeclarationName Name) const; + + /// \brief A simplistic name lookup mechanism that performs name lookup + /// into this declaration context without consulting the external source. + /// + /// This function should almost never be used, because it subverts the + /// usual relationship between a DeclContext and the external source. + /// See the ASTImporter for the (few, but important) use cases. + void localUncachedLookup(DeclarationName Name, + llvm::SmallVectorImpl<NamedDecl *> &Results); + + /// @brief Makes a declaration visible within this context. + /// + /// This routine makes the declaration D visible to name lookup + /// within this context and, if this is a transparent context, + /// within its parent contexts up to the first enclosing + /// non-transparent context. Making a declaration visible within a + /// context does not transfer ownership of a declaration, and a + /// declaration can be visible in many contexts that aren't its + /// lexical context. + /// + /// If D is a redeclaration of an existing declaration that is + /// visible from this context, as determined by + /// NamedDecl::declarationReplaces, the previous declaration will be + /// replaced with D. + void makeDeclVisibleInContext(NamedDecl *D); + + /// all_lookups_iterator - An iterator that provides a view over the results + /// of looking up every possible name. + class all_lookups_iterator; + + all_lookups_iterator lookups_begin() const; + + all_lookups_iterator lookups_end() const; + + /// udir_iterator - Iterates through the using-directives stored + /// within this context. + typedef UsingDirectiveDecl * const * udir_iterator; + + typedef std::pair<udir_iterator, udir_iterator> udir_iterator_range; + + udir_iterator_range getUsingDirectives() const; + + udir_iterator using_directives_begin() const { + return getUsingDirectives().first; + } + + udir_iterator using_directives_end() const { + return getUsingDirectives().second; + } + + // These are all defined in DependentDiagnostic.h. + class ddiag_iterator; + inline ddiag_iterator ddiag_begin() const; + inline ddiag_iterator ddiag_end() const; + + // Low-level accessors + + /// \brief Retrieve the internal representation of the lookup structure. + /// This may omit some names if we are lazily building the structure. + StoredDeclsMap *getLookupPtr() const { return LookupPtr.getPointer(); } + + /// \brief Ensure the lookup structure is fully-built and return it. + StoredDeclsMap *buildLookup(); + + /// \brief Whether this DeclContext has external storage containing + /// additional declarations that are lexically in this context. + bool hasExternalLexicalStorage() const { return ExternalLexicalStorage; } + + /// \brief State whether this DeclContext has external storage for + /// declarations lexically in this context. + void setHasExternalLexicalStorage(bool ES = true) { + ExternalLexicalStorage = ES; + } + + /// \brief Whether this DeclContext has external storage containing + /// additional declarations that are visible in this context. + bool hasExternalVisibleStorage() const { return ExternalVisibleStorage; } + + /// \brief State whether this DeclContext has external storage for + /// declarations visible in this context. + void setHasExternalVisibleStorage(bool ES = true) { + ExternalVisibleStorage = ES; + } + + /// \brief Determine whether the given declaration is stored in the list of + /// declarations lexically within this context. + bool isDeclInLexicalTraversal(const Decl *D) const { + return D && (D->NextInContextAndBits.getPointer() || D == FirstDecl || + D == LastDecl); + } + + static bool classof(const Decl *D); + static bool classof(const DeclContext *D) { return true; } +#define DECL(NAME, BASE) +#define DECL_CONTEXT(NAME) \ + static bool classof(const NAME##Decl *D) { return true; } +#include "clang/AST/DeclNodes.inc" + + LLVM_ATTRIBUTE_USED void dumpDeclContext() const; + +private: + void LoadLexicalDeclsFromExternalStorage() const; + + /// @brief Makes a declaration visible within this context, but + /// suppresses searches for external declarations with the same + /// name. + /// + /// Analogous to makeDeclVisibleInContext, but for the exclusive + /// use of addDeclInternal(). + void makeDeclVisibleInContextInternal(NamedDecl *D); + + friend class DependentDiagnostic; + StoredDeclsMap *CreateStoredDeclsMap(ASTContext &C) const; + + void buildLookupImpl(DeclContext *DCtx); + void makeDeclVisibleInContextWithFlags(NamedDecl *D, bool Internal, + bool Rediscoverable); + void makeDeclVisibleInContextImpl(NamedDecl *D, bool Internal); +}; + +inline bool Decl::isTemplateParameter() const { + return getKind() == TemplateTypeParm || getKind() == NonTypeTemplateParm || + getKind() == TemplateTemplateParm; +} + +// Specialization selected when ToTy is not a known subclass of DeclContext. +template <class ToTy, + bool IsKnownSubtype = ::llvm::is_base_of< DeclContext, ToTy>::value> +struct cast_convert_decl_context { + static const ToTy *doit(const DeclContext *Val) { + return static_cast<const ToTy*>(Decl::castFromDeclContext(Val)); + } + + static ToTy *doit(DeclContext *Val) { + return static_cast<ToTy*>(Decl::castFromDeclContext(Val)); + } +}; + +// Specialization selected when ToTy is a known subclass of DeclContext. +template <class ToTy> +struct cast_convert_decl_context<ToTy, true> { + static const ToTy *doit(const DeclContext *Val) { + return static_cast<const ToTy*>(Val); + } + + static ToTy *doit(DeclContext *Val) { + return static_cast<ToTy*>(Val); + } +}; + + +} // end clang. + +namespace llvm { + +/// isa<T>(DeclContext*) +template <typename To> +struct isa_impl<To, ::clang::DeclContext> { + static bool doit(const ::clang::DeclContext &Val) { + return To::classofKind(Val.getDeclKind()); + } +}; + +/// cast<T>(DeclContext*) +template<class ToTy> +struct cast_convert_val<ToTy, + const ::clang::DeclContext,const ::clang::DeclContext> { + static const ToTy &doit(const ::clang::DeclContext &Val) { + return *::clang::cast_convert_decl_context<ToTy>::doit(&Val); + } +}; +template<class ToTy> +struct cast_convert_val<ToTy, ::clang::DeclContext, ::clang::DeclContext> { + static ToTy &doit(::clang::DeclContext &Val) { + return *::clang::cast_convert_decl_context<ToTy>::doit(&Val); + } +}; +template<class ToTy> +struct cast_convert_val<ToTy, + const ::clang::DeclContext*, const ::clang::DeclContext*> { + static const ToTy *doit(const ::clang::DeclContext *Val) { + return ::clang::cast_convert_decl_context<ToTy>::doit(Val); + } +}; +template<class ToTy> +struct cast_convert_val<ToTy, ::clang::DeclContext*, ::clang::DeclContext*> { + static ToTy *doit(::clang::DeclContext *Val) { + return ::clang::cast_convert_decl_context<ToTy>::doit(Val); + } +}; + +/// Implement cast_convert_val for Decl -> DeclContext conversions. +template<class FromTy> +struct cast_convert_val< ::clang::DeclContext, FromTy, FromTy> { + static ::clang::DeclContext &doit(const FromTy &Val) { + return *FromTy::castToDeclContext(&Val); + } +}; + +template<class FromTy> +struct cast_convert_val< ::clang::DeclContext, FromTy*, FromTy*> { + static ::clang::DeclContext *doit(const FromTy *Val) { + return FromTy::castToDeclContext(Val); + } +}; + +template<class FromTy> +struct cast_convert_val< const ::clang::DeclContext, FromTy, FromTy> { + static const ::clang::DeclContext &doit(const FromTy &Val) { + return *FromTy::castToDeclContext(&Val); + } +}; + +template<class FromTy> +struct cast_convert_val< const ::clang::DeclContext, FromTy*, FromTy*> { + static const ::clang::DeclContext *doit(const FromTy *Val) { + return FromTy::castToDeclContext(Val); + } +}; + +} // end namespace llvm + +#endif diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h new file mode 100644 index 0000000..7f3ec4c --- /dev/null +++ b/clang/include/clang/AST/DeclCXX.h @@ -0,0 +1,2938 @@ +//===-- DeclCXX.h - Classes for representing C++ declarations -*- C++ -*-=====// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the C++ Decl subclasses, other than those for +// templates (in DeclTemplate.h) and friends (in DeclFriend.h). +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_DECLCXX_H +#define LLVM_CLANG_AST_DECLCXX_H + +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/Decl.h" +#include "clang/AST/TypeLoc.h" +#include "clang/AST/UnresolvedSet.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/Support/Compiler.h" + +namespace clang { + +class ClassTemplateDecl; +class ClassTemplateSpecializationDecl; +class CXXBasePath; +class CXXBasePaths; +class CXXConstructorDecl; +class CXXConversionDecl; +class CXXDestructorDecl; +class CXXMethodDecl; +class CXXRecordDecl; +class CXXMemberLookupCriteria; +class CXXFinalOverriderMap; +class CXXIndirectPrimaryBaseSet; +class FriendDecl; +class LambdaExpr; + +/// \brief Represents any kind of function declaration, whether it is a +/// concrete function or a function template. +class AnyFunctionDecl { + NamedDecl *Function; + + AnyFunctionDecl(NamedDecl *ND) : Function(ND) { } + +public: + AnyFunctionDecl(FunctionDecl *FD) : Function(FD) { } + AnyFunctionDecl(FunctionTemplateDecl *FTD); + + /// \brief Implicily converts any function or function template into a + /// named declaration. + operator NamedDecl *() const { return Function; } + + /// \brief Retrieve the underlying function or function template. + NamedDecl *get() const { return Function; } + + static AnyFunctionDecl getFromNamedDecl(NamedDecl *ND) { + return AnyFunctionDecl(ND); + } +}; + +} // end namespace clang + +namespace llvm { + /// Implement simplify_type for AnyFunctionDecl, so that we can dyn_cast from + /// AnyFunctionDecl to any function or function template declaration. + template<> struct simplify_type<const ::clang::AnyFunctionDecl> { + typedef ::clang::NamedDecl* SimpleType; + static SimpleType getSimplifiedValue(const ::clang::AnyFunctionDecl &Val) { + return Val; + } + }; + template<> struct simplify_type< ::clang::AnyFunctionDecl> + : public simplify_type<const ::clang::AnyFunctionDecl> {}; + + // Provide PointerLikeTypeTraits for non-cvr pointers. + template<> + class PointerLikeTypeTraits< ::clang::AnyFunctionDecl> { + public: + static inline void *getAsVoidPointer(::clang::AnyFunctionDecl F) { + return F.get(); + } + static inline ::clang::AnyFunctionDecl getFromVoidPointer(void *P) { + return ::clang::AnyFunctionDecl::getFromNamedDecl( + static_cast< ::clang::NamedDecl*>(P)); + } + + enum { NumLowBitsAvailable = 2 }; + }; + +} // end namespace llvm + +namespace clang { + +/// AccessSpecDecl - An access specifier followed by colon ':'. +/// +/// An objects of this class represents sugar for the syntactic occurrence +/// of an access specifier followed by a colon in the list of member +/// specifiers of a C++ class definition. +/// +/// Note that they do not represent other uses of access specifiers, +/// such as those occurring in a list of base specifiers. +/// Also note that this class has nothing to do with so-called +/// "access declarations" (C++98 11.3 [class.access.dcl]). +class AccessSpecDecl : public Decl { + virtual void anchor(); + /// ColonLoc - The location of the ':'. + SourceLocation ColonLoc; + + AccessSpecDecl(AccessSpecifier AS, DeclContext *DC, + SourceLocation ASLoc, SourceLocation ColonLoc) + : Decl(AccessSpec, DC, ASLoc), ColonLoc(ColonLoc) { + setAccess(AS); + } + AccessSpecDecl(EmptyShell Empty) + : Decl(AccessSpec, Empty) { } +public: + /// getAccessSpecifierLoc - The location of the access specifier. + SourceLocation getAccessSpecifierLoc() const { return getLocation(); } + /// setAccessSpecifierLoc - Sets the location of the access specifier. + void setAccessSpecifierLoc(SourceLocation ASLoc) { setLocation(ASLoc); } + + /// getColonLoc - The location of the colon following the access specifier. + SourceLocation getColonLoc() const { return ColonLoc; } + /// setColonLoc - Sets the location of the colon. + void setColonLoc(SourceLocation CLoc) { ColonLoc = CLoc; } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(getAccessSpecifierLoc(), getColonLoc()); + } + + static AccessSpecDecl *Create(ASTContext &C, AccessSpecifier AS, + DeclContext *DC, SourceLocation ASLoc, + SourceLocation ColonLoc) { + return new (C) AccessSpecDecl(AS, DC, ASLoc, ColonLoc); + } + static AccessSpecDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const AccessSpecDecl *D) { return true; } + static bool classofKind(Kind K) { return K == AccessSpec; } +}; + + +/// CXXBaseSpecifier - A base class of a C++ class. +/// +/// Each CXXBaseSpecifier represents a single, direct base class (or +/// struct) of a C++ class (or struct). It specifies the type of that +/// base class, whether it is a virtual or non-virtual base, and what +/// level of access (public, protected, private) is used for the +/// derivation. For example: +/// +/// @code +/// class A { }; +/// class B { }; +/// class C : public virtual A, protected B { }; +/// @endcode +/// +/// In this code, C will have two CXXBaseSpecifiers, one for "public +/// virtual A" and the other for "protected B". +class CXXBaseSpecifier { + /// Range - The source code range that covers the full base + /// specifier, including the "virtual" (if present) and access + /// specifier (if present). + SourceRange Range; + + /// \brief The source location of the ellipsis, if this is a pack + /// expansion. + SourceLocation EllipsisLoc; + + /// Virtual - Whether this is a virtual base class or not. + bool Virtual : 1; + + /// BaseOfClass - Whether this is the base of a class (true) or of a + /// struct (false). This determines the mapping from the access + /// specifier as written in the source code to the access specifier + /// used for semantic analysis. + bool BaseOfClass : 1; + + /// Access - Access specifier as written in the source code (which + /// may be AS_none). The actual type of data stored here is an + /// AccessSpecifier, but we use "unsigned" here to work around a + /// VC++ bug. + unsigned Access : 2; + + /// InheritConstructors - Whether the class contains a using declaration + /// to inherit the named class's constructors. + bool InheritConstructors : 1; + + /// BaseTypeInfo - The type of the base class. This will be a class or struct + /// (or a typedef of such). The source code range does not include the + /// "virtual" or access specifier. + TypeSourceInfo *BaseTypeInfo; + +public: + CXXBaseSpecifier() { } + + CXXBaseSpecifier(SourceRange R, bool V, bool BC, AccessSpecifier A, + TypeSourceInfo *TInfo, SourceLocation EllipsisLoc) + : Range(R), EllipsisLoc(EllipsisLoc), Virtual(V), BaseOfClass(BC), + Access(A), InheritConstructors(false), BaseTypeInfo(TInfo) { } + + /// getSourceRange - Retrieves the source range that contains the + /// entire base specifier. + SourceRange getSourceRange() const LLVM_READONLY { return Range; } + SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); } + SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); } + + /// isVirtual - Determines whether the base class is a virtual base + /// class (or not). + bool isVirtual() const { return Virtual; } + + /// \brief Determine whether this base class is a base of a class declared + /// with the 'class' keyword (vs. one declared with the 'struct' keyword). + bool isBaseOfClass() const { return BaseOfClass; } + + /// \brief Determine whether this base specifier is a pack expansion. + bool isPackExpansion() const { return EllipsisLoc.isValid(); } + + /// \brief Determine whether this base class's constructors get inherited. + bool getInheritConstructors() const { return InheritConstructors; } + + /// \brief Set that this base class's constructors should be inherited. + void setInheritConstructors(bool Inherit = true) { + InheritConstructors = Inherit; + } + + /// \brief For a pack expansion, determine the location of the ellipsis. + SourceLocation getEllipsisLoc() const { + return EllipsisLoc; + } + + /// getAccessSpecifier - Returns the access specifier for this base + /// specifier. This is the actual base specifier as used for + /// semantic analysis, so the result can never be AS_none. To + /// retrieve the access specifier as written in the source code, use + /// getAccessSpecifierAsWritten(). + AccessSpecifier getAccessSpecifier() const { + if ((AccessSpecifier)Access == AS_none) + return BaseOfClass? AS_private : AS_public; + else + return (AccessSpecifier)Access; + } + + /// getAccessSpecifierAsWritten - Retrieves the access specifier as + /// written in the source code (which may mean that no access + /// specifier was explicitly written). Use getAccessSpecifier() to + /// retrieve the access specifier for use in semantic analysis. + AccessSpecifier getAccessSpecifierAsWritten() const { + return (AccessSpecifier)Access; + } + + /// getType - Retrieves the type of the base class. This type will + /// always be an unqualified class type. + QualType getType() const { return BaseTypeInfo->getType(); } + + /// getTypeLoc - Retrieves the type and source location of the base class. + TypeSourceInfo *getTypeSourceInfo() const { return BaseTypeInfo; } +}; + +/// CXXRecordDecl - Represents a C++ struct/union/class. +/// FIXME: This class will disappear once we've properly taught RecordDecl +/// to deal with C++-specific things. +class CXXRecordDecl : public RecordDecl { + + friend void TagDecl::startDefinition(); + + struct DefinitionData { + DefinitionData(CXXRecordDecl *D); + + /// UserDeclaredConstructor - True when this class has a + /// user-declared constructor. + bool UserDeclaredConstructor : 1; + + /// UserDeclaredCopyConstructor - True when this class has a + /// user-declared copy constructor. + bool UserDeclaredCopyConstructor : 1; + + /// UserDeclareMoveConstructor - True when this class has a + /// user-declared move constructor. + bool UserDeclaredMoveConstructor : 1; + + /// UserDeclaredCopyAssignment - True when this class has a + /// user-declared copy assignment operator. + bool UserDeclaredCopyAssignment : 1; + + /// UserDeclareMoveAssignment - True when this class has a + /// user-declared move assignment. + bool UserDeclaredMoveAssignment : 1; + + /// UserDeclaredDestructor - True when this class has a + /// user-declared destructor. + bool UserDeclaredDestructor : 1; + + /// Aggregate - True when this class is an aggregate. + bool Aggregate : 1; + + /// PlainOldData - True when this class is a POD-type. + bool PlainOldData : 1; + + /// Empty - true when this class is empty for traits purposes, + /// i.e. has no data members other than 0-width bit-fields, has no + /// virtual function/base, and doesn't inherit from a non-empty + /// class. Doesn't take union-ness into account. + bool Empty : 1; + + /// Polymorphic - True when this class is polymorphic, i.e. has at + /// least one virtual member or derives from a polymorphic class. + bool Polymorphic : 1; + + /// Abstract - True when this class is abstract, i.e. has at least + /// one pure virtual function, (that can come from a base class). + bool Abstract : 1; + + /// IsStandardLayout - True when this class has standard layout. + /// + /// C++0x [class]p7. A standard-layout class is a class that: + /// * has no non-static data members of type non-standard-layout class (or + /// array of such types) or reference, + /// * has no virtual functions (10.3) and no virtual base classes (10.1), + /// * has the same access control (Clause 11) for all non-static data + /// members + /// * has no non-standard-layout base classes, + /// * either has no non-static data members in the most derived class and at + /// most one base class with non-static data members, or has no base + /// classes with non-static data members, and + /// * has no base classes of the same type as the first non-static data + /// member. + bool IsStandardLayout : 1; + + /// HasNoNonEmptyBases - True when there are no non-empty base classes. + /// + /// This is a helper bit of state used to implement IsStandardLayout more + /// efficiently. + bool HasNoNonEmptyBases : 1; + + /// HasPrivateFields - True when there are private non-static data members. + bool HasPrivateFields : 1; + + /// HasProtectedFields - True when there are protected non-static data + /// members. + bool HasProtectedFields : 1; + + /// HasPublicFields - True when there are private non-static data members. + bool HasPublicFields : 1; + + /// \brief True if this class (or any subobject) has mutable fields. + bool HasMutableFields : 1; + + /// \brief True if there no non-field members declared by the user. + bool HasOnlyCMembers : 1; + + /// HasTrivialDefaultConstructor - True when, if this class has a default + /// constructor, this default constructor is trivial. + /// + /// C++0x [class.ctor]p5 + /// A default constructor is trivial if it is not user-provided and if + /// -- its class has no virtual functions and no virtual base classes, + /// and + /// -- no non-static data member of its class has a + /// brace-or-equal-initializer, and + /// -- all the direct base classes of its class have trivial + /// default constructors, and + /// -- for all the nonstatic data members of its class that are of class + /// type (or array thereof), each such class has a trivial + /// default constructor. + bool HasTrivialDefaultConstructor : 1; + + /// HasConstexprNonCopyMoveConstructor - True when this class has at least + /// one user-declared constexpr constructor which is neither the copy nor + /// move constructor. + bool HasConstexprNonCopyMoveConstructor : 1; + + /// DefaultedDefaultConstructorIsConstexpr - True if a defaulted default + /// constructor for this class would be constexpr. + bool DefaultedDefaultConstructorIsConstexpr : 1; + + /// DefaultedCopyConstructorIsConstexpr - True if a defaulted copy + /// constructor for this class would be constexpr. + bool DefaultedCopyConstructorIsConstexpr : 1; + + /// DefaultedMoveConstructorIsConstexpr - True if a defaulted move + /// constructor for this class would be constexpr. + bool DefaultedMoveConstructorIsConstexpr : 1; + + /// HasConstexprDefaultConstructor - True if this class has a constexpr + /// default constructor (either user-declared or implicitly declared). + bool HasConstexprDefaultConstructor : 1; + + /// HasConstexprCopyConstructor - True if this class has a constexpr copy + /// constructor (either user-declared or implicitly declared). + bool HasConstexprCopyConstructor : 1; + + /// HasConstexprMoveConstructor - True if this class has a constexpr move + /// constructor (either user-declared or implicitly declared). + bool HasConstexprMoveConstructor : 1; + + /// HasTrivialCopyConstructor - True when this class has a trivial copy + /// constructor. + /// + /// C++0x [class.copy]p13: + /// A copy/move constructor for class X is trivial if it is neither + /// user-provided and if + /// -- class X has no virtual functions and no virtual base classes, and + /// -- the constructor selected to copy/move each direct base class + /// subobject is trivial, and + /// -- for each non-static data member of X that is of class type (or an + /// array thereof), the constructor selected to copy/move that member + /// is trivial; + /// otherwise the copy/move constructor is non-trivial. + bool HasTrivialCopyConstructor : 1; + + /// HasTrivialMoveConstructor - True when this class has a trivial move + /// constructor. + /// + /// C++0x [class.copy]p13: + /// A copy/move constructor for class X is trivial if it is neither + /// user-provided and if + /// -- class X has no virtual functions and no virtual base classes, and + /// -- the constructor selected to copy/move each direct base class + /// subobject is trivial, and + /// -- for each non-static data member of X that is of class type (or an + /// array thereof), the constructor selected to copy/move that member + /// is trivial; + /// otherwise the copy/move constructor is non-trivial. + bool HasTrivialMoveConstructor : 1; + + /// HasTrivialCopyAssignment - True when this class has a trivial copy + /// assignment operator. + /// + /// C++0x [class.copy]p27: + /// A copy/move assignment operator for class X is trivial if it is + /// neither user-provided nor deleted and if + /// -- class X has no virtual functions and no virtual base classes, and + /// -- the assignment operator selected to copy/move each direct base + /// class subobject is trivial, and + /// -- for each non-static data member of X that is of class type (or an + /// array thereof), the assignment operator selected to copy/move + /// that member is trivial; + /// otherwise the copy/move assignment operator is non-trivial. + bool HasTrivialCopyAssignment : 1; + + /// HasTrivialMoveAssignment - True when this class has a trivial move + /// assignment operator. + /// + /// C++0x [class.copy]p27: + /// A copy/move assignment operator for class X is trivial if it is + /// neither user-provided nor deleted and if + /// -- class X has no virtual functions and no virtual base classes, and + /// -- the assignment operator selected to copy/move each direct base + /// class subobject is trivial, and + /// -- for each non-static data member of X that is of class type (or an + /// array thereof), the assignment operator selected to copy/move + /// that member is trivial; + /// otherwise the copy/move assignment operator is non-trivial. + bool HasTrivialMoveAssignment : 1; + + /// HasTrivialDestructor - True when this class has a trivial destructor. + /// + /// C++ [class.dtor]p3. A destructor is trivial if it is an + /// implicitly-declared destructor and if: + /// * all of the direct base classes of its class have trivial destructors + /// and + /// * for all of the non-static data members of its class that are of class + /// type (or array thereof), each such class has a trivial destructor. + bool HasTrivialDestructor : 1; + + /// HasIrrelevantDestructor - True when this class has a destructor with no + /// semantic effect. + bool HasIrrelevantDestructor : 1; + + /// HasNonLiteralTypeFieldsOrBases - True when this class contains at least + /// one non-static data member or base class of non-literal or volatile + /// type. + bool HasNonLiteralTypeFieldsOrBases : 1; + + /// ComputedVisibleConversions - True when visible conversion functions are + /// already computed and are available. + bool ComputedVisibleConversions : 1; + + /// \brief Whether we have a C++0x user-provided default constructor (not + /// explicitly deleted or defaulted). + bool UserProvidedDefaultConstructor : 1; + + /// \brief Whether we have already declared the default constructor. + bool DeclaredDefaultConstructor : 1; + + /// \brief Whether we have already declared the copy constructor. + bool DeclaredCopyConstructor : 1; + + /// \brief Whether we have already declared the move constructor. + bool DeclaredMoveConstructor : 1; + + /// \brief Whether we have already declared the copy-assignment operator. + bool DeclaredCopyAssignment : 1; + + /// \brief Whether we have already declared the move-assignment operator. + bool DeclaredMoveAssignment : 1; + + /// \brief Whether we have already declared a destructor within the class. + bool DeclaredDestructor : 1; + + /// \brief Whether an implicit move constructor was attempted to be declared + /// but would have been deleted. + bool FailedImplicitMoveConstructor : 1; + + /// \brief Whether an implicit move assignment operator was attempted to be + /// declared but would have been deleted. + bool FailedImplicitMoveAssignment : 1; + + /// \brief Whether this class describes a C++ lambda. + bool IsLambda : 1; + + /// NumBases - The number of base class specifiers in Bases. + unsigned NumBases; + + /// NumVBases - The number of virtual base class specifiers in VBases. + unsigned NumVBases; + + /// Bases - Base classes of this class. + /// FIXME: This is wasted space for a union. + LazyCXXBaseSpecifiersPtr Bases; + + /// VBases - direct and indirect virtual base classes of this class. + LazyCXXBaseSpecifiersPtr VBases; + + /// Conversions - Overload set containing the conversion functions + /// of this C++ class (but not its inherited conversion + /// functions). Each of the entries in this overload set is a + /// CXXConversionDecl. + UnresolvedSet<4> Conversions; + + /// VisibleConversions - Overload set containing the conversion + /// functions of this C++ class and all those inherited conversion + /// functions that are visible in this class. Each of the entries + /// in this overload set is a CXXConversionDecl or a + /// FunctionTemplateDecl. + UnresolvedSet<4> VisibleConversions; + + /// Definition - The declaration which defines this record. + CXXRecordDecl *Definition; + + /// FirstFriend - The first friend declaration in this class, or + /// null if there aren't any. This is actually currently stored + /// in reverse order. + FriendDecl *FirstFriend; + + /// \brief Retrieve the set of direct base classes. + CXXBaseSpecifier *getBases() const { + return Bases.get(Definition->getASTContext().getExternalSource()); + } + + /// \brief Retrieve the set of virtual base classes. + CXXBaseSpecifier *getVBases() const { + return VBases.get(Definition->getASTContext().getExternalSource()); + } + } *DefinitionData; + + /// \brief Describes a C++ closure type (generated by a lambda expression). + struct LambdaDefinitionData : public DefinitionData { + typedef LambdaExpr::Capture Capture; + + LambdaDefinitionData(CXXRecordDecl *D, bool Dependent) + : DefinitionData(D), Dependent(Dependent), NumCaptures(0), + NumExplicitCaptures(0), ManglingNumber(0), ContextDecl(0), Captures(0) + { + IsLambda = true; + } + + /// \brief Whether this lambda is known to be dependent, even if its + /// context isn't dependent. + /// + /// A lambda with a non-dependent context can be dependent if it occurs + /// within the default argument of a function template, because the + /// lambda will have been created with the enclosing context as its + /// declaration context, rather than function. This is an unfortunate + /// artifact of having to parse the default arguments before + unsigned Dependent : 1; + + /// \brief The number of captures in this lambda. + unsigned NumCaptures : 16; + + /// \brief The number of explicit captures in this lambda. + unsigned NumExplicitCaptures : 15; + + /// \brief The number used to indicate this lambda expression for name + /// mangling in the Itanium C++ ABI. + unsigned ManglingNumber; + + /// \brief The declaration that provides context for this lambda, if the + /// actual DeclContext does not suffice. This is used for lambdas that + /// occur within default arguments of function parameters within the class + /// or within a data member initializer. + Decl *ContextDecl; + + /// \brief The list of captures, both explicit and implicit, for this + /// lambda. + Capture *Captures; + }; + + struct DefinitionData &data() { + assert(DefinitionData && "queried property of class with no definition"); + return *DefinitionData; + } + + const struct DefinitionData &data() const { + assert(DefinitionData && "queried property of class with no definition"); + return *DefinitionData; + } + + struct LambdaDefinitionData &getLambdaData() const { + assert(DefinitionData && "queried property of lambda with no definition"); + assert(DefinitionData->IsLambda && + "queried lambda property of non-lambda class"); + return static_cast<LambdaDefinitionData &>(*DefinitionData); + } + + /// \brief The template or declaration that this declaration + /// describes or was instantiated from, respectively. + /// + /// For non-templates, this value will be NULL. For record + /// declarations that describe a class template, this will be a + /// pointer to a ClassTemplateDecl. For member + /// classes of class template specializations, this will be the + /// MemberSpecializationInfo referring to the member class that was + /// instantiated or specialized. + llvm::PointerUnion<ClassTemplateDecl*, MemberSpecializationInfo*> + TemplateOrInstantiation; + + friend class DeclContext; + friend class LambdaExpr; + + /// \brief Notify the class that member has been added. + /// + /// This routine helps maintain information about the class based on which + /// members have been added. It will be invoked by DeclContext::addDecl() + /// whenever a member is added to this record. + void addedMember(Decl *D); + + void markedVirtualFunctionPure(); + friend void FunctionDecl::setPure(bool); + + friend class ASTNodeImporter; + +protected: + CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC, + SourceLocation StartLoc, SourceLocation IdLoc, + IdentifierInfo *Id, CXXRecordDecl *PrevDecl); + +public: + /// base_class_iterator - Iterator that traverses the base classes + /// of a class. + typedef CXXBaseSpecifier* base_class_iterator; + + /// base_class_const_iterator - Iterator that traverses the base + /// classes of a class. + typedef const CXXBaseSpecifier* base_class_const_iterator; + + /// reverse_base_class_iterator = Iterator that traverses the base classes + /// of a class in reverse order. + typedef std::reverse_iterator<base_class_iterator> + reverse_base_class_iterator; + + /// reverse_base_class_iterator = Iterator that traverses the base classes + /// of a class in reverse order. + typedef std::reverse_iterator<base_class_const_iterator> + reverse_base_class_const_iterator; + + virtual CXXRecordDecl *getCanonicalDecl() { + return cast<CXXRecordDecl>(RecordDecl::getCanonicalDecl()); + } + virtual const CXXRecordDecl *getCanonicalDecl() const { + return cast<CXXRecordDecl>(RecordDecl::getCanonicalDecl()); + } + + const CXXRecordDecl *getPreviousDecl() const { + return cast_or_null<CXXRecordDecl>(RecordDecl::getPreviousDecl()); + } + CXXRecordDecl *getPreviousDecl() { + return cast_or_null<CXXRecordDecl>(RecordDecl::getPreviousDecl()); + } + + const CXXRecordDecl *getMostRecentDecl() const { + return cast_or_null<CXXRecordDecl>(RecordDecl::getMostRecentDecl()); + } + CXXRecordDecl *getMostRecentDecl() { + return cast_or_null<CXXRecordDecl>(RecordDecl::getMostRecentDecl()); + } + + CXXRecordDecl *getDefinition() const { + if (!DefinitionData) return 0; + return data().Definition; + } + + bool hasDefinition() const { return DefinitionData != 0; } + + static CXXRecordDecl *Create(const ASTContext &C, TagKind TK, DeclContext *DC, + SourceLocation StartLoc, SourceLocation IdLoc, + IdentifierInfo *Id, CXXRecordDecl* PrevDecl=0, + bool DelayTypeCreation = false); + static CXXRecordDecl *CreateLambda(const ASTContext &C, DeclContext *DC, + SourceLocation Loc, bool DependentLambda); + static CXXRecordDecl *CreateDeserialized(const ASTContext &C, unsigned ID); + + bool isDynamicClass() const { + return data().Polymorphic || data().NumVBases != 0; + } + + /// setBases - Sets the base classes of this struct or class. + void setBases(CXXBaseSpecifier const * const *Bases, unsigned NumBases); + + /// getNumBases - Retrieves the number of base classes of this + /// class. + unsigned getNumBases() const { return data().NumBases; } + + base_class_iterator bases_begin() { return data().getBases(); } + base_class_const_iterator bases_begin() const { return data().getBases(); } + base_class_iterator bases_end() { return bases_begin() + data().NumBases; } + base_class_const_iterator bases_end() const { + return bases_begin() + data().NumBases; + } + reverse_base_class_iterator bases_rbegin() { + return reverse_base_class_iterator(bases_end()); + } + reverse_base_class_const_iterator bases_rbegin() const { + return reverse_base_class_const_iterator(bases_end()); + } + reverse_base_class_iterator bases_rend() { + return reverse_base_class_iterator(bases_begin()); + } + reverse_base_class_const_iterator bases_rend() const { + return reverse_base_class_const_iterator(bases_begin()); + } + + /// getNumVBases - Retrieves the number of virtual base classes of this + /// class. + unsigned getNumVBases() const { return data().NumVBases; } + + base_class_iterator vbases_begin() { return data().getVBases(); } + base_class_const_iterator vbases_begin() const { return data().getVBases(); } + base_class_iterator vbases_end() { return vbases_begin() + data().NumVBases; } + base_class_const_iterator vbases_end() const { + return vbases_begin() + data().NumVBases; + } + reverse_base_class_iterator vbases_rbegin() { + return reverse_base_class_iterator(vbases_end()); + } + reverse_base_class_const_iterator vbases_rbegin() const { + return reverse_base_class_const_iterator(vbases_end()); + } + reverse_base_class_iterator vbases_rend() { + return reverse_base_class_iterator(vbases_begin()); + } + reverse_base_class_const_iterator vbases_rend() const { + return reverse_base_class_const_iterator(vbases_begin()); + } + + /// \brief Determine whether this class has any dependent base classes. + bool hasAnyDependentBases() const; + + /// Iterator access to method members. The method iterator visits + /// all method members of the class, including non-instance methods, + /// special methods, etc. + typedef specific_decl_iterator<CXXMethodDecl> method_iterator; + + /// method_begin - Method begin iterator. Iterates in the order the methods + /// were declared. + method_iterator method_begin() const { + return method_iterator(decls_begin()); + } + /// method_end - Method end iterator. + method_iterator method_end() const { + return method_iterator(decls_end()); + } + + /// Iterator access to constructor members. + typedef specific_decl_iterator<CXXConstructorDecl> ctor_iterator; + + ctor_iterator ctor_begin() const { + return ctor_iterator(decls_begin()); + } + ctor_iterator ctor_end() const { + return ctor_iterator(decls_end()); + } + + /// An iterator over friend declarations. All of these are defined + /// in DeclFriend.h. + class friend_iterator; + friend_iterator friend_begin() const; + friend_iterator friend_end() const; + void pushFriendDecl(FriendDecl *FD); + + /// Determines whether this record has any friends. + bool hasFriends() const { + return data().FirstFriend != 0; + } + + /// \brief Determine if we need to declare a default constructor for + /// this class. + /// + /// This value is used for lazy creation of default constructors. + bool needsImplicitDefaultConstructor() const { + return !data().UserDeclaredConstructor && + !data().DeclaredDefaultConstructor; + } + + /// hasDeclaredDefaultConstructor - Whether this class's default constructor + /// has been declared (either explicitly or implicitly). + bool hasDeclaredDefaultConstructor() const { + return data().DeclaredDefaultConstructor; + } + + /// hasConstCopyConstructor - Determines whether this class has a + /// copy constructor that accepts a const-qualified argument. + bool hasConstCopyConstructor() const; + + /// getCopyConstructor - Returns the copy constructor for this class + CXXConstructorDecl *getCopyConstructor(unsigned TypeQuals) const; + + /// getMoveConstructor - Returns the move constructor for this class + CXXConstructorDecl *getMoveConstructor() const; + + /// \brief Retrieve the copy-assignment operator for this class, if available. + /// + /// This routine attempts to find the copy-assignment operator for this + /// class, using a simplistic form of overload resolution. + /// + /// \param ArgIsConst Whether the argument to the copy-assignment operator + /// is const-qualified. + /// + /// \returns The copy-assignment operator that can be invoked, or NULL if + /// a unique copy-assignment operator could not be found. + CXXMethodDecl *getCopyAssignmentOperator(bool ArgIsConst) const; + + /// getMoveAssignmentOperator - Returns the move assignment operator for this + /// class + CXXMethodDecl *getMoveAssignmentOperator() const; + + /// hasUserDeclaredConstructor - Whether this class has any + /// user-declared constructors. When true, a default constructor + /// will not be implicitly declared. + bool hasUserDeclaredConstructor() const { + return data().UserDeclaredConstructor; + } + + /// hasUserProvidedDefaultconstructor - Whether this class has a + /// user-provided default constructor per C++0x. + bool hasUserProvidedDefaultConstructor() const { + return data().UserProvidedDefaultConstructor; + } + + /// hasUserDeclaredCopyConstructor - Whether this class has a + /// user-declared copy constructor. When false, a copy constructor + /// will be implicitly declared. + bool hasUserDeclaredCopyConstructor() const { + return data().UserDeclaredCopyConstructor; + } + + /// \brief Determine whether this class has had its copy constructor + /// declared, either via the user or via an implicit declaration. + /// + /// This value is used for lazy creation of copy constructors. + bool hasDeclaredCopyConstructor() const { + return data().DeclaredCopyConstructor; + } + + /// hasUserDeclaredMoveOperation - Whether this class has a user- + /// declared move constructor or assignment operator. When false, a + /// move constructor and assignment operator may be implicitly declared. + bool hasUserDeclaredMoveOperation() const { + return data().UserDeclaredMoveConstructor || + data().UserDeclaredMoveAssignment; + } + + /// \brief Determine whether this class has had a move constructor + /// declared by the user. + bool hasUserDeclaredMoveConstructor() const { + return data().UserDeclaredMoveConstructor; + } + + /// \brief Determine whether this class has had a move constructor + /// declared. + bool hasDeclaredMoveConstructor() const { + return data().DeclaredMoveConstructor; + } + + /// \brief Determine whether implicit move constructor generation for this + /// class has failed before. + bool hasFailedImplicitMoveConstructor() const { + return data().FailedImplicitMoveConstructor; + } + + /// \brief Set whether implicit move constructor generation for this class + /// has failed before. + void setFailedImplicitMoveConstructor(bool Failed = true) { + data().FailedImplicitMoveConstructor = Failed; + } + + /// \brief Determine whether this class should get an implicit move + /// constructor or if any existing special member function inhibits this. + /// + /// Covers all bullets of C++0x [class.copy]p9 except the last, that the + /// constructor wouldn't be deleted, which is only looked up from a cached + /// result. + bool needsImplicitMoveConstructor() const { + return !hasFailedImplicitMoveConstructor() && + !hasDeclaredMoveConstructor() && + !hasUserDeclaredCopyConstructor() && + !hasUserDeclaredCopyAssignment() && + !hasUserDeclaredMoveAssignment() && + !hasUserDeclaredDestructor(); + } + + /// hasUserDeclaredCopyAssignment - Whether this class has a + /// user-declared copy assignment operator. When false, a copy + /// assigment operator will be implicitly declared. + bool hasUserDeclaredCopyAssignment() const { + return data().UserDeclaredCopyAssignment; + } + + /// \brief Determine whether this class has had its copy assignment operator + /// declared, either via the user or via an implicit declaration. + /// + /// This value is used for lazy creation of copy assignment operators. + bool hasDeclaredCopyAssignment() const { + return data().DeclaredCopyAssignment; + } + + /// \brief Determine whether this class has had a move assignment + /// declared by the user. + bool hasUserDeclaredMoveAssignment() const { + return data().UserDeclaredMoveAssignment; + } + + /// hasDeclaredMoveAssignment - Whether this class has a + /// declared move assignment operator. + bool hasDeclaredMoveAssignment() const { + return data().DeclaredMoveAssignment; + } + + /// \brief Determine whether implicit move assignment generation for this + /// class has failed before. + bool hasFailedImplicitMoveAssignment() const { + return data().FailedImplicitMoveAssignment; + } + + /// \brief Set whether implicit move assignment generation for this class + /// has failed before. + void setFailedImplicitMoveAssignment(bool Failed = true) { + data().FailedImplicitMoveAssignment = Failed; + } + + /// \brief Determine whether this class should get an implicit move + /// assignment operator or if any existing special member function inhibits + /// this. + /// + /// Covers all bullets of C++0x [class.copy]p20 except the last, that the + /// constructor wouldn't be deleted. + bool needsImplicitMoveAssignment() const { + return !hasFailedImplicitMoveAssignment() && + !hasDeclaredMoveAssignment() && + !hasUserDeclaredCopyConstructor() && + !hasUserDeclaredCopyAssignment() && + !hasUserDeclaredMoveConstructor() && + !hasUserDeclaredDestructor(); + } + + /// hasUserDeclaredDestructor - Whether this class has a + /// user-declared destructor. When false, a destructor will be + /// implicitly declared. + bool hasUserDeclaredDestructor() const { + return data().UserDeclaredDestructor; + } + + /// \brief Determine whether this class has had its destructor declared, + /// either via the user or via an implicit declaration. + /// + /// This value is used for lazy creation of destructors. + bool hasDeclaredDestructor() const { return data().DeclaredDestructor; } + + /// \brief Determine whether this class describes a lambda function object. + bool isLambda() const { return hasDefinition() && data().IsLambda; } + + /// \brief For a closure type, retrieve the mapping from captured + /// variables and this to the non-static data members that store the + /// values or references of the captures. + /// + /// \param Captures Will be populated with the mapping from captured + /// variables to the corresponding fields. + /// + /// \param ThisCapture Will be set to the field declaration for the + /// 'this' capture. + void getCaptureFields(llvm::DenseMap<const VarDecl *, FieldDecl *> &Captures, + FieldDecl *&ThisCapture) const; + + typedef const LambdaExpr::Capture* capture_const_iterator; + capture_const_iterator captures_begin() const { + return isLambda() ? getLambdaData().Captures : NULL; + } + capture_const_iterator captures_end() const { + return isLambda() ? captures_begin() + getLambdaData().NumCaptures : NULL; + } + + /// getConversions - Retrieve the overload set containing all of the + /// conversion functions in this class. + UnresolvedSetImpl *getConversionFunctions() { + return &data().Conversions; + } + const UnresolvedSetImpl *getConversionFunctions() const { + return &data().Conversions; + } + + typedef UnresolvedSetImpl::iterator conversion_iterator; + conversion_iterator conversion_begin() const { + return getConversionFunctions()->begin(); + } + conversion_iterator conversion_end() const { + return getConversionFunctions()->end(); + } + + /// Removes a conversion function from this class. The conversion + /// function must currently be a member of this class. Furthermore, + /// this class must currently be in the process of being defined. + void removeConversion(const NamedDecl *Old); + + /// getVisibleConversionFunctions - get all conversion functions visible + /// in current class; including conversion function templates. + const UnresolvedSetImpl *getVisibleConversionFunctions(); + + /// isAggregate - Whether this class is an aggregate (C++ + /// [dcl.init.aggr]), which is a class with no user-declared + /// constructors, no private or protected non-static data members, + /// no base classes, and no virtual functions (C++ [dcl.init.aggr]p1). + bool isAggregate() const { return data().Aggregate; } + + /// isPOD - Whether this class is a POD-type (C++ [class]p4), which is a class + /// that is an aggregate that has no non-static non-POD data members, no + /// reference data members, no user-defined copy assignment operator and no + /// user-defined destructor. + bool isPOD() const { return data().PlainOldData; } + + /// \brief True if this class is C-like, without C++-specific features, e.g. + /// it contains only public fields, no bases, tag kind is not 'class', etc. + bool isCLike() const; + + /// isEmpty - Whether this class is empty (C++0x [meta.unary.prop]), which + /// means it has a virtual function, virtual base, data member (other than + /// 0-width bit-field) or inherits from a non-empty class. Does NOT include + /// a check for union-ness. + bool isEmpty() const { return data().Empty; } + + /// isPolymorphic - Whether this class is polymorphic (C++ [class.virtual]), + /// which means that the class contains or inherits a virtual function. + bool isPolymorphic() const { return data().Polymorphic; } + + /// isAbstract - Whether this class is abstract (C++ [class.abstract]), + /// which means that the class contains or inherits a pure virtual function. + bool isAbstract() const { return data().Abstract; } + + /// isStandardLayout - Whether this class has standard layout + /// (C++ [class]p7) + bool isStandardLayout() const { return data().IsStandardLayout; } + + /// \brief Whether this class, or any of its class subobjects, contains a + /// mutable field. + bool hasMutableFields() const { return data().HasMutableFields; } + + /// hasTrivialDefaultConstructor - Whether this class has a trivial default + /// constructor (C++11 [class.ctor]p5). + bool hasTrivialDefaultConstructor() const { + return data().HasTrivialDefaultConstructor && + (!data().UserDeclaredConstructor || + data().DeclaredDefaultConstructor); + } + + /// hasConstexprNonCopyMoveConstructor - Whether this class has at least one + /// constexpr constructor other than the copy or move constructors. + bool hasConstexprNonCopyMoveConstructor() const { + return data().HasConstexprNonCopyMoveConstructor || + (!hasUserDeclaredConstructor() && + defaultedDefaultConstructorIsConstexpr()); + } + + /// defaultedDefaultConstructorIsConstexpr - Whether a defaulted default + /// constructor for this class would be constexpr. + bool defaultedDefaultConstructorIsConstexpr() const { + return data().DefaultedDefaultConstructorIsConstexpr; + } + + /// defaultedCopyConstructorIsConstexpr - Whether a defaulted copy + /// constructor for this class would be constexpr. + bool defaultedCopyConstructorIsConstexpr() const { + return data().DefaultedCopyConstructorIsConstexpr; + } + + /// defaultedMoveConstructorIsConstexpr - Whether a defaulted move + /// constructor for this class would be constexpr. + bool defaultedMoveConstructorIsConstexpr() const { + return data().DefaultedMoveConstructorIsConstexpr; + } + + /// hasConstexprDefaultConstructor - Whether this class has a constexpr + /// default constructor. + bool hasConstexprDefaultConstructor() const { + return data().HasConstexprDefaultConstructor || + (!data().UserDeclaredConstructor && + data().DefaultedDefaultConstructorIsConstexpr && isLiteral()); + } + + /// hasConstexprCopyConstructor - Whether this class has a constexpr copy + /// constructor. + bool hasConstexprCopyConstructor() const { + return data().HasConstexprCopyConstructor || + (!data().DeclaredCopyConstructor && + data().DefaultedCopyConstructorIsConstexpr && isLiteral()); + } + + /// hasConstexprMoveConstructor - Whether this class has a constexpr move + /// constructor. + bool hasConstexprMoveConstructor() const { + return data().HasConstexprMoveConstructor || + (needsImplicitMoveConstructor() && + data().DefaultedMoveConstructorIsConstexpr && isLiteral()); + } + + // hasTrivialCopyConstructor - Whether this class has a trivial copy + // constructor (C++ [class.copy]p6, C++0x [class.copy]p13) + bool hasTrivialCopyConstructor() const { + return data().HasTrivialCopyConstructor; + } + + // hasTrivialMoveConstructor - Whether this class has a trivial move + // constructor (C++0x [class.copy]p13) + bool hasTrivialMoveConstructor() const { + return data().HasTrivialMoveConstructor; + } + + // hasTrivialCopyAssignment - Whether this class has a trivial copy + // assignment operator (C++ [class.copy]p11, C++0x [class.copy]p27) + bool hasTrivialCopyAssignment() const { + return data().HasTrivialCopyAssignment; + } + + // hasTrivialMoveAssignment - Whether this class has a trivial move + // assignment operator (C++0x [class.copy]p27) + bool hasTrivialMoveAssignment() const { + return data().HasTrivialMoveAssignment; + } + + // hasTrivialDestructor - Whether this class has a trivial destructor + // (C++ [class.dtor]p3) + bool hasTrivialDestructor() const { return data().HasTrivialDestructor; } + + // hasIrrelevantDestructor - Whether this class has a destructor which has no + // semantic effect. Any such destructor will be trivial, public, defaulted + // and not deleted, and will call only irrelevant destructors. + bool hasIrrelevantDestructor() const { + return data().HasIrrelevantDestructor; + } + + // hasNonLiteralTypeFieldsOrBases - Whether this class has a non-literal or + // volatile type non-static data member or base class. + bool hasNonLiteralTypeFieldsOrBases() const { + return data().HasNonLiteralTypeFieldsOrBases; + } + + // isTriviallyCopyable - Whether this class is considered trivially copyable + // (C++0x [class]p6). + bool isTriviallyCopyable() const; + + // isTrivial - Whether this class is considered trivial + // + // C++0x [class]p6 + // A trivial class is a class that has a trivial default constructor and + // is trivially copiable. + bool isTrivial() const { + return isTriviallyCopyable() && hasTrivialDefaultConstructor(); + } + + // isLiteral - Whether this class is a literal type. + // + // C++11 [basic.types]p10 + // A class type that has all the following properties: + // -- it has a trivial destructor + // -- every constructor call and full-expression in the + // brace-or-equal-intializers for non-static data members (if any) is + // a constant expression. + // -- it is an aggregate type or has at least one constexpr constructor or + // constructor template that is not a copy or move constructor, and + // -- all of its non-static data members and base classes are of literal + // types + // + // We resolve DR1361 by ignoring the second bullet. We resolve DR1452 by + // treating types with trivial default constructors as literal types. + bool isLiteral() const { + return hasTrivialDestructor() && + (isAggregate() || hasConstexprNonCopyMoveConstructor() || + hasTrivialDefaultConstructor()) && + !hasNonLiteralTypeFieldsOrBases(); + } + + /// \brief If this record is an instantiation of a member class, + /// retrieves the member class from which it was instantiated. + /// + /// This routine will return non-NULL for (non-templated) member + /// classes of class templates. For example, given: + /// + /// \code + /// template<typename T> + /// struct X { + /// struct A { }; + /// }; + /// \endcode + /// + /// The declaration for X<int>::A is a (non-templated) CXXRecordDecl + /// whose parent is the class template specialization X<int>. For + /// this declaration, getInstantiatedFromMemberClass() will return + /// the CXXRecordDecl X<T>::A. When a complete definition of + /// X<int>::A is required, it will be instantiated from the + /// declaration returned by getInstantiatedFromMemberClass(). + CXXRecordDecl *getInstantiatedFromMemberClass() const; + + /// \brief If this class is an instantiation of a member class of a + /// class template specialization, retrieves the member specialization + /// information. + MemberSpecializationInfo *getMemberSpecializationInfo() const; + + /// \brief Specify that this record is an instantiation of the + /// member class RD. + void setInstantiationOfMemberClass(CXXRecordDecl *RD, + TemplateSpecializationKind TSK); + + /// \brief Retrieves the class template that is described by this + /// class declaration. + /// + /// Every class template is represented as a ClassTemplateDecl and a + /// CXXRecordDecl. The former contains template properties (such as + /// the template parameter lists) while the latter contains the + /// actual description of the template's + /// contents. ClassTemplateDecl::getTemplatedDecl() retrieves the + /// CXXRecordDecl that from a ClassTemplateDecl, while + /// getDescribedClassTemplate() retrieves the ClassTemplateDecl from + /// a CXXRecordDecl. + ClassTemplateDecl *getDescribedClassTemplate() const { + return TemplateOrInstantiation.dyn_cast<ClassTemplateDecl*>(); + } + + void setDescribedClassTemplate(ClassTemplateDecl *Template) { + TemplateOrInstantiation = Template; + } + + /// \brief Determine whether this particular class is a specialization or + /// instantiation of a class template or member class of a class template, + /// and how it was instantiated or specialized. + TemplateSpecializationKind getTemplateSpecializationKind() const; + + /// \brief Set the kind of specialization or template instantiation this is. + void setTemplateSpecializationKind(TemplateSpecializationKind TSK); + + /// getDestructor - Returns the destructor decl for this class. + CXXDestructorDecl *getDestructor() const; + + /// isLocalClass - If the class is a local class [class.local], returns + /// the enclosing function declaration. + const FunctionDecl *isLocalClass() const { + if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(getDeclContext())) + return RD->isLocalClass(); + + return dyn_cast<FunctionDecl>(getDeclContext()); + } + + /// \brief Determine whether this class is derived from the class \p Base. + /// + /// This routine only determines whether this class is derived from \p Base, + /// but does not account for factors that may make a Derived -> Base class + /// ill-formed, such as private/protected inheritance or multiple, ambiguous + /// base class subobjects. + /// + /// \param Base the base class we are searching for. + /// + /// \returns true if this class is derived from Base, false otherwise. + bool isDerivedFrom(const CXXRecordDecl *Base) const; + + /// \brief Determine whether this class is derived from the type \p Base. + /// + /// This routine only determines whether this class is derived from \p Base, + /// but does not account for factors that may make a Derived -> Base class + /// ill-formed, such as private/protected inheritance or multiple, ambiguous + /// base class subobjects. + /// + /// \param Base the base class we are searching for. + /// + /// \param Paths will contain the paths taken from the current class to the + /// given \p Base class. + /// + /// \returns true if this class is derived from Base, false otherwise. + /// + /// \todo add a separate paramaeter to configure IsDerivedFrom, rather than + /// tangling input and output in \p Paths + bool isDerivedFrom(const CXXRecordDecl *Base, CXXBasePaths &Paths) const; + + /// \brief Determine whether this class is virtually derived from + /// the class \p Base. + /// + /// This routine only determines whether this class is virtually + /// derived from \p Base, but does not account for factors that may + /// make a Derived -> Base class ill-formed, such as + /// private/protected inheritance or multiple, ambiguous base class + /// subobjects. + /// + /// \param Base the base class we are searching for. + /// + /// \returns true if this class is virtually derived from Base, + /// false otherwise. + bool isVirtuallyDerivedFrom(CXXRecordDecl *Base) const; + + /// \brief Determine whether this class is provably not derived from + /// the type \p Base. + bool isProvablyNotDerivedFrom(const CXXRecordDecl *Base) const; + + /// \brief Function type used by forallBases() as a callback. + /// + /// \param Base the definition of the base class + /// + /// \returns true if this base matched the search criteria + typedef bool ForallBasesCallback(const CXXRecordDecl *BaseDefinition, + void *UserData); + + /// \brief Determines if the given callback holds for all the direct + /// or indirect base classes of this type. + /// + /// The class itself does not count as a base class. This routine + /// returns false if the class has non-computable base classes. + /// + /// \param AllowShortCircuit if false, forces the callback to be called + /// for every base class, even if a dependent or non-matching base was + /// found. + bool forallBases(ForallBasesCallback *BaseMatches, void *UserData, + bool AllowShortCircuit = true) const; + + /// \brief Function type used by lookupInBases() to determine whether a + /// specific base class subobject matches the lookup criteria. + /// + /// \param Specifier the base-class specifier that describes the inheritance + /// from the base class we are trying to match. + /// + /// \param Path the current path, from the most-derived class down to the + /// base named by the \p Specifier. + /// + /// \param UserData a single pointer to user-specified data, provided to + /// lookupInBases(). + /// + /// \returns true if this base matched the search criteria, false otherwise. + typedef bool BaseMatchesCallback(const CXXBaseSpecifier *Specifier, + CXXBasePath &Path, + void *UserData); + + /// \brief Look for entities within the base classes of this C++ class, + /// transitively searching all base class subobjects. + /// + /// This routine uses the callback function \p BaseMatches to find base + /// classes meeting some search criteria, walking all base class subobjects + /// and populating the given \p Paths structure with the paths through the + /// inheritance hierarchy that resulted in a match. On a successful search, + /// the \p Paths structure can be queried to retrieve the matching paths and + /// to determine if there were any ambiguities. + /// + /// \param BaseMatches callback function used to determine whether a given + /// base matches the user-defined search criteria. + /// + /// \param UserData user data pointer that will be provided to \p BaseMatches. + /// + /// \param Paths used to record the paths from this class to its base class + /// subobjects that match the search criteria. + /// + /// \returns true if there exists any path from this class to a base class + /// subobject that matches the search criteria. + bool lookupInBases(BaseMatchesCallback *BaseMatches, void *UserData, + CXXBasePaths &Paths) const; + + /// \brief Base-class lookup callback that determines whether the given + /// base class specifier refers to a specific class declaration. + /// + /// This callback can be used with \c lookupInBases() to determine whether + /// a given derived class has is a base class subobject of a particular type. + /// The user data pointer should refer to the canonical CXXRecordDecl of the + /// base class that we are searching for. + static bool FindBaseClass(const CXXBaseSpecifier *Specifier, + CXXBasePath &Path, void *BaseRecord); + + /// \brief Base-class lookup callback that determines whether the + /// given base class specifier refers to a specific class + /// declaration and describes virtual derivation. + /// + /// This callback can be used with \c lookupInBases() to determine + /// whether a given derived class has is a virtual base class + /// subobject of a particular type. The user data pointer should + /// refer to the canonical CXXRecordDecl of the base class that we + /// are searching for. + static bool FindVirtualBaseClass(const CXXBaseSpecifier *Specifier, + CXXBasePath &Path, void *BaseRecord); + + /// \brief Base-class lookup callback that determines whether there exists + /// a tag with the given name. + /// + /// This callback can be used with \c lookupInBases() to find tag members + /// of the given name within a C++ class hierarchy. The user data pointer + /// is an opaque \c DeclarationName pointer. + static bool FindTagMember(const CXXBaseSpecifier *Specifier, + CXXBasePath &Path, void *Name); + + /// \brief Base-class lookup callback that determines whether there exists + /// a member with the given name. + /// + /// This callback can be used with \c lookupInBases() to find members + /// of the given name within a C++ class hierarchy. The user data pointer + /// is an opaque \c DeclarationName pointer. + static bool FindOrdinaryMember(const CXXBaseSpecifier *Specifier, + CXXBasePath &Path, void *Name); + + /// \brief Base-class lookup callback that determines whether there exists + /// a member with the given name that can be used in a nested-name-specifier. + /// + /// This callback can be used with \c lookupInBases() to find membes of + /// the given name within a C++ class hierarchy that can occur within + /// nested-name-specifiers. + static bool FindNestedNameSpecifierMember(const CXXBaseSpecifier *Specifier, + CXXBasePath &Path, + void *UserData); + + /// \brief Retrieve the final overriders for each virtual member + /// function in the class hierarchy where this class is the + /// most-derived class in the class hierarchy. + void getFinalOverriders(CXXFinalOverriderMap &FinaOverriders) const; + + /// \brief Get the indirect primary bases for this class. + void getIndirectPrimaryBases(CXXIndirectPrimaryBaseSet& Bases) const; + + /// viewInheritance - Renders and displays an inheritance diagram + /// for this C++ class and all of its base classes (transitively) using + /// GraphViz. + void viewInheritance(ASTContext& Context) const; + + /// MergeAccess - Calculates the access of a decl that is reached + /// along a path. + static AccessSpecifier MergeAccess(AccessSpecifier PathAccess, + AccessSpecifier DeclAccess) { + assert(DeclAccess != AS_none); + if (DeclAccess == AS_private) return AS_none; + return (PathAccess > DeclAccess ? PathAccess : DeclAccess); + } + + /// \brief Indicates that the definition of this class is now complete. + virtual void completeDefinition(); + + /// \brief Indicates that the definition of this class is now complete, + /// and provides a final overrider map to help determine + /// + /// \param FinalOverriders The final overrider map for this class, which can + /// be provided as an optimization for abstract-class checking. If NULL, + /// final overriders will be computed if they are needed to complete the + /// definition. + void completeDefinition(CXXFinalOverriderMap *FinalOverriders); + + /// \brief Determine whether this class may end up being abstract, even though + /// it is not yet known to be abstract. + /// + /// \returns true if this class is not known to be abstract but has any + /// base classes that are abstract. In this case, \c completeDefinition() + /// will need to compute final overriders to determine whether the class is + /// actually abstract. + bool mayBeAbstract() const; + + /// \brief If this is the closure type of a lambda expression, retrieve the + /// number to be used for name mangling in the Itanium C++ ABI. + /// + /// Zero indicates that this closure type has internal linkage, so the + /// mangling number does not matter, while a non-zero value indicates which + /// lambda expression this is in this particular context. + unsigned getLambdaManglingNumber() const { + assert(isLambda() && "Not a lambda closure type!"); + return getLambdaData().ManglingNumber; + } + + /// \brief Retrieve the declaration that provides additional context for a + /// lambda, when the normal declaration context is not specific enough. + /// + /// Certain contexts (default arguments of in-class function parameters and + /// the initializers of data members) have separate name mangling rules for + /// lambdas within the Itanium C++ ABI. For these cases, this routine provides + /// the declaration in which the lambda occurs, e.g., the function parameter + /// or the non-static data member. Otherwise, it returns NULL to imply that + /// the declaration context suffices. + Decl *getLambdaContextDecl() const { + assert(isLambda() && "Not a lambda closure type!"); + return getLambdaData().ContextDecl; + } + + /// \brief Set the mangling number and context declaration for a lambda + /// class. + void setLambdaMangling(unsigned ManglingNumber, Decl *ContextDecl) { + getLambdaData().ManglingNumber = ManglingNumber; + getLambdaData().ContextDecl = ContextDecl; + } + + /// \brief Determine whether this lambda expression was known to be dependent + /// at the time it was created, even if its context does not appear to be + /// dependent. + /// + /// This flag is a workaround for an issue with parsing, where default + /// arguments are parsed before their enclosing function declarations have + /// been created. This means that any lambda expressions within those + /// default arguments will have as their DeclContext the context enclosing + /// the function declaration, which may be non-dependent even when the + /// function declaration itself is dependent. This flag indicates when we + /// know that the lambda is dependent despite that. + bool isDependentLambda() const { + return isLambda() && getLambdaData().Dependent; + } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { + return K >= firstCXXRecord && K <= lastCXXRecord; + } + static bool classof(const CXXRecordDecl *D) { return true; } + static bool classof(const ClassTemplateSpecializationDecl *D) { + return true; + } + + friend class ASTDeclReader; + friend class ASTDeclWriter; + friend class ASTReader; + friend class ASTWriter; +}; + +/// CXXMethodDecl - Represents a static or instance method of a +/// struct/union/class. +class CXXMethodDecl : public FunctionDecl { + virtual void anchor(); +protected: + CXXMethodDecl(Kind DK, CXXRecordDecl *RD, SourceLocation StartLoc, + const DeclarationNameInfo &NameInfo, + QualType T, TypeSourceInfo *TInfo, + bool isStatic, StorageClass SCAsWritten, bool isInline, + bool isConstexpr, SourceLocation EndLocation) + : FunctionDecl(DK, RD, StartLoc, NameInfo, T, TInfo, + (isStatic ? SC_Static : SC_None), + SCAsWritten, isInline, isConstexpr) { + if (EndLocation.isValid()) + setRangeEnd(EndLocation); + } + +public: + static CXXMethodDecl *Create(ASTContext &C, CXXRecordDecl *RD, + SourceLocation StartLoc, + const DeclarationNameInfo &NameInfo, + QualType T, TypeSourceInfo *TInfo, + bool isStatic, + StorageClass SCAsWritten, + bool isInline, + bool isConstexpr, + SourceLocation EndLocation); + + static CXXMethodDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + bool isStatic() const { return getStorageClass() == SC_Static; } + bool isInstance() const { return !isStatic(); } + + bool isVirtual() const { + CXXMethodDecl *CD = + cast<CXXMethodDecl>(const_cast<CXXMethodDecl*>(this)->getCanonicalDecl()); + + if (CD->isVirtualAsWritten()) + return true; + + return (CD->begin_overridden_methods() != CD->end_overridden_methods()); + } + + /// \brief Determine whether this is a usual deallocation function + /// (C++ [basic.stc.dynamic.deallocation]p2), which is an overloaded + /// delete or delete[] operator with a particular signature. + bool isUsualDeallocationFunction() const; + + /// \brief Determine whether this is a copy-assignment operator, regardless + /// of whether it was declared implicitly or explicitly. + bool isCopyAssignmentOperator() const; + + /// \brief Determine whether this is a move assignment operator. + bool isMoveAssignmentOperator() const; + + const CXXMethodDecl *getCanonicalDecl() const { + return cast<CXXMethodDecl>(FunctionDecl::getCanonicalDecl()); + } + CXXMethodDecl *getCanonicalDecl() { + return cast<CXXMethodDecl>(FunctionDecl::getCanonicalDecl()); + } + + /// isUserProvided - True if it is either an implicit constructor or + /// if it was defaulted or deleted on first declaration. + bool isUserProvided() const { + return !(isDeleted() || getCanonicalDecl()->isDefaulted()); + } + + /// + void addOverriddenMethod(const CXXMethodDecl *MD); + + typedef const CXXMethodDecl *const* method_iterator; + + method_iterator begin_overridden_methods() const; + method_iterator end_overridden_methods() const; + unsigned size_overridden_methods() const; + + /// getParent - Returns the parent of this method declaration, which + /// is the class in which this method is defined. + const CXXRecordDecl *getParent() const { + return cast<CXXRecordDecl>(FunctionDecl::getParent()); + } + + /// getParent - Returns the parent of this method declaration, which + /// is the class in which this method is defined. + CXXRecordDecl *getParent() { + return const_cast<CXXRecordDecl *>( + cast<CXXRecordDecl>(FunctionDecl::getParent())); + } + + /// getThisType - Returns the type of 'this' pointer. + /// Should only be called for instance methods. + QualType getThisType(ASTContext &C) const; + + unsigned getTypeQualifiers() const { + return getType()->getAs<FunctionProtoType>()->getTypeQuals(); + } + + /// \brief Retrieve the ref-qualifier associated with this method. + /// + /// In the following example, \c f() has an lvalue ref-qualifier, \c g() + /// has an rvalue ref-qualifier, and \c h() has no ref-qualifier. + /// \code + /// struct X { + /// void f() &; + /// void g() &&; + /// void h(); + /// }; + /// \endcode + RefQualifierKind getRefQualifier() const { + return getType()->getAs<FunctionProtoType>()->getRefQualifier(); + } + + bool hasInlineBody() const; + + /// \brief Determine whether this is a lambda closure type's static member + /// function that is used for the result of the lambda's conversion to + /// function pointer (for a lambda with no captures). + /// + /// The function itself, if used, will have a placeholder body that will be + /// supplied by IR generation to either forward to the function call operator + /// or clone the function call operator. + bool isLambdaStaticInvoker() const; + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const CXXMethodDecl *D) { return true; } + static bool classofKind(Kind K) { + return K >= firstCXXMethod && K <= lastCXXMethod; + } +}; + +/// CXXCtorInitializer - Represents a C++ base or member +/// initializer, which is part of a constructor initializer that +/// initializes one non-static member variable or one base class. For +/// example, in the following, both 'A(a)' and 'f(3.14159)' are member +/// initializers: +/// +/// @code +/// class A { }; +/// class B : public A { +/// float f; +/// public: +/// B(A& a) : A(a), f(3.14159) { } +/// }; +/// @endcode +class CXXCtorInitializer { + /// \brief Either the base class name/delegating constructor type (stored as + /// a TypeSourceInfo*), an normal field (FieldDecl), or an anonymous field + /// (IndirectFieldDecl*) being initialized. + llvm::PointerUnion3<TypeSourceInfo *, FieldDecl *, IndirectFieldDecl *> + Initializee; + + /// \brief The source location for the field name or, for a base initializer + /// pack expansion, the location of the ellipsis. In the case of a delegating + /// constructor, it will still include the type's source location as the + /// Initializee points to the CXXConstructorDecl (to allow loop detection). + SourceLocation MemberOrEllipsisLocation; + + /// \brief The argument used to initialize the base or member, which may + /// end up constructing an object (when multiple arguments are involved). + /// If 0, this is a field initializer, and the in-class member initializer + /// will be used. + Stmt *Init; + + /// LParenLoc - Location of the left paren of the ctor-initializer. + SourceLocation LParenLoc; + + /// RParenLoc - Location of the right paren of the ctor-initializer. + SourceLocation RParenLoc; + + /// \brief If the initializee is a type, whether that type makes this + /// a delegating initialization. + bool IsDelegating : 1; + + /// IsVirtual - If the initializer is a base initializer, this keeps track + /// of whether the base is virtual or not. + bool IsVirtual : 1; + + /// IsWritten - Whether or not the initializer is explicitly written + /// in the sources. + bool IsWritten : 1; + + /// SourceOrderOrNumArrayIndices - If IsWritten is true, then this + /// number keeps track of the textual order of this initializer in the + /// original sources, counting from 0; otherwise, if IsWritten is false, + /// it stores the number of array index variables stored after this + /// object in memory. + unsigned SourceOrderOrNumArrayIndices : 13; + + CXXCtorInitializer(ASTContext &Context, FieldDecl *Member, + SourceLocation MemberLoc, SourceLocation L, Expr *Init, + SourceLocation R, VarDecl **Indices, unsigned NumIndices); + +public: + /// CXXCtorInitializer - Creates a new base-class initializer. + explicit + CXXCtorInitializer(ASTContext &Context, TypeSourceInfo *TInfo, bool IsVirtual, + SourceLocation L, Expr *Init, SourceLocation R, + SourceLocation EllipsisLoc); + + /// CXXCtorInitializer - Creates a new member initializer. + explicit + CXXCtorInitializer(ASTContext &Context, FieldDecl *Member, + SourceLocation MemberLoc, SourceLocation L, Expr *Init, + SourceLocation R); + + /// CXXCtorInitializer - Creates a new anonymous field initializer. + explicit + CXXCtorInitializer(ASTContext &Context, IndirectFieldDecl *Member, + SourceLocation MemberLoc, SourceLocation L, Expr *Init, + SourceLocation R); + + /// CXXCtorInitializer - Creates a new delegating Initializer. + explicit + CXXCtorInitializer(ASTContext &Context, TypeSourceInfo *TInfo, + SourceLocation L, Expr *Init, SourceLocation R); + + /// \brief Creates a new member initializer that optionally contains + /// array indices used to describe an elementwise initialization. + static CXXCtorInitializer *Create(ASTContext &Context, FieldDecl *Member, + SourceLocation MemberLoc, SourceLocation L, + Expr *Init, SourceLocation R, + VarDecl **Indices, unsigned NumIndices); + + /// isBaseInitializer - Returns true when this initializer is + /// initializing a base class. + bool isBaseInitializer() const { + return Initializee.is<TypeSourceInfo*>() && !IsDelegating; + } + + /// isMemberInitializer - Returns true when this initializer is + /// initializing a non-static data member. + bool isMemberInitializer() const { return Initializee.is<FieldDecl*>(); } + + bool isAnyMemberInitializer() const { + return isMemberInitializer() || isIndirectMemberInitializer(); + } + + bool isIndirectMemberInitializer() const { + return Initializee.is<IndirectFieldDecl*>(); + } + + /// isInClassMemberInitializer - Returns true when this initializer is an + /// implicit ctor initializer generated for a field with an initializer + /// defined on the member declaration. + bool isInClassMemberInitializer() const { + return !Init; + } + + /// isDelegatingInitializer - Returns true when this initializer is creating + /// a delegating constructor. + bool isDelegatingInitializer() const { + return Initializee.is<TypeSourceInfo*>() && IsDelegating; + } + + /// \brief Determine whether this initializer is a pack expansion. + bool isPackExpansion() const { + return isBaseInitializer() && MemberOrEllipsisLocation.isValid(); + } + + // \brief For a pack expansion, returns the location of the ellipsis. + SourceLocation getEllipsisLoc() const { + assert(isPackExpansion() && "Initializer is not a pack expansion"); + return MemberOrEllipsisLocation; + } + + /// If this is a base class initializer, returns the type of the + /// base class with location information. Otherwise, returns an NULL + /// type location. + TypeLoc getBaseClassLoc() const; + + /// If this is a base class initializer, returns the type of the base class. + /// Otherwise, returns NULL. + const Type *getBaseClass() const; + + /// Returns whether the base is virtual or not. + bool isBaseVirtual() const { + assert(isBaseInitializer() && "Must call this on base initializer!"); + + return IsVirtual; + } + + /// \brief Returns the declarator information for a base class or delegating + /// initializer. + TypeSourceInfo *getTypeSourceInfo() const { + return Initializee.dyn_cast<TypeSourceInfo *>(); + } + + /// getMember - If this is a member initializer, returns the + /// declaration of the non-static data member being + /// initialized. Otherwise, returns NULL. + FieldDecl *getMember() const { + if (isMemberInitializer()) + return Initializee.get<FieldDecl*>(); + return 0; + } + FieldDecl *getAnyMember() const { + if (isMemberInitializer()) + return Initializee.get<FieldDecl*>(); + if (isIndirectMemberInitializer()) + return Initializee.get<IndirectFieldDecl*>()->getAnonField(); + return 0; + } + + IndirectFieldDecl *getIndirectMember() const { + if (isIndirectMemberInitializer()) + return Initializee.get<IndirectFieldDecl*>(); + return 0; + } + + SourceLocation getMemberLocation() const { + return MemberOrEllipsisLocation; + } + + /// \brief Determine the source location of the initializer. + SourceLocation getSourceLocation() const; + + /// \brief Determine the source range covering the entire initializer. + SourceRange getSourceRange() const LLVM_READONLY; + + /// isWritten - Returns true if this initializer is explicitly written + /// in the source code. + bool isWritten() const { return IsWritten; } + + /// \brief Return the source position of the initializer, counting from 0. + /// If the initializer was implicit, -1 is returned. + int getSourceOrder() const { + return IsWritten ? static_cast<int>(SourceOrderOrNumArrayIndices) : -1; + } + + /// \brief Set the source order of this initializer. This method can only + /// be called once for each initializer; it cannot be called on an + /// initializer having a positive number of (implicit) array indices. + void setSourceOrder(int pos) { + assert(!IsWritten && + "calling twice setSourceOrder() on the same initializer"); + assert(SourceOrderOrNumArrayIndices == 0 && + "setSourceOrder() used when there are implicit array indices"); + assert(pos >= 0 && + "setSourceOrder() used to make an initializer implicit"); + IsWritten = true; + SourceOrderOrNumArrayIndices = static_cast<unsigned>(pos); + } + + SourceLocation getLParenLoc() const { return LParenLoc; } + SourceLocation getRParenLoc() const { return RParenLoc; } + + /// \brief Determine the number of implicit array indices used while + /// described an array member initialization. + unsigned getNumArrayIndices() const { + return IsWritten ? 0 : SourceOrderOrNumArrayIndices; + } + + /// \brief Retrieve a particular array index variable used to + /// describe an array member initialization. + VarDecl *getArrayIndex(unsigned I) { + assert(I < getNumArrayIndices() && "Out of bounds member array index"); + return reinterpret_cast<VarDecl **>(this + 1)[I]; + } + const VarDecl *getArrayIndex(unsigned I) const { + assert(I < getNumArrayIndices() && "Out of bounds member array index"); + return reinterpret_cast<const VarDecl * const *>(this + 1)[I]; + } + void setArrayIndex(unsigned I, VarDecl *Index) { + assert(I < getNumArrayIndices() && "Out of bounds member array index"); + reinterpret_cast<VarDecl **>(this + 1)[I] = Index; + } + ArrayRef<VarDecl *> getArrayIndexes() { + assert(getNumArrayIndices() != 0 && "Getting indexes for non-array init"); + return ArrayRef<VarDecl *>(reinterpret_cast<VarDecl **>(this + 1), + getNumArrayIndices()); + } + + /// \brief Get the initializer. This is 0 if this is an in-class initializer + /// for a non-static data member which has not yet been parsed. + Expr *getInit() const { + if (!Init) + return getAnyMember()->getInClassInitializer(); + + return static_cast<Expr*>(Init); + } +}; + +/// CXXConstructorDecl - Represents a C++ constructor within a +/// class. For example: +/// +/// @code +/// class X { +/// public: +/// explicit X(int); // represented by a CXXConstructorDecl. +/// }; +/// @endcode +class CXXConstructorDecl : public CXXMethodDecl { + virtual void anchor(); + /// IsExplicitSpecified - Whether this constructor declaration has the + /// 'explicit' keyword specified. + bool IsExplicitSpecified : 1; + + /// ImplicitlyDefined - Whether this constructor was implicitly + /// defined by the compiler. When false, the constructor was defined + /// by the user. In C++03, this flag will have the same value as + /// Implicit. In C++0x, however, a constructor that is + /// explicitly defaulted (i.e., defined with " = default") will have + /// @c !Implicit && ImplicitlyDefined. + bool ImplicitlyDefined : 1; + + /// Support for base and member initializers. + /// CtorInitializers - The arguments used to initialize the base + /// or member. + CXXCtorInitializer **CtorInitializers; + unsigned NumCtorInitializers; + + CXXConstructorDecl(CXXRecordDecl *RD, SourceLocation StartLoc, + const DeclarationNameInfo &NameInfo, + QualType T, TypeSourceInfo *TInfo, + bool isExplicitSpecified, bool isInline, + bool isImplicitlyDeclared, bool isConstexpr) + : CXXMethodDecl(CXXConstructor, RD, StartLoc, NameInfo, T, TInfo, false, + SC_None, isInline, isConstexpr, SourceLocation()), + IsExplicitSpecified(isExplicitSpecified), ImplicitlyDefined(false), + CtorInitializers(0), NumCtorInitializers(0) { + setImplicit(isImplicitlyDeclared); + } + +public: + static CXXConstructorDecl *CreateDeserialized(ASTContext &C, unsigned ID); + static CXXConstructorDecl *Create(ASTContext &C, CXXRecordDecl *RD, + SourceLocation StartLoc, + const DeclarationNameInfo &NameInfo, + QualType T, TypeSourceInfo *TInfo, + bool isExplicit, + bool isInline, bool isImplicitlyDeclared, + bool isConstexpr); + + /// isExplicitSpecified - Whether this constructor declaration has the + /// 'explicit' keyword specified. + bool isExplicitSpecified() const { return IsExplicitSpecified; } + + /// isExplicit - Whether this constructor was marked "explicit" or not. + bool isExplicit() const { + return cast<CXXConstructorDecl>(getFirstDeclaration()) + ->isExplicitSpecified(); + } + + /// isImplicitlyDefined - Whether this constructor was implicitly + /// defined. If false, then this constructor was defined by the + /// user. This operation can only be invoked if the constructor has + /// already been defined. + bool isImplicitlyDefined() const { + assert(isThisDeclarationADefinition() && + "Can only get the implicit-definition flag once the " + "constructor has been defined"); + return ImplicitlyDefined; + } + + /// setImplicitlyDefined - Set whether this constructor was + /// implicitly defined or not. + void setImplicitlyDefined(bool ID) { + assert(isThisDeclarationADefinition() && + "Can only set the implicit-definition flag once the constructor " + "has been defined"); + ImplicitlyDefined = ID; + } + + /// init_iterator - Iterates through the member/base initializer list. + typedef CXXCtorInitializer **init_iterator; + + /// init_const_iterator - Iterates through the memberbase initializer list. + typedef CXXCtorInitializer * const * init_const_iterator; + + /// init_begin() - Retrieve an iterator to the first initializer. + init_iterator init_begin() { return CtorInitializers; } + /// begin() - Retrieve an iterator to the first initializer. + init_const_iterator init_begin() const { return CtorInitializers; } + + /// init_end() - Retrieve an iterator past the last initializer. + init_iterator init_end() { + return CtorInitializers + NumCtorInitializers; + } + /// end() - Retrieve an iterator past the last initializer. + init_const_iterator init_end() const { + return CtorInitializers + NumCtorInitializers; + } + + typedef std::reverse_iterator<init_iterator> init_reverse_iterator; + typedef std::reverse_iterator<init_const_iterator> + init_const_reverse_iterator; + + init_reverse_iterator init_rbegin() { + return init_reverse_iterator(init_end()); + } + init_const_reverse_iterator init_rbegin() const { + return init_const_reverse_iterator(init_end()); + } + + init_reverse_iterator init_rend() { + return init_reverse_iterator(init_begin()); + } + init_const_reverse_iterator init_rend() const { + return init_const_reverse_iterator(init_begin()); + } + + /// getNumArgs - Determine the number of arguments used to + /// initialize the member or base. + unsigned getNumCtorInitializers() const { + return NumCtorInitializers; + } + + void setNumCtorInitializers(unsigned numCtorInitializers) { + NumCtorInitializers = numCtorInitializers; + } + + void setCtorInitializers(CXXCtorInitializer ** initializers) { + CtorInitializers = initializers; + } + + /// isDelegatingConstructor - Whether this constructor is a + /// delegating constructor + bool isDelegatingConstructor() const { + return (getNumCtorInitializers() == 1) && + CtorInitializers[0]->isDelegatingInitializer(); + } + + /// getTargetConstructor - When this constructor delegates to + /// another, retrieve the target + CXXConstructorDecl *getTargetConstructor() const; + + /// isDefaultConstructor - Whether this constructor is a default + /// constructor (C++ [class.ctor]p5), which can be used to + /// default-initialize a class of this type. + bool isDefaultConstructor() const; + + /// isCopyConstructor - Whether this constructor is a copy + /// constructor (C++ [class.copy]p2, which can be used to copy the + /// class. @p TypeQuals will be set to the qualifiers on the + /// argument type. For example, @p TypeQuals would be set to @c + /// QualType::Const for the following copy constructor: + /// + /// @code + /// class X { + /// public: + /// X(const X&); + /// }; + /// @endcode + bool isCopyConstructor(unsigned &TypeQuals) const; + + /// isCopyConstructor - Whether this constructor is a copy + /// constructor (C++ [class.copy]p2, which can be used to copy the + /// class. + bool isCopyConstructor() const { + unsigned TypeQuals = 0; + return isCopyConstructor(TypeQuals); + } + + /// \brief Determine whether this constructor is a move constructor + /// (C++0x [class.copy]p3), which can be used to move values of the class. + /// + /// \param TypeQuals If this constructor is a move constructor, will be set + /// to the type qualifiers on the referent of the first parameter's type. + bool isMoveConstructor(unsigned &TypeQuals) const; + + /// \brief Determine whether this constructor is a move constructor + /// (C++0x [class.copy]p3), which can be used to move values of the class. + bool isMoveConstructor() const { + unsigned TypeQuals = 0; + return isMoveConstructor(TypeQuals); + } + + /// \brief Determine whether this is a copy or move constructor. + /// + /// \param TypeQuals Will be set to the type qualifiers on the reference + /// parameter, if in fact this is a copy or move constructor. + bool isCopyOrMoveConstructor(unsigned &TypeQuals) const; + + /// \brief Determine whether this a copy or move constructor. + bool isCopyOrMoveConstructor() const { + unsigned Quals; + return isCopyOrMoveConstructor(Quals); + } + + /// isConvertingConstructor - Whether this constructor is a + /// converting constructor (C++ [class.conv.ctor]), which can be + /// used for user-defined conversions. + bool isConvertingConstructor(bool AllowExplicit) const; + + /// \brief Determine whether this is a member template specialization that + /// would copy the object to itself. Such constructors are never used to copy + /// an object. + bool isSpecializationCopyingObject() const; + + /// \brief Get the constructor that this inheriting constructor is based on. + const CXXConstructorDecl *getInheritedConstructor() const; + + /// \brief Set the constructor that this inheriting constructor is based on. + void setInheritedConstructor(const CXXConstructorDecl *BaseCtor); + + const CXXConstructorDecl *getCanonicalDecl() const { + return cast<CXXConstructorDecl>(FunctionDecl::getCanonicalDecl()); + } + CXXConstructorDecl *getCanonicalDecl() { + return cast<CXXConstructorDecl>(FunctionDecl::getCanonicalDecl()); + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const CXXConstructorDecl *D) { return true; } + static bool classofKind(Kind K) { return K == CXXConstructor; } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +/// CXXDestructorDecl - Represents a C++ destructor within a +/// class. For example: +/// +/// @code +/// class X { +/// public: +/// ~X(); // represented by a CXXDestructorDecl. +/// }; +/// @endcode +class CXXDestructorDecl : public CXXMethodDecl { + virtual void anchor(); + /// ImplicitlyDefined - Whether this destructor was implicitly + /// defined by the compiler. When false, the destructor was defined + /// by the user. In C++03, this flag will have the same value as + /// Implicit. In C++0x, however, a destructor that is + /// explicitly defaulted (i.e., defined with " = default") will have + /// @c !Implicit && ImplicitlyDefined. + bool ImplicitlyDefined : 1; + + FunctionDecl *OperatorDelete; + + CXXDestructorDecl(CXXRecordDecl *RD, SourceLocation StartLoc, + const DeclarationNameInfo &NameInfo, + QualType T, TypeSourceInfo *TInfo, + bool isInline, bool isImplicitlyDeclared) + : CXXMethodDecl(CXXDestructor, RD, StartLoc, NameInfo, T, TInfo, false, + SC_None, isInline, /*isConstexpr=*/false, SourceLocation()), + ImplicitlyDefined(false), OperatorDelete(0) { + setImplicit(isImplicitlyDeclared); + } + +public: + static CXXDestructorDecl *Create(ASTContext &C, CXXRecordDecl *RD, + SourceLocation StartLoc, + const DeclarationNameInfo &NameInfo, + QualType T, TypeSourceInfo* TInfo, + bool isInline, + bool isImplicitlyDeclared); + static CXXDestructorDecl *CreateDeserialized(ASTContext & C, unsigned ID); + + /// isImplicitlyDefined - Whether this destructor was implicitly + /// defined. If false, then this destructor was defined by the + /// user. This operation can only be invoked if the destructor has + /// already been defined. + bool isImplicitlyDefined() const { + assert(isThisDeclarationADefinition() && + "Can only get the implicit-definition flag once the destructor has " + "been defined"); + return ImplicitlyDefined; + } + + /// setImplicitlyDefined - Set whether this destructor was + /// implicitly defined or not. + void setImplicitlyDefined(bool ID) { + assert(isThisDeclarationADefinition() && + "Can only set the implicit-definition flag once the destructor has " + "been defined"); + ImplicitlyDefined = ID; + } + + void setOperatorDelete(FunctionDecl *OD) { OperatorDelete = OD; } + const FunctionDecl *getOperatorDelete() const { return OperatorDelete; } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const CXXDestructorDecl *D) { return true; } + static bool classofKind(Kind K) { return K == CXXDestructor; } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +/// CXXConversionDecl - Represents a C++ conversion function within a +/// class. For example: +/// +/// @code +/// class X { +/// public: +/// operator bool(); +/// }; +/// @endcode +class CXXConversionDecl : public CXXMethodDecl { + virtual void anchor(); + /// IsExplicitSpecified - Whether this conversion function declaration is + /// marked "explicit", meaning that it can only be applied when the user + /// explicitly wrote a cast. This is a C++0x feature. + bool IsExplicitSpecified : 1; + + CXXConversionDecl(CXXRecordDecl *RD, SourceLocation StartLoc, + const DeclarationNameInfo &NameInfo, + QualType T, TypeSourceInfo *TInfo, + bool isInline, bool isExplicitSpecified, + bool isConstexpr, SourceLocation EndLocation) + : CXXMethodDecl(CXXConversion, RD, StartLoc, NameInfo, T, TInfo, false, + SC_None, isInline, isConstexpr, EndLocation), + IsExplicitSpecified(isExplicitSpecified) { } + +public: + static CXXConversionDecl *Create(ASTContext &C, CXXRecordDecl *RD, + SourceLocation StartLoc, + const DeclarationNameInfo &NameInfo, + QualType T, TypeSourceInfo *TInfo, + bool isInline, bool isExplicit, + bool isConstexpr, + SourceLocation EndLocation); + static CXXConversionDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + /// IsExplicitSpecified - Whether this conversion function declaration is + /// marked "explicit", meaning that it can only be applied when the user + /// explicitly wrote a cast. This is a C++0x feature. + bool isExplicitSpecified() const { return IsExplicitSpecified; } + + /// isExplicit - Whether this is an explicit conversion operator + /// (C++0x only). Explicit conversion operators are only considered + /// when the user has explicitly written a cast. + bool isExplicit() const { + return cast<CXXConversionDecl>(getFirstDeclaration()) + ->isExplicitSpecified(); + } + + /// getConversionType - Returns the type that this conversion + /// function is converting to. + QualType getConversionType() const { + return getType()->getAs<FunctionType>()->getResultType(); + } + + /// \brief Determine whether this conversion function is a conversion from + /// a lambda closure type to a block pointer. + bool isLambdaToBlockPointerConversion() const; + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const CXXConversionDecl *D) { return true; } + static bool classofKind(Kind K) { return K == CXXConversion; } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +/// LinkageSpecDecl - This represents a linkage specification. For example: +/// extern "C" void foo(); +/// +class LinkageSpecDecl : public Decl, public DeclContext { + virtual void anchor(); +public: + /// LanguageIDs - Used to represent the language in a linkage + /// specification. The values are part of the serialization abi for + /// ASTs and cannot be changed without altering that abi. To help + /// ensure a stable abi for this, we choose the DW_LANG_ encodings + /// from the dwarf standard. + enum LanguageIDs { + lang_c = /* DW_LANG_C */ 0x0002, + lang_cxx = /* DW_LANG_C_plus_plus */ 0x0004 + }; +private: + /// Language - The language for this linkage specification. + LanguageIDs Language; + /// ExternLoc - The source location for the extern keyword. + SourceLocation ExternLoc; + /// RBraceLoc - The source location for the right brace (if valid). + SourceLocation RBraceLoc; + + LinkageSpecDecl(DeclContext *DC, SourceLocation ExternLoc, + SourceLocation LangLoc, LanguageIDs lang, + SourceLocation RBLoc) + : Decl(LinkageSpec, DC, LangLoc), DeclContext(LinkageSpec), + Language(lang), ExternLoc(ExternLoc), RBraceLoc(RBLoc) { } + +public: + static LinkageSpecDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation ExternLoc, + SourceLocation LangLoc, LanguageIDs Lang, + SourceLocation RBraceLoc = SourceLocation()); + static LinkageSpecDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + /// \brief Return the language specified by this linkage specification. + LanguageIDs getLanguage() const { return Language; } + /// \brief Set the language specified by this linkage specification. + void setLanguage(LanguageIDs L) { Language = L; } + + /// \brief Determines whether this linkage specification had braces in + /// its syntactic form. + bool hasBraces() const { return RBraceLoc.isValid(); } + + SourceLocation getExternLoc() const { return ExternLoc; } + SourceLocation getRBraceLoc() const { return RBraceLoc; } + void setExternLoc(SourceLocation L) { ExternLoc = L; } + void setRBraceLoc(SourceLocation L) { RBraceLoc = L; } + + SourceLocation getLocEnd() const LLVM_READONLY { + if (hasBraces()) + return getRBraceLoc(); + // No braces: get the end location of the (only) declaration in context + // (if present). + return decls_empty() ? getLocation() : decls_begin()->getLocEnd(); + } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(ExternLoc, getLocEnd()); + } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const LinkageSpecDecl *D) { return true; } + static bool classofKind(Kind K) { return K == LinkageSpec; } + static DeclContext *castToDeclContext(const LinkageSpecDecl *D) { + return static_cast<DeclContext *>(const_cast<LinkageSpecDecl*>(D)); + } + static LinkageSpecDecl *castFromDeclContext(const DeclContext *DC) { + return static_cast<LinkageSpecDecl *>(const_cast<DeclContext*>(DC)); + } +}; + +/// UsingDirectiveDecl - Represents C++ using-directive. For example: +/// +/// using namespace std; +/// +// NB: UsingDirectiveDecl should be Decl not NamedDecl, but we provide +// artificial names for all using-directives in order to store +// them in DeclContext effectively. +class UsingDirectiveDecl : public NamedDecl { + virtual void anchor(); + /// \brief The location of the "using" keyword. + SourceLocation UsingLoc; + + /// SourceLocation - Location of 'namespace' token. + SourceLocation NamespaceLoc; + + /// \brief The nested-name-specifier that precedes the namespace. + NestedNameSpecifierLoc QualifierLoc; + + /// NominatedNamespace - Namespace nominated by using-directive. + NamedDecl *NominatedNamespace; + + /// Enclosing context containing both using-directive and nominated + /// namespace. + DeclContext *CommonAncestor; + + /// getUsingDirectiveName - Returns special DeclarationName used by + /// using-directives. This is only used by DeclContext for storing + /// UsingDirectiveDecls in its lookup structure. + static DeclarationName getName() { + return DeclarationName::getUsingDirectiveName(); + } + + UsingDirectiveDecl(DeclContext *DC, SourceLocation UsingLoc, + SourceLocation NamespcLoc, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation IdentLoc, + NamedDecl *Nominated, + DeclContext *CommonAncestor) + : NamedDecl(UsingDirective, DC, IdentLoc, getName()), UsingLoc(UsingLoc), + NamespaceLoc(NamespcLoc), QualifierLoc(QualifierLoc), + NominatedNamespace(Nominated), CommonAncestor(CommonAncestor) { } + +public: + /// \brief Retrieve the nested-name-specifier that qualifies the + /// name of the namespace, with source-location information. + NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; } + + /// \brief Retrieve the nested-name-specifier that qualifies the + /// name of the namespace. + NestedNameSpecifier *getQualifier() const { + return QualifierLoc.getNestedNameSpecifier(); + } + + NamedDecl *getNominatedNamespaceAsWritten() { return NominatedNamespace; } + const NamedDecl *getNominatedNamespaceAsWritten() const { + return NominatedNamespace; + } + + /// getNominatedNamespace - Returns namespace nominated by using-directive. + NamespaceDecl *getNominatedNamespace(); + + const NamespaceDecl *getNominatedNamespace() const { + return const_cast<UsingDirectiveDecl*>(this)->getNominatedNamespace(); + } + + /// \brief Returns the common ancestor context of this using-directive and + /// its nominated namespace. + DeclContext *getCommonAncestor() { return CommonAncestor; } + const DeclContext *getCommonAncestor() const { return CommonAncestor; } + + /// \brief Return the location of the "using" keyword. + SourceLocation getUsingLoc() const { return UsingLoc; } + + // FIXME: Could omit 'Key' in name. + /// getNamespaceKeyLocation - Returns location of namespace keyword. + SourceLocation getNamespaceKeyLocation() const { return NamespaceLoc; } + + /// getIdentLocation - Returns location of identifier. + SourceLocation getIdentLocation() const { return getLocation(); } + + static UsingDirectiveDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation UsingLoc, + SourceLocation NamespaceLoc, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation IdentLoc, + NamedDecl *Nominated, + DeclContext *CommonAncestor); + static UsingDirectiveDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(UsingLoc, getLocation()); + } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const UsingDirectiveDecl *D) { return true; } + static bool classofKind(Kind K) { return K == UsingDirective; } + + // Friend for getUsingDirectiveName. + friend class DeclContext; + + friend class ASTDeclReader; +}; + +/// NamespaceAliasDecl - Represents a C++ namespace alias. For example: +/// +/// @code +/// namespace Foo = Bar; +/// @endcode +class NamespaceAliasDecl : public NamedDecl { + virtual void anchor(); + + /// \brief The location of the "namespace" keyword. + SourceLocation NamespaceLoc; + + /// IdentLoc - Location of namespace identifier. Accessed by TargetNameLoc. + SourceLocation IdentLoc; + + /// \brief The nested-name-specifier that precedes the namespace. + NestedNameSpecifierLoc QualifierLoc; + + /// Namespace - The Decl that this alias points to. Can either be a + /// NamespaceDecl or a NamespaceAliasDecl. + NamedDecl *Namespace; + + NamespaceAliasDecl(DeclContext *DC, SourceLocation NamespaceLoc, + SourceLocation AliasLoc, IdentifierInfo *Alias, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation IdentLoc, NamedDecl *Namespace) + : NamedDecl(NamespaceAlias, DC, AliasLoc, Alias), + NamespaceLoc(NamespaceLoc), IdentLoc(IdentLoc), + QualifierLoc(QualifierLoc), Namespace(Namespace) { } + + friend class ASTDeclReader; + +public: + /// \brief Retrieve the nested-name-specifier that qualifies the + /// name of the namespace, with source-location information. + NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; } + + /// \brief Retrieve the nested-name-specifier that qualifies the + /// name of the namespace. + NestedNameSpecifier *getQualifier() const { + return QualifierLoc.getNestedNameSpecifier(); + } + + /// \brief Retrieve the namespace declaration aliased by this directive. + NamespaceDecl *getNamespace() { + if (NamespaceAliasDecl *AD = dyn_cast<NamespaceAliasDecl>(Namespace)) + return AD->getNamespace(); + + return cast<NamespaceDecl>(Namespace); + } + + const NamespaceDecl *getNamespace() const { + return const_cast<NamespaceAliasDecl*>(this)->getNamespace(); + } + + /// Returns the location of the alias name, i.e. 'foo' in + /// "namespace foo = ns::bar;". + SourceLocation getAliasLoc() const { return getLocation(); } + + /// Returns the location of the 'namespace' keyword. + SourceLocation getNamespaceLoc() const { return NamespaceLoc; } + + /// Returns the location of the identifier in the named namespace. + SourceLocation getTargetNameLoc() const { return IdentLoc; } + + /// \brief Retrieve the namespace that this alias refers to, which + /// may either be a NamespaceDecl or a NamespaceAliasDecl. + NamedDecl *getAliasedNamespace() const { return Namespace; } + + static NamespaceAliasDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation NamespaceLoc, + SourceLocation AliasLoc, + IdentifierInfo *Alias, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation IdentLoc, + NamedDecl *Namespace); + + static NamespaceAliasDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + virtual SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(NamespaceLoc, IdentLoc); + } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const NamespaceAliasDecl *D) { return true; } + static bool classofKind(Kind K) { return K == NamespaceAlias; } +}; + +/// UsingShadowDecl - Represents a shadow declaration introduced into +/// a scope by a (resolved) using declaration. For example, +/// +/// namespace A { +/// void foo(); +/// } +/// namespace B { +/// using A::foo(); // <- a UsingDecl +/// // Also creates a UsingShadowDecl for A::foo in B +/// } +/// +class UsingShadowDecl : public NamedDecl { + virtual void anchor(); + + /// The referenced declaration. + NamedDecl *Underlying; + + /// \brief The using declaration which introduced this decl or the next using + /// shadow declaration contained in the aforementioned using declaration. + NamedDecl *UsingOrNextShadow; + friend class UsingDecl; + + UsingShadowDecl(DeclContext *DC, SourceLocation Loc, UsingDecl *Using, + NamedDecl *Target) + : NamedDecl(UsingShadow, DC, Loc, DeclarationName()), + Underlying(Target), + UsingOrNextShadow(reinterpret_cast<NamedDecl *>(Using)) { + if (Target) { + setDeclName(Target->getDeclName()); + IdentifierNamespace = Target->getIdentifierNamespace(); + } + setImplicit(); + } + +public: + static UsingShadowDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation Loc, UsingDecl *Using, + NamedDecl *Target) { + return new (C) UsingShadowDecl(DC, Loc, Using, Target); + } + + static UsingShadowDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + /// \brief Gets the underlying declaration which has been brought into the + /// local scope. + NamedDecl *getTargetDecl() const { return Underlying; } + + /// \brief Sets the underlying declaration which has been brought into the + /// local scope. + void setTargetDecl(NamedDecl* ND) { + assert(ND && "Target decl is null!"); + Underlying = ND; + IdentifierNamespace = ND->getIdentifierNamespace(); + } + + /// \brief Gets the using declaration to which this declaration is tied. + UsingDecl *getUsingDecl() const; + + /// \brief The next using shadow declaration contained in the shadow decl + /// chain of the using declaration which introduced this decl. + UsingShadowDecl *getNextUsingShadowDecl() const { + return dyn_cast_or_null<UsingShadowDecl>(UsingOrNextShadow); + } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const UsingShadowDecl *D) { return true; } + static bool classofKind(Kind K) { return K == Decl::UsingShadow; } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +/// UsingDecl - Represents a C++ using-declaration. For example: +/// using someNameSpace::someIdentifier; +class UsingDecl : public NamedDecl { + virtual void anchor(); + + /// \brief The source location of the "using" location itself. + SourceLocation UsingLocation; + + /// \brief The nested-name-specifier that precedes the name. + NestedNameSpecifierLoc QualifierLoc; + + /// DNLoc - Provides source/type location info for the + /// declaration name embedded in the ValueDecl base class. + DeclarationNameLoc DNLoc; + + /// \brief The first shadow declaration of the shadow decl chain associated + /// with this using declaration. The bool member of the pair store whether + /// this decl has the 'typename' keyword. + llvm::PointerIntPair<UsingShadowDecl *, 1, bool> FirstUsingShadow; + + UsingDecl(DeclContext *DC, SourceLocation UL, + NestedNameSpecifierLoc QualifierLoc, + const DeclarationNameInfo &NameInfo, bool IsTypeNameArg) + : NamedDecl(Using, DC, NameInfo.getLoc(), NameInfo.getName()), + UsingLocation(UL), QualifierLoc(QualifierLoc), + DNLoc(NameInfo.getInfo()), FirstUsingShadow(0, IsTypeNameArg) { + } + +public: + /// \brief Returns the source location of the "using" keyword. + SourceLocation getUsingLocation() const { return UsingLocation; } + + /// \brief Set the source location of the 'using' keyword. + void setUsingLocation(SourceLocation L) { UsingLocation = L; } + + /// \brief Retrieve the nested-name-specifier that qualifies the name, + /// with source-location information. + NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; } + + /// \brief Retrieve the nested-name-specifier that qualifies the name. + NestedNameSpecifier *getQualifier() const { + return QualifierLoc.getNestedNameSpecifier(); + } + + DeclarationNameInfo getNameInfo() const { + return DeclarationNameInfo(getDeclName(), getLocation(), DNLoc); + } + + /// \brief Return true if the using declaration has 'typename'. + bool isTypeName() const { return FirstUsingShadow.getInt(); } + + /// \brief Sets whether the using declaration has 'typename'. + void setTypeName(bool TN) { FirstUsingShadow.setInt(TN); } + + /// \brief Iterates through the using shadow declarations assosiated with + /// this using declaration. + class shadow_iterator { + /// \brief The current using shadow declaration. + UsingShadowDecl *Current; + + public: + typedef UsingShadowDecl* value_type; + typedef UsingShadowDecl* reference; + typedef UsingShadowDecl* pointer; + typedef std::forward_iterator_tag iterator_category; + typedef std::ptrdiff_t difference_type; + + shadow_iterator() : Current(0) { } + explicit shadow_iterator(UsingShadowDecl *C) : Current(C) { } + + reference operator*() const { return Current; } + pointer operator->() const { return Current; } + + shadow_iterator& operator++() { + Current = Current->getNextUsingShadowDecl(); + return *this; + } + + shadow_iterator operator++(int) { + shadow_iterator tmp(*this); + ++(*this); + return tmp; + } + + friend bool operator==(shadow_iterator x, shadow_iterator y) { + return x.Current == y.Current; + } + friend bool operator!=(shadow_iterator x, shadow_iterator y) { + return x.Current != y.Current; + } + }; + + shadow_iterator shadow_begin() const { + return shadow_iterator(FirstUsingShadow.getPointer()); + } + shadow_iterator shadow_end() const { return shadow_iterator(); } + + /// \brief Return the number of shadowed declarations associated with this + /// using declaration. + unsigned shadow_size() const { + return std::distance(shadow_begin(), shadow_end()); + } + + void addShadowDecl(UsingShadowDecl *S); + void removeShadowDecl(UsingShadowDecl *S); + + static UsingDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation UsingL, + NestedNameSpecifierLoc QualifierLoc, + const DeclarationNameInfo &NameInfo, + bool IsTypeNameArg); + + static UsingDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(UsingLocation, getNameInfo().getEndLoc()); + } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const UsingDecl *D) { return true; } + static bool classofKind(Kind K) { return K == Using; } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +/// UnresolvedUsingValueDecl - Represents a dependent using +/// declaration which was not marked with 'typename'. Unlike +/// non-dependent using declarations, these *only* bring through +/// non-types; otherwise they would break two-phase lookup. +/// +/// template <class T> class A : public Base<T> { +/// using Base<T>::foo; +/// }; +class UnresolvedUsingValueDecl : public ValueDecl { + virtual void anchor(); + + /// \brief The source location of the 'using' keyword + SourceLocation UsingLocation; + + /// \brief The nested-name-specifier that precedes the name. + NestedNameSpecifierLoc QualifierLoc; + + /// DNLoc - Provides source/type location info for the + /// declaration name embedded in the ValueDecl base class. + DeclarationNameLoc DNLoc; + + UnresolvedUsingValueDecl(DeclContext *DC, QualType Ty, + SourceLocation UsingLoc, + NestedNameSpecifierLoc QualifierLoc, + const DeclarationNameInfo &NameInfo) + : ValueDecl(UnresolvedUsingValue, DC, + NameInfo.getLoc(), NameInfo.getName(), Ty), + UsingLocation(UsingLoc), QualifierLoc(QualifierLoc), + DNLoc(NameInfo.getInfo()) + { } + +public: + /// \brief Returns the source location of the 'using' keyword. + SourceLocation getUsingLoc() const { return UsingLocation; } + + /// \brief Set the source location of the 'using' keyword. + void setUsingLoc(SourceLocation L) { UsingLocation = L; } + + /// \brief Retrieve the nested-name-specifier that qualifies the name, + /// with source-location information. + NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; } + + /// \brief Retrieve the nested-name-specifier that qualifies the name. + NestedNameSpecifier *getQualifier() const { + return QualifierLoc.getNestedNameSpecifier(); + } + + DeclarationNameInfo getNameInfo() const { + return DeclarationNameInfo(getDeclName(), getLocation(), DNLoc); + } + + static UnresolvedUsingValueDecl * + Create(ASTContext &C, DeclContext *DC, SourceLocation UsingLoc, + NestedNameSpecifierLoc QualifierLoc, + const DeclarationNameInfo &NameInfo); + + static UnresolvedUsingValueDecl * + CreateDeserialized(ASTContext &C, unsigned ID); + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(UsingLocation, getNameInfo().getEndLoc()); + } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const UnresolvedUsingValueDecl *D) { return true; } + static bool classofKind(Kind K) { return K == UnresolvedUsingValue; } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +/// UnresolvedUsingTypenameDecl - Represents a dependent using +/// declaration which was marked with 'typename'. +/// +/// template <class T> class A : public Base<T> { +/// using typename Base<T>::foo; +/// }; +/// +/// The type associated with a unresolved using typename decl is +/// currently always a typename type. +class UnresolvedUsingTypenameDecl : public TypeDecl { + virtual void anchor(); + + /// \brief The source location of the 'using' keyword + SourceLocation UsingLocation; + + /// \brief The source location of the 'typename' keyword + SourceLocation TypenameLocation; + + /// \brief The nested-name-specifier that precedes the name. + NestedNameSpecifierLoc QualifierLoc; + + UnresolvedUsingTypenameDecl(DeclContext *DC, SourceLocation UsingLoc, + SourceLocation TypenameLoc, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation TargetNameLoc, + IdentifierInfo *TargetName) + : TypeDecl(UnresolvedUsingTypename, DC, TargetNameLoc, TargetName, + UsingLoc), + TypenameLocation(TypenameLoc), QualifierLoc(QualifierLoc) { } + + friend class ASTDeclReader; + +public: + /// \brief Returns the source location of the 'using' keyword. + SourceLocation getUsingLoc() const { return getLocStart(); } + + /// \brief Returns the source location of the 'typename' keyword. + SourceLocation getTypenameLoc() const { return TypenameLocation; } + + /// \brief Retrieve the nested-name-specifier that qualifies the name, + /// with source-location information. + NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; } + + /// \brief Retrieve the nested-name-specifier that qualifies the name. + NestedNameSpecifier *getQualifier() const { + return QualifierLoc.getNestedNameSpecifier(); + } + + static UnresolvedUsingTypenameDecl * + Create(ASTContext &C, DeclContext *DC, SourceLocation UsingLoc, + SourceLocation TypenameLoc, NestedNameSpecifierLoc QualifierLoc, + SourceLocation TargetNameLoc, DeclarationName TargetName); + + static UnresolvedUsingTypenameDecl * + CreateDeserialized(ASTContext &C, unsigned ID); + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const UnresolvedUsingTypenameDecl *D) { return true; } + static bool classofKind(Kind K) { return K == UnresolvedUsingTypename; } +}; + +/// StaticAssertDecl - Represents a C++0x static_assert declaration. +class StaticAssertDecl : public Decl { + virtual void anchor(); + Expr *AssertExpr; + StringLiteral *Message; + SourceLocation RParenLoc; + + StaticAssertDecl(DeclContext *DC, SourceLocation StaticAssertLoc, + Expr *assertexpr, StringLiteral *message, + SourceLocation RParenLoc) + : Decl(StaticAssert, DC, StaticAssertLoc), AssertExpr(assertexpr), + Message(message), RParenLoc(RParenLoc) { } + +public: + static StaticAssertDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation StaticAssertLoc, + Expr *AssertExpr, StringLiteral *Message, + SourceLocation RParenLoc); + static StaticAssertDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + Expr *getAssertExpr() { return AssertExpr; } + const Expr *getAssertExpr() const { return AssertExpr; } + + StringLiteral *getMessage() { return Message; } + const StringLiteral *getMessage() const { return Message; } + + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(getLocation(), getRParenLoc()); + } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(StaticAssertDecl *D) { return true; } + static bool classofKind(Kind K) { return K == StaticAssert; } + + friend class ASTDeclReader; +}; + +/// Insertion operator for diagnostics. This allows sending AccessSpecifier's +/// into a diagnostic with <<. +const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + AccessSpecifier AS); + +const PartialDiagnostic &operator<<(const PartialDiagnostic &DB, + AccessSpecifier AS); + +} // end namespace clang + +#endif diff --git a/clang/include/clang/AST/DeclContextInternals.h b/clang/include/clang/AST/DeclContextInternals.h new file mode 100644 index 0000000..c5f2aa0 --- /dev/null +++ b/clang/include/clang/AST/DeclContextInternals.h @@ -0,0 +1,223 @@ +//===-- DeclContextInternals.h - DeclContext Representation -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the data structures used in the implementation +// of DeclContext. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_AST_DECLCONTEXTINTERNALS_H +#define LLVM_CLANG_AST_DECLCONTEXTINTERNALS_H + +#include "clang/AST/Decl.h" +#include "clang/AST/DeclarationName.h" +#include "clang/AST/DeclCXX.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/SmallVector.h" +#include <algorithm> + +namespace clang { + +class DependentDiagnostic; + +/// StoredDeclsList - This is an array of decls optimized a common case of only +/// containing one entry. +struct StoredDeclsList { + + /// DeclsTy - When in vector form, this is what the Data pointer points to. + typedef SmallVector<NamedDecl *, 4> DeclsTy; + + /// \brief The stored data, which will be either a pointer to a NamedDecl, + /// or a pointer to a vector. + llvm::PointerUnion<NamedDecl *, DeclsTy *> Data; + +public: + StoredDeclsList() {} + + StoredDeclsList(const StoredDeclsList &RHS) : Data(RHS.Data) { + if (DeclsTy *RHSVec = RHS.getAsVector()) + Data = new DeclsTy(*RHSVec); + } + + ~StoredDeclsList() { + // If this is a vector-form, free the vector. + if (DeclsTy *Vector = getAsVector()) + delete Vector; + } + + StoredDeclsList &operator=(const StoredDeclsList &RHS) { + if (DeclsTy *Vector = getAsVector()) + delete Vector; + Data = RHS.Data; + if (DeclsTy *RHSVec = RHS.getAsVector()) + Data = new DeclsTy(*RHSVec); + return *this; + } + + bool isNull() const { return Data.isNull(); } + + NamedDecl *getAsDecl() const { + return Data.dyn_cast<NamedDecl *>(); + } + + DeclsTy *getAsVector() const { + return Data.dyn_cast<DeclsTy *>(); + } + + void setOnlyValue(NamedDecl *ND) { + assert(!getAsVector() && "Not inline"); + Data = ND; + // Make sure that Data is a plain NamedDecl* so we can use its address + // at getLookupResult. + assert(*(NamedDecl **)&Data == ND && + "PointerUnion mangles the NamedDecl pointer!"); + } + + void remove(NamedDecl *D) { + assert(!isNull() && "removing from empty list"); + if (NamedDecl *Singleton = getAsDecl()) { + assert(Singleton == D && "list is different singleton"); + (void)Singleton; + Data = (NamedDecl *)0; + return; + } + + DeclsTy &Vec = *getAsVector(); + DeclsTy::iterator I = std::find(Vec.begin(), Vec.end(), D); + assert(I != Vec.end() && "list does not contain decl"); + Vec.erase(I); + + assert(std::find(Vec.begin(), Vec.end(), D) + == Vec.end() && "list still contains decl"); + } + + /// getLookupResult - Return an array of all the decls that this list + /// represents. + DeclContext::lookup_result getLookupResult() { + if (isNull()) + return DeclContext::lookup_result(DeclContext::lookup_iterator(0), + DeclContext::lookup_iterator(0)); + + // If we have a single NamedDecl, return it. + if (getAsDecl()) { + assert(!isNull() && "Empty list isn't allowed"); + + // Data is a raw pointer to a NamedDecl*, return it. + void *Ptr = &Data; + return DeclContext::lookup_result((NamedDecl**)Ptr, (NamedDecl**)Ptr+1); + } + + assert(getAsVector() && "Must have a vector at this point"); + DeclsTy &Vector = *getAsVector(); + + // Otherwise, we have a range result. + return DeclContext::lookup_result(&Vector[0], &Vector[0]+Vector.size()); + } + + /// HandleRedeclaration - If this is a redeclaration of an existing decl, + /// replace the old one with D and return true. Otherwise return false. + bool HandleRedeclaration(NamedDecl *D) { + // Most decls only have one entry in their list, special case it. + if (NamedDecl *OldD = getAsDecl()) { + if (!D->declarationReplaces(OldD)) + return false; + setOnlyValue(D); + return true; + } + + // Determine if this declaration is actually a redeclaration. + DeclsTy &Vec = *getAsVector(); + for (DeclsTy::iterator OD = Vec.begin(), ODEnd = Vec.end(); + OD != ODEnd; ++OD) { + NamedDecl *OldD = *OD; + if (D->declarationReplaces(OldD)) { + *OD = D; + return true; + } + } + + return false; + } + + /// AddSubsequentDecl - This is called on the second and later decl when it is + /// not a redeclaration to merge it into the appropriate place in our list. + /// + void AddSubsequentDecl(NamedDecl *D) { + // If this is the second decl added to the list, convert this to vector + // form. + if (NamedDecl *OldD = getAsDecl()) { + DeclsTy *VT = new DeclsTy(); + VT->push_back(OldD); + Data = VT; + } + + DeclsTy &Vec = *getAsVector(); + + // Using directives end up in a special entry which contains only + // other using directives, so all this logic is wasted for them. + // But avoiding the logic wastes time in the far-more-common case + // that we're *not* adding a new using directive. + + // Tag declarations always go at the end of the list so that an + // iterator which points at the first tag will start a span of + // decls that only contains tags. + if (D->hasTagIdentifierNamespace()) + Vec.push_back(D); + + // Resolved using declarations go at the front of the list so that + // they won't show up in other lookup results. Unresolved using + // declarations (which are always in IDNS_Using | IDNS_Ordinary) + // follow that so that the using declarations will be contiguous. + else if (D->getIdentifierNamespace() & Decl::IDNS_Using) { + DeclsTy::iterator I = Vec.begin(); + if (D->getIdentifierNamespace() != Decl::IDNS_Using) { + while (I != Vec.end() && + (*I)->getIdentifierNamespace() == Decl::IDNS_Using) + ++I; + } + Vec.insert(I, D); + + // All other declarations go at the end of the list, but before any + // tag declarations. But we can be clever about tag declarations + // because there can only ever be one in a scope. + } else if (Vec.back()->hasTagIdentifierNamespace()) { + NamedDecl *TagD = Vec.back(); + Vec.back() = D; + Vec.push_back(TagD); + } else + Vec.push_back(D); + } +}; + +class StoredDeclsMap + : public llvm::DenseMap<DeclarationName, StoredDeclsList> { + +public: + static void DestroyAll(StoredDeclsMap *Map, bool Dependent); + +private: + friend class ASTContext; // walks the chain deleting these + friend class DeclContext; + llvm::PointerIntPair<StoredDeclsMap*, 1> Previous; +}; + +class DependentStoredDeclsMap : public StoredDeclsMap { +public: + DependentStoredDeclsMap() : FirstDiagnostic(0) {} + +private: + friend class DependentDiagnostic; + friend class DeclContext; // iterates over diagnostics + + DependentDiagnostic *FirstDiagnostic; +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/AST/DeclFriend.h b/clang/include/clang/AST/DeclFriend.h new file mode 100644 index 0000000..ba1eb8d --- /dev/null +++ b/clang/include/clang/AST/DeclFriend.h @@ -0,0 +1,198 @@ +//===-- DeclFriend.h - Classes for C++ friend declarations -*- C++ -*------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the section of the AST representing C++ friend +// declarations. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_DECLFRIEND_H +#define LLVM_CLANG_AST_DECLFRIEND_H + +#include "clang/AST/DeclCXX.h" +#include "llvm/Support/Compiler.h" + +namespace clang { + +/// FriendDecl - Represents the declaration of a friend entity, +/// which can be a function, a type, or a templated function or type. +// For example: +/// +/// @code +/// template <typename T> class A { +/// friend int foo(T); +/// friend class B; +/// friend T; // only in C++0x +/// template <typename U> friend class C; +/// template <typename U> friend A& operator+=(A&, const U&) { ... } +/// }; +/// @endcode +/// +/// The semantic context of a friend decl is its declaring class. +class FriendDecl : public Decl { + virtual void anchor(); +public: + typedef llvm::PointerUnion<NamedDecl*,TypeSourceInfo*> FriendUnion; + +private: + // The declaration that's a friend of this class. + FriendUnion Friend; + + // A pointer to the next friend in the sequence. + LazyDeclPtr NextFriend; + + // Location of the 'friend' specifier. + SourceLocation FriendLoc; + + /// True if this 'friend' declaration is unsupported. Eventually we + /// will support every possible friend declaration, but for now we + /// silently ignore some and set this flag to authorize all access. + bool UnsupportedFriend; + + friend class CXXRecordDecl::friend_iterator; + friend class CXXRecordDecl; + + FriendDecl(DeclContext *DC, SourceLocation L, FriendUnion Friend, + SourceLocation FriendL) + : Decl(Decl::Friend, DC, L), + Friend(Friend), + NextFriend(), + FriendLoc(FriendL), + UnsupportedFriend(false) { + } + + explicit FriendDecl(EmptyShell Empty) + : Decl(Decl::Friend, Empty), NextFriend() { } + + FriendDecl *getNextFriend() { + return cast_or_null<FriendDecl>( + NextFriend.get(getASTContext().getExternalSource())); + } + +public: + static FriendDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, FriendUnion Friend_, + SourceLocation FriendL); + static FriendDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + /// If this friend declaration names an (untemplated but possibly + /// dependent) type, return the type; otherwise return null. This + /// is used for elaborated-type-specifiers and, in C++0x, for + /// arbitrary friend type declarations. + TypeSourceInfo *getFriendType() const { + return Friend.dyn_cast<TypeSourceInfo*>(); + } + + /// If this friend declaration doesn't name a type, return the inner + /// declaration. + NamedDecl *getFriendDecl() const { + return Friend.dyn_cast<NamedDecl*>(); + } + + /// Retrieves the location of the 'friend' keyword. + SourceLocation getFriendLoc() const { + return FriendLoc; + } + + /// Retrieves the source range for the friend declaration. + SourceRange getSourceRange() const LLVM_READONLY { + /* FIXME: consider the case of templates wrt start of range. */ + if (NamedDecl *ND = getFriendDecl()) + return SourceRange(getFriendLoc(), ND->getLocEnd()); + else if (TypeSourceInfo *TInfo = getFriendType()) + return SourceRange(getFriendLoc(), TInfo->getTypeLoc().getEndLoc()); + else + return SourceRange(getFriendLoc(), getLocation()); + } + + /// Determines if this friend kind is unsupported. + bool isUnsupportedFriend() const { + return UnsupportedFriend; + } + void setUnsupportedFriend(bool Unsupported) { + UnsupportedFriend = Unsupported; + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const FriendDecl *D) { return true; } + static bool classofKind(Kind K) { return K == Decl::Friend; } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +/// An iterator over the friend declarations of a class. +class CXXRecordDecl::friend_iterator { + FriendDecl *Ptr; + + friend class CXXRecordDecl; + explicit friend_iterator(FriendDecl *Ptr) : Ptr(Ptr) {} +public: + friend_iterator() {} + + typedef FriendDecl *value_type; + typedef FriendDecl *reference; + typedef FriendDecl *pointer; + typedef int difference_type; + typedef std::forward_iterator_tag iterator_category; + + reference operator*() const { return Ptr; } + + friend_iterator &operator++() { + assert(Ptr && "attempt to increment past end of friend list"); + Ptr = Ptr->getNextFriend(); + return *this; + } + + friend_iterator operator++(int) { + friend_iterator tmp = *this; + ++*this; + return tmp; + } + + bool operator==(const friend_iterator &Other) const { + return Ptr == Other.Ptr; + } + + bool operator!=(const friend_iterator &Other) const { + return Ptr != Other.Ptr; + } + + friend_iterator &operator+=(difference_type N) { + assert(N >= 0 && "cannot rewind a CXXRecordDecl::friend_iterator"); + while (N--) + ++*this; + return *this; + } + + friend_iterator operator+(difference_type N) const { + friend_iterator tmp = *this; + tmp += N; + return tmp; + } +}; + +inline CXXRecordDecl::friend_iterator CXXRecordDecl::friend_begin() const { + return friend_iterator(data().FirstFriend); +} + +inline CXXRecordDecl::friend_iterator CXXRecordDecl::friend_end() const { + return friend_iterator(0); +} + +inline void CXXRecordDecl::pushFriendDecl(FriendDecl *FD) { + assert(FD->NextFriend == 0 && "friend already has next friend?"); + FD->NextFriend = data().FirstFriend; + data().FirstFriend = FD; +} + +} + +#endif diff --git a/clang/include/clang/AST/DeclGroup.h b/clang/include/clang/AST/DeclGroup.h new file mode 100644 index 0000000..63cdac5 --- /dev/null +++ b/clang/include/clang/AST/DeclGroup.h @@ -0,0 +1,151 @@ +//===--- DeclGroup.h - Classes for representing groups of Decls -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the DeclGroup, DeclGroupRef, and OwningDeclGroup classes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_DECLGROUP_H +#define LLVM_CLANG_AST_DECLGROUP_H + +#include "llvm/Support/DataTypes.h" +#include <cassert> + +namespace clang { + +class ASTContext; +class Decl; +class DeclGroup; +class DeclGroupIterator; + +class DeclGroup { + // FIXME: Include a TypeSpecifier object. + unsigned NumDecls; + +private: + DeclGroup() : NumDecls(0) {} + DeclGroup(unsigned numdecls, Decl** decls); + +public: + static DeclGroup *Create(ASTContext &C, Decl **Decls, unsigned NumDecls); + + unsigned size() const { return NumDecls; } + + Decl*& operator[](unsigned i) { + assert (i < NumDecls && "Out-of-bounds access."); + return ((Decl**) (this+1))[i]; + } + + Decl* const& operator[](unsigned i) const { + assert (i < NumDecls && "Out-of-bounds access."); + return ((Decl* const*) (this+1))[i]; + } +}; + +class DeclGroupRef { + // Note this is not a PointerIntPair because we need the address of the + // non-group case to be valid as a Decl** for iteration. + enum Kind { SingleDeclKind=0x0, DeclGroupKind=0x1, Mask=0x1 }; + Decl* D; + + Kind getKind() const { + return (Kind) (reinterpret_cast<uintptr_t>(D) & Mask); + } + +public: + DeclGroupRef() : D(0) {} + + explicit DeclGroupRef(Decl* d) : D(d) {} + explicit DeclGroupRef(DeclGroup* dg) + : D((Decl*) (reinterpret_cast<uintptr_t>(dg) | DeclGroupKind)) {} + + static DeclGroupRef Create(ASTContext &C, Decl **Decls, unsigned NumDecls) { + if (NumDecls == 0) + return DeclGroupRef(); + if (NumDecls == 1) + return DeclGroupRef(Decls[0]); + return DeclGroupRef(DeclGroup::Create(C, Decls, NumDecls)); + } + + typedef Decl** iterator; + typedef Decl* const * const_iterator; + + bool isNull() const { return D == 0; } + bool isSingleDecl() const { return getKind() == SingleDeclKind; } + bool isDeclGroup() const { return getKind() == DeclGroupKind; } + + Decl *getSingleDecl() { + assert(isSingleDecl() && "Isn't a declgroup"); + return D; + } + const Decl *getSingleDecl() const { + return const_cast<DeclGroupRef*>(this)->getSingleDecl(); + } + + DeclGroup &getDeclGroup() { + assert(isDeclGroup() && "Isn't a declgroup"); + return *((DeclGroup*)(reinterpret_cast<uintptr_t>(D) & ~Mask)); + } + const DeclGroup &getDeclGroup() const { + return const_cast<DeclGroupRef*>(this)->getDeclGroup(); + } + + iterator begin() { + if (isSingleDecl()) + return D ? &D : 0; + return &getDeclGroup()[0]; + } + + iterator end() { + if (isSingleDecl()) + return D ? &D+1 : 0; + DeclGroup &G = getDeclGroup(); + return &G[0] + G.size(); + } + + const_iterator begin() const { + if (isSingleDecl()) + return D ? &D : 0; + return &getDeclGroup()[0]; + } + + const_iterator end() const { + if (isSingleDecl()) + return D ? &D+1 : 0; + const DeclGroup &G = getDeclGroup(); + return &G[0] + G.size(); + } + + void *getAsOpaquePtr() const { return D; } + static DeclGroupRef getFromOpaquePtr(void *Ptr) { + DeclGroupRef X; + X.D = static_cast<Decl*>(Ptr); + return X; + } +}; + +} // end clang namespace + +namespace llvm { + // DeclGroupRef is "like a pointer", implement PointerLikeTypeTraits. + template <typename T> + class PointerLikeTypeTraits; + template <> + class PointerLikeTypeTraits<clang::DeclGroupRef> { + public: + static inline void *getAsVoidPointer(clang::DeclGroupRef P) { + return P.getAsOpaquePtr(); + } + static inline clang::DeclGroupRef getFromVoidPointer(void *P) { + return clang::DeclGroupRef::getFromOpaquePtr(P); + } + enum { NumLowBitsAvailable = 0 }; + }; +} +#endif diff --git a/clang/include/clang/AST/DeclLookups.h b/clang/include/clang/AST/DeclLookups.h new file mode 100644 index 0000000..b8abe97 --- /dev/null +++ b/clang/include/clang/AST/DeclLookups.h @@ -0,0 +1,88 @@ +//===-- DeclLookups.h - Low-level interface to all names in a DC-*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines DeclContext::all_lookups_iterator. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_DECLLOOKUPS_H +#define LLVM_CLANG_AST_DECLLOOKUPS_H + +#include "clang/AST/DeclBase.h" +#include "clang/AST/DeclContextInternals.h" +#include "clang/AST/DeclarationName.h" + +namespace clang { + +/// all_lookups_iterator - An iterator that provides a view over the results +/// of looking up every possible name. +class DeclContext::all_lookups_iterator { + StoredDeclsMap::iterator It, End; +public: + typedef lookup_result value_type; + typedef lookup_result reference; + typedef lookup_result pointer; + typedef std::forward_iterator_tag iterator_category; + typedef std::ptrdiff_t difference_type; + + all_lookups_iterator() {} + all_lookups_iterator(StoredDeclsMap::iterator It, + StoredDeclsMap::iterator End) + : It(It), End(End) {} + + reference operator*() const { return It->second.getLookupResult(); } + pointer operator->() const { return It->second.getLookupResult(); } + + all_lookups_iterator& operator++() { + // Filter out using directives. They don't belong as results from name + // lookup anyways, except as an implementation detail. Users of the API + // should not expect to get them (or worse, rely on it). + do { + ++It; + } while (It != End && + It->first == DeclarationName::getUsingDirectiveName()); + + return *this; + } + + all_lookups_iterator operator++(int) { + all_lookups_iterator tmp(*this); + ++(*this); + return tmp; + } + + friend bool operator==(all_lookups_iterator x, all_lookups_iterator y) { + return x.It == y.It; + } + friend bool operator!=(all_lookups_iterator x, all_lookups_iterator y) { + return x.It != y.It; + } +}; + +DeclContext::all_lookups_iterator DeclContext::lookups_begin() const { + DeclContext *Primary = const_cast<DeclContext*>(this)->getPrimaryContext(); + if (hasExternalVisibleStorage()) + getParentASTContext().getExternalSource()->completeVisibleDeclsMap(Primary); + if (StoredDeclsMap *Map = Primary->buildLookup()) + return all_lookups_iterator(Map->begin(), Map->end()); + return all_lookups_iterator(); +} + +DeclContext::all_lookups_iterator DeclContext::lookups_end() const { + DeclContext *Primary = const_cast<DeclContext*>(this)->getPrimaryContext(); + if (hasExternalVisibleStorage()) + getParentASTContext().getExternalSource()->completeVisibleDeclsMap(Primary); + if (StoredDeclsMap *Map = Primary->buildLookup()) + return all_lookups_iterator(Map->end(), Map->end()); + return all_lookups_iterator(); +} + +} // end namespace clang + +#endif diff --git a/clang/include/clang/AST/DeclObjC.h b/clang/include/clang/AST/DeclObjC.h new file mode 100644 index 0000000..4ae073e --- /dev/null +++ b/clang/include/clang/AST/DeclObjC.h @@ -0,0 +1,1988 @@ +//===--- DeclObjC.h - Classes for representing declarations -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the DeclObjC interface and subclasses. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_DECLOBJC_H +#define LLVM_CLANG_AST_DECLOBJC_H + +#include "clang/AST/Decl.h" +#include "clang/AST/SelectorLocationsKind.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/Compiler.h" + +namespace clang { +class Expr; +class Stmt; +class FunctionDecl; +class RecordDecl; +class ObjCIvarDecl; +class ObjCMethodDecl; +class ObjCProtocolDecl; +class ObjCCategoryDecl; +class ObjCPropertyDecl; +class ObjCPropertyImplDecl; +class CXXCtorInitializer; + +class ObjCListBase { + void operator=(const ObjCListBase &); // DO NOT IMPLEMENT + ObjCListBase(const ObjCListBase&); // DO NOT IMPLEMENT +protected: + /// List is an array of pointers to objects that are not owned by this object. + void **List; + unsigned NumElts; + +public: + ObjCListBase() : List(0), NumElts(0) {} + unsigned size() const { return NumElts; } + bool empty() const { return NumElts == 0; } + +protected: + void set(void *const* InList, unsigned Elts, ASTContext &Ctx); +}; + + +/// ObjCList - This is a simple template class used to hold various lists of +/// decls etc, which is heavily used by the ObjC front-end. This only use case +/// this supports is setting the list all at once and then reading elements out +/// of it. +template <typename T> +class ObjCList : public ObjCListBase { +public: + void set(T* const* InList, unsigned Elts, ASTContext &Ctx) { + ObjCListBase::set(reinterpret_cast<void*const*>(InList), Elts, Ctx); + } + + typedef T* const * iterator; + iterator begin() const { return (iterator)List; } + iterator end() const { return (iterator)List+NumElts; } + + T* operator[](unsigned Idx) const { + assert(Idx < NumElts && "Invalid access"); + return (T*)List[Idx]; + } +}; + +/// \brief A list of Objective-C protocols, along with the source +/// locations at which they were referenced. +class ObjCProtocolList : public ObjCList<ObjCProtocolDecl> { + SourceLocation *Locations; + + using ObjCList<ObjCProtocolDecl>::set; + +public: + ObjCProtocolList() : ObjCList<ObjCProtocolDecl>(), Locations(0) { } + + typedef const SourceLocation *loc_iterator; + loc_iterator loc_begin() const { return Locations; } + loc_iterator loc_end() const { return Locations + size(); } + + void set(ObjCProtocolDecl* const* InList, unsigned Elts, + const SourceLocation *Locs, ASTContext &Ctx); +}; + + +/// ObjCMethodDecl - Represents an instance or class method declaration. +/// ObjC methods can be declared within 4 contexts: class interfaces, +/// categories, protocols, and class implementations. While C++ member +/// functions leverage C syntax, Objective-C method syntax is modeled after +/// Smalltalk (using colons to specify argument types/expressions). +/// Here are some brief examples: +/// +/// Setter/getter instance methods: +/// - (void)setMenu:(NSMenu *)menu; +/// - (NSMenu *)menu; +/// +/// Instance method that takes 2 NSView arguments: +/// - (void)replaceSubview:(NSView *)oldView with:(NSView *)newView; +/// +/// Getter class method: +/// + (NSMenu *)defaultMenu; +/// +/// A selector represents a unique name for a method. The selector names for +/// the above methods are setMenu:, menu, replaceSubview:with:, and defaultMenu. +/// +class ObjCMethodDecl : public NamedDecl, public DeclContext { +public: + enum ImplementationControl { None, Required, Optional }; +private: + // The conventional meaning of this method; an ObjCMethodFamily. + // This is not serialized; instead, it is computed on demand and + // cached. + mutable unsigned Family : ObjCMethodFamilyBitWidth; + + /// instance (true) or class (false) method. + unsigned IsInstance : 1; + unsigned IsVariadic : 1; + + // Synthesized declaration method for a property setter/getter + unsigned IsSynthesized : 1; + + // Method has a definition. + unsigned IsDefined : 1; + + /// \brief Method redeclaration in the same interface. + unsigned IsRedeclaration : 1; + + /// \brief Is redeclared in the same interface. + mutable unsigned HasRedeclaration : 1; + + // NOTE: VC++ treats enums as signed, avoid using ImplementationControl enum + /// @required/@optional + unsigned DeclImplementation : 2; + + // NOTE: VC++ treats enums as signed, avoid using the ObjCDeclQualifier enum + /// in, inout, etc. + unsigned objcDeclQualifier : 6; + + /// \brief Indicates whether this method has a related result type. + unsigned RelatedResultType : 1; + + /// \brief Whether the locations of the selector identifiers are in a + /// "standard" position, a enum SelectorLocationsKind. + unsigned SelLocsKind : 2; + + // Result type of this method. + QualType MethodDeclType; + + // Type source information for the result type. + TypeSourceInfo *ResultTInfo; + + /// \brief Array of ParmVarDecls for the formal parameters of this method + /// and optionally followed by selector locations. + void *ParamsAndSelLocs; + unsigned NumParams; + + /// List of attributes for this method declaration. + SourceLocation EndLoc; // the location of the ';' or '}'. + + // The following are only used for method definitions, null otherwise. + // FIXME: space savings opportunity, consider a sub-class. + Stmt *Body; + + /// SelfDecl - Decl for the implicit self parameter. This is lazily + /// constructed by createImplicitParams. + ImplicitParamDecl *SelfDecl; + /// CmdDecl - Decl for the implicit _cmd parameter. This is lazily + /// constructed by createImplicitParams. + ImplicitParamDecl *CmdDecl; + + SelectorLocationsKind getSelLocsKind() const { + return (SelectorLocationsKind)SelLocsKind; + } + bool hasStandardSelLocs() const { + return getSelLocsKind() != SelLoc_NonStandard; + } + + /// \brief Get a pointer to the stored selector identifiers locations array. + /// No locations will be stored if HasStandardSelLocs is true. + SourceLocation *getStoredSelLocs() { + return reinterpret_cast<SourceLocation*>(getParams() + NumParams); + } + const SourceLocation *getStoredSelLocs() const { + return reinterpret_cast<const SourceLocation*>(getParams() + NumParams); + } + + /// \brief Get a pointer to the stored selector identifiers locations array. + /// No locations will be stored if HasStandardSelLocs is true. + ParmVarDecl **getParams() { + return reinterpret_cast<ParmVarDecl **>(ParamsAndSelLocs); + } + const ParmVarDecl *const *getParams() const { + return reinterpret_cast<const ParmVarDecl *const *>(ParamsAndSelLocs); + } + + /// \brief Get the number of stored selector identifiers locations. + /// No locations will be stored if HasStandardSelLocs is true. + unsigned getNumStoredSelLocs() const { + if (hasStandardSelLocs()) + return 0; + return getNumSelectorLocs(); + } + + void setParamsAndSelLocs(ASTContext &C, + ArrayRef<ParmVarDecl*> Params, + ArrayRef<SourceLocation> SelLocs); + + ObjCMethodDecl(SourceLocation beginLoc, SourceLocation endLoc, + Selector SelInfo, QualType T, + TypeSourceInfo *ResultTInfo, + DeclContext *contextDecl, + bool isInstance = true, + bool isVariadic = false, + bool isSynthesized = false, + bool isImplicitlyDeclared = false, + bool isDefined = false, + ImplementationControl impControl = None, + bool HasRelatedResultType = false) + : NamedDecl(ObjCMethod, contextDecl, beginLoc, SelInfo), + DeclContext(ObjCMethod), Family(InvalidObjCMethodFamily), + IsInstance(isInstance), IsVariadic(isVariadic), + IsSynthesized(isSynthesized), + IsDefined(isDefined), IsRedeclaration(0), HasRedeclaration(0), + DeclImplementation(impControl), objcDeclQualifier(OBJC_TQ_None), + RelatedResultType(HasRelatedResultType), + SelLocsKind(SelLoc_StandardNoSpace), + MethodDeclType(T), ResultTInfo(ResultTInfo), + ParamsAndSelLocs(0), NumParams(0), + EndLoc(endLoc), Body(0), SelfDecl(0), CmdDecl(0) { + setImplicit(isImplicitlyDeclared); + } + + /// \brief A definition will return its interface declaration. + /// An interface declaration will return its definition. + /// Otherwise it will return itself. + virtual ObjCMethodDecl *getNextRedeclaration(); + +public: + static ObjCMethodDecl *Create(ASTContext &C, + SourceLocation beginLoc, + SourceLocation endLoc, + Selector SelInfo, + QualType T, + TypeSourceInfo *ResultTInfo, + DeclContext *contextDecl, + bool isInstance = true, + bool isVariadic = false, + bool isSynthesized = false, + bool isImplicitlyDeclared = false, + bool isDefined = false, + ImplementationControl impControl = None, + bool HasRelatedResultType = false); + + static ObjCMethodDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + virtual ObjCMethodDecl *getCanonicalDecl(); + const ObjCMethodDecl *getCanonicalDecl() const { + return const_cast<ObjCMethodDecl*>(this)->getCanonicalDecl(); + } + + ObjCDeclQualifier getObjCDeclQualifier() const { + return ObjCDeclQualifier(objcDeclQualifier); + } + void setObjCDeclQualifier(ObjCDeclQualifier QV) { objcDeclQualifier = QV; } + + /// \brief Determine whether this method has a result type that is related + /// to the message receiver's type. + bool hasRelatedResultType() const { return RelatedResultType; } + + /// \brief Note whether this method has a related result type. + void SetRelatedResultType(bool RRT = true) { RelatedResultType = RRT; } + + /// \brief True if this is a method redeclaration in the same interface. + bool isRedeclaration() const { return IsRedeclaration; } + void setAsRedeclaration(const ObjCMethodDecl *PrevMethod); + + // Location information, modeled after the Stmt API. + SourceLocation getLocStart() const LLVM_READONLY { return getLocation(); } + SourceLocation getLocEnd() const LLVM_READONLY { return EndLoc; } + void setEndLoc(SourceLocation Loc) { EndLoc = Loc; } + virtual SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(getLocation(), EndLoc); + } + + SourceLocation getSelectorStartLoc() const { + if (isImplicit()) + return getLocStart(); + return getSelectorLoc(0); + } + SourceLocation getSelectorLoc(unsigned Index) const { + assert(Index < getNumSelectorLocs() && "Index out of range!"); + if (hasStandardSelLocs()) + return getStandardSelectorLoc(Index, getSelector(), + getSelLocsKind() == SelLoc_StandardWithSpace, + llvm::makeArrayRef(const_cast<ParmVarDecl**>(getParams()), + NumParams), + EndLoc); + return getStoredSelLocs()[Index]; + } + + void getSelectorLocs(SmallVectorImpl<SourceLocation> &SelLocs) const; + + unsigned getNumSelectorLocs() const { + if (isImplicit()) + return 0; + Selector Sel = getSelector(); + if (Sel.isUnarySelector()) + return 1; + return Sel.getNumArgs(); + } + + ObjCInterfaceDecl *getClassInterface(); + const ObjCInterfaceDecl *getClassInterface() const { + return const_cast<ObjCMethodDecl*>(this)->getClassInterface(); + } + + Selector getSelector() const { return getDeclName().getObjCSelector(); } + + QualType getResultType() const { return MethodDeclType; } + void setResultType(QualType T) { MethodDeclType = T; } + + /// \brief Determine the type of an expression that sends a message to this + /// function. + QualType getSendResultType() const { + return getResultType().getNonLValueExprType(getASTContext()); + } + + TypeSourceInfo *getResultTypeSourceInfo() const { return ResultTInfo; } + void setResultTypeSourceInfo(TypeSourceInfo *TInfo) { ResultTInfo = TInfo; } + + // Iterator access to formal parameters. + unsigned param_size() const { return NumParams; } + typedef const ParmVarDecl *const *param_const_iterator; + typedef ParmVarDecl *const *param_iterator; + param_const_iterator param_begin() const { return getParams(); } + param_const_iterator param_end() const { return getParams() + NumParams; } + param_iterator param_begin() { return getParams(); } + param_iterator param_end() { return getParams() + NumParams; } + // This method returns and of the parameters which are part of the selector + // name mangling requirements. + param_const_iterator sel_param_end() const { + return param_begin() + getSelector().getNumArgs(); + } + + /// \brief Sets the method's parameters and selector source locations. + /// If the method is implicit (not coming from source) \arg SelLocs is + /// ignored. + void setMethodParams(ASTContext &C, + ArrayRef<ParmVarDecl*> Params, + ArrayRef<SourceLocation> SelLocs = + ArrayRef<SourceLocation>()); + + // Iterator access to parameter types. + typedef std::const_mem_fun_t<QualType, ParmVarDecl> deref_fun; + typedef llvm::mapped_iterator<param_const_iterator, deref_fun> + arg_type_iterator; + + arg_type_iterator arg_type_begin() const { + return llvm::map_iterator(param_begin(), deref_fun(&ParmVarDecl::getType)); + } + arg_type_iterator arg_type_end() const { + return llvm::map_iterator(param_end(), deref_fun(&ParmVarDecl::getType)); + } + + /// createImplicitParams - Used to lazily create the self and cmd + /// implict parameters. This must be called prior to using getSelfDecl() + /// or getCmdDecl(). The call is ignored if the implicit paramters + /// have already been created. + void createImplicitParams(ASTContext &Context, const ObjCInterfaceDecl *ID); + + ImplicitParamDecl * getSelfDecl() const { return SelfDecl; } + void setSelfDecl(ImplicitParamDecl *SD) { SelfDecl = SD; } + ImplicitParamDecl * getCmdDecl() const { return CmdDecl; } + void setCmdDecl(ImplicitParamDecl *CD) { CmdDecl = CD; } + + /// Determines the family of this method. + ObjCMethodFamily getMethodFamily() const; + + bool isInstanceMethod() const { return IsInstance; } + void setInstanceMethod(bool isInst) { IsInstance = isInst; } + bool isVariadic() const { return IsVariadic; } + void setVariadic(bool isVar) { IsVariadic = isVar; } + + bool isClassMethod() const { return !IsInstance; } + + bool isSynthesized() const { return IsSynthesized; } + void setSynthesized(bool isSynth) { IsSynthesized = isSynth; } + + bool isDefined() const { return IsDefined; } + void setDefined(bool isDefined) { IsDefined = isDefined; } + + // Related to protocols declared in @protocol + void setDeclImplementation(ImplementationControl ic) { + DeclImplementation = ic; + } + ImplementationControl getImplementationControl() const { + return ImplementationControl(DeclImplementation); + } + + virtual Stmt *getBody() const { + return (Stmt*) Body; + } + CompoundStmt *getCompoundBody() { return (CompoundStmt*)Body; } + void setBody(Stmt *B) { Body = B; } + + /// \brief Returns whether this specific method is a definition. + bool isThisDeclarationADefinition() const { return Body; } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const ObjCMethodDecl *D) { return true; } + static bool classofKind(Kind K) { return K == ObjCMethod; } + static DeclContext *castToDeclContext(const ObjCMethodDecl *D) { + return static_cast<DeclContext *>(const_cast<ObjCMethodDecl*>(D)); + } + static ObjCMethodDecl *castFromDeclContext(const DeclContext *DC) { + return static_cast<ObjCMethodDecl *>(const_cast<DeclContext*>(DC)); + } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +/// ObjCContainerDecl - Represents a container for method declarations. +/// Current sub-classes are ObjCInterfaceDecl, ObjCCategoryDecl, +/// ObjCProtocolDecl, and ObjCImplDecl. +/// +class ObjCContainerDecl : public NamedDecl, public DeclContext { + virtual void anchor(); + + SourceLocation AtStart; + + // These two locations in the range mark the end of the method container. + // The first points to the '@' token, and the second to the 'end' token. + SourceRange AtEnd; +public: + + ObjCContainerDecl(Kind DK, DeclContext *DC, + IdentifierInfo *Id, SourceLocation nameLoc, + SourceLocation atStartLoc) + : NamedDecl(DK, DC, nameLoc, Id), DeclContext(DK), AtStart(atStartLoc) {} + + // Iterator access to properties. + typedef specific_decl_iterator<ObjCPropertyDecl> prop_iterator; + prop_iterator prop_begin() const { + return prop_iterator(decls_begin()); + } + prop_iterator prop_end() const { + return prop_iterator(decls_end()); + } + + // Iterator access to instance/class methods. + typedef specific_decl_iterator<ObjCMethodDecl> method_iterator; + method_iterator meth_begin() const { + return method_iterator(decls_begin()); + } + method_iterator meth_end() const { + return method_iterator(decls_end()); + } + + typedef filtered_decl_iterator<ObjCMethodDecl, + &ObjCMethodDecl::isInstanceMethod> + instmeth_iterator; + instmeth_iterator instmeth_begin() const { + return instmeth_iterator(decls_begin()); + } + instmeth_iterator instmeth_end() const { + return instmeth_iterator(decls_end()); + } + + typedef filtered_decl_iterator<ObjCMethodDecl, + &ObjCMethodDecl::isClassMethod> + classmeth_iterator; + classmeth_iterator classmeth_begin() const { + return classmeth_iterator(decls_begin()); + } + classmeth_iterator classmeth_end() const { + return classmeth_iterator(decls_end()); + } + + // Get the local instance/class method declared in this interface. + ObjCMethodDecl *getMethod(Selector Sel, bool isInstance) const; + ObjCMethodDecl *getInstanceMethod(Selector Sel) const { + return getMethod(Sel, true/*isInstance*/); + } + ObjCMethodDecl *getClassMethod(Selector Sel) const { + return getMethod(Sel, false/*isInstance*/); + } + ObjCIvarDecl *getIvarDecl(IdentifierInfo *Id) const; + + ObjCPropertyDecl *FindPropertyDeclaration(IdentifierInfo *PropertyId) const; + + SourceLocation getAtStartLoc() const { return AtStart; } + void setAtStartLoc(SourceLocation Loc) { AtStart = Loc; } + + // Marks the end of the container. + SourceRange getAtEndRange() const { + return AtEnd; + } + void setAtEndRange(SourceRange atEnd) { + AtEnd = atEnd; + } + + virtual SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(AtStart, getAtEndRange().getEnd()); + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const ObjCContainerDecl *D) { return true; } + static bool classofKind(Kind K) { + return K >= firstObjCContainer && + K <= lastObjCContainer; + } + + static DeclContext *castToDeclContext(const ObjCContainerDecl *D) { + return static_cast<DeclContext *>(const_cast<ObjCContainerDecl*>(D)); + } + static ObjCContainerDecl *castFromDeclContext(const DeclContext *DC) { + return static_cast<ObjCContainerDecl *>(const_cast<DeclContext*>(DC)); + } +}; + +/// ObjCInterfaceDecl - Represents an ObjC class declaration. For example: +/// +/// // MostPrimitive declares no super class (not particularly useful). +/// @interface MostPrimitive +/// // no instance variables or methods. +/// @end +/// +/// // NSResponder inherits from NSObject & implements NSCoding (a protocol). +/// @interface NSResponder : NSObject <NSCoding> +/// { // instance variables are represented by ObjCIvarDecl. +/// id nextResponder; // nextResponder instance variable. +/// } +/// - (NSResponder *)nextResponder; // return a pointer to NSResponder. +/// - (void)mouseMoved:(NSEvent *)theEvent; // return void, takes a pointer +/// @end // to an NSEvent. +/// +/// Unlike C/C++, forward class declarations are accomplished with @class. +/// Unlike C/C++, @class allows for a list of classes to be forward declared. +/// Unlike C++, ObjC is a single-rooted class model. In Cocoa, classes +/// typically inherit from NSObject (an exception is NSProxy). +/// +class ObjCInterfaceDecl : public ObjCContainerDecl + , public Redeclarable<ObjCInterfaceDecl> { + virtual void anchor(); + + /// TypeForDecl - This indicates the Type object that represents this + /// TypeDecl. It is a cache maintained by ASTContext::getObjCInterfaceType + mutable const Type *TypeForDecl; + friend class ASTContext; + + struct DefinitionData { + /// \brief The definition of this class, for quick access from any + /// declaration. + ObjCInterfaceDecl *Definition; + + /// Class's super class. + ObjCInterfaceDecl *SuperClass; + + /// Protocols referenced in the @interface declaration + ObjCProtocolList ReferencedProtocols; + + /// Protocols reference in both the @interface and class extensions. + ObjCList<ObjCProtocolDecl> AllReferencedProtocols; + + /// \brief List of categories and class extensions defined for this class. + /// + /// Categories are stored as a linked list in the AST, since the categories + /// and class extensions come long after the initial interface declaration, + /// and we avoid dynamically-resized arrays in the AST wherever possible. + ObjCCategoryDecl *CategoryList; + + /// IvarList - List of all ivars defined by this class; including class + /// extensions and implementation. This list is built lazily. + ObjCIvarDecl *IvarList; + + /// \brief Indicates that the contents of this Objective-C class will be + /// completed by the external AST source when required. + mutable bool ExternallyCompleted : 1; + + /// \brief The location of the superclass, if any. + SourceLocation SuperClassLoc; + + /// \brief The location of the last location in this declaration, before + /// the properties/methods. For example, this will be the '>', '}', or + /// identifier, + SourceLocation EndLoc; + + DefinitionData() : Definition(), SuperClass(), CategoryList(), IvarList(), + ExternallyCompleted() { } + }; + + ObjCInterfaceDecl(DeclContext *DC, SourceLocation atLoc, IdentifierInfo *Id, + SourceLocation CLoc, ObjCInterfaceDecl *PrevDecl, + bool isInternal); + + void LoadExternalDefinition() const; + + /// \brief Contains a pointer to the data associated with this class, + /// which will be NULL if this class has not yet been defined. + DefinitionData *Data; + + DefinitionData &data() const { + assert(Data != 0 && "Declaration has no definition!"); + return *Data; + } + + /// \brief Allocate the definition data for this class. + void allocateDefinitionData(); + + typedef Redeclarable<ObjCInterfaceDecl> redeclarable_base; + virtual ObjCInterfaceDecl *getNextRedeclaration() { + return RedeclLink.getNext(); + } + virtual ObjCInterfaceDecl *getPreviousDeclImpl() { + return getPreviousDecl(); + } + virtual ObjCInterfaceDecl *getMostRecentDeclImpl() { + return getMostRecentDecl(); + } + +public: + static ObjCInterfaceDecl *Create(const ASTContext &C, DeclContext *DC, + SourceLocation atLoc, + IdentifierInfo *Id, + ObjCInterfaceDecl *PrevDecl, + SourceLocation ClassLoc = SourceLocation(), + bool isInternal = false); + + static ObjCInterfaceDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + virtual SourceRange getSourceRange() const LLVM_READONLY { + if (isThisDeclarationADefinition()) + return ObjCContainerDecl::getSourceRange(); + + return SourceRange(getAtStartLoc(), getLocation()); + } + + /// \brief Indicate that this Objective-C class is complete, but that + /// the external AST source will be responsible for filling in its contents + /// when a complete class is required. + void setExternallyCompleted(); + + const ObjCProtocolList &getReferencedProtocols() const { + assert(hasDefinition() && "Caller did not check for forward reference!"); + if (data().ExternallyCompleted) + LoadExternalDefinition(); + + return data().ReferencedProtocols; + } + + ObjCImplementationDecl *getImplementation() const; + void setImplementation(ObjCImplementationDecl *ImplD); + + ObjCCategoryDecl *FindCategoryDeclaration(IdentifierInfo *CategoryId) const; + + // Get the local instance/class method declared in a category. + ObjCMethodDecl *getCategoryInstanceMethod(Selector Sel) const; + ObjCMethodDecl *getCategoryClassMethod(Selector Sel) const; + ObjCMethodDecl *getCategoryMethod(Selector Sel, bool isInstance) const { + return isInstance ? getInstanceMethod(Sel) + : getClassMethod(Sel); + } + + typedef ObjCProtocolList::iterator protocol_iterator; + + protocol_iterator protocol_begin() const { + // FIXME: Should make sure no callers ever do this. + if (!hasDefinition()) + return protocol_iterator(); + + if (data().ExternallyCompleted) + LoadExternalDefinition(); + + return data().ReferencedProtocols.begin(); + } + protocol_iterator protocol_end() const { + // FIXME: Should make sure no callers ever do this. + if (!hasDefinition()) + return protocol_iterator(); + + if (data().ExternallyCompleted) + LoadExternalDefinition(); + + return data().ReferencedProtocols.end(); + } + + typedef ObjCProtocolList::loc_iterator protocol_loc_iterator; + + protocol_loc_iterator protocol_loc_begin() const { + // FIXME: Should make sure no callers ever do this. + if (!hasDefinition()) + return protocol_loc_iterator(); + + if (data().ExternallyCompleted) + LoadExternalDefinition(); + + return data().ReferencedProtocols.loc_begin(); + } + + protocol_loc_iterator protocol_loc_end() const { + // FIXME: Should make sure no callers ever do this. + if (!hasDefinition()) + return protocol_loc_iterator(); + + if (data().ExternallyCompleted) + LoadExternalDefinition(); + + return data().ReferencedProtocols.loc_end(); + } + + typedef ObjCList<ObjCProtocolDecl>::iterator all_protocol_iterator; + + all_protocol_iterator all_referenced_protocol_begin() const { + // FIXME: Should make sure no callers ever do this. + if (!hasDefinition()) + return all_protocol_iterator(); + + if (data().ExternallyCompleted) + LoadExternalDefinition(); + + return data().AllReferencedProtocols.empty() + ? protocol_begin() + : data().AllReferencedProtocols.begin(); + } + all_protocol_iterator all_referenced_protocol_end() const { + // FIXME: Should make sure no callers ever do this. + if (!hasDefinition()) + return all_protocol_iterator(); + + if (data().ExternallyCompleted) + LoadExternalDefinition(); + + return data().AllReferencedProtocols.empty() + ? protocol_end() + : data().AllReferencedProtocols.end(); + } + + typedef specific_decl_iterator<ObjCIvarDecl> ivar_iterator; + + ivar_iterator ivar_begin() const { + if (const ObjCInterfaceDecl *Def = getDefinition()) + return ivar_iterator(Def->decls_begin()); + + // FIXME: Should make sure no callers ever do this. + return ivar_iterator(); + } + ivar_iterator ivar_end() const { + if (const ObjCInterfaceDecl *Def = getDefinition()) + return ivar_iterator(Def->decls_end()); + + // FIXME: Should make sure no callers ever do this. + return ivar_iterator(); + } + + unsigned ivar_size() const { + return std::distance(ivar_begin(), ivar_end()); + } + + bool ivar_empty() const { return ivar_begin() == ivar_end(); } + + ObjCIvarDecl *all_declared_ivar_begin(); + const ObjCIvarDecl *all_declared_ivar_begin() const { + // Even though this modifies IvarList, it's conceptually const: + // the ivar chain is essentially a cached property of ObjCInterfaceDecl. + return const_cast<ObjCInterfaceDecl *>(this)->all_declared_ivar_begin(); + } + void setIvarList(ObjCIvarDecl *ivar) { data().IvarList = ivar; } + + /// setProtocolList - Set the list of protocols that this interface + /// implements. + void setProtocolList(ObjCProtocolDecl *const* List, unsigned Num, + const SourceLocation *Locs, ASTContext &C) { + data().ReferencedProtocols.set(List, Num, Locs, C); + } + + /// mergeClassExtensionProtocolList - Merge class extension's protocol list + /// into the protocol list for this class. + void mergeClassExtensionProtocolList(ObjCProtocolDecl *const* List, + unsigned Num, + ASTContext &C); + + /// \brief Determine whether this particular declaration of this class is + /// actually also a definition. + bool isThisDeclarationADefinition() const { + return Data && Data->Definition == this; + } + + /// \brief Determine whether this class has been defined. + bool hasDefinition() const { return Data; } + + /// \brief Retrieve the definition of this class, or NULL if this class + /// has been forward-declared (with @class) but not yet defined (with + /// @interface). + ObjCInterfaceDecl *getDefinition() { + return hasDefinition()? Data->Definition : 0; + } + + /// \brief Retrieve the definition of this class, or NULL if this class + /// has been forward-declared (with @class) but not yet defined (with + /// @interface). + const ObjCInterfaceDecl *getDefinition() const { + return hasDefinition()? Data->Definition : 0; + } + + /// \brief Starts the definition of this Objective-C class, taking it from + /// a forward declaration (@class) to a definition (@interface). + void startDefinition(); + + ObjCInterfaceDecl *getSuperClass() const { + // FIXME: Should make sure no callers ever do this. + if (!hasDefinition()) + return 0; + + if (data().ExternallyCompleted) + LoadExternalDefinition(); + + return data().SuperClass; + } + + void setSuperClass(ObjCInterfaceDecl * superCls) { + data().SuperClass = + (superCls && superCls->hasDefinition()) ? superCls->getDefinition() + : superCls; + } + + ObjCCategoryDecl* getCategoryList() const { + // FIXME: Should make sure no callers ever do this. + if (!hasDefinition()) + return 0; + + if (data().ExternallyCompleted) + LoadExternalDefinition(); + + return data().CategoryList; + } + + void setCategoryList(ObjCCategoryDecl *category) { + data().CategoryList = category; + } + + ObjCCategoryDecl* getFirstClassExtension() const; + + ObjCPropertyDecl + *FindPropertyVisibleInPrimaryClass(IdentifierInfo *PropertyId) const; + + /// isSuperClassOf - Return true if this class is the specified class or is a + /// super class of the specified interface class. + bool isSuperClassOf(const ObjCInterfaceDecl *I) const { + // If RHS is derived from LHS it is OK; else it is not OK. + while (I != NULL) { + if (declaresSameEntity(this, I)) + return true; + + I = I->getSuperClass(); + } + return false; + } + + /// isArcWeakrefUnavailable - Checks for a class or one of its super classes + /// to be incompatible with __weak references. Returns true if it is. + bool isArcWeakrefUnavailable() const { + const ObjCInterfaceDecl *Class = this; + while (Class) { + if (Class->hasAttr<ArcWeakrefUnavailableAttr>()) + return true; + Class = Class->getSuperClass(); + } + return false; + } + + /// isObjCRequiresPropertyDefs - Checks that a class or one of its super + /// classes must not be auto-synthesized. Returns class decl. if it must not be; + /// 0, otherwise. + const ObjCInterfaceDecl *isObjCRequiresPropertyDefs() const { + const ObjCInterfaceDecl *Class = this; + while (Class) { + if (Class->hasAttr<ObjCRequiresPropertyDefsAttr>()) + return Class; + Class = Class->getSuperClass(); + } + return 0; + } + + ObjCIvarDecl *lookupInstanceVariable(IdentifierInfo *IVarName, + ObjCInterfaceDecl *&ClassDeclared); + ObjCIvarDecl *lookupInstanceVariable(IdentifierInfo *IVarName) { + ObjCInterfaceDecl *ClassDeclared; + return lookupInstanceVariable(IVarName, ClassDeclared); + } + + // Lookup a method. First, we search locally. If a method isn't + // found, we search referenced protocols and class categories. + ObjCMethodDecl *lookupMethod(Selector Sel, bool isInstance, + bool shallowCategoryLookup= false) const; + ObjCMethodDecl *lookupInstanceMethod(Selector Sel, + bool shallowCategoryLookup = false) const { + return lookupMethod(Sel, true/*isInstance*/, shallowCategoryLookup); + } + ObjCMethodDecl *lookupClassMethod(Selector Sel, + bool shallowCategoryLookup = false) const { + return lookupMethod(Sel, false/*isInstance*/, shallowCategoryLookup); + } + ObjCInterfaceDecl *lookupInheritedClass(const IdentifierInfo *ICName); + + // Lookup a method in the classes implementation hierarchy. + ObjCMethodDecl *lookupPrivateMethod(const Selector &Sel, bool Instance=true); + + SourceLocation getEndOfDefinitionLoc() const { + if (!hasDefinition()) + return getLocation(); + + return data().EndLoc; + } + + void setEndOfDefinitionLoc(SourceLocation LE) { data().EndLoc = LE; } + + void setSuperClassLoc(SourceLocation Loc) { data().SuperClassLoc = Loc; } + SourceLocation getSuperClassLoc() const { return data().SuperClassLoc; } + + /// isImplicitInterfaceDecl - check that this is an implicitly declared + /// ObjCInterfaceDecl node. This is for legacy objective-c @implementation + /// declaration without an @interface declaration. + bool isImplicitInterfaceDecl() const { + return hasDefinition() ? Data->Definition->isImplicit() : isImplicit(); + } + + /// ClassImplementsProtocol - Checks that 'lProto' protocol + /// has been implemented in IDecl class, its super class or categories (if + /// lookupCategory is true). + bool ClassImplementsProtocol(ObjCProtocolDecl *lProto, + bool lookupCategory, + bool RHSIsQualifiedID = false); + + typedef redeclarable_base::redecl_iterator redecl_iterator; + using redeclarable_base::redecls_begin; + using redeclarable_base::redecls_end; + using redeclarable_base::getPreviousDecl; + using redeclarable_base::getMostRecentDecl; + + /// Retrieves the canonical declaration of this Objective-C class. + ObjCInterfaceDecl *getCanonicalDecl() { + return getFirstDeclaration(); + } + const ObjCInterfaceDecl *getCanonicalDecl() const { + return getFirstDeclaration(); + } + + // Low-level accessor + const Type *getTypeForDecl() const { return TypeForDecl; } + void setTypeForDecl(const Type *TD) const { TypeForDecl = TD; } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const ObjCInterfaceDecl *D) { return true; } + static bool classofKind(Kind K) { return K == ObjCInterface; } + + friend class ASTReader; + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +/// ObjCIvarDecl - Represents an ObjC instance variable. In general, ObjC +/// instance variables are identical to C. The only exception is Objective-C +/// supports C++ style access control. For example: +/// +/// @interface IvarExample : NSObject +/// { +/// id defaultToProtected; +/// @public: +/// id canBePublic; // same as C++. +/// @protected: +/// id canBeProtected; // same as C++. +/// @package: +/// id canBePackage; // framework visibility (not available in C++). +/// } +/// +class ObjCIvarDecl : public FieldDecl { + virtual void anchor(); + +public: + enum AccessControl { + None, Private, Protected, Public, Package + }; + +private: + ObjCIvarDecl(ObjCContainerDecl *DC, SourceLocation StartLoc, + SourceLocation IdLoc, IdentifierInfo *Id, + QualType T, TypeSourceInfo *TInfo, AccessControl ac, Expr *BW, + bool synthesized) + : FieldDecl(ObjCIvar, DC, StartLoc, IdLoc, Id, T, TInfo, BW, + /*Mutable=*/false, /*HasInit=*/false), + NextIvar(0), DeclAccess(ac), Synthesized(synthesized) {} + +public: + static ObjCIvarDecl *Create(ASTContext &C, ObjCContainerDecl *DC, + SourceLocation StartLoc, SourceLocation IdLoc, + IdentifierInfo *Id, QualType T, + TypeSourceInfo *TInfo, + AccessControl ac, Expr *BW = NULL, + bool synthesized=false); + + static ObjCIvarDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + /// \brief Return the class interface that this ivar is logically contained + /// in; this is either the interface where the ivar was declared, or the + /// interface the ivar is conceptually a part of in the case of synthesized + /// ivars. + const ObjCInterfaceDecl *getContainingInterface() const; + + ObjCIvarDecl *getNextIvar() { return NextIvar; } + const ObjCIvarDecl *getNextIvar() const { return NextIvar; } + void setNextIvar(ObjCIvarDecl *ivar) { NextIvar = ivar; } + + void setAccessControl(AccessControl ac) { DeclAccess = ac; } + + AccessControl getAccessControl() const { return AccessControl(DeclAccess); } + + AccessControl getCanonicalAccessControl() const { + return DeclAccess == None ? Protected : AccessControl(DeclAccess); + } + + void setSynthesize(bool synth) { Synthesized = synth; } + bool getSynthesize() const { return Synthesized; } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const ObjCIvarDecl *D) { return true; } + static bool classofKind(Kind K) { return K == ObjCIvar; } +private: + /// NextIvar - Next Ivar in the list of ivars declared in class; class's + /// extensions and class's implementation + ObjCIvarDecl *NextIvar; + + // NOTE: VC++ treats enums as signed, avoid using the AccessControl enum + unsigned DeclAccess : 3; + unsigned Synthesized : 1; +}; + + +/// ObjCAtDefsFieldDecl - Represents a field declaration created by an +/// @defs(...). +class ObjCAtDefsFieldDecl : public FieldDecl { + virtual void anchor(); + ObjCAtDefsFieldDecl(DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, IdentifierInfo *Id, + QualType T, Expr *BW) + : FieldDecl(ObjCAtDefsField, DC, StartLoc, IdLoc, Id, T, + /*TInfo=*/0, // FIXME: Do ObjCAtDefs have declarators ? + BW, /*Mutable=*/false, /*HasInit=*/false) {} + +public: + static ObjCAtDefsFieldDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, + SourceLocation IdLoc, IdentifierInfo *Id, + QualType T, Expr *BW); + + static ObjCAtDefsFieldDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const ObjCAtDefsFieldDecl *D) { return true; } + static bool classofKind(Kind K) { return K == ObjCAtDefsField; } +}; + +/// ObjCProtocolDecl - Represents a protocol declaration. ObjC protocols +/// declare a pure abstract type (i.e no instance variables are permitted). +/// Protocols originally drew inspiration from C++ pure virtual functions (a C++ +/// feature with nice semantics and lousy syntax:-). Here is an example: +/// +/// @protocol NSDraggingInfo <refproto1, refproto2> +/// - (NSWindow *)draggingDestinationWindow; +/// - (NSImage *)draggedImage; +/// @end +/// +/// This says that NSDraggingInfo requires two methods and requires everything +/// that the two "referenced protocols" 'refproto1' and 'refproto2' require as +/// well. +/// +/// @interface ImplementsNSDraggingInfo : NSObject <NSDraggingInfo> +/// @end +/// +/// ObjC protocols inspired Java interfaces. Unlike Java, ObjC classes and +/// protocols are in distinct namespaces. For example, Cocoa defines both +/// an NSObject protocol and class (which isn't allowed in Java). As a result, +/// protocols are referenced using angle brackets as follows: +/// +/// id <NSDraggingInfo> anyObjectThatImplementsNSDraggingInfo; +/// +class ObjCProtocolDecl : public ObjCContainerDecl, + public Redeclarable<ObjCProtocolDecl> { + virtual void anchor(); + + struct DefinitionData { + // \brief The declaration that defines this protocol. + ObjCProtocolDecl *Definition; + + /// \brief Referenced protocols + ObjCProtocolList ReferencedProtocols; + }; + + DefinitionData *Data; + + DefinitionData &data() const { + assert(Data && "Objective-C protocol has no definition!"); + return *Data; + } + + ObjCProtocolDecl(DeclContext *DC, IdentifierInfo *Id, + SourceLocation nameLoc, SourceLocation atStartLoc, + ObjCProtocolDecl *PrevDecl); + + void allocateDefinitionData(); + + typedef Redeclarable<ObjCProtocolDecl> redeclarable_base; + virtual ObjCProtocolDecl *getNextRedeclaration() { + return RedeclLink.getNext(); + } + virtual ObjCProtocolDecl *getPreviousDeclImpl() { + return getPreviousDecl(); + } + virtual ObjCProtocolDecl *getMostRecentDeclImpl() { + return getMostRecentDecl(); + } + +public: + static ObjCProtocolDecl *Create(ASTContext &C, DeclContext *DC, + IdentifierInfo *Id, + SourceLocation nameLoc, + SourceLocation atStartLoc, + ObjCProtocolDecl *PrevDecl); + + static ObjCProtocolDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + const ObjCProtocolList &getReferencedProtocols() const { + assert(hasDefinition() && "No definition available!"); + return data().ReferencedProtocols; + } + typedef ObjCProtocolList::iterator protocol_iterator; + protocol_iterator protocol_begin() const { + if (!hasDefinition()) + return protocol_iterator(); + + return data().ReferencedProtocols.begin(); + } + protocol_iterator protocol_end() const { + if (!hasDefinition()) + return protocol_iterator(); + + return data().ReferencedProtocols.end(); + } + typedef ObjCProtocolList::loc_iterator protocol_loc_iterator; + protocol_loc_iterator protocol_loc_begin() const { + if (!hasDefinition()) + return protocol_loc_iterator(); + + return data().ReferencedProtocols.loc_begin(); + } + protocol_loc_iterator protocol_loc_end() const { + if (!hasDefinition()) + return protocol_loc_iterator(); + + return data().ReferencedProtocols.loc_end(); + } + unsigned protocol_size() const { + if (!hasDefinition()) + return 0; + + return data().ReferencedProtocols.size(); + } + + /// setProtocolList - Set the list of protocols that this interface + /// implements. + void setProtocolList(ObjCProtocolDecl *const*List, unsigned Num, + const SourceLocation *Locs, ASTContext &C) { + assert(Data && "Protocol is not defined"); + data().ReferencedProtocols.set(List, Num, Locs, C); + } + + ObjCProtocolDecl *lookupProtocolNamed(IdentifierInfo *PName); + + // Lookup a method. First, we search locally. If a method isn't + // found, we search referenced protocols and class categories. + ObjCMethodDecl *lookupMethod(Selector Sel, bool isInstance) const; + ObjCMethodDecl *lookupInstanceMethod(Selector Sel) const { + return lookupMethod(Sel, true/*isInstance*/); + } + ObjCMethodDecl *lookupClassMethod(Selector Sel) const { + return lookupMethod(Sel, false/*isInstance*/); + } + + /// \brief Determine whether this protocol has a definition. + bool hasDefinition() const { return Data != 0; } + + /// \brief Retrieve the definition of this protocol, if any. + ObjCProtocolDecl *getDefinition() { + return Data? Data->Definition : 0; + } + + /// \brief Retrieve the definition of this protocol, if any. + const ObjCProtocolDecl *getDefinition() const { + return Data? Data->Definition : 0; + } + + /// \brief Determine whether this particular declaration is also the + /// definition. + bool isThisDeclarationADefinition() const { + return getDefinition() == this; + } + + /// \brief Starts the definition of this Objective-C protocol. + void startDefinition(); + + virtual SourceRange getSourceRange() const LLVM_READONLY { + if (isThisDeclarationADefinition()) + return ObjCContainerDecl::getSourceRange(); + + return SourceRange(getAtStartLoc(), getLocation()); + } + + typedef redeclarable_base::redecl_iterator redecl_iterator; + using redeclarable_base::redecls_begin; + using redeclarable_base::redecls_end; + using redeclarable_base::getPreviousDecl; + using redeclarable_base::getMostRecentDecl; + + /// Retrieves the canonical declaration of this Objective-C protocol. + ObjCProtocolDecl *getCanonicalDecl() { + return getFirstDeclaration(); + } + const ObjCProtocolDecl *getCanonicalDecl() const { + return getFirstDeclaration(); + } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const ObjCProtocolDecl *D) { return true; } + static bool classofKind(Kind K) { return K == ObjCProtocol; } + + friend class ASTReader; + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +/// ObjCCategoryDecl - Represents a category declaration. A category allows +/// you to add methods to an existing class (without subclassing or modifying +/// the original class interface or implementation:-). Categories don't allow +/// you to add instance data. The following example adds "myMethod" to all +/// NSView's within a process: +/// +/// @interface NSView (MyViewMethods) +/// - myMethod; +/// @end +/// +/// Categories also allow you to split the implementation of a class across +/// several files (a feature more naturally supported in C++). +/// +/// Categories were originally inspired by dynamic languages such as Common +/// Lisp and Smalltalk. More traditional class-based languages (C++, Java) +/// don't support this level of dynamism, which is both powerful and dangerous. +/// +class ObjCCategoryDecl : public ObjCContainerDecl { + virtual void anchor(); + + /// Interface belonging to this category + ObjCInterfaceDecl *ClassInterface; + + /// referenced protocols in this category. + ObjCProtocolList ReferencedProtocols; + + /// Next category belonging to this class. + /// FIXME: this should not be a singly-linked list. Move storage elsewhere. + ObjCCategoryDecl *NextClassCategory; + + /// true of class extension has at least one bitfield ivar. + bool HasSynthBitfield : 1; + + /// \brief The location of the category name in this declaration. + SourceLocation CategoryNameLoc; + + /// class extension may have private ivars. + SourceLocation IvarLBraceLoc; + SourceLocation IvarRBraceLoc; + + ObjCCategoryDecl(DeclContext *DC, SourceLocation AtLoc, + SourceLocation ClassNameLoc, SourceLocation CategoryNameLoc, + IdentifierInfo *Id, ObjCInterfaceDecl *IDecl, + SourceLocation IvarLBraceLoc=SourceLocation(), + SourceLocation IvarRBraceLoc=SourceLocation()) + : ObjCContainerDecl(ObjCCategory, DC, Id, ClassNameLoc, AtLoc), + ClassInterface(IDecl), NextClassCategory(0), HasSynthBitfield(false), + CategoryNameLoc(CategoryNameLoc), + IvarLBraceLoc(IvarLBraceLoc), IvarRBraceLoc(IvarRBraceLoc) { + } +public: + + static ObjCCategoryDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation AtLoc, + SourceLocation ClassNameLoc, + SourceLocation CategoryNameLoc, + IdentifierInfo *Id, + ObjCInterfaceDecl *IDecl, + SourceLocation IvarLBraceLoc=SourceLocation(), + SourceLocation IvarRBraceLoc=SourceLocation()); + static ObjCCategoryDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + ObjCInterfaceDecl *getClassInterface() { return ClassInterface; } + const ObjCInterfaceDecl *getClassInterface() const { return ClassInterface; } + + ObjCCategoryImplDecl *getImplementation() const; + void setImplementation(ObjCCategoryImplDecl *ImplD); + + /// setProtocolList - Set the list of protocols that this interface + /// implements. + void setProtocolList(ObjCProtocolDecl *const*List, unsigned Num, + const SourceLocation *Locs, ASTContext &C) { + ReferencedProtocols.set(List, Num, Locs, C); + } + + const ObjCProtocolList &getReferencedProtocols() const { + return ReferencedProtocols; + } + + typedef ObjCProtocolList::iterator protocol_iterator; + protocol_iterator protocol_begin() const {return ReferencedProtocols.begin();} + protocol_iterator protocol_end() const { return ReferencedProtocols.end(); } + unsigned protocol_size() const { return ReferencedProtocols.size(); } + typedef ObjCProtocolList::loc_iterator protocol_loc_iterator; + protocol_loc_iterator protocol_loc_begin() const { + return ReferencedProtocols.loc_begin(); + } + protocol_loc_iterator protocol_loc_end() const { + return ReferencedProtocols.loc_end(); + } + + ObjCCategoryDecl *getNextClassCategory() const { return NextClassCategory; } + + bool IsClassExtension() const { return getIdentifier() == 0; } + const ObjCCategoryDecl *getNextClassExtension() const; + + bool hasSynthBitfield() const { return HasSynthBitfield; } + void setHasSynthBitfield (bool val) { HasSynthBitfield = val; } + + typedef specific_decl_iterator<ObjCIvarDecl> ivar_iterator; + ivar_iterator ivar_begin() const { + return ivar_iterator(decls_begin()); + } + ivar_iterator ivar_end() const { + return ivar_iterator(decls_end()); + } + unsigned ivar_size() const { + return std::distance(ivar_begin(), ivar_end()); + } + bool ivar_empty() const { + return ivar_begin() == ivar_end(); + } + + SourceLocation getCategoryNameLoc() const { return CategoryNameLoc; } + void setCategoryNameLoc(SourceLocation Loc) { CategoryNameLoc = Loc; } + + void setIvarLBraceLoc(SourceLocation Loc) { IvarLBraceLoc = Loc; } + SourceLocation getIvarLBraceLoc() const { return IvarLBraceLoc; } + void setIvarRBraceLoc(SourceLocation Loc) { IvarRBraceLoc = Loc; } + SourceLocation getIvarRBraceLoc() const { return IvarRBraceLoc; } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const ObjCCategoryDecl *D) { return true; } + static bool classofKind(Kind K) { return K == ObjCCategory; } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +class ObjCImplDecl : public ObjCContainerDecl { + virtual void anchor(); + + /// Class interface for this class/category implementation + ObjCInterfaceDecl *ClassInterface; + +protected: + ObjCImplDecl(Kind DK, DeclContext *DC, + ObjCInterfaceDecl *classInterface, + SourceLocation nameLoc, SourceLocation atStartLoc) + : ObjCContainerDecl(DK, DC, + classInterface? classInterface->getIdentifier() : 0, + nameLoc, atStartLoc), + ClassInterface(classInterface) {} + +public: + const ObjCInterfaceDecl *getClassInterface() const { return ClassInterface; } + ObjCInterfaceDecl *getClassInterface() { return ClassInterface; } + void setClassInterface(ObjCInterfaceDecl *IFace); + + void addInstanceMethod(ObjCMethodDecl *method) { + // FIXME: Context should be set correctly before we get here. + method->setLexicalDeclContext(this); + addDecl(method); + } + void addClassMethod(ObjCMethodDecl *method) { + // FIXME: Context should be set correctly before we get here. + method->setLexicalDeclContext(this); + addDecl(method); + } + + void addPropertyImplementation(ObjCPropertyImplDecl *property); + + ObjCPropertyImplDecl *FindPropertyImplDecl(IdentifierInfo *propertyId) const; + ObjCPropertyImplDecl *FindPropertyImplIvarDecl(IdentifierInfo *ivarId) const; + + // Iterator access to properties. + typedef specific_decl_iterator<ObjCPropertyImplDecl> propimpl_iterator; + propimpl_iterator propimpl_begin() const { + return propimpl_iterator(decls_begin()); + } + propimpl_iterator propimpl_end() const { + return propimpl_iterator(decls_end()); + } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const ObjCImplDecl *D) { return true; } + static bool classofKind(Kind K) { + return K >= firstObjCImpl && K <= lastObjCImpl; + } +}; + +/// ObjCCategoryImplDecl - An object of this class encapsulates a category +/// @implementation declaration. If a category class has declaration of a +/// property, its implementation must be specified in the category's +/// @implementation declaration. Example: +/// @interface I @end +/// @interface I(CATEGORY) +/// @property int p1, d1; +/// @end +/// @implementation I(CATEGORY) +/// @dynamic p1,d1; +/// @end +/// +/// ObjCCategoryImplDecl +class ObjCCategoryImplDecl : public ObjCImplDecl { + virtual void anchor(); + + // Category name + IdentifierInfo *Id; + + // Category name location + SourceLocation CategoryNameLoc; + + ObjCCategoryImplDecl(DeclContext *DC, IdentifierInfo *Id, + ObjCInterfaceDecl *classInterface, + SourceLocation nameLoc, SourceLocation atStartLoc, + SourceLocation CategoryNameLoc) + : ObjCImplDecl(ObjCCategoryImpl, DC, classInterface, nameLoc, atStartLoc), + Id(Id), CategoryNameLoc(CategoryNameLoc) {} +public: + static ObjCCategoryImplDecl *Create(ASTContext &C, DeclContext *DC, + IdentifierInfo *Id, + ObjCInterfaceDecl *classInterface, + SourceLocation nameLoc, + SourceLocation atStartLoc, + SourceLocation CategoryNameLoc); + static ObjCCategoryImplDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + /// getIdentifier - Get the identifier that names the category + /// interface associated with this implementation. + /// FIXME: This is a bad API, we are overriding the NamedDecl::getIdentifier() + /// to mean something different. For example: + /// ((NamedDecl *)SomeCategoryImplDecl)->getIdentifier() + /// returns the class interface name, whereas + /// ((ObjCCategoryImplDecl *)SomeCategoryImplDecl)->getIdentifier() + /// returns the category name. + IdentifierInfo *getIdentifier() const { + return Id; + } + void setIdentifier(IdentifierInfo *II) { Id = II; } + + ObjCCategoryDecl *getCategoryDecl() const; + + SourceLocation getCategoryNameLoc() const { return CategoryNameLoc; } + + /// getName - Get the name of identifier for the class interface associated + /// with this implementation as a StringRef. + // + // FIXME: This is a bad API, we are overriding the NamedDecl::getName, to mean + // something different. + StringRef getName() const { + return Id ? Id->getNameStart() : ""; + } + + /// getNameAsCString - Get the name of identifier for the class + /// interface associated with this implementation as a C string + /// (const char*). + // + // FIXME: Deprecated, move clients to getName(). + const char *getNameAsCString() const { + return Id ? Id->getNameStart() : ""; + } + + /// @brief Get the name of the class associated with this interface. + // + // FIXME: Deprecated, move clients to getName(). + std::string getNameAsString() const { + return getName(); + } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const ObjCCategoryImplDecl *D) { return true; } + static bool classofKind(Kind K) { return K == ObjCCategoryImpl;} + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +raw_ostream &operator<<(raw_ostream &OS, const ObjCCategoryImplDecl &CID); + +/// ObjCImplementationDecl - Represents a class definition - this is where +/// method definitions are specified. For example: +/// +/// @code +/// @implementation MyClass +/// - (void)myMethod { /* do something */ } +/// @end +/// @endcode +/// +/// Typically, instance variables are specified in the class interface, +/// *not* in the implementation. Nevertheless (for legacy reasons), we +/// allow instance variables to be specified in the implementation. When +/// specified, they need to be *identical* to the interface. +/// +class ObjCImplementationDecl : public ObjCImplDecl { + virtual void anchor(); + /// Implementation Class's super class. + ObjCInterfaceDecl *SuperClass; + /// @implementation may have private ivars. + SourceLocation IvarLBraceLoc; + SourceLocation IvarRBraceLoc; + + /// Support for ivar initialization. + /// IvarInitializers - The arguments used to initialize the ivars + CXXCtorInitializer **IvarInitializers; + unsigned NumIvarInitializers; + + /// true if class has a .cxx_[construct,destruct] method. + bool HasCXXStructors : 1; + + /// true of class extension has at least one bitfield ivar. + bool HasSynthBitfield : 1; + + ObjCImplementationDecl(DeclContext *DC, + ObjCInterfaceDecl *classInterface, + ObjCInterfaceDecl *superDecl, + SourceLocation nameLoc, SourceLocation atStartLoc, + SourceLocation IvarLBraceLoc=SourceLocation(), + SourceLocation IvarRBraceLoc=SourceLocation()) + : ObjCImplDecl(ObjCImplementation, DC, classInterface, nameLoc, atStartLoc), + SuperClass(superDecl), IvarLBraceLoc(IvarLBraceLoc), + IvarRBraceLoc(IvarRBraceLoc), + IvarInitializers(0), NumIvarInitializers(0), + HasCXXStructors(false), HasSynthBitfield(false){} +public: + static ObjCImplementationDecl *Create(ASTContext &C, DeclContext *DC, + ObjCInterfaceDecl *classInterface, + ObjCInterfaceDecl *superDecl, + SourceLocation nameLoc, + SourceLocation atStartLoc, + SourceLocation IvarLBraceLoc=SourceLocation(), + SourceLocation IvarRBraceLoc=SourceLocation()); + + static ObjCImplementationDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + /// init_iterator - Iterates through the ivar initializer list. + typedef CXXCtorInitializer **init_iterator; + + /// init_const_iterator - Iterates through the ivar initializer list. + typedef CXXCtorInitializer * const * init_const_iterator; + + /// init_begin() - Retrieve an iterator to the first initializer. + init_iterator init_begin() { return IvarInitializers; } + /// begin() - Retrieve an iterator to the first initializer. + init_const_iterator init_begin() const { return IvarInitializers; } + + /// init_end() - Retrieve an iterator past the last initializer. + init_iterator init_end() { + return IvarInitializers + NumIvarInitializers; + } + /// end() - Retrieve an iterator past the last initializer. + init_const_iterator init_end() const { + return IvarInitializers + NumIvarInitializers; + } + /// getNumArgs - Number of ivars which must be initialized. + unsigned getNumIvarInitializers() const { + return NumIvarInitializers; + } + + void setNumIvarInitializers(unsigned numNumIvarInitializers) { + NumIvarInitializers = numNumIvarInitializers; + } + + void setIvarInitializers(ASTContext &C, + CXXCtorInitializer ** initializers, + unsigned numInitializers); + + bool hasCXXStructors() const { return HasCXXStructors; } + void setHasCXXStructors(bool val) { HasCXXStructors = val; } + + bool hasSynthBitfield() const { return HasSynthBitfield; } + void setHasSynthBitfield (bool val) { HasSynthBitfield = val; } + + /// getIdentifier - Get the identifier that names the class + /// interface associated with this implementation. + IdentifierInfo *getIdentifier() const { + return getClassInterface()->getIdentifier(); + } + + /// getName - Get the name of identifier for the class interface associated + /// with this implementation as a StringRef. + // + // FIXME: This is a bad API, we are overriding the NamedDecl::getName, to mean + // something different. + StringRef getName() const { + assert(getIdentifier() && "Name is not a simple identifier"); + return getIdentifier()->getName(); + } + + /// getNameAsCString - Get the name of identifier for the class + /// interface associated with this implementation as a C string + /// (const char*). + // + // FIXME: Move to StringRef API. + const char *getNameAsCString() const { + return getName().data(); + } + + /// @brief Get the name of the class associated with this interface. + // + // FIXME: Move to StringRef API. + std::string getNameAsString() const { + return getName(); + } + + const ObjCInterfaceDecl *getSuperClass() const { return SuperClass; } + ObjCInterfaceDecl *getSuperClass() { return SuperClass; } + + void setSuperClass(ObjCInterfaceDecl * superCls) { SuperClass = superCls; } + + void setIvarLBraceLoc(SourceLocation Loc) { IvarLBraceLoc = Loc; } + SourceLocation getIvarLBraceLoc() const { return IvarLBraceLoc; } + void setIvarRBraceLoc(SourceLocation Loc) { IvarRBraceLoc = Loc; } + SourceLocation getIvarRBraceLoc() const { return IvarRBraceLoc; } + + typedef specific_decl_iterator<ObjCIvarDecl> ivar_iterator; + ivar_iterator ivar_begin() const { + return ivar_iterator(decls_begin()); + } + ivar_iterator ivar_end() const { + return ivar_iterator(decls_end()); + } + unsigned ivar_size() const { + return std::distance(ivar_begin(), ivar_end()); + } + bool ivar_empty() const { + return ivar_begin() == ivar_end(); + } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const ObjCImplementationDecl *D) { return true; } + static bool classofKind(Kind K) { return K == ObjCImplementation; } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +raw_ostream &operator<<(raw_ostream &OS, const ObjCImplementationDecl &ID); + +/// ObjCCompatibleAliasDecl - Represents alias of a class. This alias is +/// declared as @compatibility_alias alias class. +class ObjCCompatibleAliasDecl : public NamedDecl { + virtual void anchor(); + /// Class that this is an alias of. + ObjCInterfaceDecl *AliasedClass; + + ObjCCompatibleAliasDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id, + ObjCInterfaceDecl* aliasedClass) + : NamedDecl(ObjCCompatibleAlias, DC, L, Id), AliasedClass(aliasedClass) {} +public: + static ObjCCompatibleAliasDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id, + ObjCInterfaceDecl* aliasedClass); + + static ObjCCompatibleAliasDecl *CreateDeserialized(ASTContext &C, + unsigned ID); + + const ObjCInterfaceDecl *getClassInterface() const { return AliasedClass; } + ObjCInterfaceDecl *getClassInterface() { return AliasedClass; } + void setClassInterface(ObjCInterfaceDecl *D) { AliasedClass = D; } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const ObjCCompatibleAliasDecl *D) { return true; } + static bool classofKind(Kind K) { return K == ObjCCompatibleAlias; } + +}; + +/// ObjCPropertyDecl - Represents one property declaration in an interface. +/// For example: +/// @property (assign, readwrite) int MyProperty; +/// +class ObjCPropertyDecl : public NamedDecl { + virtual void anchor(); +public: + enum PropertyAttributeKind { + OBJC_PR_noattr = 0x00, + OBJC_PR_readonly = 0x01, + OBJC_PR_getter = 0x02, + OBJC_PR_assign = 0x04, + OBJC_PR_readwrite = 0x08, + OBJC_PR_retain = 0x10, + OBJC_PR_copy = 0x20, + OBJC_PR_nonatomic = 0x40, + OBJC_PR_setter = 0x80, + OBJC_PR_atomic = 0x100, + OBJC_PR_weak = 0x200, + OBJC_PR_strong = 0x400, + OBJC_PR_unsafe_unretained = 0x800 + // Adding a property should change NumPropertyAttrsBits + }; + + enum { + /// \brief Number of bits fitting all the property attributes. + NumPropertyAttrsBits = 12 + }; + + enum SetterKind { Assign, Retain, Copy, Weak }; + enum PropertyControl { None, Required, Optional }; +private: + SourceLocation AtLoc; // location of @property + SourceLocation LParenLoc; // location of '(' starting attribute list or null. + TypeSourceInfo *DeclType; + unsigned PropertyAttributes : NumPropertyAttrsBits; + unsigned PropertyAttributesAsWritten : NumPropertyAttrsBits; + // @required/@optional + unsigned PropertyImplementation : 2; + + Selector GetterName; // getter name of NULL if no getter + Selector SetterName; // setter name of NULL if no setter + + ObjCMethodDecl *GetterMethodDecl; // Declaration of getter instance method + ObjCMethodDecl *SetterMethodDecl; // Declaration of setter instance method + ObjCIvarDecl *PropertyIvarDecl; // Synthesize ivar for this property + + ObjCPropertyDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id, + SourceLocation AtLocation, SourceLocation LParenLocation, + TypeSourceInfo *T) + : NamedDecl(ObjCProperty, DC, L, Id), AtLoc(AtLocation), + LParenLoc(LParenLocation), DeclType(T), + PropertyAttributes(OBJC_PR_noattr), + PropertyAttributesAsWritten(OBJC_PR_noattr), + PropertyImplementation(None), + GetterName(Selector()), + SetterName(Selector()), + GetterMethodDecl(0), SetterMethodDecl(0) , PropertyIvarDecl(0) {} +public: + static ObjCPropertyDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + IdentifierInfo *Id, SourceLocation AtLocation, + SourceLocation LParenLocation, + TypeSourceInfo *T, + PropertyControl propControl = None); + + static ObjCPropertyDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + SourceLocation getAtLoc() const { return AtLoc; } + void setAtLoc(SourceLocation L) { AtLoc = L; } + + SourceLocation getLParenLoc() const { return LParenLoc; } + void setLParenLoc(SourceLocation L) { LParenLoc = L; } + + TypeSourceInfo *getTypeSourceInfo() const { return DeclType; } + QualType getType() const { return DeclType->getType(); } + void setType(TypeSourceInfo *T) { DeclType = T; } + + PropertyAttributeKind getPropertyAttributes() const { + return PropertyAttributeKind(PropertyAttributes); + } + void setPropertyAttributes(PropertyAttributeKind PRVal) { + PropertyAttributes |= PRVal; + } + + PropertyAttributeKind getPropertyAttributesAsWritten() const { + return PropertyAttributeKind(PropertyAttributesAsWritten); + } + + bool hasWrittenStorageAttribute() const { + return PropertyAttributesAsWritten & (OBJC_PR_assign | OBJC_PR_copy | + OBJC_PR_unsafe_unretained | OBJC_PR_retain | OBJC_PR_strong | + OBJC_PR_weak); + } + + void setPropertyAttributesAsWritten(PropertyAttributeKind PRVal) { + PropertyAttributesAsWritten = PRVal; + } + + void makeitReadWriteAttribute(void) { + PropertyAttributes &= ~OBJC_PR_readonly; + PropertyAttributes |= OBJC_PR_readwrite; + } + + // Helper methods for accessing attributes. + + /// isReadOnly - Return true iff the property has a setter. + bool isReadOnly() const { + return (PropertyAttributes & OBJC_PR_readonly); + } + + /// isAtomic - Return true if the property is atomic. + bool isAtomic() const { + return (PropertyAttributes & OBJC_PR_atomic); + } + + /// isRetaining - Return true if the property retains its value. + bool isRetaining() const { + return (PropertyAttributes & + (OBJC_PR_retain | OBJC_PR_strong | OBJC_PR_copy)); + } + + /// getSetterKind - Return the method used for doing assignment in + /// the property setter. This is only valid if the property has been + /// defined to have a setter. + SetterKind getSetterKind() const { + if (PropertyAttributes & OBJC_PR_strong) + return getType()->isBlockPointerType() ? Copy : Retain; + if (PropertyAttributes & OBJC_PR_retain) + return Retain; + if (PropertyAttributes & OBJC_PR_copy) + return Copy; + if (PropertyAttributes & OBJC_PR_weak) + return Weak; + return Assign; + } + + Selector getGetterName() const { return GetterName; } + void setGetterName(Selector Sel) { GetterName = Sel; } + + Selector getSetterName() const { return SetterName; } + void setSetterName(Selector Sel) { SetterName = Sel; } + + ObjCMethodDecl *getGetterMethodDecl() const { return GetterMethodDecl; } + void setGetterMethodDecl(ObjCMethodDecl *gDecl) { GetterMethodDecl = gDecl; } + + ObjCMethodDecl *getSetterMethodDecl() const { return SetterMethodDecl; } + void setSetterMethodDecl(ObjCMethodDecl *gDecl) { SetterMethodDecl = gDecl; } + + // Related to @optional/@required declared in @protocol + void setPropertyImplementation(PropertyControl pc) { + PropertyImplementation = pc; + } + PropertyControl getPropertyImplementation() const { + return PropertyControl(PropertyImplementation); + } + + void setPropertyIvarDecl(ObjCIvarDecl *Ivar) { + PropertyIvarDecl = Ivar; + } + ObjCIvarDecl *getPropertyIvarDecl() const { + return PropertyIvarDecl; + } + + virtual SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(AtLoc, getLocation()); + } + + /// Lookup a property by name in the specified DeclContext. + static ObjCPropertyDecl *findPropertyDecl(const DeclContext *DC, + IdentifierInfo *propertyID); + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const ObjCPropertyDecl *D) { return true; } + static bool classofKind(Kind K) { return K == ObjCProperty; } +}; + +/// ObjCPropertyImplDecl - Represents implementation declaration of a property +/// in a class or category implementation block. For example: +/// @synthesize prop1 = ivar1; +/// +class ObjCPropertyImplDecl : public Decl { +public: + enum Kind { + Synthesize, + Dynamic + }; +private: + SourceLocation AtLoc; // location of @synthesize or @dynamic + + /// \brief For @synthesize, the location of the ivar, if it was written in + /// the source code. + /// + /// \code + /// @synthesize int a = b + /// \endcode + SourceLocation IvarLoc; + + /// Property declaration being implemented + ObjCPropertyDecl *PropertyDecl; + + /// Null for @dynamic. Required for @synthesize. + ObjCIvarDecl *PropertyIvarDecl; + + /// Null for @dynamic. Non-null if property must be copy-constructed in getter + Expr *GetterCXXConstructor; + + /// Null for @dynamic. Non-null if property has assignment operator to call + /// in Setter synthesis. + Expr *SetterCXXAssignment; + + ObjCPropertyImplDecl(DeclContext *DC, SourceLocation atLoc, SourceLocation L, + ObjCPropertyDecl *property, + Kind PK, + ObjCIvarDecl *ivarDecl, + SourceLocation ivarLoc) + : Decl(ObjCPropertyImpl, DC, L), AtLoc(atLoc), + IvarLoc(ivarLoc), PropertyDecl(property), PropertyIvarDecl(ivarDecl), + GetterCXXConstructor(0), SetterCXXAssignment(0) { + assert (PK == Dynamic || PropertyIvarDecl); + } + +public: + static ObjCPropertyImplDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation atLoc, SourceLocation L, + ObjCPropertyDecl *property, + Kind PK, + ObjCIvarDecl *ivarDecl, + SourceLocation ivarLoc); + + static ObjCPropertyImplDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + virtual SourceRange getSourceRange() const LLVM_READONLY; + + SourceLocation getLocStart() const LLVM_READONLY { return AtLoc; } + void setAtLoc(SourceLocation Loc) { AtLoc = Loc; } + + ObjCPropertyDecl *getPropertyDecl() const { + return PropertyDecl; + } + void setPropertyDecl(ObjCPropertyDecl *Prop) { PropertyDecl = Prop; } + + Kind getPropertyImplementation() const { + return PropertyIvarDecl ? Synthesize : Dynamic; + } + + ObjCIvarDecl *getPropertyIvarDecl() const { + return PropertyIvarDecl; + } + SourceLocation getPropertyIvarDeclLoc() const { return IvarLoc; } + + void setPropertyIvarDecl(ObjCIvarDecl *Ivar, + SourceLocation IvarLoc) { + PropertyIvarDecl = Ivar; + this->IvarLoc = IvarLoc; + } + + Expr *getGetterCXXConstructor() const { + return GetterCXXConstructor; + } + void setGetterCXXConstructor(Expr *getterCXXConstructor) { + GetterCXXConstructor = getterCXXConstructor; + } + + Expr *getSetterCXXAssignment() const { + return SetterCXXAssignment; + } + void setSetterCXXAssignment(Expr *setterCXXAssignment) { + SetterCXXAssignment = setterCXXAssignment; + } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const ObjCPropertyImplDecl *D) { return true; } + static bool classofKind(Decl::Kind K) { return K == ObjCPropertyImpl; } + + friend class ASTDeclReader; +}; + +} // end namespace clang +#endif diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h new file mode 100644 index 0000000..36549ea --- /dev/null +++ b/clang/include/clang/AST/DeclTemplate.h @@ -0,0 +1,2106 @@ +//===-- DeclTemplate.h - Classes for representing C++ templates -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the C++ template declaration subclasses. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_DECLTEMPLATE_H +#define LLVM_CLANG_AST_DECLTEMPLATE_H + +#include "clang/AST/DeclCXX.h" +#include "clang/AST/Redeclarable.h" +#include "clang/AST/TemplateBase.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/Support/Compiler.h" +#include <limits> + +namespace clang { + +class TemplateParameterList; +class TemplateDecl; +class RedeclarableTemplateDecl; +class FunctionTemplateDecl; +class ClassTemplateDecl; +class ClassTemplatePartialSpecializationDecl; +class TemplateTypeParmDecl; +class NonTypeTemplateParmDecl; +class TemplateTemplateParmDecl; +class TypeAliasTemplateDecl; + +/// \brief Stores a template parameter of any kind. +typedef llvm::PointerUnion3<TemplateTypeParmDecl*, NonTypeTemplateParmDecl*, + TemplateTemplateParmDecl*> TemplateParameter; + +/// TemplateParameterList - Stores a list of template parameters for a +/// TemplateDecl and its derived classes. +class TemplateParameterList { + /// The location of the 'template' keyword. + SourceLocation TemplateLoc; + + /// The locations of the '<' and '>' angle brackets. + SourceLocation LAngleLoc, RAngleLoc; + + /// The number of template parameters in this template + /// parameter list. + unsigned NumParams; + +protected: + TemplateParameterList(SourceLocation TemplateLoc, SourceLocation LAngleLoc, + NamedDecl **Params, unsigned NumParams, + SourceLocation RAngleLoc); + +public: + static TemplateParameterList *Create(const ASTContext &C, + SourceLocation TemplateLoc, + SourceLocation LAngleLoc, + NamedDecl **Params, + unsigned NumParams, + SourceLocation RAngleLoc); + + /// iterator - Iterates through the template parameters in this list. + typedef NamedDecl** iterator; + + /// const_iterator - Iterates through the template parameters in this list. + typedef NamedDecl* const* const_iterator; + + iterator begin() { return reinterpret_cast<NamedDecl **>(this + 1); } + const_iterator begin() const { + return reinterpret_cast<NamedDecl * const *>(this + 1); + } + iterator end() { return begin() + NumParams; } + const_iterator end() const { return begin() + NumParams; } + + unsigned size() const { return NumParams; } + + NamedDecl* getParam(unsigned Idx) { + assert(Idx < size() && "Template parameter index out-of-range"); + return begin()[Idx]; + } + + const NamedDecl* getParam(unsigned Idx) const { + assert(Idx < size() && "Template parameter index out-of-range"); + return begin()[Idx]; + } + + /// \brief Returns the minimum number of arguments needed to form a + /// template specialization. This may be fewer than the number of + /// template parameters, if some of the parameters have default + /// arguments or if there is a parameter pack. + unsigned getMinRequiredArguments() const; + + /// \brief Get the depth of this template parameter list in the set of + /// template parameter lists. + /// + /// The first template parameter list in a declaration will have depth 0, + /// the second template parameter list will have depth 1, etc. + unsigned getDepth() const; + + SourceLocation getTemplateLoc() const { return TemplateLoc; } + SourceLocation getLAngleLoc() const { return LAngleLoc; } + SourceLocation getRAngleLoc() const { return RAngleLoc; } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(TemplateLoc, RAngleLoc); + } +}; + +/// FixedSizeTemplateParameterList - Stores a list of template parameters for a +/// TemplateDecl and its derived classes. Suitable for creating on the stack. +template<size_t N> +class FixedSizeTemplateParameterList : public TemplateParameterList { + NamedDecl *Params[N]; + +public: + FixedSizeTemplateParameterList(SourceLocation TemplateLoc, + SourceLocation LAngleLoc, + NamedDecl **Params, SourceLocation RAngleLoc) : + TemplateParameterList(TemplateLoc, LAngleLoc, Params, N, RAngleLoc) { + } +}; + +/// \brief A template argument list. +class TemplateArgumentList { + /// \brief The template argument list. + /// + /// The integer value will be non-zero to indicate that this + /// template argument list does own the pointer. + llvm::PointerIntPair<const TemplateArgument *, 1> Arguments; + + /// \brief The number of template arguments in this template + /// argument list. + unsigned NumArguments; + + TemplateArgumentList(const TemplateArgumentList &Other); // DO NOT IMPL + void operator=(const TemplateArgumentList &Other); // DO NOT IMPL + + TemplateArgumentList(const TemplateArgument *Args, unsigned NumArgs, + bool Owned) + : Arguments(Args, Owned), NumArguments(NumArgs) { } + +public: + /// \brief Type used to indicate that the template argument list itself is a + /// stack object. It does not own its template arguments. + enum OnStackType { OnStack }; + + /// \brief Create a new template argument list that copies the given set of + /// template arguments. + static TemplateArgumentList *CreateCopy(ASTContext &Context, + const TemplateArgument *Args, + unsigned NumArgs); + + /// \brief Construct a new, temporary template argument list on the stack. + /// + /// The template argument list does not own the template arguments + /// provided. + explicit TemplateArgumentList(OnStackType, + const TemplateArgument *Args, unsigned NumArgs) + : Arguments(Args, false), NumArguments(NumArgs) { } + + /// \brief Produces a shallow copy of the given template argument list. + /// + /// This operation assumes that the input argument list outlives it. + /// This takes the list as a pointer to avoid looking like a copy + /// constructor, since this really really isn't safe to use that + /// way. + explicit TemplateArgumentList(const TemplateArgumentList *Other) + : Arguments(Other->data(), false), NumArguments(Other->size()) { } + + /// \brief Retrieve the template argument at a given index. + const TemplateArgument &get(unsigned Idx) const { + assert(Idx < NumArguments && "Invalid template argument index"); + return data()[Idx]; + } + + /// \brief Retrieve the template argument at a given index. + const TemplateArgument &operator[](unsigned Idx) const { return get(Idx); } + + /// \brief Retrieve the number of template arguments in this + /// template argument list. + unsigned size() const { return NumArguments; } + + /// \brief Retrieve a pointer to the template argument list. + const TemplateArgument *data() const { + return Arguments.getPointer(); + } +}; + +//===----------------------------------------------------------------------===// +// Kinds of Templates +//===----------------------------------------------------------------------===// + +/// TemplateDecl - The base class of all kinds of template declarations (e.g., +/// class, function, etc.). The TemplateDecl class stores the list of template +/// parameters and a reference to the templated scoped declaration: the +/// underlying AST node. +class TemplateDecl : public NamedDecl { + virtual void anchor(); +protected: + // This is probably never used. + TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, + DeclarationName Name) + : NamedDecl(DK, DC, L, Name), TemplatedDecl(0), TemplateParams(0) { } + + // Construct a template decl with the given name and parameters. + // Used when there is not templated element (tt-params, alias?). + TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, + DeclarationName Name, TemplateParameterList *Params) + : NamedDecl(DK, DC, L, Name), TemplatedDecl(0), TemplateParams(Params) { } + + // Construct a template decl with name, parameters, and templated element. + TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, + DeclarationName Name, TemplateParameterList *Params, + NamedDecl *Decl) + : NamedDecl(DK, DC, L, Name), TemplatedDecl(Decl), + TemplateParams(Params) { } +public: + /// Get the list of template parameters + TemplateParameterList *getTemplateParameters() const { + return TemplateParams; + } + + /// Get the underlying, templated declaration. + NamedDecl *getTemplatedDecl() const { return TemplatedDecl; } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const TemplateDecl *D) { return true; } + static bool classof(const RedeclarableTemplateDecl *D) { return true; } + static bool classof(const FunctionTemplateDecl *D) { return true; } + static bool classof(const ClassTemplateDecl *D) { return true; } + static bool classof(const TemplateTemplateParmDecl *D) { return true; } + static bool classof(const TypeAliasTemplateDecl *D) { return true; } + static bool classofKind(Kind K) { + return K >= firstTemplate && K <= lastTemplate; + } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(TemplateParams->getTemplateLoc(), + TemplatedDecl->getSourceRange().getEnd()); + } + +protected: + NamedDecl *TemplatedDecl; + TemplateParameterList* TemplateParams; + +public: + /// \brief Initialize the underlying templated declaration and + /// template parameters. + void init(NamedDecl *templatedDecl, TemplateParameterList* templateParams) { + assert(TemplatedDecl == 0 && "TemplatedDecl already set!"); + assert(TemplateParams == 0 && "TemplateParams already set!"); + TemplatedDecl = templatedDecl; + TemplateParams = templateParams; + } +}; + +/// \brief Provides information about a function template specialization, +/// which is a FunctionDecl that has been explicitly specialization or +/// instantiated from a function template. +class FunctionTemplateSpecializationInfo : public llvm::FoldingSetNode { + FunctionTemplateSpecializationInfo(FunctionDecl *FD, + FunctionTemplateDecl *Template, + TemplateSpecializationKind TSK, + const TemplateArgumentList *TemplateArgs, + const ASTTemplateArgumentListInfo *TemplateArgsAsWritten, + SourceLocation POI) + : Function(FD), + Template(Template, TSK - 1), + TemplateArguments(TemplateArgs), + TemplateArgumentsAsWritten(TemplateArgsAsWritten), + PointOfInstantiation(POI) { } + +public: + static FunctionTemplateSpecializationInfo * + Create(ASTContext &C, FunctionDecl *FD, FunctionTemplateDecl *Template, + TemplateSpecializationKind TSK, + const TemplateArgumentList *TemplateArgs, + const TemplateArgumentListInfo *TemplateArgsAsWritten, + SourceLocation POI); + + /// \brief The function template specialization that this structure + /// describes. + FunctionDecl *Function; + + /// \brief The function template from which this function template + /// specialization was generated. + /// + /// The two bits are contain the top 4 values of TemplateSpecializationKind. + llvm::PointerIntPair<FunctionTemplateDecl *, 2> Template; + + /// \brief The template arguments used to produce the function template + /// specialization from the function template. + const TemplateArgumentList *TemplateArguments; + + /// \brief The template arguments as written in the sources, if provided. + const ASTTemplateArgumentListInfo *TemplateArgumentsAsWritten; + + /// \brief The point at which this function template specialization was + /// first instantiated. + SourceLocation PointOfInstantiation; + + /// \brief Retrieve the template from which this function was specialized. + FunctionTemplateDecl *getTemplate() const { return Template.getPointer(); } + + /// \brief Determine what kind of template specialization this is. + TemplateSpecializationKind getTemplateSpecializationKind() const { + return (TemplateSpecializationKind)(Template.getInt() + 1); + } + + bool isExplicitSpecialization() const { + return getTemplateSpecializationKind() == TSK_ExplicitSpecialization; + } + + /// \brief Set the template specialization kind. + void setTemplateSpecializationKind(TemplateSpecializationKind TSK) { + assert(TSK != TSK_Undeclared && + "Cannot encode TSK_Undeclared for a function template specialization"); + Template.setInt(TSK - 1); + } + + /// \brief Retrieve the first point of instantiation of this function + /// template specialization. + /// + /// The point of instantiation may be an invalid source location if this + /// function has yet to be instantiated. + SourceLocation getPointOfInstantiation() const { + return PointOfInstantiation; + } + + /// \brief Set the (first) point of instantiation of this function template + /// specialization. + void setPointOfInstantiation(SourceLocation POI) { + PointOfInstantiation = POI; + } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, TemplateArguments->data(), + TemplateArguments->size(), + Function->getASTContext()); + } + + static void + Profile(llvm::FoldingSetNodeID &ID, const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, ASTContext &Context) { + ID.AddInteger(NumTemplateArgs); + for (unsigned Arg = 0; Arg != NumTemplateArgs; ++Arg) + TemplateArgs[Arg].Profile(ID, Context); + } +}; + +/// \brief Provides information a specialization of a member of a class +/// template, which may be a member function, static data member, +/// member class or member enumeration. +class MemberSpecializationInfo { + // The member declaration from which this member was instantiated, and the + // manner in which the instantiation occurred (in the lower two bits). + llvm::PointerIntPair<NamedDecl *, 2> MemberAndTSK; + + // The point at which this member was first instantiated. + SourceLocation PointOfInstantiation; + +public: + explicit + MemberSpecializationInfo(NamedDecl *IF, TemplateSpecializationKind TSK, + SourceLocation POI = SourceLocation()) + : MemberAndTSK(IF, TSK - 1), PointOfInstantiation(POI) { + assert(TSK != TSK_Undeclared && + "Cannot encode undeclared template specializations for members"); + } + + /// \brief Retrieve the member declaration from which this member was + /// instantiated. + NamedDecl *getInstantiatedFrom() const { return MemberAndTSK.getPointer(); } + + /// \brief Determine what kind of template specialization this is. + TemplateSpecializationKind getTemplateSpecializationKind() const { + return (TemplateSpecializationKind)(MemberAndTSK.getInt() + 1); + } + + /// \brief Set the template specialization kind. + void setTemplateSpecializationKind(TemplateSpecializationKind TSK) { + assert(TSK != TSK_Undeclared && + "Cannot encode undeclared template specializations for members"); + MemberAndTSK.setInt(TSK - 1); + } + + /// \brief Retrieve the first point of instantiation of this member. + /// If the point of instantiation is an invalid location, then this member + /// has not yet been instantiated. + SourceLocation getPointOfInstantiation() const { + return PointOfInstantiation; + } + + /// \brief Set the first point of instantiation. + void setPointOfInstantiation(SourceLocation POI) { + PointOfInstantiation = POI; + } +}; + +/// \brief Provides information about a dependent function-template +/// specialization declaration. Since explicit function template +/// specialization and instantiation declarations can only appear in +/// namespace scope, and you can only specialize a member of a +/// fully-specialized class, the only way to get one of these is in +/// a friend declaration like the following: +/// +/// template <class T> void foo(T); +/// template <class T> class A { +/// friend void foo<>(T); +/// }; +class DependentFunctionTemplateSpecializationInfo { + union { + // Force sizeof to be a multiple of sizeof(void*) so that the + // trailing data is aligned. + void *Aligner; + + struct { + /// The number of potential template candidates. + unsigned NumTemplates; + + /// The number of template arguments. + unsigned NumArgs; + } d; + }; + + /// The locations of the left and right angle brackets. + SourceRange AngleLocs; + + FunctionTemplateDecl * const *getTemplates() const { + return reinterpret_cast<FunctionTemplateDecl*const*>(this+1); + } + +public: + DependentFunctionTemplateSpecializationInfo( + const UnresolvedSetImpl &Templates, + const TemplateArgumentListInfo &TemplateArgs); + + /// \brief Returns the number of function templates that this might + /// be a specialization of. + unsigned getNumTemplates() const { + return d.NumTemplates; + } + + /// \brief Returns the i'th template candidate. + FunctionTemplateDecl *getTemplate(unsigned I) const { + assert(I < getNumTemplates() && "template index out of range"); + return getTemplates()[I]; + } + + /// \brief Returns the explicit template arguments that were given. + const TemplateArgumentLoc *getTemplateArgs() const { + return reinterpret_cast<const TemplateArgumentLoc*>( + &getTemplates()[getNumTemplates()]); + } + + /// \brief Returns the number of explicit template arguments that were given. + unsigned getNumTemplateArgs() const { + return d.NumArgs; + } + + /// \brief Returns the nth template argument. + const TemplateArgumentLoc &getTemplateArg(unsigned I) const { + assert(I < getNumTemplateArgs() && "template arg index out of range"); + return getTemplateArgs()[I]; + } + + SourceLocation getLAngleLoc() const { + return AngleLocs.getBegin(); + } + + SourceLocation getRAngleLoc() const { + return AngleLocs.getEnd(); + } +}; + +/// Declaration of a redeclarable template. +class RedeclarableTemplateDecl : public TemplateDecl, + public Redeclarable<RedeclarableTemplateDecl> +{ + typedef Redeclarable<RedeclarableTemplateDecl> redeclarable_base; + virtual RedeclarableTemplateDecl *getNextRedeclaration() { + return RedeclLink.getNext(); + } + virtual RedeclarableTemplateDecl *getPreviousDeclImpl() { + return getPreviousDecl(); + } + virtual RedeclarableTemplateDecl *getMostRecentDeclImpl() { + return getMostRecentDecl(); + } + +protected: + template <typename EntryType> struct SpecEntryTraits { + typedef EntryType DeclType; + + static DeclType *getMostRecentDecl(EntryType *D) { + return D->getMostRecentDecl(); + } + }; + + template <typename EntryType, + typename _SETraits = SpecEntryTraits<EntryType>, + typename _DeclType = typename _SETraits::DeclType> + class SpecIterator : public std::iterator<std::forward_iterator_tag, + _DeclType*, ptrdiff_t, + _DeclType*, _DeclType*> { + typedef _SETraits SETraits; + typedef _DeclType DeclType; + + typedef typename llvm::FoldingSet<EntryType>::iterator SetIteratorType; + + SetIteratorType SetIter; + + public: + SpecIterator() : SetIter() {} + SpecIterator(SetIteratorType SetIter) : SetIter(SetIter) {} + + DeclType *operator*() const { + return SETraits::getMostRecentDecl(&*SetIter); + } + DeclType *operator->() const { return **this; } + + SpecIterator &operator++() { ++SetIter; return *this; } + SpecIterator operator++(int) { + SpecIterator tmp(*this); + ++(*this); + return tmp; + } + + bool operator==(SpecIterator Other) const { + return SetIter == Other.SetIter; + } + bool operator!=(SpecIterator Other) const { + return SetIter != Other.SetIter; + } + }; + + template <typename EntryType> + SpecIterator<EntryType> makeSpecIterator(llvm::FoldingSet<EntryType> &Specs, + bool isEnd) { + return SpecIterator<EntryType>(isEnd ? Specs.end() : Specs.begin()); + } + + template <class EntryType> typename SpecEntryTraits<EntryType>::DeclType* + findSpecializationImpl(llvm::FoldingSet<EntryType> &Specs, + const TemplateArgument *Args, unsigned NumArgs, + void *&InsertPos); + + struct CommonBase { + CommonBase() : InstantiatedFromMember(0, false) { } + + /// \brief The template from which this was most + /// directly instantiated (or null). + /// + /// The boolean value indicates whether this template + /// was explicitly specialized. + llvm::PointerIntPair<RedeclarableTemplateDecl*, 1, bool> + InstantiatedFromMember; + }; + + /// \brief Pointer to the common data shared by all declarations of this + /// template. + CommonBase *Common; + + /// \brief Retrieves the "common" pointer shared by all (re-)declarations of + /// the same template. Calling this routine may implicitly allocate memory + /// for the common pointer. + CommonBase *getCommonPtr(); + + virtual CommonBase *newCommon(ASTContext &C) = 0; + + // Construct a template decl with name, parameters, and templated element. + RedeclarableTemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, + DeclarationName Name, TemplateParameterList *Params, + NamedDecl *Decl) + : TemplateDecl(DK, DC, L, Name, Params, Decl), Common() { } + +public: + template <class decl_type> friend class RedeclarableTemplate; + + /// Retrieves the canonical declaration of this template. + RedeclarableTemplateDecl *getCanonicalDecl() { return getFirstDeclaration(); } + const RedeclarableTemplateDecl *getCanonicalDecl() const { + return getFirstDeclaration(); + } + + /// \brief Determines whether this template was a specialization of a + /// member template. + /// + /// In the following example, the function template \c X<int>::f and the + /// member template \c X<int>::Inner are member specializations. + /// + /// \code + /// template<typename T> + /// struct X { + /// template<typename U> void f(T, U); + /// template<typename U> struct Inner; + /// }; + /// + /// template<> template<typename T> + /// void X<int>::f(int, T); + /// template<> template<typename T> + /// struct X<int>::Inner { /* ... */ }; + /// \endcode + bool isMemberSpecialization() { + return getCommonPtr()->InstantiatedFromMember.getInt(); + } + + /// \brief Note that this member template is a specialization. + void setMemberSpecialization() { + assert(getCommonPtr()->InstantiatedFromMember.getPointer() && + "Only member templates can be member template specializations"); + getCommonPtr()->InstantiatedFromMember.setInt(true); + } + + /// \brief Retrieve the member template from which this template was + /// instantiated, or NULL if this template was not instantiated from a + /// member template. + /// + /// A template is instantiated from a member template when the member + /// template itself is part of a class template (or member thereof). For + /// example, given + /// + /// \code + /// template<typename T> + /// struct X { + /// template<typename U> void f(T, U); + /// }; + /// + /// void test(X<int> x) { + /// x.f(1, 'a'); + /// }; + /// \endcode + /// + /// \c X<int>::f is a FunctionTemplateDecl that describes the function + /// template + /// + /// \code + /// template<typename U> void X<int>::f(int, U); + /// \endcode + /// + /// which was itself created during the instantiation of \c X<int>. Calling + /// getInstantiatedFromMemberTemplate() on this FunctionTemplateDecl will + /// retrieve the FunctionTemplateDecl for the original template "f" within + /// the class template \c X<T>, i.e., + /// + /// \code + /// template<typename T> + /// template<typename U> + /// void X<T>::f(T, U); + /// \endcode + RedeclarableTemplateDecl *getInstantiatedFromMemberTemplate() { + return getCommonPtr()->InstantiatedFromMember.getPointer(); + } + + void setInstantiatedFromMemberTemplate(RedeclarableTemplateDecl *TD) { + assert(!getCommonPtr()->InstantiatedFromMember.getPointer()); + getCommonPtr()->InstantiatedFromMember.setPointer(TD); + } + + typedef redeclarable_base::redecl_iterator redecl_iterator; + using redeclarable_base::redecls_begin; + using redeclarable_base::redecls_end; + using redeclarable_base::getPreviousDecl; + using redeclarable_base::getMostRecentDecl; + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const RedeclarableTemplateDecl *D) { return true; } + static bool classof(const FunctionTemplateDecl *D) { return true; } + static bool classof(const ClassTemplateDecl *D) { return true; } + static bool classof(const TypeAliasTemplateDecl *D) { return true; } + static bool classofKind(Kind K) { + return K >= firstRedeclarableTemplate && K <= lastRedeclarableTemplate; + } + + friend class ASTReader; + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +template <> struct RedeclarableTemplateDecl:: +SpecEntryTraits<FunctionTemplateSpecializationInfo> { + typedef FunctionDecl DeclType; + + static DeclType * + getMostRecentDecl(FunctionTemplateSpecializationInfo *I) { + return I->Function->getMostRecentDecl(); + } +}; + +/// Declaration of a template function. +class FunctionTemplateDecl : public RedeclarableTemplateDecl { + static void DeallocateCommon(void *Ptr); + +protected: + /// \brief Data that is common to all of the declarations of a given + /// function template. + struct Common : CommonBase { + Common() : InjectedArgs(0) { } + + /// \brief The function template specializations for this function + /// template, including explicit specializations and instantiations. + llvm::FoldingSet<FunctionTemplateSpecializationInfo> Specializations; + + /// \brief The set of "injected" template arguments used within this + /// function template. + /// + /// This pointer refers to the template arguments (there are as + /// many template arguments as template parameaters) for the function + /// template, and is allocated lazily, since most function templates do not + /// require the use of this information. + TemplateArgument *InjectedArgs; + }; + + FunctionTemplateDecl(DeclContext *DC, SourceLocation L, DeclarationName Name, + TemplateParameterList *Params, NamedDecl *Decl) + : RedeclarableTemplateDecl(FunctionTemplate, DC, L, Name, Params, Decl) { } + + CommonBase *newCommon(ASTContext &C); + + Common *getCommonPtr() { + return static_cast<Common *>(RedeclarableTemplateDecl::getCommonPtr()); + } + + friend class FunctionDecl; + + /// \brief Retrieve the set of function template specializations of this + /// function template. + llvm::FoldingSet<FunctionTemplateSpecializationInfo> &getSpecializations() { + return getCommonPtr()->Specializations; + } + + /// \brief Add a specialization of this function template. + /// + /// \param InsertPos Insert position in the FoldingSet, must have been + /// retrieved by an earlier call to findSpecialization(). + void addSpecialization(FunctionTemplateSpecializationInfo* Info, + void *InsertPos); + +public: + /// Get the underlying function declaration of the template. + FunctionDecl *getTemplatedDecl() const { + return static_cast<FunctionDecl*>(TemplatedDecl); + } + + /// Returns whether this template declaration defines the primary + /// pattern. + bool isThisDeclarationADefinition() const { + return getTemplatedDecl()->isThisDeclarationADefinition(); + } + + /// \brief Return the specialization with the provided arguments if it exists, + /// otherwise return the insertion point. + FunctionDecl *findSpecialization(const TemplateArgument *Args, + unsigned NumArgs, void *&InsertPos); + + FunctionTemplateDecl *getCanonicalDecl() { + return cast<FunctionTemplateDecl>( + RedeclarableTemplateDecl::getCanonicalDecl()); + } + const FunctionTemplateDecl *getCanonicalDecl() const { + return cast<FunctionTemplateDecl>( + RedeclarableTemplateDecl::getCanonicalDecl()); + } + + /// \brief Retrieve the previous declaration of this function template, or + /// NULL if no such declaration exists. + FunctionTemplateDecl *getPreviousDecl() { + return cast_or_null<FunctionTemplateDecl>( + RedeclarableTemplateDecl::getPreviousDecl()); + } + + /// \brief Retrieve the previous declaration of this function template, or + /// NULL if no such declaration exists. + const FunctionTemplateDecl *getPreviousDecl() const { + return cast_or_null<FunctionTemplateDecl>( + RedeclarableTemplateDecl::getPreviousDecl()); + } + + FunctionTemplateDecl *getInstantiatedFromMemberTemplate() { + return cast_or_null<FunctionTemplateDecl>( + RedeclarableTemplateDecl::getInstantiatedFromMemberTemplate()); + } + + typedef SpecIterator<FunctionTemplateSpecializationInfo> spec_iterator; + + spec_iterator spec_begin() { + return makeSpecIterator(getSpecializations(), false); + } + + spec_iterator spec_end() { + return makeSpecIterator(getSpecializations(), true); + } + + /// \brief Retrieve the "injected" template arguments that correspond to the + /// template parameters of this function template. + /// + /// Although the C++ standard has no notion of the "injected" template + /// arguments for a function template, the notion is convenient when + /// we need to perform substitutions inside the definition of a function + /// template. + std::pair<const TemplateArgument *, unsigned> getInjectedTemplateArgs(); + + /// \brief Create a function template node. + static FunctionTemplateDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + DeclarationName Name, + TemplateParameterList *Params, + NamedDecl *Decl); + + /// \brief Create an empty function template node. + static FunctionTemplateDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + // Implement isa/cast/dyncast support + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const FunctionTemplateDecl *D) { return true; } + static bool classofKind(Kind K) { return K == FunctionTemplate; } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +//===----------------------------------------------------------------------===// +// Kinds of Template Parameters +//===----------------------------------------------------------------------===// + +/// The TemplateParmPosition class defines the position of a template parameter +/// within a template parameter list. Because template parameter can be listed +/// sequentially for out-of-line template members, each template parameter is +/// given a Depth - the nesting of template parameter scopes - and a Position - +/// the occurrence within the parameter list. +/// This class is inheritedly privately by different kinds of template +/// parameters and is not part of the Decl hierarchy. Just a facility. +class TemplateParmPosition { +protected: + // FIXME: This should probably never be called, but it's here as + TemplateParmPosition() + : Depth(0), Position(0) + { /* llvm_unreachable("Cannot create positionless template parameter"); */ } + + TemplateParmPosition(unsigned D, unsigned P) + : Depth(D), Position(P) + { } + + // FIXME: These probably don't need to be ints. int:5 for depth, int:8 for + // position? Maybe? + unsigned Depth; + unsigned Position; + +public: + /// Get the nesting depth of the template parameter. + unsigned getDepth() const { return Depth; } + void setDepth(unsigned D) { Depth = D; } + + /// Get the position of the template parameter within its parameter list. + unsigned getPosition() const { return Position; } + void setPosition(unsigned P) { Position = P; } + + /// Get the index of the template parameter within its parameter list. + unsigned getIndex() const { return Position; } +}; + +/// TemplateTypeParmDecl - Declaration of a template type parameter, +/// e.g., "T" in +/// @code +/// template<typename T> class vector; +/// @endcode +class TemplateTypeParmDecl : public TypeDecl { + /// \brief Whether this template type parameter was declaration with + /// the 'typename' keyword. If false, it was declared with the + /// 'class' keyword. + bool Typename : 1; + + /// \brief Whether this template type parameter inherited its + /// default argument. + bool InheritedDefault : 1; + + /// \brief The default template argument, if any. + TypeSourceInfo *DefaultArgument; + + TemplateTypeParmDecl(DeclContext *DC, SourceLocation KeyLoc, + SourceLocation IdLoc, IdentifierInfo *Id, + bool Typename) + : TypeDecl(TemplateTypeParm, DC, IdLoc, Id, KeyLoc), Typename(Typename), + InheritedDefault(false), DefaultArgument() { } + + /// Sema creates these on the stack during auto type deduction. + friend class Sema; + +public: + static TemplateTypeParmDecl *Create(const ASTContext &C, DeclContext *DC, + SourceLocation KeyLoc, + SourceLocation NameLoc, + unsigned D, unsigned P, + IdentifierInfo *Id, bool Typename, + bool ParameterPack); + static TemplateTypeParmDecl *CreateDeserialized(const ASTContext &C, + unsigned ID); + + /// \brief Whether this template type parameter was declared with + /// the 'typename' keyword. If not, it was declared with the 'class' + /// keyword. + bool wasDeclaredWithTypename() const { return Typename; } + + /// \brief Determine whether this template parameter has a default + /// argument. + bool hasDefaultArgument() const { return DefaultArgument != 0; } + + /// \brief Retrieve the default argument, if any. + QualType getDefaultArgument() const { return DefaultArgument->getType(); } + + /// \brief Retrieves the default argument's source information, if any. + TypeSourceInfo *getDefaultArgumentInfo() const { return DefaultArgument; } + + /// \brief Retrieves the location of the default argument declaration. + SourceLocation getDefaultArgumentLoc() const; + + /// \brief Determines whether the default argument was inherited + /// from a previous declaration of this template. + bool defaultArgumentWasInherited() const { return InheritedDefault; } + + /// \brief Set the default argument for this template parameter, and + /// whether that default argument was inherited from another + /// declaration. + void setDefaultArgument(TypeSourceInfo *DefArg, bool Inherited) { + DefaultArgument = DefArg; + InheritedDefault = Inherited; + } + + /// \brief Removes the default argument of this template parameter. + void removeDefaultArgument() { + DefaultArgument = 0; + InheritedDefault = false; + } + + /// \brief Set whether this template type parameter was declared with + /// the 'typename' or 'class' keyword. + void setDeclaredWithTypename(bool withTypename) { Typename = withTypename; } + + /// \brief Retrieve the depth of the template parameter. + unsigned getDepth() const; + + /// \brief Retrieve the index of the template parameter. + unsigned getIndex() const; + + /// \brief Returns whether this is a parameter pack. + bool isParameterPack() const; + + SourceRange getSourceRange() const LLVM_READONLY; + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const TemplateTypeParmDecl *D) { return true; } + static bool classofKind(Kind K) { return K == TemplateTypeParm; } +}; + +/// NonTypeTemplateParmDecl - Declares a non-type template parameter, +/// e.g., "Size" in +/// @code +/// template<int Size> class array { }; +/// @endcode +class NonTypeTemplateParmDecl + : public DeclaratorDecl, protected TemplateParmPosition { + /// \brief The default template argument, if any, and whether or not + /// it was inherited. + llvm::PointerIntPair<Expr*, 1, bool> DefaultArgumentAndInherited; + + // FIXME: Collapse this into TemplateParamPosition; or, just move depth/index + // down here to save memory. + + /// \brief Whether this non-type template parameter is a parameter pack. + bool ParameterPack; + + /// \brief Whether this non-type template parameter is an "expanded" + /// parameter pack, meaning that its type is a pack expansion and we + /// already know the set of types that expansion expands to. + bool ExpandedParameterPack; + + /// \brief The number of types in an expanded parameter pack. + unsigned NumExpandedTypes; + + NonTypeTemplateParmDecl(DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, unsigned D, unsigned P, + IdentifierInfo *Id, QualType T, + bool ParameterPack, TypeSourceInfo *TInfo) + : DeclaratorDecl(NonTypeTemplateParm, DC, IdLoc, Id, T, TInfo, StartLoc), + TemplateParmPosition(D, P), DefaultArgumentAndInherited(0, false), + ParameterPack(ParameterPack), ExpandedParameterPack(false), + NumExpandedTypes(0) + { } + + NonTypeTemplateParmDecl(DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, unsigned D, unsigned P, + IdentifierInfo *Id, QualType T, + TypeSourceInfo *TInfo, + const QualType *ExpandedTypes, + unsigned NumExpandedTypes, + TypeSourceInfo **ExpandedTInfos); + + friend class ASTDeclReader; + +public: + static NonTypeTemplateParmDecl * + Create(const ASTContext &C, DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, unsigned D, unsigned P, IdentifierInfo *Id, + QualType T, bool ParameterPack, TypeSourceInfo *TInfo); + + static NonTypeTemplateParmDecl * + Create(const ASTContext &C, DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, unsigned D, unsigned P, IdentifierInfo *Id, + QualType T, TypeSourceInfo *TInfo, + const QualType *ExpandedTypes, unsigned NumExpandedTypes, + TypeSourceInfo **ExpandedTInfos); + + static NonTypeTemplateParmDecl *CreateDeserialized(ASTContext &C, + unsigned ID); + static NonTypeTemplateParmDecl *CreateDeserialized(ASTContext &C, + unsigned ID, + unsigned NumExpandedTypes); + + using TemplateParmPosition::getDepth; + using TemplateParmPosition::setDepth; + using TemplateParmPosition::getPosition; + using TemplateParmPosition::setPosition; + using TemplateParmPosition::getIndex; + + SourceRange getSourceRange() const LLVM_READONLY; + + /// \brief Determine whether this template parameter has a default + /// argument. + bool hasDefaultArgument() const { + return DefaultArgumentAndInherited.getPointer() != 0; + } + + /// \brief Retrieve the default argument, if any. + Expr *getDefaultArgument() const { + return DefaultArgumentAndInherited.getPointer(); + } + + /// \brief Retrieve the location of the default argument, if any. + SourceLocation getDefaultArgumentLoc() const; + + /// \brief Determines whether the default argument was inherited + /// from a previous declaration of this template. + bool defaultArgumentWasInherited() const { + return DefaultArgumentAndInherited.getInt(); + } + + /// \brief Set the default argument for this template parameter, and + /// whether that default argument was inherited from another + /// declaration. + void setDefaultArgument(Expr *DefArg, bool Inherited) { + DefaultArgumentAndInherited.setPointer(DefArg); + DefaultArgumentAndInherited.setInt(Inherited); + } + + /// \brief Removes the default argument of this template parameter. + void removeDefaultArgument() { + DefaultArgumentAndInherited.setPointer(0); + DefaultArgumentAndInherited.setInt(false); + } + + /// \brief Whether this parameter is a non-type template parameter pack. + /// + /// If the parameter is a parameter pack, the type may be a + /// \c PackExpansionType. In the following example, the \c Dims parameter + /// is a parameter pack (whose type is 'unsigned'). + /// + /// \code + /// template<typename T, unsigned ...Dims> struct multi_array; + /// \endcode + bool isParameterPack() const { return ParameterPack; } + + /// \brief Whether this parameter is a non-type template parameter pack + /// that has different types at different positions. + /// + /// A parameter pack is an expanded parameter pack when the original + /// parameter pack's type was itself a pack expansion, and that expansion + /// has already been expanded. For example, given: + /// + /// \code + /// template<typename ...Types> + /// struct X { + /// template<Types ...Values> + /// struct Y { /* ... */ }; + /// }; + /// \endcode + /// + /// The parameter pack \c Values has a \c PackExpansionType as its type, + /// which expands \c Types. When \c Types is supplied with template arguments + /// by instantiating \c X, the instantiation of \c Values becomes an + /// expanded parameter pack. For example, instantiating + /// \c X<int, unsigned int> results in \c Values being an expanded parameter + /// pack with expansion types \c int and \c unsigned int. + /// + /// The \c getExpansionType() and \c getExpansionTypeSourceInfo() functions + /// return the expansion types. + bool isExpandedParameterPack() const { return ExpandedParameterPack; } + + /// \brief Retrieves the number of expansion types in an expanded parameter + /// pack. + unsigned getNumExpansionTypes() const { + assert(ExpandedParameterPack && "Not an expansion parameter pack"); + return NumExpandedTypes; + } + + /// \brief Retrieve a particular expansion type within an expanded parameter + /// pack. + QualType getExpansionType(unsigned I) const { + assert(I < NumExpandedTypes && "Out-of-range expansion type index"); + void * const *TypesAndInfos = reinterpret_cast<void * const*>(this + 1); + return QualType::getFromOpaquePtr(TypesAndInfos[2*I]); + } + + /// \brief Retrieve a particular expansion type source info within an + /// expanded parameter pack. + TypeSourceInfo *getExpansionTypeSourceInfo(unsigned I) const { + assert(I < NumExpandedTypes && "Out-of-range expansion type index"); + void * const *TypesAndInfos = reinterpret_cast<void * const*>(this + 1); + return static_cast<TypeSourceInfo *>(TypesAndInfos[2*I+1]); + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const NonTypeTemplateParmDecl *D) { return true; } + static bool classofKind(Kind K) { return K == NonTypeTemplateParm; } +}; + +/// TemplateTemplateParmDecl - Declares a template template parameter, +/// e.g., "T" in +/// @code +/// template <template <typename> class T> class container { }; +/// @endcode +/// A template template parameter is a TemplateDecl because it defines the +/// name of a template and the template parameters allowable for substitution. +class TemplateTemplateParmDecl : public TemplateDecl, + protected TemplateParmPosition +{ + virtual void anchor(); + + /// DefaultArgument - The default template argument, if any. + TemplateArgumentLoc DefaultArgument; + /// Whether or not the default argument was inherited. + bool DefaultArgumentWasInherited; + + /// \brief Whether this parameter is a parameter pack. + bool ParameterPack; + + TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L, + unsigned D, unsigned P, bool ParameterPack, + IdentifierInfo *Id, TemplateParameterList *Params) + : TemplateDecl(TemplateTemplateParm, DC, L, Id, Params), + TemplateParmPosition(D, P), DefaultArgument(), + DefaultArgumentWasInherited(false), ParameterPack(ParameterPack) + { } + +public: + static TemplateTemplateParmDecl *Create(const ASTContext &C, DeclContext *DC, + SourceLocation L, unsigned D, + unsigned P, bool ParameterPack, + IdentifierInfo *Id, + TemplateParameterList *Params); + + static TemplateTemplateParmDecl *CreateDeserialized(ASTContext &C, + unsigned ID); + + using TemplateParmPosition::getDepth; + using TemplateParmPosition::getPosition; + using TemplateParmPosition::getIndex; + + /// \brief Whether this template template parameter is a template + /// parameter pack. + /// + /// \code + /// template<template <class T> ...MetaFunctions> struct Apply; + /// \endcode + bool isParameterPack() const { return ParameterPack; } + + /// \brief Determine whether this template parameter has a default + /// argument. + bool hasDefaultArgument() const { + return !DefaultArgument.getArgument().isNull(); + } + + /// \brief Retrieve the default argument, if any. + const TemplateArgumentLoc &getDefaultArgument() const { + return DefaultArgument; + } + + /// \brief Retrieve the location of the default argument, if any. + SourceLocation getDefaultArgumentLoc() const; + + /// \brief Determines whether the default argument was inherited + /// from a previous declaration of this template. + bool defaultArgumentWasInherited() const { + return DefaultArgumentWasInherited; + } + + /// \brief Set the default argument for this template parameter, and + /// whether that default argument was inherited from another + /// declaration. + void setDefaultArgument(const TemplateArgumentLoc &DefArg, bool Inherited) { + DefaultArgument = DefArg; + DefaultArgumentWasInherited = Inherited; + } + + /// \brief Removes the default argument of this template parameter. + void removeDefaultArgument() { + DefaultArgument = TemplateArgumentLoc(); + DefaultArgumentWasInherited = false; + } + + SourceRange getSourceRange() const LLVM_READONLY { + SourceLocation End = getLocation(); + if (hasDefaultArgument() && !defaultArgumentWasInherited()) + End = getDefaultArgument().getSourceRange().getEnd(); + return SourceRange(getTemplateParameters()->getTemplateLoc(), End); + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const TemplateTemplateParmDecl *D) { return true; } + static bool classofKind(Kind K) { return K == TemplateTemplateParm; } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +/// \brief Represents a class template specialization, which refers to +/// a class template with a given set of template arguments. +/// +/// Class template specializations represent both explicit +/// specialization of class templates, as in the example below, and +/// implicit instantiations of class templates. +/// +/// \code +/// template<typename T> class array; +/// +/// template<> +/// class array<bool> { }; // class template specialization array<bool> +/// \endcode +class ClassTemplateSpecializationDecl + : public CXXRecordDecl, public llvm::FoldingSetNode { + + /// \brief Structure that stores information about a class template + /// specialization that was instantiated from a class template partial + /// specialization. + struct SpecializedPartialSpecialization { + /// \brief The class template partial specialization from which this + /// class template specialization was instantiated. + ClassTemplatePartialSpecializationDecl *PartialSpecialization; + + /// \brief The template argument list deduced for the class template + /// partial specialization itself. + TemplateArgumentList *TemplateArgs; + }; + + /// \brief The template that this specialization specializes + llvm::PointerUnion<ClassTemplateDecl *, SpecializedPartialSpecialization *> + SpecializedTemplate; + + /// \brief Further info for explicit template specialization/instantiation. + struct ExplicitSpecializationInfo { + /// \brief The type-as-written. + TypeSourceInfo *TypeAsWritten; + /// \brief The location of the extern keyword. + SourceLocation ExternLoc; + /// \brief The location of the template keyword. + SourceLocation TemplateKeywordLoc; + + ExplicitSpecializationInfo() + : TypeAsWritten(0), ExternLoc(), TemplateKeywordLoc() {} + }; + + /// \brief Further info for explicit template specialization/instantiation. + /// Does not apply to implicit specializations. + ExplicitSpecializationInfo *ExplicitInfo; + + /// \brief The template arguments used to describe this specialization. + TemplateArgumentList *TemplateArgs; + + /// \brief The point where this template was instantiated (if any) + SourceLocation PointOfInstantiation; + + /// \brief The kind of specialization this declaration refers to. + /// Really a value of type TemplateSpecializationKind. + unsigned SpecializationKind : 3; + +protected: + ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK, TagKind TK, + DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, + ClassTemplateDecl *SpecializedTemplate, + const TemplateArgument *Args, + unsigned NumArgs, + ClassTemplateSpecializationDecl *PrevDecl); + + explicit ClassTemplateSpecializationDecl(Kind DK); + +public: + static ClassTemplateSpecializationDecl * + Create(ASTContext &Context, TagKind TK, DeclContext *DC, + SourceLocation StartLoc, SourceLocation IdLoc, + ClassTemplateDecl *SpecializedTemplate, + const TemplateArgument *Args, + unsigned NumArgs, + ClassTemplateSpecializationDecl *PrevDecl); + static ClassTemplateSpecializationDecl * + CreateDeserialized(ASTContext &C, unsigned ID); + + virtual void getNameForDiagnostic(std::string &S, + const PrintingPolicy &Policy, + bool Qualified) const; + + ClassTemplateSpecializationDecl *getMostRecentDecl() { + CXXRecordDecl *Recent + = cast<CXXRecordDecl>(CXXRecordDecl::getMostRecentDecl()); + if (!isa<ClassTemplateSpecializationDecl>(Recent)) { + // FIXME: Does injected class name need to be in the redeclarations chain? + assert(Recent->isInjectedClassName() && Recent->getPreviousDecl()); + Recent = Recent->getPreviousDecl(); + } + return cast<ClassTemplateSpecializationDecl>(Recent); + } + + /// \brief Retrieve the template that this specialization specializes. + ClassTemplateDecl *getSpecializedTemplate() const; + + /// \brief Retrieve the template arguments of the class template + /// specialization. + const TemplateArgumentList &getTemplateArgs() const { + return *TemplateArgs; + } + + /// \brief Determine the kind of specialization that this + /// declaration represents. + TemplateSpecializationKind getSpecializationKind() const { + return static_cast<TemplateSpecializationKind>(SpecializationKind); + } + + bool isExplicitSpecialization() const { + return getSpecializationKind() == TSK_ExplicitSpecialization; + } + + void setSpecializationKind(TemplateSpecializationKind TSK) { + SpecializationKind = TSK; + } + + /// \brief Get the point of instantiation (if any), or null if none. + SourceLocation getPointOfInstantiation() const { + return PointOfInstantiation; + } + + void setPointOfInstantiation(SourceLocation Loc) { + assert(Loc.isValid() && "point of instantiation must be valid!"); + PointOfInstantiation = Loc; + } + + /// \brief If this class template specialization is an instantiation of + /// a template (rather than an explicit specialization), return the + /// class template or class template partial specialization from which it + /// was instantiated. + llvm::PointerUnion<ClassTemplateDecl *, + ClassTemplatePartialSpecializationDecl *> + getInstantiatedFrom() const { + if (getSpecializationKind() != TSK_ImplicitInstantiation && + getSpecializationKind() != TSK_ExplicitInstantiationDefinition && + getSpecializationKind() != TSK_ExplicitInstantiationDeclaration) + return llvm::PointerUnion<ClassTemplateDecl *, + ClassTemplatePartialSpecializationDecl *>(); + + if (SpecializedPartialSpecialization *PartialSpec + = SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization*>()) + return PartialSpec->PartialSpecialization; + + return const_cast<ClassTemplateDecl*>( + SpecializedTemplate.get<ClassTemplateDecl*>()); + } + + /// \brief Retrieve the class template or class template partial + /// specialization which was specialized by this. + llvm::PointerUnion<ClassTemplateDecl *, + ClassTemplatePartialSpecializationDecl *> + getSpecializedTemplateOrPartial() const { + if (SpecializedPartialSpecialization *PartialSpec + = SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization*>()) + return PartialSpec->PartialSpecialization; + + return const_cast<ClassTemplateDecl*>( + SpecializedTemplate.get<ClassTemplateDecl*>()); + } + + /// \brief Retrieve the set of template arguments that should be used + /// to instantiate members of the class template or class template partial + /// specialization from which this class template specialization was + /// instantiated. + /// + /// \returns For a class template specialization instantiated from the primary + /// template, this function will return the same template arguments as + /// getTemplateArgs(). For a class template specialization instantiated from + /// a class template partial specialization, this function will return the + /// deduced template arguments for the class template partial specialization + /// itself. + const TemplateArgumentList &getTemplateInstantiationArgs() const { + if (SpecializedPartialSpecialization *PartialSpec + = SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization*>()) + return *PartialSpec->TemplateArgs; + + return getTemplateArgs(); + } + + /// \brief Note that this class template specialization is actually an + /// instantiation of the given class template partial specialization whose + /// template arguments have been deduced. + void setInstantiationOf(ClassTemplatePartialSpecializationDecl *PartialSpec, + TemplateArgumentList *TemplateArgs) { + assert(!SpecializedTemplate.is<SpecializedPartialSpecialization*>() && + "Already set to a class template partial specialization!"); + SpecializedPartialSpecialization *PS + = new (getASTContext()) SpecializedPartialSpecialization(); + PS->PartialSpecialization = PartialSpec; + PS->TemplateArgs = TemplateArgs; + SpecializedTemplate = PS; + } + + /// \brief Note that this class template specialization is an instantiation + /// of the given class template. + void setInstantiationOf(ClassTemplateDecl *TemplDecl) { + assert(!SpecializedTemplate.is<SpecializedPartialSpecialization*>() && + "Previously set to a class template partial specialization!"); + SpecializedTemplate = TemplDecl; + } + + /// \brief Sets the type of this specialization as it was written by + /// the user. This will be a class template specialization type. + void setTypeAsWritten(TypeSourceInfo *T) { + if (!ExplicitInfo) + ExplicitInfo = new (getASTContext()) ExplicitSpecializationInfo; + ExplicitInfo->TypeAsWritten = T; + } + /// \brief Gets the type of this specialization as it was written by + /// the user, if it was so written. + TypeSourceInfo *getTypeAsWritten() const { + return ExplicitInfo ? ExplicitInfo->TypeAsWritten : 0; + } + + /// \brief Gets the location of the extern keyword, if present. + SourceLocation getExternLoc() const { + return ExplicitInfo ? ExplicitInfo->ExternLoc : SourceLocation(); + } + /// \brief Sets the location of the extern keyword. + void setExternLoc(SourceLocation Loc) { + if (!ExplicitInfo) + ExplicitInfo = new (getASTContext()) ExplicitSpecializationInfo; + ExplicitInfo->ExternLoc = Loc; + } + + /// \brief Sets the location of the template keyword. + void setTemplateKeywordLoc(SourceLocation Loc) { + if (!ExplicitInfo) + ExplicitInfo = new (getASTContext()) ExplicitSpecializationInfo; + ExplicitInfo->TemplateKeywordLoc = Loc; + } + /// \brief Gets the location of the template keyword, if present. + SourceLocation getTemplateKeywordLoc() const { + return ExplicitInfo ? ExplicitInfo->TemplateKeywordLoc : SourceLocation(); + } + + SourceRange getSourceRange() const LLVM_READONLY; + + void Profile(llvm::FoldingSetNodeID &ID) const { + Profile(ID, TemplateArgs->data(), TemplateArgs->size(), getASTContext()); + } + + static void + Profile(llvm::FoldingSetNodeID &ID, const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, ASTContext &Context) { + ID.AddInteger(NumTemplateArgs); + for (unsigned Arg = 0; Arg != NumTemplateArgs; ++Arg) + TemplateArgs[Arg].Profile(ID, Context); + } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { + return K >= firstClassTemplateSpecialization && + K <= lastClassTemplateSpecialization; + } + + static bool classof(const ClassTemplateSpecializationDecl *) { + return true; + } + + static bool classof(const ClassTemplatePartialSpecializationDecl *) { + return true; + } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +class ClassTemplatePartialSpecializationDecl + : public ClassTemplateSpecializationDecl { + virtual void anchor(); + + /// \brief The list of template parameters + TemplateParameterList* TemplateParams; + + /// \brief The source info for the template arguments as written. + /// FIXME: redundant with TypeAsWritten? + TemplateArgumentLoc *ArgsAsWritten; + unsigned NumArgsAsWritten; + + /// \brief Sequence number indicating when this class template partial + /// specialization was added to the set of partial specializations for + /// its owning class template. + unsigned SequenceNumber; + + /// \brief The class template partial specialization from which this + /// class template partial specialization was instantiated. + /// + /// The boolean value will be true to indicate that this class template + /// partial specialization was specialized at this level. + llvm::PointerIntPair<ClassTemplatePartialSpecializationDecl *, 1, bool> + InstantiatedFromMember; + + ClassTemplatePartialSpecializationDecl(ASTContext &Context, TagKind TK, + DeclContext *DC, + SourceLocation StartLoc, + SourceLocation IdLoc, + TemplateParameterList *Params, + ClassTemplateDecl *SpecializedTemplate, + const TemplateArgument *Args, + unsigned NumArgs, + TemplateArgumentLoc *ArgInfos, + unsigned NumArgInfos, + ClassTemplatePartialSpecializationDecl *PrevDecl, + unsigned SequenceNumber); + + ClassTemplatePartialSpecializationDecl() + : ClassTemplateSpecializationDecl(ClassTemplatePartialSpecialization), + TemplateParams(0), ArgsAsWritten(0), + NumArgsAsWritten(0), SequenceNumber(0), + InstantiatedFromMember(0, false) { } + +public: + static ClassTemplatePartialSpecializationDecl * + Create(ASTContext &Context, TagKind TK, DeclContext *DC, + SourceLocation StartLoc, SourceLocation IdLoc, + TemplateParameterList *Params, + ClassTemplateDecl *SpecializedTemplate, + const TemplateArgument *Args, + unsigned NumArgs, + const TemplateArgumentListInfo &ArgInfos, + QualType CanonInjectedType, + ClassTemplatePartialSpecializationDecl *PrevDecl, + unsigned SequenceNumber); + + static ClassTemplatePartialSpecializationDecl * + CreateDeserialized(ASTContext &C, unsigned ID); + + ClassTemplatePartialSpecializationDecl *getMostRecentDecl() { + return cast<ClassTemplatePartialSpecializationDecl>( + ClassTemplateSpecializationDecl::getMostRecentDecl()); + } + + /// Get the list of template parameters + TemplateParameterList *getTemplateParameters() const { + return TemplateParams; + } + + /// Get the template arguments as written. + TemplateArgumentLoc *getTemplateArgsAsWritten() const { + return ArgsAsWritten; + } + + /// Get the number of template arguments as written. + unsigned getNumTemplateArgsAsWritten() const { + return NumArgsAsWritten; + } + + /// \brief Get the sequence number for this class template partial + /// specialization. + unsigned getSequenceNumber() const { return SequenceNumber; } + + /// \brief Retrieve the member class template partial specialization from + /// which this particular class template partial specialization was + /// instantiated. + /// + /// \code + /// template<typename T> + /// struct Outer { + /// template<typename U> struct Inner; + /// template<typename U> struct Inner<U*> { }; // #1 + /// }; + /// + /// Outer<float>::Inner<int*> ii; + /// \endcode + /// + /// In this example, the instantiation of \c Outer<float>::Inner<int*> will + /// end up instantiating the partial specialization + /// \c Outer<float>::Inner<U*>, which itself was instantiated from the class + /// template partial specialization \c Outer<T>::Inner<U*>. Given + /// \c Outer<float>::Inner<U*>, this function would return + /// \c Outer<T>::Inner<U*>. + ClassTemplatePartialSpecializationDecl *getInstantiatedFromMember() { + ClassTemplatePartialSpecializationDecl *First + = cast<ClassTemplatePartialSpecializationDecl>(getFirstDeclaration()); + return First->InstantiatedFromMember.getPointer(); + } + + void setInstantiatedFromMember( + ClassTemplatePartialSpecializationDecl *PartialSpec) { + ClassTemplatePartialSpecializationDecl *First + = cast<ClassTemplatePartialSpecializationDecl>(getFirstDeclaration()); + First->InstantiatedFromMember.setPointer(PartialSpec); + } + + /// \brief Determines whether this class template partial specialization + /// template was a specialization of a member partial specialization. + /// + /// In the following example, the member template partial specialization + /// \c X<int>::Inner<T*> is a member specialization. + /// + /// \code + /// template<typename T> + /// struct X { + /// template<typename U> struct Inner; + /// template<typename U> struct Inner<U*>; + /// }; + /// + /// template<> template<typename T> + /// struct X<int>::Inner<T*> { /* ... */ }; + /// \endcode + bool isMemberSpecialization() { + ClassTemplatePartialSpecializationDecl *First + = cast<ClassTemplatePartialSpecializationDecl>(getFirstDeclaration()); + return First->InstantiatedFromMember.getInt(); + } + + /// \brief Note that this member template is a specialization. + void setMemberSpecialization() { + ClassTemplatePartialSpecializationDecl *First + = cast<ClassTemplatePartialSpecializationDecl>(getFirstDeclaration()); + assert(First->InstantiatedFromMember.getPointer() && + "Only member templates can be member template specializations"); + return First->InstantiatedFromMember.setInt(true); + } + + /// Retrieves the injected specialization type for this partial + /// specialization. This is not the same as the type-decl-type for + /// this partial specialization, which is an InjectedClassNameType. + QualType getInjectedSpecializationType() const { + assert(getTypeForDecl() && "partial specialization has no type set!"); + return cast<InjectedClassNameType>(getTypeForDecl()) + ->getInjectedSpecializationType(); + } + + // FIXME: Add Profile support! + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { + return K == ClassTemplatePartialSpecialization; + } + + static bool classof(const ClassTemplatePartialSpecializationDecl *) { + return true; + } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +/// Declaration of a class template. +class ClassTemplateDecl : public RedeclarableTemplateDecl { + static void DeallocateCommon(void *Ptr); + +protected: + /// \brief Data that is common to all of the declarations of a given + /// class template. + struct Common : CommonBase { + Common() : LazySpecializations() { } + + /// \brief The class template specializations for this class + /// template, including explicit specializations and instantiations. + llvm::FoldingSet<ClassTemplateSpecializationDecl> Specializations; + + /// \brief The class template partial specializations for this class + /// template. + llvm::FoldingSet<ClassTemplatePartialSpecializationDecl> + PartialSpecializations; + + /// \brief The injected-class-name type for this class template. + QualType InjectedClassNameType; + + /// \brief If non-null, points to an array of specializations (including + /// partial specializations) known ownly by their external declaration IDs. + /// + /// The first value in the array is the number of of specializations/ + /// partial specializations that follow. + uint32_t *LazySpecializations; + }; + + /// \brief Load any lazily-loaded specializations from the external source. + void LoadLazySpecializations(); + + /// \brief Retrieve the set of specializations of this class template. + llvm::FoldingSet<ClassTemplateSpecializationDecl> &getSpecializations(); + + /// \brief Retrieve the set of partial specializations of this class + /// template. + llvm::FoldingSet<ClassTemplatePartialSpecializationDecl> & + getPartialSpecializations(); + + ClassTemplateDecl(DeclContext *DC, SourceLocation L, DeclarationName Name, + TemplateParameterList *Params, NamedDecl *Decl) + : RedeclarableTemplateDecl(ClassTemplate, DC, L, Name, Params, Decl) { } + + ClassTemplateDecl(EmptyShell Empty) + : RedeclarableTemplateDecl(ClassTemplate, 0, SourceLocation(), + DeclarationName(), 0, 0) { } + + CommonBase *newCommon(ASTContext &C); + + Common *getCommonPtr() { + return static_cast<Common *>(RedeclarableTemplateDecl::getCommonPtr()); + } + +public: + /// Get the underlying class declarations of the template. + CXXRecordDecl *getTemplatedDecl() const { + return static_cast<CXXRecordDecl *>(TemplatedDecl); + } + + /// Returns whether this template declaration defines the primary + /// class pattern. + bool isThisDeclarationADefinition() const { + return getTemplatedDecl()->isThisDeclarationADefinition(); + } + + /// Create a class template node. + static ClassTemplateDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + DeclarationName Name, + TemplateParameterList *Params, + NamedDecl *Decl, + ClassTemplateDecl *PrevDecl); + + /// Create an empty class template node. + static ClassTemplateDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + /// \brief Return the specialization with the provided arguments if it exists, + /// otherwise return the insertion point. + ClassTemplateSpecializationDecl * + findSpecialization(const TemplateArgument *Args, unsigned NumArgs, + void *&InsertPos); + + /// \brief Insert the specified specialization knowing that it is not already + /// in. InsertPos must be obtained from findSpecialization. + void AddSpecialization(ClassTemplateSpecializationDecl *D, void *InsertPos); + + ClassTemplateDecl *getCanonicalDecl() { + return cast<ClassTemplateDecl>( + RedeclarableTemplateDecl::getCanonicalDecl()); + } + const ClassTemplateDecl *getCanonicalDecl() const { + return cast<ClassTemplateDecl>( + RedeclarableTemplateDecl::getCanonicalDecl()); + } + + /// \brief Retrieve the previous declaration of this class template, or + /// NULL if no such declaration exists. + ClassTemplateDecl *getPreviousDecl() { + return cast_or_null<ClassTemplateDecl>( + RedeclarableTemplateDecl::getPreviousDecl()); + } + + /// \brief Retrieve the previous declaration of this class template, or + /// NULL if no such declaration exists. + const ClassTemplateDecl *getPreviousDecl() const { + return cast_or_null<ClassTemplateDecl>( + RedeclarableTemplateDecl::getPreviousDecl()); + } + + ClassTemplateDecl *getInstantiatedFromMemberTemplate() { + return cast_or_null<ClassTemplateDecl>( + RedeclarableTemplateDecl::getInstantiatedFromMemberTemplate()); + } + + /// \brief Return the partial specialization with the provided arguments if it + /// exists, otherwise return the insertion point. + ClassTemplatePartialSpecializationDecl * + findPartialSpecialization(const TemplateArgument *Args, unsigned NumArgs, + void *&InsertPos); + + /// \brief Insert the specified partial specialization knowing that it is not + /// already in. InsertPos must be obtained from findPartialSpecialization. + void AddPartialSpecialization(ClassTemplatePartialSpecializationDecl *D, + void *InsertPos); + + /// \brief Return the next partial specialization sequence number. + unsigned getNextPartialSpecSequenceNumber() { + return getPartialSpecializations().size(); + } + + /// \brief Retrieve the partial specializations as an ordered list. + void getPartialSpecializations( + SmallVectorImpl<ClassTemplatePartialSpecializationDecl *> &PS); + + /// \brief Find a class template partial specialization with the given + /// type T. + /// + /// \param T a dependent type that names a specialization of this class + /// template. + /// + /// \returns the class template partial specialization that exactly matches + /// the type \p T, or NULL if no such partial specialization exists. + ClassTemplatePartialSpecializationDecl *findPartialSpecialization(QualType T); + + /// \brief Find a class template partial specialization which was instantiated + /// from the given member partial specialization. + /// + /// \param D a member class template partial specialization. + /// + /// \returns the class template partial specialization which was instantiated + /// from the given member partial specialization, or NULL if no such partial + /// specialization exists. + ClassTemplatePartialSpecializationDecl * + findPartialSpecInstantiatedFromMember( + ClassTemplatePartialSpecializationDecl *D); + + /// \brief Retrieve the template specialization type of the + /// injected-class-name for this class template. + /// + /// The injected-class-name for a class template \c X is \c + /// X<template-args>, where \c template-args is formed from the + /// template arguments that correspond to the template parameters of + /// \c X. For example: + /// + /// \code + /// template<typename T, int N> + /// struct array { + /// typedef array this_type; // "array" is equivalent to "array<T, N>" + /// }; + /// \endcode + QualType getInjectedClassNameSpecialization(); + + typedef SpecIterator<ClassTemplateSpecializationDecl> spec_iterator; + + spec_iterator spec_begin() { + return makeSpecIterator(getSpecializations(), false); + } + + spec_iterator spec_end() { + return makeSpecIterator(getSpecializations(), true); + } + + typedef SpecIterator<ClassTemplatePartialSpecializationDecl> + partial_spec_iterator; + + partial_spec_iterator partial_spec_begin() { + return makeSpecIterator(getPartialSpecializations(), false); + } + + partial_spec_iterator partial_spec_end() { + return makeSpecIterator(getPartialSpecializations(), true); + } + + // Implement isa/cast/dyncast support + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const ClassTemplateDecl *D) { return true; } + static bool classofKind(Kind K) { return K == ClassTemplate; } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +/// Declaration of a friend template. For example: +/// +/// template <typename T> class A { +/// friend class MyVector<T>; // not a friend template +/// template <typename U> friend class B; // not a friend template +/// template <typename U> friend class Foo<T>::Nested; // friend template +/// }; +/// NOTE: This class is not currently in use. All of the above +/// will yield a FriendDecl, not a FriendTemplateDecl. +class FriendTemplateDecl : public Decl { + virtual void anchor(); +public: + typedef llvm::PointerUnion<NamedDecl*,TypeSourceInfo*> FriendUnion; + +private: + // The number of template parameters; always non-zero. + unsigned NumParams; + + // The parameter list. + TemplateParameterList **Params; + + // The declaration that's a friend of this class. + FriendUnion Friend; + + // Location of the 'friend' specifier. + SourceLocation FriendLoc; + + + FriendTemplateDecl(DeclContext *DC, SourceLocation Loc, + unsigned NParams, + TemplateParameterList **Params, + FriendUnion Friend, + SourceLocation FriendLoc) + : Decl(Decl::FriendTemplate, DC, Loc), + NumParams(NParams), + Params(Params), + Friend(Friend), + FriendLoc(FriendLoc) + {} + + FriendTemplateDecl(EmptyShell Empty) + : Decl(Decl::FriendTemplate, Empty), + NumParams(0), + Params(0) + {} + +public: + static FriendTemplateDecl *Create(ASTContext &Context, + DeclContext *DC, SourceLocation Loc, + unsigned NParams, + TemplateParameterList **Params, + FriendUnion Friend, + SourceLocation FriendLoc); + + static FriendTemplateDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + /// If this friend declaration names a templated type (or + /// a dependent member type of a templated type), return that + /// type; otherwise return null. + TypeSourceInfo *getFriendType() const { + return Friend.dyn_cast<TypeSourceInfo*>(); + } + + /// If this friend declaration names a templated function (or + /// a member function of a templated type), return that type; + /// otherwise return null. + NamedDecl *getFriendDecl() const { + return Friend.dyn_cast<NamedDecl*>(); + } + + /// Retrieves the location of the 'friend' keyword. + SourceLocation getFriendLoc() const { + return FriendLoc; + } + + TemplateParameterList *getTemplateParameterList(unsigned i) const { + assert(i <= NumParams); + return Params[i]; + } + + unsigned getNumTemplateParameters() const { + return NumParams; + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == Decl::FriendTemplate; } + static bool classof(const FriendTemplateDecl *D) { return true; } + + friend class ASTDeclReader; +}; + +/// Declaration of an alias template. For example: +/// +/// template <typename T> using V = std::map<T*, int, MyCompare<T>>; +class TypeAliasTemplateDecl : public RedeclarableTemplateDecl { + static void DeallocateCommon(void *Ptr); + +protected: + typedef CommonBase Common; + + TypeAliasTemplateDecl(DeclContext *DC, SourceLocation L, DeclarationName Name, + TemplateParameterList *Params, NamedDecl *Decl) + : RedeclarableTemplateDecl(TypeAliasTemplate, DC, L, Name, Params, Decl) { } + + CommonBase *newCommon(ASTContext &C); + + Common *getCommonPtr() { + return static_cast<Common *>(RedeclarableTemplateDecl::getCommonPtr()); + } + +public: + /// Get the underlying function declaration of the template. + TypeAliasDecl *getTemplatedDecl() const { + return static_cast<TypeAliasDecl*>(TemplatedDecl); + } + + + TypeAliasTemplateDecl *getCanonicalDecl() { + return cast<TypeAliasTemplateDecl>( + RedeclarableTemplateDecl::getCanonicalDecl()); + } + const TypeAliasTemplateDecl *getCanonicalDecl() const { + return cast<TypeAliasTemplateDecl>( + RedeclarableTemplateDecl::getCanonicalDecl()); + } + + /// \brief Retrieve the previous declaration of this function template, or + /// NULL if no such declaration exists. + TypeAliasTemplateDecl *getPreviousDecl() { + return cast_or_null<TypeAliasTemplateDecl>( + RedeclarableTemplateDecl::getPreviousDecl()); + } + + /// \brief Retrieve the previous declaration of this function template, or + /// NULL if no such declaration exists. + const TypeAliasTemplateDecl *getPreviousDecl() const { + return cast_or_null<TypeAliasTemplateDecl>( + RedeclarableTemplateDecl::getPreviousDecl()); + } + + TypeAliasTemplateDecl *getInstantiatedFromMemberTemplate() { + return cast_or_null<TypeAliasTemplateDecl>( + RedeclarableTemplateDecl::getInstantiatedFromMemberTemplate()); + } + + + /// \brief Create a function template node. + static TypeAliasTemplateDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + DeclarationName Name, + TemplateParameterList *Params, + NamedDecl *Decl); + + /// \brief Create an empty alias template node. + static TypeAliasTemplateDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + // Implement isa/cast/dyncast support + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const TypeAliasTemplateDecl *D) { return true; } + static bool classofKind(Kind K) { return K == TypeAliasTemplate; } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +/// Declaration of a function specialization at template class scope. +/// This is a non standard extension needed to support MSVC. +/// For example: +/// template <class T> +/// class A { +/// template <class U> void foo(U a) { } +/// template<> void foo(int a) { } +/// } +/// +/// "template<> foo(int a)" will be saved in Specialization as a normal +/// CXXMethodDecl. Then during an instantiation of class A, it will be +/// transformed into an actual function specialization. +class ClassScopeFunctionSpecializationDecl : public Decl { + virtual void anchor(); + + ClassScopeFunctionSpecializationDecl(DeclContext *DC, SourceLocation Loc, + CXXMethodDecl *FD) + : Decl(Decl::ClassScopeFunctionSpecialization, DC, Loc), + Specialization(FD) {} + + ClassScopeFunctionSpecializationDecl(EmptyShell Empty) + : Decl(Decl::ClassScopeFunctionSpecialization, Empty) {} + + CXXMethodDecl *Specialization; + +public: + CXXMethodDecl *getSpecialization() const { return Specialization; } + + static ClassScopeFunctionSpecializationDecl *Create(ASTContext &C, + DeclContext *DC, + SourceLocation Loc, + CXXMethodDecl *FD) { + return new (C) ClassScopeFunctionSpecializationDecl(DC , Loc, FD); + } + + static ClassScopeFunctionSpecializationDecl * + CreateDeserialized(ASTContext &Context, unsigned ID); + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { + return K == Decl::ClassScopeFunctionSpecialization; + } + static bool classof(const ClassScopeFunctionSpecializationDecl *D) { + return true; + } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +/// Implementation of inline functions that require the template declarations +inline AnyFunctionDecl::AnyFunctionDecl(FunctionTemplateDecl *FTD) + : Function(FTD) { } + +} /* end of namespace clang */ + +#endif diff --git a/clang/include/clang/AST/DeclVisitor.h b/clang/include/clang/AST/DeclVisitor.h new file mode 100644 index 0000000..62654b8 --- /dev/null +++ b/clang/include/clang/AST/DeclVisitor.h @@ -0,0 +1,54 @@ +//===--- DeclVisitor.h - Visitor for Decl subclasses ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the DeclVisitor interface. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_AST_DECLVISITOR_H +#define LLVM_CLANG_AST_DECLVISITOR_H + +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclFriend.h" +#include "clang/AST/DeclTemplate.h" + +namespace clang { + +#define DISPATCH(NAME, CLASS) \ + return static_cast<ImplClass*>(this)-> Visit##NAME(static_cast<CLASS*>(D)) + +/// \brief A simple visitor class that helps create declaration visitors. +template<typename ImplClass, typename RetTy=void> +class DeclVisitor { +public: + RetTy Visit(Decl *D) { + switch (D->getKind()) { +#define DECL(DERIVED, BASE) \ + case Decl::DERIVED: DISPATCH(DERIVED##Decl, DERIVED##Decl); +#define ABSTRACT_DECL(DECL) +#include "clang/AST/DeclNodes.inc" + } + llvm_unreachable("Decl that isn't part of DeclNodes.inc!"); + } + + // If the implementation chooses not to implement a certain visit + // method, fall back to the parent. +#define DECL(DERIVED, BASE) \ + RetTy Visit##DERIVED##Decl(DERIVED##Decl *D) { DISPATCH(BASE, BASE); } +#include "clang/AST/DeclNodes.inc" + + RetTy VisitDecl(Decl *D) { return RetTy(); } +}; + +#undef DISPATCH + +} // end namespace clang + +#endif // LLVM_CLANG_AST_DECLVISITOR_H diff --git a/clang/include/clang/AST/DeclarationName.h b/clang/include/clang/AST/DeclarationName.h new file mode 100644 index 0000000..6349d9c --- /dev/null +++ b/clang/include/clang/AST/DeclarationName.h @@ -0,0 +1,580 @@ +//===-- DeclarationName.h - Representation of declaration names -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the DeclarationName and DeclarationNameTable classes. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_AST_DECLARATIONNAME_H +#define LLVM_CLANG_AST_DECLARATIONNAME_H + +#include "clang/Basic/IdentifierTable.h" +#include "clang/AST/Type.h" +#include "clang/AST/CanonicalType.h" +#include "clang/Basic/PartialDiagnostic.h" +#include "llvm/Support/Compiler.h" + +namespace llvm { + template <typename T> struct DenseMapInfo; +} + +namespace clang { + class CXXSpecialName; + class CXXOperatorIdName; + class CXXLiteralOperatorIdName; + class DeclarationNameExtra; + class IdentifierInfo; + class MultiKeywordSelector; + class UsingDirectiveDecl; + class TypeSourceInfo; + +/// DeclarationName - The name of a declaration. In the common case, +/// this just stores an IdentifierInfo pointer to a normal +/// name. However, it also provides encodings for Objective-C +/// selectors (optimizing zero- and one-argument selectors, which make +/// up 78% percent of all selectors in Cocoa.h) and special C++ names +/// for constructors, destructors, and conversion functions. +class DeclarationName { +public: + /// NameKind - The kind of name this object contains. + enum NameKind { + Identifier, + ObjCZeroArgSelector, + ObjCOneArgSelector, + ObjCMultiArgSelector, + CXXConstructorName, + CXXDestructorName, + CXXConversionFunctionName, + CXXOperatorName, + CXXLiteralOperatorName, + CXXUsingDirective + }; + +private: + /// StoredNameKind - The kind of name that is actually stored in the + /// upper bits of the Ptr field. This is only used internally. + enum StoredNameKind { + StoredIdentifier = 0, + StoredObjCZeroArgSelector, + StoredObjCOneArgSelector, + StoredDeclarationNameExtra, + PtrMask = 0x03 + }; + + /// Ptr - The lowest two bits are used to express what kind of name + /// we're actually storing, using the values of NameKind. Depending + /// on the kind of name this is, the upper bits of Ptr may have one + /// of several different meanings: + /// + /// StoredIdentifier - The name is a normal identifier, and Ptr is + /// a normal IdentifierInfo pointer. + /// + /// StoredObjCZeroArgSelector - The name is an Objective-C + /// selector with zero arguments, and Ptr is an IdentifierInfo + /// pointer pointing to the selector name. + /// + /// StoredObjCOneArgSelector - The name is an Objective-C selector + /// with one argument, and Ptr is an IdentifierInfo pointer + /// pointing to the selector name. + /// + /// StoredDeclarationNameExtra - Ptr is actually a pointer to a + /// DeclarationNameExtra structure, whose first value will tell us + /// whether this is an Objective-C selector, C++ operator-id name, + /// or special C++ name. + uintptr_t Ptr; + + /// getStoredNameKind - Return the kind of object that is stored in + /// Ptr. + StoredNameKind getStoredNameKind() const { + return static_cast<StoredNameKind>(Ptr & PtrMask); + } + + /// getExtra - Get the "extra" information associated with this + /// multi-argument selector or C++ special name. + DeclarationNameExtra *getExtra() const { + assert(getStoredNameKind() == StoredDeclarationNameExtra && + "Declaration name does not store an Extra structure"); + return reinterpret_cast<DeclarationNameExtra *>(Ptr & ~PtrMask); + } + + /// getAsCXXSpecialName - If the stored pointer is actually a + /// CXXSpecialName, returns a pointer to it. Otherwise, returns + /// a NULL pointer. + CXXSpecialName *getAsCXXSpecialName() const { + if (getNameKind() >= CXXConstructorName && + getNameKind() <= CXXConversionFunctionName) + return reinterpret_cast<CXXSpecialName *>(Ptr & ~PtrMask); + return 0; + } + + /// getAsCXXOperatorIdName + CXXOperatorIdName *getAsCXXOperatorIdName() const { + if (getNameKind() == CXXOperatorName) + return reinterpret_cast<CXXOperatorIdName *>(Ptr & ~PtrMask); + return 0; + } + + CXXLiteralOperatorIdName *getAsCXXLiteralOperatorIdName() const { + if (getNameKind() == CXXLiteralOperatorName) + return reinterpret_cast<CXXLiteralOperatorIdName *>(Ptr & ~PtrMask); + return 0; + } + + // Construct a declaration name from the name of a C++ constructor, + // destructor, or conversion function. + DeclarationName(CXXSpecialName *Name) + : Ptr(reinterpret_cast<uintptr_t>(Name)) { + assert((Ptr & PtrMask) == 0 && "Improperly aligned CXXSpecialName"); + Ptr |= StoredDeclarationNameExtra; + } + + // Construct a declaration name from the name of a C++ overloaded + // operator. + DeclarationName(CXXOperatorIdName *Name) + : Ptr(reinterpret_cast<uintptr_t>(Name)) { + assert((Ptr & PtrMask) == 0 && "Improperly aligned CXXOperatorId"); + Ptr |= StoredDeclarationNameExtra; + } + + DeclarationName(CXXLiteralOperatorIdName *Name) + : Ptr(reinterpret_cast<uintptr_t>(Name)) { + assert((Ptr & PtrMask) == 0 && "Improperly aligned CXXLiteralOperatorId"); + Ptr |= StoredDeclarationNameExtra; + } + + /// Construct a declaration name from a raw pointer. + DeclarationName(uintptr_t Ptr) : Ptr(Ptr) { } + + friend class DeclarationNameTable; + friend class NamedDecl; + + /// getFETokenInfoAsVoid - Retrieves the front end-specified pointer + /// for this name as a void pointer. + void *getFETokenInfoAsVoid() const; + +public: + /// DeclarationName - Used to create an empty selector. + DeclarationName() : Ptr(0) { } + + // Construct a declaration name from an IdentifierInfo *. + DeclarationName(const IdentifierInfo *II) + : Ptr(reinterpret_cast<uintptr_t>(II)) { + assert((Ptr & PtrMask) == 0 && "Improperly aligned IdentifierInfo"); + } + + // Construct a declaration name from an Objective-C selector. + DeclarationName(Selector Sel); + + /// getUsingDirectiveName - Return name for all using-directives. + static DeclarationName getUsingDirectiveName(); + + // operator bool() - Evaluates true when this declaration name is + // non-empty. + operator bool() const { + return ((Ptr & PtrMask) != 0) || + (reinterpret_cast<IdentifierInfo *>(Ptr & ~PtrMask)); + } + + /// Predicate functions for querying what type of name this is. + bool isIdentifier() const { return getStoredNameKind() == StoredIdentifier; } + bool isObjCZeroArgSelector() const { + return getStoredNameKind() == StoredObjCZeroArgSelector; + } + bool isObjCOneArgSelector() const { + return getStoredNameKind() == StoredObjCOneArgSelector; + } + + /// getNameKind - Determine what kind of name this is. + NameKind getNameKind() const; + + /// \brief Determines whether the name itself is dependent, e.g., because it + /// involves a C++ type that is itself dependent. + /// + /// Note that this does not capture all of the notions of "dependent name", + /// because an identifier can be a dependent name if it is used as the + /// callee in a call expression with dependent arguments. + bool isDependentName() const; + + /// getNameAsString - Retrieve the human-readable string for this name. + std::string getAsString() const; + + /// printName - Print the human-readable name to a stream. + void printName(raw_ostream &OS) const; + + /// getAsIdentifierInfo - Retrieve the IdentifierInfo * stored in + /// this declaration name, or NULL if this declaration name isn't a + /// simple identifier. + IdentifierInfo *getAsIdentifierInfo() const { + if (isIdentifier()) + return reinterpret_cast<IdentifierInfo *>(Ptr); + return 0; + } + + /// getAsOpaqueInteger - Get the representation of this declaration + /// name as an opaque integer. + uintptr_t getAsOpaqueInteger() const { return Ptr; } + + /// getAsOpaquePtr - Get the representation of this declaration name as + /// an opaque pointer. + void *getAsOpaquePtr() const { return reinterpret_cast<void*>(Ptr); } + + static DeclarationName getFromOpaquePtr(void *P) { + DeclarationName N; + N.Ptr = reinterpret_cast<uintptr_t> (P); + return N; + } + + static DeclarationName getFromOpaqueInteger(uintptr_t P) { + DeclarationName N; + N.Ptr = P; + return N; + } + + /// getCXXNameType - If this name is one of the C++ names (of a + /// constructor, destructor, or conversion function), return the + /// type associated with that name. + QualType getCXXNameType() const; + + /// getCXXOverloadedOperator - If this name is the name of an + /// overloadable operator in C++ (e.g., @c operator+), retrieve the + /// kind of overloaded operator. + OverloadedOperatorKind getCXXOverloadedOperator() const; + + /// getCXXLiteralIdentifier - If this name is the name of a literal + /// operator, retrieve the identifier associated with it. + IdentifierInfo *getCXXLiteralIdentifier() const; + + /// getObjCSelector - Get the Objective-C selector stored in this + /// declaration name. + Selector getObjCSelector() const; + + /// getFETokenInfo/setFETokenInfo - The language front-end is + /// allowed to associate arbitrary metadata with some kinds of + /// declaration names, including normal identifiers and C++ + /// constructors, destructors, and conversion functions. + template<typename T> + T *getFETokenInfo() const { return static_cast<T*>(getFETokenInfoAsVoid()); } + + void setFETokenInfo(void *T); + + /// operator== - Determine whether the specified names are identical.. + friend bool operator==(DeclarationName LHS, DeclarationName RHS) { + return LHS.Ptr == RHS.Ptr; + } + + /// operator!= - Determine whether the specified names are different. + friend bool operator!=(DeclarationName LHS, DeclarationName RHS) { + return LHS.Ptr != RHS.Ptr; + } + + static DeclarationName getEmptyMarker() { + return DeclarationName(uintptr_t(-1)); + } + + static DeclarationName getTombstoneMarker() { + return DeclarationName(uintptr_t(-2)); + } + + static int compare(DeclarationName LHS, DeclarationName RHS); + + void dump() const; +}; + +/// Ordering on two declaration names. If both names are identifiers, +/// this provides a lexicographical ordering. +inline bool operator<(DeclarationName LHS, DeclarationName RHS) { + return DeclarationName::compare(LHS, RHS) < 0; +} + +/// Ordering on two declaration names. If both names are identifiers, +/// this provides a lexicographical ordering. +inline bool operator>(DeclarationName LHS, DeclarationName RHS) { + return DeclarationName::compare(LHS, RHS) > 0; +} + +/// Ordering on two declaration names. If both names are identifiers, +/// this provides a lexicographical ordering. +inline bool operator<=(DeclarationName LHS, DeclarationName RHS) { + return DeclarationName::compare(LHS, RHS) <= 0; +} + +/// Ordering on two declaration names. If both names are identifiers, +/// this provides a lexicographical ordering. +inline bool operator>=(DeclarationName LHS, DeclarationName RHS) { + return DeclarationName::compare(LHS, RHS) >= 0; +} + +/// DeclarationNameTable - Used to store and retrieve DeclarationName +/// instances for the various kinds of declaration names, e.g., normal +/// identifiers, C++ constructor names, etc. This class contains +/// uniqued versions of each of the C++ special names, which can be +/// retrieved using its member functions (e.g., +/// getCXXConstructorName). +class DeclarationNameTable { + const ASTContext &Ctx; + void *CXXSpecialNamesImpl; // Actually a FoldingSet<CXXSpecialName> * + CXXOperatorIdName *CXXOperatorNames; // Operator names + void *CXXLiteralOperatorNames; // Actually a CXXOperatorIdName* + + DeclarationNameTable(const DeclarationNameTable&); // NONCOPYABLE + DeclarationNameTable& operator=(const DeclarationNameTable&); // NONCOPYABLE + +public: + DeclarationNameTable(const ASTContext &C); + ~DeclarationNameTable(); + + /// getIdentifier - Create a declaration name that is a simple + /// identifier. + DeclarationName getIdentifier(const IdentifierInfo *ID) { + return DeclarationName(ID); + } + + /// getCXXConstructorName - Returns the name of a C++ constructor + /// for the given Type. + DeclarationName getCXXConstructorName(CanQualType Ty) { + return getCXXSpecialName(DeclarationName::CXXConstructorName, + Ty.getUnqualifiedType()); + } + + /// getCXXDestructorName - Returns the name of a C++ destructor + /// for the given Type. + DeclarationName getCXXDestructorName(CanQualType Ty) { + return getCXXSpecialName(DeclarationName::CXXDestructorName, + Ty.getUnqualifiedType()); + } + + /// getCXXConversionFunctionName - Returns the name of a C++ + /// conversion function for the given Type. + DeclarationName getCXXConversionFunctionName(CanQualType Ty) { + return getCXXSpecialName(DeclarationName::CXXConversionFunctionName, Ty); + } + + /// getCXXSpecialName - Returns a declaration name for special kind + /// of C++ name, e.g., for a constructor, destructor, or conversion + /// function. + DeclarationName getCXXSpecialName(DeclarationName::NameKind Kind, + CanQualType Ty); + + /// getCXXOperatorName - Get the name of the overloadable C++ + /// operator corresponding to Op. + DeclarationName getCXXOperatorName(OverloadedOperatorKind Op); + + /// getCXXLiteralOperatorName - Get the name of the literal operator function + /// with II as the identifier. + DeclarationName getCXXLiteralOperatorName(IdentifierInfo *II); +}; + +/// DeclarationNameLoc - Additional source/type location info +/// for a declaration name. Needs a DeclarationName in order +/// to be interpreted correctly. +struct DeclarationNameLoc { + union { + // The source location for identifier stored elsewhere. + // struct {} Identifier; + + // Type info for constructors, destructors and conversion functions. + // Locations (if any) for the tilde (destructor) or operator keyword + // (conversion) are stored elsewhere. + struct { + TypeSourceInfo* TInfo; + } NamedType; + + // The location (if any) of the operator keyword is stored elsewhere. + struct { + unsigned BeginOpNameLoc; + unsigned EndOpNameLoc; + } CXXOperatorName; + + // The location (if any) of the operator keyword is stored elsewhere. + struct { + unsigned OpNameLoc; + } CXXLiteralOperatorName; + + // struct {} CXXUsingDirective; + // struct {} ObjCZeroArgSelector; + // struct {} ObjCOneArgSelector; + // struct {} ObjCMultiArgSelector; + }; + + DeclarationNameLoc(DeclarationName Name); + // FIXME: this should go away once all DNLocs are properly initialized. + DeclarationNameLoc() { memset((void*) this, 0, sizeof(*this)); } +}; // struct DeclarationNameLoc + + +/// DeclarationNameInfo - A collector data type for bundling together +/// a DeclarationName and the correspnding source/type location info. +struct DeclarationNameInfo { +private: + /// Name - The declaration name, also encoding name kind. + DeclarationName Name; + /// Loc - The main source location for the declaration name. + SourceLocation NameLoc; + /// Info - Further source/type location info for special kinds of names. + DeclarationNameLoc LocInfo; + +public: + // FIXME: remove it. + DeclarationNameInfo() {} + + DeclarationNameInfo(DeclarationName Name, SourceLocation NameLoc) + : Name(Name), NameLoc(NameLoc), LocInfo(Name) {} + + DeclarationNameInfo(DeclarationName Name, SourceLocation NameLoc, + DeclarationNameLoc LocInfo) + : Name(Name), NameLoc(NameLoc), LocInfo(LocInfo) {} + + /// getName - Returns the embedded declaration name. + DeclarationName getName() const { return Name; } + /// setName - Sets the embedded declaration name. + void setName(DeclarationName N) { Name = N; } + + /// getLoc - Returns the main location of the declaration name. + SourceLocation getLoc() const { return NameLoc; } + /// setLoc - Sets the main location of the declaration name. + void setLoc(SourceLocation L) { NameLoc = L; } + + const DeclarationNameLoc &getInfo() const { return LocInfo; } + DeclarationNameLoc &getInfo() { return LocInfo; } + void setInfo(const DeclarationNameLoc &Info) { LocInfo = Info; } + + /// getNamedTypeInfo - Returns the source type info associated to + /// the name. Assumes it is a constructor, destructor or conversion. + TypeSourceInfo *getNamedTypeInfo() const { + assert(Name.getNameKind() == DeclarationName::CXXConstructorName || + Name.getNameKind() == DeclarationName::CXXDestructorName || + Name.getNameKind() == DeclarationName::CXXConversionFunctionName); + return LocInfo.NamedType.TInfo; + } + /// setNamedTypeInfo - Sets the source type info associated to + /// the name. Assumes it is a constructor, destructor or conversion. + void setNamedTypeInfo(TypeSourceInfo *TInfo) { + assert(Name.getNameKind() == DeclarationName::CXXConstructorName || + Name.getNameKind() == DeclarationName::CXXDestructorName || + Name.getNameKind() == DeclarationName::CXXConversionFunctionName); + LocInfo.NamedType.TInfo = TInfo; + } + + /// getCXXOperatorNameRange - Gets the range of the operator name + /// (without the operator keyword). Assumes it is a (non-literal) operator. + SourceRange getCXXOperatorNameRange() const { + assert(Name.getNameKind() == DeclarationName::CXXOperatorName); + return SourceRange( + SourceLocation::getFromRawEncoding(LocInfo.CXXOperatorName.BeginOpNameLoc), + SourceLocation::getFromRawEncoding(LocInfo.CXXOperatorName.EndOpNameLoc) + ); + } + /// setCXXOperatorNameRange - Sets the range of the operator name + /// (without the operator keyword). Assumes it is a C++ operator. + void setCXXOperatorNameRange(SourceRange R) { + assert(Name.getNameKind() == DeclarationName::CXXOperatorName); + LocInfo.CXXOperatorName.BeginOpNameLoc = R.getBegin().getRawEncoding(); + LocInfo.CXXOperatorName.EndOpNameLoc = R.getEnd().getRawEncoding(); + } + + /// getCXXLiteralOperatorNameLoc - Returns the location of the literal + /// operator name (not the operator keyword). + /// Assumes it is a literal operator. + SourceLocation getCXXLiteralOperatorNameLoc() const { + assert(Name.getNameKind() == DeclarationName::CXXLiteralOperatorName); + return SourceLocation:: + getFromRawEncoding(LocInfo.CXXLiteralOperatorName.OpNameLoc); + } + /// setCXXLiteralOperatorNameLoc - Sets the location of the literal + /// operator name (not the operator keyword). + /// Assumes it is a literal operator. + void setCXXLiteralOperatorNameLoc(SourceLocation Loc) { + assert(Name.getNameKind() == DeclarationName::CXXLiteralOperatorName); + LocInfo.CXXLiteralOperatorName.OpNameLoc = Loc.getRawEncoding(); + } + + /// \brief Determine whether this name involves a template parameter. + bool isInstantiationDependent() const; + + /// \brief Determine whether this name contains an unexpanded + /// parameter pack. + bool containsUnexpandedParameterPack() const; + + /// getAsString - Retrieve the human-readable string for this name. + std::string getAsString() const; + + /// printName - Print the human-readable name to a stream. + void printName(raw_ostream &OS) const; + + /// getBeginLoc - Retrieve the location of the first token. + SourceLocation getBeginLoc() const { return NameLoc; } + /// getEndLoc - Retrieve the location of the last token. + SourceLocation getEndLoc() const; + /// getSourceRange - The range of the declaration name. + SourceRange getSourceRange() const LLVM_READONLY { + SourceLocation BeginLoc = getBeginLoc(); + SourceLocation EndLoc = getEndLoc(); + return SourceRange(BeginLoc, EndLoc.isValid() ? EndLoc : BeginLoc); + } + SourceLocation getLocStart() const LLVM_READONLY { + return getBeginLoc(); + } + SourceLocation getLocEnd() const LLVM_READONLY { + SourceLocation EndLoc = getEndLoc(); + return EndLoc.isValid() ? EndLoc : getLocStart(); + } +}; + +/// Insertion operator for diagnostics. This allows sending DeclarationName's +/// into a diagnostic with <<. +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + DeclarationName N) { + DB.AddTaggedVal(N.getAsOpaqueInteger(), + DiagnosticsEngine::ak_declarationname); + return DB; +} + +/// Insertion operator for partial diagnostics. This allows binding +/// DeclarationName's into a partial diagnostic with <<. +inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, + DeclarationName N) { + PD.AddTaggedVal(N.getAsOpaqueInteger(), + DiagnosticsEngine::ak_declarationname); + return PD; +} + +inline raw_ostream &operator<<(raw_ostream &OS, + DeclarationNameInfo DNInfo) { + DNInfo.printName(OS); + return OS; +} + +} // end namespace clang + +namespace llvm { +/// Define DenseMapInfo so that DeclarationNames can be used as keys +/// in DenseMap and DenseSets. +template<> +struct DenseMapInfo<clang::DeclarationName> { + static inline clang::DeclarationName getEmptyKey() { + return clang::DeclarationName::getEmptyMarker(); + } + + static inline clang::DeclarationName getTombstoneKey() { + return clang::DeclarationName::getTombstoneMarker(); + } + + static unsigned getHashValue(clang::DeclarationName); + + static inline bool + isEqual(clang::DeclarationName LHS, clang::DeclarationName RHS) { + return LHS == RHS; + } +}; + +template <> +struct isPodLike<clang::DeclarationName> { static const bool value = true; }; + +} // end namespace llvm + +#endif diff --git a/clang/include/clang/AST/DependentDiagnostic.h b/clang/include/clang/AST/DependentDiagnostic.h new file mode 100644 index 0000000..948dcb4 --- /dev/null +++ b/clang/include/clang/AST/DependentDiagnostic.h @@ -0,0 +1,192 @@ +//===-- DependentDiagnostic.h - Dependently-generated diagnostics -*- C++ -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines interfaces for diagnostics which may or may +// fire based on how a template is instantiated. +// +// At the moment, the only consumer of this interface is access +// control. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_DEPENDENT_DIAGNOSTIC_H +#define LLVM_CLANG_AST_DEPENDENT_DIAGNOSTIC_H + +#include "clang/Basic/PartialDiagnostic.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/AST/DeclBase.h" +#include "clang/AST/DeclContextInternals.h" +#include "clang/AST/Type.h" + +namespace clang { + +class ASTContext; +class CXXRecordDecl; +class NamedDecl; + +/// A dependently-generated diagnostic. +class DependentDiagnostic { +public: + enum AccessNonce { Access = 0 }; + + static DependentDiagnostic *Create(ASTContext &Context, + DeclContext *Parent, + AccessNonce _, + SourceLocation Loc, + bool IsMemberAccess, + AccessSpecifier AS, + NamedDecl *TargetDecl, + CXXRecordDecl *NamingClass, + QualType BaseObjectType, + const PartialDiagnostic &PDiag) { + DependentDiagnostic *DD = Create(Context, Parent, PDiag); + DD->AccessData.Loc = Loc.getRawEncoding(); + DD->AccessData.IsMember = IsMemberAccess; + DD->AccessData.Access = AS; + DD->AccessData.TargetDecl = TargetDecl; + DD->AccessData.NamingClass = NamingClass; + DD->AccessData.BaseObjectType = BaseObjectType.getAsOpaquePtr(); + return DD; + } + + unsigned getKind() const { + return Access; + } + + bool isAccessToMember() const { + assert(getKind() == Access); + return AccessData.IsMember; + } + + AccessSpecifier getAccess() const { + assert(getKind() == Access); + return AccessSpecifier(AccessData.Access); + } + + SourceLocation getAccessLoc() const { + assert(getKind() == Access); + return SourceLocation::getFromRawEncoding(AccessData.Loc); + } + + NamedDecl *getAccessTarget() const { + assert(getKind() == Access); + return AccessData.TargetDecl; + } + + NamedDecl *getAccessNamingClass() const { + assert(getKind() == Access); + return AccessData.NamingClass; + } + + QualType getAccessBaseObjectType() const { + assert(getKind() == Access); + return QualType::getFromOpaquePtr(AccessData.BaseObjectType); + } + + const PartialDiagnostic &getDiagnostic() const { + return Diag; + } + +private: + DependentDiagnostic(const PartialDiagnostic &PDiag, + PartialDiagnostic::Storage *Storage) + : Diag(PDiag, Storage) {} + + static DependentDiagnostic *Create(ASTContext &Context, + DeclContext *Parent, + const PartialDiagnostic &PDiag); + + friend class DependentStoredDeclsMap; + friend class DeclContext::ddiag_iterator; + DependentDiagnostic *NextDiagnostic; + + PartialDiagnostic Diag; + + union { + struct { + unsigned Loc; + unsigned Access : 2; + unsigned IsMember : 1; + NamedDecl *TargetDecl; + CXXRecordDecl *NamingClass; + void *BaseObjectType; + } AccessData; + }; +}; + +/// + +/// An iterator over the dependent diagnostics in a dependent context. +class DeclContext::ddiag_iterator { +public: + ddiag_iterator() : Ptr(0) {} + explicit ddiag_iterator(DependentDiagnostic *Ptr) : Ptr(Ptr) {} + + typedef DependentDiagnostic *value_type; + typedef DependentDiagnostic *reference; + typedef DependentDiagnostic *pointer; + typedef int difference_type; + typedef std::forward_iterator_tag iterator_category; + + reference operator*() const { return Ptr; } + + ddiag_iterator &operator++() { + assert(Ptr && "attempt to increment past end of diag list"); + Ptr = Ptr->NextDiagnostic; + return *this; + } + + ddiag_iterator operator++(int) { + ddiag_iterator tmp = *this; + ++*this; + return tmp; + } + + bool operator==(ddiag_iterator Other) const { + return Ptr == Other.Ptr; + } + + bool operator!=(ddiag_iterator Other) const { + return Ptr != Other.Ptr; + } + + ddiag_iterator &operator+=(difference_type N) { + assert(N >= 0 && "cannot rewind a DeclContext::ddiag_iterator"); + while (N--) + ++*this; + return *this; + } + + ddiag_iterator operator+(difference_type N) const { + ddiag_iterator tmp = *this; + tmp += N; + return tmp; + } + +private: + DependentDiagnostic *Ptr; +}; + +inline DeclContext::ddiag_iterator DeclContext::ddiag_begin() const { + assert(isDependentContext() + && "cannot iterate dependent diagnostics of non-dependent context"); + const DependentStoredDeclsMap *Map + = static_cast<DependentStoredDeclsMap*>(getPrimaryContext()->getLookupPtr()); + + if (!Map) return ddiag_iterator(); + return ddiag_iterator(Map->FirstDiagnostic); +} + +inline DeclContext::ddiag_iterator DeclContext::ddiag_end() const { + return ddiag_iterator(); +} + +} + +#endif diff --git a/clang/include/clang/AST/EvaluatedExprVisitor.h b/clang/include/clang/AST/EvaluatedExprVisitor.h new file mode 100644 index 0000000..bab1606 --- /dev/null +++ b/clang/include/clang/AST/EvaluatedExprVisitor.h @@ -0,0 +1,83 @@ +//===--- EvaluatedExprVisitor.h - Evaluated expression visitor --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the EvaluatedExprVisitor class template, which visits +// the potentially-evaluated subexpressions of a potentially-evaluated +// expression. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_AST_EVALUATEDEXPRVISITOR_H +#define LLVM_CLANG_AST_EVALUATEDEXPRVISITOR_H + +#include "clang/AST/StmtVisitor.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" + +namespace clang { + +class ASTContext; + +/// \begin Given a potentially-evaluated expression, this visitor visits all +/// of its potentially-evaluated subexpressions, recursively. +template<typename ImplClass> +class EvaluatedExprVisitor : public StmtVisitor<ImplClass> { + ASTContext &Context; + +public: + explicit EvaluatedExprVisitor(ASTContext &Context) : Context(Context) { } + + // Expressions that have no potentially-evaluated subexpressions (but may have + // other sub-expressions). + void VisitDeclRefExpr(DeclRefExpr *E) { } + void VisitOffsetOfExpr(OffsetOfExpr *E) { } + void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) { } + void VisitExpressionTraitExpr(ExpressionTraitExpr *E) { } + void VisitBlockExpr(BlockExpr *E) { } + void VisitCXXUuidofExpr(CXXUuidofExpr *E) { } + void VisitCXXNoexceptExpr(CXXNoexceptExpr *E) { } + + void VisitMemberExpr(MemberExpr *E) { + // Only the base matters. + return this->Visit(E->getBase()); + } + + void VisitChooseExpr(ChooseExpr *E) { + // Only the selected subexpression matters; the other one is not evaluated. + return this->Visit(E->getChosenSubExpr(Context)); + } + + void VisitDesignatedInitExpr(DesignatedInitExpr *E) { + // Only the actual initializer matters; the designators are all constant + // expressions. + return this->Visit(E->getInit()); + } + + void VisitCXXTypeidExpr(CXXTypeidExpr *E) { + // typeid(expression) is potentially evaluated when the argument is + // a glvalue of polymorphic type. (C++ 5.2.8p2-3) + if (!E->isTypeOperand() && E->Classify(Context).isGLValue()) + if (const RecordType *Record + = E->getExprOperand()->getType()->template getAs<RecordType>()) + if (cast<CXXRecordDecl>(Record->getDecl())->isPolymorphic()) + return this->Visit(E->getExprOperand()); + } + + /// \brief The basis case walks all of the children of the statement or + /// expression, assuming they are all potentially evaluated. + void VisitStmt(Stmt *S) { + for (Stmt::child_range C = S->children(); C; ++C) + if (*C) + this->Visit(*C); + } +}; + +} + +#endif // LLVM_CLANG_AST_EVALUATEDEXPRVISITOR_H diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h new file mode 100644 index 0000000..b0b9b0f --- /dev/null +++ b/clang/include/clang/AST/Expr.h @@ -0,0 +1,4561 @@ +//===--- Expr.h - Classes for representing expressions ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Expr interface and subclasses. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_EXPR_H +#define LLVM_CLANG_AST_EXPR_H + +#include "clang/AST/APValue.h" +#include "clang/AST/Stmt.h" +#include "clang/AST/Type.h" +#include "clang/AST/DeclAccessPair.h" +#include "clang/AST/OperationKinds.h" +#include "clang/AST/ASTVector.h" +#include "clang/AST/TemplateBase.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TypeTraits.h" +#include "llvm/ADT/APSInt.h" +#include "llvm/ADT/APFloat.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Compiler.h" +#include <cctype> + +namespace clang { + class ASTContext; + class APValue; + class Decl; + class IdentifierInfo; + class ParmVarDecl; + class NamedDecl; + class ValueDecl; + class BlockDecl; + class CXXBaseSpecifier; + class CXXOperatorCallExpr; + class CXXMemberCallExpr; + class ObjCPropertyRefExpr; + class OpaqueValueExpr; + +/// \brief A simple array of base specifiers. +typedef SmallVector<CXXBaseSpecifier*, 4> CXXCastPath; + +/// Expr - This represents one expression. Note that Expr's are subclasses of +/// Stmt. This allows an expression to be transparently used any place a Stmt +/// is required. +/// +class Expr : public Stmt { + QualType TR; + +protected: + Expr(StmtClass SC, QualType T, ExprValueKind VK, ExprObjectKind OK, + bool TD, bool VD, bool ID, bool ContainsUnexpandedParameterPack) + : Stmt(SC) + { + ExprBits.TypeDependent = TD; + ExprBits.ValueDependent = VD; + ExprBits.InstantiationDependent = ID; + ExprBits.ValueKind = VK; + ExprBits.ObjectKind = OK; + ExprBits.ContainsUnexpandedParameterPack = ContainsUnexpandedParameterPack; + setType(T); + } + + /// \brief Construct an empty expression. + explicit Expr(StmtClass SC, EmptyShell) : Stmt(SC) { } + +public: + QualType getType() const { return TR; } + void setType(QualType t) { + // In C++, the type of an expression is always adjusted so that it + // will not have reference type an expression will never have + // reference type (C++ [expr]p6). Use + // QualType::getNonReferenceType() to retrieve the non-reference + // type. Additionally, inspect Expr::isLvalue to determine whether + // an expression that is adjusted in this manner should be + // considered an lvalue. + assert((t.isNull() || !t->isReferenceType()) && + "Expressions can't have reference type"); + + TR = t; + } + + /// isValueDependent - Determines whether this expression is + /// value-dependent (C++ [temp.dep.constexpr]). For example, the + /// array bound of "Chars" in the following example is + /// value-dependent. + /// @code + /// template<int Size, char (&Chars)[Size]> struct meta_string; + /// @endcode + bool isValueDependent() const { return ExprBits.ValueDependent; } + + /// \brief Set whether this expression is value-dependent or not. + void setValueDependent(bool VD) { + ExprBits.ValueDependent = VD; + if (VD) + ExprBits.InstantiationDependent = true; + } + + /// isTypeDependent - Determines whether this expression is + /// type-dependent (C++ [temp.dep.expr]), which means that its type + /// could change from one template instantiation to the next. For + /// example, the expressions "x" and "x + y" are type-dependent in + /// the following code, but "y" is not type-dependent: + /// @code + /// template<typename T> + /// void add(T x, int y) { + /// x + y; + /// } + /// @endcode + bool isTypeDependent() const { return ExprBits.TypeDependent; } + + /// \brief Set whether this expression is type-dependent or not. + void setTypeDependent(bool TD) { + ExprBits.TypeDependent = TD; + if (TD) + ExprBits.InstantiationDependent = true; + } + + /// \brief Whether this expression is instantiation-dependent, meaning that + /// it depends in some way on a template parameter, even if neither its type + /// nor (constant) value can change due to the template instantiation. + /// + /// In the following example, the expression \c sizeof(sizeof(T() + T())) is + /// instantiation-dependent (since it involves a template parameter \c T), but + /// is neither type- nor value-dependent, since the type of the inner + /// \c sizeof is known (\c std::size_t) and therefore the size of the outer + /// \c sizeof is known. + /// + /// \code + /// template<typename T> + /// void f(T x, T y) { + /// sizeof(sizeof(T() + T()); + /// } + /// \endcode + /// + bool isInstantiationDependent() const { + return ExprBits.InstantiationDependent; + } + + /// \brief Set whether this expression is instantiation-dependent or not. + void setInstantiationDependent(bool ID) { + ExprBits.InstantiationDependent = ID; + } + + /// \brief Whether this expression contains an unexpanded parameter + /// pack (for C++0x variadic templates). + /// + /// Given the following function template: + /// + /// \code + /// template<typename F, typename ...Types> + /// void forward(const F &f, Types &&...args) { + /// f(static_cast<Types&&>(args)...); + /// } + /// \endcode + /// + /// The expressions \c args and \c static_cast<Types&&>(args) both + /// contain parameter packs. + bool containsUnexpandedParameterPack() const { + return ExprBits.ContainsUnexpandedParameterPack; + } + + /// \brief Set the bit that describes whether this expression + /// contains an unexpanded parameter pack. + void setContainsUnexpandedParameterPack(bool PP = true) { + ExprBits.ContainsUnexpandedParameterPack = PP; + } + + /// getExprLoc - Return the preferred location for the arrow when diagnosing + /// a problem with a generic expression. + SourceLocation getExprLoc() const LLVM_READONLY; + + /// isUnusedResultAWarning - Return true if this immediate expression should + /// be warned about if the result is unused. If so, fill in Loc and Ranges + /// with location to warn on and the source range[s] to report with the + /// warning. + bool isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, + SourceRange &R2, ASTContext &Ctx) const; + + /// isLValue - True if this expression is an "l-value" according to + /// the rules of the current language. C and C++ give somewhat + /// different rules for this concept, but in general, the result of + /// an l-value expression identifies a specific object whereas the + /// result of an r-value expression is a value detached from any + /// specific storage. + /// + /// C++0x divides the concept of "r-value" into pure r-values + /// ("pr-values") and so-called expiring values ("x-values"), which + /// identify specific objects that can be safely cannibalized for + /// their resources. This is an unfortunate abuse of terminology on + /// the part of the C++ committee. In Clang, when we say "r-value", + /// we generally mean a pr-value. + bool isLValue() const { return getValueKind() == VK_LValue; } + bool isRValue() const { return getValueKind() == VK_RValue; } + bool isXValue() const { return getValueKind() == VK_XValue; } + bool isGLValue() const { return getValueKind() != VK_RValue; } + + enum LValueClassification { + LV_Valid, + LV_NotObjectType, + LV_IncompleteVoidType, + LV_DuplicateVectorComponents, + LV_InvalidExpression, + LV_InvalidMessageExpression, + LV_MemberFunction, + LV_SubObjCPropertySetting, + LV_ClassTemporary + }; + /// Reasons why an expression might not be an l-value. + LValueClassification ClassifyLValue(ASTContext &Ctx) const; + + /// isModifiableLvalue - C99 6.3.2.1: an lvalue that does not have array type, + /// does not have an incomplete type, does not have a const-qualified type, + /// and if it is a structure or union, does not have any member (including, + /// recursively, any member or element of all contained aggregates or unions) + /// with a const-qualified type. + /// + /// \param Loc [in] [out] - A source location which *may* be filled + /// in with the location of the expression making this a + /// non-modifiable lvalue, if specified. + enum isModifiableLvalueResult { + MLV_Valid, + MLV_NotObjectType, + MLV_IncompleteVoidType, + MLV_DuplicateVectorComponents, + MLV_InvalidExpression, + MLV_LValueCast, // Specialized form of MLV_InvalidExpression. + MLV_IncompleteType, + MLV_ConstQualified, + MLV_ArrayType, + MLV_ReadonlyProperty, + MLV_NoSetterProperty, + MLV_MemberFunction, + MLV_SubObjCPropertySetting, + MLV_InvalidMessageExpression, + MLV_ClassTemporary + }; + isModifiableLvalueResult isModifiableLvalue(ASTContext &Ctx, + SourceLocation *Loc = 0) const; + + /// \brief The return type of classify(). Represents the C++0x expression + /// taxonomy. + class Classification { + public: + /// \brief The various classification results. Most of these mean prvalue. + enum Kinds { + CL_LValue, + CL_XValue, + CL_Function, // Functions cannot be lvalues in C. + CL_Void, // Void cannot be an lvalue in C. + CL_AddressableVoid, // Void expression whose address can be taken in C. + CL_DuplicateVectorComponents, // A vector shuffle with dupes. + CL_MemberFunction, // An expression referring to a member function + CL_SubObjCPropertySetting, + CL_ClassTemporary, // A prvalue of class type + CL_ObjCMessageRValue, // ObjC message is an rvalue + CL_PRValue // A prvalue for any other reason, of any other type + }; + /// \brief The results of modification testing. + enum ModifiableType { + CM_Untested, // testModifiable was false. + CM_Modifiable, + CM_RValue, // Not modifiable because it's an rvalue + CM_Function, // Not modifiable because it's a function; C++ only + CM_LValueCast, // Same as CM_RValue, but indicates GCC cast-as-lvalue ext + CM_NoSetterProperty,// Implicit assignment to ObjC property without setter + CM_ConstQualified, + CM_ArrayType, + CM_IncompleteType + }; + + private: + friend class Expr; + + unsigned short Kind; + unsigned short Modifiable; + + explicit Classification(Kinds k, ModifiableType m) + : Kind(k), Modifiable(m) + {} + + public: + Classification() {} + + Kinds getKind() const { return static_cast<Kinds>(Kind); } + ModifiableType getModifiable() const { + assert(Modifiable != CM_Untested && "Did not test for modifiability."); + return static_cast<ModifiableType>(Modifiable); + } + bool isLValue() const { return Kind == CL_LValue; } + bool isXValue() const { return Kind == CL_XValue; } + bool isGLValue() const { return Kind <= CL_XValue; } + bool isPRValue() const { return Kind >= CL_Function; } + bool isRValue() const { return Kind >= CL_XValue; } + bool isModifiable() const { return getModifiable() == CM_Modifiable; } + + /// \brief Create a simple, modifiably lvalue + static Classification makeSimpleLValue() { + return Classification(CL_LValue, CM_Modifiable); + } + + }; + /// \brief Classify - Classify this expression according to the C++0x + /// expression taxonomy. + /// + /// C++0x defines ([basic.lval]) a new taxonomy of expressions to replace the + /// old lvalue vs rvalue. This function determines the type of expression this + /// is. There are three expression types: + /// - lvalues are classical lvalues as in C++03. + /// - prvalues are equivalent to rvalues in C++03. + /// - xvalues are expressions yielding unnamed rvalue references, e.g. a + /// function returning an rvalue reference. + /// lvalues and xvalues are collectively referred to as glvalues, while + /// prvalues and xvalues together form rvalues. + Classification Classify(ASTContext &Ctx) const { + return ClassifyImpl(Ctx, 0); + } + + /// \brief ClassifyModifiable - Classify this expression according to the + /// C++0x expression taxonomy, and see if it is valid on the left side + /// of an assignment. + /// + /// This function extends classify in that it also tests whether the + /// expression is modifiable (C99 6.3.2.1p1). + /// \param Loc A source location that might be filled with a relevant location + /// if the expression is not modifiable. + Classification ClassifyModifiable(ASTContext &Ctx, SourceLocation &Loc) const{ + return ClassifyImpl(Ctx, &Loc); + } + + /// getValueKindForType - Given a formal return or parameter type, + /// give its value kind. + static ExprValueKind getValueKindForType(QualType T) { + if (const ReferenceType *RT = T->getAs<ReferenceType>()) + return (isa<LValueReferenceType>(RT) + ? VK_LValue + : (RT->getPointeeType()->isFunctionType() + ? VK_LValue : VK_XValue)); + return VK_RValue; + } + + /// getValueKind - The value kind that this expression produces. + ExprValueKind getValueKind() const { + return static_cast<ExprValueKind>(ExprBits.ValueKind); + } + + /// getObjectKind - The object kind that this expression produces. + /// Object kinds are meaningful only for expressions that yield an + /// l-value or x-value. + ExprObjectKind getObjectKind() const { + return static_cast<ExprObjectKind>(ExprBits.ObjectKind); + } + + bool isOrdinaryOrBitFieldObject() const { + ExprObjectKind OK = getObjectKind(); + return (OK == OK_Ordinary || OK == OK_BitField); + } + + /// setValueKind - Set the value kind produced by this expression. + void setValueKind(ExprValueKind Cat) { ExprBits.ValueKind = Cat; } + + /// setObjectKind - Set the object kind produced by this expression. + void setObjectKind(ExprObjectKind Cat) { ExprBits.ObjectKind = Cat; } + +private: + Classification ClassifyImpl(ASTContext &Ctx, SourceLocation *Loc) const; + +public: + + /// \brief If this expression refers to a bit-field, retrieve the + /// declaration of that bit-field. + FieldDecl *getBitField(); + + const FieldDecl *getBitField() const { + return const_cast<Expr*>(this)->getBitField(); + } + + /// \brief If this expression is an l-value for an Objective C + /// property, find the underlying property reference expression. + const ObjCPropertyRefExpr *getObjCProperty() const; + + /// \brief Returns whether this expression refers to a vector element. + bool refersToVectorElement() const; + + /// \brief Returns whether this expression has a placeholder type. + bool hasPlaceholderType() const { + return getType()->isPlaceholderType(); + } + + /// \brief Returns whether this expression has a specific placeholder type. + bool hasPlaceholderType(BuiltinType::Kind K) const { + assert(BuiltinType::isPlaceholderTypeKind(K)); + if (const BuiltinType *BT = dyn_cast<BuiltinType>(getType())) + return BT->getKind() == K; + return false; + } + + /// isKnownToHaveBooleanValue - Return true if this is an integer expression + /// that is known to return 0 or 1. This happens for _Bool/bool expressions + /// but also int expressions which are produced by things like comparisons in + /// C. + bool isKnownToHaveBooleanValue() const; + + /// isIntegerConstantExpr - Return true if this expression is a valid integer + /// constant expression, and, if so, return its value in Result. If not a + /// valid i-c-e, return false and fill in Loc (if specified) with the location + /// of the invalid expression. + /// + /// Note: This does not perform the implicit conversions required by C++11 + /// [expr.const]p5. + bool isIntegerConstantExpr(llvm::APSInt &Result, ASTContext &Ctx, + SourceLocation *Loc = 0, + bool isEvaluated = true) const; + bool isIntegerConstantExpr(ASTContext &Ctx, SourceLocation *Loc = 0) const; + + /// isCXX98IntegralConstantExpr - Return true if this expression is an + /// integral constant expression in C++98. Can only be used in C++. + bool isCXX98IntegralConstantExpr(ASTContext &Ctx) const; + + /// isCXX11ConstantExpr - Return true if this expression is a constant + /// expression in C++11. Can only be used in C++. + /// + /// Note: This does not perform the implicit conversions required by C++11 + /// [expr.const]p5. + bool isCXX11ConstantExpr(ASTContext &Ctx, APValue *Result = 0, + SourceLocation *Loc = 0) const; + + /// isPotentialConstantExpr - Return true if this function's definition + /// might be usable in a constant expression in C++11, if it were marked + /// constexpr. Return false if the function can never produce a constant + /// expression, along with diagnostics describing why not. + static bool isPotentialConstantExpr(const FunctionDecl *FD, + llvm::SmallVectorImpl< + PartialDiagnosticAt> &Diags); + + /// isConstantInitializer - Returns true if this expression can be emitted to + /// IR as a constant, and thus can be used as a constant initializer in C. + bool isConstantInitializer(ASTContext &Ctx, bool ForRef) const; + + /// EvalStatus is a struct with detailed info about an evaluation in progress. + struct EvalStatus { + /// HasSideEffects - Whether the evaluated expression has side effects. + /// For example, (f() && 0) can be folded, but it still has side effects. + bool HasSideEffects; + + /// Diag - If this is non-null, it will be filled in with a stack of notes + /// indicating why evaluation failed (or why it failed to produce a constant + /// expression). + /// If the expression is unfoldable, the notes will indicate why it's not + /// foldable. If the expression is foldable, but not a constant expression, + /// the notes will describes why it isn't a constant expression. If the + /// expression *is* a constant expression, no notes will be produced. + llvm::SmallVectorImpl<PartialDiagnosticAt> *Diag; + + EvalStatus() : HasSideEffects(false), Diag(0) {} + + // hasSideEffects - Return true if the evaluated expression has + // side effects. + bool hasSideEffects() const { + return HasSideEffects; + } + }; + + /// EvalResult is a struct with detailed info about an evaluated expression. + struct EvalResult : EvalStatus { + /// Val - This is the value the expression can be folded to. + APValue Val; + + // isGlobalLValue - Return true if the evaluated lvalue expression + // is global. + bool isGlobalLValue() const; + }; + + /// EvaluateAsRValue - Return true if this is a constant which we can fold to + /// an rvalue using any crazy technique (that has nothing to do with language + /// standards) that we want to, even if the expression has side-effects. If + /// this function returns true, it returns the folded constant in Result. If + /// the expression is a glvalue, an lvalue-to-rvalue conversion will be + /// applied. + bool EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx) const; + + /// EvaluateAsBooleanCondition - Return true if this is a constant + /// which we we can fold and convert to a boolean condition using + /// any crazy technique that we want to, even if the expression has + /// side-effects. + bool EvaluateAsBooleanCondition(bool &Result, const ASTContext &Ctx) const; + + enum SideEffectsKind { SE_NoSideEffects, SE_AllowSideEffects }; + + /// EvaluateAsInt - Return true if this is a constant which we can fold and + /// convert to an integer, using any crazy technique that we want to. + bool EvaluateAsInt(llvm::APSInt &Result, const ASTContext &Ctx, + SideEffectsKind AllowSideEffects = SE_NoSideEffects) const; + + /// isEvaluatable - Call EvaluateAsRValue to see if this expression can be + /// constant folded without side-effects, but discard the result. + bool isEvaluatable(const ASTContext &Ctx) const; + + /// HasSideEffects - This routine returns true for all those expressions + /// which must be evaluated each time and must not be optimized away + /// or evaluated at compile time. Example is a function call, volatile + /// variable read. + bool HasSideEffects(const ASTContext &Ctx) const; + + /// \brief Determine whether this expression involves a call to any function + /// that is not trivial. + bool hasNonTrivialCall(ASTContext &Ctx); + + /// EvaluateKnownConstInt - Call EvaluateAsRValue and return the folded + /// integer. This must be called on an expression that constant folds to an + /// integer. + llvm::APSInt EvaluateKnownConstInt(const ASTContext &Ctx) const; + + /// EvaluateAsLValue - Evaluate an expression to see if we can fold it to an + /// lvalue with link time known address, with no side-effects. + bool EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx) const; + + /// EvaluateAsInitializer - Evaluate an expression as if it were the + /// initializer of the given declaration. Returns true if the initializer + /// can be folded to a constant, and produces any relevant notes. In C++11, + /// notes will be produced if the expression is not a constant expression. + bool EvaluateAsInitializer(APValue &Result, const ASTContext &Ctx, + const VarDecl *VD, + llvm::SmallVectorImpl<PartialDiagnosticAt> &Notes) const; + + /// \brief Enumeration used to describe the kind of Null pointer constant + /// returned from \c isNullPointerConstant(). + enum NullPointerConstantKind { + /// \brief Expression is not a Null pointer constant. + NPCK_NotNull = 0, + + /// \brief Expression is a Null pointer constant built from a zero integer. + NPCK_ZeroInteger, + + /// \brief Expression is a C++0X nullptr. + NPCK_CXX0X_nullptr, + + /// \brief Expression is a GNU-style __null constant. + NPCK_GNUNull + }; + + /// \brief Enumeration used to describe how \c isNullPointerConstant() + /// should cope with value-dependent expressions. + enum NullPointerConstantValueDependence { + /// \brief Specifies that the expression should never be value-dependent. + NPC_NeverValueDependent = 0, + + /// \brief Specifies that a value-dependent expression of integral or + /// dependent type should be considered a null pointer constant. + NPC_ValueDependentIsNull, + + /// \brief Specifies that a value-dependent expression should be considered + /// to never be a null pointer constant. + NPC_ValueDependentIsNotNull + }; + + /// isNullPointerConstant - C99 6.3.2.3p3 - Test if this reduces down to + /// a Null pointer constant. The return value can further distinguish the + /// kind of NULL pointer constant that was detected. + NullPointerConstantKind isNullPointerConstant( + ASTContext &Ctx, + NullPointerConstantValueDependence NPC) const; + + /// isOBJCGCCandidate - Return true if this expression may be used in a read/ + /// write barrier. + bool isOBJCGCCandidate(ASTContext &Ctx) const; + + /// \brief Returns true if this expression is a bound member function. + bool isBoundMemberFunction(ASTContext &Ctx) const; + + /// \brief Given an expression of bound-member type, find the type + /// of the member. Returns null if this is an *overloaded* bound + /// member expression. + static QualType findBoundMemberType(const Expr *expr); + + /// IgnoreImpCasts - Skip past any implicit casts which might + /// surround this expression. Only skips ImplicitCastExprs. + Expr *IgnoreImpCasts() LLVM_READONLY; + + /// IgnoreImplicit - Skip past any implicit AST nodes which might + /// surround this expression. + Expr *IgnoreImplicit() LLVM_READONLY { + return cast<Expr>(Stmt::IgnoreImplicit()); + } + + /// IgnoreParens - Ignore parentheses. If this Expr is a ParenExpr, return + /// its subexpression. If that subexpression is also a ParenExpr, + /// then this method recursively returns its subexpression, and so forth. + /// Otherwise, the method returns the current Expr. + Expr *IgnoreParens() LLVM_READONLY; + + /// IgnoreParenCasts - Ignore parentheses and casts. Strip off any ParenExpr + /// or CastExprs, returning their operand. + Expr *IgnoreParenCasts() LLVM_READONLY; + + /// IgnoreParenImpCasts - Ignore parentheses and implicit casts. Strip off + /// any ParenExpr or ImplicitCastExprs, returning their operand. + Expr *IgnoreParenImpCasts() LLVM_READONLY; + + /// IgnoreConversionOperator - Ignore conversion operator. If this Expr is a + /// call to a conversion operator, return the argument. + Expr *IgnoreConversionOperator() LLVM_READONLY; + + const Expr *IgnoreConversionOperator() const LLVM_READONLY { + return const_cast<Expr*>(this)->IgnoreConversionOperator(); + } + + const Expr *IgnoreParenImpCasts() const LLVM_READONLY { + return const_cast<Expr*>(this)->IgnoreParenImpCasts(); + } + + /// Ignore parentheses and lvalue casts. Strip off any ParenExpr and + /// CastExprs that represent lvalue casts, returning their operand. + Expr *IgnoreParenLValueCasts() LLVM_READONLY; + + const Expr *IgnoreParenLValueCasts() const LLVM_READONLY { + return const_cast<Expr*>(this)->IgnoreParenLValueCasts(); + } + + /// IgnoreParenNoopCasts - Ignore parentheses and casts that do not change the + /// value (including ptr->int casts of the same size). Strip off any + /// ParenExpr or CastExprs, returning their operand. + Expr *IgnoreParenNoopCasts(ASTContext &Ctx) LLVM_READONLY; + + /// \brief Determine whether this expression is a default function argument. + /// + /// Default arguments are implicitly generated in the abstract syntax tree + /// by semantic analysis for function calls, object constructions, etc. in + /// C++. Default arguments are represented by \c CXXDefaultArgExpr nodes; + /// this routine also looks through any implicit casts to determine whether + /// the expression is a default argument. + bool isDefaultArgument() const; + + /// \brief Determine whether the result of this expression is a + /// temporary object of the given class type. + bool isTemporaryObject(ASTContext &Ctx, const CXXRecordDecl *TempTy) const; + + /// \brief Whether this expression is an implicit reference to 'this' in C++. + bool isImplicitCXXThis() const; + + const Expr *IgnoreImpCasts() const LLVM_READONLY { + return const_cast<Expr*>(this)->IgnoreImpCasts(); + } + const Expr *IgnoreParens() const LLVM_READONLY { + return const_cast<Expr*>(this)->IgnoreParens(); + } + const Expr *IgnoreParenCasts() const LLVM_READONLY { + return const_cast<Expr*>(this)->IgnoreParenCasts(); + } + const Expr *IgnoreParenNoopCasts(ASTContext &Ctx) const LLVM_READONLY { + return const_cast<Expr*>(this)->IgnoreParenNoopCasts(Ctx); + } + + static bool hasAnyTypeDependentArguments(llvm::ArrayRef<Expr *> Exprs); + + static bool classof(const Stmt *T) { + return T->getStmtClass() >= firstExprConstant && + T->getStmtClass() <= lastExprConstant; + } + static bool classof(const Expr *) { return true; } +}; + + +//===----------------------------------------------------------------------===// +// Primary Expressions. +//===----------------------------------------------------------------------===// + +/// OpaqueValueExpr - An expression referring to an opaque object of a +/// fixed type and value class. These don't correspond to concrete +/// syntax; instead they're used to express operations (usually copy +/// operations) on values whose source is generally obvious from +/// context. +class OpaqueValueExpr : public Expr { + friend class ASTStmtReader; + Expr *SourceExpr; + SourceLocation Loc; + +public: + OpaqueValueExpr(SourceLocation Loc, QualType T, ExprValueKind VK, + ExprObjectKind OK = OK_Ordinary, + Expr *SourceExpr = 0) + : Expr(OpaqueValueExprClass, T, VK, OK, + T->isDependentType(), + T->isDependentType() || + (SourceExpr && SourceExpr->isValueDependent()), + T->isInstantiationDependentType(), + false), + SourceExpr(SourceExpr), Loc(Loc) { + } + + /// Given an expression which invokes a copy constructor --- i.e. a + /// CXXConstructExpr, possibly wrapped in an ExprWithCleanups --- + /// find the OpaqueValueExpr that's the source of the construction. + static const OpaqueValueExpr *findInCopyConstruct(const Expr *expr); + + explicit OpaqueValueExpr(EmptyShell Empty) + : Expr(OpaqueValueExprClass, Empty) { } + + /// \brief Retrieve the location of this expression. + SourceLocation getLocation() const { return Loc; } + + SourceRange getSourceRange() const LLVM_READONLY { + if (SourceExpr) return SourceExpr->getSourceRange(); + return Loc; + } + SourceLocation getExprLoc() const LLVM_READONLY { + if (SourceExpr) return SourceExpr->getExprLoc(); + return Loc; + } + + child_range children() { return child_range(); } + + /// The source expression of an opaque value expression is the + /// expression which originally generated the value. This is + /// provided as a convenience for analyses that don't wish to + /// precisely model the execution behavior of the program. + /// + /// The source expression is typically set when building the + /// expression which binds the opaque value expression in the first + /// place. + Expr *getSourceExpr() const { return SourceExpr; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OpaqueValueExprClass; + } + static bool classof(const OpaqueValueExpr *) { return true; } +}; + +/// \brief A reference to a declared variable, function, enum, etc. +/// [C99 6.5.1p2] +/// +/// This encodes all the information about how a declaration is referenced +/// within an expression. +/// +/// There are several optional constructs attached to DeclRefExprs only when +/// they apply in order to conserve memory. These are laid out past the end of +/// the object, and flags in the DeclRefExprBitfield track whether they exist: +/// +/// DeclRefExprBits.HasQualifier: +/// Specifies when this declaration reference expression has a C++ +/// nested-name-specifier. +/// DeclRefExprBits.HasFoundDecl: +/// Specifies when this declaration reference expression has a record of +/// a NamedDecl (different from the referenced ValueDecl) which was found +/// during name lookup and/or overload resolution. +/// DeclRefExprBits.HasTemplateKWAndArgsInfo: +/// Specifies when this declaration reference expression has an explicit +/// C++ template keyword and/or template argument list. +/// DeclRefExprBits.RefersToEnclosingLocal +/// Specifies when this declaration reference expression (validly) +/// refers to a local variable from a different function. +class DeclRefExpr : public Expr { + /// \brief The declaration that we are referencing. + ValueDecl *D; + + /// \brief The location of the declaration name itself. + SourceLocation Loc; + + /// \brief Provides source/type location info for the declaration name + /// embedded in D. + DeclarationNameLoc DNLoc; + + /// \brief Helper to retrieve the optional NestedNameSpecifierLoc. + NestedNameSpecifierLoc &getInternalQualifierLoc() { + assert(hasQualifier()); + return *reinterpret_cast<NestedNameSpecifierLoc *>(this + 1); + } + + /// \brief Helper to retrieve the optional NestedNameSpecifierLoc. + const NestedNameSpecifierLoc &getInternalQualifierLoc() const { + return const_cast<DeclRefExpr *>(this)->getInternalQualifierLoc(); + } + + /// \brief Test whether there is a distinct FoundDecl attached to the end of + /// this DRE. + bool hasFoundDecl() const { return DeclRefExprBits.HasFoundDecl; } + + /// \brief Helper to retrieve the optional NamedDecl through which this + /// reference occured. + NamedDecl *&getInternalFoundDecl() { + assert(hasFoundDecl()); + if (hasQualifier()) + return *reinterpret_cast<NamedDecl **>(&getInternalQualifierLoc() + 1); + return *reinterpret_cast<NamedDecl **>(this + 1); + } + + /// \brief Helper to retrieve the optional NamedDecl through which this + /// reference occured. + NamedDecl *getInternalFoundDecl() const { + return const_cast<DeclRefExpr *>(this)->getInternalFoundDecl(); + } + + DeclRefExpr(ASTContext &Ctx, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation TemplateKWLoc, + ValueDecl *D, bool refersToEnclosingLocal, + const DeclarationNameInfo &NameInfo, + NamedDecl *FoundD, + const TemplateArgumentListInfo *TemplateArgs, + QualType T, ExprValueKind VK); + + /// \brief Construct an empty declaration reference expression. + explicit DeclRefExpr(EmptyShell Empty) + : Expr(DeclRefExprClass, Empty) { } + + /// \brief Computes the type- and value-dependence flags for this + /// declaration reference expression. + void computeDependence(ASTContext &C); + +public: + DeclRefExpr(ValueDecl *D, bool refersToEnclosingLocal, QualType T, + ExprValueKind VK, SourceLocation L, + const DeclarationNameLoc &LocInfo = DeclarationNameLoc()) + : Expr(DeclRefExprClass, T, VK, OK_Ordinary, false, false, false, false), + D(D), Loc(L), DNLoc(LocInfo) { + DeclRefExprBits.HasQualifier = 0; + DeclRefExprBits.HasTemplateKWAndArgsInfo = 0; + DeclRefExprBits.HasFoundDecl = 0; + DeclRefExprBits.HadMultipleCandidates = 0; + DeclRefExprBits.RefersToEnclosingLocal = refersToEnclosingLocal; + computeDependence(D->getASTContext()); + } + + static DeclRefExpr *Create(ASTContext &Context, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation TemplateKWLoc, + ValueDecl *D, + bool isEnclosingLocal, + SourceLocation NameLoc, + QualType T, ExprValueKind VK, + NamedDecl *FoundD = 0, + const TemplateArgumentListInfo *TemplateArgs = 0); + + static DeclRefExpr *Create(ASTContext &Context, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation TemplateKWLoc, + ValueDecl *D, + bool isEnclosingLocal, + const DeclarationNameInfo &NameInfo, + QualType T, ExprValueKind VK, + NamedDecl *FoundD = 0, + const TemplateArgumentListInfo *TemplateArgs = 0); + + /// \brief Construct an empty declaration reference expression. + static DeclRefExpr *CreateEmpty(ASTContext &Context, + bool HasQualifier, + bool HasFoundDecl, + bool HasTemplateKWAndArgsInfo, + unsigned NumTemplateArgs); + + ValueDecl *getDecl() { return D; } + const ValueDecl *getDecl() const { return D; } + void setDecl(ValueDecl *NewD) { D = NewD; } + + DeclarationNameInfo getNameInfo() const { + return DeclarationNameInfo(getDecl()->getDeclName(), Loc, DNLoc); + } + + SourceLocation getLocation() const { return Loc; } + void setLocation(SourceLocation L) { Loc = L; } + SourceRange getSourceRange() const LLVM_READONLY; + SourceLocation getLocStart() const LLVM_READONLY; + SourceLocation getLocEnd() const LLVM_READONLY; + + /// \brief Determine whether this declaration reference was preceded by a + /// C++ nested-name-specifier, e.g., \c N::foo. + bool hasQualifier() const { return DeclRefExprBits.HasQualifier; } + + /// \brief If the name was qualified, retrieves the nested-name-specifier + /// that precedes the name. Otherwise, returns NULL. + NestedNameSpecifier *getQualifier() const { + if (!hasQualifier()) + return 0; + + return getInternalQualifierLoc().getNestedNameSpecifier(); + } + + /// \brief If the name was qualified, retrieves the nested-name-specifier + /// that precedes the name, with source-location information. + NestedNameSpecifierLoc getQualifierLoc() const { + if (!hasQualifier()) + return NestedNameSpecifierLoc(); + + return getInternalQualifierLoc(); + } + + /// \brief Get the NamedDecl through which this reference occured. + /// + /// This Decl may be different from the ValueDecl actually referred to in the + /// presence of using declarations, etc. It always returns non-NULL, and may + /// simple return the ValueDecl when appropriate. + NamedDecl *getFoundDecl() { + return hasFoundDecl() ? getInternalFoundDecl() : D; + } + + /// \brief Get the NamedDecl through which this reference occurred. + /// See non-const variant. + const NamedDecl *getFoundDecl() const { + return hasFoundDecl() ? getInternalFoundDecl() : D; + } + + bool hasTemplateKWAndArgsInfo() const { + return DeclRefExprBits.HasTemplateKWAndArgsInfo; + } + + /// \brief Return the optional template keyword and arguments info. + ASTTemplateKWAndArgsInfo *getTemplateKWAndArgsInfo() { + if (!hasTemplateKWAndArgsInfo()) + return 0; + + if (hasFoundDecl()) + return reinterpret_cast<ASTTemplateKWAndArgsInfo *>( + &getInternalFoundDecl() + 1); + + if (hasQualifier()) + return reinterpret_cast<ASTTemplateKWAndArgsInfo *>( + &getInternalQualifierLoc() + 1); + + return reinterpret_cast<ASTTemplateKWAndArgsInfo *>(this + 1); + } + + /// \brief Return the optional template keyword and arguments info. + const ASTTemplateKWAndArgsInfo *getTemplateKWAndArgsInfo() const { + return const_cast<DeclRefExpr*>(this)->getTemplateKWAndArgsInfo(); + } + + /// \brief Retrieve the location of the template keyword preceding + /// this name, if any. + SourceLocation getTemplateKeywordLoc() const { + if (!hasTemplateKWAndArgsInfo()) return SourceLocation(); + return getTemplateKWAndArgsInfo()->getTemplateKeywordLoc(); + } + + /// \brief Retrieve the location of the left angle bracket starting the + /// explicit template argument list following the name, if any. + SourceLocation getLAngleLoc() const { + if (!hasTemplateKWAndArgsInfo()) return SourceLocation(); + return getTemplateKWAndArgsInfo()->LAngleLoc; + } + + /// \brief Retrieve the location of the right angle bracket ending the + /// explicit template argument list following the name, if any. + SourceLocation getRAngleLoc() const { + if (!hasTemplateKWAndArgsInfo()) return SourceLocation(); + return getTemplateKWAndArgsInfo()->RAngleLoc; + } + + /// \brief Determines whether the name in this declaration reference + /// was preceded by the template keyword. + bool hasTemplateKeyword() const { return getTemplateKeywordLoc().isValid(); } + + /// \brief Determines whether this declaration reference was followed by an + /// explicit template argument list. + bool hasExplicitTemplateArgs() const { return getLAngleLoc().isValid(); } + + /// \brief Retrieve the explicit template argument list that followed the + /// member template name. + ASTTemplateArgumentListInfo &getExplicitTemplateArgs() { + assert(hasExplicitTemplateArgs()); + return *getTemplateKWAndArgsInfo(); + } + + /// \brief Retrieve the explicit template argument list that followed the + /// member template name. + const ASTTemplateArgumentListInfo &getExplicitTemplateArgs() const { + return const_cast<DeclRefExpr *>(this)->getExplicitTemplateArgs(); + } + + /// \brief Retrieves the optional explicit template arguments. + /// This points to the same data as getExplicitTemplateArgs(), but + /// returns null if there are no explicit template arguments. + const ASTTemplateArgumentListInfo *getOptionalExplicitTemplateArgs() const { + if (!hasExplicitTemplateArgs()) return 0; + return &getExplicitTemplateArgs(); + } + + /// \brief Copies the template arguments (if present) into the given + /// structure. + void copyTemplateArgumentsInto(TemplateArgumentListInfo &List) const { + if (hasExplicitTemplateArgs()) + getExplicitTemplateArgs().copyInto(List); + } + + /// \brief Retrieve the template arguments provided as part of this + /// template-id. + const TemplateArgumentLoc *getTemplateArgs() const { + if (!hasExplicitTemplateArgs()) + return 0; + + return getExplicitTemplateArgs().getTemplateArgs(); + } + + /// \brief Retrieve the number of template arguments provided as part of this + /// template-id. + unsigned getNumTemplateArgs() const { + if (!hasExplicitTemplateArgs()) + return 0; + + return getExplicitTemplateArgs().NumTemplateArgs; + } + + /// \brief Returns true if this expression refers to a function that + /// was resolved from an overloaded set having size greater than 1. + bool hadMultipleCandidates() const { + return DeclRefExprBits.HadMultipleCandidates; + } + /// \brief Sets the flag telling whether this expression refers to + /// a function that was resolved from an overloaded set having size + /// greater than 1. + void setHadMultipleCandidates(bool V = true) { + DeclRefExprBits.HadMultipleCandidates = V; + } + + /// Does this DeclRefExpr refer to a local declaration from an + /// enclosing function scope? + bool refersToEnclosingLocal() const { + return DeclRefExprBits.RefersToEnclosingLocal; + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == DeclRefExprClass; + } + static bool classof(const DeclRefExpr *) { return true; } + + // Iterators + child_range children() { return child_range(); } + + friend class ASTStmtReader; + friend class ASTStmtWriter; +}; + +/// PredefinedExpr - [C99 6.4.2.2] - A predefined identifier such as __func__. +class PredefinedExpr : public Expr { +public: + enum IdentType { + Func, + Function, + PrettyFunction, + /// PrettyFunctionNoVirtual - The same as PrettyFunction, except that the + /// 'virtual' keyword is omitted for virtual member functions. + PrettyFunctionNoVirtual + }; + +private: + SourceLocation Loc; + IdentType Type; +public: + PredefinedExpr(SourceLocation l, QualType type, IdentType IT) + : Expr(PredefinedExprClass, type, VK_LValue, OK_Ordinary, + type->isDependentType(), type->isDependentType(), + type->isInstantiationDependentType(), + /*ContainsUnexpandedParameterPack=*/false), + Loc(l), Type(IT) {} + + /// \brief Construct an empty predefined expression. + explicit PredefinedExpr(EmptyShell Empty) + : Expr(PredefinedExprClass, Empty) { } + + IdentType getIdentType() const { return Type; } + void setIdentType(IdentType IT) { Type = IT; } + + SourceLocation getLocation() const { return Loc; } + void setLocation(SourceLocation L) { Loc = L; } + + static std::string ComputeName(IdentType IT, const Decl *CurrentDecl); + + SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(Loc); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == PredefinedExprClass; + } + static bool classof(const PredefinedExpr *) { return true; } + + // Iterators + child_range children() { return child_range(); } +}; + +/// \brief Used by IntegerLiteral/FloatingLiteral to store the numeric without +/// leaking memory. +/// +/// For large floats/integers, APFloat/APInt will allocate memory from the heap +/// to represent these numbers. Unfortunately, when we use a BumpPtrAllocator +/// to allocate IntegerLiteral/FloatingLiteral nodes the memory associated with +/// the APFloat/APInt values will never get freed. APNumericStorage uses +/// ASTContext's allocator for memory allocation. +class APNumericStorage { + union { + uint64_t VAL; ///< Used to store the <= 64 bits integer value. + uint64_t *pVal; ///< Used to store the >64 bits integer value. + }; + unsigned BitWidth; + + bool hasAllocation() const { return llvm::APInt::getNumWords(BitWidth) > 1; } + + APNumericStorage(const APNumericStorage&); // do not implement + APNumericStorage& operator=(const APNumericStorage&); // do not implement + +protected: + APNumericStorage() : VAL(0), BitWidth(0) { } + + llvm::APInt getIntValue() const { + unsigned NumWords = llvm::APInt::getNumWords(BitWidth); + if (NumWords > 1) + return llvm::APInt(BitWidth, NumWords, pVal); + else + return llvm::APInt(BitWidth, VAL); + } + void setIntValue(ASTContext &C, const llvm::APInt &Val); +}; + +class APIntStorage : private APNumericStorage { +public: + llvm::APInt getValue() const { return getIntValue(); } + void setValue(ASTContext &C, const llvm::APInt &Val) { setIntValue(C, Val); } +}; + +class APFloatStorage : private APNumericStorage { +public: + llvm::APFloat getValue(bool IsIEEE) const { + return llvm::APFloat(getIntValue(), IsIEEE); + } + void setValue(ASTContext &C, const llvm::APFloat &Val) { + setIntValue(C, Val.bitcastToAPInt()); + } +}; + +class IntegerLiteral : public Expr, public APIntStorage { + SourceLocation Loc; + + /// \brief Construct an empty integer literal. + explicit IntegerLiteral(EmptyShell Empty) + : Expr(IntegerLiteralClass, Empty) { } + +public: + // type should be IntTy, LongTy, LongLongTy, UnsignedIntTy, UnsignedLongTy, + // or UnsignedLongLongTy + IntegerLiteral(ASTContext &C, const llvm::APInt &V, + QualType type, SourceLocation l) + : Expr(IntegerLiteralClass, type, VK_RValue, OK_Ordinary, false, false, + false, false), + Loc(l) { + assert(type->isIntegerType() && "Illegal type in IntegerLiteral"); + assert(V.getBitWidth() == C.getIntWidth(type) && + "Integer type is not the correct size for constant."); + setValue(C, V); + } + + /// \brief Returns a new integer literal with value 'V' and type 'type'. + /// \param type - either IntTy, LongTy, LongLongTy, UnsignedIntTy, + /// UnsignedLongTy, or UnsignedLongLongTy which should match the size of V + /// \param V - the value that the returned integer literal contains. + static IntegerLiteral *Create(ASTContext &C, const llvm::APInt &V, + QualType type, SourceLocation l); + /// \brief Returns a new empty integer literal. + static IntegerLiteral *Create(ASTContext &C, EmptyShell Empty); + + SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(Loc); } + + /// \brief Retrieve the location of the literal. + SourceLocation getLocation() const { return Loc; } + + void setLocation(SourceLocation Location) { Loc = Location; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == IntegerLiteralClass; + } + static bool classof(const IntegerLiteral *) { return true; } + + // Iterators + child_range children() { return child_range(); } +}; + +class CharacterLiteral : public Expr { +public: + enum CharacterKind { + Ascii, + Wide, + UTF16, + UTF32 + }; + +private: + unsigned Value; + SourceLocation Loc; +public: + // type should be IntTy + CharacterLiteral(unsigned value, CharacterKind kind, QualType type, + SourceLocation l) + : Expr(CharacterLiteralClass, type, VK_RValue, OK_Ordinary, false, false, + false, false), + Value(value), Loc(l) { + CharacterLiteralBits.Kind = kind; + } + + /// \brief Construct an empty character literal. + CharacterLiteral(EmptyShell Empty) : Expr(CharacterLiteralClass, Empty) { } + + SourceLocation getLocation() const { return Loc; } + CharacterKind getKind() const { + return static_cast<CharacterKind>(CharacterLiteralBits.Kind); + } + + SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(Loc); } + + unsigned getValue() const { return Value; } + + void setLocation(SourceLocation Location) { Loc = Location; } + void setKind(CharacterKind kind) { CharacterLiteralBits.Kind = kind; } + void setValue(unsigned Val) { Value = Val; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CharacterLiteralClass; + } + static bool classof(const CharacterLiteral *) { return true; } + + // Iterators + child_range children() { return child_range(); } +}; + +class FloatingLiteral : public Expr, private APFloatStorage { + SourceLocation Loc; + + FloatingLiteral(ASTContext &C, const llvm::APFloat &V, bool isexact, + QualType Type, SourceLocation L) + : Expr(FloatingLiteralClass, Type, VK_RValue, OK_Ordinary, false, false, + false, false), Loc(L) { + FloatingLiteralBits.IsIEEE = + &C.getTargetInfo().getLongDoubleFormat() == &llvm::APFloat::IEEEquad; + FloatingLiteralBits.IsExact = isexact; + setValue(C, V); + } + + /// \brief Construct an empty floating-point literal. + explicit FloatingLiteral(ASTContext &C, EmptyShell Empty) + : Expr(FloatingLiteralClass, Empty) { + FloatingLiteralBits.IsIEEE = + &C.getTargetInfo().getLongDoubleFormat() == &llvm::APFloat::IEEEquad; + FloatingLiteralBits.IsExact = false; + } + +public: + static FloatingLiteral *Create(ASTContext &C, const llvm::APFloat &V, + bool isexact, QualType Type, SourceLocation L); + static FloatingLiteral *Create(ASTContext &C, EmptyShell Empty); + + llvm::APFloat getValue() const { + return APFloatStorage::getValue(FloatingLiteralBits.IsIEEE); + } + void setValue(ASTContext &C, const llvm::APFloat &Val) { + APFloatStorage::setValue(C, Val); + } + + bool isExact() const { return FloatingLiteralBits.IsExact; } + void setExact(bool E) { FloatingLiteralBits.IsExact = E; } + + /// getValueAsApproximateDouble - This returns the value as an inaccurate + /// double. Note that this may cause loss of precision, but is useful for + /// debugging dumps, etc. + double getValueAsApproximateDouble() const; + + SourceLocation getLocation() const { return Loc; } + void setLocation(SourceLocation L) { Loc = L; } + + SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(Loc); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == FloatingLiteralClass; + } + static bool classof(const FloatingLiteral *) { return true; } + + // Iterators + child_range children() { return child_range(); } +}; + +/// ImaginaryLiteral - We support imaginary integer and floating point literals, +/// like "1.0i". We represent these as a wrapper around FloatingLiteral and +/// IntegerLiteral classes. Instances of this class always have a Complex type +/// whose element type matches the subexpression. +/// +class ImaginaryLiteral : public Expr { + Stmt *Val; +public: + ImaginaryLiteral(Expr *val, QualType Ty) + : Expr(ImaginaryLiteralClass, Ty, VK_RValue, OK_Ordinary, false, false, + false, false), + Val(val) {} + + /// \brief Build an empty imaginary literal. + explicit ImaginaryLiteral(EmptyShell Empty) + : Expr(ImaginaryLiteralClass, Empty) { } + + const Expr *getSubExpr() const { return cast<Expr>(Val); } + Expr *getSubExpr() { return cast<Expr>(Val); } + void setSubExpr(Expr *E) { Val = E; } + + SourceRange getSourceRange() const LLVM_READONLY { return Val->getSourceRange(); } + static bool classof(const Stmt *T) { + return T->getStmtClass() == ImaginaryLiteralClass; + } + static bool classof(const ImaginaryLiteral *) { return true; } + + // Iterators + child_range children() { return child_range(&Val, &Val+1); } +}; + +/// StringLiteral - This represents a string literal expression, e.g. "foo" +/// or L"bar" (wide strings). The actual string is returned by getStrData() +/// is NOT null-terminated, and the length of the string is determined by +/// calling getByteLength(). The C type for a string is always a +/// ConstantArrayType. In C++, the char type is const qualified, in C it is +/// not. +/// +/// Note that strings in C can be formed by concatenation of multiple string +/// literal pptokens in translation phase #6. This keeps track of the locations +/// of each of these pieces. +/// +/// Strings in C can also be truncated and extended by assigning into arrays, +/// e.g. with constructs like: +/// char X[2] = "foobar"; +/// In this case, getByteLength() will return 6, but the string literal will +/// have type "char[2]". +class StringLiteral : public Expr { +public: + enum StringKind { + Ascii, + Wide, + UTF8, + UTF16, + UTF32 + }; + +private: + friend class ASTStmtReader; + + union { + const char *asChar; + const uint16_t *asUInt16; + const uint32_t *asUInt32; + } StrData; + unsigned Length; + unsigned CharByteWidth : 4; + unsigned Kind : 3; + unsigned IsPascal : 1; + unsigned NumConcatenated; + SourceLocation TokLocs[1]; + + StringLiteral(QualType Ty) : + Expr(StringLiteralClass, Ty, VK_LValue, OK_Ordinary, false, false, false, + false) {} + + static int mapCharByteWidth(TargetInfo const &target,StringKind k); + +public: + /// This is the "fully general" constructor that allows representation of + /// strings formed from multiple concatenated tokens. + static StringLiteral *Create(ASTContext &C, StringRef Str, StringKind Kind, + bool Pascal, QualType Ty, + const SourceLocation *Loc, unsigned NumStrs); + + /// Simple constructor for string literals made from one token. + static StringLiteral *Create(ASTContext &C, StringRef Str, StringKind Kind, + bool Pascal, QualType Ty, + SourceLocation Loc) { + return Create(C, Str, Kind, Pascal, Ty, &Loc, 1); + } + + /// \brief Construct an empty string literal. + static StringLiteral *CreateEmpty(ASTContext &C, unsigned NumStrs); + + StringRef getString() const { + assert(CharByteWidth==1 + && "This function is used in places that assume strings use char"); + return StringRef(StrData.asChar, getByteLength()); + } + + /// Allow clients that need the byte representation, such as ASTWriterStmt + /// ::VisitStringLiteral(), access. + StringRef getBytes() const { + // FIXME: StringRef may not be the right type to use as a result for this. + if (CharByteWidth == 1) + return StringRef(StrData.asChar, getByteLength()); + if (CharByteWidth == 4) + return StringRef(reinterpret_cast<const char*>(StrData.asUInt32), + getByteLength()); + assert(CharByteWidth == 2 && "unsupported CharByteWidth"); + return StringRef(reinterpret_cast<const char*>(StrData.asUInt16), + getByteLength()); + } + + uint32_t getCodeUnit(size_t i) const { + assert(i < Length && "out of bounds access"); + if (CharByteWidth == 1) + return static_cast<unsigned char>(StrData.asChar[i]); + if (CharByteWidth == 4) + return StrData.asUInt32[i]; + assert(CharByteWidth == 2 && "unsupported CharByteWidth"); + return StrData.asUInt16[i]; + } + + unsigned getByteLength() const { return CharByteWidth*Length; } + unsigned getLength() const { return Length; } + unsigned getCharByteWidth() const { return CharByteWidth; } + + /// \brief Sets the string data to the given string data. + void setString(ASTContext &C, StringRef Str, + StringKind Kind, bool IsPascal); + + StringKind getKind() const { return static_cast<StringKind>(Kind); } + + + bool isAscii() const { return Kind == Ascii; } + bool isWide() const { return Kind == Wide; } + bool isUTF8() const { return Kind == UTF8; } + bool isUTF16() const { return Kind == UTF16; } + bool isUTF32() const { return Kind == UTF32; } + bool isPascal() const { return IsPascal; } + + bool containsNonAsciiOrNull() const { + StringRef Str = getString(); + for (unsigned i = 0, e = Str.size(); i != e; ++i) + if (!isascii(Str[i]) || !Str[i]) + return true; + return false; + } + + /// getNumConcatenated - Get the number of string literal tokens that were + /// concatenated in translation phase #6 to form this string literal. + unsigned getNumConcatenated() const { return NumConcatenated; } + + SourceLocation getStrTokenLoc(unsigned TokNum) const { + assert(TokNum < NumConcatenated && "Invalid tok number"); + return TokLocs[TokNum]; + } + void setStrTokenLoc(unsigned TokNum, SourceLocation L) { + assert(TokNum < NumConcatenated && "Invalid tok number"); + TokLocs[TokNum] = L; + } + + /// getLocationOfByte - Return a source location that points to the specified + /// byte of this string literal. + /// + /// Strings are amazingly complex. They can be formed from multiple tokens + /// and can have escape sequences in them in addition to the usual trigraph + /// and escaped newline business. This routine handles this complexity. + /// + SourceLocation getLocationOfByte(unsigned ByteNo, const SourceManager &SM, + const LangOptions &Features, + const TargetInfo &Target) const; + + typedef const SourceLocation *tokloc_iterator; + tokloc_iterator tokloc_begin() const { return TokLocs; } + tokloc_iterator tokloc_end() const { return TokLocs+NumConcatenated; } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(TokLocs[0], TokLocs[NumConcatenated-1]); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == StringLiteralClass; + } + static bool classof(const StringLiteral *) { return true; } + + // Iterators + child_range children() { return child_range(); } +}; + +/// ParenExpr - This represents a parethesized expression, e.g. "(1)". This +/// AST node is only formed if full location information is requested. +class ParenExpr : public Expr { + SourceLocation L, R; + Stmt *Val; +public: + ParenExpr(SourceLocation l, SourceLocation r, Expr *val) + : Expr(ParenExprClass, val->getType(), + val->getValueKind(), val->getObjectKind(), + val->isTypeDependent(), val->isValueDependent(), + val->isInstantiationDependent(), + val->containsUnexpandedParameterPack()), + L(l), R(r), Val(val) {} + + /// \brief Construct an empty parenthesized expression. + explicit ParenExpr(EmptyShell Empty) + : Expr(ParenExprClass, Empty) { } + + const Expr *getSubExpr() const { return cast<Expr>(Val); } + Expr *getSubExpr() { return cast<Expr>(Val); } + void setSubExpr(Expr *E) { Val = E; } + + SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(L, R); } + + /// \brief Get the location of the left parentheses '('. + SourceLocation getLParen() const { return L; } + void setLParen(SourceLocation Loc) { L = Loc; } + + /// \brief Get the location of the right parentheses ')'. + SourceLocation getRParen() const { return R; } + void setRParen(SourceLocation Loc) { R = Loc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ParenExprClass; + } + static bool classof(const ParenExpr *) { return true; } + + // Iterators + child_range children() { return child_range(&Val, &Val+1); } +}; + + +/// UnaryOperator - This represents the unary-expression's (except sizeof and +/// alignof), the postinc/postdec operators from postfix-expression, and various +/// extensions. +/// +/// Notes on various nodes: +/// +/// Real/Imag - These return the real/imag part of a complex operand. If +/// applied to a non-complex value, the former returns its operand and the +/// later returns zero in the type of the operand. +/// +class UnaryOperator : public Expr { +public: + typedef UnaryOperatorKind Opcode; + +private: + unsigned Opc : 5; + SourceLocation Loc; + Stmt *Val; +public: + + UnaryOperator(Expr *input, Opcode opc, QualType type, + ExprValueKind VK, ExprObjectKind OK, SourceLocation l) + : Expr(UnaryOperatorClass, type, VK, OK, + input->isTypeDependent() || type->isDependentType(), + input->isValueDependent(), + (input->isInstantiationDependent() || + type->isInstantiationDependentType()), + input->containsUnexpandedParameterPack()), + Opc(opc), Loc(l), Val(input) {} + + /// \brief Build an empty unary operator. + explicit UnaryOperator(EmptyShell Empty) + : Expr(UnaryOperatorClass, Empty), Opc(UO_AddrOf) { } + + Opcode getOpcode() const { return static_cast<Opcode>(Opc); } + void setOpcode(Opcode O) { Opc = O; } + + Expr *getSubExpr() const { return cast<Expr>(Val); } + void setSubExpr(Expr *E) { Val = E; } + + /// getOperatorLoc - Return the location of the operator. + SourceLocation getOperatorLoc() const { return Loc; } + void setOperatorLoc(SourceLocation L) { Loc = L; } + + /// isPostfix - Return true if this is a postfix operation, like x++. + static bool isPostfix(Opcode Op) { + return Op == UO_PostInc || Op == UO_PostDec; + } + + /// isPrefix - Return true if this is a prefix operation, like --x. + static bool isPrefix(Opcode Op) { + return Op == UO_PreInc || Op == UO_PreDec; + } + + bool isPrefix() const { return isPrefix(getOpcode()); } + bool isPostfix() const { return isPostfix(getOpcode()); } + + static bool isIncrementOp(Opcode Op) { + return Op == UO_PreInc || Op == UO_PostInc; + } + bool isIncrementOp() const { + return isIncrementOp(getOpcode()); + } + + static bool isDecrementOp(Opcode Op) { + return Op == UO_PreDec || Op == UO_PostDec; + } + bool isDecrementOp() const { + return isDecrementOp(getOpcode()); + } + + static bool isIncrementDecrementOp(Opcode Op) { return Op <= UO_PreDec; } + bool isIncrementDecrementOp() const { + return isIncrementDecrementOp(getOpcode()); + } + + static bool isArithmeticOp(Opcode Op) { + return Op >= UO_Plus && Op <= UO_LNot; + } + bool isArithmeticOp() const { return isArithmeticOp(getOpcode()); } + + /// getOpcodeStr - Turn an Opcode enum value into the punctuation char it + /// corresponds to, e.g. "sizeof" or "[pre]++" + static const char *getOpcodeStr(Opcode Op); + + /// \brief Retrieve the unary opcode that corresponds to the given + /// overloaded operator. + static Opcode getOverloadedOpcode(OverloadedOperatorKind OO, bool Postfix); + + /// \brief Retrieve the overloaded operator kind that corresponds to + /// the given unary opcode. + static OverloadedOperatorKind getOverloadedOperator(Opcode Opc); + + SourceRange getSourceRange() const LLVM_READONLY { + if (isPostfix()) + return SourceRange(Val->getLocStart(), Loc); + else + return SourceRange(Loc, Val->getLocEnd()); + } + SourceLocation getExprLoc() const LLVM_READONLY { return Loc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == UnaryOperatorClass; + } + static bool classof(const UnaryOperator *) { return true; } + + // Iterators + child_range children() { return child_range(&Val, &Val+1); } +}; + +/// OffsetOfExpr - [C99 7.17] - This represents an expression of the form +/// offsetof(record-type, member-designator). For example, given: +/// @code +/// struct S { +/// float f; +/// double d; +/// }; +/// struct T { +/// int i; +/// struct S s[10]; +/// }; +/// @endcode +/// we can represent and evaluate the expression @c offsetof(struct T, s[2].d). + +class OffsetOfExpr : public Expr { +public: + // __builtin_offsetof(type, identifier(.identifier|[expr])*) + class OffsetOfNode { + public: + /// \brief The kind of offsetof node we have. + enum Kind { + /// \brief An index into an array. + Array = 0x00, + /// \brief A field. + Field = 0x01, + /// \brief A field in a dependent type, known only by its name. + Identifier = 0x02, + /// \brief An implicit indirection through a C++ base class, when the + /// field found is in a base class. + Base = 0x03 + }; + + private: + enum { MaskBits = 2, Mask = 0x03 }; + + /// \brief The source range that covers this part of the designator. + SourceRange Range; + + /// \brief The data describing the designator, which comes in three + /// different forms, depending on the lower two bits. + /// - An unsigned index into the array of Expr*'s stored after this node + /// in memory, for [constant-expression] designators. + /// - A FieldDecl*, for references to a known field. + /// - An IdentifierInfo*, for references to a field with a given name + /// when the class type is dependent. + /// - A CXXBaseSpecifier*, for references that look at a field in a + /// base class. + uintptr_t Data; + + public: + /// \brief Create an offsetof node that refers to an array element. + OffsetOfNode(SourceLocation LBracketLoc, unsigned Index, + SourceLocation RBracketLoc) + : Range(LBracketLoc, RBracketLoc), Data((Index << 2) | Array) { } + + /// \brief Create an offsetof node that refers to a field. + OffsetOfNode(SourceLocation DotLoc, FieldDecl *Field, + SourceLocation NameLoc) + : Range(DotLoc.isValid()? DotLoc : NameLoc, NameLoc), + Data(reinterpret_cast<uintptr_t>(Field) | OffsetOfNode::Field) { } + + /// \brief Create an offsetof node that refers to an identifier. + OffsetOfNode(SourceLocation DotLoc, IdentifierInfo *Name, + SourceLocation NameLoc) + : Range(DotLoc.isValid()? DotLoc : NameLoc, NameLoc), + Data(reinterpret_cast<uintptr_t>(Name) | Identifier) { } + + /// \brief Create an offsetof node that refers into a C++ base class. + explicit OffsetOfNode(const CXXBaseSpecifier *Base) + : Range(), Data(reinterpret_cast<uintptr_t>(Base) | OffsetOfNode::Base) {} + + /// \brief Determine what kind of offsetof node this is. + Kind getKind() const { + return static_cast<Kind>(Data & Mask); + } + + /// \brief For an array element node, returns the index into the array + /// of expressions. + unsigned getArrayExprIndex() const { + assert(getKind() == Array); + return Data >> 2; + } + + /// \brief For a field offsetof node, returns the field. + FieldDecl *getField() const { + assert(getKind() == Field); + return reinterpret_cast<FieldDecl *>(Data & ~(uintptr_t)Mask); + } + + /// \brief For a field or identifier offsetof node, returns the name of + /// the field. + IdentifierInfo *getFieldName() const; + + /// \brief For a base class node, returns the base specifier. + CXXBaseSpecifier *getBase() const { + assert(getKind() == Base); + return reinterpret_cast<CXXBaseSpecifier *>(Data & ~(uintptr_t)Mask); + } + + /// \brief Retrieve the source range that covers this offsetof node. + /// + /// For an array element node, the source range contains the locations of + /// the square brackets. For a field or identifier node, the source range + /// contains the location of the period (if there is one) and the + /// identifier. + SourceRange getSourceRange() const LLVM_READONLY { return Range; } + }; + +private: + + SourceLocation OperatorLoc, RParenLoc; + // Base type; + TypeSourceInfo *TSInfo; + // Number of sub-components (i.e. instances of OffsetOfNode). + unsigned NumComps; + // Number of sub-expressions (i.e. array subscript expressions). + unsigned NumExprs; + + OffsetOfExpr(ASTContext &C, QualType type, + SourceLocation OperatorLoc, TypeSourceInfo *tsi, + OffsetOfNode* compsPtr, unsigned numComps, + Expr** exprsPtr, unsigned numExprs, + SourceLocation RParenLoc); + + explicit OffsetOfExpr(unsigned numComps, unsigned numExprs) + : Expr(OffsetOfExprClass, EmptyShell()), + TSInfo(0), NumComps(numComps), NumExprs(numExprs) {} + +public: + + static OffsetOfExpr *Create(ASTContext &C, QualType type, + SourceLocation OperatorLoc, TypeSourceInfo *tsi, + OffsetOfNode* compsPtr, unsigned numComps, + Expr** exprsPtr, unsigned numExprs, + SourceLocation RParenLoc); + + static OffsetOfExpr *CreateEmpty(ASTContext &C, + unsigned NumComps, unsigned NumExprs); + + /// getOperatorLoc - Return the location of the operator. + SourceLocation getOperatorLoc() const { return OperatorLoc; } + void setOperatorLoc(SourceLocation L) { OperatorLoc = L; } + + /// \brief Return the location of the right parentheses. + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation R) { RParenLoc = R; } + + TypeSourceInfo *getTypeSourceInfo() const { + return TSInfo; + } + void setTypeSourceInfo(TypeSourceInfo *tsi) { + TSInfo = tsi; + } + + const OffsetOfNode &getComponent(unsigned Idx) const { + assert(Idx < NumComps && "Subscript out of range"); + return reinterpret_cast<const OffsetOfNode *> (this + 1)[Idx]; + } + + void setComponent(unsigned Idx, OffsetOfNode ON) { + assert(Idx < NumComps && "Subscript out of range"); + reinterpret_cast<OffsetOfNode *> (this + 1)[Idx] = ON; + } + + unsigned getNumComponents() const { + return NumComps; + } + + Expr* getIndexExpr(unsigned Idx) { + assert(Idx < NumExprs && "Subscript out of range"); + return reinterpret_cast<Expr **>( + reinterpret_cast<OffsetOfNode *>(this+1) + NumComps)[Idx]; + } + const Expr *getIndexExpr(unsigned Idx) const { + return const_cast<OffsetOfExpr*>(this)->getIndexExpr(Idx); + } + + void setIndexExpr(unsigned Idx, Expr* E) { + assert(Idx < NumComps && "Subscript out of range"); + reinterpret_cast<Expr **>( + reinterpret_cast<OffsetOfNode *>(this+1) + NumComps)[Idx] = E; + } + + unsigned getNumExpressions() const { + return NumExprs; + } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(OperatorLoc, RParenLoc); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == OffsetOfExprClass; + } + + static bool classof(const OffsetOfExpr *) { return true; } + + // Iterators + child_range children() { + Stmt **begin = + reinterpret_cast<Stmt**>(reinterpret_cast<OffsetOfNode*>(this + 1) + + NumComps); + return child_range(begin, begin + NumExprs); + } +}; + +/// UnaryExprOrTypeTraitExpr - expression with either a type or (unevaluated) +/// expression operand. Used for sizeof/alignof (C99 6.5.3.4) and +/// vec_step (OpenCL 1.1 6.11.12). +class UnaryExprOrTypeTraitExpr : public Expr { + union { + TypeSourceInfo *Ty; + Stmt *Ex; + } Argument; + SourceLocation OpLoc, RParenLoc; + +public: + UnaryExprOrTypeTraitExpr(UnaryExprOrTypeTrait ExprKind, TypeSourceInfo *TInfo, + QualType resultType, SourceLocation op, + SourceLocation rp) : + Expr(UnaryExprOrTypeTraitExprClass, resultType, VK_RValue, OK_Ordinary, + false, // Never type-dependent (C++ [temp.dep.expr]p3). + // Value-dependent if the argument is type-dependent. + TInfo->getType()->isDependentType(), + TInfo->getType()->isInstantiationDependentType(), + TInfo->getType()->containsUnexpandedParameterPack()), + OpLoc(op), RParenLoc(rp) { + UnaryExprOrTypeTraitExprBits.Kind = ExprKind; + UnaryExprOrTypeTraitExprBits.IsType = true; + Argument.Ty = TInfo; + } + + UnaryExprOrTypeTraitExpr(UnaryExprOrTypeTrait ExprKind, Expr *E, + QualType resultType, SourceLocation op, + SourceLocation rp) : + Expr(UnaryExprOrTypeTraitExprClass, resultType, VK_RValue, OK_Ordinary, + false, // Never type-dependent (C++ [temp.dep.expr]p3). + // Value-dependent if the argument is type-dependent. + E->isTypeDependent(), + E->isInstantiationDependent(), + E->containsUnexpandedParameterPack()), + OpLoc(op), RParenLoc(rp) { + UnaryExprOrTypeTraitExprBits.Kind = ExprKind; + UnaryExprOrTypeTraitExprBits.IsType = false; + Argument.Ex = E; + } + + /// \brief Construct an empty sizeof/alignof expression. + explicit UnaryExprOrTypeTraitExpr(EmptyShell Empty) + : Expr(UnaryExprOrTypeTraitExprClass, Empty) { } + + UnaryExprOrTypeTrait getKind() const { + return static_cast<UnaryExprOrTypeTrait>(UnaryExprOrTypeTraitExprBits.Kind); + } + void setKind(UnaryExprOrTypeTrait K) { UnaryExprOrTypeTraitExprBits.Kind = K;} + + bool isArgumentType() const { return UnaryExprOrTypeTraitExprBits.IsType; } + QualType getArgumentType() const { + return getArgumentTypeInfo()->getType(); + } + TypeSourceInfo *getArgumentTypeInfo() const { + assert(isArgumentType() && "calling getArgumentType() when arg is expr"); + return Argument.Ty; + } + Expr *getArgumentExpr() { + assert(!isArgumentType() && "calling getArgumentExpr() when arg is type"); + return static_cast<Expr*>(Argument.Ex); + } + const Expr *getArgumentExpr() const { + return const_cast<UnaryExprOrTypeTraitExpr*>(this)->getArgumentExpr(); + } + + void setArgument(Expr *E) { + Argument.Ex = E; + UnaryExprOrTypeTraitExprBits.IsType = false; + } + void setArgument(TypeSourceInfo *TInfo) { + Argument.Ty = TInfo; + UnaryExprOrTypeTraitExprBits.IsType = true; + } + + /// Gets the argument type, or the type of the argument expression, whichever + /// is appropriate. + QualType getTypeOfArgument() const { + return isArgumentType() ? getArgumentType() : getArgumentExpr()->getType(); + } + + SourceLocation getOperatorLoc() const { return OpLoc; } + void setOperatorLoc(SourceLocation L) { OpLoc = L; } + + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(OpLoc, RParenLoc); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == UnaryExprOrTypeTraitExprClass; + } + static bool classof(const UnaryExprOrTypeTraitExpr *) { return true; } + + // Iterators + child_range children(); +}; + +//===----------------------------------------------------------------------===// +// Postfix Operators. +//===----------------------------------------------------------------------===// + +/// ArraySubscriptExpr - [C99 6.5.2.1] Array Subscripting. +class ArraySubscriptExpr : public Expr { + enum { LHS, RHS, END_EXPR=2 }; + Stmt* SubExprs[END_EXPR]; + SourceLocation RBracketLoc; +public: + ArraySubscriptExpr(Expr *lhs, Expr *rhs, QualType t, + ExprValueKind VK, ExprObjectKind OK, + SourceLocation rbracketloc) + : Expr(ArraySubscriptExprClass, t, VK, OK, + lhs->isTypeDependent() || rhs->isTypeDependent(), + lhs->isValueDependent() || rhs->isValueDependent(), + (lhs->isInstantiationDependent() || + rhs->isInstantiationDependent()), + (lhs->containsUnexpandedParameterPack() || + rhs->containsUnexpandedParameterPack())), + RBracketLoc(rbracketloc) { + SubExprs[LHS] = lhs; + SubExprs[RHS] = rhs; + } + + /// \brief Create an empty array subscript expression. + explicit ArraySubscriptExpr(EmptyShell Shell) + : Expr(ArraySubscriptExprClass, Shell) { } + + /// An array access can be written A[4] or 4[A] (both are equivalent). + /// - getBase() and getIdx() always present the normalized view: A[4]. + /// In this case getBase() returns "A" and getIdx() returns "4". + /// - getLHS() and getRHS() present the syntactic view. e.g. for + /// 4[A] getLHS() returns "4". + /// Note: Because vector element access is also written A[4] we must + /// predicate the format conversion in getBase and getIdx only on the + /// the type of the RHS, as it is possible for the LHS to be a vector of + /// integer type + Expr *getLHS() { return cast<Expr>(SubExprs[LHS]); } + const Expr *getLHS() const { return cast<Expr>(SubExprs[LHS]); } + void setLHS(Expr *E) { SubExprs[LHS] = E; } + + Expr *getRHS() { return cast<Expr>(SubExprs[RHS]); } + const Expr *getRHS() const { return cast<Expr>(SubExprs[RHS]); } + void setRHS(Expr *E) { SubExprs[RHS] = E; } + + Expr *getBase() { + return cast<Expr>(getRHS()->getType()->isIntegerType() ? getLHS():getRHS()); + } + + const Expr *getBase() const { + return cast<Expr>(getRHS()->getType()->isIntegerType() ? getLHS():getRHS()); + } + + Expr *getIdx() { + return cast<Expr>(getRHS()->getType()->isIntegerType() ? getRHS():getLHS()); + } + + const Expr *getIdx() const { + return cast<Expr>(getRHS()->getType()->isIntegerType() ? getRHS():getLHS()); + } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(getLHS()->getLocStart(), RBracketLoc); + } + + SourceLocation getRBracketLoc() const { return RBracketLoc; } + void setRBracketLoc(SourceLocation L) { RBracketLoc = L; } + + SourceLocation getExprLoc() const LLVM_READONLY { return getBase()->getExprLoc(); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ArraySubscriptExprClass; + } + static bool classof(const ArraySubscriptExpr *) { return true; } + + // Iterators + child_range children() { + return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR); + } +}; + + +/// CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]). +/// CallExpr itself represents a normal function call, e.g., "f(x, 2)", +/// while its subclasses may represent alternative syntax that (semantically) +/// results in a function call. For example, CXXOperatorCallExpr is +/// a subclass for overloaded operator calls that use operator syntax, e.g., +/// "str1 + str2" to resolve to a function call. +class CallExpr : public Expr { + enum { FN=0, PREARGS_START=1 }; + Stmt **SubExprs; + unsigned NumArgs; + SourceLocation RParenLoc; + +protected: + // These versions of the constructor are for derived classes. + CallExpr(ASTContext& C, StmtClass SC, Expr *fn, unsigned NumPreArgs, + Expr **args, unsigned numargs, QualType t, ExprValueKind VK, + SourceLocation rparenloc); + CallExpr(ASTContext &C, StmtClass SC, unsigned NumPreArgs, EmptyShell Empty); + + Stmt *getPreArg(unsigned i) { + assert(i < getNumPreArgs() && "Prearg access out of range!"); + return SubExprs[PREARGS_START+i]; + } + const Stmt *getPreArg(unsigned i) const { + assert(i < getNumPreArgs() && "Prearg access out of range!"); + return SubExprs[PREARGS_START+i]; + } + void setPreArg(unsigned i, Stmt *PreArg) { + assert(i < getNumPreArgs() && "Prearg access out of range!"); + SubExprs[PREARGS_START+i] = PreArg; + } + + unsigned getNumPreArgs() const { return CallExprBits.NumPreArgs; } + +public: + CallExpr(ASTContext& C, Expr *fn, Expr **args, unsigned numargs, QualType t, + ExprValueKind VK, SourceLocation rparenloc); + + /// \brief Build an empty call expression. + CallExpr(ASTContext &C, StmtClass SC, EmptyShell Empty); + + const Expr *getCallee() const { return cast<Expr>(SubExprs[FN]); } + Expr *getCallee() { return cast<Expr>(SubExprs[FN]); } + void setCallee(Expr *F) { SubExprs[FN] = F; } + + Decl *getCalleeDecl(); + const Decl *getCalleeDecl() const { + return const_cast<CallExpr*>(this)->getCalleeDecl(); + } + + /// \brief If the callee is a FunctionDecl, return it. Otherwise return 0. + FunctionDecl *getDirectCallee(); + const FunctionDecl *getDirectCallee() const { + return const_cast<CallExpr*>(this)->getDirectCallee(); + } + + /// getNumArgs - Return the number of actual arguments to this call. + /// + unsigned getNumArgs() const { return NumArgs; } + + /// \brief Retrieve the call arguments. + Expr **getArgs() { + return reinterpret_cast<Expr **>(SubExprs+getNumPreArgs()+PREARGS_START); + } + const Expr *const *getArgs() const { + return const_cast<CallExpr*>(this)->getArgs(); + } + + /// getArg - Return the specified argument. + Expr *getArg(unsigned Arg) { + assert(Arg < NumArgs && "Arg access out of range!"); + return cast<Expr>(SubExprs[Arg+getNumPreArgs()+PREARGS_START]); + } + const Expr *getArg(unsigned Arg) const { + assert(Arg < NumArgs && "Arg access out of range!"); + return cast<Expr>(SubExprs[Arg+getNumPreArgs()+PREARGS_START]); + } + + /// setArg - Set the specified argument. + void setArg(unsigned Arg, Expr *ArgExpr) { + assert(Arg < NumArgs && "Arg access out of range!"); + SubExprs[Arg+getNumPreArgs()+PREARGS_START] = ArgExpr; + } + + /// setNumArgs - This changes the number of arguments present in this call. + /// Any orphaned expressions are deleted by this, and any new operands are set + /// to null. + void setNumArgs(ASTContext& C, unsigned NumArgs); + + typedef ExprIterator arg_iterator; + typedef ConstExprIterator const_arg_iterator; + + arg_iterator arg_begin() { return SubExprs+PREARGS_START+getNumPreArgs(); } + arg_iterator arg_end() { + return SubExprs+PREARGS_START+getNumPreArgs()+getNumArgs(); + } + const_arg_iterator arg_begin() const { + return SubExprs+PREARGS_START+getNumPreArgs(); + } + const_arg_iterator arg_end() const { + return SubExprs+PREARGS_START+getNumPreArgs()+getNumArgs(); + } + + /// getNumCommas - Return the number of commas that must have been present in + /// this function call. + unsigned getNumCommas() const { return NumArgs ? NumArgs - 1 : 0; } + + /// isBuiltinCall - If this is a call to a builtin, return the builtin ID. If + /// not, return 0. + unsigned isBuiltinCall() const; + + /// getCallReturnType - Get the return type of the call expr. This is not + /// always the type of the expr itself, if the return type is a reference + /// type. + QualType getCallReturnType() const; + + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } + + SourceRange getSourceRange() const LLVM_READONLY; + SourceLocation getLocStart() const LLVM_READONLY; + SourceLocation getLocEnd() const LLVM_READONLY; + + static bool classof(const Stmt *T) { + return T->getStmtClass() >= firstCallExprConstant && + T->getStmtClass() <= lastCallExprConstant; + } + static bool classof(const CallExpr *) { return true; } + + // Iterators + child_range children() { + return child_range(&SubExprs[0], + &SubExprs[0]+NumArgs+getNumPreArgs()+PREARGS_START); + } +}; + +/// MemberExpr - [C99 6.5.2.3] Structure and Union Members. X->F and X.F. +/// +class MemberExpr : public Expr { + /// Extra data stored in some member expressions. + struct MemberNameQualifier { + /// \brief The nested-name-specifier that qualifies the name, including + /// source-location information. + NestedNameSpecifierLoc QualifierLoc; + + /// \brief The DeclAccessPair through which the MemberDecl was found due to + /// name qualifiers. + DeclAccessPair FoundDecl; + }; + + /// Base - the expression for the base pointer or structure references. In + /// X.F, this is "X". + Stmt *Base; + + /// MemberDecl - This is the decl being referenced by the field/member name. + /// In X.F, this is the decl referenced by F. + ValueDecl *MemberDecl; + + /// MemberDNLoc - Provides source/type location info for the + /// declaration name embedded in MemberDecl. + DeclarationNameLoc MemberDNLoc; + + /// MemberLoc - This is the location of the member name. + SourceLocation MemberLoc; + + /// IsArrow - True if this is "X->F", false if this is "X.F". + bool IsArrow : 1; + + /// \brief True if this member expression used a nested-name-specifier to + /// refer to the member, e.g., "x->Base::f", or found its member via a using + /// declaration. When true, a MemberNameQualifier + /// structure is allocated immediately after the MemberExpr. + bool HasQualifierOrFoundDecl : 1; + + /// \brief True if this member expression specified a template keyword + /// and/or a template argument list explicitly, e.g., x->f<int>, + /// x->template f, x->template f<int>. + /// When true, an ASTTemplateKWAndArgsInfo structure and its + /// TemplateArguments (if any) are allocated immediately after + /// the MemberExpr or, if the member expression also has a qualifier, + /// after the MemberNameQualifier structure. + bool HasTemplateKWAndArgsInfo : 1; + + /// \brief True if this member expression refers to a method that + /// was resolved from an overloaded set having size greater than 1. + bool HadMultipleCandidates : 1; + + /// \brief Retrieve the qualifier that preceded the member name, if any. + MemberNameQualifier *getMemberQualifier() { + assert(HasQualifierOrFoundDecl); + return reinterpret_cast<MemberNameQualifier *> (this + 1); + } + + /// \brief Retrieve the qualifier that preceded the member name, if any. + const MemberNameQualifier *getMemberQualifier() const { + return const_cast<MemberExpr *>(this)->getMemberQualifier(); + } + +public: + MemberExpr(Expr *base, bool isarrow, ValueDecl *memberdecl, + const DeclarationNameInfo &NameInfo, QualType ty, + ExprValueKind VK, ExprObjectKind OK) + : Expr(MemberExprClass, ty, VK, OK, + base->isTypeDependent(), + base->isValueDependent(), + base->isInstantiationDependent(), + base->containsUnexpandedParameterPack()), + Base(base), MemberDecl(memberdecl), MemberDNLoc(NameInfo.getInfo()), + MemberLoc(NameInfo.getLoc()), IsArrow(isarrow), + HasQualifierOrFoundDecl(false), HasTemplateKWAndArgsInfo(false), + HadMultipleCandidates(false) { + assert(memberdecl->getDeclName() == NameInfo.getName()); + } + + // NOTE: this constructor should be used only when it is known that + // the member name can not provide additional syntactic info + // (i.e., source locations for C++ operator names or type source info + // for constructors, destructors and conversion operators). + MemberExpr(Expr *base, bool isarrow, ValueDecl *memberdecl, + SourceLocation l, QualType ty, + ExprValueKind VK, ExprObjectKind OK) + : Expr(MemberExprClass, ty, VK, OK, + base->isTypeDependent(), base->isValueDependent(), + base->isInstantiationDependent(), + base->containsUnexpandedParameterPack()), + Base(base), MemberDecl(memberdecl), MemberDNLoc(), MemberLoc(l), + IsArrow(isarrow), + HasQualifierOrFoundDecl(false), HasTemplateKWAndArgsInfo(false), + HadMultipleCandidates(false) {} + + static MemberExpr *Create(ASTContext &C, Expr *base, bool isarrow, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation TemplateKWLoc, + ValueDecl *memberdecl, DeclAccessPair founddecl, + DeclarationNameInfo MemberNameInfo, + const TemplateArgumentListInfo *targs, + QualType ty, ExprValueKind VK, ExprObjectKind OK); + + void setBase(Expr *E) { Base = E; } + Expr *getBase() const { return cast<Expr>(Base); } + + /// \brief Retrieve the member declaration to which this expression refers. + /// + /// The returned declaration will either be a FieldDecl or (in C++) + /// a CXXMethodDecl. + ValueDecl *getMemberDecl() const { return MemberDecl; } + void setMemberDecl(ValueDecl *D) { MemberDecl = D; } + + /// \brief Retrieves the declaration found by lookup. + DeclAccessPair getFoundDecl() const { + if (!HasQualifierOrFoundDecl) + return DeclAccessPair::make(getMemberDecl(), + getMemberDecl()->getAccess()); + return getMemberQualifier()->FoundDecl; + } + + /// \brief Determines whether this member expression actually had + /// a C++ nested-name-specifier prior to the name of the member, e.g., + /// x->Base::foo. + bool hasQualifier() const { return getQualifier() != 0; } + + /// \brief If the member name was qualified, retrieves the + /// nested-name-specifier that precedes the member name. Otherwise, returns + /// NULL. + NestedNameSpecifier *getQualifier() const { + if (!HasQualifierOrFoundDecl) + return 0; + + return getMemberQualifier()->QualifierLoc.getNestedNameSpecifier(); + } + + /// \brief If the member name was qualified, retrieves the + /// nested-name-specifier that precedes the member name, with source-location + /// information. + NestedNameSpecifierLoc getQualifierLoc() const { + if (!hasQualifier()) + return NestedNameSpecifierLoc(); + + return getMemberQualifier()->QualifierLoc; + } + + /// \brief Return the optional template keyword and arguments info. + ASTTemplateKWAndArgsInfo *getTemplateKWAndArgsInfo() { + if (!HasTemplateKWAndArgsInfo) + return 0; + + if (!HasQualifierOrFoundDecl) + return reinterpret_cast<ASTTemplateKWAndArgsInfo *>(this + 1); + + return reinterpret_cast<ASTTemplateKWAndArgsInfo *>( + getMemberQualifier() + 1); + } + + /// \brief Return the optional template keyword and arguments info. + const ASTTemplateKWAndArgsInfo *getTemplateKWAndArgsInfo() const { + return const_cast<MemberExpr*>(this)->getTemplateKWAndArgsInfo(); + } + + /// \brief Retrieve the location of the template keyword preceding + /// the member name, if any. + SourceLocation getTemplateKeywordLoc() const { + if (!HasTemplateKWAndArgsInfo) return SourceLocation(); + return getTemplateKWAndArgsInfo()->getTemplateKeywordLoc(); + } + + /// \brief Retrieve the location of the left angle bracket starting the + /// explicit template argument list following the member name, if any. + SourceLocation getLAngleLoc() const { + if (!HasTemplateKWAndArgsInfo) return SourceLocation(); + return getTemplateKWAndArgsInfo()->LAngleLoc; + } + + /// \brief Retrieve the location of the right angle bracket ending the + /// explicit template argument list following the member name, if any. + SourceLocation getRAngleLoc() const { + if (!HasTemplateKWAndArgsInfo) return SourceLocation(); + return getTemplateKWAndArgsInfo()->RAngleLoc; + } + + /// Determines whether the member name was preceded by the template keyword. + bool hasTemplateKeyword() const { return getTemplateKeywordLoc().isValid(); } + + /// \brief Determines whether the member name was followed by an + /// explicit template argument list. + bool hasExplicitTemplateArgs() const { return getLAngleLoc().isValid(); } + + /// \brief Copies the template arguments (if present) into the given + /// structure. + void copyTemplateArgumentsInto(TemplateArgumentListInfo &List) const { + if (hasExplicitTemplateArgs()) + getExplicitTemplateArgs().copyInto(List); + } + + /// \brief Retrieve the explicit template argument list that + /// follow the member template name. This must only be called on an + /// expression with explicit template arguments. + ASTTemplateArgumentListInfo &getExplicitTemplateArgs() { + assert(hasExplicitTemplateArgs()); + return *getTemplateKWAndArgsInfo(); + } + + /// \brief Retrieve the explicit template argument list that + /// followed the member template name. This must only be called on + /// an expression with explicit template arguments. + const ASTTemplateArgumentListInfo &getExplicitTemplateArgs() const { + return const_cast<MemberExpr *>(this)->getExplicitTemplateArgs(); + } + + /// \brief Retrieves the optional explicit template arguments. + /// This points to the same data as getExplicitTemplateArgs(), but + /// returns null if there are no explicit template arguments. + const ASTTemplateArgumentListInfo *getOptionalExplicitTemplateArgs() const { + if (!hasExplicitTemplateArgs()) return 0; + return &getExplicitTemplateArgs(); + } + + /// \brief Retrieve the template arguments provided as part of this + /// template-id. + const TemplateArgumentLoc *getTemplateArgs() const { + if (!hasExplicitTemplateArgs()) + return 0; + + return getExplicitTemplateArgs().getTemplateArgs(); + } + + /// \brief Retrieve the number of template arguments provided as part of this + /// template-id. + unsigned getNumTemplateArgs() const { + if (!hasExplicitTemplateArgs()) + return 0; + + return getExplicitTemplateArgs().NumTemplateArgs; + } + + /// \brief Retrieve the member declaration name info. + DeclarationNameInfo getMemberNameInfo() const { + return DeclarationNameInfo(MemberDecl->getDeclName(), + MemberLoc, MemberDNLoc); + } + + bool isArrow() const { return IsArrow; } + void setArrow(bool A) { IsArrow = A; } + + /// getMemberLoc - Return the location of the "member", in X->F, it is the + /// location of 'F'. + SourceLocation getMemberLoc() const { return MemberLoc; } + void setMemberLoc(SourceLocation L) { MemberLoc = L; } + + SourceRange getSourceRange() const LLVM_READONLY; + SourceLocation getLocStart() const LLVM_READONLY; + SourceLocation getLocEnd() const LLVM_READONLY; + + SourceLocation getExprLoc() const LLVM_READONLY { return MemberLoc; } + + /// \brief Determine whether the base of this explicit is implicit. + bool isImplicitAccess() const { + return getBase() && getBase()->isImplicitCXXThis(); + } + + /// \brief Returns true if this member expression refers to a method that + /// was resolved from an overloaded set having size greater than 1. + bool hadMultipleCandidates() const { + return HadMultipleCandidates; + } + /// \brief Sets the flag telling whether this expression refers to + /// a method that was resolved from an overloaded set having size + /// greater than 1. + void setHadMultipleCandidates(bool V = true) { + HadMultipleCandidates = V; + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == MemberExprClass; + } + static bool classof(const MemberExpr *) { return true; } + + // Iterators + child_range children() { return child_range(&Base, &Base+1); } + + friend class ASTReader; + friend class ASTStmtWriter; +}; + +/// CompoundLiteralExpr - [C99 6.5.2.5] +/// +class CompoundLiteralExpr : public Expr { + /// LParenLoc - If non-null, this is the location of the left paren in a + /// compound literal like "(int){4}". This can be null if this is a + /// synthesized compound expression. + SourceLocation LParenLoc; + + /// The type as written. This can be an incomplete array type, in + /// which case the actual expression type will be different. + /// The int part of the pair stores whether this expr is file scope. + llvm::PointerIntPair<TypeSourceInfo *, 1, bool> TInfoAndScope; + Stmt *Init; +public: + CompoundLiteralExpr(SourceLocation lparenloc, TypeSourceInfo *tinfo, + QualType T, ExprValueKind VK, Expr *init, bool fileScope) + : Expr(CompoundLiteralExprClass, T, VK, OK_Ordinary, + tinfo->getType()->isDependentType(), + init->isValueDependent(), + (init->isInstantiationDependent() || + tinfo->getType()->isInstantiationDependentType()), + init->containsUnexpandedParameterPack()), + LParenLoc(lparenloc), TInfoAndScope(tinfo, fileScope), Init(init) {} + + /// \brief Construct an empty compound literal. + explicit CompoundLiteralExpr(EmptyShell Empty) + : Expr(CompoundLiteralExprClass, Empty) { } + + const Expr *getInitializer() const { return cast<Expr>(Init); } + Expr *getInitializer() { return cast<Expr>(Init); } + void setInitializer(Expr *E) { Init = E; } + + bool isFileScope() const { return TInfoAndScope.getInt(); } + void setFileScope(bool FS) { TInfoAndScope.setInt(FS); } + + SourceLocation getLParenLoc() const { return LParenLoc; } + void setLParenLoc(SourceLocation L) { LParenLoc = L; } + + TypeSourceInfo *getTypeSourceInfo() const { + return TInfoAndScope.getPointer(); + } + void setTypeSourceInfo(TypeSourceInfo *tinfo) { + TInfoAndScope.setPointer(tinfo); + } + + SourceRange getSourceRange() const LLVM_READONLY { + // FIXME: Init should never be null. + if (!Init) + return SourceRange(); + if (LParenLoc.isInvalid()) + return Init->getSourceRange(); + return SourceRange(LParenLoc, Init->getLocEnd()); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CompoundLiteralExprClass; + } + static bool classof(const CompoundLiteralExpr *) { return true; } + + // Iterators + child_range children() { return child_range(&Init, &Init+1); } +}; + +/// CastExpr - Base class for type casts, including both implicit +/// casts (ImplicitCastExpr) and explicit casts that have some +/// representation in the source code (ExplicitCastExpr's derived +/// classes). +class CastExpr : public Expr { +public: + typedef clang::CastKind CastKind; + +private: + Stmt *Op; + + void CheckCastConsistency() const; + + const CXXBaseSpecifier * const *path_buffer() const { + return const_cast<CastExpr*>(this)->path_buffer(); + } + CXXBaseSpecifier **path_buffer(); + + void setBasePathSize(unsigned basePathSize) { + CastExprBits.BasePathSize = basePathSize; + assert(CastExprBits.BasePathSize == basePathSize && + "basePathSize doesn't fit in bits of CastExprBits.BasePathSize!"); + } + +protected: + CastExpr(StmtClass SC, QualType ty, ExprValueKind VK, + const CastKind kind, Expr *op, unsigned BasePathSize) : + Expr(SC, ty, VK, OK_Ordinary, + // Cast expressions are type-dependent if the type is + // dependent (C++ [temp.dep.expr]p3). + ty->isDependentType(), + // Cast expressions are value-dependent if the type is + // dependent or if the subexpression is value-dependent. + ty->isDependentType() || (op && op->isValueDependent()), + (ty->isInstantiationDependentType() || + (op && op->isInstantiationDependent())), + (ty->containsUnexpandedParameterPack() || + op->containsUnexpandedParameterPack())), + Op(op) { + assert(kind != CK_Invalid && "creating cast with invalid cast kind"); + CastExprBits.Kind = kind; + setBasePathSize(BasePathSize); +#ifndef NDEBUG + CheckCastConsistency(); +#endif + } + + /// \brief Construct an empty cast. + CastExpr(StmtClass SC, EmptyShell Empty, unsigned BasePathSize) + : Expr(SC, Empty) { + setBasePathSize(BasePathSize); + } + +public: + CastKind getCastKind() const { return (CastKind) CastExprBits.Kind; } + void setCastKind(CastKind K) { CastExprBits.Kind = K; } + const char *getCastKindName() const; + + Expr *getSubExpr() { return cast<Expr>(Op); } + const Expr *getSubExpr() const { return cast<Expr>(Op); } + void setSubExpr(Expr *E) { Op = E; } + + /// \brief Retrieve the cast subexpression as it was written in the source + /// code, looking through any implicit casts or other intermediate nodes + /// introduced by semantic analysis. + Expr *getSubExprAsWritten(); + const Expr *getSubExprAsWritten() const { + return const_cast<CastExpr *>(this)->getSubExprAsWritten(); + } + + typedef CXXBaseSpecifier **path_iterator; + typedef const CXXBaseSpecifier * const *path_const_iterator; + bool path_empty() const { return CastExprBits.BasePathSize == 0; } + unsigned path_size() const { return CastExprBits.BasePathSize; } + path_iterator path_begin() { return path_buffer(); } + path_iterator path_end() { return path_buffer() + path_size(); } + path_const_iterator path_begin() const { return path_buffer(); } + path_const_iterator path_end() const { return path_buffer() + path_size(); } + + void setCastPath(const CXXCastPath &Path); + + static bool classof(const Stmt *T) { + return T->getStmtClass() >= firstCastExprConstant && + T->getStmtClass() <= lastCastExprConstant; + } + static bool classof(const CastExpr *) { return true; } + + // Iterators + child_range children() { return child_range(&Op, &Op+1); } +}; + +/// ImplicitCastExpr - Allows us to explicitly represent implicit type +/// conversions, which have no direct representation in the original +/// source code. For example: converting T[]->T*, void f()->void +/// (*f)(), float->double, short->int, etc. +/// +/// In C, implicit casts always produce rvalues. However, in C++, an +/// implicit cast whose result is being bound to a reference will be +/// an lvalue or xvalue. For example: +/// +/// @code +/// class Base { }; +/// class Derived : public Base { }; +/// Derived &&ref(); +/// void f(Derived d) { +/// Base& b = d; // initializer is an ImplicitCastExpr +/// // to an lvalue of type Base +/// Base&& r = ref(); // initializer is an ImplicitCastExpr +/// // to an xvalue of type Base +/// } +/// @endcode +class ImplicitCastExpr : public CastExpr { +private: + ImplicitCastExpr(QualType ty, CastKind kind, Expr *op, + unsigned BasePathLength, ExprValueKind VK) + : CastExpr(ImplicitCastExprClass, ty, VK, kind, op, BasePathLength) { + } + + /// \brief Construct an empty implicit cast. + explicit ImplicitCastExpr(EmptyShell Shell, unsigned PathSize) + : CastExpr(ImplicitCastExprClass, Shell, PathSize) { } + +public: + enum OnStack_t { OnStack }; + ImplicitCastExpr(OnStack_t _, QualType ty, CastKind kind, Expr *op, + ExprValueKind VK) + : CastExpr(ImplicitCastExprClass, ty, VK, kind, op, 0) { + } + + static ImplicitCastExpr *Create(ASTContext &Context, QualType T, + CastKind Kind, Expr *Operand, + const CXXCastPath *BasePath, + ExprValueKind Cat); + + static ImplicitCastExpr *CreateEmpty(ASTContext &Context, unsigned PathSize); + + SourceRange getSourceRange() const LLVM_READONLY { + return getSubExpr()->getSourceRange(); + } + SourceLocation getLocStart() const LLVM_READONLY { + return getSubExpr()->getLocStart(); + } + SourceLocation getLocEnd() const LLVM_READONLY { + return getSubExpr()->getLocEnd(); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ImplicitCastExprClass; + } + static bool classof(const ImplicitCastExpr *) { return true; } +}; + +inline Expr *Expr::IgnoreImpCasts() { + Expr *e = this; + while (ImplicitCastExpr *ice = dyn_cast<ImplicitCastExpr>(e)) + e = ice->getSubExpr(); + return e; +} + +/// ExplicitCastExpr - An explicit cast written in the source +/// code. +/// +/// This class is effectively an abstract class, because it provides +/// the basic representation of an explicitly-written cast without +/// specifying which kind of cast (C cast, functional cast, static +/// cast, etc.) was written; specific derived classes represent the +/// particular style of cast and its location information. +/// +/// Unlike implicit casts, explicit cast nodes have two different +/// types: the type that was written into the source code, and the +/// actual type of the expression as determined by semantic +/// analysis. These types may differ slightly. For example, in C++ one +/// can cast to a reference type, which indicates that the resulting +/// expression will be an lvalue or xvalue. The reference type, however, +/// will not be used as the type of the expression. +class ExplicitCastExpr : public CastExpr { + /// TInfo - Source type info for the (written) type + /// this expression is casting to. + TypeSourceInfo *TInfo; + +protected: + ExplicitCastExpr(StmtClass SC, QualType exprTy, ExprValueKind VK, + CastKind kind, Expr *op, unsigned PathSize, + TypeSourceInfo *writtenTy) + : CastExpr(SC, exprTy, VK, kind, op, PathSize), TInfo(writtenTy) {} + + /// \brief Construct an empty explicit cast. + ExplicitCastExpr(StmtClass SC, EmptyShell Shell, unsigned PathSize) + : CastExpr(SC, Shell, PathSize) { } + +public: + /// getTypeInfoAsWritten - Returns the type source info for the type + /// that this expression is casting to. + TypeSourceInfo *getTypeInfoAsWritten() const { return TInfo; } + void setTypeInfoAsWritten(TypeSourceInfo *writtenTy) { TInfo = writtenTy; } + + /// getTypeAsWritten - Returns the type that this expression is + /// casting to, as written in the source code. + QualType getTypeAsWritten() const { return TInfo->getType(); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() >= firstExplicitCastExprConstant && + T->getStmtClass() <= lastExplicitCastExprConstant; + } + static bool classof(const ExplicitCastExpr *) { return true; } +}; + +/// CStyleCastExpr - An explicit cast in C (C99 6.5.4) or a C-style +/// cast in C++ (C++ [expr.cast]), which uses the syntax +/// (Type)expr. For example: @c (int)f. +class CStyleCastExpr : public ExplicitCastExpr { + SourceLocation LPLoc; // the location of the left paren + SourceLocation RPLoc; // the location of the right paren + + CStyleCastExpr(QualType exprTy, ExprValueKind vk, CastKind kind, Expr *op, + unsigned PathSize, TypeSourceInfo *writtenTy, + SourceLocation l, SourceLocation r) + : ExplicitCastExpr(CStyleCastExprClass, exprTy, vk, kind, op, PathSize, + writtenTy), LPLoc(l), RPLoc(r) {} + + /// \brief Construct an empty C-style explicit cast. + explicit CStyleCastExpr(EmptyShell Shell, unsigned PathSize) + : ExplicitCastExpr(CStyleCastExprClass, Shell, PathSize) { } + +public: + static CStyleCastExpr *Create(ASTContext &Context, QualType T, + ExprValueKind VK, CastKind K, + Expr *Op, const CXXCastPath *BasePath, + TypeSourceInfo *WrittenTy, SourceLocation L, + SourceLocation R); + + static CStyleCastExpr *CreateEmpty(ASTContext &Context, unsigned PathSize); + + SourceLocation getLParenLoc() const { return LPLoc; } + void setLParenLoc(SourceLocation L) { LPLoc = L; } + + SourceLocation getRParenLoc() const { return RPLoc; } + void setRParenLoc(SourceLocation L) { RPLoc = L; } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(LPLoc, getSubExpr()->getSourceRange().getEnd()); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == CStyleCastExprClass; + } + static bool classof(const CStyleCastExpr *) { return true; } +}; + +/// \brief A builtin binary operation expression such as "x + y" or "x <= y". +/// +/// This expression node kind describes a builtin binary operation, +/// such as "x + y" for integer values "x" and "y". The operands will +/// already have been converted to appropriate types (e.g., by +/// performing promotions or conversions). +/// +/// In C++, where operators may be overloaded, a different kind of +/// expression node (CXXOperatorCallExpr) is used to express the +/// invocation of an overloaded operator with operator syntax. Within +/// a C++ template, whether BinaryOperator or CXXOperatorCallExpr is +/// used to store an expression "x + y" depends on the subexpressions +/// for x and y. If neither x or y is type-dependent, and the "+" +/// operator resolves to a built-in operation, BinaryOperator will be +/// used to express the computation (x and y may still be +/// value-dependent). If either x or y is type-dependent, or if the +/// "+" resolves to an overloaded operator, CXXOperatorCallExpr will +/// be used to express the computation. +class BinaryOperator : public Expr { +public: + typedef BinaryOperatorKind Opcode; + +private: + unsigned Opc : 6; + SourceLocation OpLoc; + + enum { LHS, RHS, END_EXPR }; + Stmt* SubExprs[END_EXPR]; +public: + + BinaryOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy, + ExprValueKind VK, ExprObjectKind OK, + SourceLocation opLoc) + : Expr(BinaryOperatorClass, ResTy, VK, OK, + lhs->isTypeDependent() || rhs->isTypeDependent(), + lhs->isValueDependent() || rhs->isValueDependent(), + (lhs->isInstantiationDependent() || + rhs->isInstantiationDependent()), + (lhs->containsUnexpandedParameterPack() || + rhs->containsUnexpandedParameterPack())), + Opc(opc), OpLoc(opLoc) { + SubExprs[LHS] = lhs; + SubExprs[RHS] = rhs; + assert(!isCompoundAssignmentOp() && + "Use ArithAssignBinaryOperator for compound assignments"); + } + + /// \brief Construct an empty binary operator. + explicit BinaryOperator(EmptyShell Empty) + : Expr(BinaryOperatorClass, Empty), Opc(BO_Comma) { } + + SourceLocation getExprLoc() const LLVM_READONLY { return OpLoc; } + SourceLocation getOperatorLoc() const { return OpLoc; } + void setOperatorLoc(SourceLocation L) { OpLoc = L; } + + Opcode getOpcode() const { return static_cast<Opcode>(Opc); } + void setOpcode(Opcode O) { Opc = O; } + + Expr *getLHS() const { return cast<Expr>(SubExprs[LHS]); } + void setLHS(Expr *E) { SubExprs[LHS] = E; } + Expr *getRHS() const { return cast<Expr>(SubExprs[RHS]); } + void setRHS(Expr *E) { SubExprs[RHS] = E; } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(getLHS()->getLocStart(), getRHS()->getLocEnd()); + } + + /// getOpcodeStr - Turn an Opcode enum value into the punctuation char it + /// corresponds to, e.g. "<<=". + static const char *getOpcodeStr(Opcode Op); + + const char *getOpcodeStr() const { return getOpcodeStr(getOpcode()); } + + /// \brief Retrieve the binary opcode that corresponds to the given + /// overloaded operator. + static Opcode getOverloadedOpcode(OverloadedOperatorKind OO); + + /// \brief Retrieve the overloaded operator kind that corresponds to + /// the given binary opcode. + static OverloadedOperatorKind getOverloadedOperator(Opcode Opc); + + /// predicates to categorize the respective opcodes. + bool isPtrMemOp() const { return Opc == BO_PtrMemD || Opc == BO_PtrMemI; } + bool isMultiplicativeOp() const { return Opc >= BO_Mul && Opc <= BO_Rem; } + static bool isAdditiveOp(Opcode Opc) { return Opc == BO_Add || Opc==BO_Sub; } + bool isAdditiveOp() const { return isAdditiveOp(getOpcode()); } + static bool isShiftOp(Opcode Opc) { return Opc == BO_Shl || Opc == BO_Shr; } + bool isShiftOp() const { return isShiftOp(getOpcode()); } + + static bool isBitwiseOp(Opcode Opc) { return Opc >= BO_And && Opc <= BO_Or; } + bool isBitwiseOp() const { return isBitwiseOp(getOpcode()); } + + static bool isRelationalOp(Opcode Opc) { return Opc >= BO_LT && Opc<=BO_GE; } + bool isRelationalOp() const { return isRelationalOp(getOpcode()); } + + static bool isEqualityOp(Opcode Opc) { return Opc == BO_EQ || Opc == BO_NE; } + bool isEqualityOp() const { return isEqualityOp(getOpcode()); } + + static bool isComparisonOp(Opcode Opc) { return Opc >= BO_LT && Opc<=BO_NE; } + bool isComparisonOp() const { return isComparisonOp(getOpcode()); } + + static bool isLogicalOp(Opcode Opc) { return Opc == BO_LAnd || Opc==BO_LOr; } + bool isLogicalOp() const { return isLogicalOp(getOpcode()); } + + static bool isAssignmentOp(Opcode Opc) { + return Opc >= BO_Assign && Opc <= BO_OrAssign; + } + bool isAssignmentOp() const { return isAssignmentOp(getOpcode()); } + + static bool isCompoundAssignmentOp(Opcode Opc) { + return Opc > BO_Assign && Opc <= BO_OrAssign; + } + bool isCompoundAssignmentOp() const { + return isCompoundAssignmentOp(getOpcode()); + } + static Opcode getOpForCompoundAssignment(Opcode Opc) { + assert(isCompoundAssignmentOp(Opc)); + if (Opc >= BO_AndAssign) + return Opcode(unsigned(Opc) - BO_AndAssign + BO_And); + else + return Opcode(unsigned(Opc) - BO_MulAssign + BO_Mul); + } + + static bool isShiftAssignOp(Opcode Opc) { + return Opc == BO_ShlAssign || Opc == BO_ShrAssign; + } + bool isShiftAssignOp() const { + return isShiftAssignOp(getOpcode()); + } + + static bool classof(const Stmt *S) { + return S->getStmtClass() >= firstBinaryOperatorConstant && + S->getStmtClass() <= lastBinaryOperatorConstant; + } + static bool classof(const BinaryOperator *) { return true; } + + // Iterators + child_range children() { + return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR); + } + +protected: + BinaryOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResTy, + ExprValueKind VK, ExprObjectKind OK, + SourceLocation opLoc, bool dead) + : Expr(CompoundAssignOperatorClass, ResTy, VK, OK, + lhs->isTypeDependent() || rhs->isTypeDependent(), + lhs->isValueDependent() || rhs->isValueDependent(), + (lhs->isInstantiationDependent() || + rhs->isInstantiationDependent()), + (lhs->containsUnexpandedParameterPack() || + rhs->containsUnexpandedParameterPack())), + Opc(opc), OpLoc(opLoc) { + SubExprs[LHS] = lhs; + SubExprs[RHS] = rhs; + } + + BinaryOperator(StmtClass SC, EmptyShell Empty) + : Expr(SC, Empty), Opc(BO_MulAssign) { } +}; + +/// CompoundAssignOperator - For compound assignments (e.g. +=), we keep +/// track of the type the operation is performed in. Due to the semantics of +/// these operators, the operands are promoted, the arithmetic performed, an +/// implicit conversion back to the result type done, then the assignment takes +/// place. This captures the intermediate type which the computation is done +/// in. +class CompoundAssignOperator : public BinaryOperator { + QualType ComputationLHSType; + QualType ComputationResultType; +public: + CompoundAssignOperator(Expr *lhs, Expr *rhs, Opcode opc, QualType ResType, + ExprValueKind VK, ExprObjectKind OK, + QualType CompLHSType, QualType CompResultType, + SourceLocation OpLoc) + : BinaryOperator(lhs, rhs, opc, ResType, VK, OK, OpLoc, true), + ComputationLHSType(CompLHSType), + ComputationResultType(CompResultType) { + assert(isCompoundAssignmentOp() && + "Only should be used for compound assignments"); + } + + /// \brief Build an empty compound assignment operator expression. + explicit CompoundAssignOperator(EmptyShell Empty) + : BinaryOperator(CompoundAssignOperatorClass, Empty) { } + + // The two computation types are the type the LHS is converted + // to for the computation and the type of the result; the two are + // distinct in a few cases (specifically, int+=ptr and ptr-=ptr). + QualType getComputationLHSType() const { return ComputationLHSType; } + void setComputationLHSType(QualType T) { ComputationLHSType = T; } + + QualType getComputationResultType() const { return ComputationResultType; } + void setComputationResultType(QualType T) { ComputationResultType = T; } + + static bool classof(const CompoundAssignOperator *) { return true; } + static bool classof(const Stmt *S) { + return S->getStmtClass() == CompoundAssignOperatorClass; + } +}; + +/// AbstractConditionalOperator - An abstract base class for +/// ConditionalOperator and BinaryConditionalOperator. +class AbstractConditionalOperator : public Expr { + SourceLocation QuestionLoc, ColonLoc; + friend class ASTStmtReader; + +protected: + AbstractConditionalOperator(StmtClass SC, QualType T, + ExprValueKind VK, ExprObjectKind OK, + bool TD, bool VD, bool ID, + bool ContainsUnexpandedParameterPack, + SourceLocation qloc, + SourceLocation cloc) + : Expr(SC, T, VK, OK, TD, VD, ID, ContainsUnexpandedParameterPack), + QuestionLoc(qloc), ColonLoc(cloc) {} + + AbstractConditionalOperator(StmtClass SC, EmptyShell Empty) + : Expr(SC, Empty) { } + +public: + // getCond - Return the expression representing the condition for + // the ?: operator. + Expr *getCond() const; + + // getTrueExpr - Return the subexpression representing the value of + // the expression if the condition evaluates to true. + Expr *getTrueExpr() const; + + // getFalseExpr - Return the subexpression representing the value of + // the expression if the condition evaluates to false. This is + // the same as getRHS. + Expr *getFalseExpr() const; + + SourceLocation getQuestionLoc() const { return QuestionLoc; } + SourceLocation getColonLoc() const { return ColonLoc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ConditionalOperatorClass || + T->getStmtClass() == BinaryConditionalOperatorClass; + } + static bool classof(const AbstractConditionalOperator *) { return true; } +}; + +/// ConditionalOperator - The ?: ternary operator. The GNU "missing +/// middle" extension is a BinaryConditionalOperator. +class ConditionalOperator : public AbstractConditionalOperator { + enum { COND, LHS, RHS, END_EXPR }; + Stmt* SubExprs[END_EXPR]; // Left/Middle/Right hand sides. + + friend class ASTStmtReader; +public: + ConditionalOperator(Expr *cond, SourceLocation QLoc, Expr *lhs, + SourceLocation CLoc, Expr *rhs, + QualType t, ExprValueKind VK, ExprObjectKind OK) + : AbstractConditionalOperator(ConditionalOperatorClass, t, VK, OK, + // FIXME: the type of the conditional operator doesn't + // depend on the type of the conditional, but the standard + // seems to imply that it could. File a bug! + (lhs->isTypeDependent() || rhs->isTypeDependent()), + (cond->isValueDependent() || lhs->isValueDependent() || + rhs->isValueDependent()), + (cond->isInstantiationDependent() || + lhs->isInstantiationDependent() || + rhs->isInstantiationDependent()), + (cond->containsUnexpandedParameterPack() || + lhs->containsUnexpandedParameterPack() || + rhs->containsUnexpandedParameterPack()), + QLoc, CLoc) { + SubExprs[COND] = cond; + SubExprs[LHS] = lhs; + SubExprs[RHS] = rhs; + } + + /// \brief Build an empty conditional operator. + explicit ConditionalOperator(EmptyShell Empty) + : AbstractConditionalOperator(ConditionalOperatorClass, Empty) { } + + // getCond - Return the expression representing the condition for + // the ?: operator. + Expr *getCond() const { return cast<Expr>(SubExprs[COND]); } + + // getTrueExpr - Return the subexpression representing the value of + // the expression if the condition evaluates to true. + Expr *getTrueExpr() const { return cast<Expr>(SubExprs[LHS]); } + + // getFalseExpr - Return the subexpression representing the value of + // the expression if the condition evaluates to false. This is + // the same as getRHS. + Expr *getFalseExpr() const { return cast<Expr>(SubExprs[RHS]); } + + Expr *getLHS() const { return cast<Expr>(SubExprs[LHS]); } + Expr *getRHS() const { return cast<Expr>(SubExprs[RHS]); } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(getCond()->getLocStart(), getRHS()->getLocEnd()); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == ConditionalOperatorClass; + } + static bool classof(const ConditionalOperator *) { return true; } + + // Iterators + child_range children() { + return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR); + } +}; + +/// BinaryConditionalOperator - The GNU extension to the conditional +/// operator which allows the middle operand to be omitted. +/// +/// This is a different expression kind on the assumption that almost +/// every client ends up needing to know that these are different. +class BinaryConditionalOperator : public AbstractConditionalOperator { + enum { COMMON, COND, LHS, RHS, NUM_SUBEXPRS }; + + /// - the common condition/left-hand-side expression, which will be + /// evaluated as the opaque value + /// - the condition, expressed in terms of the opaque value + /// - the left-hand-side, expressed in terms of the opaque value + /// - the right-hand-side + Stmt *SubExprs[NUM_SUBEXPRS]; + OpaqueValueExpr *OpaqueValue; + + friend class ASTStmtReader; +public: + BinaryConditionalOperator(Expr *common, OpaqueValueExpr *opaqueValue, + Expr *cond, Expr *lhs, Expr *rhs, + SourceLocation qloc, SourceLocation cloc, + QualType t, ExprValueKind VK, ExprObjectKind OK) + : AbstractConditionalOperator(BinaryConditionalOperatorClass, t, VK, OK, + (common->isTypeDependent() || rhs->isTypeDependent()), + (common->isValueDependent() || rhs->isValueDependent()), + (common->isInstantiationDependent() || + rhs->isInstantiationDependent()), + (common->containsUnexpandedParameterPack() || + rhs->containsUnexpandedParameterPack()), + qloc, cloc), + OpaqueValue(opaqueValue) { + SubExprs[COMMON] = common; + SubExprs[COND] = cond; + SubExprs[LHS] = lhs; + SubExprs[RHS] = rhs; + assert(OpaqueValue->getSourceExpr() == common && "Wrong opaque value"); + } + + /// \brief Build an empty conditional operator. + explicit BinaryConditionalOperator(EmptyShell Empty) + : AbstractConditionalOperator(BinaryConditionalOperatorClass, Empty) { } + + /// \brief getCommon - Return the common expression, written to the + /// left of the condition. The opaque value will be bound to the + /// result of this expression. + Expr *getCommon() const { return cast<Expr>(SubExprs[COMMON]); } + + /// \brief getOpaqueValue - Return the opaque value placeholder. + OpaqueValueExpr *getOpaqueValue() const { return OpaqueValue; } + + /// \brief getCond - Return the condition expression; this is defined + /// in terms of the opaque value. + Expr *getCond() const { return cast<Expr>(SubExprs[COND]); } + + /// \brief getTrueExpr - Return the subexpression which will be + /// evaluated if the condition evaluates to true; this is defined + /// in terms of the opaque value. + Expr *getTrueExpr() const { + return cast<Expr>(SubExprs[LHS]); + } + + /// \brief getFalseExpr - Return the subexpression which will be + /// evaluated if the condnition evaluates to false; this is + /// defined in terms of the opaque value. + Expr *getFalseExpr() const { + return cast<Expr>(SubExprs[RHS]); + } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(getCommon()->getLocStart(), getFalseExpr()->getLocEnd()); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == BinaryConditionalOperatorClass; + } + static bool classof(const BinaryConditionalOperator *) { return true; } + + // Iterators + child_range children() { + return child_range(SubExprs, SubExprs + NUM_SUBEXPRS); + } +}; + +inline Expr *AbstractConditionalOperator::getCond() const { + if (const ConditionalOperator *co = dyn_cast<ConditionalOperator>(this)) + return co->getCond(); + return cast<BinaryConditionalOperator>(this)->getCond(); +} + +inline Expr *AbstractConditionalOperator::getTrueExpr() const { + if (const ConditionalOperator *co = dyn_cast<ConditionalOperator>(this)) + return co->getTrueExpr(); + return cast<BinaryConditionalOperator>(this)->getTrueExpr(); +} + +inline Expr *AbstractConditionalOperator::getFalseExpr() const { + if (const ConditionalOperator *co = dyn_cast<ConditionalOperator>(this)) + return co->getFalseExpr(); + return cast<BinaryConditionalOperator>(this)->getFalseExpr(); +} + +/// AddrLabelExpr - The GNU address of label extension, representing &&label. +class AddrLabelExpr : public Expr { + SourceLocation AmpAmpLoc, LabelLoc; + LabelDecl *Label; +public: + AddrLabelExpr(SourceLocation AALoc, SourceLocation LLoc, LabelDecl *L, + QualType t) + : Expr(AddrLabelExprClass, t, VK_RValue, OK_Ordinary, false, false, false, + false), + AmpAmpLoc(AALoc), LabelLoc(LLoc), Label(L) {} + + /// \brief Build an empty address of a label expression. + explicit AddrLabelExpr(EmptyShell Empty) + : Expr(AddrLabelExprClass, Empty) { } + + SourceLocation getAmpAmpLoc() const { return AmpAmpLoc; } + void setAmpAmpLoc(SourceLocation L) { AmpAmpLoc = L; } + SourceLocation getLabelLoc() const { return LabelLoc; } + void setLabelLoc(SourceLocation L) { LabelLoc = L; } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(AmpAmpLoc, LabelLoc); + } + + LabelDecl *getLabel() const { return Label; } + void setLabel(LabelDecl *L) { Label = L; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == AddrLabelExprClass; + } + static bool classof(const AddrLabelExpr *) { return true; } + + // Iterators + child_range children() { return child_range(); } +}; + +/// StmtExpr - This is the GNU Statement Expression extension: ({int X=4; X;}). +/// The StmtExpr contains a single CompoundStmt node, which it evaluates and +/// takes the value of the last subexpression. +/// +/// A StmtExpr is always an r-value; values "returned" out of a +/// StmtExpr will be copied. +class StmtExpr : public Expr { + Stmt *SubStmt; + SourceLocation LParenLoc, RParenLoc; +public: + // FIXME: Does type-dependence need to be computed differently? + // FIXME: Do we need to compute instantiation instantiation-dependence for + // statements? (ugh!) + StmtExpr(CompoundStmt *substmt, QualType T, + SourceLocation lp, SourceLocation rp) : + Expr(StmtExprClass, T, VK_RValue, OK_Ordinary, + T->isDependentType(), false, false, false), + SubStmt(substmt), LParenLoc(lp), RParenLoc(rp) { } + + /// \brief Build an empty statement expression. + explicit StmtExpr(EmptyShell Empty) : Expr(StmtExprClass, Empty) { } + + CompoundStmt *getSubStmt() { return cast<CompoundStmt>(SubStmt); } + const CompoundStmt *getSubStmt() const { return cast<CompoundStmt>(SubStmt); } + void setSubStmt(CompoundStmt *S) { SubStmt = S; } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(LParenLoc, RParenLoc); + } + + SourceLocation getLParenLoc() const { return LParenLoc; } + void setLParenLoc(SourceLocation L) { LParenLoc = L; } + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == StmtExprClass; + } + static bool classof(const StmtExpr *) { return true; } + + // Iterators + child_range children() { return child_range(&SubStmt, &SubStmt+1); } +}; + + +/// ShuffleVectorExpr - clang-specific builtin-in function +/// __builtin_shufflevector. +/// This AST node represents a operator that does a constant +/// shuffle, similar to LLVM's shufflevector instruction. It takes +/// two vectors and a variable number of constant indices, +/// and returns the appropriately shuffled vector. +class ShuffleVectorExpr : public Expr { + SourceLocation BuiltinLoc, RParenLoc; + + // SubExprs - the list of values passed to the __builtin_shufflevector + // function. The first two are vectors, and the rest are constant + // indices. The number of values in this list is always + // 2+the number of indices in the vector type. + Stmt **SubExprs; + unsigned NumExprs; + +public: + ShuffleVectorExpr(ASTContext &C, Expr **args, unsigned nexpr, + QualType Type, SourceLocation BLoc, + SourceLocation RP); + + /// \brief Build an empty vector-shuffle expression. + explicit ShuffleVectorExpr(EmptyShell Empty) + : Expr(ShuffleVectorExprClass, Empty), SubExprs(0) { } + + SourceLocation getBuiltinLoc() const { return BuiltinLoc; } + void setBuiltinLoc(SourceLocation L) { BuiltinLoc = L; } + + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(BuiltinLoc, RParenLoc); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == ShuffleVectorExprClass; + } + static bool classof(const ShuffleVectorExpr *) { return true; } + + /// getNumSubExprs - Return the size of the SubExprs array. This includes the + /// constant expression, the actual arguments passed in, and the function + /// pointers. + unsigned getNumSubExprs() const { return NumExprs; } + + /// \brief Retrieve the array of expressions. + Expr **getSubExprs() { return reinterpret_cast<Expr **>(SubExprs); } + + /// getExpr - Return the Expr at the specified index. + Expr *getExpr(unsigned Index) { + assert((Index < NumExprs) && "Arg access out of range!"); + return cast<Expr>(SubExprs[Index]); + } + const Expr *getExpr(unsigned Index) const { + assert((Index < NumExprs) && "Arg access out of range!"); + return cast<Expr>(SubExprs[Index]); + } + + void setExprs(ASTContext &C, Expr ** Exprs, unsigned NumExprs); + + unsigned getShuffleMaskIdx(ASTContext &Ctx, unsigned N) { + assert((N < NumExprs - 2) && "Shuffle idx out of range!"); + return getExpr(N+2)->EvaluateKnownConstInt(Ctx).getZExtValue(); + } + + // Iterators + child_range children() { + return child_range(&SubExprs[0], &SubExprs[0]+NumExprs); + } +}; + +/// ChooseExpr - GNU builtin-in function __builtin_choose_expr. +/// This AST node is similar to the conditional operator (?:) in C, with +/// the following exceptions: +/// - the test expression must be a integer constant expression. +/// - the expression returned acts like the chosen subexpression in every +/// visible way: the type is the same as that of the chosen subexpression, +/// and all predicates (whether it's an l-value, whether it's an integer +/// constant expression, etc.) return the same result as for the chosen +/// sub-expression. +class ChooseExpr : public Expr { + enum { COND, LHS, RHS, END_EXPR }; + Stmt* SubExprs[END_EXPR]; // Left/Middle/Right hand sides. + SourceLocation BuiltinLoc, RParenLoc; +public: + ChooseExpr(SourceLocation BLoc, Expr *cond, Expr *lhs, Expr *rhs, + QualType t, ExprValueKind VK, ExprObjectKind OK, + SourceLocation RP, bool TypeDependent, bool ValueDependent) + : Expr(ChooseExprClass, t, VK, OK, TypeDependent, ValueDependent, + (cond->isInstantiationDependent() || + lhs->isInstantiationDependent() || + rhs->isInstantiationDependent()), + (cond->containsUnexpandedParameterPack() || + lhs->containsUnexpandedParameterPack() || + rhs->containsUnexpandedParameterPack())), + BuiltinLoc(BLoc), RParenLoc(RP) { + SubExprs[COND] = cond; + SubExprs[LHS] = lhs; + SubExprs[RHS] = rhs; + } + + /// \brief Build an empty __builtin_choose_expr. + explicit ChooseExpr(EmptyShell Empty) : Expr(ChooseExprClass, Empty) { } + + /// isConditionTrue - Return whether the condition is true (i.e. not + /// equal to zero). + bool isConditionTrue(const ASTContext &C) const; + + /// getChosenSubExpr - Return the subexpression chosen according to the + /// condition. + Expr *getChosenSubExpr(const ASTContext &C) const { + return isConditionTrue(C) ? getLHS() : getRHS(); + } + + Expr *getCond() const { return cast<Expr>(SubExprs[COND]); } + void setCond(Expr *E) { SubExprs[COND] = E; } + Expr *getLHS() const { return cast<Expr>(SubExprs[LHS]); } + void setLHS(Expr *E) { SubExprs[LHS] = E; } + Expr *getRHS() const { return cast<Expr>(SubExprs[RHS]); } + void setRHS(Expr *E) { SubExprs[RHS] = E; } + + SourceLocation getBuiltinLoc() const { return BuiltinLoc; } + void setBuiltinLoc(SourceLocation L) { BuiltinLoc = L; } + + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(BuiltinLoc, RParenLoc); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == ChooseExprClass; + } + static bool classof(const ChooseExpr *) { return true; } + + // Iterators + child_range children() { + return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR); + } +}; + +/// GNUNullExpr - Implements the GNU __null extension, which is a name +/// for a null pointer constant that has integral type (e.g., int or +/// long) and is the same size and alignment as a pointer. The __null +/// extension is typically only used by system headers, which define +/// NULL as __null in C++ rather than using 0 (which is an integer +/// that may not match the size of a pointer). +class GNUNullExpr : public Expr { + /// TokenLoc - The location of the __null keyword. + SourceLocation TokenLoc; + +public: + GNUNullExpr(QualType Ty, SourceLocation Loc) + : Expr(GNUNullExprClass, Ty, VK_RValue, OK_Ordinary, false, false, false, + false), + TokenLoc(Loc) { } + + /// \brief Build an empty GNU __null expression. + explicit GNUNullExpr(EmptyShell Empty) : Expr(GNUNullExprClass, Empty) { } + + /// getTokenLocation - The location of the __null token. + SourceLocation getTokenLocation() const { return TokenLoc; } + void setTokenLocation(SourceLocation L) { TokenLoc = L; } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(TokenLoc); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == GNUNullExprClass; + } + static bool classof(const GNUNullExpr *) { return true; } + + // Iterators + child_range children() { return child_range(); } +}; + +/// VAArgExpr, used for the builtin function __builtin_va_arg. +class VAArgExpr : public Expr { + Stmt *Val; + TypeSourceInfo *TInfo; + SourceLocation BuiltinLoc, RParenLoc; +public: + VAArgExpr(SourceLocation BLoc, Expr* e, TypeSourceInfo *TInfo, + SourceLocation RPLoc, QualType t) + : Expr(VAArgExprClass, t, VK_RValue, OK_Ordinary, + t->isDependentType(), false, + (TInfo->getType()->isInstantiationDependentType() || + e->isInstantiationDependent()), + (TInfo->getType()->containsUnexpandedParameterPack() || + e->containsUnexpandedParameterPack())), + Val(e), TInfo(TInfo), + BuiltinLoc(BLoc), + RParenLoc(RPLoc) { } + + /// \brief Create an empty __builtin_va_arg expression. + explicit VAArgExpr(EmptyShell Empty) : Expr(VAArgExprClass, Empty) { } + + const Expr *getSubExpr() const { return cast<Expr>(Val); } + Expr *getSubExpr() { return cast<Expr>(Val); } + void setSubExpr(Expr *E) { Val = E; } + + TypeSourceInfo *getWrittenTypeInfo() const { return TInfo; } + void setWrittenTypeInfo(TypeSourceInfo *TI) { TInfo = TI; } + + SourceLocation getBuiltinLoc() const { return BuiltinLoc; } + void setBuiltinLoc(SourceLocation L) { BuiltinLoc = L; } + + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(BuiltinLoc, RParenLoc); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == VAArgExprClass; + } + static bool classof(const VAArgExpr *) { return true; } + + // Iterators + child_range children() { return child_range(&Val, &Val+1); } +}; + +/// @brief Describes an C or C++ initializer list. +/// +/// InitListExpr describes an initializer list, which can be used to +/// initialize objects of different types, including +/// struct/class/union types, arrays, and vectors. For example: +/// +/// @code +/// struct foo x = { 1, { 2, 3 } }; +/// @endcode +/// +/// Prior to semantic analysis, an initializer list will represent the +/// initializer list as written by the user, but will have the +/// placeholder type "void". This initializer list is called the +/// syntactic form of the initializer, and may contain C99 designated +/// initializers (represented as DesignatedInitExprs), initializations +/// of subobject members without explicit braces, and so on. Clients +/// interested in the original syntax of the initializer list should +/// use the syntactic form of the initializer list. +/// +/// After semantic analysis, the initializer list will represent the +/// semantic form of the initializer, where the initializations of all +/// subobjects are made explicit with nested InitListExpr nodes and +/// C99 designators have been eliminated by placing the designated +/// initializations into the subobject they initialize. Additionally, +/// any "holes" in the initialization, where no initializer has been +/// specified for a particular subobject, will be replaced with +/// implicitly-generated ImplicitValueInitExpr expressions that +/// value-initialize the subobjects. Note, however, that the +/// initializer lists may still have fewer initializers than there are +/// elements to initialize within the object. +/// +/// Given the semantic form of the initializer list, one can retrieve +/// the original syntactic form of that initializer list (if it +/// exists) using getSyntacticForm(). Since many initializer lists +/// have the same syntactic and semantic forms, getSyntacticForm() may +/// return NULL, indicating that the current initializer list also +/// serves as its syntactic form. +class InitListExpr : public Expr { + // FIXME: Eliminate this vector in favor of ASTContext allocation + typedef ASTVector<Stmt *> InitExprsTy; + InitExprsTy InitExprs; + SourceLocation LBraceLoc, RBraceLoc; + + /// Contains the initializer list that describes the syntactic form + /// written in the source code. + InitListExpr *SyntacticForm; + + /// \brief Either: + /// If this initializer list initializes an array with more elements than + /// there are initializers in the list, specifies an expression to be used + /// for value initialization of the rest of the elements. + /// Or + /// If this initializer list initializes a union, specifies which + /// field within the union will be initialized. + llvm::PointerUnion<Expr *, FieldDecl *> ArrayFillerOrUnionFieldInit; + +public: + InitListExpr(ASTContext &C, SourceLocation lbraceloc, + Expr **initexprs, unsigned numinits, + SourceLocation rbraceloc); + + /// \brief Build an empty initializer list. + explicit InitListExpr(ASTContext &C, EmptyShell Empty) + : Expr(InitListExprClass, Empty), InitExprs(C) { } + + unsigned getNumInits() const { return InitExprs.size(); } + + /// \brief Retrieve the set of initializers. + Expr **getInits() { return reinterpret_cast<Expr **>(InitExprs.data()); } + + const Expr *getInit(unsigned Init) const { + assert(Init < getNumInits() && "Initializer access out of range!"); + return cast_or_null<Expr>(InitExprs[Init]); + } + + Expr *getInit(unsigned Init) { + assert(Init < getNumInits() && "Initializer access out of range!"); + return cast_or_null<Expr>(InitExprs[Init]); + } + + void setInit(unsigned Init, Expr *expr) { + assert(Init < getNumInits() && "Initializer access out of range!"); + InitExprs[Init] = expr; + } + + /// \brief Reserve space for some number of initializers. + void reserveInits(ASTContext &C, unsigned NumInits); + + /// @brief Specify the number of initializers + /// + /// If there are more than @p NumInits initializers, the remaining + /// initializers will be destroyed. If there are fewer than @p + /// NumInits initializers, NULL expressions will be added for the + /// unknown initializers. + void resizeInits(ASTContext &Context, unsigned NumInits); + + /// @brief Updates the initializer at index @p Init with the new + /// expression @p expr, and returns the old expression at that + /// location. + /// + /// When @p Init is out of range for this initializer list, the + /// initializer list will be extended with NULL expressions to + /// accommodate the new entry. + Expr *updateInit(ASTContext &C, unsigned Init, Expr *expr); + + /// \brief If this initializer list initializes an array with more elements + /// than there are initializers in the list, specifies an expression to be + /// used for value initialization of the rest of the elements. + Expr *getArrayFiller() { + return ArrayFillerOrUnionFieldInit.dyn_cast<Expr *>(); + } + const Expr *getArrayFiller() const { + return const_cast<InitListExpr *>(this)->getArrayFiller(); + } + void setArrayFiller(Expr *filler); + + /// \brief Return true if this is an array initializer and its array "filler" + /// has been set. + bool hasArrayFiller() const { return getArrayFiller(); } + + /// \brief If this initializes a union, specifies which field in the + /// union to initialize. + /// + /// Typically, this field is the first named field within the + /// union. However, a designated initializer can specify the + /// initialization of a different field within the union. + FieldDecl *getInitializedFieldInUnion() { + return ArrayFillerOrUnionFieldInit.dyn_cast<FieldDecl *>(); + } + const FieldDecl *getInitializedFieldInUnion() const { + return const_cast<InitListExpr *>(this)->getInitializedFieldInUnion(); + } + void setInitializedFieldInUnion(FieldDecl *FD) { + ArrayFillerOrUnionFieldInit = FD; + } + + // Explicit InitListExpr's originate from source code (and have valid source + // locations). Implicit InitListExpr's are created by the semantic analyzer. + bool isExplicit() { + return LBraceLoc.isValid() && RBraceLoc.isValid(); + } + + // Is this an initializer for an array of characters, initialized by a string + // literal or an @encode? + bool isStringLiteralInit() const; + + SourceLocation getLBraceLoc() const { return LBraceLoc; } + void setLBraceLoc(SourceLocation Loc) { LBraceLoc = Loc; } + SourceLocation getRBraceLoc() const { return RBraceLoc; } + void setRBraceLoc(SourceLocation Loc) { RBraceLoc = Loc; } + + /// @brief Retrieve the initializer list that describes the + /// syntactic form of the initializer. + /// + /// + InitListExpr *getSyntacticForm() const { return SyntacticForm; } + void setSyntacticForm(InitListExpr *Init) { SyntacticForm = Init; } + + bool hadArrayRangeDesignator() const { + return InitListExprBits.HadArrayRangeDesignator != 0; + } + void sawArrayRangeDesignator(bool ARD = true) { + InitListExprBits.HadArrayRangeDesignator = ARD; + } + + bool initializesStdInitializerList() const { + return InitListExprBits.InitializesStdInitializerList != 0; + } + void setInitializesStdInitializerList(bool ISIL = true) { + InitListExprBits.InitializesStdInitializerList = ISIL; + } + + SourceRange getSourceRange() const LLVM_READONLY; + + static bool classof(const Stmt *T) { + return T->getStmtClass() == InitListExprClass; + } + static bool classof(const InitListExpr *) { return true; } + + // Iterators + child_range children() { + if (InitExprs.empty()) return child_range(); + return child_range(&InitExprs[0], &InitExprs[0] + InitExprs.size()); + } + + typedef InitExprsTy::iterator iterator; + typedef InitExprsTy::const_iterator const_iterator; + typedef InitExprsTy::reverse_iterator reverse_iterator; + typedef InitExprsTy::const_reverse_iterator const_reverse_iterator; + + iterator begin() { return InitExprs.begin(); } + const_iterator begin() const { return InitExprs.begin(); } + iterator end() { return InitExprs.end(); } + const_iterator end() const { return InitExprs.end(); } + reverse_iterator rbegin() { return InitExprs.rbegin(); } + const_reverse_iterator rbegin() const { return InitExprs.rbegin(); } + reverse_iterator rend() { return InitExprs.rend(); } + const_reverse_iterator rend() const { return InitExprs.rend(); } + + friend class ASTStmtReader; + friend class ASTStmtWriter; +}; + +/// @brief Represents a C99 designated initializer expression. +/// +/// A designated initializer expression (C99 6.7.8) contains one or +/// more designators (which can be field designators, array +/// designators, or GNU array-range designators) followed by an +/// expression that initializes the field or element(s) that the +/// designators refer to. For example, given: +/// +/// @code +/// struct point { +/// double x; +/// double y; +/// }; +/// struct point ptarray[10] = { [2].y = 1.0, [2].x = 2.0, [0].x = 1.0 }; +/// @endcode +/// +/// The InitListExpr contains three DesignatedInitExprs, the first of +/// which covers @c [2].y=1.0. This DesignatedInitExpr will have two +/// designators, one array designator for @c [2] followed by one field +/// designator for @c .y. The initalization expression will be 1.0. +class DesignatedInitExpr : public Expr { +public: + /// \brief Forward declaration of the Designator class. + class Designator; + +private: + /// The location of the '=' or ':' prior to the actual initializer + /// expression. + SourceLocation EqualOrColonLoc; + + /// Whether this designated initializer used the GNU deprecated + /// syntax rather than the C99 '=' syntax. + bool GNUSyntax : 1; + + /// The number of designators in this initializer expression. + unsigned NumDesignators : 15; + + /// The number of subexpressions of this initializer expression, + /// which contains both the initializer and any additional + /// expressions used by array and array-range designators. + unsigned NumSubExprs : 16; + + /// \brief The designators in this designated initialization + /// expression. + Designator *Designators; + + + DesignatedInitExpr(ASTContext &C, QualType Ty, unsigned NumDesignators, + const Designator *Designators, + SourceLocation EqualOrColonLoc, bool GNUSyntax, + Expr **IndexExprs, unsigned NumIndexExprs, + Expr *Init); + + explicit DesignatedInitExpr(unsigned NumSubExprs) + : Expr(DesignatedInitExprClass, EmptyShell()), + NumDesignators(0), NumSubExprs(NumSubExprs), Designators(0) { } + +public: + /// A field designator, e.g., ".x". + struct FieldDesignator { + /// Refers to the field that is being initialized. The low bit + /// of this field determines whether this is actually a pointer + /// to an IdentifierInfo (if 1) or a FieldDecl (if 0). When + /// initially constructed, a field designator will store an + /// IdentifierInfo*. After semantic analysis has resolved that + /// name, the field designator will instead store a FieldDecl*. + uintptr_t NameOrField; + + /// The location of the '.' in the designated initializer. + unsigned DotLoc; + + /// The location of the field name in the designated initializer. + unsigned FieldLoc; + }; + + /// An array or GNU array-range designator, e.g., "[9]" or "[10..15]". + struct ArrayOrRangeDesignator { + /// Location of the first index expression within the designated + /// initializer expression's list of subexpressions. + unsigned Index; + /// The location of the '[' starting the array range designator. + unsigned LBracketLoc; + /// The location of the ellipsis separating the start and end + /// indices. Only valid for GNU array-range designators. + unsigned EllipsisLoc; + /// The location of the ']' terminating the array range designator. + unsigned RBracketLoc; + }; + + /// @brief Represents a single C99 designator. + /// + /// @todo This class is infuriatingly similar to clang::Designator, + /// but minor differences (storing indices vs. storing pointers) + /// keep us from reusing it. Try harder, later, to rectify these + /// differences. + class Designator { + /// @brief The kind of designator this describes. + enum { + FieldDesignator, + ArrayDesignator, + ArrayRangeDesignator + } Kind; + + union { + /// A field designator, e.g., ".x". + struct FieldDesignator Field; + /// An array or GNU array-range designator, e.g., "[9]" or "[10..15]". + struct ArrayOrRangeDesignator ArrayOrRange; + }; + friend class DesignatedInitExpr; + + public: + Designator() {} + + /// @brief Initializes a field designator. + Designator(const IdentifierInfo *FieldName, SourceLocation DotLoc, + SourceLocation FieldLoc) + : Kind(FieldDesignator) { + Field.NameOrField = reinterpret_cast<uintptr_t>(FieldName) | 0x01; + Field.DotLoc = DotLoc.getRawEncoding(); + Field.FieldLoc = FieldLoc.getRawEncoding(); + } + + /// @brief Initializes an array designator. + Designator(unsigned Index, SourceLocation LBracketLoc, + SourceLocation RBracketLoc) + : Kind(ArrayDesignator) { + ArrayOrRange.Index = Index; + ArrayOrRange.LBracketLoc = LBracketLoc.getRawEncoding(); + ArrayOrRange.EllipsisLoc = SourceLocation().getRawEncoding(); + ArrayOrRange.RBracketLoc = RBracketLoc.getRawEncoding(); + } + + /// @brief Initializes a GNU array-range designator. + Designator(unsigned Index, SourceLocation LBracketLoc, + SourceLocation EllipsisLoc, SourceLocation RBracketLoc) + : Kind(ArrayRangeDesignator) { + ArrayOrRange.Index = Index; + ArrayOrRange.LBracketLoc = LBracketLoc.getRawEncoding(); + ArrayOrRange.EllipsisLoc = EllipsisLoc.getRawEncoding(); + ArrayOrRange.RBracketLoc = RBracketLoc.getRawEncoding(); + } + + bool isFieldDesignator() const { return Kind == FieldDesignator; } + bool isArrayDesignator() const { return Kind == ArrayDesignator; } + bool isArrayRangeDesignator() const { return Kind == ArrayRangeDesignator; } + + IdentifierInfo *getFieldName() const; + + FieldDecl *getField() const { + assert(Kind == FieldDesignator && "Only valid on a field designator"); + if (Field.NameOrField & 0x01) + return 0; + else + return reinterpret_cast<FieldDecl *>(Field.NameOrField); + } + + void setField(FieldDecl *FD) { + assert(Kind == FieldDesignator && "Only valid on a field designator"); + Field.NameOrField = reinterpret_cast<uintptr_t>(FD); + } + + SourceLocation getDotLoc() const { + assert(Kind == FieldDesignator && "Only valid on a field designator"); + return SourceLocation::getFromRawEncoding(Field.DotLoc); + } + + SourceLocation getFieldLoc() const { + assert(Kind == FieldDesignator && "Only valid on a field designator"); + return SourceLocation::getFromRawEncoding(Field.FieldLoc); + } + + SourceLocation getLBracketLoc() const { + assert((Kind == ArrayDesignator || Kind == ArrayRangeDesignator) && + "Only valid on an array or array-range designator"); + return SourceLocation::getFromRawEncoding(ArrayOrRange.LBracketLoc); + } + + SourceLocation getRBracketLoc() const { + assert((Kind == ArrayDesignator || Kind == ArrayRangeDesignator) && + "Only valid on an array or array-range designator"); + return SourceLocation::getFromRawEncoding(ArrayOrRange.RBracketLoc); + } + + SourceLocation getEllipsisLoc() const { + assert(Kind == ArrayRangeDesignator && + "Only valid on an array-range designator"); + return SourceLocation::getFromRawEncoding(ArrayOrRange.EllipsisLoc); + } + + unsigned getFirstExprIndex() const { + assert((Kind == ArrayDesignator || Kind == ArrayRangeDesignator) && + "Only valid on an array or array-range designator"); + return ArrayOrRange.Index; + } + + SourceLocation getStartLocation() const { + if (Kind == FieldDesignator) + return getDotLoc().isInvalid()? getFieldLoc() : getDotLoc(); + else + return getLBracketLoc(); + } + SourceLocation getEndLocation() const { + return Kind == FieldDesignator ? getFieldLoc() : getRBracketLoc(); + } + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(getStartLocation(), getEndLocation()); + } + }; + + static DesignatedInitExpr *Create(ASTContext &C, Designator *Designators, + unsigned NumDesignators, + Expr **IndexExprs, unsigned NumIndexExprs, + SourceLocation EqualOrColonLoc, + bool GNUSyntax, Expr *Init); + + static DesignatedInitExpr *CreateEmpty(ASTContext &C, unsigned NumIndexExprs); + + /// @brief Returns the number of designators in this initializer. + unsigned size() const { return NumDesignators; } + + // Iterator access to the designators. + typedef Designator *designators_iterator; + designators_iterator designators_begin() { return Designators; } + designators_iterator designators_end() { + return Designators + NumDesignators; + } + + typedef const Designator *const_designators_iterator; + const_designators_iterator designators_begin() const { return Designators; } + const_designators_iterator designators_end() const { + return Designators + NumDesignators; + } + + typedef std::reverse_iterator<designators_iterator> + reverse_designators_iterator; + reverse_designators_iterator designators_rbegin() { + return reverse_designators_iterator(designators_end()); + } + reverse_designators_iterator designators_rend() { + return reverse_designators_iterator(designators_begin()); + } + + typedef std::reverse_iterator<const_designators_iterator> + const_reverse_designators_iterator; + const_reverse_designators_iterator designators_rbegin() const { + return const_reverse_designators_iterator(designators_end()); + } + const_reverse_designators_iterator designators_rend() const { + return const_reverse_designators_iterator(designators_begin()); + } + + Designator *getDesignator(unsigned Idx) { return &designators_begin()[Idx]; } + + void setDesignators(ASTContext &C, const Designator *Desigs, + unsigned NumDesigs); + + Expr *getArrayIndex(const Designator& D); + Expr *getArrayRangeStart(const Designator& D); + Expr *getArrayRangeEnd(const Designator& D); + + /// @brief Retrieve the location of the '=' that precedes the + /// initializer value itself, if present. + SourceLocation getEqualOrColonLoc() const { return EqualOrColonLoc; } + void setEqualOrColonLoc(SourceLocation L) { EqualOrColonLoc = L; } + + /// @brief Determines whether this designated initializer used the + /// deprecated GNU syntax for designated initializers. + bool usesGNUSyntax() const { return GNUSyntax; } + void setGNUSyntax(bool GNU) { GNUSyntax = GNU; } + + /// @brief Retrieve the initializer value. + Expr *getInit() const { + return cast<Expr>(*const_cast<DesignatedInitExpr*>(this)->child_begin()); + } + + void setInit(Expr *init) { + *child_begin() = init; + } + + /// \brief Retrieve the total number of subexpressions in this + /// designated initializer expression, including the actual + /// initialized value and any expressions that occur within array + /// and array-range designators. + unsigned getNumSubExprs() const { return NumSubExprs; } + + Expr *getSubExpr(unsigned Idx) { + assert(Idx < NumSubExprs && "Subscript out of range"); + char* Ptr = static_cast<char*>(static_cast<void *>(this)); + Ptr += sizeof(DesignatedInitExpr); + return reinterpret_cast<Expr**>(reinterpret_cast<void**>(Ptr))[Idx]; + } + + void setSubExpr(unsigned Idx, Expr *E) { + assert(Idx < NumSubExprs && "Subscript out of range"); + char* Ptr = static_cast<char*>(static_cast<void *>(this)); + Ptr += sizeof(DesignatedInitExpr); + reinterpret_cast<Expr**>(reinterpret_cast<void**>(Ptr))[Idx] = E; + } + + /// \brief Replaces the designator at index @p Idx with the series + /// of designators in [First, Last). + void ExpandDesignator(ASTContext &C, unsigned Idx, const Designator *First, + const Designator *Last); + + SourceRange getDesignatorsSourceRange() const; + + SourceRange getSourceRange() const LLVM_READONLY; + + static bool classof(const Stmt *T) { + return T->getStmtClass() == DesignatedInitExprClass; + } + static bool classof(const DesignatedInitExpr *) { return true; } + + // Iterators + child_range children() { + Stmt **begin = reinterpret_cast<Stmt**>(this + 1); + return child_range(begin, begin + NumSubExprs); + } +}; + +/// \brief Represents an implicitly-generated value initialization of +/// an object of a given type. +/// +/// Implicit value initializations occur within semantic initializer +/// list expressions (InitListExpr) as placeholders for subobject +/// initializations not explicitly specified by the user. +/// +/// \see InitListExpr +class ImplicitValueInitExpr : public Expr { +public: + explicit ImplicitValueInitExpr(QualType ty) + : Expr(ImplicitValueInitExprClass, ty, VK_RValue, OK_Ordinary, + false, false, ty->isInstantiationDependentType(), false) { } + + /// \brief Construct an empty implicit value initialization. + explicit ImplicitValueInitExpr(EmptyShell Empty) + : Expr(ImplicitValueInitExprClass, Empty) { } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ImplicitValueInitExprClass; + } + static bool classof(const ImplicitValueInitExpr *) { return true; } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(); + } + + // Iterators + child_range children() { return child_range(); } +}; + + +class ParenListExpr : public Expr { + Stmt **Exprs; + unsigned NumExprs; + SourceLocation LParenLoc, RParenLoc; + +public: + ParenListExpr(ASTContext& C, SourceLocation lparenloc, Expr **exprs, + unsigned numexprs, SourceLocation rparenloc); + + /// \brief Build an empty paren list. + explicit ParenListExpr(EmptyShell Empty) : Expr(ParenListExprClass, Empty) { } + + unsigned getNumExprs() const { return NumExprs; } + + const Expr* getExpr(unsigned Init) const { + assert(Init < getNumExprs() && "Initializer access out of range!"); + return cast_or_null<Expr>(Exprs[Init]); + } + + Expr* getExpr(unsigned Init) { + assert(Init < getNumExprs() && "Initializer access out of range!"); + return cast_or_null<Expr>(Exprs[Init]); + } + + Expr **getExprs() { return reinterpret_cast<Expr **>(Exprs); } + + SourceLocation getLParenLoc() const { return LParenLoc; } + SourceLocation getRParenLoc() const { return RParenLoc; } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(LParenLoc, RParenLoc); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == ParenListExprClass; + } + static bool classof(const ParenListExpr *) { return true; } + + // Iterators + child_range children() { + return child_range(&Exprs[0], &Exprs[0]+NumExprs); + } + + friend class ASTStmtReader; + friend class ASTStmtWriter; +}; + + +/// \brief Represents a C11 generic selection. +/// +/// A generic selection (C11 6.5.1.1) contains an unevaluated controlling +/// expression, followed by one or more generic associations. Each generic +/// association specifies a type name and an expression, or "default" and an +/// expression (in which case it is known as a default generic association). +/// The type and value of the generic selection are identical to those of its +/// result expression, which is defined as the expression in the generic +/// association with a type name that is compatible with the type of the +/// controlling expression, or the expression in the default generic association +/// if no types are compatible. For example: +/// +/// @code +/// _Generic(X, double: 1, float: 2, default: 3) +/// @endcode +/// +/// The above expression evaluates to 1 if 1.0 is substituted for X, 2 if 1.0f +/// or 3 if "hello". +/// +/// As an extension, generic selections are allowed in C++, where the following +/// additional semantics apply: +/// +/// Any generic selection whose controlling expression is type-dependent or +/// which names a dependent type in its association list is result-dependent, +/// which means that the choice of result expression is dependent. +/// Result-dependent generic associations are both type- and value-dependent. +class GenericSelectionExpr : public Expr { + enum { CONTROLLING, END_EXPR }; + TypeSourceInfo **AssocTypes; + Stmt **SubExprs; + unsigned NumAssocs, ResultIndex; + SourceLocation GenericLoc, DefaultLoc, RParenLoc; + +public: + GenericSelectionExpr(ASTContext &Context, + SourceLocation GenericLoc, Expr *ControllingExpr, + TypeSourceInfo **AssocTypes, Expr **AssocExprs, + unsigned NumAssocs, SourceLocation DefaultLoc, + SourceLocation RParenLoc, + bool ContainsUnexpandedParameterPack, + unsigned ResultIndex); + + /// This constructor is used in the result-dependent case. + GenericSelectionExpr(ASTContext &Context, + SourceLocation GenericLoc, Expr *ControllingExpr, + TypeSourceInfo **AssocTypes, Expr **AssocExprs, + unsigned NumAssocs, SourceLocation DefaultLoc, + SourceLocation RParenLoc, + bool ContainsUnexpandedParameterPack); + + explicit GenericSelectionExpr(EmptyShell Empty) + : Expr(GenericSelectionExprClass, Empty) { } + + unsigned getNumAssocs() const { return NumAssocs; } + + SourceLocation getGenericLoc() const { return GenericLoc; } + SourceLocation getDefaultLoc() const { return DefaultLoc; } + SourceLocation getRParenLoc() const { return RParenLoc; } + + const Expr *getAssocExpr(unsigned i) const { + return cast<Expr>(SubExprs[END_EXPR+i]); + } + Expr *getAssocExpr(unsigned i) { return cast<Expr>(SubExprs[END_EXPR+i]); } + + const TypeSourceInfo *getAssocTypeSourceInfo(unsigned i) const { + return AssocTypes[i]; + } + TypeSourceInfo *getAssocTypeSourceInfo(unsigned i) { return AssocTypes[i]; } + + QualType getAssocType(unsigned i) const { + if (const TypeSourceInfo *TS = getAssocTypeSourceInfo(i)) + return TS->getType(); + else + return QualType(); + } + + const Expr *getControllingExpr() const { + return cast<Expr>(SubExprs[CONTROLLING]); + } + Expr *getControllingExpr() { return cast<Expr>(SubExprs[CONTROLLING]); } + + /// Whether this generic selection is result-dependent. + bool isResultDependent() const { return ResultIndex == -1U; } + + /// The zero-based index of the result expression's generic association in + /// the generic selection's association list. Defined only if the + /// generic selection is not result-dependent. + unsigned getResultIndex() const { + assert(!isResultDependent() && "Generic selection is result-dependent"); + return ResultIndex; + } + + /// The generic selection's result expression. Defined only if the + /// generic selection is not result-dependent. + const Expr *getResultExpr() const { return getAssocExpr(getResultIndex()); } + Expr *getResultExpr() { return getAssocExpr(getResultIndex()); } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(GenericLoc, RParenLoc); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == GenericSelectionExprClass; + } + static bool classof(const GenericSelectionExpr *) { return true; } + + child_range children() { + return child_range(SubExprs, SubExprs+END_EXPR+NumAssocs); + } + + friend class ASTStmtReader; +}; + +//===----------------------------------------------------------------------===// +// Clang Extensions +//===----------------------------------------------------------------------===// + + +/// ExtVectorElementExpr - This represents access to specific elements of a +/// vector, and may occur on the left hand side or right hand side. For example +/// the following is legal: "V.xy = V.zw" if V is a 4 element extended vector. +/// +/// Note that the base may have either vector or pointer to vector type, just +/// like a struct field reference. +/// +class ExtVectorElementExpr : public Expr { + Stmt *Base; + IdentifierInfo *Accessor; + SourceLocation AccessorLoc; +public: + ExtVectorElementExpr(QualType ty, ExprValueKind VK, Expr *base, + IdentifierInfo &accessor, SourceLocation loc) + : Expr(ExtVectorElementExprClass, ty, VK, + (VK == VK_RValue ? OK_Ordinary : OK_VectorComponent), + base->isTypeDependent(), base->isValueDependent(), + base->isInstantiationDependent(), + base->containsUnexpandedParameterPack()), + Base(base), Accessor(&accessor), AccessorLoc(loc) {} + + /// \brief Build an empty vector element expression. + explicit ExtVectorElementExpr(EmptyShell Empty) + : Expr(ExtVectorElementExprClass, Empty) { } + + const Expr *getBase() const { return cast<Expr>(Base); } + Expr *getBase() { return cast<Expr>(Base); } + void setBase(Expr *E) { Base = E; } + + IdentifierInfo &getAccessor() const { return *Accessor; } + void setAccessor(IdentifierInfo *II) { Accessor = II; } + + SourceLocation getAccessorLoc() const { return AccessorLoc; } + void setAccessorLoc(SourceLocation L) { AccessorLoc = L; } + + /// getNumElements - Get the number of components being selected. + unsigned getNumElements() const; + + /// containsDuplicateElements - Return true if any element access is + /// repeated. + bool containsDuplicateElements() const; + + /// getEncodedElementAccess - Encode the elements accessed into an llvm + /// aggregate Constant of ConstantInt(s). + void getEncodedElementAccess(SmallVectorImpl<unsigned> &Elts) const; + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(getBase()->getLocStart(), AccessorLoc); + } + + /// isArrow - Return true if the base expression is a pointer to vector, + /// return false if the base expression is a vector. + bool isArrow() const; + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ExtVectorElementExprClass; + } + static bool classof(const ExtVectorElementExpr *) { return true; } + + // Iterators + child_range children() { return child_range(&Base, &Base+1); } +}; + + +/// BlockExpr - Adaptor class for mixing a BlockDecl with expressions. +/// ^{ statement-body } or ^(int arg1, float arg2){ statement-body } +class BlockExpr : public Expr { +protected: + BlockDecl *TheBlock; +public: + BlockExpr(BlockDecl *BD, QualType ty) + : Expr(BlockExprClass, ty, VK_RValue, OK_Ordinary, + ty->isDependentType(), ty->isDependentType(), + ty->isInstantiationDependentType() || BD->isDependentContext(), + false), + TheBlock(BD) {} + + /// \brief Build an empty block expression. + explicit BlockExpr(EmptyShell Empty) : Expr(BlockExprClass, Empty) { } + + const BlockDecl *getBlockDecl() const { return TheBlock; } + BlockDecl *getBlockDecl() { return TheBlock; } + void setBlockDecl(BlockDecl *BD) { TheBlock = BD; } + + // Convenience functions for probing the underlying BlockDecl. + SourceLocation getCaretLocation() const; + const Stmt *getBody() const; + Stmt *getBody(); + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(getCaretLocation(), getBody()->getLocEnd()); + } + + /// getFunctionType - Return the underlying function type for this block. + const FunctionProtoType *getFunctionType() const; + + static bool classof(const Stmt *T) { + return T->getStmtClass() == BlockExprClass; + } + static bool classof(const BlockExpr *) { return true; } + + // Iterators + child_range children() { return child_range(); } +}; + +/// AsTypeExpr - Clang builtin function __builtin_astype [OpenCL 6.2.4.2] +/// This AST node provides support for reinterpreting a type to another +/// type of the same size. +class AsTypeExpr : public Expr { // Should this be an ExplicitCastExpr? +private: + Stmt *SrcExpr; + SourceLocation BuiltinLoc, RParenLoc; + + friend class ASTReader; + friend class ASTStmtReader; + explicit AsTypeExpr(EmptyShell Empty) : Expr(AsTypeExprClass, Empty) {} + +public: + AsTypeExpr(Expr* SrcExpr, QualType DstType, + ExprValueKind VK, ExprObjectKind OK, + SourceLocation BuiltinLoc, SourceLocation RParenLoc) + : Expr(AsTypeExprClass, DstType, VK, OK, + DstType->isDependentType(), + DstType->isDependentType() || SrcExpr->isValueDependent(), + (DstType->isInstantiationDependentType() || + SrcExpr->isInstantiationDependent()), + (DstType->containsUnexpandedParameterPack() || + SrcExpr->containsUnexpandedParameterPack())), + SrcExpr(SrcExpr), BuiltinLoc(BuiltinLoc), RParenLoc(RParenLoc) {} + + /// getSrcExpr - Return the Expr to be converted. + Expr *getSrcExpr() const { return cast<Expr>(SrcExpr); } + + /// getBuiltinLoc - Return the location of the __builtin_astype token. + SourceLocation getBuiltinLoc() const { return BuiltinLoc; } + + /// getRParenLoc - Return the location of final right parenthesis. + SourceLocation getRParenLoc() const { return RParenLoc; } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(BuiltinLoc, RParenLoc); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == AsTypeExprClass; + } + static bool classof(const AsTypeExpr *) { return true; } + + // Iterators + child_range children() { return child_range(&SrcExpr, &SrcExpr+1); } +}; + +/// PseudoObjectExpr - An expression which accesses a pseudo-object +/// l-value. A pseudo-object is an abstract object, accesses to which +/// are translated to calls. The pseudo-object expression has a +/// syntactic form, which shows how the expression was actually +/// written in the source code, and a semantic form, which is a series +/// of expressions to be executed in order which detail how the +/// operation is actually evaluated. Optionally, one of the semantic +/// forms may also provide a result value for the expression. +/// +/// If any of the semantic-form expressions is an OpaqueValueExpr, +/// that OVE is required to have a source expression, and it is bound +/// to the result of that source expression. Such OVEs may appear +/// only in subsequent semantic-form expressions and as +/// sub-expressions of the syntactic form. +/// +/// PseudoObjectExpr should be used only when an operation can be +/// usefully described in terms of fairly simple rewrite rules on +/// objects and functions that are meant to be used by end-developers. +/// For example, under the Itanium ABI, dynamic casts are implemented +/// as a call to a runtime function called __dynamic_cast; using this +/// class to describe that would be inappropriate because that call is +/// not really part of the user-visible semantics, and instead the +/// cast is properly reflected in the AST and IR-generation has been +/// taught to generate the call as necessary. In contrast, an +/// Objective-C property access is semantically defined to be +/// equivalent to a particular message send, and this is very much +/// part of the user model. The name of this class encourages this +/// modelling design. +class PseudoObjectExpr : public Expr { + // PseudoObjectExprBits.NumSubExprs - The number of sub-expressions. + // Always at least two, because the first sub-expression is the + // syntactic form. + + // PseudoObjectExprBits.ResultIndex - The index of the + // sub-expression holding the result. 0 means the result is void, + // which is unambiguous because it's the index of the syntactic + // form. Note that this is therefore 1 higher than the value passed + // in to Create, which is an index within the semantic forms. + // Note also that ASTStmtWriter assumes this encoding. + + Expr **getSubExprsBuffer() { return reinterpret_cast<Expr**>(this + 1); } + const Expr * const *getSubExprsBuffer() const { + return reinterpret_cast<const Expr * const *>(this + 1); + } + + friend class ASTStmtReader; + + PseudoObjectExpr(QualType type, ExprValueKind VK, + Expr *syntactic, ArrayRef<Expr*> semantic, + unsigned resultIndex); + + PseudoObjectExpr(EmptyShell shell, unsigned numSemanticExprs); + + unsigned getNumSubExprs() const { + return PseudoObjectExprBits.NumSubExprs; + } + +public: + /// NoResult - A value for the result index indicating that there is + /// no semantic result. + enum { NoResult = ~0U }; + + static PseudoObjectExpr *Create(ASTContext &Context, Expr *syntactic, + ArrayRef<Expr*> semantic, + unsigned resultIndex); + + static PseudoObjectExpr *Create(ASTContext &Context, EmptyShell shell, + unsigned numSemanticExprs); + + /// Return the syntactic form of this expression, i.e. the + /// expression it actually looks like. Likely to be expressed in + /// terms of OpaqueValueExprs bound in the semantic form. + Expr *getSyntacticForm() { return getSubExprsBuffer()[0]; } + const Expr *getSyntacticForm() const { return getSubExprsBuffer()[0]; } + + /// Return the index of the result-bearing expression into the semantics + /// expressions, or PseudoObjectExpr::NoResult if there is none. + unsigned getResultExprIndex() const { + if (PseudoObjectExprBits.ResultIndex == 0) return NoResult; + return PseudoObjectExprBits.ResultIndex - 1; + } + + /// Return the result-bearing expression, or null if there is none. + Expr *getResultExpr() { + if (PseudoObjectExprBits.ResultIndex == 0) + return 0; + return getSubExprsBuffer()[PseudoObjectExprBits.ResultIndex]; + } + const Expr *getResultExpr() const { + return const_cast<PseudoObjectExpr*>(this)->getResultExpr(); + } + + unsigned getNumSemanticExprs() const { return getNumSubExprs() - 1; } + + typedef Expr * const *semantics_iterator; + typedef const Expr * const *const_semantics_iterator; + semantics_iterator semantics_begin() { + return getSubExprsBuffer() + 1; + } + const_semantics_iterator semantics_begin() const { + return getSubExprsBuffer() + 1; + } + semantics_iterator semantics_end() { + return getSubExprsBuffer() + getNumSubExprs(); + } + const_semantics_iterator semantics_end() const { + return getSubExprsBuffer() + getNumSubExprs(); + } + Expr *getSemanticExpr(unsigned index) { + assert(index + 1 < getNumSubExprs()); + return getSubExprsBuffer()[index + 1]; + } + const Expr *getSemanticExpr(unsigned index) const { + return const_cast<PseudoObjectExpr*>(this)->getSemanticExpr(index); + } + + SourceLocation getExprLoc() const LLVM_READONLY { + return getSyntacticForm()->getExprLoc(); + } + SourceRange getSourceRange() const LLVM_READONLY { + return getSyntacticForm()->getSourceRange(); + } + + child_range children() { + Stmt **cs = reinterpret_cast<Stmt**>(getSubExprsBuffer()); + return child_range(cs, cs + getNumSubExprs()); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == PseudoObjectExprClass; + } + static bool classof(const PseudoObjectExpr *) { return true; } +}; + +/// AtomicExpr - Variadic atomic builtins: __atomic_exchange, __atomic_fetch_*, +/// __atomic_load, __atomic_store, and __atomic_compare_exchange_*, for the +/// similarly-named C++11 instructions, and __c11 variants for <stdatomic.h>. +/// All of these instructions take one primary pointer and at least one memory +/// order. +class AtomicExpr : public Expr { +public: + enum AtomicOp { +#define BUILTIN(ID, TYPE, ATTRS) +#define ATOMIC_BUILTIN(ID, TYPE, ATTRS) AO ## ID, +#include "clang/Basic/Builtins.def" + // Avoid trailing comma + BI_First = 0 + }; + +private: + enum { PTR, ORDER, VAL1, ORDER_FAIL, VAL2, WEAK, END_EXPR }; + Stmt* SubExprs[END_EXPR]; + unsigned NumSubExprs; + SourceLocation BuiltinLoc, RParenLoc; + AtomicOp Op; + + friend class ASTStmtReader; + +public: + AtomicExpr(SourceLocation BLoc, Expr **args, unsigned nexpr, QualType t, + AtomicOp op, SourceLocation RP); + + /// \brief Determine the number of arguments the specified atomic builtin + /// should have. + static unsigned getNumSubExprs(AtomicOp Op); + + /// \brief Build an empty AtomicExpr. + explicit AtomicExpr(EmptyShell Empty) : Expr(AtomicExprClass, Empty) { } + + Expr *getPtr() const { + return cast<Expr>(SubExprs[PTR]); + } + Expr *getOrder() const { + return cast<Expr>(SubExprs[ORDER]); + } + Expr *getVal1() const { + if (Op == AO__c11_atomic_init) + return cast<Expr>(SubExprs[ORDER]); + assert(NumSubExprs > VAL1); + return cast<Expr>(SubExprs[VAL1]); + } + Expr *getOrderFail() const { + assert(NumSubExprs > ORDER_FAIL); + return cast<Expr>(SubExprs[ORDER_FAIL]); + } + Expr *getVal2() const { + if (Op == AO__atomic_exchange) + return cast<Expr>(SubExprs[ORDER_FAIL]); + assert(NumSubExprs > VAL2); + return cast<Expr>(SubExprs[VAL2]); + } + Expr *getWeak() const { + assert(NumSubExprs > WEAK); + return cast<Expr>(SubExprs[WEAK]); + } + + AtomicOp getOp() const { return Op; } + unsigned getNumSubExprs() { return NumSubExprs; } + + Expr **getSubExprs() { return reinterpret_cast<Expr **>(SubExprs); } + + bool isVolatile() const { + return getPtr()->getType()->getPointeeType().isVolatileQualified(); + } + + bool isCmpXChg() const { + return getOp() == AO__c11_atomic_compare_exchange_strong || + getOp() == AO__c11_atomic_compare_exchange_weak || + getOp() == AO__atomic_compare_exchange || + getOp() == AO__atomic_compare_exchange_n; + } + + SourceLocation getBuiltinLoc() const { return BuiltinLoc; } + SourceLocation getRParenLoc() const { return RParenLoc; } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(BuiltinLoc, RParenLoc); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == AtomicExprClass; + } + static bool classof(const AtomicExpr *) { return true; } + + // Iterators + child_range children() { + return child_range(SubExprs, SubExprs+NumSubExprs); + } +}; +} // end namespace clang + +#endif diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h new file mode 100644 index 0000000..b69693d --- /dev/null +++ b/clang/include/clang/AST/ExprCXX.h @@ -0,0 +1,3638 @@ +//===--- ExprCXX.h - Classes for representing expressions -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Expr interface and subclasses for C++ expressions. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_EXPRCXX_H +#define LLVM_CLANG_AST_EXPRCXX_H + +#include "clang/AST/Expr.h" +#include "clang/AST/UnresolvedSet.h" +#include "clang/AST/TemplateBase.h" +#include "clang/Basic/ExpressionTraits.h" +#include "clang/Basic/Lambda.h" +#include "clang/Basic/TypeTraits.h" +#include "llvm/Support/Compiler.h" + +namespace clang { + +class CXXConstructorDecl; +class CXXDestructorDecl; +class CXXMethodDecl; +class CXXTemporary; +class TemplateArgumentListInfo; + +//===--------------------------------------------------------------------===// +// C++ Expressions. +//===--------------------------------------------------------------------===// + +/// \brief A call to an overloaded operator written using operator +/// syntax. +/// +/// Represents a call to an overloaded operator written using operator +/// syntax, e.g., "x + y" or "*p". While semantically equivalent to a +/// normal call, this AST node provides better information about the +/// syntactic representation of the call. +/// +/// In a C++ template, this expression node kind will be used whenever +/// any of the arguments are type-dependent. In this case, the +/// function itself will be a (possibly empty) set of functions and +/// function templates that were found by name lookup at template +/// definition time. +class CXXOperatorCallExpr : public CallExpr { + /// \brief The overloaded operator. + OverloadedOperatorKind Operator; + +public: + CXXOperatorCallExpr(ASTContext& C, OverloadedOperatorKind Op, Expr *fn, + Expr **args, unsigned numargs, QualType t, + ExprValueKind VK, SourceLocation operatorloc) + : CallExpr(C, CXXOperatorCallExprClass, fn, 0, args, numargs, t, VK, + operatorloc), + Operator(Op) {} + explicit CXXOperatorCallExpr(ASTContext& C, EmptyShell Empty) : + CallExpr(C, CXXOperatorCallExprClass, Empty) { } + + + /// getOperator - Returns the kind of overloaded operator that this + /// expression refers to. + OverloadedOperatorKind getOperator() const { return Operator; } + void setOperator(OverloadedOperatorKind Kind) { Operator = Kind; } + + /// getOperatorLoc - Returns the location of the operator symbol in + /// the expression. When @c getOperator()==OO_Call, this is the + /// location of the right parentheses; when @c + /// getOperator()==OO_Subscript, this is the location of the right + /// bracket. + SourceLocation getOperatorLoc() const { return getRParenLoc(); } + + SourceRange getSourceRange() const LLVM_READONLY; + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXOperatorCallExprClass; + } + static bool classof(const CXXOperatorCallExpr *) { return true; } +}; + +/// CXXMemberCallExpr - Represents a call to a member function that +/// may be written either with member call syntax (e.g., "obj.func()" +/// or "objptr->func()") or with normal function-call syntax +/// ("func()") within a member function that ends up calling a member +/// function. The callee in either case is a MemberExpr that contains +/// both the object argument and the member function, while the +/// arguments are the arguments within the parentheses (not including +/// the object argument). +class CXXMemberCallExpr : public CallExpr { +public: + CXXMemberCallExpr(ASTContext &C, Expr *fn, Expr **args, unsigned numargs, + QualType t, ExprValueKind VK, SourceLocation RP) + : CallExpr(C, CXXMemberCallExprClass, fn, 0, args, numargs, t, VK, RP) {} + + CXXMemberCallExpr(ASTContext &C, EmptyShell Empty) + : CallExpr(C, CXXMemberCallExprClass, Empty) { } + + /// getImplicitObjectArgument - Retrieves the implicit object + /// argument for the member call. For example, in "x.f(5)", this + /// operation would return "x". + Expr *getImplicitObjectArgument() const; + + /// Retrieves the declaration of the called method. + CXXMethodDecl *getMethodDecl() const; + + /// getRecordDecl - Retrieves the CXXRecordDecl for the underlying type of + /// the implicit object argument. Note that this is may not be the same + /// declaration as that of the class context of the CXXMethodDecl which this + /// function is calling. + /// FIXME: Returns 0 for member pointer call exprs. + CXXRecordDecl *getRecordDecl(); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXMemberCallExprClass; + } + static bool classof(const CXXMemberCallExpr *) { return true; } +}; + +/// CUDAKernelCallExpr - Represents a call to a CUDA kernel function. +class CUDAKernelCallExpr : public CallExpr { +private: + enum { CONFIG, END_PREARG }; + +public: + CUDAKernelCallExpr(ASTContext &C, Expr *fn, CallExpr *Config, + Expr **args, unsigned numargs, QualType t, + ExprValueKind VK, SourceLocation RP) + : CallExpr(C, CUDAKernelCallExprClass, fn, END_PREARG, args, numargs, t, VK, + RP) { + setConfig(Config); + } + + CUDAKernelCallExpr(ASTContext &C, EmptyShell Empty) + : CallExpr(C, CUDAKernelCallExprClass, END_PREARG, Empty) { } + + const CallExpr *getConfig() const { + return cast_or_null<CallExpr>(getPreArg(CONFIG)); + } + CallExpr *getConfig() { return cast_or_null<CallExpr>(getPreArg(CONFIG)); } + void setConfig(CallExpr *E) { setPreArg(CONFIG, E); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CUDAKernelCallExprClass; + } + static bool classof(const CUDAKernelCallExpr *) { return true; } +}; + +/// CXXNamedCastExpr - Abstract class common to all of the C++ "named" +/// casts, @c static_cast, @c dynamic_cast, @c reinterpret_cast, or @c +/// const_cast. +/// +/// This abstract class is inherited by all of the classes +/// representing "named" casts, e.g., CXXStaticCastExpr, +/// CXXDynamicCastExpr, CXXReinterpretCastExpr, and CXXConstCastExpr. +class CXXNamedCastExpr : public ExplicitCastExpr { +private: + SourceLocation Loc; // the location of the casting op + SourceLocation RParenLoc; // the location of the right parenthesis + +protected: + CXXNamedCastExpr(StmtClass SC, QualType ty, ExprValueKind VK, + CastKind kind, Expr *op, unsigned PathSize, + TypeSourceInfo *writtenTy, SourceLocation l, + SourceLocation RParenLoc) + : ExplicitCastExpr(SC, ty, VK, kind, op, PathSize, writtenTy), Loc(l), + RParenLoc(RParenLoc) {} + + explicit CXXNamedCastExpr(StmtClass SC, EmptyShell Shell, unsigned PathSize) + : ExplicitCastExpr(SC, Shell, PathSize) { } + + friend class ASTStmtReader; + +public: + const char *getCastName() const; + + /// \brief Retrieve the location of the cast operator keyword, e.g., + /// "static_cast". + SourceLocation getOperatorLoc() const { return Loc; } + + /// \brief Retrieve the location of the closing parenthesis. + SourceLocation getRParenLoc() const { return RParenLoc; } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(Loc, RParenLoc); + } + static bool classof(const Stmt *T) { + switch (T->getStmtClass()) { + case CXXStaticCastExprClass: + case CXXDynamicCastExprClass: + case CXXReinterpretCastExprClass: + case CXXConstCastExprClass: + return true; + default: + return false; + } + } + static bool classof(const CXXNamedCastExpr *) { return true; } +}; + +/// CXXStaticCastExpr - A C++ @c static_cast expression +/// (C++ [expr.static.cast]). +/// +/// This expression node represents a C++ static cast, e.g., +/// @c static_cast<int>(1.0). +class CXXStaticCastExpr : public CXXNamedCastExpr { + CXXStaticCastExpr(QualType ty, ExprValueKind vk, CastKind kind, Expr *op, + unsigned pathSize, TypeSourceInfo *writtenTy, + SourceLocation l, SourceLocation RParenLoc) + : CXXNamedCastExpr(CXXStaticCastExprClass, ty, vk, kind, op, pathSize, + writtenTy, l, RParenLoc) {} + + explicit CXXStaticCastExpr(EmptyShell Empty, unsigned PathSize) + : CXXNamedCastExpr(CXXStaticCastExprClass, Empty, PathSize) { } + +public: + static CXXStaticCastExpr *Create(ASTContext &Context, QualType T, + ExprValueKind VK, CastKind K, Expr *Op, + const CXXCastPath *Path, + TypeSourceInfo *Written, SourceLocation L, + SourceLocation RParenLoc); + static CXXStaticCastExpr *CreateEmpty(ASTContext &Context, + unsigned PathSize); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXStaticCastExprClass; + } + static bool classof(const CXXStaticCastExpr *) { return true; } +}; + +/// CXXDynamicCastExpr - A C++ @c dynamic_cast expression +/// (C++ [expr.dynamic.cast]), which may perform a run-time check to +/// determine how to perform the type cast. +/// +/// This expression node represents a dynamic cast, e.g., +/// @c dynamic_cast<Derived*>(BasePtr). +class CXXDynamicCastExpr : public CXXNamedCastExpr { + CXXDynamicCastExpr(QualType ty, ExprValueKind VK, CastKind kind, + Expr *op, unsigned pathSize, TypeSourceInfo *writtenTy, + SourceLocation l, SourceLocation RParenLoc) + : CXXNamedCastExpr(CXXDynamicCastExprClass, ty, VK, kind, op, pathSize, + writtenTy, l, RParenLoc) {} + + explicit CXXDynamicCastExpr(EmptyShell Empty, unsigned pathSize) + : CXXNamedCastExpr(CXXDynamicCastExprClass, Empty, pathSize) { } + +public: + static CXXDynamicCastExpr *Create(ASTContext &Context, QualType T, + ExprValueKind VK, CastKind Kind, Expr *Op, + const CXXCastPath *Path, + TypeSourceInfo *Written, SourceLocation L, + SourceLocation RParenLoc); + + static CXXDynamicCastExpr *CreateEmpty(ASTContext &Context, + unsigned pathSize); + + bool isAlwaysNull() const; + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXDynamicCastExprClass; + } + static bool classof(const CXXDynamicCastExpr *) { return true; } +}; + +/// CXXReinterpretCastExpr - A C++ @c reinterpret_cast expression (C++ +/// [expr.reinterpret.cast]), which provides a differently-typed view +/// of a value but performs no actual work at run time. +/// +/// This expression node represents a reinterpret cast, e.g., +/// @c reinterpret_cast<int>(VoidPtr). +class CXXReinterpretCastExpr : public CXXNamedCastExpr { + CXXReinterpretCastExpr(QualType ty, ExprValueKind vk, CastKind kind, + Expr *op, unsigned pathSize, + TypeSourceInfo *writtenTy, SourceLocation l, + SourceLocation RParenLoc) + : CXXNamedCastExpr(CXXReinterpretCastExprClass, ty, vk, kind, op, + pathSize, writtenTy, l, RParenLoc) {} + + CXXReinterpretCastExpr(EmptyShell Empty, unsigned pathSize) + : CXXNamedCastExpr(CXXReinterpretCastExprClass, Empty, pathSize) { } + +public: + static CXXReinterpretCastExpr *Create(ASTContext &Context, QualType T, + ExprValueKind VK, CastKind Kind, + Expr *Op, const CXXCastPath *Path, + TypeSourceInfo *WrittenTy, SourceLocation L, + SourceLocation RParenLoc); + static CXXReinterpretCastExpr *CreateEmpty(ASTContext &Context, + unsigned pathSize); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXReinterpretCastExprClass; + } + static bool classof(const CXXReinterpretCastExpr *) { return true; } +}; + +/// CXXConstCastExpr - A C++ @c const_cast expression (C++ [expr.const.cast]), +/// which can remove type qualifiers but does not change the underlying value. +/// +/// This expression node represents a const cast, e.g., +/// @c const_cast<char*>(PtrToConstChar). +class CXXConstCastExpr : public CXXNamedCastExpr { + CXXConstCastExpr(QualType ty, ExprValueKind VK, Expr *op, + TypeSourceInfo *writtenTy, SourceLocation l, + SourceLocation RParenLoc) + : CXXNamedCastExpr(CXXConstCastExprClass, ty, VK, CK_NoOp, op, + 0, writtenTy, l, RParenLoc) {} + + explicit CXXConstCastExpr(EmptyShell Empty) + : CXXNamedCastExpr(CXXConstCastExprClass, Empty, 0) { } + +public: + static CXXConstCastExpr *Create(ASTContext &Context, QualType T, + ExprValueKind VK, Expr *Op, + TypeSourceInfo *WrittenTy, SourceLocation L, + SourceLocation RParenLoc); + static CXXConstCastExpr *CreateEmpty(ASTContext &Context); + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXConstCastExprClass; + } + static bool classof(const CXXConstCastExpr *) { return true; } +}; + +/// UserDefinedLiteral - A call to a literal operator (C++11 [over.literal]) +/// written as a user-defined literal (C++11 [lit.ext]). +/// +/// Represents a user-defined literal, e.g. "foo"_bar or 1.23_xyz. While this +/// is semantically equivalent to a normal call, this AST node provides better +/// information about the syntactic representation of the literal. +/// +/// Since literal operators are never found by ADL and can only be declared at +/// namespace scope, a user-defined literal is never dependent. +class UserDefinedLiteral : public CallExpr { + /// \brief The location of a ud-suffix within the literal. + SourceLocation UDSuffixLoc; + +public: + UserDefinedLiteral(ASTContext &C, Expr *Fn, Expr **Args, unsigned NumArgs, + QualType T, ExprValueKind VK, SourceLocation LitEndLoc, + SourceLocation SuffixLoc) + : CallExpr(C, UserDefinedLiteralClass, Fn, 0, Args, NumArgs, T, VK, + LitEndLoc), UDSuffixLoc(SuffixLoc) {} + explicit UserDefinedLiteral(ASTContext &C, EmptyShell Empty) + : CallExpr(C, UserDefinedLiteralClass, Empty) {} + + /// The kind of literal operator which is invoked. + enum LiteralOperatorKind { + LOK_Raw, ///< Raw form: operator "" X (const char *) + LOK_Template, ///< Raw form: operator "" X<cs...> () + LOK_Integer, ///< operator "" X (unsigned long long) + LOK_Floating, ///< operator "" X (long double) + LOK_String, ///< operator "" X (const CharT *, size_t) + LOK_Character ///< operator "" X (CharT) + }; + + /// getLiteralOperatorKind - Returns the kind of literal operator invocation + /// which this expression represents. + LiteralOperatorKind getLiteralOperatorKind() const; + + /// getCookedLiteral - If this is not a raw user-defined literal, get the + /// underlying cooked literal (representing the literal with the suffix + /// removed). + Expr *getCookedLiteral(); + const Expr *getCookedLiteral() const { + return const_cast<UserDefinedLiteral*>(this)->getCookedLiteral(); + } + + /// getUDSuffixLoc - Returns the location of a ud-suffix in the expression. + /// For a string literal, there may be multiple identical suffixes. This + /// returns the first. + SourceLocation getUDSuffixLoc() const { return getRParenLoc(); } + + /// getUDSuffix - Returns the ud-suffix specified for this literal. + const IdentifierInfo *getUDSuffix() const; + + static bool classof(const Stmt *S) { + return S->getStmtClass() == UserDefinedLiteralClass; + } + static bool classof(const UserDefinedLiteral *) { return true; } + + friend class ASTStmtReader; + friend class ASTStmtWriter; +}; + +/// CXXBoolLiteralExpr - [C++ 2.13.5] C++ Boolean Literal. +/// +class CXXBoolLiteralExpr : public Expr { + bool Value; + SourceLocation Loc; +public: + CXXBoolLiteralExpr(bool val, QualType Ty, SourceLocation l) : + Expr(CXXBoolLiteralExprClass, Ty, VK_RValue, OK_Ordinary, false, false, + false, false), + Value(val), Loc(l) {} + + explicit CXXBoolLiteralExpr(EmptyShell Empty) + : Expr(CXXBoolLiteralExprClass, Empty) { } + + bool getValue() const { return Value; } + void setValue(bool V) { Value = V; } + + SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(Loc); } + + SourceLocation getLocation() const { return Loc; } + void setLocation(SourceLocation L) { Loc = L; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXBoolLiteralExprClass; + } + static bool classof(const CXXBoolLiteralExpr *) { return true; } + + // Iterators + child_range children() { return child_range(); } +}; + +/// CXXNullPtrLiteralExpr - [C++0x 2.14.7] C++ Pointer Literal +class CXXNullPtrLiteralExpr : public Expr { + SourceLocation Loc; +public: + CXXNullPtrLiteralExpr(QualType Ty, SourceLocation l) : + Expr(CXXNullPtrLiteralExprClass, Ty, VK_RValue, OK_Ordinary, false, false, + false, false), + Loc(l) {} + + explicit CXXNullPtrLiteralExpr(EmptyShell Empty) + : Expr(CXXNullPtrLiteralExprClass, Empty) { } + + SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(Loc); } + + SourceLocation getLocation() const { return Loc; } + void setLocation(SourceLocation L) { Loc = L; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXNullPtrLiteralExprClass; + } + static bool classof(const CXXNullPtrLiteralExpr *) { return true; } + + child_range children() { return child_range(); } +}; + +/// CXXTypeidExpr - A C++ @c typeid expression (C++ [expr.typeid]), which gets +/// the type_info that corresponds to the supplied type, or the (possibly +/// dynamic) type of the supplied expression. +/// +/// This represents code like @c typeid(int) or @c typeid(*objPtr) +class CXXTypeidExpr : public Expr { +private: + llvm::PointerUnion<Stmt *, TypeSourceInfo *> Operand; + SourceRange Range; + +public: + CXXTypeidExpr(QualType Ty, TypeSourceInfo *Operand, SourceRange R) + : Expr(CXXTypeidExprClass, Ty, VK_LValue, OK_Ordinary, + // typeid is never type-dependent (C++ [temp.dep.expr]p4) + false, + // typeid is value-dependent if the type or expression are dependent + Operand->getType()->isDependentType(), + Operand->getType()->isInstantiationDependentType(), + Operand->getType()->containsUnexpandedParameterPack()), + Operand(Operand), Range(R) { } + + CXXTypeidExpr(QualType Ty, Expr *Operand, SourceRange R) + : Expr(CXXTypeidExprClass, Ty, VK_LValue, OK_Ordinary, + // typeid is never type-dependent (C++ [temp.dep.expr]p4) + false, + // typeid is value-dependent if the type or expression are dependent + Operand->isTypeDependent() || Operand->isValueDependent(), + Operand->isInstantiationDependent(), + Operand->containsUnexpandedParameterPack()), + Operand(Operand), Range(R) { } + + CXXTypeidExpr(EmptyShell Empty, bool isExpr) + : Expr(CXXTypeidExprClass, Empty) { + if (isExpr) + Operand = (Expr*)0; + else + Operand = (TypeSourceInfo*)0; + } + + bool isTypeOperand() const { return Operand.is<TypeSourceInfo *>(); } + + /// \brief Retrieves the type operand of this typeid() expression after + /// various required adjustments (removing reference types, cv-qualifiers). + QualType getTypeOperand() const; + + /// \brief Retrieve source information for the type operand. + TypeSourceInfo *getTypeOperandSourceInfo() const { + assert(isTypeOperand() && "Cannot call getTypeOperand for typeid(expr)"); + return Operand.get<TypeSourceInfo *>(); + } + + void setTypeOperandSourceInfo(TypeSourceInfo *TSI) { + assert(isTypeOperand() && "Cannot call getTypeOperand for typeid(expr)"); + Operand = TSI; + } + + Expr *getExprOperand() const { + assert(!isTypeOperand() && "Cannot call getExprOperand for typeid(type)"); + return static_cast<Expr*>(Operand.get<Stmt *>()); + } + + void setExprOperand(Expr *E) { + assert(!isTypeOperand() && "Cannot call getExprOperand for typeid(type)"); + Operand = E; + } + + SourceRange getSourceRange() const LLVM_READONLY { return Range; } + void setSourceRange(SourceRange R) { Range = R; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXTypeidExprClass; + } + static bool classof(const CXXTypeidExpr *) { return true; } + + // Iterators + child_range children() { + if (isTypeOperand()) return child_range(); + Stmt **begin = reinterpret_cast<Stmt**>(&Operand); + return child_range(begin, begin + 1); + } +}; + +/// CXXUuidofExpr - A microsoft C++ @c __uuidof expression, which gets +/// the _GUID that corresponds to the supplied type or expression. +/// +/// This represents code like @c __uuidof(COMTYPE) or @c __uuidof(*comPtr) +class CXXUuidofExpr : public Expr { +private: + llvm::PointerUnion<Stmt *, TypeSourceInfo *> Operand; + SourceRange Range; + +public: + CXXUuidofExpr(QualType Ty, TypeSourceInfo *Operand, SourceRange R) + : Expr(CXXUuidofExprClass, Ty, VK_LValue, OK_Ordinary, + false, Operand->getType()->isDependentType(), + Operand->getType()->isInstantiationDependentType(), + Operand->getType()->containsUnexpandedParameterPack()), + Operand(Operand), Range(R) { } + + CXXUuidofExpr(QualType Ty, Expr *Operand, SourceRange R) + : Expr(CXXUuidofExprClass, Ty, VK_LValue, OK_Ordinary, + false, Operand->isTypeDependent(), + Operand->isInstantiationDependent(), + Operand->containsUnexpandedParameterPack()), + Operand(Operand), Range(R) { } + + CXXUuidofExpr(EmptyShell Empty, bool isExpr) + : Expr(CXXUuidofExprClass, Empty) { + if (isExpr) + Operand = (Expr*)0; + else + Operand = (TypeSourceInfo*)0; + } + + bool isTypeOperand() const { return Operand.is<TypeSourceInfo *>(); } + + /// \brief Retrieves the type operand of this __uuidof() expression after + /// various required adjustments (removing reference types, cv-qualifiers). + QualType getTypeOperand() const; + + /// \brief Retrieve source information for the type operand. + TypeSourceInfo *getTypeOperandSourceInfo() const { + assert(isTypeOperand() && "Cannot call getTypeOperand for __uuidof(expr)"); + return Operand.get<TypeSourceInfo *>(); + } + + void setTypeOperandSourceInfo(TypeSourceInfo *TSI) { + assert(isTypeOperand() && "Cannot call getTypeOperand for __uuidof(expr)"); + Operand = TSI; + } + + Expr *getExprOperand() const { + assert(!isTypeOperand() && "Cannot call getExprOperand for __uuidof(type)"); + return static_cast<Expr*>(Operand.get<Stmt *>()); + } + + void setExprOperand(Expr *E) { + assert(!isTypeOperand() && "Cannot call getExprOperand for __uuidof(type)"); + Operand = E; + } + + SourceRange getSourceRange() const LLVM_READONLY { return Range; } + void setSourceRange(SourceRange R) { Range = R; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXUuidofExprClass; + } + static bool classof(const CXXUuidofExpr *) { return true; } + + // Iterators + child_range children() { + if (isTypeOperand()) return child_range(); + Stmt **begin = reinterpret_cast<Stmt**>(&Operand); + return child_range(begin, begin + 1); + } +}; + +/// CXXThisExpr - Represents the "this" expression in C++, which is a +/// pointer to the object on which the current member function is +/// executing (C++ [expr.prim]p3). Example: +/// +/// @code +/// class Foo { +/// public: +/// void bar(); +/// void test() { this->bar(); } +/// }; +/// @endcode +class CXXThisExpr : public Expr { + SourceLocation Loc; + bool Implicit : 1; + +public: + CXXThisExpr(SourceLocation L, QualType Type, bool isImplicit) + : Expr(CXXThisExprClass, Type, VK_RValue, OK_Ordinary, + // 'this' is type-dependent if the class type of the enclosing + // member function is dependent (C++ [temp.dep.expr]p2) + Type->isDependentType(), Type->isDependentType(), + Type->isInstantiationDependentType(), + /*ContainsUnexpandedParameterPack=*/false), + Loc(L), Implicit(isImplicit) { } + + CXXThisExpr(EmptyShell Empty) : Expr(CXXThisExprClass, Empty) {} + + SourceLocation getLocation() const { return Loc; } + void setLocation(SourceLocation L) { Loc = L; } + + SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(Loc); } + + bool isImplicit() const { return Implicit; } + void setImplicit(bool I) { Implicit = I; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXThisExprClass; + } + static bool classof(const CXXThisExpr *) { return true; } + + // Iterators + child_range children() { return child_range(); } +}; + +/// CXXThrowExpr - [C++ 15] C++ Throw Expression. This handles +/// 'throw' and 'throw' assignment-expression. When +/// assignment-expression isn't present, Op will be null. +/// +class CXXThrowExpr : public Expr { + Stmt *Op; + SourceLocation ThrowLoc; + /// \brief Whether the thrown variable (if any) is in scope. + unsigned IsThrownVariableInScope : 1; + + friend class ASTStmtReader; + +public: + // Ty is the void type which is used as the result type of the + // exepression. The l is the location of the throw keyword. expr + // can by null, if the optional expression to throw isn't present. + CXXThrowExpr(Expr *expr, QualType Ty, SourceLocation l, + bool IsThrownVariableInScope) : + Expr(CXXThrowExprClass, Ty, VK_RValue, OK_Ordinary, false, false, + expr && expr->isInstantiationDependent(), + expr && expr->containsUnexpandedParameterPack()), + Op(expr), ThrowLoc(l), IsThrownVariableInScope(IsThrownVariableInScope) {} + CXXThrowExpr(EmptyShell Empty) : Expr(CXXThrowExprClass, Empty) {} + + const Expr *getSubExpr() const { return cast_or_null<Expr>(Op); } + Expr *getSubExpr() { return cast_or_null<Expr>(Op); } + + SourceLocation getThrowLoc() const { return ThrowLoc; } + + /// \brief Determines whether the variable thrown by this expression (if any!) + /// is within the innermost try block. + /// + /// This information is required to determine whether the NRVO can apply to + /// this variable. + bool isThrownVariableInScope() const { return IsThrownVariableInScope; } + + SourceRange getSourceRange() const LLVM_READONLY { + if (getSubExpr() == 0) + return SourceRange(ThrowLoc, ThrowLoc); + return SourceRange(ThrowLoc, getSubExpr()->getSourceRange().getEnd()); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXThrowExprClass; + } + static bool classof(const CXXThrowExpr *) { return true; } + + // Iterators + child_range children() { + return child_range(&Op, Op ? &Op+1 : &Op); + } +}; + +/// CXXDefaultArgExpr - C++ [dcl.fct.default]. This wraps up a +/// function call argument that was created from the corresponding +/// parameter's default argument, when the call did not explicitly +/// supply arguments for all of the parameters. +class CXXDefaultArgExpr : public Expr { + /// \brief The parameter whose default is being used. + /// + /// When the bit is set, the subexpression is stored after the + /// CXXDefaultArgExpr itself. When the bit is clear, the parameter's + /// actual default expression is the subexpression. + llvm::PointerIntPair<ParmVarDecl *, 1, bool> Param; + + /// \brief The location where the default argument expression was used. + SourceLocation Loc; + + CXXDefaultArgExpr(StmtClass SC, SourceLocation Loc, ParmVarDecl *param) + : Expr(SC, + param->hasUnparsedDefaultArg() + ? param->getType().getNonReferenceType() + : param->getDefaultArg()->getType(), + param->getDefaultArg()->getValueKind(), + param->getDefaultArg()->getObjectKind(), false, false, false, false), + Param(param, false), Loc(Loc) { } + + CXXDefaultArgExpr(StmtClass SC, SourceLocation Loc, ParmVarDecl *param, + Expr *SubExpr) + : Expr(SC, SubExpr->getType(), + SubExpr->getValueKind(), SubExpr->getObjectKind(), + false, false, false, false), + Param(param, true), Loc(Loc) { + *reinterpret_cast<Expr **>(this + 1) = SubExpr; + } + +public: + CXXDefaultArgExpr(EmptyShell Empty) : Expr(CXXDefaultArgExprClass, Empty) {} + + + // Param is the parameter whose default argument is used by this + // expression. + static CXXDefaultArgExpr *Create(ASTContext &C, SourceLocation Loc, + ParmVarDecl *Param) { + return new (C) CXXDefaultArgExpr(CXXDefaultArgExprClass, Loc, Param); + } + + // Param is the parameter whose default argument is used by this + // expression, and SubExpr is the expression that will actually be used. + static CXXDefaultArgExpr *Create(ASTContext &C, + SourceLocation Loc, + ParmVarDecl *Param, + Expr *SubExpr); + + // Retrieve the parameter that the argument was created from. + const ParmVarDecl *getParam() const { return Param.getPointer(); } + ParmVarDecl *getParam() { return Param.getPointer(); } + + // Retrieve the actual argument to the function call. + const Expr *getExpr() const { + if (Param.getInt()) + return *reinterpret_cast<Expr const * const*> (this + 1); + return getParam()->getDefaultArg(); + } + Expr *getExpr() { + if (Param.getInt()) + return *reinterpret_cast<Expr **> (this + 1); + return getParam()->getDefaultArg(); + } + + /// \brief Retrieve the location where this default argument was actually + /// used. + SourceLocation getUsedLocation() const { return Loc; } + + SourceRange getSourceRange() const LLVM_READONLY { + // Default argument expressions have no representation in the + // source, so they have an empty source range. + return SourceRange(); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXDefaultArgExprClass; + } + static bool classof(const CXXDefaultArgExpr *) { return true; } + + // Iterators + child_range children() { return child_range(); } + + friend class ASTStmtReader; + friend class ASTStmtWriter; +}; + +/// CXXTemporary - Represents a C++ temporary. +class CXXTemporary { + /// Destructor - The destructor that needs to be called. + const CXXDestructorDecl *Destructor; + + CXXTemporary(const CXXDestructorDecl *destructor) + : Destructor(destructor) { } + +public: + static CXXTemporary *Create(ASTContext &C, + const CXXDestructorDecl *Destructor); + + const CXXDestructorDecl *getDestructor() const { return Destructor; } + void setDestructor(const CXXDestructorDecl *Dtor) { + Destructor = Dtor; + } +}; + +/// \brief Represents binding an expression to a temporary. +/// +/// This ensures the destructor is called for the temporary. It should only be +/// needed for non-POD, non-trivially destructable class types. For example: +/// +/// \code +/// struct S { +/// S() { } // User defined constructor makes S non-POD. +/// ~S() { } // User defined destructor makes it non-trivial. +/// }; +/// void test() { +/// const S &s_ref = S(); // Requires a CXXBindTemporaryExpr. +/// } +/// \endcode +class CXXBindTemporaryExpr : public Expr { + CXXTemporary *Temp; + + Stmt *SubExpr; + + CXXBindTemporaryExpr(CXXTemporary *temp, Expr* SubExpr) + : Expr(CXXBindTemporaryExprClass, SubExpr->getType(), + VK_RValue, OK_Ordinary, SubExpr->isTypeDependent(), + SubExpr->isValueDependent(), + SubExpr->isInstantiationDependent(), + SubExpr->containsUnexpandedParameterPack()), + Temp(temp), SubExpr(SubExpr) { } + +public: + CXXBindTemporaryExpr(EmptyShell Empty) + : Expr(CXXBindTemporaryExprClass, Empty), Temp(0), SubExpr(0) {} + + static CXXBindTemporaryExpr *Create(ASTContext &C, CXXTemporary *Temp, + Expr* SubExpr); + + CXXTemporary *getTemporary() { return Temp; } + const CXXTemporary *getTemporary() const { return Temp; } + void setTemporary(CXXTemporary *T) { Temp = T; } + + const Expr *getSubExpr() const { return cast<Expr>(SubExpr); } + Expr *getSubExpr() { return cast<Expr>(SubExpr); } + void setSubExpr(Expr *E) { SubExpr = E; } + + SourceRange getSourceRange() const LLVM_READONLY { + return SubExpr->getSourceRange(); + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXBindTemporaryExprClass; + } + static bool classof(const CXXBindTemporaryExpr *) { return true; } + + // Iterators + child_range children() { return child_range(&SubExpr, &SubExpr + 1); } +}; + +/// CXXConstructExpr - Represents a call to a C++ constructor. +class CXXConstructExpr : public Expr { +public: + enum ConstructionKind { + CK_Complete, + CK_NonVirtualBase, + CK_VirtualBase, + CK_Delegating + }; + +private: + CXXConstructorDecl *Constructor; + + SourceLocation Loc; + SourceRange ParenRange; + unsigned NumArgs : 16; + bool Elidable : 1; + bool HadMultipleCandidates : 1; + bool ListInitialization : 1; + bool ZeroInitialization : 1; + unsigned ConstructKind : 2; + Stmt **Args; + +protected: + CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T, + SourceLocation Loc, + CXXConstructorDecl *d, bool elidable, + Expr **args, unsigned numargs, + bool HadMultipleCandidates, + bool ListInitialization, + bool ZeroInitialization, + ConstructionKind ConstructKind, + SourceRange ParenRange); + + /// \brief Construct an empty C++ construction expression. + CXXConstructExpr(StmtClass SC, EmptyShell Empty) + : Expr(SC, Empty), Constructor(0), NumArgs(0), Elidable(false), + HadMultipleCandidates(false), ListInitialization(false), + ZeroInitialization(false), ConstructKind(0), Args(0) + { } + +public: + /// \brief Construct an empty C++ construction expression. + explicit CXXConstructExpr(EmptyShell Empty) + : Expr(CXXConstructExprClass, Empty), Constructor(0), + NumArgs(0), Elidable(false), HadMultipleCandidates(false), + ListInitialization(false), ZeroInitialization(false), + ConstructKind(0), Args(0) + { } + + static CXXConstructExpr *Create(ASTContext &C, QualType T, + SourceLocation Loc, + CXXConstructorDecl *D, bool Elidable, + Expr **Args, unsigned NumArgs, + bool HadMultipleCandidates, + bool ListInitialization, + bool ZeroInitialization, + ConstructionKind ConstructKind, + SourceRange ParenRange); + + CXXConstructorDecl* getConstructor() const { return Constructor; } + void setConstructor(CXXConstructorDecl *C) { Constructor = C; } + + SourceLocation getLocation() const { return Loc; } + void setLocation(SourceLocation Loc) { this->Loc = Loc; } + + /// \brief Whether this construction is elidable. + bool isElidable() const { return Elidable; } + void setElidable(bool E) { Elidable = E; } + + /// \brief Whether the referred constructor was resolved from + /// an overloaded set having size greater than 1. + bool hadMultipleCandidates() const { return HadMultipleCandidates; } + void setHadMultipleCandidates(bool V) { HadMultipleCandidates = V; } + + /// \brief Whether this constructor call was written as list-initialization. + bool isListInitialization() const { return ListInitialization; } + void setListInitialization(bool V) { ListInitialization = V; } + + /// \brief Whether this construction first requires + /// zero-initialization before the initializer is called. + bool requiresZeroInitialization() const { return ZeroInitialization; } + void setRequiresZeroInitialization(bool ZeroInit) { + ZeroInitialization = ZeroInit; + } + + /// \brief Determines whether this constructor is actually constructing + /// a base class (rather than a complete object). + ConstructionKind getConstructionKind() const { + return (ConstructionKind)ConstructKind; + } + void setConstructionKind(ConstructionKind CK) { + ConstructKind = CK; + } + + typedef ExprIterator arg_iterator; + typedef ConstExprIterator const_arg_iterator; + + arg_iterator arg_begin() { return Args; } + arg_iterator arg_end() { return Args + NumArgs; } + const_arg_iterator arg_begin() const { return Args; } + const_arg_iterator arg_end() const { return Args + NumArgs; } + + Expr **getArgs() const { return reinterpret_cast<Expr **>(Args); } + unsigned getNumArgs() const { return NumArgs; } + + /// getArg - Return the specified argument. + Expr *getArg(unsigned Arg) { + assert(Arg < NumArgs && "Arg access out of range!"); + return cast<Expr>(Args[Arg]); + } + const Expr *getArg(unsigned Arg) const { + assert(Arg < NumArgs && "Arg access out of range!"); + return cast<Expr>(Args[Arg]); + } + + /// setArg - Set the specified argument. + void setArg(unsigned Arg, Expr *ArgExpr) { + assert(Arg < NumArgs && "Arg access out of range!"); + Args[Arg] = ArgExpr; + } + + SourceRange getSourceRange() const LLVM_READONLY; + SourceRange getParenRange() const { return ParenRange; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXConstructExprClass || + T->getStmtClass() == CXXTemporaryObjectExprClass; + } + static bool classof(const CXXConstructExpr *) { return true; } + + // Iterators + child_range children() { + return child_range(&Args[0], &Args[0]+NumArgs); + } + + friend class ASTStmtReader; +}; + +/// CXXFunctionalCastExpr - Represents an explicit C++ type conversion +/// that uses "functional" notion (C++ [expr.type.conv]). Example: @c +/// x = int(0.5); +class CXXFunctionalCastExpr : public ExplicitCastExpr { + SourceLocation TyBeginLoc; + SourceLocation RParenLoc; + + CXXFunctionalCastExpr(QualType ty, ExprValueKind VK, + TypeSourceInfo *writtenTy, + SourceLocation tyBeginLoc, CastKind kind, + Expr *castExpr, unsigned pathSize, + SourceLocation rParenLoc) + : ExplicitCastExpr(CXXFunctionalCastExprClass, ty, VK, kind, + castExpr, pathSize, writtenTy), + TyBeginLoc(tyBeginLoc), RParenLoc(rParenLoc) {} + + explicit CXXFunctionalCastExpr(EmptyShell Shell, unsigned PathSize) + : ExplicitCastExpr(CXXFunctionalCastExprClass, Shell, PathSize) { } + +public: + static CXXFunctionalCastExpr *Create(ASTContext &Context, QualType T, + ExprValueKind VK, + TypeSourceInfo *Written, + SourceLocation TyBeginLoc, + CastKind Kind, Expr *Op, + const CXXCastPath *Path, + SourceLocation RPLoc); + static CXXFunctionalCastExpr *CreateEmpty(ASTContext &Context, + unsigned PathSize); + + SourceLocation getTypeBeginLoc() const { return TyBeginLoc; } + void setTypeBeginLoc(SourceLocation L) { TyBeginLoc = L; } + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(TyBeginLoc, RParenLoc); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXFunctionalCastExprClass; + } + static bool classof(const CXXFunctionalCastExpr *) { return true; } +}; + +/// @brief Represents a C++ functional cast expression that builds a +/// temporary object. +/// +/// This expression type represents a C++ "functional" cast +/// (C++[expr.type.conv]) with N != 1 arguments that invokes a +/// constructor to build a temporary object. With N == 1 arguments the +/// functional cast expression will be represented by CXXFunctionalCastExpr. +/// Example: +/// @code +/// struct X { X(int, float); } +/// +/// X create_X() { +/// return X(1, 3.14f); // creates a CXXTemporaryObjectExpr +/// }; +/// @endcode +class CXXTemporaryObjectExpr : public CXXConstructExpr { + TypeSourceInfo *Type; + +public: + CXXTemporaryObjectExpr(ASTContext &C, CXXConstructorDecl *Cons, + TypeSourceInfo *Type, + Expr **Args,unsigned NumArgs, + SourceRange parenRange, + bool HadMultipleCandidates, + bool ZeroInitialization = false); + explicit CXXTemporaryObjectExpr(EmptyShell Empty) + : CXXConstructExpr(CXXTemporaryObjectExprClass, Empty), Type() { } + + TypeSourceInfo *getTypeSourceInfo() const { return Type; } + + SourceRange getSourceRange() const LLVM_READONLY; + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXTemporaryObjectExprClass; + } + static bool classof(const CXXTemporaryObjectExpr *) { return true; } + + friend class ASTStmtReader; +}; + +/// \brief A C++ lambda expression, which produces a function object +/// (of unspecified type) that can be invoked later. +/// +/// Example: +/// \code +/// void low_pass_filter(std::vector<double> &values, double cutoff) { +/// values.erase(std::remove_if(values.begin(), values.end(), +// [=](double value) { return value > cutoff; }); +/// } +/// \endcode +/// +/// Lambda expressions can capture local variables, either by copying +/// the values of those local variables at the time the function +/// object is constructed (not when it is called!) or by holding a +/// reference to the local variable. These captures can occur either +/// implicitly or can be written explicitly between the square +/// brackets ([...]) that start the lambda expression. +class LambdaExpr : public Expr { + enum { + /// \brief Flag used by the Capture class to indicate that the given + /// capture was implicit. + Capture_Implicit = 0x01, + + /// \brief Flag used by the Capture class to indciate that the + /// given capture was by-copy. + Capture_ByCopy = 0x02 + }; + + /// \brief The source range that covers the lambda introducer ([...]). + SourceRange IntroducerRange; + + /// \brief The number of captures. + unsigned NumCaptures : 16; + + /// \brief The default capture kind, which is a value of type + /// LambdaCaptureDefault. + unsigned CaptureDefault : 2; + + /// \brief Whether this lambda had an explicit parameter list vs. an + /// implicit (and empty) parameter list. + unsigned ExplicitParams : 1; + + /// \brief Whether this lambda had the result type explicitly specified. + unsigned ExplicitResultType : 1; + + /// \brief Whether there are any array index variables stored at the end of + /// this lambda expression. + unsigned HasArrayIndexVars : 1; + + /// \brief The location of the closing brace ('}') that completes + /// the lambda. + /// + /// The location of the brace is also available by looking up the + /// function call operator in the lambda class. However, it is + /// stored here to improve the performance of getSourceRange(), and + /// to avoid having to deserialize the function call operator from a + /// module file just to determine the source range. + SourceLocation ClosingBrace; + + // Note: The capture initializers are stored directly after the lambda + // expression, along with the index variables used to initialize by-copy + // array captures. + +public: + /// \brief Describes the capture of either a variable or 'this'. + class Capture { + llvm::PointerIntPair<VarDecl *, 2> VarAndBits; + SourceLocation Loc; + SourceLocation EllipsisLoc; + + friend class ASTStmtReader; + friend class ASTStmtWriter; + + public: + /// \brief Create a new capture. + /// + /// \param Loc The source location associated with this capture. + /// + /// \param Kind The kind of capture (this, byref, bycopy). + /// + /// \param Implicit Whether the capture was implicit or explicit. + /// + /// \param Var The local variable being captured, or null if capturing this. + /// + /// \param EllipsisLoc The location of the ellipsis (...) for a + /// capture that is a pack expansion, or an invalid source + /// location to indicate that this is not a pack expansion. + Capture(SourceLocation Loc, bool Implicit, + LambdaCaptureKind Kind, VarDecl *Var = 0, + SourceLocation EllipsisLoc = SourceLocation()); + + /// \brief Determine the kind of capture. + LambdaCaptureKind getCaptureKind() const; + + /// \brief Determine whether this capture handles the C++ 'this' + /// pointer. + bool capturesThis() const { return VarAndBits.getPointer() == 0; } + + /// \brief Determine whether this capture handles a variable. + bool capturesVariable() const { return VarAndBits.getPointer() != 0; } + + /// \brief Retrieve the declaration of the local variable being + /// captured. + /// + /// This operation is only valid if this capture does not capture + /// 'this'. + VarDecl *getCapturedVar() const { + assert(!capturesThis() && "No variable available for 'this' capture"); + return VarAndBits.getPointer(); + } + + /// \brief Determine whether this was an implicit capture (not + /// written between the square brackets introducing the lambda). + bool isImplicit() const { return VarAndBits.getInt() & Capture_Implicit; } + + /// \brief Determine whether this was an explicit capture, written + /// between the square brackets introducing the lambda. + bool isExplicit() const { return !isImplicit(); } + + /// \brief Retrieve the source location of the capture. + /// + /// For an explicit capture, this returns the location of the + /// explicit capture in the source. For an implicit capture, this + /// returns the location at which the variable or 'this' was first + /// used. + SourceLocation getLocation() const { return Loc; } + + /// \brief Determine whether this capture is a pack expansion, + /// which captures a function parameter pack. + bool isPackExpansion() const { return EllipsisLoc.isValid(); } + + /// \brief Retrieve the location of the ellipsis for a capture + /// that is a pack expansion. + SourceLocation getEllipsisLoc() const { + assert(isPackExpansion() && "No ellipsis location for a non-expansion"); + return EllipsisLoc; + } + }; + +private: + /// \brief Construct a lambda expression. + LambdaExpr(QualType T, SourceRange IntroducerRange, + LambdaCaptureDefault CaptureDefault, + ArrayRef<Capture> Captures, + bool ExplicitParams, + bool ExplicitResultType, + ArrayRef<Expr *> CaptureInits, + ArrayRef<VarDecl *> ArrayIndexVars, + ArrayRef<unsigned> ArrayIndexStarts, + SourceLocation ClosingBrace); + + /// \brief Construct an empty lambda expression. + LambdaExpr(EmptyShell Empty, unsigned NumCaptures, bool HasArrayIndexVars) + : Expr(LambdaExprClass, Empty), + NumCaptures(NumCaptures), CaptureDefault(LCD_None), ExplicitParams(false), + ExplicitResultType(false), HasArrayIndexVars(true) { + getStoredStmts()[NumCaptures] = 0; + } + + Stmt **getStoredStmts() const { + return reinterpret_cast<Stmt **>(const_cast<LambdaExpr *>(this) + 1); + } + + /// \brief Retrieve the mapping from captures to the first array index + /// variable. + unsigned *getArrayIndexStarts() const { + return reinterpret_cast<unsigned *>(getStoredStmts() + NumCaptures + 1); + } + + /// \brief Retrieve the complete set of array-index variables. + VarDecl **getArrayIndexVars() const { + return reinterpret_cast<VarDecl **>( + getArrayIndexStarts() + NumCaptures + 1); + } + +public: + /// \brief Construct a new lambda expression. + static LambdaExpr *Create(ASTContext &C, + CXXRecordDecl *Class, + SourceRange IntroducerRange, + LambdaCaptureDefault CaptureDefault, + ArrayRef<Capture> Captures, + bool ExplicitParams, + bool ExplicitResultType, + ArrayRef<Expr *> CaptureInits, + ArrayRef<VarDecl *> ArrayIndexVars, + ArrayRef<unsigned> ArrayIndexStarts, + SourceLocation ClosingBrace); + + /// \brief Construct a new lambda expression that will be deserialized from + /// an external source. + static LambdaExpr *CreateDeserialized(ASTContext &C, unsigned NumCaptures, + unsigned NumArrayIndexVars); + + /// \brief Determine the default capture kind for this lambda. + LambdaCaptureDefault getCaptureDefault() const { + return static_cast<LambdaCaptureDefault>(CaptureDefault); + } + + /// \brief An iterator that walks over the captures of the lambda, + /// both implicit and explicit. + typedef const Capture *capture_iterator; + + /// \brief Retrieve an iterator pointing to the first lambda capture. + capture_iterator capture_begin() const; + + /// \brief Retrieve an iterator pointing past the end of the + /// sequence of lambda captures. + capture_iterator capture_end() const; + + /// \brief Determine the number of captures in this lambda. + unsigned capture_size() const { return NumCaptures; } + + /// \brief Retrieve an iterator pointing to the first explicit + /// lambda capture. + capture_iterator explicit_capture_begin() const; + + /// \brief Retrieve an iterator pointing past the end of the sequence of + /// explicit lambda captures. + capture_iterator explicit_capture_end() const; + + /// \brief Retrieve an iterator pointing to the first implicit + /// lambda capture. + capture_iterator implicit_capture_begin() const; + + /// \brief Retrieve an iterator pointing past the end of the sequence of + /// implicit lambda captures. + capture_iterator implicit_capture_end() const; + + /// \brief Iterator that walks over the capture initialization + /// arguments. + typedef Expr **capture_init_iterator; + + /// \brief Retrieve the first initialization argument for this + /// lambda expression (which initializes the first capture field). + capture_init_iterator capture_init_begin() const { + return reinterpret_cast<Expr **>(getStoredStmts()); + } + + /// \brief Retrieve the iterator pointing one past the last + /// initialization argument for this lambda expression. + capture_init_iterator capture_init_end() const { + return capture_init_begin() + NumCaptures; + } + + /// \brief Retrieve the set of index variables used in the capture + /// initializer of an array captured by copy. + /// + /// \param Iter The iterator that points at the capture initializer for + /// which we are extracting the corresponding index variables. + ArrayRef<VarDecl *> getCaptureInitIndexVars(capture_init_iterator Iter) const; + + /// \brief Retrieve the source range covering the lambda introducer, + /// which contains the explicit capture list surrounded by square + /// brackets ([...]). + SourceRange getIntroducerRange() const { return IntroducerRange; } + + /// \brief Retrieve the class that corresponds to the lambda, which + /// stores the captures in its fields and provides the various + /// operations permitted on a lambda (copying, calling). + CXXRecordDecl *getLambdaClass() const; + + /// \brief Retrieve the function call operator associated with this + /// lambda expression. + CXXMethodDecl *getCallOperator() const; + + /// \brief Retrieve the body of the lambda. + CompoundStmt *getBody() const; + + /// \brief Determine whether the lambda is mutable, meaning that any + /// captures values can be modified. + bool isMutable() const; + + /// \brief Determine whether this lambda has an explicit parameter + /// list vs. an implicit (empty) parameter list. + bool hasExplicitParameters() const { return ExplicitParams; } + + /// \brief Whether this lambda had its result type explicitly specified. + bool hasExplicitResultType() const { return ExplicitResultType; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == LambdaExprClass; + } + static bool classof(const LambdaExpr *) { return true; } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(IntroducerRange.getBegin(), ClosingBrace); + } + + child_range children() { + return child_range(getStoredStmts(), getStoredStmts() + NumCaptures + 1); + } + + friend class ASTStmtReader; + friend class ASTStmtWriter; +}; + +/// CXXScalarValueInitExpr - [C++ 5.2.3p2] +/// Expression "T()" which creates a value-initialized rvalue of type +/// T, which is a non-class type. +/// +class CXXScalarValueInitExpr : public Expr { + SourceLocation RParenLoc; + TypeSourceInfo *TypeInfo; + + friend class ASTStmtReader; + +public: + /// \brief Create an explicitly-written scalar-value initialization + /// expression. + CXXScalarValueInitExpr(QualType Type, + TypeSourceInfo *TypeInfo, + SourceLocation rParenLoc ) : + Expr(CXXScalarValueInitExprClass, Type, VK_RValue, OK_Ordinary, + false, false, Type->isInstantiationDependentType(), false), + RParenLoc(rParenLoc), TypeInfo(TypeInfo) {} + + explicit CXXScalarValueInitExpr(EmptyShell Shell) + : Expr(CXXScalarValueInitExprClass, Shell) { } + + TypeSourceInfo *getTypeSourceInfo() const { + return TypeInfo; + } + + SourceLocation getRParenLoc() const { return RParenLoc; } + + SourceRange getSourceRange() const LLVM_READONLY; + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXScalarValueInitExprClass; + } + static bool classof(const CXXScalarValueInitExpr *) { return true; } + + // Iterators + child_range children() { return child_range(); } +}; + +/// CXXNewExpr - A new expression for memory allocation and constructor calls, +/// e.g: "new CXXNewExpr(foo)". +class CXXNewExpr : public Expr { + // Contains an optional array size expression, an optional initialization + // expression, and any number of optional placement arguments, in that order. + Stmt **SubExprs; + // Points to the allocation function used. + FunctionDecl *OperatorNew; + // Points to the deallocation function used in case of error. May be null. + FunctionDecl *OperatorDelete; + + /// \brief The allocated type-source information, as written in the source. + TypeSourceInfo *AllocatedTypeInfo; + + /// \brief If the allocated type was expressed as a parenthesized type-id, + /// the source range covering the parenthesized type-id. + SourceRange TypeIdParens; + + /// \brief Location of the first token. + SourceLocation StartLoc; + + /// \brief Source-range of a paren-delimited initializer. + SourceRange DirectInitRange; + + // Was the usage ::new, i.e. is the global new to be used? + bool GlobalNew : 1; + // Do we allocate an array? If so, the first SubExpr is the size expression. + bool Array : 1; + // If this is an array allocation, does the usual deallocation + // function for the allocated type want to know the allocated size? + bool UsualArrayDeleteWantsSize : 1; + // The number of placement new arguments. + unsigned NumPlacementArgs : 13; + // What kind of initializer do we have? Could be none, parens, or braces. + // In storage, we distinguish between "none, and no initializer expr", and + // "none, but an implicit initializer expr". + unsigned StoredInitializationStyle : 2; + + friend class ASTStmtReader; + friend class ASTStmtWriter; +public: + enum InitializationStyle { + NoInit, ///< New-expression has no initializer as written. + CallInit, ///< New-expression has a C++98 paren-delimited initializer. + ListInit ///< New-expression has a C++11 list-initializer. + }; + + CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew, + FunctionDecl *operatorDelete, bool usualArrayDeleteWantsSize, + Expr **placementArgs, unsigned numPlaceArgs, + SourceRange typeIdParens, Expr *arraySize, + InitializationStyle initializationStyle, Expr *initializer, + QualType ty, TypeSourceInfo *AllocatedTypeInfo, + SourceLocation startLoc, SourceRange directInitRange); + explicit CXXNewExpr(EmptyShell Shell) + : Expr(CXXNewExprClass, Shell), SubExprs(0) { } + + void AllocateArgsArray(ASTContext &C, bool isArray, unsigned numPlaceArgs, + bool hasInitializer); + + QualType getAllocatedType() const { + assert(getType()->isPointerType()); + return getType()->getAs<PointerType>()->getPointeeType(); + } + + TypeSourceInfo *getAllocatedTypeSourceInfo() const { + return AllocatedTypeInfo; + } + + /// \brief True if the allocation result needs to be null-checked. + /// C++0x [expr.new]p13: + /// If the allocation function returns null, initialization shall + /// not be done, the deallocation function shall not be called, + /// and the value of the new-expression shall be null. + /// An allocation function is not allowed to return null unless it + /// has a non-throwing exception-specification. The '03 rule is + /// identical except that the definition of a non-throwing + /// exception specification is just "is it throw()?". + bool shouldNullCheckAllocation(ASTContext &Ctx) const; + + FunctionDecl *getOperatorNew() const { return OperatorNew; } + void setOperatorNew(FunctionDecl *D) { OperatorNew = D; } + FunctionDecl *getOperatorDelete() const { return OperatorDelete; } + void setOperatorDelete(FunctionDecl *D) { OperatorDelete = D; } + + bool isArray() const { return Array; } + Expr *getArraySize() { + return Array ? cast<Expr>(SubExprs[0]) : 0; + } + const Expr *getArraySize() const { + return Array ? cast<Expr>(SubExprs[0]) : 0; + } + + unsigned getNumPlacementArgs() const { return NumPlacementArgs; } + Expr **getPlacementArgs() { + return reinterpret_cast<Expr **>(SubExprs + Array + hasInitializer()); + } + + Expr *getPlacementArg(unsigned i) { + assert(i < NumPlacementArgs && "Index out of range"); + return getPlacementArgs()[i]; + } + const Expr *getPlacementArg(unsigned i) const { + assert(i < NumPlacementArgs && "Index out of range"); + return const_cast<CXXNewExpr*>(this)->getPlacementArg(i); + } + + bool isParenTypeId() const { return TypeIdParens.isValid(); } + SourceRange getTypeIdParens() const { return TypeIdParens; } + + bool isGlobalNew() const { return GlobalNew; } + + /// \brief Whether this new-expression has any initializer at all. + bool hasInitializer() const { return StoredInitializationStyle > 0; } + + /// \brief The kind of initializer this new-expression has. + InitializationStyle getInitializationStyle() const { + if (StoredInitializationStyle == 0) + return NoInit; + return static_cast<InitializationStyle>(StoredInitializationStyle-1); + } + + /// \brief The initializer of this new-expression. + Expr *getInitializer() { + return hasInitializer() ? cast<Expr>(SubExprs[Array]) : 0; + } + const Expr *getInitializer() const { + return hasInitializer() ? cast<Expr>(SubExprs[Array]) : 0; + } + + /// \brief Returns the CXXConstructExpr from this new-expression, or NULL. + const CXXConstructExpr* getConstructExpr() { + return dyn_cast_or_null<CXXConstructExpr>(getInitializer()); + } + + /// Answers whether the usual array deallocation function for the + /// allocated type expects the size of the allocation as a + /// parameter. + bool doesUsualArrayDeleteWantSize() const { + return UsualArrayDeleteWantsSize; + } + + typedef ExprIterator arg_iterator; + typedef ConstExprIterator const_arg_iterator; + + arg_iterator placement_arg_begin() { + return SubExprs + Array + hasInitializer(); + } + arg_iterator placement_arg_end() { + return SubExprs + Array + hasInitializer() + getNumPlacementArgs(); + } + const_arg_iterator placement_arg_begin() const { + return SubExprs + Array + hasInitializer(); + } + const_arg_iterator placement_arg_end() const { + return SubExprs + Array + hasInitializer() + getNumPlacementArgs(); + } + + typedef Stmt **raw_arg_iterator; + raw_arg_iterator raw_arg_begin() { return SubExprs; } + raw_arg_iterator raw_arg_end() { + return SubExprs + Array + hasInitializer() + getNumPlacementArgs(); + } + const_arg_iterator raw_arg_begin() const { return SubExprs; } + const_arg_iterator raw_arg_end() const { + return SubExprs + Array + hasInitializer() + getNumPlacementArgs(); + } + + SourceLocation getStartLoc() const { return StartLoc; } + SourceLocation getEndLoc() const; + + SourceRange getDirectInitRange() const { return DirectInitRange; } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(getStartLoc(), getEndLoc()); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXNewExprClass; + } + static bool classof(const CXXNewExpr *) { return true; } + + // Iterators + child_range children() { + return child_range(raw_arg_begin(), raw_arg_end()); + } +}; + +/// CXXDeleteExpr - A delete expression for memory deallocation and destructor +/// calls, e.g. "delete[] pArray". +class CXXDeleteExpr : public Expr { + // Points to the operator delete overload that is used. Could be a member. + FunctionDecl *OperatorDelete; + // The pointer expression to be deleted. + Stmt *Argument; + // Location of the expression. + SourceLocation Loc; + // Is this a forced global delete, i.e. "::delete"? + bool GlobalDelete : 1; + // Is this the array form of delete, i.e. "delete[]"? + bool ArrayForm : 1; + // ArrayFormAsWritten can be different from ArrayForm if 'delete' is applied + // to pointer-to-array type (ArrayFormAsWritten will be false while ArrayForm + // will be true). + bool ArrayFormAsWritten : 1; + // Does the usual deallocation function for the element type require + // a size_t argument? + bool UsualArrayDeleteWantsSize : 1; +public: + CXXDeleteExpr(QualType ty, bool globalDelete, bool arrayForm, + bool arrayFormAsWritten, bool usualArrayDeleteWantsSize, + FunctionDecl *operatorDelete, Expr *arg, SourceLocation loc) + : Expr(CXXDeleteExprClass, ty, VK_RValue, OK_Ordinary, false, false, + arg->isInstantiationDependent(), + arg->containsUnexpandedParameterPack()), + OperatorDelete(operatorDelete), Argument(arg), Loc(loc), + GlobalDelete(globalDelete), + ArrayForm(arrayForm), ArrayFormAsWritten(arrayFormAsWritten), + UsualArrayDeleteWantsSize(usualArrayDeleteWantsSize) { } + explicit CXXDeleteExpr(EmptyShell Shell) + : Expr(CXXDeleteExprClass, Shell), OperatorDelete(0), Argument(0) { } + + bool isGlobalDelete() const { return GlobalDelete; } + bool isArrayForm() const { return ArrayForm; } + bool isArrayFormAsWritten() const { return ArrayFormAsWritten; } + + /// Answers whether the usual array deallocation function for the + /// allocated type expects the size of the allocation as a + /// parameter. This can be true even if the actual deallocation + /// function that we're using doesn't want a size. + bool doesUsualArrayDeleteWantSize() const { + return UsualArrayDeleteWantsSize; + } + + FunctionDecl *getOperatorDelete() const { return OperatorDelete; } + + Expr *getArgument() { return cast<Expr>(Argument); } + const Expr *getArgument() const { return cast<Expr>(Argument); } + + /// \brief Retrieve the type being destroyed. If the type being + /// destroyed is a dependent type which may or may not be a pointer, + /// return an invalid type. + QualType getDestroyedType() const; + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(Loc, Argument->getLocEnd()); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXDeleteExprClass; + } + static bool classof(const CXXDeleteExpr *) { return true; } + + // Iterators + child_range children() { return child_range(&Argument, &Argument+1); } + + friend class ASTStmtReader; +}; + +/// \brief Structure used to store the type being destroyed by a +/// pseudo-destructor expression. +class PseudoDestructorTypeStorage { + /// \brief Either the type source information or the name of the type, if + /// it couldn't be resolved due to type-dependence. + llvm::PointerUnion<TypeSourceInfo *, IdentifierInfo *> Type; + + /// \brief The starting source location of the pseudo-destructor type. + SourceLocation Location; + +public: + PseudoDestructorTypeStorage() { } + + PseudoDestructorTypeStorage(IdentifierInfo *II, SourceLocation Loc) + : Type(II), Location(Loc) { } + + PseudoDestructorTypeStorage(TypeSourceInfo *Info); + + TypeSourceInfo *getTypeSourceInfo() const { + return Type.dyn_cast<TypeSourceInfo *>(); + } + + IdentifierInfo *getIdentifier() const { + return Type.dyn_cast<IdentifierInfo *>(); + } + + SourceLocation getLocation() const { return Location; } +}; + +/// \brief Represents a C++ pseudo-destructor (C++ [expr.pseudo]). +/// +/// A pseudo-destructor is an expression that looks like a member access to a +/// destructor of a scalar type, except that scalar types don't have +/// destructors. For example: +/// +/// \code +/// typedef int T; +/// void f(int *p) { +/// p->T::~T(); +/// } +/// \endcode +/// +/// Pseudo-destructors typically occur when instantiating templates such as: +/// +/// \code +/// template<typename T> +/// void destroy(T* ptr) { +/// ptr->T::~T(); +/// } +/// \endcode +/// +/// for scalar types. A pseudo-destructor expression has no run-time semantics +/// beyond evaluating the base expression. +class CXXPseudoDestructorExpr : public Expr { + /// \brief The base expression (that is being destroyed). + Stmt *Base; + + /// \brief Whether the operator was an arrow ('->'); otherwise, it was a + /// period ('.'). + bool IsArrow : 1; + + /// \brief The location of the '.' or '->' operator. + SourceLocation OperatorLoc; + + /// \brief The nested-name-specifier that follows the operator, if present. + NestedNameSpecifierLoc QualifierLoc; + + /// \brief The type that precedes the '::' in a qualified pseudo-destructor + /// expression. + TypeSourceInfo *ScopeType; + + /// \brief The location of the '::' in a qualified pseudo-destructor + /// expression. + SourceLocation ColonColonLoc; + + /// \brief The location of the '~'. + SourceLocation TildeLoc; + + /// \brief The type being destroyed, or its name if we were unable to + /// resolve the name. + PseudoDestructorTypeStorage DestroyedType; + + friend class ASTStmtReader; + +public: + CXXPseudoDestructorExpr(ASTContext &Context, + Expr *Base, bool isArrow, SourceLocation OperatorLoc, + NestedNameSpecifierLoc QualifierLoc, + TypeSourceInfo *ScopeType, + SourceLocation ColonColonLoc, + SourceLocation TildeLoc, + PseudoDestructorTypeStorage DestroyedType); + + explicit CXXPseudoDestructorExpr(EmptyShell Shell) + : Expr(CXXPseudoDestructorExprClass, Shell), + Base(0), IsArrow(false), QualifierLoc(), ScopeType(0) { } + + Expr *getBase() const { return cast<Expr>(Base); } + + /// \brief Determines whether this member expression actually had + /// a C++ nested-name-specifier prior to the name of the member, e.g., + /// x->Base::foo. + bool hasQualifier() const { return QualifierLoc; } + + /// \brief Retrieves the nested-name-specifier that qualifies the type name, + /// with source-location information. + NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; } + + /// \brief If the member name was qualified, retrieves the + /// nested-name-specifier that precedes the member name. Otherwise, returns + /// NULL. + NestedNameSpecifier *getQualifier() const { + return QualifierLoc.getNestedNameSpecifier(); + } + + /// \brief Determine whether this pseudo-destructor expression was written + /// using an '->' (otherwise, it used a '.'). + bool isArrow() const { return IsArrow; } + + /// \brief Retrieve the location of the '.' or '->' operator. + SourceLocation getOperatorLoc() const { return OperatorLoc; } + + /// \brief Retrieve the scope type in a qualified pseudo-destructor + /// expression. + /// + /// Pseudo-destructor expressions can have extra qualification within them + /// that is not part of the nested-name-specifier, e.g., \c p->T::~T(). + /// Here, if the object type of the expression is (or may be) a scalar type, + /// \p T may also be a scalar type and, therefore, cannot be part of a + /// nested-name-specifier. It is stored as the "scope type" of the pseudo- + /// destructor expression. + TypeSourceInfo *getScopeTypeInfo() const { return ScopeType; } + + /// \brief Retrieve the location of the '::' in a qualified pseudo-destructor + /// expression. + SourceLocation getColonColonLoc() const { return ColonColonLoc; } + + /// \brief Retrieve the location of the '~'. + SourceLocation getTildeLoc() const { return TildeLoc; } + + /// \brief Retrieve the source location information for the type + /// being destroyed. + /// + /// This type-source information is available for non-dependent + /// pseudo-destructor expressions and some dependent pseudo-destructor + /// expressions. Returns NULL if we only have the identifier for a + /// dependent pseudo-destructor expression. + TypeSourceInfo *getDestroyedTypeInfo() const { + return DestroyedType.getTypeSourceInfo(); + } + + /// \brief In a dependent pseudo-destructor expression for which we do not + /// have full type information on the destroyed type, provides the name + /// of the destroyed type. + IdentifierInfo *getDestroyedTypeIdentifier() const { + return DestroyedType.getIdentifier(); + } + + /// \brief Retrieve the type being destroyed. + QualType getDestroyedType() const; + + /// \brief Retrieve the starting location of the type being destroyed. + SourceLocation getDestroyedTypeLoc() const { + return DestroyedType.getLocation(); + } + + /// \brief Set the name of destroyed type for a dependent pseudo-destructor + /// expression. + void setDestroyedType(IdentifierInfo *II, SourceLocation Loc) { + DestroyedType = PseudoDestructorTypeStorage(II, Loc); + } + + /// \brief Set the destroyed type. + void setDestroyedType(TypeSourceInfo *Info) { + DestroyedType = PseudoDestructorTypeStorage(Info); + } + + SourceRange getSourceRange() const LLVM_READONLY; + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXPseudoDestructorExprClass; + } + static bool classof(const CXXPseudoDestructorExpr *) { return true; } + + // Iterators + child_range children() { return child_range(&Base, &Base + 1); } +}; + +/// UnaryTypeTraitExpr - A GCC or MS unary type trait, as used in the +/// implementation of TR1/C++0x type trait templates. +/// Example: +/// __is_pod(int) == true +/// __is_enum(std::string) == false +class UnaryTypeTraitExpr : public Expr { + /// UTT - The trait. A UnaryTypeTrait enum in MSVC compat unsigned. + unsigned UTT : 31; + /// The value of the type trait. Unspecified if dependent. + bool Value : 1; + + /// Loc - The location of the type trait keyword. + SourceLocation Loc; + + /// RParen - The location of the closing paren. + SourceLocation RParen; + + /// The type being queried. + TypeSourceInfo *QueriedType; + +public: + UnaryTypeTraitExpr(SourceLocation loc, UnaryTypeTrait utt, + TypeSourceInfo *queried, bool value, + SourceLocation rparen, QualType ty) + : Expr(UnaryTypeTraitExprClass, ty, VK_RValue, OK_Ordinary, + false, queried->getType()->isDependentType(), + queried->getType()->isInstantiationDependentType(), + queried->getType()->containsUnexpandedParameterPack()), + UTT(utt), Value(value), Loc(loc), RParen(rparen), QueriedType(queried) { } + + explicit UnaryTypeTraitExpr(EmptyShell Empty) + : Expr(UnaryTypeTraitExprClass, Empty), UTT(0), Value(false), + QueriedType() { } + + SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(Loc, RParen);} + + UnaryTypeTrait getTrait() const { return static_cast<UnaryTypeTrait>(UTT); } + + QualType getQueriedType() const { return QueriedType->getType(); } + + TypeSourceInfo *getQueriedTypeSourceInfo() const { return QueriedType; } + + bool getValue() const { return Value; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == UnaryTypeTraitExprClass; + } + static bool classof(const UnaryTypeTraitExpr *) { return true; } + + // Iterators + child_range children() { return child_range(); } + + friend class ASTStmtReader; +}; + +/// BinaryTypeTraitExpr - A GCC or MS binary type trait, as used in the +/// implementation of TR1/C++0x type trait templates. +/// Example: +/// __is_base_of(Base, Derived) == true +class BinaryTypeTraitExpr : public Expr { + /// BTT - The trait. A BinaryTypeTrait enum in MSVC compat unsigned. + unsigned BTT : 8; + + /// The value of the type trait. Unspecified if dependent. + bool Value : 1; + + /// Loc - The location of the type trait keyword. + SourceLocation Loc; + + /// RParen - The location of the closing paren. + SourceLocation RParen; + + /// The lhs type being queried. + TypeSourceInfo *LhsType; + + /// The rhs type being queried. + TypeSourceInfo *RhsType; + +public: + BinaryTypeTraitExpr(SourceLocation loc, BinaryTypeTrait btt, + TypeSourceInfo *lhsType, TypeSourceInfo *rhsType, + bool value, SourceLocation rparen, QualType ty) + : Expr(BinaryTypeTraitExprClass, ty, VK_RValue, OK_Ordinary, false, + lhsType->getType()->isDependentType() || + rhsType->getType()->isDependentType(), + (lhsType->getType()->isInstantiationDependentType() || + rhsType->getType()->isInstantiationDependentType()), + (lhsType->getType()->containsUnexpandedParameterPack() || + rhsType->getType()->containsUnexpandedParameterPack())), + BTT(btt), Value(value), Loc(loc), RParen(rparen), + LhsType(lhsType), RhsType(rhsType) { } + + + explicit BinaryTypeTraitExpr(EmptyShell Empty) + : Expr(BinaryTypeTraitExprClass, Empty), BTT(0), Value(false), + LhsType(), RhsType() { } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(Loc, RParen); + } + + BinaryTypeTrait getTrait() const { + return static_cast<BinaryTypeTrait>(BTT); + } + + QualType getLhsType() const { return LhsType->getType(); } + QualType getRhsType() const { return RhsType->getType(); } + + TypeSourceInfo *getLhsTypeSourceInfo() const { return LhsType; } + TypeSourceInfo *getRhsTypeSourceInfo() const { return RhsType; } + + bool getValue() const { assert(!isTypeDependent()); return Value; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == BinaryTypeTraitExprClass; + } + static bool classof(const BinaryTypeTraitExpr *) { return true; } + + // Iterators + child_range children() { return child_range(); } + + friend class ASTStmtReader; +}; + +/// \brief A type trait used in the implementation of various C++11 and +/// Library TR1 trait templates. +/// +/// \code +/// __is_trivially_constructible(vector<int>, int*, int*) +/// \endcode +class TypeTraitExpr : public Expr { + /// \brief The location of the type trait keyword. + SourceLocation Loc; + + /// \brief The location of the closing parenthesis. + SourceLocation RParenLoc; + + // Note: The TypeSourceInfos for the arguments are allocated after the + // TypeTraitExpr. + + TypeTraitExpr(QualType T, SourceLocation Loc, TypeTrait Kind, + ArrayRef<TypeSourceInfo *> Args, + SourceLocation RParenLoc, + bool Value); + + TypeTraitExpr(EmptyShell Empty) : Expr(TypeTraitExprClass, Empty) { } + + /// \brief Retrieve the argument types. + TypeSourceInfo **getTypeSourceInfos() { + return reinterpret_cast<TypeSourceInfo **>(this+1); + } + + /// \brief Retrieve the argument types. + TypeSourceInfo * const *getTypeSourceInfos() const { + return reinterpret_cast<TypeSourceInfo * const*>(this+1); + } + +public: + /// \brief Create a new type trait expression. + static TypeTraitExpr *Create(ASTContext &C, QualType T, SourceLocation Loc, + TypeTrait Kind, + ArrayRef<TypeSourceInfo *> Args, + SourceLocation RParenLoc, + bool Value); + + static TypeTraitExpr *CreateDeserialized(ASTContext &C, unsigned NumArgs); + + /// \brief Determine which type trait this expression uses. + TypeTrait getTrait() const { + return static_cast<TypeTrait>(TypeTraitExprBits.Kind); + } + + bool getValue() const { + assert(!isValueDependent()); + return TypeTraitExprBits.Value; + } + + /// \brief Determine the number of arguments to this type trait. + unsigned getNumArgs() const { return TypeTraitExprBits.NumArgs; } + + /// \brief Retrieve the Ith argument. + TypeSourceInfo *getArg(unsigned I) const { + assert(I < getNumArgs() && "Argument out-of-range"); + return getArgs()[I]; + } + + /// \brief Retrieve the argument types. + ArrayRef<TypeSourceInfo *> getArgs() const { + return ArrayRef<TypeSourceInfo *>(getTypeSourceInfos(), getNumArgs()); + } + + typedef TypeSourceInfo **arg_iterator; + arg_iterator arg_begin() { + return getTypeSourceInfos(); + } + arg_iterator arg_end() { + return getTypeSourceInfos() + getNumArgs(); + } + + typedef TypeSourceInfo const * const *arg_const_iterator; + arg_const_iterator arg_begin() const { return getTypeSourceInfos(); } + arg_const_iterator arg_end() const { + return getTypeSourceInfos() + getNumArgs(); + } + + SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(Loc, RParenLoc); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == TypeTraitExprClass; + } + static bool classof(const TypeTraitExpr *) { return true; } + + // Iterators + child_range children() { return child_range(); } + + friend class ASTStmtReader; + friend class ASTStmtWriter; + +}; + +/// ArrayTypeTraitExpr - An Embarcadero array type trait, as used in the +/// implementation of __array_rank and __array_extent. +/// Example: +/// __array_rank(int[10][20]) == 2 +/// __array_extent(int, 1) == 20 +class ArrayTypeTraitExpr : public Expr { + virtual void anchor(); + + /// ATT - The trait. An ArrayTypeTrait enum in MSVC compat unsigned. + unsigned ATT : 2; + + /// The value of the type trait. Unspecified if dependent. + uint64_t Value; + + /// The array dimension being queried, or -1 if not used + Expr *Dimension; + + /// Loc - The location of the type trait keyword. + SourceLocation Loc; + + /// RParen - The location of the closing paren. + SourceLocation RParen; + + /// The type being queried. + TypeSourceInfo *QueriedType; + +public: + ArrayTypeTraitExpr(SourceLocation loc, ArrayTypeTrait att, + TypeSourceInfo *queried, uint64_t value, + Expr *dimension, SourceLocation rparen, QualType ty) + : Expr(ArrayTypeTraitExprClass, ty, VK_RValue, OK_Ordinary, + false, queried->getType()->isDependentType(), + (queried->getType()->isInstantiationDependentType() || + (dimension && dimension->isInstantiationDependent())), + queried->getType()->containsUnexpandedParameterPack()), + ATT(att), Value(value), Dimension(dimension), + Loc(loc), RParen(rparen), QueriedType(queried) { } + + + explicit ArrayTypeTraitExpr(EmptyShell Empty) + : Expr(ArrayTypeTraitExprClass, Empty), ATT(0), Value(false), + QueriedType() { } + + virtual ~ArrayTypeTraitExpr() { } + + virtual SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(Loc, RParen); + } + + ArrayTypeTrait getTrait() const { return static_cast<ArrayTypeTrait>(ATT); } + + QualType getQueriedType() const { return QueriedType->getType(); } + + TypeSourceInfo *getQueriedTypeSourceInfo() const { return QueriedType; } + + uint64_t getValue() const { assert(!isTypeDependent()); return Value; } + + Expr *getDimensionExpression() const { return Dimension; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ArrayTypeTraitExprClass; + } + static bool classof(const ArrayTypeTraitExpr *) { return true; } + + // Iterators + child_range children() { return child_range(); } + + friend class ASTStmtReader; +}; + +/// ExpressionTraitExpr - An expression trait intrinsic +/// Example: +/// __is_lvalue_expr(std::cout) == true +/// __is_lvalue_expr(1) == false +class ExpressionTraitExpr : public Expr { + /// ET - The trait. A ExpressionTrait enum in MSVC compat unsigned. + unsigned ET : 31; + /// The value of the type trait. Unspecified if dependent. + bool Value : 1; + + /// Loc - The location of the type trait keyword. + SourceLocation Loc; + + /// RParen - The location of the closing paren. + SourceLocation RParen; + + Expr* QueriedExpression; +public: + ExpressionTraitExpr(SourceLocation loc, ExpressionTrait et, + Expr *queried, bool value, + SourceLocation rparen, QualType resultType) + : Expr(ExpressionTraitExprClass, resultType, VK_RValue, OK_Ordinary, + false, // Not type-dependent + // Value-dependent if the argument is type-dependent. + queried->isTypeDependent(), + queried->isInstantiationDependent(), + queried->containsUnexpandedParameterPack()), + ET(et), Value(value), Loc(loc), RParen(rparen), + QueriedExpression(queried) { } + + explicit ExpressionTraitExpr(EmptyShell Empty) + : Expr(ExpressionTraitExprClass, Empty), ET(0), Value(false), + QueriedExpression() { } + + SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(Loc, RParen);} + + ExpressionTrait getTrait() const { return static_cast<ExpressionTrait>(ET); } + + Expr *getQueriedExpression() const { return QueriedExpression; } + + bool getValue() const { return Value; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ExpressionTraitExprClass; + } + static bool classof(const ExpressionTraitExpr *) { return true; } + + // Iterators + child_range children() { return child_range(); } + + friend class ASTStmtReader; +}; + + +/// \brief A reference to an overloaded function set, either an +/// \t UnresolvedLookupExpr or an \t UnresolvedMemberExpr. +class OverloadExpr : public Expr { + /// The common name of these declarations. + DeclarationNameInfo NameInfo; + + /// \brief The nested-name-specifier that qualifies the name, if any. + NestedNameSpecifierLoc QualifierLoc; + + /// The results. These are undesugared, which is to say, they may + /// include UsingShadowDecls. Access is relative to the naming + /// class. + // FIXME: Allocate this data after the OverloadExpr subclass. + DeclAccessPair *Results; + unsigned NumResults; + +protected: + /// \brief Whether the name includes info for explicit template + /// keyword and arguments. + bool HasTemplateKWAndArgsInfo; + + /// \brief Return the optional template keyword and arguments info. + ASTTemplateKWAndArgsInfo *getTemplateKWAndArgsInfo(); // defined far below. + + /// \brief Return the optional template keyword and arguments info. + const ASTTemplateKWAndArgsInfo *getTemplateKWAndArgsInfo() const { + return const_cast<OverloadExpr*>(this)->getTemplateKWAndArgsInfo(); + } + + OverloadExpr(StmtClass K, ASTContext &C, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation TemplateKWLoc, + const DeclarationNameInfo &NameInfo, + const TemplateArgumentListInfo *TemplateArgs, + UnresolvedSetIterator Begin, UnresolvedSetIterator End, + bool KnownDependent, + bool KnownInstantiationDependent, + bool KnownContainsUnexpandedParameterPack); + + OverloadExpr(StmtClass K, EmptyShell Empty) + : Expr(K, Empty), QualifierLoc(), Results(0), NumResults(0), + HasTemplateKWAndArgsInfo(false) { } + + void initializeResults(ASTContext &C, + UnresolvedSetIterator Begin, + UnresolvedSetIterator End); + +public: + struct FindResult { + OverloadExpr *Expression; + bool IsAddressOfOperand; + bool HasFormOfMemberPointer; + }; + + /// Finds the overloaded expression in the given expression of + /// OverloadTy. + /// + /// \return the expression (which must be there) and true if it has + /// the particular form of a member pointer expression + static FindResult find(Expr *E) { + assert(E->getType()->isSpecificBuiltinType(BuiltinType::Overload)); + + FindResult Result; + + E = E->IgnoreParens(); + if (isa<UnaryOperator>(E)) { + assert(cast<UnaryOperator>(E)->getOpcode() == UO_AddrOf); + E = cast<UnaryOperator>(E)->getSubExpr(); + OverloadExpr *Ovl = cast<OverloadExpr>(E->IgnoreParens()); + + Result.HasFormOfMemberPointer = (E == Ovl && Ovl->getQualifier()); + Result.IsAddressOfOperand = true; + Result.Expression = Ovl; + } else { + Result.HasFormOfMemberPointer = false; + Result.IsAddressOfOperand = false; + Result.Expression = cast<OverloadExpr>(E); + } + + return Result; + } + + /// Gets the naming class of this lookup, if any. + CXXRecordDecl *getNamingClass() const; + + typedef UnresolvedSetImpl::iterator decls_iterator; + decls_iterator decls_begin() const { return UnresolvedSetIterator(Results); } + decls_iterator decls_end() const { + return UnresolvedSetIterator(Results + NumResults); + } + + /// Gets the number of declarations in the unresolved set. + unsigned getNumDecls() const { return NumResults; } + + /// Gets the full name info. + const DeclarationNameInfo &getNameInfo() const { return NameInfo; } + + /// Gets the name looked up. + DeclarationName getName() const { return NameInfo.getName(); } + + /// Gets the location of the name. + SourceLocation getNameLoc() const { return NameInfo.getLoc(); } + + /// Fetches the nested-name qualifier, if one was given. + NestedNameSpecifier *getQualifier() const { + return QualifierLoc.getNestedNameSpecifier(); + } + + /// Fetches the nested-name qualifier with source-location information, if + /// one was given. + NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; } + + /// \brief Retrieve the location of the template keyword preceding + /// this name, if any. + SourceLocation getTemplateKeywordLoc() const { + if (!HasTemplateKWAndArgsInfo) return SourceLocation(); + return getTemplateKWAndArgsInfo()->getTemplateKeywordLoc(); + } + + /// \brief Retrieve the location of the left angle bracket starting the + /// explicit template argument list following the name, if any. + SourceLocation getLAngleLoc() const { + if (!HasTemplateKWAndArgsInfo) return SourceLocation(); + return getTemplateKWAndArgsInfo()->LAngleLoc; + } + + /// \brief Retrieve the location of the right angle bracket ending the + /// explicit template argument list following the name, if any. + SourceLocation getRAngleLoc() const { + if (!HasTemplateKWAndArgsInfo) return SourceLocation(); + return getTemplateKWAndArgsInfo()->RAngleLoc; + } + + /// Determines whether the name was preceded by the template keyword. + bool hasTemplateKeyword() const { return getTemplateKeywordLoc().isValid(); } + + /// Determines whether this expression had explicit template arguments. + bool hasExplicitTemplateArgs() const { return getLAngleLoc().isValid(); } + + // Note that, inconsistently with the explicit-template-argument AST + // nodes, users are *forbidden* from calling these methods on objects + // without explicit template arguments. + + ASTTemplateArgumentListInfo &getExplicitTemplateArgs() { + assert(hasExplicitTemplateArgs()); + return *getTemplateKWAndArgsInfo(); + } + + const ASTTemplateArgumentListInfo &getExplicitTemplateArgs() const { + return const_cast<OverloadExpr*>(this)->getExplicitTemplateArgs(); + } + + TemplateArgumentLoc const *getTemplateArgs() const { + return getExplicitTemplateArgs().getTemplateArgs(); + } + + unsigned getNumTemplateArgs() const { + return getExplicitTemplateArgs().NumTemplateArgs; + } + + /// Copies the template arguments into the given structure. + void copyTemplateArgumentsInto(TemplateArgumentListInfo &List) const { + getExplicitTemplateArgs().copyInto(List); + } + + /// \brief Retrieves the optional explicit template arguments. + /// This points to the same data as getExplicitTemplateArgs(), but + /// returns null if there are no explicit template arguments. + const ASTTemplateArgumentListInfo *getOptionalExplicitTemplateArgs() { + if (!hasExplicitTemplateArgs()) return 0; + return &getExplicitTemplateArgs(); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == UnresolvedLookupExprClass || + T->getStmtClass() == UnresolvedMemberExprClass; + } + static bool classof(const OverloadExpr *) { return true; } + + friend class ASTStmtReader; + friend class ASTStmtWriter; +}; + +/// \brief A reference to a name which we were able to look up during +/// parsing but could not resolve to a specific declaration. This +/// arises in several ways: +/// * we might be waiting for argument-dependent lookup +/// * the name might resolve to an overloaded function +/// and eventually: +/// * the lookup might have included a function template +/// These never include UnresolvedUsingValueDecls, which are always +/// class members and therefore appear only in +/// UnresolvedMemberLookupExprs. +class UnresolvedLookupExpr : public OverloadExpr { + /// True if these lookup results should be extended by + /// argument-dependent lookup if this is the operand of a function + /// call. + bool RequiresADL; + + /// True if namespace ::std should be considered an associated namespace + /// for the purposes of argument-dependent lookup. See C++0x [stmt.ranged]p1. + bool StdIsAssociatedNamespace; + + /// True if these lookup results are overloaded. This is pretty + /// trivially rederivable if we urgently need to kill this field. + bool Overloaded; + + /// The naming class (C++ [class.access.base]p5) of the lookup, if + /// any. This can generally be recalculated from the context chain, + /// but that can be fairly expensive for unqualified lookups. If we + /// want to improve memory use here, this could go in a union + /// against the qualified-lookup bits. + CXXRecordDecl *NamingClass; + + UnresolvedLookupExpr(ASTContext &C, + CXXRecordDecl *NamingClass, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation TemplateKWLoc, + const DeclarationNameInfo &NameInfo, + bool RequiresADL, bool Overloaded, + const TemplateArgumentListInfo *TemplateArgs, + UnresolvedSetIterator Begin, UnresolvedSetIterator End, + bool StdIsAssociatedNamespace) + : OverloadExpr(UnresolvedLookupExprClass, C, QualifierLoc, TemplateKWLoc, + NameInfo, TemplateArgs, Begin, End, false, false, false), + RequiresADL(RequiresADL), + StdIsAssociatedNamespace(StdIsAssociatedNamespace), + Overloaded(Overloaded), NamingClass(NamingClass) + {} + + UnresolvedLookupExpr(EmptyShell Empty) + : OverloadExpr(UnresolvedLookupExprClass, Empty), + RequiresADL(false), StdIsAssociatedNamespace(false), Overloaded(false), + NamingClass(0) + {} + + friend class ASTStmtReader; + +public: + static UnresolvedLookupExpr *Create(ASTContext &C, + CXXRecordDecl *NamingClass, + NestedNameSpecifierLoc QualifierLoc, + const DeclarationNameInfo &NameInfo, + bool ADL, bool Overloaded, + UnresolvedSetIterator Begin, + UnresolvedSetIterator End, + bool StdIsAssociatedNamespace = false) { + assert((ADL || !StdIsAssociatedNamespace) && + "std considered associated namespace when not performing ADL"); + return new(C) UnresolvedLookupExpr(C, NamingClass, QualifierLoc, + SourceLocation(), NameInfo, + ADL, Overloaded, 0, Begin, End, + StdIsAssociatedNamespace); + } + + static UnresolvedLookupExpr *Create(ASTContext &C, + CXXRecordDecl *NamingClass, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation TemplateKWLoc, + const DeclarationNameInfo &NameInfo, + bool ADL, + const TemplateArgumentListInfo *Args, + UnresolvedSetIterator Begin, + UnresolvedSetIterator End); + + static UnresolvedLookupExpr *CreateEmpty(ASTContext &C, + bool HasTemplateKWAndArgsInfo, + unsigned NumTemplateArgs); + + /// True if this declaration should be extended by + /// argument-dependent lookup. + bool requiresADL() const { return RequiresADL; } + + /// True if namespace ::std should be artificially added to the set of + /// associated namespaecs for argument-dependent lookup purposes. + bool isStdAssociatedNamespace() const { return StdIsAssociatedNamespace; } + + /// True if this lookup is overloaded. + bool isOverloaded() const { return Overloaded; } + + /// Gets the 'naming class' (in the sense of C++0x + /// [class.access.base]p5) of the lookup. This is the scope + /// that was looked in to find these results. + CXXRecordDecl *getNamingClass() const { return NamingClass; } + + SourceRange getSourceRange() const LLVM_READONLY { + SourceRange Range(getNameInfo().getSourceRange()); + if (getQualifierLoc()) + Range.setBegin(getQualifierLoc().getBeginLoc()); + if (hasExplicitTemplateArgs()) + Range.setEnd(getRAngleLoc()); + return Range; + } + + child_range children() { return child_range(); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == UnresolvedLookupExprClass; + } + static bool classof(const UnresolvedLookupExpr *) { return true; } +}; + +/// \brief A qualified reference to a name whose declaration cannot +/// yet be resolved. +/// +/// DependentScopeDeclRefExpr is similar to DeclRefExpr in that +/// it expresses a reference to a declaration such as +/// X<T>::value. The difference, however, is that an +/// DependentScopeDeclRefExpr node is used only within C++ templates when +/// the qualification (e.g., X<T>::) refers to a dependent type. In +/// this case, X<T>::value cannot resolve to a declaration because the +/// declaration will differ from on instantiation of X<T> to the +/// next. Therefore, DependentScopeDeclRefExpr keeps track of the +/// qualifier (X<T>::) and the name of the entity being referenced +/// ("value"). Such expressions will instantiate to a DeclRefExpr once the +/// declaration can be found. +class DependentScopeDeclRefExpr : public Expr { + /// \brief The nested-name-specifier that qualifies this unresolved + /// declaration name. + NestedNameSpecifierLoc QualifierLoc; + + /// The name of the entity we will be referencing. + DeclarationNameInfo NameInfo; + + /// \brief Whether the name includes info for explicit template + /// keyword and arguments. + bool HasTemplateKWAndArgsInfo; + + /// \brief Return the optional template keyword and arguments info. + ASTTemplateKWAndArgsInfo *getTemplateKWAndArgsInfo() { + if (!HasTemplateKWAndArgsInfo) return 0; + return reinterpret_cast<ASTTemplateKWAndArgsInfo*>(this + 1); + } + /// \brief Return the optional template keyword and arguments info. + const ASTTemplateKWAndArgsInfo *getTemplateKWAndArgsInfo() const { + return const_cast<DependentScopeDeclRefExpr*>(this) + ->getTemplateKWAndArgsInfo(); + } + + DependentScopeDeclRefExpr(QualType T, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation TemplateKWLoc, + const DeclarationNameInfo &NameInfo, + const TemplateArgumentListInfo *Args); + +public: + static DependentScopeDeclRefExpr *Create(ASTContext &C, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation TemplateKWLoc, + const DeclarationNameInfo &NameInfo, + const TemplateArgumentListInfo *TemplateArgs); + + static DependentScopeDeclRefExpr *CreateEmpty(ASTContext &C, + bool HasTemplateKWAndArgsInfo, + unsigned NumTemplateArgs); + + /// \brief Retrieve the name that this expression refers to. + const DeclarationNameInfo &getNameInfo() const { return NameInfo; } + + /// \brief Retrieve the name that this expression refers to. + DeclarationName getDeclName() const { return NameInfo.getName(); } + + /// \brief Retrieve the location of the name within the expression. + SourceLocation getLocation() const { return NameInfo.getLoc(); } + + /// \brief Retrieve the nested-name-specifier that qualifies the + /// name, with source location information. + NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; } + + + /// \brief Retrieve the nested-name-specifier that qualifies this + /// declaration. + NestedNameSpecifier *getQualifier() const { + return QualifierLoc.getNestedNameSpecifier(); + } + + /// \brief Retrieve the location of the template keyword preceding + /// this name, if any. + SourceLocation getTemplateKeywordLoc() const { + if (!HasTemplateKWAndArgsInfo) return SourceLocation(); + return getTemplateKWAndArgsInfo()->getTemplateKeywordLoc(); + } + + /// \brief Retrieve the location of the left angle bracket starting the + /// explicit template argument list following the name, if any. + SourceLocation getLAngleLoc() const { + if (!HasTemplateKWAndArgsInfo) return SourceLocation(); + return getTemplateKWAndArgsInfo()->LAngleLoc; + } + + /// \brief Retrieve the location of the right angle bracket ending the + /// explicit template argument list following the name, if any. + SourceLocation getRAngleLoc() const { + if (!HasTemplateKWAndArgsInfo) return SourceLocation(); + return getTemplateKWAndArgsInfo()->RAngleLoc; + } + + /// Determines whether the name was preceded by the template keyword. + bool hasTemplateKeyword() const { return getTemplateKeywordLoc().isValid(); } + + /// Determines whether this lookup had explicit template arguments. + bool hasExplicitTemplateArgs() const { return getLAngleLoc().isValid(); } + + // Note that, inconsistently with the explicit-template-argument AST + // nodes, users are *forbidden* from calling these methods on objects + // without explicit template arguments. + + ASTTemplateArgumentListInfo &getExplicitTemplateArgs() { + assert(hasExplicitTemplateArgs()); + return *reinterpret_cast<ASTTemplateArgumentListInfo*>(this + 1); + } + + /// Gets a reference to the explicit template argument list. + const ASTTemplateArgumentListInfo &getExplicitTemplateArgs() const { + assert(hasExplicitTemplateArgs()); + return *reinterpret_cast<const ASTTemplateArgumentListInfo*>(this + 1); + } + + /// \brief Retrieves the optional explicit template arguments. + /// This points to the same data as getExplicitTemplateArgs(), but + /// returns null if there are no explicit template arguments. + const ASTTemplateArgumentListInfo *getOptionalExplicitTemplateArgs() { + if (!hasExplicitTemplateArgs()) return 0; + return &getExplicitTemplateArgs(); + } + + /// \brief Copies the template arguments (if present) into the given + /// structure. + void copyTemplateArgumentsInto(TemplateArgumentListInfo &List) const { + getExplicitTemplateArgs().copyInto(List); + } + + TemplateArgumentLoc const *getTemplateArgs() const { + return getExplicitTemplateArgs().getTemplateArgs(); + } + + unsigned getNumTemplateArgs() const { + return getExplicitTemplateArgs().NumTemplateArgs; + } + + SourceRange getSourceRange() const LLVM_READONLY { + SourceRange Range(QualifierLoc.getBeginLoc(), getLocation()); + if (hasExplicitTemplateArgs()) + Range.setEnd(getRAngleLoc()); + return Range; + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == DependentScopeDeclRefExprClass; + } + static bool classof(const DependentScopeDeclRefExpr *) { return true; } + + child_range children() { return child_range(); } + + friend class ASTStmtReader; + friend class ASTStmtWriter; +}; + +/// Represents an expression --- generally a full-expression --- which +/// introduces cleanups to be run at the end of the sub-expression's +/// evaluation. The most common source of expression-introduced +/// cleanups is temporary objects in C++, but several other kinds of +/// expressions can create cleanups, including basically every +/// call in ARC that returns an Objective-C pointer. +/// +/// This expression also tracks whether the sub-expression contains a +/// potentially-evaluated block literal. The lifetime of a block +/// literal is the extent of the enclosing scope. +class ExprWithCleanups : public Expr { +public: + /// The type of objects that are kept in the cleanup. + /// It's useful to remember the set of blocks; we could also + /// remember the set of temporaries, but there's currently + /// no need. + typedef BlockDecl *CleanupObject; + +private: + Stmt *SubExpr; + + ExprWithCleanups(EmptyShell, unsigned NumObjects); + ExprWithCleanups(Expr *SubExpr, ArrayRef<CleanupObject> Objects); + + CleanupObject *getObjectsBuffer() { + return reinterpret_cast<CleanupObject*>(this + 1); + } + const CleanupObject *getObjectsBuffer() const { + return reinterpret_cast<const CleanupObject*>(this + 1); + } + friend class ASTStmtReader; + +public: + static ExprWithCleanups *Create(ASTContext &C, EmptyShell empty, + unsigned numObjects); + + static ExprWithCleanups *Create(ASTContext &C, Expr *subexpr, + ArrayRef<CleanupObject> objects); + + ArrayRef<CleanupObject> getObjects() const { + return ArrayRef<CleanupObject>(getObjectsBuffer(), getNumObjects()); + } + + unsigned getNumObjects() const { return ExprWithCleanupsBits.NumObjects; } + + CleanupObject getObject(unsigned i) const { + assert(i < getNumObjects() && "Index out of range"); + return getObjects()[i]; + } + + Expr *getSubExpr() { return cast<Expr>(SubExpr); } + const Expr *getSubExpr() const { return cast<Expr>(SubExpr); } + + /// setSubExpr - As with any mutator of the AST, be very careful + /// when modifying an existing AST to preserve its invariants. + void setSubExpr(Expr *E) { SubExpr = E; } + + SourceRange getSourceRange() const LLVM_READONLY { + return SubExpr->getSourceRange(); + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Stmt *T) { + return T->getStmtClass() == ExprWithCleanupsClass; + } + static bool classof(const ExprWithCleanups *) { return true; } + + // Iterators + child_range children() { return child_range(&SubExpr, &SubExpr + 1); } +}; + +/// \brief Describes an explicit type conversion that uses functional +/// notion but could not be resolved because one or more arguments are +/// type-dependent. +/// +/// The explicit type conversions expressed by +/// CXXUnresolvedConstructExpr have the form \c T(a1, a2, ..., aN), +/// where \c T is some type and \c a1, a2, ..., aN are values, and +/// either \C T is a dependent type or one or more of the \c a's is +/// type-dependent. For example, this would occur in a template such +/// as: +/// +/// \code +/// template<typename T, typename A1> +/// inline T make_a(const A1& a1) { +/// return T(a1); +/// } +/// \endcode +/// +/// When the returned expression is instantiated, it may resolve to a +/// constructor call, conversion function call, or some kind of type +/// conversion. +class CXXUnresolvedConstructExpr : public Expr { + /// \brief The type being constructed. + TypeSourceInfo *Type; + + /// \brief The location of the left parentheses ('('). + SourceLocation LParenLoc; + + /// \brief The location of the right parentheses (')'). + SourceLocation RParenLoc; + + /// \brief The number of arguments used to construct the type. + unsigned NumArgs; + + CXXUnresolvedConstructExpr(TypeSourceInfo *Type, + SourceLocation LParenLoc, + Expr **Args, + unsigned NumArgs, + SourceLocation RParenLoc); + + CXXUnresolvedConstructExpr(EmptyShell Empty, unsigned NumArgs) + : Expr(CXXUnresolvedConstructExprClass, Empty), Type(), NumArgs(NumArgs) { } + + friend class ASTStmtReader; + +public: + static CXXUnresolvedConstructExpr *Create(ASTContext &C, + TypeSourceInfo *Type, + SourceLocation LParenLoc, + Expr **Args, + unsigned NumArgs, + SourceLocation RParenLoc); + + static CXXUnresolvedConstructExpr *CreateEmpty(ASTContext &C, + unsigned NumArgs); + + /// \brief Retrieve the type that is being constructed, as specified + /// in the source code. + QualType getTypeAsWritten() const { return Type->getType(); } + + /// \brief Retrieve the type source information for the type being + /// constructed. + TypeSourceInfo *getTypeSourceInfo() const { return Type; } + + /// \brief Retrieve the location of the left parentheses ('(') that + /// precedes the argument list. + SourceLocation getLParenLoc() const { return LParenLoc; } + void setLParenLoc(SourceLocation L) { LParenLoc = L; } + + /// \brief Retrieve the location of the right parentheses (')') that + /// follows the argument list. + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } + + /// \brief Retrieve the number of arguments. + unsigned arg_size() const { return NumArgs; } + + typedef Expr** arg_iterator; + arg_iterator arg_begin() { return reinterpret_cast<Expr**>(this + 1); } + arg_iterator arg_end() { return arg_begin() + NumArgs; } + + typedef const Expr* const * const_arg_iterator; + const_arg_iterator arg_begin() const { + return reinterpret_cast<const Expr* const *>(this + 1); + } + const_arg_iterator arg_end() const { + return arg_begin() + NumArgs; + } + + Expr *getArg(unsigned I) { + assert(I < NumArgs && "Argument index out-of-range"); + return *(arg_begin() + I); + } + + const Expr *getArg(unsigned I) const { + assert(I < NumArgs && "Argument index out-of-range"); + return *(arg_begin() + I); + } + + void setArg(unsigned I, Expr *E) { + assert(I < NumArgs && "Argument index out-of-range"); + *(arg_begin() + I) = E; + } + + SourceRange getSourceRange() const LLVM_READONLY; + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXUnresolvedConstructExprClass; + } + static bool classof(const CXXUnresolvedConstructExpr *) { return true; } + + // Iterators + child_range children() { + Stmt **begin = reinterpret_cast<Stmt**>(this+1); + return child_range(begin, begin + NumArgs); + } +}; + +/// \brief Represents a C++ member access expression where the actual +/// member referenced could not be resolved because the base +/// expression or the member name was dependent. +/// +/// Like UnresolvedMemberExprs, these can be either implicit or +/// explicit accesses. It is only possible to get one of these with +/// an implicit access if a qualifier is provided. +class CXXDependentScopeMemberExpr : public Expr { + /// \brief The expression for the base pointer or class reference, + /// e.g., the \c x in x.f. Can be null in implicit accesses. + Stmt *Base; + + /// \brief The type of the base expression. Never null, even for + /// implicit accesses. + QualType BaseType; + + /// \brief Whether this member expression used the '->' operator or + /// the '.' operator. + bool IsArrow : 1; + + /// \brief Whether this member expression has info for explicit template + /// keyword and arguments. + bool HasTemplateKWAndArgsInfo : 1; + + /// \brief The location of the '->' or '.' operator. + SourceLocation OperatorLoc; + + /// \brief The nested-name-specifier that precedes the member name, if any. + NestedNameSpecifierLoc QualifierLoc; + + /// \brief In a qualified member access expression such as t->Base::f, this + /// member stores the resolves of name lookup in the context of the member + /// access expression, to be used at instantiation time. + /// + /// FIXME: This member, along with the QualifierLoc, could + /// be stuck into a structure that is optionally allocated at the end of + /// the CXXDependentScopeMemberExpr, to save space in the common case. + NamedDecl *FirstQualifierFoundInScope; + + /// \brief The member to which this member expression refers, which + /// can be name, overloaded operator, or destructor. + /// FIXME: could also be a template-id + DeclarationNameInfo MemberNameInfo; + + /// \brief Return the optional template keyword and arguments info. + ASTTemplateKWAndArgsInfo *getTemplateKWAndArgsInfo() { + if (!HasTemplateKWAndArgsInfo) return 0; + return reinterpret_cast<ASTTemplateKWAndArgsInfo*>(this + 1); + } + /// \brief Return the optional template keyword and arguments info. + const ASTTemplateKWAndArgsInfo *getTemplateKWAndArgsInfo() const { + return const_cast<CXXDependentScopeMemberExpr*>(this) + ->getTemplateKWAndArgsInfo(); + } + + CXXDependentScopeMemberExpr(ASTContext &C, + Expr *Base, QualType BaseType, bool IsArrow, + SourceLocation OperatorLoc, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation TemplateKWLoc, + NamedDecl *FirstQualifierFoundInScope, + DeclarationNameInfo MemberNameInfo, + const TemplateArgumentListInfo *TemplateArgs); + +public: + CXXDependentScopeMemberExpr(ASTContext &C, + Expr *Base, QualType BaseType, + bool IsArrow, + SourceLocation OperatorLoc, + NestedNameSpecifierLoc QualifierLoc, + NamedDecl *FirstQualifierFoundInScope, + DeclarationNameInfo MemberNameInfo); + + static CXXDependentScopeMemberExpr * + Create(ASTContext &C, + Expr *Base, QualType BaseType, bool IsArrow, + SourceLocation OperatorLoc, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation TemplateKWLoc, + NamedDecl *FirstQualifierFoundInScope, + DeclarationNameInfo MemberNameInfo, + const TemplateArgumentListInfo *TemplateArgs); + + static CXXDependentScopeMemberExpr * + CreateEmpty(ASTContext &C, bool HasTemplateKWAndArgsInfo, + unsigned NumTemplateArgs); + + /// \brief True if this is an implicit access, i.e. one in which the + /// member being accessed was not written in the source. The source + /// location of the operator is invalid in this case. + bool isImplicitAccess() const; + + /// \brief Retrieve the base object of this member expressions, + /// e.g., the \c x in \c x.m. + Expr *getBase() const { + assert(!isImplicitAccess()); + return cast<Expr>(Base); + } + + QualType getBaseType() const { return BaseType; } + + /// \brief Determine whether this member expression used the '->' + /// operator; otherwise, it used the '.' operator. + bool isArrow() const { return IsArrow; } + + /// \brief Retrieve the location of the '->' or '.' operator. + SourceLocation getOperatorLoc() const { return OperatorLoc; } + + /// \brief Retrieve the nested-name-specifier that qualifies the member + /// name. + NestedNameSpecifier *getQualifier() const { + return QualifierLoc.getNestedNameSpecifier(); + } + + /// \brief Retrieve the nested-name-specifier that qualifies the member + /// name, with source location information. + NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; } + + + /// \brief Retrieve the first part of the nested-name-specifier that was + /// found in the scope of the member access expression when the member access + /// was initially parsed. + /// + /// This function only returns a useful result when member access expression + /// uses a qualified member name, e.g., "x.Base::f". Here, the declaration + /// returned by this function describes what was found by unqualified name + /// lookup for the identifier "Base" within the scope of the member access + /// expression itself. At template instantiation time, this information is + /// combined with the results of name lookup into the type of the object + /// expression itself (the class type of x). + NamedDecl *getFirstQualifierFoundInScope() const { + return FirstQualifierFoundInScope; + } + + /// \brief Retrieve the name of the member that this expression + /// refers to. + const DeclarationNameInfo &getMemberNameInfo() const { + return MemberNameInfo; + } + + /// \brief Retrieve the name of the member that this expression + /// refers to. + DeclarationName getMember() const { return MemberNameInfo.getName(); } + + // \brief Retrieve the location of the name of the member that this + // expression refers to. + SourceLocation getMemberLoc() const { return MemberNameInfo.getLoc(); } + + /// \brief Retrieve the location of the template keyword preceding the + /// member name, if any. + SourceLocation getTemplateKeywordLoc() const { + if (!HasTemplateKWAndArgsInfo) return SourceLocation(); + return getTemplateKWAndArgsInfo()->getTemplateKeywordLoc(); + } + + /// \brief Retrieve the location of the left angle bracket starting the + /// explicit template argument list following the member name, if any. + SourceLocation getLAngleLoc() const { + if (!HasTemplateKWAndArgsInfo) return SourceLocation(); + return getTemplateKWAndArgsInfo()->LAngleLoc; + } + + /// \brief Retrieve the location of the right angle bracket ending the + /// explicit template argument list following the member name, if any. + SourceLocation getRAngleLoc() const { + if (!HasTemplateKWAndArgsInfo) return SourceLocation(); + return getTemplateKWAndArgsInfo()->RAngleLoc; + } + + /// Determines whether the member name was preceded by the template keyword. + bool hasTemplateKeyword() const { return getTemplateKeywordLoc().isValid(); } + + /// \brief Determines whether this member expression actually had a C++ + /// template argument list explicitly specified, e.g., x.f<int>. + bool hasExplicitTemplateArgs() const { return getLAngleLoc().isValid(); } + + /// \brief Retrieve the explicit template argument list that followed the + /// member template name, if any. + ASTTemplateArgumentListInfo &getExplicitTemplateArgs() { + assert(hasExplicitTemplateArgs()); + return *reinterpret_cast<ASTTemplateArgumentListInfo *>(this + 1); + } + + /// \brief Retrieve the explicit template argument list that followed the + /// member template name, if any. + const ASTTemplateArgumentListInfo &getExplicitTemplateArgs() const { + return const_cast<CXXDependentScopeMemberExpr *>(this) + ->getExplicitTemplateArgs(); + } + + /// \brief Retrieves the optional explicit template arguments. + /// This points to the same data as getExplicitTemplateArgs(), but + /// returns null if there are no explicit template arguments. + const ASTTemplateArgumentListInfo *getOptionalExplicitTemplateArgs() { + if (!hasExplicitTemplateArgs()) return 0; + return &getExplicitTemplateArgs(); + } + + /// \brief Copies the template arguments (if present) into the given + /// structure. + void copyTemplateArgumentsInto(TemplateArgumentListInfo &List) const { + getExplicitTemplateArgs().copyInto(List); + } + + /// \brief Initializes the template arguments using the given structure. + void initializeTemplateArgumentsFrom(const TemplateArgumentListInfo &List) { + getExplicitTemplateArgs().initializeFrom(List); + } + + /// \brief Retrieve the template arguments provided as part of this + /// template-id. + const TemplateArgumentLoc *getTemplateArgs() const { + return getExplicitTemplateArgs().getTemplateArgs(); + } + + /// \brief Retrieve the number of template arguments provided as part of this + /// template-id. + unsigned getNumTemplateArgs() const { + return getExplicitTemplateArgs().NumTemplateArgs; + } + + SourceRange getSourceRange() const LLVM_READONLY { + SourceRange Range; + if (!isImplicitAccess()) + Range.setBegin(Base->getSourceRange().getBegin()); + else if (getQualifier()) + Range.setBegin(getQualifierLoc().getBeginLoc()); + else + Range.setBegin(MemberNameInfo.getBeginLoc()); + + if (hasExplicitTemplateArgs()) + Range.setEnd(getRAngleLoc()); + else + Range.setEnd(MemberNameInfo.getEndLoc()); + return Range; + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXDependentScopeMemberExprClass; + } + static bool classof(const CXXDependentScopeMemberExpr *) { return true; } + + // Iterators + child_range children() { + if (isImplicitAccess()) return child_range(); + return child_range(&Base, &Base + 1); + } + + friend class ASTStmtReader; + friend class ASTStmtWriter; +}; + +/// \brief Represents a C++ member access expression for which lookup +/// produced a set of overloaded functions. +/// +/// The member access may be explicit or implicit: +/// struct A { +/// int a, b; +/// int explicitAccess() { return this->a + this->A::b; } +/// int implicitAccess() { return a + A::b; } +/// }; +/// +/// In the final AST, an explicit access always becomes a MemberExpr. +/// An implicit access may become either a MemberExpr or a +/// DeclRefExpr, depending on whether the member is static. +class UnresolvedMemberExpr : public OverloadExpr { + /// \brief Whether this member expression used the '->' operator or + /// the '.' operator. + bool IsArrow : 1; + + /// \brief Whether the lookup results contain an unresolved using + /// declaration. + bool HasUnresolvedUsing : 1; + + /// \brief The expression for the base pointer or class reference, + /// e.g., the \c x in x.f. This can be null if this is an 'unbased' + /// member expression + Stmt *Base; + + /// \brief The type of the base expression; never null. + QualType BaseType; + + /// \brief The location of the '->' or '.' operator. + SourceLocation OperatorLoc; + + UnresolvedMemberExpr(ASTContext &C, bool HasUnresolvedUsing, + Expr *Base, QualType BaseType, bool IsArrow, + SourceLocation OperatorLoc, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation TemplateKWLoc, + const DeclarationNameInfo &MemberNameInfo, + const TemplateArgumentListInfo *TemplateArgs, + UnresolvedSetIterator Begin, UnresolvedSetIterator End); + + UnresolvedMemberExpr(EmptyShell Empty) + : OverloadExpr(UnresolvedMemberExprClass, Empty), IsArrow(false), + HasUnresolvedUsing(false), Base(0) { } + + friend class ASTStmtReader; + +public: + static UnresolvedMemberExpr * + Create(ASTContext &C, bool HasUnresolvedUsing, + Expr *Base, QualType BaseType, bool IsArrow, + SourceLocation OperatorLoc, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation TemplateKWLoc, + const DeclarationNameInfo &MemberNameInfo, + const TemplateArgumentListInfo *TemplateArgs, + UnresolvedSetIterator Begin, UnresolvedSetIterator End); + + static UnresolvedMemberExpr * + CreateEmpty(ASTContext &C, bool HasTemplateKWAndArgsInfo, + unsigned NumTemplateArgs); + + /// \brief True if this is an implicit access, i.e. one in which the + /// member being accessed was not written in the source. The source + /// location of the operator is invalid in this case. + bool isImplicitAccess() const; + + /// \brief Retrieve the base object of this member expressions, + /// e.g., the \c x in \c x.m. + Expr *getBase() { + assert(!isImplicitAccess()); + return cast<Expr>(Base); + } + const Expr *getBase() const { + assert(!isImplicitAccess()); + return cast<Expr>(Base); + } + + QualType getBaseType() const { return BaseType; } + + /// \brief Determine whether the lookup results contain an unresolved using + /// declaration. + bool hasUnresolvedUsing() const { return HasUnresolvedUsing; } + + /// \brief Determine whether this member expression used the '->' + /// operator; otherwise, it used the '.' operator. + bool isArrow() const { return IsArrow; } + + /// \brief Retrieve the location of the '->' or '.' operator. + SourceLocation getOperatorLoc() const { return OperatorLoc; } + + /// \brief Retrieves the naming class of this lookup. + CXXRecordDecl *getNamingClass() const; + + /// \brief Retrieve the full name info for the member that this expression + /// refers to. + const DeclarationNameInfo &getMemberNameInfo() const { return getNameInfo(); } + + /// \brief Retrieve the name of the member that this expression + /// refers to. + DeclarationName getMemberName() const { return getName(); } + + // \brief Retrieve the location of the name of the member that this + // expression refers to. + SourceLocation getMemberLoc() const { return getNameLoc(); } + + SourceRange getSourceRange() const LLVM_READONLY { + SourceRange Range = getMemberNameInfo().getSourceRange(); + if (!isImplicitAccess()) + Range.setBegin(Base->getSourceRange().getBegin()); + else if (getQualifierLoc()) + Range.setBegin(getQualifierLoc().getBeginLoc()); + + if (hasExplicitTemplateArgs()) + Range.setEnd(getRAngleLoc()); + return Range; + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == UnresolvedMemberExprClass; + } + static bool classof(const UnresolvedMemberExpr *) { return true; } + + // Iterators + child_range children() { + if (isImplicitAccess()) return child_range(); + return child_range(&Base, &Base + 1); + } +}; + +/// \brief Represents a C++0x noexcept expression (C++ [expr.unary.noexcept]). +/// +/// The noexcept expression tests whether a given expression might throw. Its +/// result is a boolean constant. +class CXXNoexceptExpr : public Expr { + bool Value : 1; + Stmt *Operand; + SourceRange Range; + + friend class ASTStmtReader; + +public: + CXXNoexceptExpr(QualType Ty, Expr *Operand, CanThrowResult Val, + SourceLocation Keyword, SourceLocation RParen) + : Expr(CXXNoexceptExprClass, Ty, VK_RValue, OK_Ordinary, + /*TypeDependent*/false, + /*ValueDependent*/Val == CT_Dependent, + Val == CT_Dependent || Operand->isInstantiationDependent(), + Operand->containsUnexpandedParameterPack()), + Value(Val == CT_Cannot), Operand(Operand), Range(Keyword, RParen) + { } + + CXXNoexceptExpr(EmptyShell Empty) + : Expr(CXXNoexceptExprClass, Empty) + { } + + Expr *getOperand() const { return static_cast<Expr*>(Operand); } + + SourceRange getSourceRange() const LLVM_READONLY { return Range; } + + bool getValue() const { return Value; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXNoexceptExprClass; + } + static bool classof(const CXXNoexceptExpr *) { return true; } + + // Iterators + child_range children() { return child_range(&Operand, &Operand + 1); } +}; + +/// \brief Represents a C++0x pack expansion that produces a sequence of +/// expressions. +/// +/// A pack expansion expression contains a pattern (which itself is an +/// expression) followed by an ellipsis. For example: +/// +/// \code +/// template<typename F, typename ...Types> +/// void forward(F f, Types &&...args) { +/// f(static_cast<Types&&>(args)...); +/// } +/// \endcode +/// +/// Here, the argument to the function object \c f is a pack expansion whose +/// pattern is \c static_cast<Types&&>(args). When the \c forward function +/// template is instantiated, the pack expansion will instantiate to zero or +/// or more function arguments to the function object \c f. +class PackExpansionExpr : public Expr { + SourceLocation EllipsisLoc; + + /// \brief The number of expansions that will be produced by this pack + /// expansion expression, if known. + /// + /// When zero, the number of expansions is not known. Otherwise, this value + /// is the number of expansions + 1. + unsigned NumExpansions; + + Stmt *Pattern; + + friend class ASTStmtReader; + friend class ASTStmtWriter; + +public: + PackExpansionExpr(QualType T, Expr *Pattern, SourceLocation EllipsisLoc, + llvm::Optional<unsigned> NumExpansions) + : Expr(PackExpansionExprClass, T, Pattern->getValueKind(), + Pattern->getObjectKind(), /*TypeDependent=*/true, + /*ValueDependent=*/true, /*InstantiationDependent=*/true, + /*ContainsUnexpandedParameterPack=*/false), + EllipsisLoc(EllipsisLoc), + NumExpansions(NumExpansions? *NumExpansions + 1 : 0), + Pattern(Pattern) { } + + PackExpansionExpr(EmptyShell Empty) : Expr(PackExpansionExprClass, Empty) { } + + /// \brief Retrieve the pattern of the pack expansion. + Expr *getPattern() { return reinterpret_cast<Expr *>(Pattern); } + + /// \brief Retrieve the pattern of the pack expansion. + const Expr *getPattern() const { return reinterpret_cast<Expr *>(Pattern); } + + /// \brief Retrieve the location of the ellipsis that describes this pack + /// expansion. + SourceLocation getEllipsisLoc() const { return EllipsisLoc; } + + /// \brief Determine the number of expansions that will be produced when + /// this pack expansion is instantiated, if already known. + llvm::Optional<unsigned> getNumExpansions() const { + if (NumExpansions) + return NumExpansions - 1; + + return llvm::Optional<unsigned>(); + } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(Pattern->getLocStart(), EllipsisLoc); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == PackExpansionExprClass; + } + static bool classof(const PackExpansionExpr *) { return true; } + + // Iterators + child_range children() { + return child_range(&Pattern, &Pattern + 1); + } +}; + +inline ASTTemplateKWAndArgsInfo *OverloadExpr::getTemplateKWAndArgsInfo() { + if (!HasTemplateKWAndArgsInfo) return 0; + if (isa<UnresolvedLookupExpr>(this)) + return reinterpret_cast<ASTTemplateKWAndArgsInfo*> + (cast<UnresolvedLookupExpr>(this) + 1); + else + return reinterpret_cast<ASTTemplateKWAndArgsInfo*> + (cast<UnresolvedMemberExpr>(this) + 1); +} + +/// \brief Represents an expression that computes the length of a parameter +/// pack. +/// +/// \code +/// template<typename ...Types> +/// struct count { +/// static const unsigned value = sizeof...(Types); +/// }; +/// \endcode +class SizeOfPackExpr : public Expr { + /// \brief The location of the 'sizeof' keyword. + SourceLocation OperatorLoc; + + /// \brief The location of the name of the parameter pack. + SourceLocation PackLoc; + + /// \brief The location of the closing parenthesis. + SourceLocation RParenLoc; + + /// \brief The length of the parameter pack, if known. + /// + /// When this expression is value-dependent, the length of the parameter pack + /// is unknown. When this expression is not value-dependent, the length is + /// known. + unsigned Length; + + /// \brief The parameter pack itself. + NamedDecl *Pack; + + friend class ASTStmtReader; + friend class ASTStmtWriter; + +public: + /// \brief Creates a value-dependent expression that computes the length of + /// the given parameter pack. + SizeOfPackExpr(QualType SizeType, SourceLocation OperatorLoc, NamedDecl *Pack, + SourceLocation PackLoc, SourceLocation RParenLoc) + : Expr(SizeOfPackExprClass, SizeType, VK_RValue, OK_Ordinary, + /*TypeDependent=*/false, /*ValueDependent=*/true, + /*InstantiationDependent=*/true, + /*ContainsUnexpandedParameterPack=*/false), + OperatorLoc(OperatorLoc), PackLoc(PackLoc), RParenLoc(RParenLoc), + Length(0), Pack(Pack) { } + + /// \brief Creates an expression that computes the length of + /// the given parameter pack, which is already known. + SizeOfPackExpr(QualType SizeType, SourceLocation OperatorLoc, NamedDecl *Pack, + SourceLocation PackLoc, SourceLocation RParenLoc, + unsigned Length) + : Expr(SizeOfPackExprClass, SizeType, VK_RValue, OK_Ordinary, + /*TypeDependent=*/false, /*ValueDependent=*/false, + /*InstantiationDependent=*/false, + /*ContainsUnexpandedParameterPack=*/false), + OperatorLoc(OperatorLoc), PackLoc(PackLoc), RParenLoc(RParenLoc), + Length(Length), Pack(Pack) { } + + /// \brief Create an empty expression. + SizeOfPackExpr(EmptyShell Empty) : Expr(SizeOfPackExprClass, Empty) { } + + /// \brief Determine the location of the 'sizeof' keyword. + SourceLocation getOperatorLoc() const { return OperatorLoc; } + + /// \brief Determine the location of the parameter pack. + SourceLocation getPackLoc() const { return PackLoc; } + + /// \brief Determine the location of the right parenthesis. + SourceLocation getRParenLoc() const { return RParenLoc; } + + /// \brief Retrieve the parameter pack. + NamedDecl *getPack() const { return Pack; } + + /// \brief Retrieve the length of the parameter pack. + /// + /// This routine may only be invoked when the expression is not + /// value-dependent. + unsigned getPackLength() const { + assert(!isValueDependent() && + "Cannot get the length of a value-dependent pack size expression"); + return Length; + } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(OperatorLoc, RParenLoc); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == SizeOfPackExprClass; + } + static bool classof(const SizeOfPackExpr *) { return true; } + + // Iterators + child_range children() { return child_range(); } +}; + +/// \brief Represents a reference to a non-type template parameter +/// that has been substituted with a template argument. +class SubstNonTypeTemplateParmExpr : public Expr { + /// \brief The replaced parameter. + NonTypeTemplateParmDecl *Param; + + /// \brief The replacement expression. + Stmt *Replacement; + + /// \brief The location of the non-type template parameter reference. + SourceLocation NameLoc; + + friend class ASTReader; + friend class ASTStmtReader; + explicit SubstNonTypeTemplateParmExpr(EmptyShell Empty) + : Expr(SubstNonTypeTemplateParmExprClass, Empty) { } + +public: + SubstNonTypeTemplateParmExpr(QualType type, + ExprValueKind valueKind, + SourceLocation loc, + NonTypeTemplateParmDecl *param, + Expr *replacement) + : Expr(SubstNonTypeTemplateParmExprClass, type, valueKind, OK_Ordinary, + replacement->isTypeDependent(), replacement->isValueDependent(), + replacement->isInstantiationDependent(), + replacement->containsUnexpandedParameterPack()), + Param(param), Replacement(replacement), NameLoc(loc) {} + + SourceLocation getNameLoc() const { return NameLoc; } + SourceRange getSourceRange() const LLVM_READONLY { return NameLoc; } + + Expr *getReplacement() const { return cast<Expr>(Replacement); } + + NonTypeTemplateParmDecl *getParameter() const { return Param; } + + static bool classof(const Stmt *s) { + return s->getStmtClass() == SubstNonTypeTemplateParmExprClass; + } + static bool classof(const SubstNonTypeTemplateParmExpr *) { + return true; + } + + // Iterators + child_range children() { return child_range(&Replacement, &Replacement+1); } +}; + +/// \brief Represents a reference to a non-type template parameter pack that +/// has been substituted with a non-template argument pack. +/// +/// When a pack expansion in the source code contains multiple parameter packs +/// and those parameter packs correspond to different levels of template +/// parameter lists, this node node is used to represent a non-type template +/// parameter pack from an outer level, which has already had its argument pack +/// substituted but that still lives within a pack expansion that itself +/// could not be instantiated. When actually performing a substitution into +/// that pack expansion (e.g., when all template parameters have corresponding +/// arguments), this type will be replaced with the appropriate underlying +/// expression at the current pack substitution index. +class SubstNonTypeTemplateParmPackExpr : public Expr { + /// \brief The non-type template parameter pack itself. + NonTypeTemplateParmDecl *Param; + + /// \brief A pointer to the set of template arguments that this + /// parameter pack is instantiated with. + const TemplateArgument *Arguments; + + /// \brief The number of template arguments in \c Arguments. + unsigned NumArguments; + + /// \brief The location of the non-type template parameter pack reference. + SourceLocation NameLoc; + + friend class ASTReader; + friend class ASTStmtReader; + explicit SubstNonTypeTemplateParmPackExpr(EmptyShell Empty) + : Expr(SubstNonTypeTemplateParmPackExprClass, Empty) { } + +public: + SubstNonTypeTemplateParmPackExpr(QualType T, + NonTypeTemplateParmDecl *Param, + SourceLocation NameLoc, + const TemplateArgument &ArgPack); + + /// \brief Retrieve the non-type template parameter pack being substituted. + NonTypeTemplateParmDecl *getParameterPack() const { return Param; } + + /// \brief Retrieve the location of the parameter pack name. + SourceLocation getParameterPackLocation() const { return NameLoc; } + + /// \brief Retrieve the template argument pack containing the substituted + /// template arguments. + TemplateArgument getArgumentPack() const; + + SourceRange getSourceRange() const LLVM_READONLY { return NameLoc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == SubstNonTypeTemplateParmPackExprClass; + } + static bool classof(const SubstNonTypeTemplateParmPackExpr *) { + return true; + } + + // Iterators + child_range children() { return child_range(); } +}; + +/// \brief Represents a prvalue temporary that written into memory so that +/// a reference can bind to it. +/// +/// Prvalue expressions are materialized when they need to have an address +/// in memory for a reference to bind to. This happens when binding a +/// reference to the result of a conversion, e.g., +/// +/// \code +/// const int &r = 1.0; +/// \endcode +/// +/// Here, 1.0 is implicitly converted to an \c int. That resulting \c int is +/// then materialized via a \c MaterializeTemporaryExpr, and the reference +/// binds to the temporary. \c MaterializeTemporaryExprs are always glvalues +/// (either an lvalue or an xvalue, depending on the kind of reference binding +/// to it), maintaining the invariant that references always bind to glvalues. +class MaterializeTemporaryExpr : public Expr { + /// \brief The temporary-generating expression whose value will be + /// materialized. + Stmt *Temporary; + + friend class ASTStmtReader; + friend class ASTStmtWriter; + +public: + MaterializeTemporaryExpr(QualType T, Expr *Temporary, + bool BoundToLvalueReference) + : Expr(MaterializeTemporaryExprClass, T, + BoundToLvalueReference? VK_LValue : VK_XValue, OK_Ordinary, + Temporary->isTypeDependent(), Temporary->isValueDependent(), + Temporary->isInstantiationDependent(), + Temporary->containsUnexpandedParameterPack()), + Temporary(Temporary) { } + + MaterializeTemporaryExpr(EmptyShell Empty) + : Expr(MaterializeTemporaryExprClass, Empty) { } + + /// \brief Retrieve the temporary-generating subexpression whose value will + /// be materialized into a glvalue. + Expr *GetTemporaryExpr() const { return reinterpret_cast<Expr *>(Temporary); } + + /// \brief Determine whether this materialized temporary is bound to an + /// lvalue reference; otherwise, it's bound to an rvalue reference. + bool isBoundToLvalueReference() const { + return getValueKind() == VK_LValue; + } + + SourceRange getSourceRange() const LLVM_READONLY { + return Temporary->getSourceRange(); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == MaterializeTemporaryExprClass; + } + static bool classof(const MaterializeTemporaryExpr *) { + return true; + } + + // Iterators + child_range children() { return child_range(&Temporary, &Temporary + 1); } +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/AST/ExprObjC.h b/clang/include/clang/AST/ExprObjC.h new file mode 100644 index 0000000..4bfd12c --- /dev/null +++ b/clang/include/clang/AST/ExprObjC.h @@ -0,0 +1,1541 @@ +//===--- ExprObjC.h - Classes for representing ObjC expressions -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ExprObjC interface and subclasses. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_EXPROBJC_H +#define LLVM_CLANG_AST_EXPROBJC_H + +#include "clang/AST/DeclObjC.h" +#include "clang/AST/Expr.h" +#include "clang/AST/SelectorLocationsKind.h" +#include "clang/Basic/IdentifierTable.h" +#include "llvm/Support/Compiler.h" + +namespace clang { + class IdentifierInfo; + class ASTContext; + +/// ObjCStringLiteral, used for Objective-C string literals +/// i.e. @"foo". +class ObjCStringLiteral : public Expr { + Stmt *String; + SourceLocation AtLoc; +public: + ObjCStringLiteral(StringLiteral *SL, QualType T, SourceLocation L) + : Expr(ObjCStringLiteralClass, T, VK_RValue, OK_Ordinary, false, false, + false, false), + String(SL), AtLoc(L) {} + explicit ObjCStringLiteral(EmptyShell Empty) + : Expr(ObjCStringLiteralClass, Empty) {} + + StringLiteral *getString() { return cast<StringLiteral>(String); } + const StringLiteral *getString() const { return cast<StringLiteral>(String); } + void setString(StringLiteral *S) { String = S; } + + SourceLocation getAtLoc() const { return AtLoc; } + void setAtLoc(SourceLocation L) { AtLoc = L; } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(AtLoc, String->getLocEnd()); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCStringLiteralClass; + } + static bool classof(const ObjCStringLiteral *) { return true; } + + // Iterators + child_range children() { return child_range(&String, &String+1); } +}; + +/// ObjCBoolLiteralExpr - Objective-C Boolean Literal. +/// +class ObjCBoolLiteralExpr : public Expr { + bool Value; + SourceLocation Loc; +public: + ObjCBoolLiteralExpr(bool val, QualType Ty, SourceLocation l) : + Expr(ObjCBoolLiteralExprClass, Ty, VK_RValue, OK_Ordinary, false, false, + false, false), Value(val), Loc(l) {} + + explicit ObjCBoolLiteralExpr(EmptyShell Empty) + : Expr(ObjCBoolLiteralExprClass, Empty) { } + + bool getValue() const { return Value; } + void setValue(bool V) { Value = V; } + + SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(Loc); } + + SourceLocation getLocation() const { return Loc; } + void setLocation(SourceLocation L) { Loc = L; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCBoolLiteralExprClass; + } + static bool classof(const ObjCBoolLiteralExpr *) { return true; } + + // Iterators + child_range children() { return child_range(); } +}; + +/// ObjCNumericLiteral - used for objective-c numeric literals; +/// as in: @42 or @true (c++/objc++) or @__yes (c/objc) +class ObjCNumericLiteral : public Expr { + /// Number - expression AST node for the numeric literal + Stmt *Number; + ObjCMethodDecl *ObjCNumericLiteralMethod; + SourceLocation AtLoc; +public: + ObjCNumericLiteral(Stmt *NL, QualType T, ObjCMethodDecl *method, + SourceLocation L) + : Expr(ObjCNumericLiteralClass, T, VK_RValue, OK_Ordinary, + false, false, false, false), Number(NL), + ObjCNumericLiteralMethod(method), AtLoc(L) {} + explicit ObjCNumericLiteral(EmptyShell Empty) + : Expr(ObjCNumericLiteralClass, Empty) {} + + Expr *getNumber() { return cast<Expr>(Number); } + const Expr *getNumber() const { return cast<Expr>(Number); } + + ObjCMethodDecl *getObjCNumericLiteralMethod() const { + return ObjCNumericLiteralMethod; + } + + SourceLocation getAtLoc() const { return AtLoc; } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(AtLoc, Number->getSourceRange().getEnd()); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCNumericLiteralClass; + } + static bool classof(const ObjCNumericLiteral *) { return true; } + + // Iterators + child_range children() { return child_range(&Number, &Number+1); } + + friend class ASTStmtReader; +}; + +/// ObjCArrayLiteral - used for objective-c array containers; as in: +/// @[@"Hello", NSApp, [NSNumber numberWithInt:42]]; +class ObjCArrayLiteral : public Expr { + unsigned NumElements; + SourceRange Range; + ObjCMethodDecl *ArrayWithObjectsMethod; + + ObjCArrayLiteral(llvm::ArrayRef<Expr *> Elements, + QualType T, ObjCMethodDecl * Method, + SourceRange SR); + + explicit ObjCArrayLiteral(EmptyShell Empty, unsigned NumElements) + : Expr(ObjCArrayLiteralClass, Empty), NumElements(NumElements) {} + +public: + static ObjCArrayLiteral *Create(ASTContext &C, + llvm::ArrayRef<Expr *> Elements, + QualType T, ObjCMethodDecl * Method, + SourceRange SR); + + static ObjCArrayLiteral *CreateEmpty(ASTContext &C, unsigned NumElements); + + SourceRange getSourceRange() const LLVM_READONLY { return Range; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCArrayLiteralClass; + } + static bool classof(const ObjCArrayLiteral *) { return true; } + + /// \brief Retrieve elements of array of literals. + Expr **getElements() { return reinterpret_cast<Expr **>(this + 1); } + + /// \brief Retrieve elements of array of literals. + const Expr * const *getElements() const { + return reinterpret_cast<const Expr * const*>(this + 1); + } + + /// getNumElements - Return number of elements of objective-c array literal. + unsigned getNumElements() const { return NumElements; } + + /// getExpr - Return the Expr at the specified index. + Expr *getElement(unsigned Index) { + assert((Index < NumElements) && "Arg access out of range!"); + return cast<Expr>(getElements()[Index]); + } + const Expr *getElement(unsigned Index) const { + assert((Index < NumElements) && "Arg access out of range!"); + return cast<Expr>(getElements()[Index]); + } + + ObjCMethodDecl *getArrayWithObjectsMethod() const { + return ArrayWithObjectsMethod; + } + + // Iterators + child_range children() { + return child_range((Stmt **)getElements(), + (Stmt **)getElements() + NumElements); + } + + friend class ASTStmtReader; +}; + +/// \brief An element in an Objective-C dictionary literal. +/// +struct ObjCDictionaryElement { + /// \brief The key for the dictionary element. + Expr *Key; + + /// \brief The value of the dictionary element. + Expr *Value; + + /// \brief The location of the ellipsis, if this is a pack expansion. + SourceLocation EllipsisLoc; + + /// \brief The number of elements this pack expansion will expand to, if + /// this is a pack expansion and is known. + llvm::Optional<unsigned> NumExpansions; + + /// \brief Determines whether this dictionary element is a pack expansion. + bool isPackExpansion() const { return EllipsisLoc.isValid(); } +}; + +/// ObjCDictionaryLiteral - AST node to represent objective-c dictionary +/// literals; as in: @{@"name" : NSUserName(), @"date" : [NSDate date] }; +class ObjCDictionaryLiteral : public Expr { + /// \brief Key/value pair used to store the key and value of a given element. + /// + /// Objects of this type are stored directly after the expression. + struct KeyValuePair { + Expr *Key; + Expr *Value; + }; + + /// \brief Data that describes an element that is a pack expansion, used if any + /// of the elements in the dictionary literal are pack expansions. + struct ExpansionData { + /// \brief The location of the ellipsis, if this element is a pack + /// expansion. + SourceLocation EllipsisLoc; + + /// \brief If non-zero, the number of elements that this pack + /// expansion will expand to (+1). + unsigned NumExpansionsPlusOne; + }; + + /// \brief The number of elements in this dictionary literal. + unsigned NumElements : 31; + + /// \brief Determine whether this dictionary literal has any pack expansions. + /// + /// If the dictionary literal has pack expansions, then there will + /// be an array of pack expansion data following the array of + /// key/value pairs, which provide the locations of the ellipses (if + /// any) and number of elements in the expansion (if known). If + /// there are no pack expansions, we optimize away this storage. + unsigned HasPackExpansions : 1; + + SourceRange Range; + ObjCMethodDecl *DictWithObjectsMethod; + + ObjCDictionaryLiteral(ArrayRef<ObjCDictionaryElement> VK, + bool HasPackExpansions, + QualType T, ObjCMethodDecl *method, + SourceRange SR); + + explicit ObjCDictionaryLiteral(EmptyShell Empty, unsigned NumElements, + bool HasPackExpansions) + : Expr(ObjCDictionaryLiteralClass, Empty), NumElements(NumElements), + HasPackExpansions(HasPackExpansions) {} + + KeyValuePair *getKeyValues() { + return reinterpret_cast<KeyValuePair *>(this + 1); + } + + const KeyValuePair *getKeyValues() const { + return reinterpret_cast<const KeyValuePair *>(this + 1); + } + + ExpansionData *getExpansionData() { + if (!HasPackExpansions) + return 0; + + return reinterpret_cast<ExpansionData *>(getKeyValues() + NumElements); + } + + const ExpansionData *getExpansionData() const { + if (!HasPackExpansions) + return 0; + + return reinterpret_cast<const ExpansionData *>(getKeyValues()+NumElements); + } + +public: + static ObjCDictionaryLiteral *Create(ASTContext &C, + ArrayRef<ObjCDictionaryElement> VK, + bool HasPackExpansions, + QualType T, ObjCMethodDecl *method, + SourceRange SR); + + static ObjCDictionaryLiteral *CreateEmpty(ASTContext &C, + unsigned NumElements, + bool HasPackExpansions); + + /// getNumElements - Return number of elements of objective-c dictionary + /// literal. + unsigned getNumElements() const { return NumElements; } + + ObjCDictionaryElement getKeyValueElement(unsigned Index) const { + assert((Index < NumElements) && "Arg access out of range!"); + const KeyValuePair &KV = getKeyValues()[Index]; + ObjCDictionaryElement Result = { KV.Key, KV.Value, SourceLocation(), + llvm::Optional<unsigned>() }; + if (HasPackExpansions) { + const ExpansionData &Expansion = getExpansionData()[Index]; + Result.EllipsisLoc = Expansion.EllipsisLoc; + if (Expansion.NumExpansionsPlusOne > 0) + Result.NumExpansions = Expansion.NumExpansionsPlusOne - 1; + } + return Result; + } + + ObjCMethodDecl *getDictWithObjectsMethod() const + { return DictWithObjectsMethod; } + + SourceRange getSourceRange() const LLVM_READONLY { return Range; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCDictionaryLiteralClass; + } + static bool classof(const ObjCDictionaryLiteral *) { return true; } + + // Iterators + child_range children() { + // Note: we're taking advantage of the layout of the KeyValuePair struct + // here. If that struct changes, this code will need to change as well. + return child_range(reinterpret_cast<Stmt **>(this + 1), + reinterpret_cast<Stmt **>(this + 1) + NumElements * 2); + } + + friend class ASTStmtReader; + friend class ASTStmtWriter; +}; + + +/// ObjCEncodeExpr, used for @encode in Objective-C. @encode has the same type +/// and behavior as StringLiteral except that the string initializer is obtained +/// from ASTContext with the encoding type as an argument. +class ObjCEncodeExpr : public Expr { + TypeSourceInfo *EncodedType; + SourceLocation AtLoc, RParenLoc; +public: + ObjCEncodeExpr(QualType T, TypeSourceInfo *EncodedType, + SourceLocation at, SourceLocation rp) + : Expr(ObjCEncodeExprClass, T, VK_LValue, OK_Ordinary, + EncodedType->getType()->isDependentType(), + EncodedType->getType()->isDependentType(), + EncodedType->getType()->isInstantiationDependentType(), + EncodedType->getType()->containsUnexpandedParameterPack()), + EncodedType(EncodedType), AtLoc(at), RParenLoc(rp) {} + + explicit ObjCEncodeExpr(EmptyShell Empty) : Expr(ObjCEncodeExprClass, Empty){} + + + SourceLocation getAtLoc() const { return AtLoc; } + void setAtLoc(SourceLocation L) { AtLoc = L; } + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } + + QualType getEncodedType() const { return EncodedType->getType(); } + + TypeSourceInfo *getEncodedTypeSourceInfo() const { return EncodedType; } + void setEncodedTypeSourceInfo(TypeSourceInfo *EncType) { + EncodedType = EncType; + } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(AtLoc, RParenLoc); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCEncodeExprClass; + } + static bool classof(const ObjCEncodeExpr *) { return true; } + + // Iterators + child_range children() { return child_range(); } +}; + +/// ObjCSelectorExpr used for @selector in Objective-C. +class ObjCSelectorExpr : public Expr { + Selector SelName; + SourceLocation AtLoc, RParenLoc; +public: + ObjCSelectorExpr(QualType T, Selector selInfo, + SourceLocation at, SourceLocation rp) + : Expr(ObjCSelectorExprClass, T, VK_RValue, OK_Ordinary, false, false, + false, false), + SelName(selInfo), AtLoc(at), RParenLoc(rp){} + explicit ObjCSelectorExpr(EmptyShell Empty) + : Expr(ObjCSelectorExprClass, Empty) {} + + Selector getSelector() const { return SelName; } + void setSelector(Selector S) { SelName = S; } + + SourceLocation getAtLoc() const { return AtLoc; } + SourceLocation getRParenLoc() const { return RParenLoc; } + void setAtLoc(SourceLocation L) { AtLoc = L; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(AtLoc, RParenLoc); + } + + /// getNumArgs - Return the number of actual arguments to this call. + unsigned getNumArgs() const { return SelName.getNumArgs(); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCSelectorExprClass; + } + static bool classof(const ObjCSelectorExpr *) { return true; } + + // Iterators + child_range children() { return child_range(); } +}; + +/// ObjCProtocolExpr used for protocol expression in Objective-C. This is used +/// as: @protocol(foo), as in: +/// obj conformsToProtocol:@protocol(foo)] +/// The return type is "Protocol*". +class ObjCProtocolExpr : public Expr { + ObjCProtocolDecl *TheProtocol; + SourceLocation AtLoc, RParenLoc; +public: + ObjCProtocolExpr(QualType T, ObjCProtocolDecl *protocol, + SourceLocation at, SourceLocation rp) + : Expr(ObjCProtocolExprClass, T, VK_RValue, OK_Ordinary, false, false, + false, false), + TheProtocol(protocol), AtLoc(at), RParenLoc(rp) {} + explicit ObjCProtocolExpr(EmptyShell Empty) + : Expr(ObjCProtocolExprClass, Empty) {} + + ObjCProtocolDecl *getProtocol() const { return TheProtocol; } + void setProtocol(ObjCProtocolDecl *P) { TheProtocol = P; } + + SourceLocation getAtLoc() const { return AtLoc; } + SourceLocation getRParenLoc() const { return RParenLoc; } + void setAtLoc(SourceLocation L) { AtLoc = L; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(AtLoc, RParenLoc); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCProtocolExprClass; + } + static bool classof(const ObjCProtocolExpr *) { return true; } + + // Iterators + child_range children() { return child_range(); } +}; + +/// ObjCIvarRefExpr - A reference to an ObjC instance variable. +class ObjCIvarRefExpr : public Expr { + ObjCIvarDecl *D; + Stmt *Base; + SourceLocation Loc; + bool IsArrow:1; // True if this is "X->F", false if this is "X.F". + bool IsFreeIvar:1; // True if ivar reference has no base (self assumed). + +public: + ObjCIvarRefExpr(ObjCIvarDecl *d, QualType t, + SourceLocation l, Expr *base, + bool arrow = false, bool freeIvar = false) : + Expr(ObjCIvarRefExprClass, t, VK_LValue, OK_Ordinary, + /*TypeDependent=*/false, base->isValueDependent(), + base->isInstantiationDependent(), + base->containsUnexpandedParameterPack()), + D(d), Base(base), Loc(l), IsArrow(arrow), IsFreeIvar(freeIvar) {} + + explicit ObjCIvarRefExpr(EmptyShell Empty) + : Expr(ObjCIvarRefExprClass, Empty) {} + + ObjCIvarDecl *getDecl() { return D; } + const ObjCIvarDecl *getDecl() const { return D; } + void setDecl(ObjCIvarDecl *d) { D = d; } + + const Expr *getBase() const { return cast<Expr>(Base); } + Expr *getBase() { return cast<Expr>(Base); } + void setBase(Expr * base) { Base = base; } + + bool isArrow() const { return IsArrow; } + bool isFreeIvar() const { return IsFreeIvar; } + void setIsArrow(bool A) { IsArrow = A; } + void setIsFreeIvar(bool A) { IsFreeIvar = A; } + + SourceLocation getLocation() const { return Loc; } + void setLocation(SourceLocation L) { Loc = L; } + + SourceRange getSourceRange() const LLVM_READONLY { + return isFreeIvar() ? SourceRange(Loc) + : SourceRange(getBase()->getLocStart(), Loc); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCIvarRefExprClass; + } + static bool classof(const ObjCIvarRefExpr *) { return true; } + + // Iterators + child_range children() { return child_range(&Base, &Base+1); } +}; + +/// ObjCPropertyRefExpr - A dot-syntax expression to access an ObjC +/// property. +class ObjCPropertyRefExpr : public Expr { +private: + /// If the bool is true, this is an implicit property reference; the + /// pointer is an (optional) ObjCMethodDecl and Setter may be set. + /// if the bool is false, this is an explicit property reference; + /// the pointer is an ObjCPropertyDecl and Setter is always null. + llvm::PointerIntPair<NamedDecl*, 1, bool> PropertyOrGetter; + + /// \brief Indicates whether the property reference will result in a message + /// to the getter, the setter, or both. + /// This applies to both implicit and explicit property references. + enum MethodRefFlags { + MethodRef_None = 0, + MethodRef_Getter = 0x1, + MethodRef_Setter = 0x2 + }; + + /// \brief Contains the Setter method pointer and MethodRefFlags bit flags. + llvm::PointerIntPair<ObjCMethodDecl *, 2, unsigned> SetterAndMethodRefFlags; + + // FIXME: Maybe we should store the property identifier here, + // because it's not rederivable from the other data when there's an + // implicit property with no getter (because the 'foo' -> 'setFoo:' + // transformation is lossy on the first character). + + SourceLocation IdLoc; + + /// \brief When the receiver in property access is 'super', this is + /// the location of the 'super' keyword. When it's an interface, + /// this is that interface. + SourceLocation ReceiverLoc; + llvm::PointerUnion3<Stmt*, const Type*, ObjCInterfaceDecl*> Receiver; + +public: + ObjCPropertyRefExpr(ObjCPropertyDecl *PD, QualType t, + ExprValueKind VK, ExprObjectKind OK, + SourceLocation l, Expr *base) + : Expr(ObjCPropertyRefExprClass, t, VK, OK, + /*TypeDependent=*/false, base->isValueDependent(), + base->isInstantiationDependent(), + base->containsUnexpandedParameterPack()), + PropertyOrGetter(PD, false), SetterAndMethodRefFlags(), + IdLoc(l), ReceiverLoc(), Receiver(base) { + assert(t->isSpecificPlaceholderType(BuiltinType::PseudoObject)); + } + + ObjCPropertyRefExpr(ObjCPropertyDecl *PD, QualType t, + ExprValueKind VK, ExprObjectKind OK, + SourceLocation l, SourceLocation sl, QualType st) + : Expr(ObjCPropertyRefExprClass, t, VK, OK, + /*TypeDependent=*/false, false, st->isInstantiationDependentType(), + st->containsUnexpandedParameterPack()), + PropertyOrGetter(PD, false), SetterAndMethodRefFlags(), + IdLoc(l), ReceiverLoc(sl), Receiver(st.getTypePtr()) { + assert(t->isSpecificPlaceholderType(BuiltinType::PseudoObject)); + } + + ObjCPropertyRefExpr(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter, + QualType T, ExprValueKind VK, ExprObjectKind OK, + SourceLocation IdLoc, Expr *Base) + : Expr(ObjCPropertyRefExprClass, T, VK, OK, false, + Base->isValueDependent(), Base->isInstantiationDependent(), + Base->containsUnexpandedParameterPack()), + PropertyOrGetter(Getter, true), SetterAndMethodRefFlags(Setter, 0), + IdLoc(IdLoc), ReceiverLoc(), Receiver(Base) { + assert(T->isSpecificPlaceholderType(BuiltinType::PseudoObject)); + } + + ObjCPropertyRefExpr(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter, + QualType T, ExprValueKind VK, ExprObjectKind OK, + SourceLocation IdLoc, + SourceLocation SuperLoc, QualType SuperTy) + : Expr(ObjCPropertyRefExprClass, T, VK, OK, false, false, false, false), + PropertyOrGetter(Getter, true), SetterAndMethodRefFlags(Setter, 0), + IdLoc(IdLoc), ReceiverLoc(SuperLoc), Receiver(SuperTy.getTypePtr()) { + assert(T->isSpecificPlaceholderType(BuiltinType::PseudoObject)); + } + + ObjCPropertyRefExpr(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter, + QualType T, ExprValueKind VK, ExprObjectKind OK, + SourceLocation IdLoc, + SourceLocation ReceiverLoc, ObjCInterfaceDecl *Receiver) + : Expr(ObjCPropertyRefExprClass, T, VK, OK, false, false, false, false), + PropertyOrGetter(Getter, true), SetterAndMethodRefFlags(Setter, 0), + IdLoc(IdLoc), ReceiverLoc(ReceiverLoc), Receiver(Receiver) { + assert(T->isSpecificPlaceholderType(BuiltinType::PseudoObject)); + } + + explicit ObjCPropertyRefExpr(EmptyShell Empty) + : Expr(ObjCPropertyRefExprClass, Empty) {} + + bool isImplicitProperty() const { return PropertyOrGetter.getInt(); } + bool isExplicitProperty() const { return !PropertyOrGetter.getInt(); } + + ObjCPropertyDecl *getExplicitProperty() const { + assert(!isImplicitProperty()); + return cast<ObjCPropertyDecl>(PropertyOrGetter.getPointer()); + } + + ObjCMethodDecl *getImplicitPropertyGetter() const { + assert(isImplicitProperty()); + return cast_or_null<ObjCMethodDecl>(PropertyOrGetter.getPointer()); + } + + ObjCMethodDecl *getImplicitPropertySetter() const { + assert(isImplicitProperty()); + return SetterAndMethodRefFlags.getPointer(); + } + + Selector getGetterSelector() const { + if (isImplicitProperty()) + return getImplicitPropertyGetter()->getSelector(); + return getExplicitProperty()->getGetterName(); + } + + Selector getSetterSelector() const { + if (isImplicitProperty()) + return getImplicitPropertySetter()->getSelector(); + return getExplicitProperty()->getSetterName(); + } + + /// \brief True if the property reference will result in a message to the + /// getter. + /// This applies to both implicit and explicit property references. + bool isMessagingGetter() const { + return SetterAndMethodRefFlags.getInt() & MethodRef_Getter; + } + + /// \brief True if the property reference will result in a message to the + /// setter. + /// This applies to both implicit and explicit property references. + bool isMessagingSetter() const { + return SetterAndMethodRefFlags.getInt() & MethodRef_Setter; + } + + void setIsMessagingGetter(bool val = true) { + setMethodRefFlag(MethodRef_Getter, val); + } + + void setIsMessagingSetter(bool val = true) { + setMethodRefFlag(MethodRef_Setter, val); + } + + const Expr *getBase() const { + return cast<Expr>(Receiver.get<Stmt*>()); + } + Expr *getBase() { + return cast<Expr>(Receiver.get<Stmt*>()); + } + + SourceLocation getLocation() const { return IdLoc; } + + SourceLocation getReceiverLocation() const { return ReceiverLoc; } + QualType getSuperReceiverType() const { + return QualType(Receiver.get<const Type*>(), 0); + } + QualType getGetterResultType() const { + QualType ResultType; + if (isExplicitProperty()) { + const ObjCPropertyDecl *PDecl = getExplicitProperty(); + if (const ObjCMethodDecl *Getter = PDecl->getGetterMethodDecl()) + ResultType = Getter->getResultType(); + else + ResultType = PDecl->getType(); + } else { + const ObjCMethodDecl *Getter = getImplicitPropertyGetter(); + if (Getter) + ResultType = Getter->getResultType(); // with reference! + } + return ResultType; + } + + QualType getSetterArgType() const { + QualType ArgType; + if (isImplicitProperty()) { + const ObjCMethodDecl *Setter = getImplicitPropertySetter(); + ObjCMethodDecl::param_const_iterator P = Setter->param_begin(); + ArgType = (*P)->getType(); + } else { + if (ObjCPropertyDecl *PDecl = getExplicitProperty()) + if (const ObjCMethodDecl *Setter = PDecl->getSetterMethodDecl()) { + ObjCMethodDecl::param_const_iterator P = Setter->param_begin(); + ArgType = (*P)->getType(); + } + if (ArgType.isNull()) + ArgType = getType(); + } + return ArgType; + } + + ObjCInterfaceDecl *getClassReceiver() const { + return Receiver.get<ObjCInterfaceDecl*>(); + } + bool isObjectReceiver() const { return Receiver.is<Stmt*>(); } + bool isSuperReceiver() const { return Receiver.is<const Type*>(); } + bool isClassReceiver() const { return Receiver.is<ObjCInterfaceDecl*>(); } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange((isObjectReceiver() ? getBase()->getLocStart() + : getReceiverLocation()), + IdLoc); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCPropertyRefExprClass; + } + static bool classof(const ObjCPropertyRefExpr *) { return true; } + + // Iterators + child_range children() { + if (Receiver.is<Stmt*>()) { + Stmt **begin = reinterpret_cast<Stmt**>(&Receiver); // hack! + return child_range(begin, begin+1); + } + return child_range(); + } + +private: + friend class ASTStmtReader; + friend class ASTStmtWriter; + void setExplicitProperty(ObjCPropertyDecl *D, unsigned methRefFlags) { + PropertyOrGetter.setPointer(D); + PropertyOrGetter.setInt(false); + SetterAndMethodRefFlags.setPointer(0); + SetterAndMethodRefFlags.setInt(methRefFlags); + } + void setImplicitProperty(ObjCMethodDecl *Getter, ObjCMethodDecl *Setter, + unsigned methRefFlags) { + PropertyOrGetter.setPointer(Getter); + PropertyOrGetter.setInt(true); + SetterAndMethodRefFlags.setPointer(Setter); + SetterAndMethodRefFlags.setInt(methRefFlags); + } + void setBase(Expr *Base) { Receiver = Base; } + void setSuperReceiver(QualType T) { Receiver = T.getTypePtr(); } + void setClassReceiver(ObjCInterfaceDecl *D) { Receiver = D; } + + void setLocation(SourceLocation L) { IdLoc = L; } + void setReceiverLocation(SourceLocation Loc) { ReceiverLoc = Loc; } + + void setMethodRefFlag(MethodRefFlags flag, bool val) { + unsigned f = SetterAndMethodRefFlags.getInt(); + if (val) + f |= flag; + else + f &= ~flag; + SetterAndMethodRefFlags.setInt(f); + } +}; + +/// ObjCSubscriptRefExpr - used for array and dictionary subscripting. +/// array[4] = array[3]; dictionary[key] = dictionary[alt_key]; +/// +class ObjCSubscriptRefExpr : public Expr { + // Location of ']' in an indexing expression. + SourceLocation RBracket; + // array/dictionary base expression. + // for arrays, this is a numeric expression. For dictionaries, this is + // an objective-c object pointer expression. + enum { BASE, KEY, END_EXPR }; + Stmt* SubExprs[END_EXPR]; + + ObjCMethodDecl *GetAtIndexMethodDecl; + + // For immutable objects this is null. When ObjCSubscriptRefExpr is to read + // an indexed object this is null too. + ObjCMethodDecl *SetAtIndexMethodDecl; + +public: + + ObjCSubscriptRefExpr(Expr *base, Expr *key, QualType T, + ExprValueKind VK, ExprObjectKind OK, + ObjCMethodDecl *getMethod, + ObjCMethodDecl *setMethod, SourceLocation RB) + : Expr(ObjCSubscriptRefExprClass, T, VK, OK, + base->isTypeDependent() || key->isTypeDependent(), + base->isValueDependent() || key->isValueDependent(), + base->isInstantiationDependent() || key->isInstantiationDependent(), + (base->containsUnexpandedParameterPack() || + key->containsUnexpandedParameterPack())), + RBracket(RB), + GetAtIndexMethodDecl(getMethod), + SetAtIndexMethodDecl(setMethod) + {SubExprs[BASE] = base; SubExprs[KEY] = key;} + + explicit ObjCSubscriptRefExpr(EmptyShell Empty) + : Expr(ObjCSubscriptRefExprClass, Empty) {} + + static ObjCSubscriptRefExpr *Create(ASTContext &C, + Expr *base, + Expr *key, QualType T, + ObjCMethodDecl *getMethod, + ObjCMethodDecl *setMethod, + SourceLocation RB); + + SourceLocation getRBracket() const { return RBracket; } + void setRBracket(SourceLocation RB) { RBracket = RB; } + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(SubExprs[BASE]->getLocStart(), RBracket); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCSubscriptRefExprClass; + } + static bool classof(const ObjCSubscriptRefExpr *) { return true; } + + Expr *getBaseExpr() const { return cast<Expr>(SubExprs[BASE]); } + void setBaseExpr(Stmt *S) { SubExprs[BASE] = S; } + + Expr *getKeyExpr() const { return cast<Expr>(SubExprs[KEY]); } + void setKeyExpr(Stmt *S) { SubExprs[KEY] = S; } + + ObjCMethodDecl *getAtIndexMethodDecl() const { + return GetAtIndexMethodDecl; + } + + ObjCMethodDecl *setAtIndexMethodDecl() const { + return SetAtIndexMethodDecl; + } + + bool isArraySubscriptRefExpr() const { + return getKeyExpr()->getType()->isIntegralOrEnumerationType(); + } + + child_range children() { + return child_range(SubExprs, SubExprs+END_EXPR); + } +private: + friend class ASTStmtReader; +}; + + +/// \brief An expression that sends a message to the given Objective-C +/// object or class. +/// +/// The following contains two message send expressions: +/// +/// \code +/// [[NSString alloc] initWithString:@"Hello"] +/// \endcode +/// +/// The innermost message send invokes the "alloc" class method on the +/// NSString class, while the outermost message send invokes the +/// "initWithString" instance method on the object returned from +/// NSString's "alloc". In all, an Objective-C message send can take +/// on four different (although related) forms: +/// +/// 1. Send to an object instance. +/// 2. Send to a class. +/// 3. Send to the superclass instance of the current class. +/// 4. Send to the superclass of the current class. +/// +/// All four kinds of message sends are modeled by the ObjCMessageExpr +/// class, and can be distinguished via \c getReceiverKind(). Example: +/// +class ObjCMessageExpr : public Expr { + /// \brief Stores either the selector that this message is sending + /// to (when \c HasMethod is zero) or an \c ObjCMethodDecl pointer + /// referring to the method that we type-checked against. + uintptr_t SelectorOrMethod; + + enum { NumArgsBitWidth = 16 }; + + /// \brief The number of arguments in the message send, not + /// including the receiver. + unsigned NumArgs : NumArgsBitWidth; + + void setNumArgs(unsigned Num) { + assert((Num >> NumArgsBitWidth) == 0 && "Num of args is out of range!"); + NumArgs = Num; + } + + /// \brief The kind of message send this is, which is one of the + /// ReceiverKind values. + /// + /// We pad this out to a byte to avoid excessive masking and shifting. + unsigned Kind : 8; + + /// \brief Whether we have an actual method prototype in \c + /// SelectorOrMethod. + /// + /// When non-zero, we have a method declaration; otherwise, we just + /// have a selector. + unsigned HasMethod : 1; + + /// \brief Whether this message send is a "delegate init call", + /// i.e. a call of an init method on self from within an init method. + unsigned IsDelegateInitCall : 1; + + /// \brief Whether this message send was implicitly generated by + /// the implementation rather than explicitly written by the user. + unsigned IsImplicit : 1; + + /// \brief Whether the locations of the selector identifiers are in a + /// "standard" position, a enum SelectorLocationsKind. + unsigned SelLocsKind : 2; + + /// \brief When the message expression is a send to 'super', this is + /// the location of the 'super' keyword. + SourceLocation SuperLoc; + + /// \brief The source locations of the open and close square + /// brackets ('[' and ']', respectively). + SourceLocation LBracLoc, RBracLoc; + + ObjCMessageExpr(EmptyShell Empty, unsigned NumArgs) + : Expr(ObjCMessageExprClass, Empty), SelectorOrMethod(0), Kind(0), + HasMethod(0), IsDelegateInitCall(0), IsImplicit(0), SelLocsKind(0) { + setNumArgs(NumArgs); + } + + ObjCMessageExpr(QualType T, ExprValueKind VK, + SourceLocation LBracLoc, + SourceLocation SuperLoc, + bool IsInstanceSuper, + QualType SuperType, + Selector Sel, + ArrayRef<SourceLocation> SelLocs, + SelectorLocationsKind SelLocsK, + ObjCMethodDecl *Method, + ArrayRef<Expr *> Args, + SourceLocation RBracLoc, + bool isImplicit); + ObjCMessageExpr(QualType T, ExprValueKind VK, + SourceLocation LBracLoc, + TypeSourceInfo *Receiver, + Selector Sel, + ArrayRef<SourceLocation> SelLocs, + SelectorLocationsKind SelLocsK, + ObjCMethodDecl *Method, + ArrayRef<Expr *> Args, + SourceLocation RBracLoc, + bool isImplicit); + ObjCMessageExpr(QualType T, ExprValueKind VK, + SourceLocation LBracLoc, + Expr *Receiver, + Selector Sel, + ArrayRef<SourceLocation> SelLocs, + SelectorLocationsKind SelLocsK, + ObjCMethodDecl *Method, + ArrayRef<Expr *> Args, + SourceLocation RBracLoc, + bool isImplicit); + + void initArgsAndSelLocs(ArrayRef<Expr *> Args, + ArrayRef<SourceLocation> SelLocs, + SelectorLocationsKind SelLocsK); + + /// \brief Retrieve the pointer value of the message receiver. + void *getReceiverPointer() const { + return *const_cast<void **>( + reinterpret_cast<const void * const*>(this + 1)); + } + + /// \brief Set the pointer value of the message receiver. + void setReceiverPointer(void *Value) { + *reinterpret_cast<void **>(this + 1) = Value; + } + + SelectorLocationsKind getSelLocsKind() const { + return (SelectorLocationsKind)SelLocsKind; + } + bool hasStandardSelLocs() const { + return getSelLocsKind() != SelLoc_NonStandard; + } + + /// \brief Get a pointer to the stored selector identifiers locations array. + /// No locations will be stored if HasStandardSelLocs is true. + SourceLocation *getStoredSelLocs() { + return reinterpret_cast<SourceLocation*>(getArgs() + getNumArgs()); + } + const SourceLocation *getStoredSelLocs() const { + return reinterpret_cast<const SourceLocation*>(getArgs() + getNumArgs()); + } + + /// \brief Get the number of stored selector identifiers locations. + /// No locations will be stored if HasStandardSelLocs is true. + unsigned getNumStoredSelLocs() const { + if (hasStandardSelLocs()) + return 0; + return getNumSelectorLocs(); + } + + static ObjCMessageExpr *alloc(ASTContext &C, + ArrayRef<Expr *> Args, + SourceLocation RBraceLoc, + ArrayRef<SourceLocation> SelLocs, + Selector Sel, + SelectorLocationsKind &SelLocsK); + static ObjCMessageExpr *alloc(ASTContext &C, + unsigned NumArgs, + unsigned NumStoredSelLocs); + +public: + /// \brief The kind of receiver this message is sending to. + enum ReceiverKind { + /// \brief The receiver is a class. + Class = 0, + /// \brief The receiver is an object instance. + Instance, + /// \brief The receiver is a superclass. + SuperClass, + /// \brief The receiver is the instance of the superclass object. + SuperInstance + }; + + /// \brief Create a message send to super. + /// + /// \param Context The ASTContext in which this expression will be created. + /// + /// \param T The result type of this message. + /// + /// \param VK The value kind of this message. A message returning + /// a l-value or r-value reference will be an l-value or x-value, + /// respectively. + /// + /// \param LBrac The location of the open square bracket '['. + /// + /// \param SuperLoc The location of the "super" keyword. + /// + /// \param IsInstanceSuper Whether this is an instance "super" + /// message (otherwise, it's a class "super" message). + /// + /// \param Sel The selector used to determine which method gets called. + /// + /// \param Method The Objective-C method against which this message + /// send was type-checked. May be NULL. + /// + /// \param Args The message send arguments. + /// + /// \param NumArgs The number of arguments. + /// + /// \param RBracLoc The location of the closing square bracket ']'. + static ObjCMessageExpr *Create(ASTContext &Context, QualType T, + ExprValueKind VK, + SourceLocation LBracLoc, + SourceLocation SuperLoc, + bool IsInstanceSuper, + QualType SuperType, + Selector Sel, + ArrayRef<SourceLocation> SelLocs, + ObjCMethodDecl *Method, + ArrayRef<Expr *> Args, + SourceLocation RBracLoc, + bool isImplicit); + + /// \brief Create a class message send. + /// + /// \param Context The ASTContext in which this expression will be created. + /// + /// \param T The result type of this message. + /// + /// \param VK The value kind of this message. A message returning + /// a l-value or r-value reference will be an l-value or x-value, + /// respectively. + /// + /// \param LBrac The location of the open square bracket '['. + /// + /// \param Receiver The type of the receiver, including + /// source-location information. + /// + /// \param Sel The selector used to determine which method gets called. + /// + /// \param Method The Objective-C method against which this message + /// send was type-checked. May be NULL. + /// + /// \param Args The message send arguments. + /// + /// \param NumArgs The number of arguments. + /// + /// \param RBracLoc The location of the closing square bracket ']'. + static ObjCMessageExpr *Create(ASTContext &Context, QualType T, + ExprValueKind VK, + SourceLocation LBracLoc, + TypeSourceInfo *Receiver, + Selector Sel, + ArrayRef<SourceLocation> SelLocs, + ObjCMethodDecl *Method, + ArrayRef<Expr *> Args, + SourceLocation RBracLoc, + bool isImplicit); + + /// \brief Create an instance message send. + /// + /// \param Context The ASTContext in which this expression will be created. + /// + /// \param T The result type of this message. + /// + /// \param VK The value kind of this message. A message returning + /// a l-value or r-value reference will be an l-value or x-value, + /// respectively. + /// + /// \param LBrac The location of the open square bracket '['. + /// + /// \param Receiver The expression used to produce the object that + /// will receive this message. + /// + /// \param Sel The selector used to determine which method gets called. + /// + /// \param Method The Objective-C method against which this message + /// send was type-checked. May be NULL. + /// + /// \param Args The message send arguments. + /// + /// \param NumArgs The number of arguments. + /// + /// \param RBracLoc The location of the closing square bracket ']'. + static ObjCMessageExpr *Create(ASTContext &Context, QualType T, + ExprValueKind VK, + SourceLocation LBracLoc, + Expr *Receiver, + Selector Sel, + ArrayRef<SourceLocation> SeLocs, + ObjCMethodDecl *Method, + ArrayRef<Expr *> Args, + SourceLocation RBracLoc, + bool isImplicit); + + /// \brief Create an empty Objective-C message expression, to be + /// filled in by subsequent calls. + /// + /// \param Context The context in which the message send will be created. + /// + /// \param NumArgs The number of message arguments, not including + /// the receiver. + static ObjCMessageExpr *CreateEmpty(ASTContext &Context, + unsigned NumArgs, + unsigned NumStoredSelLocs); + + /// \brief Indicates whether the message send was implicitly + /// generated by the implementation. If false, it was written explicitly + /// in the source code. + bool isImplicit() const { return IsImplicit; } + + /// \brief Determine the kind of receiver that this message is being + /// sent to. + ReceiverKind getReceiverKind() const { return (ReceiverKind)Kind; } + + /// \brief Source range of the receiver. + SourceRange getReceiverRange() const; + + /// \brief Determine whether this is an instance message to either a + /// computed object or to super. + bool isInstanceMessage() const { + return getReceiverKind() == Instance || getReceiverKind() == SuperInstance; + } + + /// \brief Determine whether this is an class message to either a + /// specified class or to super. + bool isClassMessage() const { + return getReceiverKind() == Class || getReceiverKind() == SuperClass; + } + + /// \brief Returns the receiver of an instance message. + /// + /// \brief Returns the object expression for an instance message, or + /// NULL for a message that is not an instance message. + Expr *getInstanceReceiver() { + if (getReceiverKind() == Instance) + return static_cast<Expr *>(getReceiverPointer()); + + return 0; + } + const Expr *getInstanceReceiver() const { + return const_cast<ObjCMessageExpr*>(this)->getInstanceReceiver(); + } + + /// \brief Turn this message send into an instance message that + /// computes the receiver object with the given expression. + void setInstanceReceiver(Expr *rec) { + Kind = Instance; + setReceiverPointer(rec); + } + + /// \brief Returns the type of a class message send, or NULL if the + /// message is not a class message. + QualType getClassReceiver() const { + if (TypeSourceInfo *TSInfo = getClassReceiverTypeInfo()) + return TSInfo->getType(); + + return QualType(); + } + + /// \brief Returns a type-source information of a class message + /// send, or NULL if the message is not a class message. + TypeSourceInfo *getClassReceiverTypeInfo() const { + if (getReceiverKind() == Class) + return reinterpret_cast<TypeSourceInfo *>(getReceiverPointer()); + return 0; + } + + void setClassReceiver(TypeSourceInfo *TSInfo) { + Kind = Class; + setReceiverPointer(TSInfo); + } + + /// \brief Retrieve the location of the 'super' keyword for a class + /// or instance message to 'super', otherwise an invalid source location. + SourceLocation getSuperLoc() const { + if (getReceiverKind() == SuperInstance || getReceiverKind() == SuperClass) + return SuperLoc; + + return SourceLocation(); + } + + /// \brief Retrieve the Objective-C interface to which this message + /// is being directed, if known. + /// + /// This routine cross-cuts all of the different kinds of message + /// sends to determine what the underlying (statically known) type + /// of the receiver will be; use \c getReceiverKind() to determine + /// whether the message is a class or an instance method, whether it + /// is a send to super or not, etc. + /// + /// \returns The Objective-C interface if known, otherwise NULL. + ObjCInterfaceDecl *getReceiverInterface() const; + + /// \brief Retrieve the type referred to by 'super'. + /// + /// The returned type will either be an ObjCInterfaceType (for an + /// class message to super) or an ObjCObjectPointerType that refers + /// to a class (for an instance message to super); + QualType getSuperType() const { + if (getReceiverKind() == SuperInstance || getReceiverKind() == SuperClass) + return QualType::getFromOpaquePtr(getReceiverPointer()); + + return QualType(); + } + + void setSuper(SourceLocation Loc, QualType T, bool IsInstanceSuper) { + Kind = IsInstanceSuper? SuperInstance : SuperClass; + SuperLoc = Loc; + setReceiverPointer(T.getAsOpaquePtr()); + } + + Selector getSelector() const; + + void setSelector(Selector S) { + HasMethod = false; + SelectorOrMethod = reinterpret_cast<uintptr_t>(S.getAsOpaquePtr()); + } + + const ObjCMethodDecl *getMethodDecl() const { + if (HasMethod) + return reinterpret_cast<const ObjCMethodDecl *>(SelectorOrMethod); + + return 0; + } + + ObjCMethodDecl *getMethodDecl() { + if (HasMethod) + return reinterpret_cast<ObjCMethodDecl *>(SelectorOrMethod); + + return 0; + } + + void setMethodDecl(ObjCMethodDecl *MD) { + HasMethod = true; + SelectorOrMethod = reinterpret_cast<uintptr_t>(MD); + } + + ObjCMethodFamily getMethodFamily() const { + if (HasMethod) return getMethodDecl()->getMethodFamily(); + return getSelector().getMethodFamily(); + } + + /// \brief Return the number of actual arguments in this message, + /// not counting the receiver. + unsigned getNumArgs() const { return NumArgs; } + + /// \brief Retrieve the arguments to this message, not including the + /// receiver. + Expr **getArgs() { + return reinterpret_cast<Expr **>(this + 1) + 1; + } + const Expr * const *getArgs() const { + return reinterpret_cast<const Expr * const *>(this + 1) + 1; + } + + /// getArg - Return the specified argument. + Expr *getArg(unsigned Arg) { + assert(Arg < NumArgs && "Arg access out of range!"); + return cast<Expr>(getArgs()[Arg]); + } + const Expr *getArg(unsigned Arg) const { + assert(Arg < NumArgs && "Arg access out of range!"); + return cast<Expr>(getArgs()[Arg]); + } + /// setArg - Set the specified argument. + void setArg(unsigned Arg, Expr *ArgExpr) { + assert(Arg < NumArgs && "Arg access out of range!"); + getArgs()[Arg] = ArgExpr; + } + + /// isDelegateInitCall - Answers whether this message send has been + /// tagged as a "delegate init call", i.e. a call to a method in the + /// -init family on self from within an -init method implementation. + bool isDelegateInitCall() const { return IsDelegateInitCall; } + void setDelegateInitCall(bool isDelegate) { IsDelegateInitCall = isDelegate; } + + SourceLocation getLeftLoc() const { return LBracLoc; } + SourceLocation getRightLoc() const { return RBracLoc; } + + SourceLocation getSelectorStartLoc() const { + if (isImplicit()) + return getLocStart(); + return getSelectorLoc(0); + } + SourceLocation getSelectorLoc(unsigned Index) const { + assert(Index < getNumSelectorLocs() && "Index out of range!"); + if (hasStandardSelLocs()) + return getStandardSelectorLoc(Index, getSelector(), + getSelLocsKind() == SelLoc_StandardWithSpace, + llvm::makeArrayRef(const_cast<Expr**>(getArgs()), + getNumArgs()), + RBracLoc); + return getStoredSelLocs()[Index]; + } + + void getSelectorLocs(SmallVectorImpl<SourceLocation> &SelLocs) const; + + unsigned getNumSelectorLocs() const { + if (isImplicit()) + return 0; + Selector Sel = getSelector(); + if (Sel.isUnarySelector()) + return 1; + return Sel.getNumArgs(); + } + + void setSourceRange(SourceRange R) { + LBracLoc = R.getBegin(); + RBracLoc = R.getEnd(); + } + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(LBracLoc, RBracLoc); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCMessageExprClass; + } + static bool classof(const ObjCMessageExpr *) { return true; } + + // Iterators + child_range children(); + + typedef ExprIterator arg_iterator; + typedef ConstExprIterator const_arg_iterator; + + arg_iterator arg_begin() { return reinterpret_cast<Stmt **>(getArgs()); } + arg_iterator arg_end() { + return reinterpret_cast<Stmt **>(getArgs() + NumArgs); + } + const_arg_iterator arg_begin() const { + return reinterpret_cast<Stmt const * const*>(getArgs()); + } + const_arg_iterator arg_end() const { + return reinterpret_cast<Stmt const * const*>(getArgs() + NumArgs); + } + + friend class ASTStmtReader; + friend class ASTStmtWriter; +}; + +/// ObjCIsaExpr - Represent X->isa and X.isa when X is an ObjC 'id' type. +/// (similar in spirit to MemberExpr). +class ObjCIsaExpr : public Expr { + /// Base - the expression for the base object pointer. + Stmt *Base; + + /// IsaMemberLoc - This is the location of the 'isa'. + SourceLocation IsaMemberLoc; + + /// IsArrow - True if this is "X->F", false if this is "X.F". + bool IsArrow; +public: + ObjCIsaExpr(Expr *base, bool isarrow, SourceLocation l, QualType ty) + : Expr(ObjCIsaExprClass, ty, VK_LValue, OK_Ordinary, + /*TypeDependent=*/false, base->isValueDependent(), + base->isInstantiationDependent(), + /*ContainsUnexpandedParameterPack=*/false), + Base(base), IsaMemberLoc(l), IsArrow(isarrow) {} + + /// \brief Build an empty expression. + explicit ObjCIsaExpr(EmptyShell Empty) : Expr(ObjCIsaExprClass, Empty) { } + + void setBase(Expr *E) { Base = E; } + Expr *getBase() const { return cast<Expr>(Base); } + + bool isArrow() const { return IsArrow; } + void setArrow(bool A) { IsArrow = A; } + + /// getMemberLoc - Return the location of the "member", in X->F, it is the + /// location of 'F'. + SourceLocation getIsaMemberLoc() const { return IsaMemberLoc; } + void setIsaMemberLoc(SourceLocation L) { IsaMemberLoc = L; } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(getBase()->getLocStart(), IsaMemberLoc); + } + + SourceLocation getExprLoc() const LLVM_READONLY { return IsaMemberLoc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCIsaExprClass; + } + static bool classof(const ObjCIsaExpr *) { return true; } + + // Iterators + child_range children() { return child_range(&Base, &Base+1); } +}; + + +/// ObjCIndirectCopyRestoreExpr - Represents the passing of a function +/// argument by indirect copy-restore in ARC. This is used to support +/// passing indirect arguments with the wrong lifetime, e.g. when +/// passing the address of a __strong local variable to an 'out' +/// parameter. This expression kind is only valid in an "argument" +/// position to some sort of call expression. +/// +/// The parameter must have type 'pointer to T', and the argument must +/// have type 'pointer to U', where T and U agree except possibly in +/// qualification. If the argument value is null, then a null pointer +/// is passed; otherwise it points to an object A, and: +/// 1. A temporary object B of type T is initialized, either by +/// zero-initialization (used when initializing an 'out' parameter) +/// or copy-initialization (used when initializing an 'inout' +/// parameter). +/// 2. The address of the temporary is passed to the function. +/// 3. If the call completes normally, A is move-assigned from B. +/// 4. Finally, A is destroyed immediately. +/// +/// Currently 'T' must be a retainable object lifetime and must be +/// __autoreleasing; this qualifier is ignored when initializing +/// the value. +class ObjCIndirectCopyRestoreExpr : public Expr { + Stmt *Operand; + + // unsigned ObjCIndirectCopyRestoreBits.ShouldCopy : 1; + + friend class ASTReader; + friend class ASTStmtReader; + + void setShouldCopy(bool shouldCopy) { + ObjCIndirectCopyRestoreExprBits.ShouldCopy = shouldCopy; + } + + explicit ObjCIndirectCopyRestoreExpr(EmptyShell Empty) + : Expr(ObjCIndirectCopyRestoreExprClass, Empty) { } + +public: + ObjCIndirectCopyRestoreExpr(Expr *operand, QualType type, bool shouldCopy) + : Expr(ObjCIndirectCopyRestoreExprClass, type, VK_LValue, OK_Ordinary, + operand->isTypeDependent(), operand->isValueDependent(), + operand->isInstantiationDependent(), + operand->containsUnexpandedParameterPack()), + Operand(operand) { + setShouldCopy(shouldCopy); + } + + Expr *getSubExpr() { return cast<Expr>(Operand); } + const Expr *getSubExpr() const { return cast<Expr>(Operand); } + + /// shouldCopy - True if we should do the 'copy' part of the + /// copy-restore. If false, the temporary will be zero-initialized. + bool shouldCopy() const { return ObjCIndirectCopyRestoreExprBits.ShouldCopy; } + + child_range children() { return child_range(&Operand, &Operand+1); } + + // Source locations are determined by the subexpression. + SourceRange getSourceRange() const LLVM_READONLY { + return Operand->getSourceRange(); + } + SourceLocation getExprLoc() const LLVM_READONLY { + return getSubExpr()->getExprLoc(); + } + + static bool classof(const Stmt *s) { + return s->getStmtClass() == ObjCIndirectCopyRestoreExprClass; + } + static bool classof(const ObjCIndirectCopyRestoreExpr *) { return true; } +}; + +/// \brief An Objective-C "bridged" cast expression, which casts between +/// Objective-C pointers and C pointers, transferring ownership in the process. +/// +/// \code +/// NSString *str = (__bridge_transfer NSString *)CFCreateString(); +/// \endcode +class ObjCBridgedCastExpr : public ExplicitCastExpr { + SourceLocation LParenLoc; + SourceLocation BridgeKeywordLoc; + unsigned Kind : 2; + + friend class ASTStmtReader; + friend class ASTStmtWriter; + +public: + ObjCBridgedCastExpr(SourceLocation LParenLoc, ObjCBridgeCastKind Kind, + CastKind CK, SourceLocation BridgeKeywordLoc, + TypeSourceInfo *TSInfo, Expr *Operand) + : ExplicitCastExpr(ObjCBridgedCastExprClass, TSInfo->getType(), VK_RValue, + CK, Operand, 0, TSInfo), + LParenLoc(LParenLoc), BridgeKeywordLoc(BridgeKeywordLoc), Kind(Kind) { } + + /// \brief Construct an empty Objective-C bridged cast. + explicit ObjCBridgedCastExpr(EmptyShell Shell) + : ExplicitCastExpr(ObjCBridgedCastExprClass, Shell, 0) { } + + SourceLocation getLParenLoc() const { return LParenLoc; } + + /// \brief Determine which kind of bridge is being performed via this cast. + ObjCBridgeCastKind getBridgeKind() const { + return static_cast<ObjCBridgeCastKind>(Kind); + } + + /// \brief Retrieve the kind of bridge being performed as a string. + StringRef getBridgeKindName() const; + + /// \brief The location of the bridge keyword. + SourceLocation getBridgeKeywordLoc() const { return BridgeKeywordLoc; } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(LParenLoc, getSubExpr()->getLocEnd()); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCBridgedCastExprClass; + } + static bool classof(const ObjCBridgedCastExpr *) { return true; } + +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/AST/ExternalASTSource.h b/clang/include/clang/AST/ExternalASTSource.h new file mode 100644 index 0000000..e2a60d5 --- /dev/null +++ b/clang/include/clang/AST/ExternalASTSource.h @@ -0,0 +1,528 @@ +//===--- ExternalASTSource.h - Abstract External AST Interface --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ExternalASTSource interface, which enables +// construction of AST nodes from some external source. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H +#define LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H + +#include "clang/AST/DeclBase.h" +#include "clang/AST/CharUnits.h" +#include "llvm/ADT/DenseMap.h" + +namespace clang { + +class ASTConsumer; +class CXXBaseSpecifier; +class DeclarationName; +class ExternalSemaSource; // layering violation required for downcasting +class NamedDecl; +class Selector; +class Stmt; +class TagDecl; + +/// \brief Enumeration describing the result of loading information from +/// an external source. +enum ExternalLoadResult { + /// \brief Loading the external information has succeeded. + ELR_Success, + + /// \brief Loading the external information has failed. + ELR_Failure, + + /// \brief The external information has already been loaded, and therefore + /// no additional processing is required. + ELR_AlreadyLoaded +}; + +/// \brief Abstract interface for external sources of AST nodes. +/// +/// External AST sources provide AST nodes constructed from some +/// external source, such as a precompiled header. External AST +/// sources can resolve types and declarations from abstract IDs into +/// actual type and declaration nodes, and read parts of declaration +/// contexts. +class ExternalASTSource { + /// \brief Whether this AST source also provides information for + /// semantic analysis. + bool SemaSource; + + friend class ExternalSemaSource; + +public: + ExternalASTSource() : SemaSource(false) { } + + virtual ~ExternalASTSource(); + + /// \brief RAII class for safely pairing a StartedDeserializing call + /// with FinishedDeserializing. + class Deserializing { + ExternalASTSource *Source; + public: + explicit Deserializing(ExternalASTSource *source) : Source(source) { + assert(Source); + Source->StartedDeserializing(); + } + ~Deserializing() { + Source->FinishedDeserializing(); + } + }; + + /// \brief Resolve a declaration ID into a declaration, potentially + /// building a new declaration. + /// + /// This method only needs to be implemented if the AST source ever + /// passes back decl sets as VisibleDeclaration objects. + /// + /// The default implementation of this method is a no-op. + virtual Decl *GetExternalDecl(uint32_t ID); + + /// \brief Resolve a selector ID into a selector. + /// + /// This operation only needs to be implemented if the AST source + /// returns non-zero for GetNumKnownSelectors(). + /// + /// The default implementation of this method is a no-op. + virtual Selector GetExternalSelector(uint32_t ID); + + /// \brief Returns the number of selectors known to the external AST + /// source. + /// + /// The default implementation of this method is a no-op. + virtual uint32_t GetNumExternalSelectors(); + + /// \brief Resolve the offset of a statement in the decl stream into + /// a statement. + /// + /// This operation is meant to be used via a LazyOffsetPtr. It only + /// needs to be implemented if the AST source uses methods like + /// FunctionDecl::setLazyBody when building decls. + /// + /// The default implementation of this method is a no-op. + virtual Stmt *GetExternalDeclStmt(uint64_t Offset); + + /// \brief Resolve the offset of a set of C++ base specifiers in the decl + /// stream into an array of specifiers. + /// + /// The default implementation of this method is a no-op. + virtual CXXBaseSpecifier *GetExternalCXXBaseSpecifiers(uint64_t Offset); + + /// \brief Finds all declarations with the given name in the + /// given context. + /// + /// Generally the final step of this method is either to call + /// SetExternalVisibleDeclsForName or to recursively call lookup on + /// the DeclContext after calling SetExternalVisibleDecls. + /// + /// The default implementation of this method is a no-op. + virtual DeclContextLookupResult + FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name); + + /// \brief Ensures that the table of all visible declarations inside this + /// context is up to date. + /// + /// The default implementation of this functino is a no-op. + virtual void completeVisibleDeclsMap(const DeclContext *DC); + + /// \brief Finds all declarations lexically contained within the given + /// DeclContext, after applying an optional filter predicate. + /// + /// \param isKindWeWant a predicate function that returns true if the passed + /// declaration kind is one we are looking for. If NULL, all declarations + /// are returned. + /// + /// \return an indication of whether the load succeeded or failed. + /// + /// The default implementation of this method is a no-op. + virtual ExternalLoadResult FindExternalLexicalDecls(const DeclContext *DC, + bool (*isKindWeWant)(Decl::Kind), + SmallVectorImpl<Decl*> &Result); + + /// \brief Finds all declarations lexically contained within the given + /// DeclContext. + /// + /// \return true if an error occurred + ExternalLoadResult FindExternalLexicalDecls(const DeclContext *DC, + SmallVectorImpl<Decl*> &Result) { + return FindExternalLexicalDecls(DC, 0, Result); + } + + template <typename DeclTy> + ExternalLoadResult FindExternalLexicalDeclsBy(const DeclContext *DC, + SmallVectorImpl<Decl*> &Result) { + return FindExternalLexicalDecls(DC, DeclTy::classofKind, Result); + } + + /// \brief Get the decls that are contained in a file in the Offset/Length + /// range. \arg Length can be 0 to indicate a point at \arg Offset instead of + /// a range. + virtual void FindFileRegionDecls(FileID File, unsigned Offset,unsigned Length, + SmallVectorImpl<Decl *> &Decls) {} + + /// \brief Gives the external AST source an opportunity to complete + /// an incomplete type. + virtual void CompleteType(TagDecl *Tag) {} + + /// \brief Gives the external AST source an opportunity to complete an + /// incomplete Objective-C class. + /// + /// This routine will only be invoked if the "externally completed" bit is + /// set on the ObjCInterfaceDecl via the function + /// \c ObjCInterfaceDecl::setExternallyCompleted(). + virtual void CompleteType(ObjCInterfaceDecl *Class) { } + + /// \brief Notify ExternalASTSource that we started deserialization of + /// a decl or type so until FinishedDeserializing is called there may be + /// decls that are initializing. Must be paired with FinishedDeserializing. + /// + /// The default implementation of this method is a no-op. + virtual void StartedDeserializing() { } + + /// \brief Notify ExternalASTSource that we finished the deserialization of + /// a decl or type. Must be paired with StartedDeserializing. + /// + /// The default implementation of this method is a no-op. + virtual void FinishedDeserializing() { } + + /// \brief Function that will be invoked when we begin parsing a new + /// translation unit involving this external AST source. + /// + /// The default implementation of this method is a no-op. + virtual void StartTranslationUnit(ASTConsumer *Consumer) { } + + /// \brief Print any statistics that have been gathered regarding + /// the external AST source. + /// + /// The default implementation of this method is a no-op. + virtual void PrintStats(); + + + /// \brief Perform layout on the given record. + /// + /// This routine allows the external AST source to provide an specific + /// layout for a record, overriding the layout that would normally be + /// constructed. It is intended for clients who receive specific layout + /// details rather than source code (such as LLDB). The client is expected + /// to fill in the field offsets, base offsets, virtual base offsets, and + /// complete object size. + /// + /// \param Record The record whose layout is being requested. + /// + /// \param Size The final size of the record, in bits. + /// + /// \param Alignment The final alignment of the record, in bits. + /// + /// \param FieldOffsets The offset of each of the fields within the record, + /// expressed in bits. All of the fields must be provided with offsets. + /// + /// \param BaseOffsets The offset of each of the direct, non-virtual base + /// classes. If any bases are not given offsets, the bases will be laid + /// out according to the ABI. + /// + /// \param VirtualBaseOffsets The offset of each of the virtual base classes + /// (either direct or not). If any bases are not given offsets, the bases will be laid + /// out according to the ABI. + /// + /// \returns true if the record layout was provided, false otherwise. + virtual bool + layoutRecordType(const RecordDecl *Record, + uint64_t &Size, uint64_t &Alignment, + llvm::DenseMap<const FieldDecl *, uint64_t> &FieldOffsets, + llvm::DenseMap<const CXXRecordDecl *, CharUnits> &BaseOffsets, + llvm::DenseMap<const CXXRecordDecl *, CharUnits> &VirtualBaseOffsets) + { + return false; + } + + //===--------------------------------------------------------------------===// + // Queries for performance analysis. + //===--------------------------------------------------------------------===// + + struct MemoryBufferSizes { + size_t malloc_bytes; + size_t mmap_bytes; + + MemoryBufferSizes(size_t malloc_bytes, size_t mmap_bytes) + : malloc_bytes(malloc_bytes), mmap_bytes(mmap_bytes) {} + }; + + /// Return the amount of memory used by memory buffers, breaking down + /// by heap-backed versus mmap'ed memory. + MemoryBufferSizes getMemoryBufferSizes() const { + MemoryBufferSizes sizes(0, 0); + getMemoryBufferSizes(sizes); + return sizes; + } + + virtual void getMemoryBufferSizes(MemoryBufferSizes &sizes) const; + +protected: + static DeclContextLookupResult + SetExternalVisibleDeclsForName(const DeclContext *DC, + DeclarationName Name, + ArrayRef<NamedDecl*> Decls); + + static DeclContextLookupResult + SetNoExternalVisibleDeclsForName(const DeclContext *DC, + DeclarationName Name); +}; + +/// \brief A lazy pointer to an AST node (of base type T) that resides +/// within an external AST source. +/// +/// The AST node is identified within the external AST source by a +/// 63-bit offset, and can be retrieved via an operation on the +/// external AST source itself. +template<typename T, typename OffsT, T* (ExternalASTSource::*Get)(OffsT Offset)> +struct LazyOffsetPtr { + /// \brief Either a pointer to an AST node or the offset within the + /// external AST source where the AST node can be found. + /// + /// If the low bit is clear, a pointer to the AST node. If the low + /// bit is set, the upper 63 bits are the offset. + mutable uint64_t Ptr; + +public: + LazyOffsetPtr() : Ptr(0) { } + + explicit LazyOffsetPtr(T *Ptr) : Ptr(reinterpret_cast<uint64_t>(Ptr)) { } + explicit LazyOffsetPtr(uint64_t Offset) : Ptr((Offset << 1) | 0x01) { + assert((Offset << 1 >> 1) == Offset && "Offsets must require < 63 bits"); + if (Offset == 0) + Ptr = 0; + } + + LazyOffsetPtr &operator=(T *Ptr) { + this->Ptr = reinterpret_cast<uint64_t>(Ptr); + return *this; + } + + LazyOffsetPtr &operator=(uint64_t Offset) { + assert((Offset << 1 >> 1) == Offset && "Offsets must require < 63 bits"); + if (Offset == 0) + Ptr = 0; + else + Ptr = (Offset << 1) | 0x01; + + return *this; + } + + /// \brief Whether this pointer is non-NULL. + /// + /// This operation does not require the AST node to be deserialized. + operator bool() const { return Ptr != 0; } + + /// \brief Whether this pointer is currently stored as an offset. + bool isOffset() const { return Ptr & 0x01; } + + /// \brief Retrieve the pointer to the AST node that this lazy pointer + /// + /// \param Source the external AST source. + /// + /// \returns a pointer to the AST node. + T* get(ExternalASTSource *Source) const { + if (isOffset()) { + assert(Source && + "Cannot deserialize a lazy pointer without an AST source"); + Ptr = reinterpret_cast<uint64_t>((Source->*Get)(Ptr >> 1)); + } + return reinterpret_cast<T*>(Ptr); + } +}; + +/// \brief Represents a lazily-loaded vector of data. +/// +/// The lazily-loaded vector of data contains data that is partially loaded +/// from an external source and partially added by local translation. The +/// items loaded from the external source are loaded lazily, when needed for +/// iteration over the complete vector. +template<typename T, typename Source, + void (Source::*Loader)(SmallVectorImpl<T>&), + unsigned LoadedStorage = 2, unsigned LocalStorage = 4> +class LazyVector { + SmallVector<T, LoadedStorage> Loaded; + SmallVector<T, LocalStorage> Local; + +public: + // Iteration over the elements in the vector. + class iterator { + LazyVector *Self; + + /// \brief Position within the vector.. + /// + /// In a complete iteration, the Position field walks the range [-M, N), + /// where negative values are used to indicate elements + /// loaded from the external source while non-negative values are used to + /// indicate elements added via \c push_back(). + /// However, to provide iteration in source order (for, e.g., chained + /// precompiled headers), dereferencing the iterator flips the negative + /// values (corresponding to loaded entities), so that position -M + /// corresponds to element 0 in the loaded entities vector, position -M+1 + /// corresponds to element 1 in the loaded entities vector, etc. This + /// gives us a reasonably efficient, source-order walk. + int Position; + + friend class LazyVector; + + public: + typedef T value_type; + typedef value_type& reference; + typedef value_type* pointer; + typedef std::random_access_iterator_tag iterator_category; + typedef int difference_type; + + iterator() : Self(0), Position(0) { } + + iterator(LazyVector *Self, int Position) + : Self(Self), Position(Position) { } + + reference operator*() const { + if (Position < 0) + return Self->Loaded.end()[Position]; + return Self->Local[Position]; + } + + pointer operator->() const { + if (Position < 0) + return &Self->Loaded.end()[Position]; + + return &Self->Local[Position]; + } + + reference operator[](difference_type D) { + return *(*this + D); + } + + iterator &operator++() { + ++Position; + return *this; + } + + iterator operator++(int) { + iterator Prev(*this); + ++Position; + return Prev; + } + + iterator &operator--() { + --Position; + return *this; + } + + iterator operator--(int) { + iterator Prev(*this); + --Position; + return Prev; + } + + friend bool operator==(const iterator &X, const iterator &Y) { + return X.Position == Y.Position; + } + + friend bool operator!=(const iterator &X, const iterator &Y) { + return X.Position != Y.Position; + } + + friend bool operator<(const iterator &X, const iterator &Y) { + return X.Position < Y.Position; + } + + friend bool operator>(const iterator &X, const iterator &Y) { + return X.Position > Y.Position; + } + + friend bool operator<=(const iterator &X, const iterator &Y) { + return X.Position < Y.Position; + } + + friend bool operator>=(const iterator &X, const iterator &Y) { + return X.Position > Y.Position; + } + + friend iterator& operator+=(iterator &X, difference_type D) { + X.Position += D; + return X; + } + + friend iterator& operator-=(iterator &X, difference_type D) { + X.Position -= D; + return X; + } + + friend iterator operator+(iterator X, difference_type D) { + X.Position += D; + return X; + } + + friend iterator operator+(difference_type D, iterator X) { + X.Position += D; + return X; + } + + friend difference_type operator-(const iterator &X, const iterator &Y) { + return X.Position - Y.Position; + } + + friend iterator operator-(iterator X, difference_type D) { + X.Position -= D; + return X; + } + }; + friend class iterator; + + iterator begin(Source *source, bool LocalOnly = false) { + if (LocalOnly) + return iterator(this, 0); + + if (source) + (source->*Loader)(Loaded); + return iterator(this, -(int)Loaded.size()); + } + + iterator end() { + return iterator(this, Local.size()); + } + + void push_back(const T& LocalValue) { + Local.push_back(LocalValue); + } + + void erase(iterator From, iterator To) { + if (From.Position < 0 && To.Position < 0) { + Loaded.erase(Loaded.end() + From.Position, Loaded.end() + To.Position); + return; + } + + if (From.Position < 0) { + Loaded.erase(Loaded.end() + From.Position, Loaded.end()); + From = begin(0, true); + } + + Local.erase(Local.begin() + From.Position, Local.begin() + To.Position); + } +}; + +/// \brief A lazy pointer to a statement. +typedef LazyOffsetPtr<Stmt, uint64_t, &ExternalASTSource::GetExternalDeclStmt> + LazyDeclStmtPtr; + +/// \brief A lazy pointer to a declaration. +typedef LazyOffsetPtr<Decl, uint32_t, &ExternalASTSource::GetExternalDecl> + LazyDeclPtr; + +/// \brief A lazy pointer to a set of CXXBaseSpecifiers. +typedef LazyOffsetPtr<CXXBaseSpecifier, uint64_t, + &ExternalASTSource::GetExternalCXXBaseSpecifiers> + LazyCXXBaseSpecifiersPtr; + +} // end namespace clang + +#endif // LLVM_CLANG_AST_EXTERNAL_AST_SOURCE_H diff --git a/clang/include/clang/AST/GlobalDecl.h b/clang/include/clang/AST/GlobalDecl.h new file mode 100644 index 0000000..c43e44c --- /dev/null +++ b/clang/include/clang/AST/GlobalDecl.h @@ -0,0 +1,124 @@ +//===--- GlobalDecl.h - Global declaration holder ---------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// A GlobalDecl can hold either a regular variable/function or a C++ ctor/dtor +// together with its type. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_GLOBALDECL_H +#define LLVM_CLANG_AST_GLOBALDECL_H + +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/ABI.h" + +namespace clang { + +/// GlobalDecl - represents a global declaration. This can either be a +/// CXXConstructorDecl and the constructor type (Base, Complete). +/// a CXXDestructorDecl and the destructor type (Base, Complete) or +/// a VarDecl, a FunctionDecl or a BlockDecl. +class GlobalDecl { + llvm::PointerIntPair<const Decl*, 2> Value; + + void Init(const Decl *D) { + assert(!isa<CXXConstructorDecl>(D) && "Use other ctor with ctor decls!"); + assert(!isa<CXXDestructorDecl>(D) && "Use other ctor with dtor decls!"); + + Value.setPointer(D); + } + +public: + GlobalDecl() {} + + GlobalDecl(const VarDecl *D) { Init(D);} + GlobalDecl(const FunctionDecl *D) { Init(D); } + GlobalDecl(const BlockDecl *D) { Init(D); } + GlobalDecl(const ObjCMethodDecl *D) { Init(D); } + + GlobalDecl(const CXXConstructorDecl *D, CXXCtorType Type) + : Value(D, Type) {} + GlobalDecl(const CXXDestructorDecl *D, CXXDtorType Type) + : Value(D, Type) {} + + GlobalDecl getCanonicalDecl() const { + GlobalDecl CanonGD; + CanonGD.Value.setPointer(Value.getPointer()->getCanonicalDecl()); + CanonGD.Value.setInt(Value.getInt()); + + return CanonGD; + } + + const Decl *getDecl() const { return Value.getPointer(); } + + CXXCtorType getCtorType() const { + assert(isa<CXXConstructorDecl>(getDecl()) && "Decl is not a ctor!"); + return static_cast<CXXCtorType>(Value.getInt()); + } + + CXXDtorType getDtorType() const { + assert(isa<CXXDestructorDecl>(getDecl()) && "Decl is not a dtor!"); + return static_cast<CXXDtorType>(Value.getInt()); + } + + friend bool operator==(const GlobalDecl &LHS, const GlobalDecl &RHS) { + return LHS.Value == RHS.Value; + } + + void *getAsOpaquePtr() const { return Value.getOpaqueValue(); } + + static GlobalDecl getFromOpaquePtr(void *P) { + GlobalDecl GD; + GD.Value.setFromOpaqueValue(P); + return GD; + } + + GlobalDecl getWithDecl(const Decl *D) { + GlobalDecl Result(*this); + Result.Value.setPointer(D); + return Result; + } +}; + +} // end namespace clang + +namespace llvm { + template<class> struct DenseMapInfo; + + template<> struct DenseMapInfo<clang::GlobalDecl> { + static inline clang::GlobalDecl getEmptyKey() { + return clang::GlobalDecl(); + } + + static inline clang::GlobalDecl getTombstoneKey() { + return clang::GlobalDecl:: + getFromOpaquePtr(reinterpret_cast<void*>(-1)); + } + + static unsigned getHashValue(clang::GlobalDecl GD) { + return DenseMapInfo<void*>::getHashValue(GD.getAsOpaquePtr()); + } + + static bool isEqual(clang::GlobalDecl LHS, + clang::GlobalDecl RHS) { + return LHS == RHS; + } + + }; + + // GlobalDecl isn't *technically* a POD type. However, its copy constructor, + // copy assignment operator, and destructor are all trivial. + template <> + struct isPodLike<clang::GlobalDecl> { + static const bool value = true; + }; +} // end namespace llvm + +#endif diff --git a/clang/include/clang/AST/LambdaMangleContext.h b/clang/include/clang/AST/LambdaMangleContext.h new file mode 100644 index 0000000..3e2fbad --- /dev/null +++ b/clang/include/clang/AST/LambdaMangleContext.h @@ -0,0 +1,36 @@ +//===--- LambdaMangleContext.h - Context for mangling lambdas ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the LambdaMangleContext interface, which keeps track of +// the Itanium C++ ABI mangling numbers for lambda expressions. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_LAMBDAMANGLECONTEXT_H +#define LLVM_CLANG_LAMBDAMANGLECONTEXT_H + +#include "llvm/ADT/DenseMap.h" + +namespace clang { + +class CXXMethodDecl; +class FunctionProtoType; + +/// \brief Keeps track of the mangled names of lambda expressions within a +/// particular context. +class LambdaMangleContext { + llvm::DenseMap<const FunctionProtoType *, unsigned> ManglingNumbers; + +public: + /// \brief Retrieve the mangling number of a new lambda expression with the + /// given call operator within this lambda context. + unsigned getManglingNumber(CXXMethodDecl *CallOperator); +}; + +} // end namespace clang +#endif diff --git a/clang/include/clang/AST/Makefile b/clang/include/clang/AST/Makefile new file mode 100644 index 0000000..2854b7f --- /dev/null +++ b/clang/include/clang/AST/Makefile @@ -0,0 +1,29 @@ +CLANG_LEVEL := ../../.. +TD_SRC_DIR = $(PROJ_SRC_DIR)/../Basic +BUILT_SOURCES = Attrs.inc AttrImpl.inc StmtNodes.inc DeclNodes.inc + +TABLEGEN_INC_FILES_COMMON = 1 + +include $(CLANG_LEVEL)/Makefile + +$(ObjDir)/Attrs.inc.tmp : $(TD_SRC_DIR)/Attr.td $(CLANG_TBLGEN) \ + $(ObjDir)/.dir + $(Echo) "Building Clang attribute classes with tblgen" + $(Verb) $(ClangTableGen) -gen-clang-attr-classes -o $(call SYSPATH, $@) \ + -I $(PROJ_SRC_DIR)/../../ $< + +$(ObjDir)/AttrImpl.inc.tmp : $(TD_SRC_DIR)/Attr.td $(CLANG_TBLGEN) \ + $(ObjDir)/.dir + $(Echo) "Building Clang attribute implementations with tblgen" + $(Verb) $(ClangTableGen) -gen-clang-attr-impl -o $(call SYSPATH, $@) \ + -I $(PROJ_SRC_DIR)/../../ $< + +$(ObjDir)/StmtNodes.inc.tmp : $(TD_SRC_DIR)/StmtNodes.td $(CLANG_TBLGEN) \ + $(ObjDir)/.dir + $(Echo) "Building Clang statement node tables with tblgen" + $(Verb) $(ClangTableGen) -gen-clang-stmt-nodes -o $(call SYSPATH, $@) $< + +$(ObjDir)/DeclNodes.inc.tmp : $(TD_SRC_DIR)/DeclNodes.td $(CLANG_TBLGEN) \ + $(ObjDir)/.dir + $(Echo) "Building Clang declaration node tables with tblgen" + $(Verb) $(ClangTableGen) -gen-clang-decl-nodes -o $(call SYSPATH, $@) $< diff --git a/clang/include/clang/AST/Mangle.h b/clang/include/clang/AST/Mangle.h new file mode 100644 index 0000000..ca22ed6 --- /dev/null +++ b/clang/include/clang/AST/Mangle.h @@ -0,0 +1,152 @@ +//===--- Mangle.h - Mangle C++ Names ----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Defines the C++ name mangling interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_MANGLE_H +#define LLVM_CLANG_AST_MANGLE_H + +#include "clang/AST/Type.h" +#include "clang/Basic/ABI.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/raw_ostream.h" + +namespace clang { + class ASTContext; + class BlockDecl; + class CXXConstructorDecl; + class CXXDestructorDecl; + class CXXMethodDecl; + class FunctionDecl; + class NamedDecl; + class ObjCMethodDecl; + class VarDecl; + struct ThisAdjustment; + struct ThunkInfo; + +/// MangleBuffer - a convenient class for storing a name which is +/// either the result of a mangling or is a constant string with +/// external memory ownership. +class MangleBuffer { +public: + void setString(StringRef Ref) { + String = Ref; + } + + SmallVectorImpl<char> &getBuffer() { + return Buffer; + } + + StringRef getString() const { + if (!String.empty()) return String; + return Buffer.str(); + } + + operator StringRef() const { + return getString(); + } + +private: + StringRef String; + SmallString<256> Buffer; +}; + +/// MangleContext - Context for tracking state which persists across multiple +/// calls to the C++ name mangler. +class MangleContext { + virtual void anchor(); + + ASTContext &Context; + DiagnosticsEngine &Diags; + + llvm::DenseMap<const BlockDecl*, unsigned> GlobalBlockIds; + llvm::DenseMap<const BlockDecl*, unsigned> LocalBlockIds; + +public: + explicit MangleContext(ASTContext &Context, + DiagnosticsEngine &Diags) + : Context(Context), Diags(Diags) { } + + virtual ~MangleContext() { } + + ASTContext &getASTContext() const { return Context; } + + DiagnosticsEngine &getDiags() const { return Diags; } + + virtual void startNewFunction() { LocalBlockIds.clear(); } + + unsigned getBlockId(const BlockDecl *BD, bool Local) { + llvm::DenseMap<const BlockDecl *, unsigned> &BlockIds + = Local? LocalBlockIds : GlobalBlockIds; + std::pair<llvm::DenseMap<const BlockDecl *, unsigned>::iterator, bool> + Result = BlockIds.insert(std::make_pair(BD, BlockIds.size())); + return Result.first->second; + } + + /// @name Mangler Entry Points + /// @{ + + virtual bool shouldMangleDeclName(const NamedDecl *D) = 0; + virtual void mangleName(const NamedDecl *D, raw_ostream &)=0; + virtual void mangleThunk(const CXXMethodDecl *MD, + const ThunkInfo &Thunk, + raw_ostream &) = 0; + virtual void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type, + const ThisAdjustment &ThisAdjustment, + raw_ostream &) = 0; + virtual void mangleReferenceTemporary(const VarDecl *D, + raw_ostream &) = 0; + virtual void mangleCXXVTable(const CXXRecordDecl *RD, + raw_ostream &) = 0; + virtual void mangleCXXVTT(const CXXRecordDecl *RD, + raw_ostream &) = 0; + virtual void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset, + const CXXRecordDecl *Type, + raw_ostream &) = 0; + virtual void mangleCXXRTTI(QualType T, raw_ostream &) = 0; + virtual void mangleCXXRTTIName(QualType T, raw_ostream &) = 0; + virtual void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type, + raw_ostream &) = 0; + virtual void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type, + raw_ostream &) = 0; + + void mangleGlobalBlock(const BlockDecl *BD, + raw_ostream &Out); + void mangleCtorBlock(const CXXConstructorDecl *CD, CXXCtorType CT, + const BlockDecl *BD, raw_ostream &Out); + void mangleDtorBlock(const CXXDestructorDecl *CD, CXXDtorType DT, + const BlockDecl *BD, raw_ostream &Out); + void mangleBlock(const DeclContext *DC, const BlockDecl *BD, + raw_ostream &Out); + // Do the right thing. + void mangleBlock(const BlockDecl *BD, raw_ostream &Out); + + void mangleObjCMethodName(const ObjCMethodDecl *MD, + raw_ostream &); + + // This is pretty lame. + virtual void mangleItaniumGuardVariable(const VarDecl *D, + raw_ostream &) { + llvm_unreachable("Target does not support mangling guard variables"); + } + /// @} +}; + +MangleContext *createItaniumMangleContext(ASTContext &Context, + DiagnosticsEngine &Diags); +MangleContext *createMicrosoftMangleContext(ASTContext &Context, + DiagnosticsEngine &Diags); + +} + +#endif diff --git a/clang/include/clang/AST/NSAPI.h b/clang/include/clang/AST/NSAPI.h new file mode 100644 index 0000000..40e9759 --- /dev/null +++ b/clang/include/clang/AST/NSAPI.h @@ -0,0 +1,152 @@ +//===--- NSAPI.h - NSFoundation APIs ----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_NSAPI_H +#define LLVM_CLANG_AST_NSAPI_H + +#include "clang/Basic/IdentifierTable.h" +#include "llvm/ADT/Optional.h" + +namespace clang { + class ASTContext; + class QualType; + +// \brief Provides info and caches identifiers/selectors for NSFoundation API. +class NSAPI { +public: + explicit NSAPI(ASTContext &Ctx); + + ASTContext &getASTContext() const { return Ctx; } + + enum NSClassIdKindKind { + ClassId_NSObject, + ClassId_NSString, + ClassId_NSArray, + ClassId_NSMutableArray, + ClassId_NSDictionary, + ClassId_NSMutableDictionary, + ClassId_NSNumber + }; + static const unsigned NumClassIds = 7; + + enum NSStringMethodKind { + NSStr_stringWithString, + NSStr_initWithString + }; + static const unsigned NumNSStringMethods = 2; + + IdentifierInfo *getNSClassId(NSClassIdKindKind K) const; + + /// \brief The Objective-C NSString selectors. + Selector getNSStringSelector(NSStringMethodKind MK) const; + + /// \brief Enumerates the NSArray methods used to generate literals. + enum NSArrayMethodKind { + NSArr_array, + NSArr_arrayWithArray, + NSArr_arrayWithObject, + NSArr_arrayWithObjects, + NSArr_arrayWithObjectsCount, + NSArr_initWithArray, + NSArr_initWithObjects, + NSArr_objectAtIndex, + NSMutableArr_replaceObjectAtIndex + }; + static const unsigned NumNSArrayMethods = 9; + + /// \brief The Objective-C NSArray selectors. + Selector getNSArraySelector(NSArrayMethodKind MK) const; + + /// \brief Return NSArrayMethodKind if \arg Sel is such a selector. + llvm::Optional<NSArrayMethodKind> getNSArrayMethodKind(Selector Sel); + + /// \brief Enumerates the NSDictionary methods used to generate literals. + enum NSDictionaryMethodKind { + NSDict_dictionary, + NSDict_dictionaryWithDictionary, + NSDict_dictionaryWithObjectForKey, + NSDict_dictionaryWithObjectsForKeys, + NSDict_dictionaryWithObjectsForKeysCount, + NSDict_dictionaryWithObjectsAndKeys, + NSDict_initWithDictionary, + NSDict_initWithObjectsAndKeys, + NSDict_objectForKey, + NSMutableDict_setObjectForKey + }; + static const unsigned NumNSDictionaryMethods = 10; + + /// \brief The Objective-C NSDictionary selectors. + Selector getNSDictionarySelector(NSDictionaryMethodKind MK) const; + + /// \brief Return NSDictionaryMethodKind if \arg Sel is such a selector. + llvm::Optional<NSDictionaryMethodKind> + getNSDictionaryMethodKind(Selector Sel); + + /// \brief Enumerates the NSNumber methods used to generate literals. + enum NSNumberLiteralMethodKind { + NSNumberWithChar, + NSNumberWithUnsignedChar, + NSNumberWithShort, + NSNumberWithUnsignedShort, + NSNumberWithInt, + NSNumberWithUnsignedInt, + NSNumberWithLong, + NSNumberWithUnsignedLong, + NSNumberWithLongLong, + NSNumberWithUnsignedLongLong, + NSNumberWithFloat, + NSNumberWithDouble, + NSNumberWithBool, + NSNumberWithInteger, + NSNumberWithUnsignedInteger + }; + static const unsigned NumNSNumberLiteralMethods = 15; + + /// \brief The Objective-C NSNumber selectors used to create NSNumber literals. + /// \param Instance if true it will return the selector for the init* method + /// otherwise it will return the selector for the number* method. + Selector getNSNumberLiteralSelector(NSNumberLiteralMethodKind MK, + bool Instance) const; + + bool isNSNumberLiteralSelector(NSNumberLiteralMethodKind MK, + Selector Sel) const { + return Sel == getNSNumberLiteralSelector(MK, false) || + Sel == getNSNumberLiteralSelector(MK, true); + } + + /// \brief Return NSNumberLiteralMethodKind if \arg Sel is such a selector. + llvm::Optional<NSNumberLiteralMethodKind> + getNSNumberLiteralMethodKind(Selector Sel) const; + + /// \brief Determine the appropriate NSNumber factory method kind for a + /// literal of the given type. + static llvm::Optional<NSNumberLiteralMethodKind> + getNSNumberFactoryMethodKind(QualType T); + +private: + ASTContext &Ctx; + + mutable IdentifierInfo *ClassIds[NumClassIds]; + + mutable Selector NSStringSelectors[NumNSStringMethods]; + + /// \brief The selectors for Objective-C NSArray methods. + mutable Selector NSArraySelectors[NumNSArrayMethods]; + + /// \brief The selectors for Objective-C NSDictionary methods. + mutable Selector NSDictionarySelectors[NumNSDictionaryMethods]; + + /// \brief The Objective-C NSNumber selectors used to create NSNumber literals. + mutable Selector NSNumberClassSelectors[NumNSNumberLiteralMethods]; + mutable Selector NSNumberInstanceSelectors[NumNSNumberLiteralMethods]; +}; + +} // end namespace clang + +#endif // LLVM_CLANG_AST_NSAPI_H diff --git a/clang/include/clang/AST/NestedNameSpecifier.h b/clang/include/clang/AST/NestedNameSpecifier.h new file mode 100644 index 0000000..b5bd824 --- /dev/null +++ b/clang/include/clang/AST/NestedNameSpecifier.h @@ -0,0 +1,481 @@ +//===--- NestedNameSpecifier.h - C++ nested name specifiers -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the NestedNameSpecifier class, which represents +// a C++ nested-name-specifier. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_AST_NESTEDNAMESPECIFIER_H +#define LLVM_CLANG_AST_NESTEDNAMESPECIFIER_H + +#include "clang/Basic/Diagnostic.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/Support/Compiler.h" + +namespace clang { + +class ASTContext; +class NamespaceAliasDecl; +class NamespaceDecl; +class IdentifierInfo; +struct PrintingPolicy; +class Type; +class TypeLoc; +class LangOptions; + +/// \brief Represents a C++ nested name specifier, such as +/// "::std::vector<int>::". +/// +/// C++ nested name specifiers are the prefixes to qualified +/// namespaces. For example, "foo::" in "foo::x" is a nested name +/// specifier. Nested name specifiers are made up of a sequence of +/// specifiers, each of which can be a namespace, type, identifier +/// (for dependent names), decltype specifier, or the global specifier ('::'). +/// The last two specifiers can only appear at the start of a +/// nested-namespace-specifier. +class NestedNameSpecifier : public llvm::FoldingSetNode { + + /// \brief Enumeration describing + enum StoredSpecifierKind { + StoredIdentifier = 0, + StoredNamespaceOrAlias = 1, + StoredTypeSpec = 2, + StoredTypeSpecWithTemplate = 3 + }; + + /// \brief The nested name specifier that precedes this nested name + /// specifier. + /// + /// The pointer is the nested-name-specifier that precedes this + /// one. The integer stores one of the first four values of type + /// SpecifierKind. + llvm::PointerIntPair<NestedNameSpecifier *, 2, StoredSpecifierKind> Prefix; + + /// \brief The last component in the nested name specifier, which + /// can be an identifier, a declaration, or a type. + /// + /// When the pointer is NULL, this specifier represents the global + /// specifier '::'. Otherwise, the pointer is one of + /// IdentifierInfo*, Namespace*, or Type*, depending on the kind of + /// specifier as encoded within the prefix. + void* Specifier; + +public: + /// \brief The kind of specifier that completes this nested name + /// specifier. + enum SpecifierKind { + /// \brief An identifier, stored as an IdentifierInfo*. + Identifier, + /// \brief A namespace, stored as a NamespaceDecl*. + Namespace, + /// \brief A namespace alias, stored as a NamespaceAliasDecl*. + NamespaceAlias, + /// \brief A type, stored as a Type*. + TypeSpec, + /// \brief A type that was preceded by the 'template' keyword, + /// stored as a Type*. + TypeSpecWithTemplate, + /// \brief The global specifier '::'. There is no stored value. + Global + }; + +private: + /// \brief Builds the global specifier. + NestedNameSpecifier() : Prefix(0, StoredIdentifier), Specifier(0) { } + + /// \brief Copy constructor used internally to clone nested name + /// specifiers. + NestedNameSpecifier(const NestedNameSpecifier &Other) + : llvm::FoldingSetNode(Other), Prefix(Other.Prefix), + Specifier(Other.Specifier) { + } + + NestedNameSpecifier &operator=(const NestedNameSpecifier &); // do not + // implement + + /// \brief Either find or insert the given nested name specifier + /// mockup in the given context. + static NestedNameSpecifier *FindOrInsert(const ASTContext &Context, + const NestedNameSpecifier &Mockup); + +public: + /// \brief Builds a specifier combining a prefix and an identifier. + /// + /// The prefix must be dependent, since nested name specifiers + /// referencing an identifier are only permitted when the identifier + /// cannot be resolved. + static NestedNameSpecifier *Create(const ASTContext &Context, + NestedNameSpecifier *Prefix, + IdentifierInfo *II); + + /// \brief Builds a nested name specifier that names a namespace. + static NestedNameSpecifier *Create(const ASTContext &Context, + NestedNameSpecifier *Prefix, + NamespaceDecl *NS); + + /// \brief Builds a nested name specifier that names a namespace alias. + static NestedNameSpecifier *Create(const ASTContext &Context, + NestedNameSpecifier *Prefix, + NamespaceAliasDecl *Alias); + + /// \brief Builds a nested name specifier that names a type. + static NestedNameSpecifier *Create(const ASTContext &Context, + NestedNameSpecifier *Prefix, + bool Template, const Type *T); + + /// \brief Builds a specifier that consists of just an identifier. + /// + /// The nested-name-specifier is assumed to be dependent, but has no + /// prefix because the prefix is implied by something outside of the + /// nested name specifier, e.g., in "x->Base::f", the "x" has a dependent + /// type. + static NestedNameSpecifier *Create(const ASTContext &Context, + IdentifierInfo *II); + + /// \brief Returns the nested name specifier representing the global + /// scope. + static NestedNameSpecifier *GlobalSpecifier(const ASTContext &Context); + + /// \brief Return the prefix of this nested name specifier. + /// + /// The prefix contains all of the parts of the nested name + /// specifier that preced this current specifier. For example, for a + /// nested name specifier that represents "foo::bar::", the current + /// specifier will contain "bar::" and the prefix will contain + /// "foo::". + NestedNameSpecifier *getPrefix() const { return Prefix.getPointer(); } + + /// \brief Determine what kind of nested name specifier is stored. + SpecifierKind getKind() const; + + /// \brief Retrieve the identifier stored in this nested name + /// specifier. + IdentifierInfo *getAsIdentifier() const { + if (Prefix.getInt() == StoredIdentifier) + return (IdentifierInfo *)Specifier; + + return 0; + } + + /// \brief Retrieve the namespace stored in this nested name + /// specifier. + NamespaceDecl *getAsNamespace() const; + + /// \brief Retrieve the namespace alias stored in this nested name + /// specifier. + NamespaceAliasDecl *getAsNamespaceAlias() const; + + /// \brief Retrieve the type stored in this nested name specifier. + const Type *getAsType() const { + if (Prefix.getInt() == StoredTypeSpec || + Prefix.getInt() == StoredTypeSpecWithTemplate) + return (const Type *)Specifier; + + return 0; + } + + /// \brief Whether this nested name specifier refers to a dependent + /// type or not. + bool isDependent() const; + + /// \brief Whether this nested name specifier involves a template + /// parameter. + bool isInstantiationDependent() const; + + /// \brief Whether this nested-name-specifier contains an unexpanded + /// parameter pack (for C++0x variadic templates). + bool containsUnexpandedParameterPack() const; + + /// \brief Print this nested name specifier to the given output + /// stream. + void print(raw_ostream &OS, const PrintingPolicy &Policy) const; + + void Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddPointer(Prefix.getOpaqueValue()); + ID.AddPointer(Specifier); + } + + /// \brief Dump the nested name specifier to standard output to aid + /// in debugging. + void dump(const LangOptions &LO); +}; + +/// \brief A C++ nested-name-specifier augmented with source location +/// information. +class NestedNameSpecifierLoc { + NestedNameSpecifier *Qualifier; + void *Data; + + /// \brief Determines the data length for the last component in the + /// given nested-name-specifier. + static unsigned getLocalDataLength(NestedNameSpecifier *Qualifier); + + /// \brief Determines the data length for the entire + /// nested-name-specifier. + static unsigned getDataLength(NestedNameSpecifier *Qualifier); + +public: + /// \brief Construct an empty nested-name-specifier. + NestedNameSpecifierLoc() : Qualifier(0), Data(0) { } + + /// \brief Construct a nested-name-specifier with source location information + /// from + NestedNameSpecifierLoc(NestedNameSpecifier *Qualifier, void *Data) + : Qualifier(Qualifier), Data(Data) { } + + /// \brief Evalutes true when this nested-name-specifier location is + /// non-empty. + operator bool() const { return Qualifier; } + + /// \brief Retrieve the nested-name-specifier to which this instance + /// refers. + NestedNameSpecifier *getNestedNameSpecifier() const { + return Qualifier; + } + + /// \brief Retrieve the opaque pointer that refers to source-location data. + void *getOpaqueData() const { return Data; } + + /// \brief Retrieve the source range covering the entirety of this + /// nested-name-specifier. + /// + /// For example, if this instance refers to a nested-name-specifier + /// \c ::std::vector<int>::, the returned source range would cover + /// from the initial '::' to the last '::'. + SourceRange getSourceRange() const LLVM_READONLY; + + /// \brief Retrieve the source range covering just the last part of + /// this nested-name-specifier, not including the prefix. + /// + /// For example, if this instance refers to a nested-name-specifier + /// \c ::std::vector<int>::, the returned source range would cover + /// from "vector" to the last '::'. + SourceRange getLocalSourceRange() const; + + /// \brief Retrieve the location of the beginning of this + /// nested-name-specifier. + SourceLocation getBeginLoc() const { + return getSourceRange().getBegin(); + } + + /// \brief Retrieve the location of the end of this + /// nested-name-specifier. + SourceLocation getEndLoc() const { + return getSourceRange().getEnd(); + } + + /// \brief Retrieve the location of the beginning of this + /// component of the nested-name-specifier. + SourceLocation getLocalBeginLoc() const { + return getLocalSourceRange().getBegin(); + } + + /// \brief Retrieve the location of the end of this component of the + /// nested-name-specifier. + SourceLocation getLocalEndLoc() const { + return getLocalSourceRange().getEnd(); + } + + /// \brief Return the prefix of this nested-name-specifier. + /// + /// For example, if this instance refers to a nested-name-specifier + /// \c ::std::vector<int>::, the prefix is \c ::std::. Note that the + /// returned prefix may be empty, if this is the first component of + /// the nested-name-specifier. + NestedNameSpecifierLoc getPrefix() const { + if (!Qualifier) + return *this; + + return NestedNameSpecifierLoc(Qualifier->getPrefix(), Data); + } + + /// \brief For a nested-name-specifier that refers to a type, + /// retrieve the type with source-location information. + TypeLoc getTypeLoc() const; + + /// \brief Determines the data length for the entire + /// nested-name-specifier. + unsigned getDataLength() const { return getDataLength(Qualifier); } + + friend bool operator==(NestedNameSpecifierLoc X, + NestedNameSpecifierLoc Y) { + return X.Qualifier == Y.Qualifier && X.Data == Y.Data; + } + + friend bool operator!=(NestedNameSpecifierLoc X, + NestedNameSpecifierLoc Y) { + return !(X == Y); + } +}; + +/// \brief Class that aids in the construction of nested-name-specifiers along +/// with source-location information for all of the components of the +/// nested-name-specifier. +class NestedNameSpecifierLocBuilder { + /// \brief The current representation of the nested-name-specifier we're + /// building. + NestedNameSpecifier *Representation; + + /// \brief Buffer used to store source-location information for the + /// nested-name-specifier. + /// + /// Note that we explicitly manage the buffer (rather than using a + /// SmallVector) because \c Declarator expects it to be possible to memcpy() + /// a \c CXXScopeSpec, and CXXScopeSpec uses a NestedNameSpecifierLocBuilder. + char *Buffer; + + /// \brief The size of the buffer used to store source-location information + /// for the nested-name-specifier. + unsigned BufferSize; + + /// \brief The capacity of the buffer used to store source-location + /// information for the nested-name-specifier. + unsigned BufferCapacity; + +public: + NestedNameSpecifierLocBuilder() + : Representation(0), Buffer(0), BufferSize(0), BufferCapacity(0) { } + + NestedNameSpecifierLocBuilder(const NestedNameSpecifierLocBuilder &Other); + + NestedNameSpecifierLocBuilder & + operator=(const NestedNameSpecifierLocBuilder &Other); + + ~NestedNameSpecifierLocBuilder() { + if (BufferCapacity) + free(Buffer); + } + + /// \brief Retrieve the representation of the nested-name-specifier. + NestedNameSpecifier *getRepresentation() const { return Representation; } + + /// \brief Extend the current nested-name-specifier by another + /// nested-name-specifier component of the form 'type::'. + /// + /// \param Context The AST context in which this nested-name-specifier + /// resides. + /// + /// \param TemplateKWLoc The location of the 'template' keyword, if present. + /// + /// \param TL The TypeLoc that describes the type preceding the '::'. + /// + /// \param ColonColonLoc The location of the trailing '::'. + void Extend(ASTContext &Context, SourceLocation TemplateKWLoc, TypeLoc TL, + SourceLocation ColonColonLoc); + + /// \brief Extend the current nested-name-specifier by another + /// nested-name-specifier component of the form 'identifier::'. + /// + /// \param Context The AST context in which this nested-name-specifier + /// resides. + /// + /// \param Identifier The identifier. + /// + /// \param IdentifierLoc The location of the identifier. + /// + /// \param ColonColonLoc The location of the trailing '::'. + void Extend(ASTContext &Context, IdentifierInfo *Identifier, + SourceLocation IdentifierLoc, SourceLocation ColonColonLoc); + + /// \brief Extend the current nested-name-specifier by another + /// nested-name-specifier component of the form 'namespace::'. + /// + /// \param Context The AST context in which this nested-name-specifier + /// resides. + /// + /// \param Namespace The namespace. + /// + /// \param NamespaceLoc The location of the namespace name. + /// + /// \param ColonColonLoc The location of the trailing '::'. + void Extend(ASTContext &Context, NamespaceDecl *Namespace, + SourceLocation NamespaceLoc, SourceLocation ColonColonLoc); + + /// \brief Extend the current nested-name-specifier by another + /// nested-name-specifier component of the form 'namespace-alias::'. + /// + /// \param Context The AST context in which this nested-name-specifier + /// resides. + /// + /// \param Alias The namespace alias. + /// + /// \param AliasLoc The location of the namespace alias + /// name. + /// + /// \param ColonColonLoc The location of the trailing '::'. + void Extend(ASTContext &Context, NamespaceAliasDecl *Alias, + SourceLocation AliasLoc, SourceLocation ColonColonLoc); + + /// \brief Turn this (empty) nested-name-specifier into the global + /// nested-name-specifier '::'. + void MakeGlobal(ASTContext &Context, SourceLocation ColonColonLoc); + + /// \brief Make a new nested-name-specifier from incomplete source-location + /// information. + /// + /// This routine should be used very, very rarely, in cases where we + /// need to synthesize a nested-name-specifier. Most code should instead use + /// \c Adopt() with a proper \c NestedNameSpecifierLoc. + void MakeTrivial(ASTContext &Context, NestedNameSpecifier *Qualifier, + SourceRange R); + + /// \brief Adopt an existing nested-name-specifier (with source-range + /// information). + void Adopt(NestedNameSpecifierLoc Other); + + /// \brief Retrieve the source range covered by this nested-name-specifier. + SourceRange getSourceRange() const LLVM_READONLY { + return NestedNameSpecifierLoc(Representation, Buffer).getSourceRange(); + } + + /// \brief Retrieve a nested-name-specifier with location information, + /// copied into the given AST context. + /// + /// \param Context The context into which this nested-name-specifier will be + /// copied. + NestedNameSpecifierLoc getWithLocInContext(ASTContext &Context) const; + + /// \brief Retrieve a nested-name-specifier with location + /// information based on the information in this builder. This loc + /// will contain references to the builder's internal data and may + /// be invalidated by any change to the builder. + NestedNameSpecifierLoc getTemporary() const { + return NestedNameSpecifierLoc(Representation, Buffer); + } + + /// \brief Clear out this builder, and prepare it to build another + /// nested-name-specifier with source-location information. + void Clear() { + Representation = 0; + BufferSize = 0; + } + + /// \brief Retrieve the underlying buffer. + /// + /// \returns A pair containing a pointer to the buffer of source-location + /// data and the size of the source-location data that resides in that + /// buffer. + std::pair<char *, unsigned> getBuffer() const { + return std::make_pair(Buffer, BufferSize); + } +}; + +/// Insertion operator for diagnostics. This allows sending +/// NestedNameSpecifiers into a diagnostic with <<. +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + NestedNameSpecifier *NNS) { + DB.AddTaggedVal(reinterpret_cast<intptr_t>(NNS), + DiagnosticsEngine::ak_nestednamespec); + return DB; +} + +} + +#endif diff --git a/clang/include/clang/AST/OperationKinds.h b/clang/include/clang/AST/OperationKinds.h new file mode 100644 index 0000000..258637d --- /dev/null +++ b/clang/include/clang/AST/OperationKinds.h @@ -0,0 +1,345 @@ +//===- OperationKinds.h - Operation enums -----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file enumerates the different kinds of operations that can be +// performed by various expressions. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_OPERATION_KINDS_H +#define LLVM_CLANG_AST_OPERATION_KINDS_H + +namespace clang { + +/// CastKind - The kind of operation required for a conversion. +enum CastKind { + /// CK_Dependent - A conversion which cannot yet be analyzed because + /// either the expression or target type is dependent. These are + /// created only for explicit casts; dependent ASTs aren't required + /// to even approximately type-check. + /// (T*) malloc(sizeof(T)) + /// reinterpret_cast<intptr_t>(A<T>::alloc()); + CK_Dependent, + + /// CK_BitCast - A conversion which causes a bit pattern of one type + /// to be reinterpreted as a bit pattern of another type. Generally + /// the operands must have equivalent size and unrelated types. + /// + /// The pointer conversion char* -> int* is a bitcast. A conversion + /// from any pointer type to a C pointer type is a bitcast unless + /// it's actually BaseToDerived or DerivedToBase. A conversion to a + /// block pointer or ObjC pointer type is a bitcast only if the + /// operand has the same type kind; otherwise, it's one of the + /// specialized casts below. + /// + /// Vector coercions are bitcasts. + CK_BitCast, + + /// CK_LValueBitCast - A conversion which reinterprets the address of + /// an l-value as an l-value of a different kind. Used for + /// reinterpret_casts of l-value expressions to reference types. + /// bool b; reinterpret_cast<char&>(b) = 'a'; + CK_LValueBitCast, + + /// CK_LValueToRValue - A conversion which causes the extraction of + /// an r-value from the operand gl-value. The result of an r-value + /// conversion is always unqualified. + CK_LValueToRValue, + + /// CK_NoOp - A conversion which does not affect the type other than + /// (possibly) adding qualifiers. + /// int -> int + /// char** -> const char * const * + CK_NoOp, + + /// CK_BaseToDerived - A conversion from a C++ class pointer/reference + /// to a derived class pointer/reference. + /// B *b = static_cast<B*>(a); + CK_BaseToDerived, + + /// CK_DerivedToBase - A conversion from a C++ class pointer + /// to a base class pointer. + /// A *a = new B(); + CK_DerivedToBase, + + /// CK_UncheckedDerivedToBase - A conversion from a C++ class + /// pointer/reference to a base class that can assume that the + /// derived pointer is not null. + /// const A &a = B(); + /// b->method_from_a(); + CK_UncheckedDerivedToBase, + + /// CK_Dynamic - A C++ dynamic_cast. + CK_Dynamic, + + /// CK_ToUnion - The GCC cast-to-union extension. + /// int -> union { int x; float y; } + /// float -> union { int x; float y; } + CK_ToUnion, + + /// CK_ArrayToPointerDecay - Array to pointer decay. + /// int[10] -> int* + /// char[5][6] -> char(*)[6] + CK_ArrayToPointerDecay, + + /// CK_FunctionToPointerDecay - Function to pointer decay. + /// void(int) -> void(*)(int) + CK_FunctionToPointerDecay, + + /// CK_NullToPointer - Null pointer constant to pointer, ObjC + /// pointer, or block pointer. + /// (void*) 0 + /// void (^block)() = 0; + CK_NullToPointer, + + /// CK_NullToMemberPointer - Null pointer constant to member pointer. + /// int A::*mptr = 0; + /// int (A::*fptr)(int) = nullptr; + CK_NullToMemberPointer, + + /// CK_BaseToDerivedMemberPointer - Member pointer in base class to + /// member pointer in derived class. + /// int B::*mptr = &A::member; + CK_BaseToDerivedMemberPointer, + + /// CK_DerivedToBaseMemberPointer - Member pointer in derived class to + /// member pointer in base class. + /// int A::*mptr = static_cast<int A::*>(&B::member); + CK_DerivedToBaseMemberPointer, + + /// CK_MemberPointerToBoolean - Member pointer to boolean. A check + /// against the null member pointer. + CK_MemberPointerToBoolean, + + /// CK_ReinterpretMemberPointer - Reinterpret a member pointer as a + /// different kind of member pointer. C++ forbids this from + /// crossing between function and object types, but otherwise does + /// not restrict it. However, the only operation that is permitted + /// on a "punned" member pointer is casting it back to the original + /// type, which is required to be a lossless operation (although + /// many ABIs do not guarantee this on all possible intermediate types). + CK_ReinterpretMemberPointer, + + /// CK_UserDefinedConversion - Conversion using a user defined type + /// conversion function. + /// struct A { operator int(); }; int i = int(A()); + CK_UserDefinedConversion, + + /// CK_ConstructorConversion - Conversion by constructor. + /// struct A { A(int); }; A a = A(10); + CK_ConstructorConversion, + + /// CK_IntegralToPointer - Integral to pointer. A special kind of + /// reinterpreting conversion. Applies to normal, ObjC, and block + /// pointers. + /// (char*) 0x1001aab0 + /// reinterpret_cast<int*>(0) + CK_IntegralToPointer, + + /// CK_PointerToIntegral - Pointer to integral. A special kind of + /// reinterpreting conversion. Applies to normal, ObjC, and block + /// pointers. + /// (intptr_t) "help!" + CK_PointerToIntegral, + + /// CK_PointerToBoolean - Pointer to boolean conversion. A check + /// against null. Applies to normal, ObjC, and block pointers. + CK_PointerToBoolean, + + /// CK_ToVoid - Cast to void, discarding the computed value. + /// (void) malloc(2048) + CK_ToVoid, + + /// CK_VectorSplat - A conversion from an arithmetic type to a + /// vector of that element type. Fills all elements ("splats") with + /// the source value. + /// __attribute__((ext_vector_type(4))) int v = 5; + CK_VectorSplat, + + /// CK_IntegralCast - A cast between integral types (other than to + /// boolean). Variously a bitcast, a truncation, a sign-extension, + /// or a zero-extension. + /// long l = 5; + /// (unsigned) i + CK_IntegralCast, + + /// CK_IntegralToBoolean - Integral to boolean. A check against zero. + /// (bool) i + CK_IntegralToBoolean, + + /// CK_IntegralToFloating - Integral to floating point. + /// float f = i; + CK_IntegralToFloating, + + /// CK_FloatingToIntegral - Floating point to integral. Rounds + /// towards zero, discarding any fractional component. + /// (int) f + CK_FloatingToIntegral, + + /// CK_FloatingToBoolean - Floating point to boolean. + /// (bool) f + CK_FloatingToBoolean, + + /// CK_FloatingCast - Casting between floating types of different size. + /// (double) f + /// (float) ld + CK_FloatingCast, + + /// CK_CPointerToObjCPointerCast - Casting a C pointer kind to an + /// Objective-C pointer. + CK_CPointerToObjCPointerCast, + + /// CK_BlockPointerToObjCPointerCast - Casting a block pointer to an + /// ObjC pointer. + CK_BlockPointerToObjCPointerCast, + + /// CK_AnyPointerToBlockPointerCast - Casting any non-block pointer + /// to a block pointer. Block-to-block casts are bitcasts. + CK_AnyPointerToBlockPointerCast, + + /// \brief Converting between two Objective-C object types, which + /// can occur when performing reference binding to an Objective-C + /// object. + CK_ObjCObjectLValueCast, + + /// \brief A conversion of a floating point real to a floating point + /// complex of the original type. Injects the value as the real + /// component with a zero imaginary component. + /// float -> _Complex float + CK_FloatingRealToComplex, + + /// \brief Converts a floating point complex to floating point real + /// of the source's element type. Just discards the imaginary + /// component. + /// _Complex long double -> long double + CK_FloatingComplexToReal, + + /// \brief Converts a floating point complex to bool by comparing + /// against 0+0i. + CK_FloatingComplexToBoolean, + + /// \brief Converts between different floating point complex types. + /// _Complex float -> _Complex double + CK_FloatingComplexCast, + + /// \brief Converts from a floating complex to an integral complex. + /// _Complex float -> _Complex int + CK_FloatingComplexToIntegralComplex, + + /// \brief Converts from an integral real to an integral complex + /// whose element type matches the source. Injects the value as + /// the real component with a zero imaginary component. + /// long -> _Complex long + CK_IntegralRealToComplex, + + /// \brief Converts an integral complex to an integral real of the + /// source's element type by discarding the imaginary component. + /// _Complex short -> short + CK_IntegralComplexToReal, + + /// \brief Converts an integral complex to bool by comparing against + /// 0+0i. + CK_IntegralComplexToBoolean, + + /// \brief Converts between different integral complex types. + /// _Complex char -> _Complex long long + /// _Complex unsigned int -> _Complex signed int + CK_IntegralComplexCast, + + /// \brief Converts from an integral complex to a floating complex. + /// _Complex unsigned -> _Complex float + CK_IntegralComplexToFloatingComplex, + + /// \brief [ARC] Produces a retainable object pointer so that it may + /// be consumed, e.g. by being passed to a consuming parameter. + /// Calls objc_retain. + CK_ARCProduceObject, + + /// \brief [ARC] Consumes a retainable object pointer that has just + /// been produced, e.g. as the return value of a retaining call. + /// Enters a cleanup to call objc_release at some indefinite time. + CK_ARCConsumeObject, + + /// \brief [ARC] Reclaim a retainable object pointer object that may + /// have been produced and autoreleased as part of a function return + /// sequence. + CK_ARCReclaimReturnedObject, + + /// \brief [ARC] Causes a value of block type to be copied to the + /// heap, if it is not already there. A number of other operations + /// in ARC cause blocks to be copied; this is for cases where that + /// would not otherwise be guaranteed, such as when casting to a + /// non-block pointer type. + CK_ARCExtendBlockObject, + + /// \brief Converts from _Atomic(T) to T. + CK_AtomicToNonAtomic, + /// \brief Converts from T to _Atomic(T). + CK_NonAtomicToAtomic, + + /// \brief Causes a block literal to by copied to the heap and then + /// autoreleased. + /// + /// This particular cast kind is used for the conversion from a C++11 + /// lambda expression to a block pointer. + CK_CopyAndAutoreleaseBlockObject +}; + +#define CK_Invalid ((CastKind) -1) + +enum BinaryOperatorKind { + // Operators listed in order of precedence. + // Note that additions to this should also update the StmtVisitor class. + BO_PtrMemD, BO_PtrMemI, // [C++ 5.5] Pointer-to-member operators. + BO_Mul, BO_Div, BO_Rem, // [C99 6.5.5] Multiplicative operators. + BO_Add, BO_Sub, // [C99 6.5.6] Additive operators. + BO_Shl, BO_Shr, // [C99 6.5.7] Bitwise shift operators. + BO_LT, BO_GT, BO_LE, BO_GE, // [C99 6.5.8] Relational operators. + BO_EQ, BO_NE, // [C99 6.5.9] Equality operators. + BO_And, // [C99 6.5.10] Bitwise AND operator. + BO_Xor, // [C99 6.5.11] Bitwise XOR operator. + BO_Or, // [C99 6.5.12] Bitwise OR operator. + BO_LAnd, // [C99 6.5.13] Logical AND operator. + BO_LOr, // [C99 6.5.14] Logical OR operator. + BO_Assign, BO_MulAssign, // [C99 6.5.16] Assignment operators. + BO_DivAssign, BO_RemAssign, + BO_AddAssign, BO_SubAssign, + BO_ShlAssign, BO_ShrAssign, + BO_AndAssign, BO_XorAssign, + BO_OrAssign, + BO_Comma // [C99 6.5.17] Comma operator. +}; + +enum UnaryOperatorKind { + // Note that additions to this should also update the StmtVisitor class. + UO_PostInc, UO_PostDec, // [C99 6.5.2.4] Postfix increment and decrement + UO_PreInc, UO_PreDec, // [C99 6.5.3.1] Prefix increment and decrement + UO_AddrOf, UO_Deref, // [C99 6.5.3.2] Address and indirection + UO_Plus, UO_Minus, // [C99 6.5.3.3] Unary arithmetic + UO_Not, UO_LNot, // [C99 6.5.3.3] Unary arithmetic + UO_Real, UO_Imag, // "__real expr"/"__imag expr" Extension. + UO_Extension // __extension__ marker. +}; + +/// \brief The kind of bridging performed by the Objective-C bridge cast. +enum ObjCBridgeCastKind { + /// \brief Bridging via __bridge, which does nothing but reinterpret + /// the bits. + OBC_Bridge, + /// \brief Bridging via __bridge_transfer, which transfers ownership of an + /// Objective-C pointer into ARC. + OBC_BridgeTransfer, + /// \brief Bridging via __bridge_retain, which makes an ARC object available + /// as a +1 C pointer. + OBC_BridgeRetained +}; + +} + +#endif diff --git a/clang/include/clang/AST/ParentMap.h b/clang/include/clang/AST/ParentMap.h new file mode 100644 index 0000000..62eae02 --- /dev/null +++ b/clang/include/clang/AST/ParentMap.h @@ -0,0 +1,62 @@ +//===--- ParentMap.h - Mappings from Stmts to their Parents -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ParentMap class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_PARENTMAP_H +#define LLVM_CLANG_PARENTMAP_H + +namespace clang { +class Stmt; +class Expr; + +class ParentMap { + void* Impl; +public: + ParentMap(Stmt* ASTRoot); + ~ParentMap(); + + /// \brief Adds and/or updates the parent/child-relations of the complete + /// stmt tree of S. All children of S including indirect descendants are + /// visited and updated or inserted but not the parents of S. + void addStmt(Stmt* S); + + Stmt *getParent(Stmt*) const; + Stmt *getParentIgnoreParens(Stmt *) const; + Stmt *getParentIgnoreParenCasts(Stmt *) const; + Stmt *getParentIgnoreParenImpCasts(Stmt *) const; + Stmt *getOuterParenParent(Stmt *) const; + + const Stmt *getParent(const Stmt* S) const { + return getParent(const_cast<Stmt*>(S)); + } + + const Stmt *getParentIgnoreParens(const Stmt *S) const { + return getParentIgnoreParens(const_cast<Stmt*>(S)); + } + + const Stmt *getParentIgnoreParenCasts(const Stmt *S) const { + return getParentIgnoreParenCasts(const_cast<Stmt*>(S)); + } + + bool hasParent(Stmt* S) const { + return getParent(S) != 0; + } + + bool isConsumedExpr(Expr *E) const; + + bool isConsumedExpr(const Expr *E) const { + return isConsumedExpr(const_cast<Expr*>(E)); + } +}; + +} // end clang namespace +#endif diff --git a/clang/include/clang/AST/PrettyPrinter.h b/clang/include/clang/AST/PrettyPrinter.h new file mode 100644 index 0000000..2e34dc8 --- /dev/null +++ b/clang/include/clang/AST/PrettyPrinter.h @@ -0,0 +1,146 @@ +//===--- PrettyPrinter.h - Classes for aiding with AST printing -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the PrinterHelper interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_PRETTY_PRINTER_H +#define LLVM_CLANG_AST_PRETTY_PRINTER_H + +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/LLVM.h" + +namespace clang { + +class Stmt; +class TagDecl; +class LangOptions; + +class PrinterHelper { +public: + virtual ~PrinterHelper(); + virtual bool handledStmt(Stmt* E, raw_ostream& OS) = 0; +}; + +/// \brief Describes how types, statements, expressions, and +/// declarations should be printed. +struct PrintingPolicy { + /// \brief Create a default printing policy for C. + PrintingPolicy(const LangOptions &LO) + : Indentation(2), LangOpts(LO), SuppressSpecifiers(false), + SuppressTagKeyword(false), SuppressTag(false), SuppressScope(false), + SuppressUnwrittenScope(false), SuppressInitializers(false), + Dump(false), ConstantArraySizeAsWritten(false), + AnonymousTagLocations(true), SuppressStrongLifetime(false), + Bool(LO.Bool) { } + + /// \brief The number of spaces to use to indent each line. + unsigned Indentation : 8; + + /// \brief What language we're printing. + LangOptions LangOpts; + + /// \brief Whether we should suppress printing of the actual specifiers for + /// the given type or declaration. + /// + /// This flag is only used when we are printing declarators beyond + /// the first declarator within a declaration group. For example, given: + /// + /// \code + /// const int *x, *y; + /// \endcode + /// + /// SuppressSpecifiers will be false when printing the + /// declaration for "x", so that we will print "int *x"; it will be + /// \c true when we print "y", so that we suppress printing the + /// "const int" type specifier and instead only print the "*y". + bool SuppressSpecifiers : 1; + + /// \brief Whether type printing should skip printing the tag keyword. + /// + /// This is used when printing the inner type of elaborated types, + /// (as the tag keyword is part of the elaborated type): + /// + /// \code + /// struct Geometry::Point; + /// \endcode + bool SuppressTagKeyword : 1; + + /// \brief Whether type printing should skip printing the actual tag type. + /// + /// This is used when the caller needs to print a tag definition in front + /// of the type, as in constructs like the following: + /// + /// \code + /// typedef struct { int x, y; } Point; + /// \endcode + bool SuppressTag : 1; + + /// \brief Suppresses printing of scope specifiers. + bool SuppressScope : 1; + + /// \brief Suppress printing parts of scope specifiers that don't need + /// to be written, e.g., for inline or anonymous namespaces. + bool SuppressUnwrittenScope : 1; + + /// \brief Suppress printing of variable initializers. + /// + /// This flag is used when printing the loop variable in a for-range + /// statement. For example, given: + /// + /// \code + /// for (auto x : coll) + /// \endcode + /// + /// SuppressInitializers will be true when printing "auto x", so that the + /// internal initializer constructed for x will not be printed. + bool SuppressInitializers : 1; + + /// \brief True when we are "dumping" rather than "pretty-printing", + /// where dumping involves printing the internal details of the AST + /// and pretty-printing involves printing something similar to + /// source code. + bool Dump : 1; + + /// \brief Whether we should print the sizes of constant array expressions + /// as written in the sources. + /// + /// This flag is determines whether arrays types declared as + /// + /// \code + /// int a[4+10*10]; + /// char a[] = "A string"; + /// \endcode + /// + /// will be printed as written or as follows: + /// + /// \code + /// int a[104]; + /// char a[9] = "A string"; + /// \endcode + bool ConstantArraySizeAsWritten : 1; + + /// \brief When printing an anonymous tag name, also print the location of + /// that entity (e.g., "enum <anonymous at t.h:10:5>"). Otherwise, just + /// prints "<anonymous>" for the name. + bool AnonymousTagLocations : 1; + + /// \brief When true, suppress printing of the __strong lifetime qualifier in + /// ARC. + unsigned SuppressStrongLifetime : 1; + + /// \brief Whether we can use 'bool' rather than '_Bool', even if the language + /// doesn't actually have 'bool' (because, e.g., it is defined as a macro). + unsigned Bool : 1; +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/AST/RecordLayout.h b/clang/include/clang/AST/RecordLayout.h new file mode 100644 index 0000000..ec07267 --- /dev/null +++ b/clang/include/clang/AST/RecordLayout.h @@ -0,0 +1,228 @@ +//===--- RecordLayout.h - Layout information for a struct/union -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the RecordLayout interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_LAYOUTINFO_H +#define LLVM_CLANG_AST_LAYOUTINFO_H + +#include "llvm/Support/DataTypes.h" +#include "llvm/ADT/DenseMap.h" +#include "clang/AST/CharUnits.h" +#include "clang/AST/DeclCXX.h" + +namespace clang { + class ASTContext; + class FieldDecl; + class RecordDecl; + class CXXRecordDecl; + +/// ASTRecordLayout - +/// This class contains layout information for one RecordDecl, +/// which is a struct/union/class. The decl represented must be a definition, +/// not a forward declaration. +/// This class is also used to contain layout information for one +/// ObjCInterfaceDecl. FIXME - Find appropriate name. +/// These objects are managed by ASTContext. +class ASTRecordLayout { + /// Size - Size of record in characters. + CharUnits Size; + + /// DataSize - Size of record in characters without tail padding. + CharUnits DataSize; + + /// FieldOffsets - Array of field offsets in bits. + uint64_t *FieldOffsets; + + // Alignment - Alignment of record in characters. + CharUnits Alignment; + + // FieldCount - Number of fields. + unsigned FieldCount; + + /// CXXRecordLayoutInfo - Contains C++ specific layout information. + struct CXXRecordLayoutInfo { + /// NonVirtualSize - The non-virtual size (in chars) of an object, which is + /// the size of the object without virtual bases. + CharUnits NonVirtualSize; + + /// NonVirtualAlign - The non-virtual alignment (in chars) of an object, + /// which is the alignment of the object without virtual bases. + CharUnits NonVirtualAlign; + + /// SizeOfLargestEmptySubobject - The size of the largest empty subobject + /// (either a base or a member). Will be zero if the class doesn't contain + /// any empty subobjects. + CharUnits SizeOfLargestEmptySubobject; + + /// VFPtrOffset - Virtual function table offset (Microsoft-only). + CharUnits VFPtrOffset; + + /// VBPtrOffset - Virtual base table offset (Microsoft-only). + CharUnits VBPtrOffset; + + /// PrimaryBase - The primary base info for this record. + llvm::PointerIntPair<const CXXRecordDecl *, 1, bool> PrimaryBase; + + /// FIXME: This should really use a SmallPtrMap, once we have one in LLVM :) + typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> BaseOffsetsMapTy; + + /// BaseOffsets - Contains a map from base classes to their offset. + BaseOffsetsMapTy BaseOffsets; + + /// VBaseOffsets - Contains a map from vbase classes to their offset. + BaseOffsetsMapTy VBaseOffsets; + }; + + /// CXXInfo - If the record layout is for a C++ record, this will have + /// C++ specific information about the record. + CXXRecordLayoutInfo *CXXInfo; + + friend class ASTContext; + + ASTRecordLayout(const ASTContext &Ctx, CharUnits size, CharUnits alignment, + CharUnits datasize, const uint64_t *fieldoffsets, + unsigned fieldcount); + + // Constructor for C++ records. + typedef CXXRecordLayoutInfo::BaseOffsetsMapTy BaseOffsetsMapTy; + ASTRecordLayout(const ASTContext &Ctx, + CharUnits size, CharUnits alignment, + CharUnits vfptroffset, CharUnits vbptroffset, + CharUnits datasize, + const uint64_t *fieldoffsets, unsigned fieldcount, + CharUnits nonvirtualsize, CharUnits nonvirtualalign, + CharUnits SizeOfLargestEmptySubobject, + const CXXRecordDecl *PrimaryBase, + bool IsPrimaryBaseVirtual, + const BaseOffsetsMapTy& BaseOffsets, + const BaseOffsetsMapTy& VBaseOffsets); + + ~ASTRecordLayout() {} + + void Destroy(ASTContext &Ctx); + + ASTRecordLayout(const ASTRecordLayout&); // DO NOT IMPLEMENT + void operator=(const ASTRecordLayout&); // DO NOT IMPLEMENT +public: + + /// getAlignment - Get the record alignment in characters. + CharUnits getAlignment() const { return Alignment; } + + /// getSize - Get the record size in characters. + CharUnits getSize() const { return Size; } + + /// getFieldCount - Get the number of fields in the layout. + unsigned getFieldCount() const { return FieldCount; } + + /// getFieldOffset - Get the offset of the given field index, in + /// bits. + uint64_t getFieldOffset(unsigned FieldNo) const { + assert (FieldNo < FieldCount && "Invalid Field No"); + return FieldOffsets[FieldNo]; + } + + /// getDataSize() - Get the record data size, which is the record size + /// without tail padding, in characters. + CharUnits getDataSize() const { + return DataSize; + } + + /// getNonVirtualSize - Get the non-virtual size (in chars) of an object, + /// which is the size of the object without virtual bases. + CharUnits getNonVirtualSize() const { + assert(CXXInfo && "Record layout does not have C++ specific info!"); + + return CXXInfo->NonVirtualSize; + } + + /// getNonVirtualSize - Get the non-virtual alignment (in chars) of an object, + /// which is the alignment of the object without virtual bases. + CharUnits getNonVirtualAlign() const { + assert(CXXInfo && "Record layout does not have C++ specific info!"); + + return CXXInfo->NonVirtualAlign; + } + + /// getPrimaryBase - Get the primary base for this record. + const CXXRecordDecl *getPrimaryBase() const { + assert(CXXInfo && "Record layout does not have C++ specific info!"); + + return CXXInfo->PrimaryBase.getPointer(); + } + + /// isPrimaryBaseVirtual - Get whether the primary base for this record + /// is virtual or not. + bool isPrimaryBaseVirtual() const { + assert(CXXInfo && "Record layout does not have C++ specific info!"); + + return CXXInfo->PrimaryBase.getInt(); + } + + /// getBaseClassOffset - Get the offset, in chars, for the given base class. + CharUnits getBaseClassOffset(const CXXRecordDecl *Base) const { + assert(CXXInfo && "Record layout does not have C++ specific info!"); + assert(CXXInfo->BaseOffsets.count(Base) && "Did not find base!"); + + return CXXInfo->BaseOffsets[Base]; + } + + /// getVBaseClassOffset - Get the offset, in chars, for the given base class. + CharUnits getVBaseClassOffset(const CXXRecordDecl *VBase) const { + assert(CXXInfo && "Record layout does not have C++ specific info!"); + assert(CXXInfo->VBaseOffsets.count(VBase) && "Did not find base!"); + + return CXXInfo->VBaseOffsets[VBase]; + } + + /// getBaseClassOffsetInBits - Get the offset, in bits, for the given + /// base class. + uint64_t getBaseClassOffsetInBits(const CXXRecordDecl *Base) const { + assert(CXXInfo && "Record layout does not have C++ specific info!"); + assert(CXXInfo->BaseOffsets.count(Base) && "Did not find base!"); + + return getBaseClassOffset(Base).getQuantity() * + Base->getASTContext().getCharWidth(); + } + + /// getVBaseClassOffsetInBits - Get the offset, in bits, for the given + /// base class. + uint64_t getVBaseClassOffsetInBits(const CXXRecordDecl *VBase) const { + assert(CXXInfo && "Record layout does not have C++ specific info!"); + assert(CXXInfo->VBaseOffsets.count(VBase) && "Did not find base!"); + + return getVBaseClassOffset(VBase).getQuantity() * + VBase->getASTContext().getCharWidth(); + } + + CharUnits getSizeOfLargestEmptySubobject() const { + assert(CXXInfo && "Record layout does not have C++ specific info!"); + return CXXInfo->SizeOfLargestEmptySubobject; + } + + /// getVFPtrOffset - Get the offset for virtual function table pointer. + /// This is only meaningful with the Microsoft ABI. + CharUnits getVFPtrOffset() const { + assert(CXXInfo && "Record layout does not have C++ specific info!"); + return CXXInfo->VFPtrOffset; + } + + /// getVBPtrOffset - Get the offset for virtual base table pointer. + /// This is only meaningful with the Microsoft ABI. + CharUnits getVBPtrOffset() const { + assert(CXXInfo && "Record layout does not have C++ specific info!"); + return CXXInfo->VBPtrOffset; + } +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h new file mode 100644 index 0000000..f1b5171 --- /dev/null +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -0,0 +1,2242 @@ +//===--- RecursiveASTVisitor.h - Recursive AST Visitor ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the RecursiveASTVisitor interface, which recursively +// traverses the entire AST. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_AST_RECURSIVEASTVISITOR_H +#define LLVM_CLANG_AST_RECURSIVEASTVISITOR_H + +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclFriend.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprObjC.h" +#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/Stmt.h" +#include "clang/AST/StmtCXX.h" +#include "clang/AST/StmtObjC.h" +#include "clang/AST/TemplateBase.h" +#include "clang/AST/TemplateName.h" +#include "clang/AST/Type.h" +#include "clang/AST/TypeLoc.h" + +// The following three macros are used for meta programming. The code +// using them is responsible for defining macro OPERATOR(). + +// All unary operators. +#define UNARYOP_LIST() \ + OPERATOR(PostInc) OPERATOR(PostDec) \ + OPERATOR(PreInc) OPERATOR(PreDec) \ + OPERATOR(AddrOf) OPERATOR(Deref) \ + OPERATOR(Plus) OPERATOR(Minus) \ + OPERATOR(Not) OPERATOR(LNot) \ + OPERATOR(Real) OPERATOR(Imag) \ + OPERATOR(Extension) + +// All binary operators (excluding compound assign operators). +#define BINOP_LIST() \ + OPERATOR(PtrMemD) OPERATOR(PtrMemI) \ + OPERATOR(Mul) OPERATOR(Div) OPERATOR(Rem) \ + OPERATOR(Add) OPERATOR(Sub) OPERATOR(Shl) \ + OPERATOR(Shr) \ + \ + OPERATOR(LT) OPERATOR(GT) OPERATOR(LE) \ + OPERATOR(GE) OPERATOR(EQ) OPERATOR(NE) \ + OPERATOR(And) OPERATOR(Xor) OPERATOR(Or) \ + OPERATOR(LAnd) OPERATOR(LOr) \ + \ + OPERATOR(Assign) \ + OPERATOR(Comma) + +// All compound assign operators. +#define CAO_LIST() \ + OPERATOR(Mul) OPERATOR(Div) OPERATOR(Rem) OPERATOR(Add) OPERATOR(Sub) \ + OPERATOR(Shl) OPERATOR(Shr) OPERATOR(And) OPERATOR(Or) OPERATOR(Xor) + +namespace clang { + +// A helper macro to implement short-circuiting when recursing. It +// invokes CALL_EXPR, which must be a method call, on the derived +// object (s.t. a user of RecursiveASTVisitor can override the method +// in CALL_EXPR). +#define TRY_TO(CALL_EXPR) \ + do { if (!getDerived().CALL_EXPR) return false; } while (0) + +/// \brief A class that does preorder depth-first traversal on the +/// entire Clang AST and visits each node. +/// +/// This class performs three distinct tasks: +/// 1. traverse the AST (i.e. go to each node); +/// 2. at a given node, walk up the class hierarchy, starting from +/// the node's dynamic type, until the top-most class (e.g. Stmt, +/// Decl, or Type) is reached. +/// 3. given a (node, class) combination, where 'class' is some base +/// class of the dynamic type of 'node', call a user-overridable +/// function to actually visit the node. +/// +/// These tasks are done by three groups of methods, respectively: +/// 1. TraverseDecl(Decl *x) does task #1. It is the entry point +/// for traversing an AST rooted at x. This method simply +/// dispatches (i.e. forwards) to TraverseFoo(Foo *x) where Foo +/// is the dynamic type of *x, which calls WalkUpFromFoo(x) and +/// then recursively visits the child nodes of x. +/// TraverseStmt(Stmt *x) and TraverseType(QualType x) work +/// similarly. +/// 2. WalkUpFromFoo(Foo *x) does task #2. It does not try to visit +/// any child node of x. Instead, it first calls WalkUpFromBar(x) +/// where Bar is the direct parent class of Foo (unless Foo has +/// no parent), and then calls VisitFoo(x) (see the next list item). +/// 3. VisitFoo(Foo *x) does task #3. +/// +/// These three method groups are tiered (Traverse* > WalkUpFrom* > +/// Visit*). A method (e.g. Traverse*) may call methods from the same +/// tier (e.g. other Traverse*) or one tier lower (e.g. WalkUpFrom*). +/// It may not call methods from a higher tier. +/// +/// Note that since WalkUpFromFoo() calls WalkUpFromBar() (where Bar +/// is Foo's super class) before calling VisitFoo(), the result is +/// that the Visit*() methods for a given node are called in the +/// top-down order (e.g. for a node of type NamedDecl, the order will +/// be VisitDecl(), VisitNamedDecl(), and then VisitNamespaceDecl()). +/// +/// This scheme guarantees that all Visit*() calls for the same AST +/// node are grouped together. In other words, Visit*() methods for +/// different nodes are never interleaved. +/// +/// Clients of this visitor should subclass the visitor (providing +/// themselves as the template argument, using the curiously recurring +/// template pattern) and override any of the Traverse*, WalkUpFrom*, +/// and Visit* methods for declarations, types, statements, +/// expressions, or other AST nodes where the visitor should customize +/// behavior. Most users only need to override Visit*. Advanced +/// users may override Traverse* and WalkUpFrom* to implement custom +/// traversal strategies. Returning false from one of these overridden +/// functions will abort the entire traversal. +/// +/// By default, this visitor tries to visit every part of the explicit +/// source code exactly once. The default policy towards templates +/// is to descend into the 'pattern' class or function body, not any +/// explicit or implicit instantiations. Explicit specializations +/// are still visited, and the patterns of partial specializations +/// are visited separately. This behavior can be changed by +/// overriding shouldVisitTemplateInstantiations() in the derived class +/// to return true, in which case all known implicit and explicit +/// instantiations will be visited at the same time as the pattern +/// from which they were produced. +template<typename Derived> +class RecursiveASTVisitor { +public: + /// \brief Return a reference to the derived class. + Derived &getDerived() { return *static_cast<Derived*>(this); } + + /// \brief Return whether this visitor should recurse into + /// template instantiations. + bool shouldVisitTemplateInstantiations() const { return false; } + + /// \brief Return whether this visitor should recurse into the types of + /// TypeLocs. + bool shouldWalkTypesOfTypeLocs() const { return true; } + + /// \brief Return whether \param S should be traversed using data recursion + /// to avoid a stack overflow with extreme cases. + bool shouldUseDataRecursionFor(Stmt *S) const { + return isa<BinaryOperator>(S) || isa<UnaryOperator>(S) || isa<CaseStmt>(S); + } + + /// \brief Recursively visit a statement or expression, by + /// dispatching to Traverse*() based on the argument's dynamic type. + /// + /// \returns false if the visitation was terminated early, true + /// otherwise (including when the argument is NULL). + bool TraverseStmt(Stmt *S); + + /// \brief Recursively visit a type, by dispatching to + /// Traverse*Type() based on the argument's getTypeClass() property. + /// + /// \returns false if the visitation was terminated early, true + /// otherwise (including when the argument is a Null type). + bool TraverseType(QualType T); + + /// \brief Recursively visit a type with location, by dispatching to + /// Traverse*TypeLoc() based on the argument type's getTypeClass() property. + /// + /// \returns false if the visitation was terminated early, true + /// otherwise (including when the argument is a Null type location). + bool TraverseTypeLoc(TypeLoc TL); + + /// \brief Recursively visit a declaration, by dispatching to + /// Traverse*Decl() based on the argument's dynamic type. + /// + /// \returns false if the visitation was terminated early, true + /// otherwise (including when the argument is NULL). + bool TraverseDecl(Decl *D); + + /// \brief Recursively visit a C++ nested-name-specifier. + /// + /// \returns false if the visitation was terminated early, true otherwise. + bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS); + + /// \brief Recursively visit a C++ nested-name-specifier with location + /// information. + /// + /// \returns false if the visitation was terminated early, true otherwise. + bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS); + + /// \brief Recursively visit a name with its location information. + /// + /// \returns false if the visitation was terminated early, true otherwise. + bool TraverseDeclarationNameInfo(DeclarationNameInfo NameInfo); + + /// \brief Recursively visit a template name and dispatch to the + /// appropriate method. + /// + /// \returns false if the visitation was terminated early, true otherwise. + bool TraverseTemplateName(TemplateName Template); + + /// \brief Recursively visit a template argument and dispatch to the + /// appropriate method for the argument type. + /// + /// \returns false if the visitation was terminated early, true otherwise. + // FIXME: migrate callers to TemplateArgumentLoc instead. + bool TraverseTemplateArgument(const TemplateArgument &Arg); + + /// \brief Recursively visit a template argument location and dispatch to the + /// appropriate method for the argument type. + /// + /// \returns false if the visitation was terminated early, true otherwise. + bool TraverseTemplateArgumentLoc(const TemplateArgumentLoc &ArgLoc); + + /// \brief Recursively visit a set of template arguments. + /// This can be overridden by a subclass, but it's not expected that + /// will be needed -- this visitor always dispatches to another. + /// + /// \returns false if the visitation was terminated early, true otherwise. + // FIXME: take a TemplateArgumentLoc* (or TemplateArgumentListInfo) instead. + bool TraverseTemplateArguments(const TemplateArgument *Args, + unsigned NumArgs); + + /// \brief Recursively visit a constructor initializer. This + /// automatically dispatches to another visitor for the initializer + /// expression, but not for the name of the initializer, so may + /// be overridden for clients that need access to the name. + /// + /// \returns false if the visitation was terminated early, true otherwise. + bool TraverseConstructorInitializer(CXXCtorInitializer *Init); + + /// \brief Recursively visit a lambda capture. + /// + /// \returns false if the visitation was terminated early, true otherwise. + bool TraverseLambdaCapture(LambdaExpr::Capture C); + + // ---- Methods on Stmts ---- + + // Declare Traverse*() for all concrete Stmt classes. +#define ABSTRACT_STMT(STMT) +#define STMT(CLASS, PARENT) \ + bool Traverse##CLASS(CLASS *S); +#include "clang/AST/StmtNodes.inc" + // The above header #undefs ABSTRACT_STMT and STMT upon exit. + + // Define WalkUpFrom*() and empty Visit*() for all Stmt classes. + bool WalkUpFromStmt(Stmt *S) { return getDerived().VisitStmt(S); } + bool VisitStmt(Stmt *S) { return true; } +#define STMT(CLASS, PARENT) \ + bool WalkUpFrom##CLASS(CLASS *S) { \ + TRY_TO(WalkUpFrom##PARENT(S)); \ + TRY_TO(Visit##CLASS(S)); \ + return true; \ + } \ + bool Visit##CLASS(CLASS *S) { return true; } +#include "clang/AST/StmtNodes.inc" + + // Define Traverse*(), WalkUpFrom*(), and Visit*() for unary + // operator methods. Unary operators are not classes in themselves + // (they're all opcodes in UnaryOperator) but do have visitors. +#define OPERATOR(NAME) \ + bool TraverseUnary##NAME(UnaryOperator *S) { \ + TRY_TO(WalkUpFromUnary##NAME(S)); \ + TRY_TO(TraverseStmt(S->getSubExpr())); \ + return true; \ + } \ + bool WalkUpFromUnary##NAME(UnaryOperator *S) { \ + TRY_TO(WalkUpFromUnaryOperator(S)); \ + TRY_TO(VisitUnary##NAME(S)); \ + return true; \ + } \ + bool VisitUnary##NAME(UnaryOperator *S) { return true; } + + UNARYOP_LIST() +#undef OPERATOR + + // Define Traverse*(), WalkUpFrom*(), and Visit*() for binary + // operator methods. Binary operators are not classes in themselves + // (they're all opcodes in BinaryOperator) but do have visitors. +#define GENERAL_BINOP_FALLBACK(NAME, BINOP_TYPE) \ + bool TraverseBin##NAME(BINOP_TYPE *S) { \ + TRY_TO(WalkUpFromBin##NAME(S)); \ + TRY_TO(TraverseStmt(S->getLHS())); \ + TRY_TO(TraverseStmt(S->getRHS())); \ + return true; \ + } \ + bool WalkUpFromBin##NAME(BINOP_TYPE *S) { \ + TRY_TO(WalkUpFrom##BINOP_TYPE(S)); \ + TRY_TO(VisitBin##NAME(S)); \ + return true; \ + } \ + bool VisitBin##NAME(BINOP_TYPE *S) { return true; } + +#define OPERATOR(NAME) GENERAL_BINOP_FALLBACK(NAME, BinaryOperator) + BINOP_LIST() +#undef OPERATOR + + // Define Traverse*(), WalkUpFrom*(), and Visit*() for compound + // assignment methods. Compound assignment operators are not + // classes in themselves (they're all opcodes in + // CompoundAssignOperator) but do have visitors. +#define OPERATOR(NAME) \ + GENERAL_BINOP_FALLBACK(NAME##Assign, CompoundAssignOperator) + + CAO_LIST() +#undef OPERATOR +#undef GENERAL_BINOP_FALLBACK + + // ---- Methods on Types ---- + // FIXME: revamp to take TypeLoc's rather than Types. + + // Declare Traverse*() for all concrete Type classes. +#define ABSTRACT_TYPE(CLASS, BASE) +#define TYPE(CLASS, BASE) \ + bool Traverse##CLASS##Type(CLASS##Type *T); +#include "clang/AST/TypeNodes.def" + // The above header #undefs ABSTRACT_TYPE and TYPE upon exit. + + // Define WalkUpFrom*() and empty Visit*() for all Type classes. + bool WalkUpFromType(Type *T) { return getDerived().VisitType(T); } + bool VisitType(Type *T) { return true; } +#define TYPE(CLASS, BASE) \ + bool WalkUpFrom##CLASS##Type(CLASS##Type *T) { \ + TRY_TO(WalkUpFrom##BASE(T)); \ + TRY_TO(Visit##CLASS##Type(T)); \ + return true; \ + } \ + bool Visit##CLASS##Type(CLASS##Type *T) { return true; } +#include "clang/AST/TypeNodes.def" + + // ---- Methods on TypeLocs ---- + // FIXME: this currently just calls the matching Type methods + + // Declare Traverse*() for all concrete Type classes. +#define ABSTRACT_TYPELOC(CLASS, BASE) +#define TYPELOC(CLASS, BASE) \ + bool Traverse##CLASS##TypeLoc(CLASS##TypeLoc TL); +#include "clang/AST/TypeLocNodes.def" + // The above header #undefs ABSTRACT_TYPELOC and TYPELOC upon exit. + + // Define WalkUpFrom*() and empty Visit*() for all TypeLoc classes. + bool WalkUpFromTypeLoc(TypeLoc TL) { return getDerived().VisitTypeLoc(TL); } + bool VisitTypeLoc(TypeLoc TL) { return true; } + + // QualifiedTypeLoc and UnqualTypeLoc are not declared in + // TypeNodes.def and thus need to be handled specially. + bool WalkUpFromQualifiedTypeLoc(QualifiedTypeLoc TL) { + return getDerived().VisitUnqualTypeLoc(TL.getUnqualifiedLoc()); + } + bool VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { return true; } + bool WalkUpFromUnqualTypeLoc(UnqualTypeLoc TL) { + return getDerived().VisitUnqualTypeLoc(TL.getUnqualifiedLoc()); + } + bool VisitUnqualTypeLoc(UnqualTypeLoc TL) { return true; } + + // Note that BASE includes trailing 'Type' which CLASS doesn't. +#define TYPE(CLASS, BASE) \ + bool WalkUpFrom##CLASS##TypeLoc(CLASS##TypeLoc TL) { \ + TRY_TO(WalkUpFrom##BASE##Loc(TL)); \ + TRY_TO(Visit##CLASS##TypeLoc(TL)); \ + return true; \ + } \ + bool Visit##CLASS##TypeLoc(CLASS##TypeLoc TL) { return true; } +#include "clang/AST/TypeNodes.def" + + // ---- Methods on Decls ---- + + // Declare Traverse*() for all concrete Decl classes. +#define ABSTRACT_DECL(DECL) +#define DECL(CLASS, BASE) \ + bool Traverse##CLASS##Decl(CLASS##Decl *D); +#include "clang/AST/DeclNodes.inc" + // The above header #undefs ABSTRACT_DECL and DECL upon exit. + + // Define WalkUpFrom*() and empty Visit*() for all Decl classes. + bool WalkUpFromDecl(Decl *D) { return getDerived().VisitDecl(D); } + bool VisitDecl(Decl *D) { return true; } +#define DECL(CLASS, BASE) \ + bool WalkUpFrom##CLASS##Decl(CLASS##Decl *D) { \ + TRY_TO(WalkUpFrom##BASE(D)); \ + TRY_TO(Visit##CLASS##Decl(D)); \ + return true; \ + } \ + bool Visit##CLASS##Decl(CLASS##Decl *D) { return true; } +#include "clang/AST/DeclNodes.inc" + +private: + // These are helper methods used by more than one Traverse* method. + bool TraverseTemplateParameterListHelper(TemplateParameterList *TPL); + bool TraverseClassInstantiations(ClassTemplateDecl* D, Decl *Pattern); + bool TraverseFunctionInstantiations(FunctionTemplateDecl* D) ; + bool TraverseTemplateArgumentLocsHelper(const TemplateArgumentLoc *TAL, + unsigned Count); + bool TraverseArrayTypeLocHelper(ArrayTypeLoc TL); + bool TraverseRecordHelper(RecordDecl *D); + bool TraverseCXXRecordHelper(CXXRecordDecl *D); + bool TraverseDeclaratorHelper(DeclaratorDecl *D); + bool TraverseDeclContextHelper(DeclContext *DC); + bool TraverseFunctionHelper(FunctionDecl *D); + bool TraverseVarHelper(VarDecl *D); + + bool Walk(Stmt *S); + + struct EnqueueJob { + Stmt *S; + Stmt::child_iterator StmtIt; + + EnqueueJob(Stmt *S) : S(S), StmtIt() { + if (Expr *E = dyn_cast_or_null<Expr>(S)) + S = E->IgnoreParens(); + } + }; + bool dataTraverse(Stmt *S); +}; + +template<typename Derived> +bool RecursiveASTVisitor<Derived>::dataTraverse(Stmt *S) { + + SmallVector<EnqueueJob, 16> Queue; + Queue.push_back(S); + + while (!Queue.empty()) { + EnqueueJob &job = Queue.back(); + Stmt *CurrS = job.S; + if (!CurrS) { + Queue.pop_back(); + continue; + } + + if (getDerived().shouldUseDataRecursionFor(CurrS)) { + if (job.StmtIt == Stmt::child_iterator()) { + if (!Walk(CurrS)) return false; + job.StmtIt = CurrS->child_begin(); + } else { + ++job.StmtIt; + } + + if (job.StmtIt != CurrS->child_end()) + Queue.push_back(*job.StmtIt); + else + Queue.pop_back(); + continue; + } + + Queue.pop_back(); + TRY_TO(TraverseStmt(CurrS)); + } + + return true; +} + +template<typename Derived> +bool RecursiveASTVisitor<Derived>::Walk(Stmt *S) { + +#define DISPATCH_WALK(NAME, CLASS, VAR) \ + return getDerived().WalkUpFrom##NAME(static_cast<CLASS*>(VAR)); + + if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(S)) { + switch (BinOp->getOpcode()) { +#define OPERATOR(NAME) \ + case BO_##NAME: DISPATCH_WALK(Bin##NAME, BinaryOperator, S); + + BINOP_LIST() +#undef OPERATOR + +#define OPERATOR(NAME) \ + case BO_##NAME##Assign: \ + DISPATCH_WALK(Bin##NAME##Assign, CompoundAssignOperator, S); + + CAO_LIST() +#undef OPERATOR + } + } else if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(S)) { + switch (UnOp->getOpcode()) { +#define OPERATOR(NAME) \ + case UO_##NAME: DISPATCH_WALK(Unary##NAME, UnaryOperator, S); + + UNARYOP_LIST() +#undef OPERATOR + } + } + + // Top switch stmt: dispatch to TraverseFooStmt for each concrete FooStmt. + switch (S->getStmtClass()) { + case Stmt::NoStmtClass: break; +#define ABSTRACT_STMT(STMT) +#define STMT(CLASS, PARENT) \ + case Stmt::CLASS##Class: DISPATCH_WALK(CLASS, CLASS, S); +#include "clang/AST/StmtNodes.inc" + } + +#undef DISPATCH_WALK + + return true; +} + +#define DISPATCH(NAME, CLASS, VAR) \ + return getDerived().Traverse##NAME(static_cast<CLASS*>(VAR)) + +template<typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseStmt(Stmt *S) { + if (!S) + return true; + + if (getDerived().shouldUseDataRecursionFor(S)) + return dataTraverse(S); + + // If we have a binary expr, dispatch to the subcode of the binop. A smart + // optimizer (e.g. LLVM) will fold this comparison into the switch stmt + // below. + if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(S)) { + switch (BinOp->getOpcode()) { +#define OPERATOR(NAME) \ + case BO_##NAME: DISPATCH(Bin##NAME, BinaryOperator, S); + + BINOP_LIST() +#undef OPERATOR +#undef BINOP_LIST + +#define OPERATOR(NAME) \ + case BO_##NAME##Assign: \ + DISPATCH(Bin##NAME##Assign, CompoundAssignOperator, S); + + CAO_LIST() +#undef OPERATOR +#undef CAO_LIST + } + } else if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(S)) { + switch (UnOp->getOpcode()) { +#define OPERATOR(NAME) \ + case UO_##NAME: DISPATCH(Unary##NAME, UnaryOperator, S); + + UNARYOP_LIST() +#undef OPERATOR +#undef UNARYOP_LIST + } + } + + // Top switch stmt: dispatch to TraverseFooStmt for each concrete FooStmt. + switch (S->getStmtClass()) { + case Stmt::NoStmtClass: break; +#define ABSTRACT_STMT(STMT) +#define STMT(CLASS, PARENT) \ + case Stmt::CLASS##Class: DISPATCH(CLASS, CLASS, S); +#include "clang/AST/StmtNodes.inc" + } + + return true; +} + +template<typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseType(QualType T) { + if (T.isNull()) + return true; + + switch (T->getTypeClass()) { +#define ABSTRACT_TYPE(CLASS, BASE) +#define TYPE(CLASS, BASE) \ + case Type::CLASS: DISPATCH(CLASS##Type, CLASS##Type, \ + const_cast<Type*>(T.getTypePtr())); +#include "clang/AST/TypeNodes.def" + } + + return true; +} + +template<typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseTypeLoc(TypeLoc TL) { + if (TL.isNull()) + return true; + + switch (TL.getTypeLocClass()) { +#define ABSTRACT_TYPELOC(CLASS, BASE) +#define TYPELOC(CLASS, BASE) \ + case TypeLoc::CLASS: \ + return getDerived().Traverse##CLASS##TypeLoc(*cast<CLASS##TypeLoc>(&TL)); +#include "clang/AST/TypeLocNodes.def" + } + + return true; +} + + +template<typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseDecl(Decl *D) { + if (!D) + return true; + + // As a syntax visitor, we want to ignore declarations for + // implicitly-defined declarations (ones not typed explicitly by the + // user). + if (D->isImplicit()) + return true; + + switch (D->getKind()) { +#define ABSTRACT_DECL(DECL) +#define DECL(CLASS, BASE) \ + case Decl::CLASS: DISPATCH(CLASS##Decl, CLASS##Decl, D); +#include "clang/AST/DeclNodes.inc" + } + + return true; +} + +#undef DISPATCH + +template<typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseNestedNameSpecifier( + NestedNameSpecifier *NNS) { + if (!NNS) + return true; + + if (NNS->getPrefix()) + TRY_TO(TraverseNestedNameSpecifier(NNS->getPrefix())); + + switch (NNS->getKind()) { + case NestedNameSpecifier::Identifier: + case NestedNameSpecifier::Namespace: + case NestedNameSpecifier::NamespaceAlias: + case NestedNameSpecifier::Global: + return true; + + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: + TRY_TO(TraverseType(QualType(NNS->getAsType(), 0))); + } + + return true; +} + +template<typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseNestedNameSpecifierLoc( + NestedNameSpecifierLoc NNS) { + if (!NNS) + return true; + + if (NestedNameSpecifierLoc Prefix = NNS.getPrefix()) + TRY_TO(TraverseNestedNameSpecifierLoc(Prefix)); + + switch (NNS.getNestedNameSpecifier()->getKind()) { + case NestedNameSpecifier::Identifier: + case NestedNameSpecifier::Namespace: + case NestedNameSpecifier::NamespaceAlias: + case NestedNameSpecifier::Global: + return true; + + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: + TRY_TO(TraverseTypeLoc(NNS.getTypeLoc())); + break; + } + + return true; +} + +template<typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseDeclarationNameInfo( + DeclarationNameInfo NameInfo) { + switch (NameInfo.getName().getNameKind()) { + case DeclarationName::CXXConstructorName: + case DeclarationName::CXXDestructorName: + case DeclarationName::CXXConversionFunctionName: + if (TypeSourceInfo *TSInfo = NameInfo.getNamedTypeInfo()) + TRY_TO(TraverseTypeLoc(TSInfo->getTypeLoc())); + + break; + + case DeclarationName::Identifier: + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + case DeclarationName::CXXOperatorName: + case DeclarationName::CXXLiteralOperatorName: + case DeclarationName::CXXUsingDirective: + break; + } + + return true; +} + +template<typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseTemplateName(TemplateName Template) { + if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) + TRY_TO(TraverseNestedNameSpecifier(DTN->getQualifier())); + else if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName()) + TRY_TO(TraverseNestedNameSpecifier(QTN->getQualifier())); + + return true; +} + +template<typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseTemplateArgument( + const TemplateArgument &Arg) { + switch (Arg.getKind()) { + case TemplateArgument::Null: + case TemplateArgument::Declaration: + case TemplateArgument::Integral: + return true; + + case TemplateArgument::Type: + return getDerived().TraverseType(Arg.getAsType()); + + case TemplateArgument::Template: + case TemplateArgument::TemplateExpansion: + return getDerived().TraverseTemplateName( + Arg.getAsTemplateOrTemplatePattern()); + + case TemplateArgument::Expression: + return getDerived().TraverseStmt(Arg.getAsExpr()); + + case TemplateArgument::Pack: + return getDerived().TraverseTemplateArguments(Arg.pack_begin(), + Arg.pack_size()); + } + + return true; +} + +// FIXME: no template name location? +// FIXME: no source locations for a template argument pack? +template<typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseTemplateArgumentLoc( + const TemplateArgumentLoc &ArgLoc) { + const TemplateArgument &Arg = ArgLoc.getArgument(); + + switch (Arg.getKind()) { + case TemplateArgument::Null: + case TemplateArgument::Declaration: + case TemplateArgument::Integral: + return true; + + case TemplateArgument::Type: { + // FIXME: how can TSI ever be NULL? + if (TypeSourceInfo *TSI = ArgLoc.getTypeSourceInfo()) + return getDerived().TraverseTypeLoc(TSI->getTypeLoc()); + else + return getDerived().TraverseType(Arg.getAsType()); + } + + case TemplateArgument::Template: + case TemplateArgument::TemplateExpansion: + if (ArgLoc.getTemplateQualifierLoc()) + TRY_TO(getDerived().TraverseNestedNameSpecifierLoc( + ArgLoc.getTemplateQualifierLoc())); + return getDerived().TraverseTemplateName( + Arg.getAsTemplateOrTemplatePattern()); + + case TemplateArgument::Expression: + return getDerived().TraverseStmt(ArgLoc.getSourceExpression()); + + case TemplateArgument::Pack: + return getDerived().TraverseTemplateArguments(Arg.pack_begin(), + Arg.pack_size()); + } + + return true; +} + +template<typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseTemplateArguments( + const TemplateArgument *Args, + unsigned NumArgs) { + for (unsigned I = 0; I != NumArgs; ++I) { + TRY_TO(TraverseTemplateArgument(Args[I])); + } + + return true; +} + +template<typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseConstructorInitializer( + CXXCtorInitializer *Init) { + if (TypeSourceInfo *TInfo = Init->getTypeSourceInfo()) + TRY_TO(TraverseTypeLoc(TInfo->getTypeLoc())); + + if (Init->isWritten()) + TRY_TO(TraverseStmt(Init->getInit())); + return true; +} + +template<typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseLambdaCapture(LambdaExpr::Capture C){ + return true; +} + +// ----------------- Type traversal ----------------- + +// This macro makes available a variable T, the passed-in type. +#define DEF_TRAVERSE_TYPE(TYPE, CODE) \ + template<typename Derived> \ + bool RecursiveASTVisitor<Derived>::Traverse##TYPE (TYPE *T) { \ + TRY_TO(WalkUpFrom##TYPE (T)); \ + { CODE; } \ + return true; \ + } + +DEF_TRAVERSE_TYPE(BuiltinType, { }) + +DEF_TRAVERSE_TYPE(ComplexType, { + TRY_TO(TraverseType(T->getElementType())); + }) + +DEF_TRAVERSE_TYPE(PointerType, { + TRY_TO(TraverseType(T->getPointeeType())); + }) + +DEF_TRAVERSE_TYPE(BlockPointerType, { + TRY_TO(TraverseType(T->getPointeeType())); + }) + +DEF_TRAVERSE_TYPE(LValueReferenceType, { + TRY_TO(TraverseType(T->getPointeeType())); + }) + +DEF_TRAVERSE_TYPE(RValueReferenceType, { + TRY_TO(TraverseType(T->getPointeeType())); + }) + +DEF_TRAVERSE_TYPE(MemberPointerType, { + TRY_TO(TraverseType(QualType(T->getClass(), 0))); + TRY_TO(TraverseType(T->getPointeeType())); + }) + +DEF_TRAVERSE_TYPE(ConstantArrayType, { + TRY_TO(TraverseType(T->getElementType())); + }) + +DEF_TRAVERSE_TYPE(IncompleteArrayType, { + TRY_TO(TraverseType(T->getElementType())); + }) + +DEF_TRAVERSE_TYPE(VariableArrayType, { + TRY_TO(TraverseType(T->getElementType())); + TRY_TO(TraverseStmt(T->getSizeExpr())); + }) + +DEF_TRAVERSE_TYPE(DependentSizedArrayType, { + TRY_TO(TraverseType(T->getElementType())); + if (T->getSizeExpr()) + TRY_TO(TraverseStmt(T->getSizeExpr())); + }) + +DEF_TRAVERSE_TYPE(DependentSizedExtVectorType, { + if (T->getSizeExpr()) + TRY_TO(TraverseStmt(T->getSizeExpr())); + TRY_TO(TraverseType(T->getElementType())); + }) + +DEF_TRAVERSE_TYPE(VectorType, { + TRY_TO(TraverseType(T->getElementType())); + }) + +DEF_TRAVERSE_TYPE(ExtVectorType, { + TRY_TO(TraverseType(T->getElementType())); + }) + +DEF_TRAVERSE_TYPE(FunctionNoProtoType, { + TRY_TO(TraverseType(T->getResultType())); + }) + +DEF_TRAVERSE_TYPE(FunctionProtoType, { + TRY_TO(TraverseType(T->getResultType())); + + for (FunctionProtoType::arg_type_iterator A = T->arg_type_begin(), + AEnd = T->arg_type_end(); + A != AEnd; ++A) { + TRY_TO(TraverseType(*A)); + } + + for (FunctionProtoType::exception_iterator E = T->exception_begin(), + EEnd = T->exception_end(); + E != EEnd; ++E) { + TRY_TO(TraverseType(*E)); + } + }) + +DEF_TRAVERSE_TYPE(UnresolvedUsingType, { }) +DEF_TRAVERSE_TYPE(TypedefType, { }) + +DEF_TRAVERSE_TYPE(TypeOfExprType, { + TRY_TO(TraverseStmt(T->getUnderlyingExpr())); + }) + +DEF_TRAVERSE_TYPE(TypeOfType, { + TRY_TO(TraverseType(T->getUnderlyingType())); + }) + +DEF_TRAVERSE_TYPE(DecltypeType, { + TRY_TO(TraverseStmt(T->getUnderlyingExpr())); + }) + +DEF_TRAVERSE_TYPE(UnaryTransformType, { + TRY_TO(TraverseType(T->getBaseType())); + TRY_TO(TraverseType(T->getUnderlyingType())); + }) + +DEF_TRAVERSE_TYPE(AutoType, { + TRY_TO(TraverseType(T->getDeducedType())); + }) + +DEF_TRAVERSE_TYPE(RecordType, { }) +DEF_TRAVERSE_TYPE(EnumType, { }) +DEF_TRAVERSE_TYPE(TemplateTypeParmType, { }) +DEF_TRAVERSE_TYPE(SubstTemplateTypeParmType, { }) +DEF_TRAVERSE_TYPE(SubstTemplateTypeParmPackType, { }) + +DEF_TRAVERSE_TYPE(TemplateSpecializationType, { + TRY_TO(TraverseTemplateName(T->getTemplateName())); + TRY_TO(TraverseTemplateArguments(T->getArgs(), T->getNumArgs())); + }) + +DEF_TRAVERSE_TYPE(InjectedClassNameType, { }) + +DEF_TRAVERSE_TYPE(AttributedType, { + TRY_TO(TraverseType(T->getModifiedType())); + }) + +DEF_TRAVERSE_TYPE(ParenType, { + TRY_TO(TraverseType(T->getInnerType())); + }) + +DEF_TRAVERSE_TYPE(ElaboratedType, { + if (T->getQualifier()) { + TRY_TO(TraverseNestedNameSpecifier(T->getQualifier())); + } + TRY_TO(TraverseType(T->getNamedType())); + }) + +DEF_TRAVERSE_TYPE(DependentNameType, { + TRY_TO(TraverseNestedNameSpecifier(T->getQualifier())); + }) + +DEF_TRAVERSE_TYPE(DependentTemplateSpecializationType, { + TRY_TO(TraverseNestedNameSpecifier(T->getQualifier())); + TRY_TO(TraverseTemplateArguments(T->getArgs(), T->getNumArgs())); + }) + +DEF_TRAVERSE_TYPE(PackExpansionType, { + TRY_TO(TraverseType(T->getPattern())); + }) + +DEF_TRAVERSE_TYPE(ObjCInterfaceType, { }) + +DEF_TRAVERSE_TYPE(ObjCObjectType, { + // We have to watch out here because an ObjCInterfaceType's base + // type is itself. + if (T->getBaseType().getTypePtr() != T) + TRY_TO(TraverseType(T->getBaseType())); + }) + +DEF_TRAVERSE_TYPE(ObjCObjectPointerType, { + TRY_TO(TraverseType(T->getPointeeType())); + }) + +DEF_TRAVERSE_TYPE(AtomicType, { + TRY_TO(TraverseType(T->getValueType())); + }) + +#undef DEF_TRAVERSE_TYPE + +// ----------------- TypeLoc traversal ----------------- + +// This macro makes available a variable TL, the passed-in TypeLoc. +// If requested, it calls WalkUpFrom* for the Type in the given TypeLoc, +// in addition to WalkUpFrom* for the TypeLoc itself, such that existing +// clients that override the WalkUpFrom*Type() and/or Visit*Type() methods +// continue to work. +#define DEF_TRAVERSE_TYPELOC(TYPE, CODE) \ + template<typename Derived> \ + bool RecursiveASTVisitor<Derived>::Traverse##TYPE##Loc(TYPE##Loc TL) { \ + if (getDerived().shouldWalkTypesOfTypeLocs()) \ + TRY_TO(WalkUpFrom##TYPE(const_cast<TYPE*>(TL.getTypePtr()))); \ + TRY_TO(WalkUpFrom##TYPE##Loc(TL)); \ + { CODE; } \ + return true; \ + } + +template<typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseQualifiedTypeLoc( + QualifiedTypeLoc TL) { + // Move this over to the 'main' typeloc tree. Note that this is a + // move -- we pretend that we were really looking at the unqualified + // typeloc all along -- rather than a recursion, so we don't follow + // the normal CRTP plan of going through + // getDerived().TraverseTypeLoc. If we did, we'd be traversing + // twice for the same type (once as a QualifiedTypeLoc version of + // the type, once as an UnqualifiedTypeLoc version of the type), + // which in effect means we'd call VisitTypeLoc twice with the + // 'same' type. This solves that problem, at the cost of never + // seeing the qualified version of the type (unless the client + // subclasses TraverseQualifiedTypeLoc themselves). It's not a + // perfect solution. A perfect solution probably requires making + // QualifiedTypeLoc a wrapper around TypeLoc -- like QualType is a + // wrapper around Type* -- rather than being its own class in the + // type hierarchy. + return TraverseTypeLoc(TL.getUnqualifiedLoc()); +} + +DEF_TRAVERSE_TYPELOC(BuiltinType, { }) + +// FIXME: ComplexTypeLoc is unfinished +DEF_TRAVERSE_TYPELOC(ComplexType, { + TRY_TO(TraverseType(TL.getTypePtr()->getElementType())); + }) + +DEF_TRAVERSE_TYPELOC(PointerType, { + TRY_TO(TraverseTypeLoc(TL.getPointeeLoc())); + }) + +DEF_TRAVERSE_TYPELOC(BlockPointerType, { + TRY_TO(TraverseTypeLoc(TL.getPointeeLoc())); + }) + +DEF_TRAVERSE_TYPELOC(LValueReferenceType, { + TRY_TO(TraverseTypeLoc(TL.getPointeeLoc())); + }) + +DEF_TRAVERSE_TYPELOC(RValueReferenceType, { + TRY_TO(TraverseTypeLoc(TL.getPointeeLoc())); + }) + +// FIXME: location of base class? +// We traverse this in the type case as well, but how is it not reached through +// the pointee type? +DEF_TRAVERSE_TYPELOC(MemberPointerType, { + TRY_TO(TraverseType(QualType(TL.getTypePtr()->getClass(), 0))); + TRY_TO(TraverseTypeLoc(TL.getPointeeLoc())); + }) + +template<typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseArrayTypeLocHelper(ArrayTypeLoc TL) { + // This isn't available for ArrayType, but is for the ArrayTypeLoc. + TRY_TO(TraverseStmt(TL.getSizeExpr())); + return true; +} + +DEF_TRAVERSE_TYPELOC(ConstantArrayType, { + TRY_TO(TraverseTypeLoc(TL.getElementLoc())); + return TraverseArrayTypeLocHelper(TL); + }) + +DEF_TRAVERSE_TYPELOC(IncompleteArrayType, { + TRY_TO(TraverseTypeLoc(TL.getElementLoc())); + return TraverseArrayTypeLocHelper(TL); + }) + +DEF_TRAVERSE_TYPELOC(VariableArrayType, { + TRY_TO(TraverseTypeLoc(TL.getElementLoc())); + return TraverseArrayTypeLocHelper(TL); + }) + +DEF_TRAVERSE_TYPELOC(DependentSizedArrayType, { + TRY_TO(TraverseTypeLoc(TL.getElementLoc())); + return TraverseArrayTypeLocHelper(TL); + }) + +// FIXME: order? why not size expr first? +// FIXME: base VectorTypeLoc is unfinished +DEF_TRAVERSE_TYPELOC(DependentSizedExtVectorType, { + if (TL.getTypePtr()->getSizeExpr()) + TRY_TO(TraverseStmt(TL.getTypePtr()->getSizeExpr())); + TRY_TO(TraverseType(TL.getTypePtr()->getElementType())); + }) + +// FIXME: VectorTypeLoc is unfinished +DEF_TRAVERSE_TYPELOC(VectorType, { + TRY_TO(TraverseType(TL.getTypePtr()->getElementType())); + }) + +// FIXME: size and attributes +// FIXME: base VectorTypeLoc is unfinished +DEF_TRAVERSE_TYPELOC(ExtVectorType, { + TRY_TO(TraverseType(TL.getTypePtr()->getElementType())); + }) + +DEF_TRAVERSE_TYPELOC(FunctionNoProtoType, { + TRY_TO(TraverseTypeLoc(TL.getResultLoc())); + }) + +// FIXME: location of exception specifications (attributes?) +DEF_TRAVERSE_TYPELOC(FunctionProtoType, { + TRY_TO(TraverseTypeLoc(TL.getResultLoc())); + + const FunctionProtoType *T = TL.getTypePtr(); + + for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) { + if (TL.getArg(I)) { + TRY_TO(TraverseDecl(TL.getArg(I))); + } else if (I < T->getNumArgs()) { + TRY_TO(TraverseType(T->getArgType(I))); + } + } + + for (FunctionProtoType::exception_iterator E = T->exception_begin(), + EEnd = T->exception_end(); + E != EEnd; ++E) { + TRY_TO(TraverseType(*E)); + } + }) + +DEF_TRAVERSE_TYPELOC(UnresolvedUsingType, { }) +DEF_TRAVERSE_TYPELOC(TypedefType, { }) + +DEF_TRAVERSE_TYPELOC(TypeOfExprType, { + TRY_TO(TraverseStmt(TL.getUnderlyingExpr())); + }) + +DEF_TRAVERSE_TYPELOC(TypeOfType, { + TRY_TO(TraverseTypeLoc(TL.getUnderlyingTInfo()->getTypeLoc())); + }) + +// FIXME: location of underlying expr +DEF_TRAVERSE_TYPELOC(DecltypeType, { + TRY_TO(TraverseStmt(TL.getTypePtr()->getUnderlyingExpr())); + }) + +DEF_TRAVERSE_TYPELOC(UnaryTransformType, { + TRY_TO(TraverseTypeLoc(TL.getUnderlyingTInfo()->getTypeLoc())); + }) + +DEF_TRAVERSE_TYPELOC(AutoType, { + TRY_TO(TraverseType(TL.getTypePtr()->getDeducedType())); + }) + +DEF_TRAVERSE_TYPELOC(RecordType, { }) +DEF_TRAVERSE_TYPELOC(EnumType, { }) +DEF_TRAVERSE_TYPELOC(TemplateTypeParmType, { }) +DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmType, { }) +DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmPackType, { }) + +// FIXME: use the loc for the template name? +DEF_TRAVERSE_TYPELOC(TemplateSpecializationType, { + TRY_TO(TraverseTemplateName(TL.getTypePtr()->getTemplateName())); + for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) { + TRY_TO(TraverseTemplateArgumentLoc(TL.getArgLoc(I))); + } + }) + +DEF_TRAVERSE_TYPELOC(InjectedClassNameType, { }) + +DEF_TRAVERSE_TYPELOC(ParenType, { + TRY_TO(TraverseTypeLoc(TL.getInnerLoc())); + }) + +DEF_TRAVERSE_TYPELOC(AttributedType, { + TRY_TO(TraverseTypeLoc(TL.getModifiedLoc())); + }) + +DEF_TRAVERSE_TYPELOC(ElaboratedType, { + if (TL.getQualifierLoc()) { + TRY_TO(TraverseNestedNameSpecifierLoc(TL.getQualifierLoc())); + } + TRY_TO(TraverseTypeLoc(TL.getNamedTypeLoc())); + }) + +DEF_TRAVERSE_TYPELOC(DependentNameType, { + TRY_TO(TraverseNestedNameSpecifierLoc(TL.getQualifierLoc())); + }) + +DEF_TRAVERSE_TYPELOC(DependentTemplateSpecializationType, { + if (TL.getQualifierLoc()) { + TRY_TO(TraverseNestedNameSpecifierLoc(TL.getQualifierLoc())); + } + + for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) { + TRY_TO(TraverseTemplateArgumentLoc(TL.getArgLoc(I))); + } + }) + +DEF_TRAVERSE_TYPELOC(PackExpansionType, { + TRY_TO(TraverseTypeLoc(TL.getPatternLoc())); + }) + +DEF_TRAVERSE_TYPELOC(ObjCInterfaceType, { }) + +DEF_TRAVERSE_TYPELOC(ObjCObjectType, { + // We have to watch out here because an ObjCInterfaceType's base + // type is itself. + if (TL.getTypePtr()->getBaseType().getTypePtr() != TL.getTypePtr()) + TRY_TO(TraverseTypeLoc(TL.getBaseLoc())); + }) + +DEF_TRAVERSE_TYPELOC(ObjCObjectPointerType, { + TRY_TO(TraverseTypeLoc(TL.getPointeeLoc())); + }) + +DEF_TRAVERSE_TYPELOC(AtomicType, { + TRY_TO(TraverseTypeLoc(TL.getValueLoc())); + }) + +#undef DEF_TRAVERSE_TYPELOC + +// ----------------- Decl traversal ----------------- +// +// For a Decl, we automate (in the DEF_TRAVERSE_DECL macro) traversing +// the children that come from the DeclContext associated with it. +// Therefore each Traverse* only needs to worry about children other +// than those. + +template<typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseDeclContextHelper(DeclContext *DC) { + if (!DC) + return true; + + for (DeclContext::decl_iterator Child = DC->decls_begin(), + ChildEnd = DC->decls_end(); + Child != ChildEnd; ++Child) { + // BlockDecls are traversed through BlockExprs. + if (!isa<BlockDecl>(*Child)) + TRY_TO(TraverseDecl(*Child)); + } + + return true; +} + +// This macro makes available a variable D, the passed-in decl. +#define DEF_TRAVERSE_DECL(DECL, CODE) \ +template<typename Derived> \ +bool RecursiveASTVisitor<Derived>::Traverse##DECL (DECL *D) { \ + TRY_TO(WalkUpFrom##DECL (D)); \ + { CODE; } \ + TRY_TO(TraverseDeclContextHelper(dyn_cast<DeclContext>(D))); \ + return true; \ +} + +DEF_TRAVERSE_DECL(AccessSpecDecl, { }) + +DEF_TRAVERSE_DECL(BlockDecl, { + TRY_TO(TraverseTypeLoc(D->getSignatureAsWritten()->getTypeLoc())); + TRY_TO(TraverseStmt(D->getBody())); + // This return statement makes sure the traversal of nodes in + // decls_begin()/decls_end() (done in the DEF_TRAVERSE_DECL macro) + // is skipped - don't remove it. + return true; + }) + +DEF_TRAVERSE_DECL(FileScopeAsmDecl, { + TRY_TO(TraverseStmt(D->getAsmString())); + }) + +DEF_TRAVERSE_DECL(ImportDecl, { }) + +DEF_TRAVERSE_DECL(FriendDecl, { + // Friend is either decl or a type. + if (D->getFriendType()) + TRY_TO(TraverseTypeLoc(D->getFriendType()->getTypeLoc())); + else + TRY_TO(TraverseDecl(D->getFriendDecl())); + }) + +DEF_TRAVERSE_DECL(FriendTemplateDecl, { + if (D->getFriendType()) + TRY_TO(TraverseTypeLoc(D->getFriendType()->getTypeLoc())); + else + TRY_TO(TraverseDecl(D->getFriendDecl())); + for (unsigned I = 0, E = D->getNumTemplateParameters(); I < E; ++I) { + TemplateParameterList *TPL = D->getTemplateParameterList(I); + for (TemplateParameterList::iterator ITPL = TPL->begin(), + ETPL = TPL->end(); + ITPL != ETPL; ++ITPL) { + TRY_TO(TraverseDecl(*ITPL)); + } + } + }) + +DEF_TRAVERSE_DECL(ClassScopeFunctionSpecializationDecl, { + TRY_TO(TraverseDecl(D->getSpecialization())); + }) + +DEF_TRAVERSE_DECL(LinkageSpecDecl, { }) + +DEF_TRAVERSE_DECL(ObjCPropertyImplDecl, { + // FIXME: implement this + }) + +DEF_TRAVERSE_DECL(StaticAssertDecl, { + TRY_TO(TraverseStmt(D->getAssertExpr())); + TRY_TO(TraverseStmt(D->getMessage())); + }) + +DEF_TRAVERSE_DECL(TranslationUnitDecl, { + // Code in an unnamed namespace shows up automatically in + // decls_begin()/decls_end(). Thus we don't need to recurse on + // D->getAnonymousNamespace(). + }) + +DEF_TRAVERSE_DECL(NamespaceAliasDecl, { + // We shouldn't traverse an aliased namespace, since it will be + // defined (and, therefore, traversed) somewhere else. + // + // This return statement makes sure the traversal of nodes in + // decls_begin()/decls_end() (done in the DEF_TRAVERSE_DECL macro) + // is skipped - don't remove it. + return true; + }) + +DEF_TRAVERSE_DECL(LabelDecl, { + // There is no code in a LabelDecl. +}) + + +DEF_TRAVERSE_DECL(NamespaceDecl, { + // Code in an unnamed namespace shows up automatically in + // decls_begin()/decls_end(). Thus we don't need to recurse on + // D->getAnonymousNamespace(). + }) + +DEF_TRAVERSE_DECL(ObjCCompatibleAliasDecl, { + // FIXME: implement + }) + +DEF_TRAVERSE_DECL(ObjCCategoryDecl, { + // FIXME: implement + }) + +DEF_TRAVERSE_DECL(ObjCCategoryImplDecl, { + // FIXME: implement + }) + +DEF_TRAVERSE_DECL(ObjCImplementationDecl, { + // FIXME: implement + }) + +DEF_TRAVERSE_DECL(ObjCInterfaceDecl, { + // FIXME: implement + }) + +DEF_TRAVERSE_DECL(ObjCProtocolDecl, { + // FIXME: implement + }) + +DEF_TRAVERSE_DECL(ObjCMethodDecl, { + if (D->getResultTypeSourceInfo()) { + TRY_TO(TraverseTypeLoc(D->getResultTypeSourceInfo()->getTypeLoc())); + } + for (ObjCMethodDecl::param_iterator + I = D->param_begin(), E = D->param_end(); I != E; ++I) { + TRY_TO(TraverseDecl(*I)); + } + if (D->isThisDeclarationADefinition()) { + TRY_TO(TraverseStmt(D->getBody())); + } + return true; + }) + +DEF_TRAVERSE_DECL(ObjCPropertyDecl, { + // FIXME: implement + }) + +DEF_TRAVERSE_DECL(UsingDecl, { + TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc())); + TRY_TO(TraverseDeclarationNameInfo(D->getNameInfo())); + }) + +DEF_TRAVERSE_DECL(UsingDirectiveDecl, { + TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc())); + }) + +DEF_TRAVERSE_DECL(UsingShadowDecl, { }) + +// A helper method for TemplateDecl's children. +template<typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseTemplateParameterListHelper( + TemplateParameterList *TPL) { + if (TPL) { + for (TemplateParameterList::iterator I = TPL->begin(), E = TPL->end(); + I != E; ++I) { + TRY_TO(TraverseDecl(*I)); + } + } + return true; +} + +// A helper method for traversing the implicit instantiations of a +// class. +template<typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseClassInstantiations( + ClassTemplateDecl* D, Decl *Pattern) { + assert(isa<ClassTemplateDecl>(Pattern) || + isa<ClassTemplatePartialSpecializationDecl>(Pattern)); + + ClassTemplateDecl::spec_iterator end = D->spec_end(); + for (ClassTemplateDecl::spec_iterator it = D->spec_begin(); it != end; ++it) { + ClassTemplateSpecializationDecl* SD = *it; + + switch (SD->getSpecializationKind()) { + // Visit the implicit instantiations with the requested pattern. + case TSK_ImplicitInstantiation: { + llvm::PointerUnion<ClassTemplateDecl *, + ClassTemplatePartialSpecializationDecl *> U + = SD->getInstantiatedFrom(); + + bool ShouldVisit; + if (U.is<ClassTemplateDecl*>()) + ShouldVisit = (U.get<ClassTemplateDecl*>() == Pattern); + else + ShouldVisit + = (U.get<ClassTemplatePartialSpecializationDecl*>() == Pattern); + + if (ShouldVisit) + TRY_TO(TraverseDecl(SD)); + break; + } + + // We don't need to do anything on an explicit instantiation + // or explicit specialization because there will be an explicit + // node for it elsewhere. + case TSK_ExplicitInstantiationDeclaration: + case TSK_ExplicitInstantiationDefinition: + case TSK_ExplicitSpecialization: + break; + + // We don't need to do anything for an uninstantiated + // specialization. + case TSK_Undeclared: + break; + } + } + + return true; +} + +DEF_TRAVERSE_DECL(ClassTemplateDecl, { + CXXRecordDecl* TempDecl = D->getTemplatedDecl(); + TRY_TO(TraverseDecl(TempDecl)); + TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters())); + + // By default, we do not traverse the instantiations of + // class templates since they do not appear in the user code. The + // following code optionally traverses them. + if (getDerived().shouldVisitTemplateInstantiations()) { + // If this is the definition of the primary template, visit + // instantiations which were formed from this pattern. + if (D->isThisDeclarationADefinition()) + TRY_TO(TraverseClassInstantiations(D, D)); + } + + // Note that getInstantiatedFromMemberTemplate() is just a link + // from a template instantiation back to the template from which + // it was instantiated, and thus should not be traversed. + }) + +// A helper method for traversing the instantiations of a +// function while skipping its specializations. +template<typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseFunctionInstantiations( + FunctionTemplateDecl* D) { + FunctionTemplateDecl::spec_iterator end = D->spec_end(); + for (FunctionTemplateDecl::spec_iterator it = D->spec_begin(); it != end; + ++it) { + FunctionDecl* FD = *it; + switch (FD->getTemplateSpecializationKind()) { + case TSK_ImplicitInstantiation: + // We don't know what kind of FunctionDecl this is. + TRY_TO(TraverseDecl(FD)); + break; + + // No need to visit explicit instantiations, we'll find the node + // eventually. + case TSK_ExplicitInstantiationDeclaration: + case TSK_ExplicitInstantiationDefinition: + break; + + case TSK_Undeclared: // Declaration of the template definition. + case TSK_ExplicitSpecialization: + break; + } + } + + return true; +} + +DEF_TRAVERSE_DECL(FunctionTemplateDecl, { + TRY_TO(TraverseDecl(D->getTemplatedDecl())); + TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters())); + + // By default, we do not traverse the instantiations of + // function templates since they do not apprear in the user code. The + // following code optionally traverses them. + if (getDerived().shouldVisitTemplateInstantiations()) { + // Explicit function specializations will be traversed from the + // context of their declaration. There is therefore no need to + // traverse them for here. + // + // In addition, we only traverse the function instantiations when + // the function template is a function template definition. + if (D->isThisDeclarationADefinition()) { + TRY_TO(TraverseFunctionInstantiations(D)); + } + } + }) + +DEF_TRAVERSE_DECL(TemplateTemplateParmDecl, { + // D is the "T" in something like + // template <template <typename> class T> class container { }; + TRY_TO(TraverseDecl(D->getTemplatedDecl())); + if (D->hasDefaultArgument()) { + TRY_TO(TraverseTemplateArgumentLoc(D->getDefaultArgument())); + } + TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters())); + }) + +DEF_TRAVERSE_DECL(TemplateTypeParmDecl, { + // D is the "T" in something like "template<typename T> class vector;" + if (D->getTypeForDecl()) + TRY_TO(TraverseType(QualType(D->getTypeForDecl(), 0))); + if (D->hasDefaultArgument()) + TRY_TO(TraverseTypeLoc(D->getDefaultArgumentInfo()->getTypeLoc())); + }) + +DEF_TRAVERSE_DECL(TypedefDecl, { + TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc())); + // We shouldn't traverse D->getTypeForDecl(); it's a result of + // declaring the typedef, not something that was written in the + // source. + }) + +DEF_TRAVERSE_DECL(TypeAliasDecl, { + TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc())); + // We shouldn't traverse D->getTypeForDecl(); it's a result of + // declaring the type alias, not something that was written in the + // source. + }) + +DEF_TRAVERSE_DECL(TypeAliasTemplateDecl, { + TRY_TO(TraverseDecl(D->getTemplatedDecl())); + TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters())); + }) + +DEF_TRAVERSE_DECL(UnresolvedUsingTypenameDecl, { + // A dependent using declaration which was marked with 'typename'. + // template<class T> class A : public B<T> { using typename B<T>::foo; }; + TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc())); + // We shouldn't traverse D->getTypeForDecl(); it's a result of + // declaring the type, not something that was written in the + // source. + }) + +DEF_TRAVERSE_DECL(EnumDecl, { + if (D->getTypeForDecl()) + TRY_TO(TraverseType(QualType(D->getTypeForDecl(), 0))); + + TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc())); + // The enumerators are already traversed by + // decls_begin()/decls_end(). + }) + + +// Helper methods for RecordDecl and its children. +template<typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseRecordHelper( + RecordDecl *D) { + // We shouldn't traverse D->getTypeForDecl(); it's a result of + // declaring the type, not something that was written in the source. + + TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc())); + return true; +} + +template<typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseCXXRecordHelper( + CXXRecordDecl *D) { + if (!TraverseRecordHelper(D)) + return false; + if (D->hasDefinition()) { + for (CXXRecordDecl::base_class_iterator I = D->bases_begin(), + E = D->bases_end(); + I != E; ++I) { + TRY_TO(TraverseTypeLoc(I->getTypeSourceInfo()->getTypeLoc())); + } + // We don't traverse the friends or the conversions, as they are + // already in decls_begin()/decls_end(). + } + return true; +} + +DEF_TRAVERSE_DECL(RecordDecl, { + TRY_TO(TraverseRecordHelper(D)); + }) + +DEF_TRAVERSE_DECL(CXXRecordDecl, { + TRY_TO(TraverseCXXRecordHelper(D)); + }) + +DEF_TRAVERSE_DECL(ClassTemplateSpecializationDecl, { + // For implicit instantiations ("set<int> x;"), we don't want to + // recurse at all, since the instatiated class isn't written in + // the source code anywhere. (Note the instatiated *type* -- + // set<int> -- is written, and will still get a callback of + // TemplateSpecializationType). For explicit instantiations + // ("template set<int>;"), we do need a callback, since this + // is the only callback that's made for this instantiation. + // We use getTypeAsWritten() to distinguish. + if (TypeSourceInfo *TSI = D->getTypeAsWritten()) + TRY_TO(TraverseTypeLoc(TSI->getTypeLoc())); + + if (!getDerived().shouldVisitTemplateInstantiations() && + D->getTemplateSpecializationKind() != TSK_ExplicitSpecialization) + // Returning from here skips traversing the + // declaration context of the ClassTemplateSpecializationDecl + // (embedded in the DEF_TRAVERSE_DECL() macro) + // which contains the instantiated members of the class. + return true; + }) + +template <typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseTemplateArgumentLocsHelper( + const TemplateArgumentLoc *TAL, unsigned Count) { + for (unsigned I = 0; I < Count; ++I) { + TRY_TO(TraverseTemplateArgumentLoc(TAL[I])); + } + return true; +} + +DEF_TRAVERSE_DECL(ClassTemplatePartialSpecializationDecl, { + // The partial specialization. + if (TemplateParameterList *TPL = D->getTemplateParameters()) { + for (TemplateParameterList::iterator I = TPL->begin(), E = TPL->end(); + I != E; ++I) { + TRY_TO(TraverseDecl(*I)); + } + } + // The args that remains unspecialized. + TRY_TO(TraverseTemplateArgumentLocsHelper( + D->getTemplateArgsAsWritten(), D->getNumTemplateArgsAsWritten())); + + // Don't need the ClassTemplatePartialSpecializationHelper, even + // though that's our parent class -- we already visit all the + // template args here. + TRY_TO(TraverseCXXRecordHelper(D)); + + // If we're visiting instantiations, visit the instantiations of + // this template now. + if (getDerived().shouldVisitTemplateInstantiations() && + D->isThisDeclarationADefinition()) + TRY_TO(TraverseClassInstantiations(D->getSpecializedTemplate(), D)); + }) + +DEF_TRAVERSE_DECL(EnumConstantDecl, { + TRY_TO(TraverseStmt(D->getInitExpr())); + }) + +DEF_TRAVERSE_DECL(UnresolvedUsingValueDecl, { + // Like UnresolvedUsingTypenameDecl, but without the 'typename': + // template <class T> Class A : public Base<T> { using Base<T>::foo; }; + TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc())); + TRY_TO(TraverseDeclarationNameInfo(D->getNameInfo())); + }) + +DEF_TRAVERSE_DECL(IndirectFieldDecl, {}) + +template<typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseDeclaratorHelper(DeclaratorDecl *D) { + TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc())); + if (D->getTypeSourceInfo()) + TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc())); + else + TRY_TO(TraverseType(D->getType())); + return true; +} + +DEF_TRAVERSE_DECL(FieldDecl, { + TRY_TO(TraverseDeclaratorHelper(D)); + if (D->isBitField()) + TRY_TO(TraverseStmt(D->getBitWidth())); + else if (D->hasInClassInitializer()) + TRY_TO(TraverseStmt(D->getInClassInitializer())); + }) + +DEF_TRAVERSE_DECL(ObjCAtDefsFieldDecl, { + TRY_TO(TraverseDeclaratorHelper(D)); + if (D->isBitField()) + TRY_TO(TraverseStmt(D->getBitWidth())); + // FIXME: implement the rest. + }) + +DEF_TRAVERSE_DECL(ObjCIvarDecl, { + TRY_TO(TraverseDeclaratorHelper(D)); + if (D->isBitField()) + TRY_TO(TraverseStmt(D->getBitWidth())); + // FIXME: implement the rest. + }) + +template<typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseFunctionHelper(FunctionDecl *D) { + TRY_TO(TraverseNestedNameSpecifierLoc(D->getQualifierLoc())); + TRY_TO(TraverseDeclarationNameInfo(D->getNameInfo())); + + // If we're an explicit template specialization, iterate over the + // template args that were explicitly specified. If we were doing + // this in typing order, we'd do it between the return type and + // the function args, but both are handled by the FunctionTypeLoc + // above, so we have to choose one side. I've decided to do before. + if (const FunctionTemplateSpecializationInfo *FTSI = + D->getTemplateSpecializationInfo()) { + if (FTSI->getTemplateSpecializationKind() != TSK_Undeclared && + FTSI->getTemplateSpecializationKind() != TSK_ImplicitInstantiation) { + // A specialization might not have explicit template arguments if it has + // a templated return type and concrete arguments. + if (const ASTTemplateArgumentListInfo *TALI = + FTSI->TemplateArgumentsAsWritten) { + TRY_TO(TraverseTemplateArgumentLocsHelper(TALI->getTemplateArgs(), + TALI->NumTemplateArgs)); + } + } + } + + // Visit the function type itself, which can be either + // FunctionNoProtoType or FunctionProtoType, or a typedef. This + // also covers the return type and the function parameters, + // including exception specifications. + TRY_TO(TraverseTypeLoc(D->getTypeSourceInfo()->getTypeLoc())); + + if (CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(D)) { + // Constructor initializers. + for (CXXConstructorDecl::init_iterator I = Ctor->init_begin(), + E = Ctor->init_end(); + I != E; ++I) { + TRY_TO(TraverseConstructorInitializer(*I)); + } + } + + if (D->isThisDeclarationADefinition()) { + TRY_TO(TraverseStmt(D->getBody())); // Function body. + } + return true; +} + +DEF_TRAVERSE_DECL(FunctionDecl, { + // We skip decls_begin/decls_end, which are already covered by + // TraverseFunctionHelper(). + return TraverseFunctionHelper(D); + }) + +DEF_TRAVERSE_DECL(CXXMethodDecl, { + // We skip decls_begin/decls_end, which are already covered by + // TraverseFunctionHelper(). + return TraverseFunctionHelper(D); + }) + +DEF_TRAVERSE_DECL(CXXConstructorDecl, { + // We skip decls_begin/decls_end, which are already covered by + // TraverseFunctionHelper(). + return TraverseFunctionHelper(D); + }) + +// CXXConversionDecl is the declaration of a type conversion operator. +// It's not a cast expression. +DEF_TRAVERSE_DECL(CXXConversionDecl, { + // We skip decls_begin/decls_end, which are already covered by + // TraverseFunctionHelper(). + return TraverseFunctionHelper(D); + }) + +DEF_TRAVERSE_DECL(CXXDestructorDecl, { + // We skip decls_begin/decls_end, which are already covered by + // TraverseFunctionHelper(). + return TraverseFunctionHelper(D); + }) + +template<typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseVarHelper(VarDecl *D) { + TRY_TO(TraverseDeclaratorHelper(D)); + // Default params are taken care of when we traverse the ParmVarDecl. + if (!isa<ParmVarDecl>(D)) + TRY_TO(TraverseStmt(D->getInit())); + return true; +} + +DEF_TRAVERSE_DECL(VarDecl, { + TRY_TO(TraverseVarHelper(D)); + }) + +DEF_TRAVERSE_DECL(ImplicitParamDecl, { + TRY_TO(TraverseVarHelper(D)); + }) + +DEF_TRAVERSE_DECL(NonTypeTemplateParmDecl, { + // A non-type template parameter, e.g. "S" in template<int S> class Foo ... + TRY_TO(TraverseDeclaratorHelper(D)); + TRY_TO(TraverseStmt(D->getDefaultArgument())); + }) + +DEF_TRAVERSE_DECL(ParmVarDecl, { + TRY_TO(TraverseVarHelper(D)); + + if (D->hasDefaultArg() && + D->hasUninstantiatedDefaultArg() && + !D->hasUnparsedDefaultArg()) + TRY_TO(TraverseStmt(D->getUninstantiatedDefaultArg())); + + if (D->hasDefaultArg() && + !D->hasUninstantiatedDefaultArg() && + !D->hasUnparsedDefaultArg()) + TRY_TO(TraverseStmt(D->getDefaultArg())); + }) + +#undef DEF_TRAVERSE_DECL + +// ----------------- Stmt traversal ----------------- +// +// For stmts, we automate (in the DEF_TRAVERSE_STMT macro) iterating +// over the children defined in children() (every stmt defines these, +// though sometimes the range is empty). Each individual Traverse* +// method only needs to worry about children other than those. To see +// what children() does for a given class, see, e.g., +// http://clang.llvm.org/doxygen/Stmt_8cpp_source.html + +// This macro makes available a variable S, the passed-in stmt. +#define DEF_TRAVERSE_STMT(STMT, CODE) \ +template<typename Derived> \ +bool RecursiveASTVisitor<Derived>::Traverse##STMT (STMT *S) { \ + TRY_TO(WalkUpFrom##STMT(S)); \ + { CODE; } \ + for (Stmt::child_range range = S->children(); range; ++range) { \ + TRY_TO(TraverseStmt(*range)); \ + } \ + return true; \ +} + +DEF_TRAVERSE_STMT(AsmStmt, { + TRY_TO(TraverseStmt(S->getAsmString())); + for (unsigned I = 0, E = S->getNumInputs(); I < E; ++I) { + TRY_TO(TraverseStmt(S->getInputConstraintLiteral(I))); + } + for (unsigned I = 0, E = S->getNumOutputs(); I < E; ++I) { + TRY_TO(TraverseStmt(S->getOutputConstraintLiteral(I))); + } + for (unsigned I = 0, E = S->getNumClobbers(); I < E; ++I) { + TRY_TO(TraverseStmt(S->getClobber(I))); + } + // children() iterates over inputExpr and outputExpr. + }) + +DEF_TRAVERSE_STMT(CXXCatchStmt, { + TRY_TO(TraverseDecl(S->getExceptionDecl())); + // children() iterates over the handler block. + }) + +DEF_TRAVERSE_STMT(DeclStmt, { + for (DeclStmt::decl_iterator I = S->decl_begin(), E = S->decl_end(); + I != E; ++I) { + TRY_TO(TraverseDecl(*I)); + } + // Suppress the default iteration over children() by + // returning. Here's why: A DeclStmt looks like 'type var [= + // initializer]'. The decls above already traverse over the + // initializers, so we don't have to do it again (which + // children() would do). + return true; + }) + + +// These non-expr stmts (most of them), do not need any action except +// iterating over the children. +DEF_TRAVERSE_STMT(BreakStmt, { }) +DEF_TRAVERSE_STMT(CXXTryStmt, { }) +DEF_TRAVERSE_STMT(CaseStmt, { }) +DEF_TRAVERSE_STMT(CompoundStmt, { }) +DEF_TRAVERSE_STMT(ContinueStmt, { }) +DEF_TRAVERSE_STMT(DefaultStmt, { }) +DEF_TRAVERSE_STMT(DoStmt, { }) +DEF_TRAVERSE_STMT(ForStmt, { }) +DEF_TRAVERSE_STMT(GotoStmt, { }) +DEF_TRAVERSE_STMT(IfStmt, { }) +DEF_TRAVERSE_STMT(IndirectGotoStmt, { }) +DEF_TRAVERSE_STMT(LabelStmt, { }) +DEF_TRAVERSE_STMT(AttributedStmt, { }) +DEF_TRAVERSE_STMT(NullStmt, { }) +DEF_TRAVERSE_STMT(ObjCAtCatchStmt, { }) +DEF_TRAVERSE_STMT(ObjCAtFinallyStmt, { }) +DEF_TRAVERSE_STMT(ObjCAtSynchronizedStmt, { }) +DEF_TRAVERSE_STMT(ObjCAtThrowStmt, { }) +DEF_TRAVERSE_STMT(ObjCAtTryStmt, { }) +DEF_TRAVERSE_STMT(ObjCForCollectionStmt, { }) +DEF_TRAVERSE_STMT(ObjCAutoreleasePoolStmt, { }) +DEF_TRAVERSE_STMT(CXXForRangeStmt, { }) +DEF_TRAVERSE_STMT(MSDependentExistsStmt, { + TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc())); + TRY_TO(TraverseDeclarationNameInfo(S->getNameInfo())); +}) +DEF_TRAVERSE_STMT(ReturnStmt, { }) +DEF_TRAVERSE_STMT(SwitchStmt, { }) +DEF_TRAVERSE_STMT(WhileStmt, { }) + + +DEF_TRAVERSE_STMT(CXXDependentScopeMemberExpr, { + TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc())); + TRY_TO(TraverseDeclarationNameInfo(S->getMemberNameInfo())); + if (S->hasExplicitTemplateArgs()) { + TRY_TO(TraverseTemplateArgumentLocsHelper( + S->getTemplateArgs(), S->getNumTemplateArgs())); + } + }) + +DEF_TRAVERSE_STMT(DeclRefExpr, { + TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc())); + TRY_TO(TraverseDeclarationNameInfo(S->getNameInfo())); + TRY_TO(TraverseTemplateArgumentLocsHelper( + S->getTemplateArgs(), S->getNumTemplateArgs())); + }) + +DEF_TRAVERSE_STMT(DependentScopeDeclRefExpr, { + TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc())); + TRY_TO(TraverseDeclarationNameInfo(S->getNameInfo())); + if (S->hasExplicitTemplateArgs()) { + TRY_TO(TraverseTemplateArgumentLocsHelper( + S->getExplicitTemplateArgs().getTemplateArgs(), + S->getNumTemplateArgs())); + } + }) + +DEF_TRAVERSE_STMT(MemberExpr, { + TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc())); + TRY_TO(TraverseDeclarationNameInfo(S->getMemberNameInfo())); + TRY_TO(TraverseTemplateArgumentLocsHelper( + S->getTemplateArgs(), S->getNumTemplateArgs())); + }) + +DEF_TRAVERSE_STMT(ImplicitCastExpr, { + // We don't traverse the cast type, as it's not written in the + // source code. + }) + +DEF_TRAVERSE_STMT(CStyleCastExpr, { + TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc())); + }) + +DEF_TRAVERSE_STMT(CXXFunctionalCastExpr, { + TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc())); + }) + +DEF_TRAVERSE_STMT(CXXConstCastExpr, { + TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc())); + }) + +DEF_TRAVERSE_STMT(CXXDynamicCastExpr, { + TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc())); + }) + +DEF_TRAVERSE_STMT(CXXReinterpretCastExpr, { + TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc())); + }) + +DEF_TRAVERSE_STMT(CXXStaticCastExpr, { + TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc())); + }) + +// InitListExpr is a tricky one, because we want to do all our work on +// the syntactic form of the listexpr, but this method takes the +// semantic form by default. We can't use the macro helper because it +// calls WalkUp*() on the semantic form, before our code can convert +// to the syntactic form. +template<typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseInitListExpr(InitListExpr *S) { + if (InitListExpr *Syn = S->getSyntacticForm()) + S = Syn; + TRY_TO(WalkUpFromInitListExpr(S)); + // All we need are the default actions. FIXME: use a helper function. + for (Stmt::child_range range = S->children(); range; ++range) { + TRY_TO(TraverseStmt(*range)); + } + return true; +} + +// GenericSelectionExpr is a special case because the types and expressions +// are interleaved. We also need to watch out for null types (default +// generic associations). +template<typename Derived> +bool RecursiveASTVisitor<Derived>:: +TraverseGenericSelectionExpr(GenericSelectionExpr *S) { + TRY_TO(WalkUpFromGenericSelectionExpr(S)); + TRY_TO(TraverseStmt(S->getControllingExpr())); + for (unsigned i = 0; i != S->getNumAssocs(); ++i) { + if (TypeSourceInfo *TS = S->getAssocTypeSourceInfo(i)) + TRY_TO(TraverseTypeLoc(TS->getTypeLoc())); + TRY_TO(TraverseStmt(S->getAssocExpr(i))); + } + return true; +} + +// PseudoObjectExpr is a special case because of the wierdness with +// syntactic expressions and opaque values. +template<typename Derived> +bool RecursiveASTVisitor<Derived>:: +TraversePseudoObjectExpr(PseudoObjectExpr *S) { + TRY_TO(WalkUpFromPseudoObjectExpr(S)); + TRY_TO(TraverseStmt(S->getSyntacticForm())); + for (PseudoObjectExpr::semantics_iterator + i = S->semantics_begin(), e = S->semantics_end(); i != e; ++i) { + Expr *sub = *i; + if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(sub)) + sub = OVE->getSourceExpr(); + TRY_TO(TraverseStmt(sub)); + } + return true; +} + +DEF_TRAVERSE_STMT(CXXScalarValueInitExpr, { + // This is called for code like 'return T()' where T is a built-in + // (i.e. non-class) type. + TRY_TO(TraverseTypeLoc(S->getTypeSourceInfo()->getTypeLoc())); + }) + +DEF_TRAVERSE_STMT(CXXNewExpr, { + // The child-iterator will pick up the other arguments. + TRY_TO(TraverseTypeLoc(S->getAllocatedTypeSourceInfo()->getTypeLoc())); + }) + +DEF_TRAVERSE_STMT(OffsetOfExpr, { + // The child-iterator will pick up the expression representing + // the field. + // FIMXE: for code like offsetof(Foo, a.b.c), should we get + // making a MemberExpr callbacks for Foo.a, Foo.a.b, and Foo.a.b.c? + TRY_TO(TraverseTypeLoc(S->getTypeSourceInfo()->getTypeLoc())); + }) + +DEF_TRAVERSE_STMT(UnaryExprOrTypeTraitExpr, { + // The child-iterator will pick up the arg if it's an expression, + // but not if it's a type. + if (S->isArgumentType()) + TRY_TO(TraverseTypeLoc(S->getArgumentTypeInfo()->getTypeLoc())); + }) + +DEF_TRAVERSE_STMT(CXXTypeidExpr, { + // The child-iterator will pick up the arg if it's an expression, + // but not if it's a type. + if (S->isTypeOperand()) + TRY_TO(TraverseTypeLoc(S->getTypeOperandSourceInfo()->getTypeLoc())); + }) + +DEF_TRAVERSE_STMT(CXXUuidofExpr, { + // The child-iterator will pick up the arg if it's an expression, + // but not if it's a type. + if (S->isTypeOperand()) + TRY_TO(TraverseTypeLoc(S->getTypeOperandSourceInfo()->getTypeLoc())); + }) + +DEF_TRAVERSE_STMT(UnaryTypeTraitExpr, { + TRY_TO(TraverseTypeLoc(S->getQueriedTypeSourceInfo()->getTypeLoc())); + }) + +DEF_TRAVERSE_STMT(BinaryTypeTraitExpr, { + TRY_TO(TraverseTypeLoc(S->getLhsTypeSourceInfo()->getTypeLoc())); + TRY_TO(TraverseTypeLoc(S->getRhsTypeSourceInfo()->getTypeLoc())); + }) + +DEF_TRAVERSE_STMT(TypeTraitExpr, { + for (unsigned I = 0, N = S->getNumArgs(); I != N; ++I) + TRY_TO(TraverseTypeLoc(S->getArg(I)->getTypeLoc())); +}) + +DEF_TRAVERSE_STMT(ArrayTypeTraitExpr, { + TRY_TO(TraverseTypeLoc(S->getQueriedTypeSourceInfo()->getTypeLoc())); + }) + +DEF_TRAVERSE_STMT(ExpressionTraitExpr, { + TRY_TO(TraverseStmt(S->getQueriedExpression())); + }) + +DEF_TRAVERSE_STMT(VAArgExpr, { + // The child-iterator will pick up the expression argument. + TRY_TO(TraverseTypeLoc(S->getWrittenTypeInfo()->getTypeLoc())); + }) + +DEF_TRAVERSE_STMT(CXXTemporaryObjectExpr, { + // This is called for code like 'return T()' where T is a class type. + TRY_TO(TraverseTypeLoc(S->getTypeSourceInfo()->getTypeLoc())); + }) + +// Walk only the visible parts of lambda expressions. +template<typename Derived> +bool RecursiveASTVisitor<Derived>::TraverseLambdaExpr(LambdaExpr *S) { + for (LambdaExpr::capture_iterator C = S->explicit_capture_begin(), + CEnd = S->explicit_capture_end(); + C != CEnd; ++C) { + TRY_TO(TraverseLambdaCapture(*C)); + } + + if (S->hasExplicitParameters() || S->hasExplicitResultType()) { + TypeLoc TL = S->getCallOperator()->getTypeSourceInfo()->getTypeLoc(); + if (S->hasExplicitParameters() && S->hasExplicitResultType()) { + // Visit the whole type. + TRY_TO(TraverseTypeLoc(TL)); + } else if (isa<FunctionProtoTypeLoc>(TL)) { + FunctionProtoTypeLoc Proto = cast<FunctionProtoTypeLoc>(TL); + if (S->hasExplicitParameters()) { + // Visit parameters. + for (unsigned I = 0, N = Proto.getNumArgs(); I != N; ++I) { + TRY_TO(TraverseDecl(Proto.getArg(I))); + } + } else { + TRY_TO(TraverseTypeLoc(Proto.getResultLoc())); + } + } + } + + TRY_TO(TraverseStmt(S->getBody())); + return true; +} + +DEF_TRAVERSE_STMT(CXXUnresolvedConstructExpr, { + // This is called for code like 'T()', where T is a template argument. + TRY_TO(TraverseTypeLoc(S->getTypeSourceInfo()->getTypeLoc())); + }) + +// These expressions all might take explicit template arguments. +// We traverse those if so. FIXME: implement these. +DEF_TRAVERSE_STMT(CXXConstructExpr, { }) +DEF_TRAVERSE_STMT(CallExpr, { }) +DEF_TRAVERSE_STMT(CXXMemberCallExpr, { }) + +// These exprs (most of them), do not need any action except iterating +// over the children. +DEF_TRAVERSE_STMT(AddrLabelExpr, { }) +DEF_TRAVERSE_STMT(ArraySubscriptExpr, { }) +DEF_TRAVERSE_STMT(BlockExpr, { + TRY_TO(TraverseDecl(S->getBlockDecl())); + return true; // no child statements to loop through. +}) +DEF_TRAVERSE_STMT(ChooseExpr, { }) +DEF_TRAVERSE_STMT(CompoundLiteralExpr, { }) +DEF_TRAVERSE_STMT(CXXBindTemporaryExpr, { }) +DEF_TRAVERSE_STMT(CXXBoolLiteralExpr, { }) +DEF_TRAVERSE_STMT(CXXDefaultArgExpr, { }) +DEF_TRAVERSE_STMT(CXXDeleteExpr, { }) +DEF_TRAVERSE_STMT(ExprWithCleanups, { }) +DEF_TRAVERSE_STMT(CXXNullPtrLiteralExpr, { }) +DEF_TRAVERSE_STMT(CXXPseudoDestructorExpr, { + TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc())); + if (TypeSourceInfo *ScopeInfo = S->getScopeTypeInfo()) + TRY_TO(TraverseTypeLoc(ScopeInfo->getTypeLoc())); + if (TypeSourceInfo *DestroyedTypeInfo = S->getDestroyedTypeInfo()) + TRY_TO(TraverseTypeLoc(DestroyedTypeInfo->getTypeLoc())); +}) +DEF_TRAVERSE_STMT(CXXThisExpr, { }) +DEF_TRAVERSE_STMT(CXXThrowExpr, { }) +DEF_TRAVERSE_STMT(UserDefinedLiteral, { }) +DEF_TRAVERSE_STMT(DesignatedInitExpr, { }) +DEF_TRAVERSE_STMT(ExtVectorElementExpr, { }) +DEF_TRAVERSE_STMT(GNUNullExpr, { }) +DEF_TRAVERSE_STMT(ImplicitValueInitExpr, { }) +DEF_TRAVERSE_STMT(ObjCBoolLiteralExpr, { }) +DEF_TRAVERSE_STMT(ObjCEncodeExpr, { }) +DEF_TRAVERSE_STMT(ObjCIsaExpr, { }) +DEF_TRAVERSE_STMT(ObjCIvarRefExpr, { }) +DEF_TRAVERSE_STMT(ObjCMessageExpr, { }) +DEF_TRAVERSE_STMT(ObjCPropertyRefExpr, { }) +DEF_TRAVERSE_STMT(ObjCSubscriptRefExpr, { }) +DEF_TRAVERSE_STMT(ObjCProtocolExpr, { }) +DEF_TRAVERSE_STMT(ObjCSelectorExpr, { }) +DEF_TRAVERSE_STMT(ObjCIndirectCopyRestoreExpr, { }) +DEF_TRAVERSE_STMT(ObjCBridgedCastExpr, { + TRY_TO(TraverseTypeLoc(S->getTypeInfoAsWritten()->getTypeLoc())); +}) +DEF_TRAVERSE_STMT(ParenExpr, { }) +DEF_TRAVERSE_STMT(ParenListExpr, { }) +DEF_TRAVERSE_STMT(PredefinedExpr, { }) +DEF_TRAVERSE_STMT(ShuffleVectorExpr, { }) +DEF_TRAVERSE_STMT(StmtExpr, { }) +DEF_TRAVERSE_STMT(UnresolvedLookupExpr, { + TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc())); + if (S->hasExplicitTemplateArgs()) { + TRY_TO(TraverseTemplateArgumentLocsHelper(S->getTemplateArgs(), + S->getNumTemplateArgs())); + } +}) + +DEF_TRAVERSE_STMT(UnresolvedMemberExpr, { + TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc())); + if (S->hasExplicitTemplateArgs()) { + TRY_TO(TraverseTemplateArgumentLocsHelper(S->getTemplateArgs(), + S->getNumTemplateArgs())); + } +}) + +DEF_TRAVERSE_STMT(SEHTryStmt, {}) +DEF_TRAVERSE_STMT(SEHExceptStmt, {}) +DEF_TRAVERSE_STMT(SEHFinallyStmt,{}) + +DEF_TRAVERSE_STMT(CXXOperatorCallExpr, { }) +DEF_TRAVERSE_STMT(OpaqueValueExpr, { }) +DEF_TRAVERSE_STMT(CUDAKernelCallExpr, { }) + +// These operators (all of them) do not need any action except +// iterating over the children. +DEF_TRAVERSE_STMT(BinaryConditionalOperator, { }) +DEF_TRAVERSE_STMT(ConditionalOperator, { }) +DEF_TRAVERSE_STMT(UnaryOperator, { }) +DEF_TRAVERSE_STMT(BinaryOperator, { }) +DEF_TRAVERSE_STMT(CompoundAssignOperator, { }) +DEF_TRAVERSE_STMT(CXXNoexceptExpr, { }) +DEF_TRAVERSE_STMT(PackExpansionExpr, { }) +DEF_TRAVERSE_STMT(SizeOfPackExpr, { }) +DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmPackExpr, { }) +DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmExpr, { }) +DEF_TRAVERSE_STMT(MaterializeTemporaryExpr, { }) +DEF_TRAVERSE_STMT(AtomicExpr, { }) + +// These literals (all of them) do not need any action. +DEF_TRAVERSE_STMT(IntegerLiteral, { }) +DEF_TRAVERSE_STMT(CharacterLiteral, { }) +DEF_TRAVERSE_STMT(FloatingLiteral, { }) +DEF_TRAVERSE_STMT(ImaginaryLiteral, { }) +DEF_TRAVERSE_STMT(StringLiteral, { }) +DEF_TRAVERSE_STMT(ObjCStringLiteral, { }) +DEF_TRAVERSE_STMT(ObjCNumericLiteral, { }) +DEF_TRAVERSE_STMT(ObjCArrayLiteral, { }) +DEF_TRAVERSE_STMT(ObjCDictionaryLiteral, { }) + +// Traverse OpenCL: AsType, Convert. +DEF_TRAVERSE_STMT(AsTypeExpr, { }) + +// FIXME: look at the following tricky-seeming exprs to see if we +// need to recurse on anything. These are ones that have methods +// returning decls or qualtypes or nestednamespecifier -- though I'm +// not sure if they own them -- or just seemed very complicated, or +// had lots of sub-types to explore. +// +// VisitOverloadExpr and its children: recurse on template args? etc? + +// FIXME: go through all the stmts and exprs again, and see which of them +// create new types, and recurse on the types (TypeLocs?) of those. +// Candidates: +// +// http://clang.llvm.org/doxygen/classclang_1_1CXXTypeidExpr.html +// http://clang.llvm.org/doxygen/classclang_1_1UnaryExprOrTypeTraitExpr.html +// http://clang.llvm.org/doxygen/classclang_1_1TypesCompatibleExpr.html +// Every class that has getQualifier. + +#undef DEF_TRAVERSE_STMT + +#undef TRY_TO + +} // end namespace clang + +#endif // LLVM_CLANG_AST_RECURSIVEASTVISITOR_H diff --git a/clang/include/clang/AST/Redeclarable.h b/clang/include/clang/AST/Redeclarable.h new file mode 100644 index 0000000..88abadb --- /dev/null +++ b/clang/include/clang/AST/Redeclarable.h @@ -0,0 +1,181 @@ +//===-- Redeclarable.h - Base for Decls that can be redeclared -*- C++ -*-====// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Redeclarable interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_REDECLARABLE_H +#define LLVM_CLANG_AST_REDECLARABLE_H + +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/Support/Casting.h" +#include <iterator> + +namespace clang { + +/// \brief Provides common interface for the Decls that can be redeclared. +template<typename decl_type> +class Redeclarable { + +protected: + // FIXME: PointerIntPair is a value class that should not be inherited from. + // This should change to using containment. + struct DeclLink : public llvm::PointerIntPair<decl_type *, 1, bool> { + DeclLink(decl_type *D, bool isLatest) + : llvm::PointerIntPair<decl_type *, 1, bool>(D, isLatest) { } + + typedef llvm::PointerIntPair<decl_type *, 1, bool> base_type; + + bool NextIsPrevious() const { return base_type::getInt() == false; } + bool NextIsLatest() const { return base_type::getInt() == true; } + decl_type *getNext() const { return base_type::getPointer(); } + }; + + struct PreviousDeclLink : public DeclLink { + PreviousDeclLink(decl_type *D) : DeclLink(D, false) { } + }; + + struct LatestDeclLink : public DeclLink { + LatestDeclLink(decl_type *D) : DeclLink(D, true) { } + }; + + /// \brief Points to the next redeclaration in the chain. + /// + /// If NextIsPrevious() is true, this is a link to the previous declaration + /// of this same Decl. If NextIsLatest() is true, this is the first + /// declaration and Link points to the latest declaration. For example: + /// + /// #1 int f(int x, int y = 1); // <pointer to #3, true> + /// #2 int f(int x = 0, int y); // <pointer to #1, false> + /// #3 int f(int x, int y) { return x + y; } // <pointer to #2, false> + /// + /// If there is only one declaration, it is <pointer to self, true> + DeclLink RedeclLink; + +public: + Redeclarable() : RedeclLink(LatestDeclLink(static_cast<decl_type*>(this))) { } + + /// \brief Return the previous declaration of this declaration or NULL if this + /// is the first declaration. + decl_type *getPreviousDecl() { + if (RedeclLink.NextIsPrevious()) + return RedeclLink.getNext(); + return 0; + } + const decl_type *getPreviousDecl() const { + return const_cast<decl_type *>( + static_cast<const decl_type*>(this))->getPreviousDecl(); + } + + /// \brief Return the first declaration of this declaration or itself if this + /// is the only declaration. + decl_type *getFirstDeclaration() { + decl_type *D = static_cast<decl_type*>(this); + while (D->getPreviousDecl()) + D = D->getPreviousDecl(); + return D; + } + + /// \brief Return the first declaration of this declaration or itself if this + /// is the only declaration. + const decl_type *getFirstDeclaration() const { + const decl_type *D = static_cast<const decl_type*>(this); + while (D->getPreviousDecl()) + D = D->getPreviousDecl(); + return D; + } + + /// \brief Returns true if this is the first declaration. + bool isFirstDeclaration() const { + return RedeclLink.NextIsLatest(); + } + + /// \brief Returns the most recent (re)declaration of this declaration. + decl_type *getMostRecentDecl() { + return getFirstDeclaration()->RedeclLink.getNext(); + } + + /// \brief Returns the most recent (re)declaration of this declaration. + const decl_type *getMostRecentDecl() const { + return getFirstDeclaration()->RedeclLink.getNext(); + } + + /// \brief Set the previous declaration. If PrevDecl is NULL, set this as the + /// first and only declaration. + void setPreviousDeclaration(decl_type *PrevDecl); + + /// \brief Iterates through all the redeclarations of the same decl. + class redecl_iterator { + /// Current - The current declaration. + decl_type *Current; + decl_type *Starter; + bool PassedFirst; + + public: + typedef decl_type* value_type; + typedef decl_type* reference; + typedef decl_type* pointer; + typedef std::forward_iterator_tag iterator_category; + typedef std::ptrdiff_t difference_type; + + redecl_iterator() : Current(0) { } + explicit redecl_iterator(decl_type *C) + : Current(C), Starter(C), PassedFirst(false) { } + + reference operator*() const { return Current; } + pointer operator->() const { return Current; } + + redecl_iterator& operator++() { + assert(Current && "Advancing while iterator has reached end"); + // Sanity check to avoid infinite loop on invalid redecl chain. + if (Current->isFirstDeclaration()) { + if (PassedFirst) { + assert(0 && "Passed first decl twice, invalid redecl chain!"); + Current = 0; + return *this; + } + PassedFirst = true; + } + + // Get either previous decl or latest decl. + decl_type *Next = Current->RedeclLink.getNext(); + Current = (Next != Starter ? Next : 0); + return *this; + } + + redecl_iterator operator++(int) { + redecl_iterator tmp(*this); + ++(*this); + return tmp; + } + + friend bool operator==(redecl_iterator x, redecl_iterator y) { + return x.Current == y.Current; + } + friend bool operator!=(redecl_iterator x, redecl_iterator y) { + return x.Current != y.Current; + } + }; + + /// \brief Returns iterator for all the redeclarations of the same decl. + /// It will iterate at least once (when this decl is the only one). + redecl_iterator redecls_begin() const { + return redecl_iterator(const_cast<decl_type*>( + static_cast<const decl_type*>(this))); + } + redecl_iterator redecls_end() const { return redecl_iterator(); } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +} + +#endif diff --git a/clang/include/clang/AST/SelectorLocationsKind.h b/clang/include/clang/AST/SelectorLocationsKind.h new file mode 100644 index 0000000..cd43a5c --- /dev/null +++ b/clang/include/clang/AST/SelectorLocationsKind.h @@ -0,0 +1,83 @@ +//===--- SelectorLocationsKind.h - Kind of selector locations ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Describes whether the identifier locations for a selector are "standard" +// or not. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_SELECTORLOCATIONSKIND_H +#define LLVM_CLANG_AST_SELECTORLOCATIONSKIND_H + +#include "clang/Basic/LLVM.h" + +namespace clang { + class Selector; + class SourceLocation; + class Expr; + class ParmVarDecl; + +/// \brief Whether all locations of the selector identifiers are in a +/// "standard" position. +enum SelectorLocationsKind { + /// \brief Non-standard. + SelLoc_NonStandard = 0, + + /// \brief For nullary selectors, immediately before the end: + /// "[foo release]" / "-(void)release;" + /// Or immediately before the arguments: + /// "[foo first:1 second:2]" / "-(id)first:(int)x second:(int)y; + SelLoc_StandardNoSpace = 1, + + /// \brief For nullary selectors, immediately before the end: + /// "[foo release]" / "-(void)release;" + /// Or with a space between the arguments: + /// "[foo first: 1 second: 2]" / "-(id)first: (int)x second: (int)y; + SelLoc_StandardWithSpace = 2 +}; + +/// \brief Returns true if all \arg SelLocs are in a "standard" location. +SelectorLocationsKind hasStandardSelectorLocs(Selector Sel, + ArrayRef<SourceLocation> SelLocs, + ArrayRef<Expr *> Args, + SourceLocation EndLoc); + +/// \brief Get the "standard" location of a selector identifier, e.g: +/// For nullary selectors, immediately before ']': "[foo release]" +/// +/// \param WithArgSpace if true the standard location is with a space apart +/// before arguments: "[foo first: 1 second: 2]" +/// If false: "[foo first:1 second:2]" +SourceLocation getStandardSelectorLoc(unsigned Index, + Selector Sel, + bool WithArgSpace, + ArrayRef<Expr *> Args, + SourceLocation EndLoc); + +/// \brief Returns true if all \arg SelLocs are in a "standard" location. +SelectorLocationsKind hasStandardSelectorLocs(Selector Sel, + ArrayRef<SourceLocation> SelLocs, + ArrayRef<ParmVarDecl *> Args, + SourceLocation EndLoc); + +/// \brief Get the "standard" location of a selector identifier, e.g: +/// For nullary selectors, immediately before ']': "[foo release]" +/// +/// \param WithArgSpace if true the standard location is with a space apart +/// before arguments: "-(id)first: (int)x second: (int)y;" +/// If false: "-(id)first:(int)x second:(int)y;" +SourceLocation getStandardSelectorLoc(unsigned Index, + Selector Sel, + bool WithArgSpace, + ArrayRef<ParmVarDecl *> Args, + SourceLocation EndLoc); + +} // end namespace clang + +#endif diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h new file mode 100644 index 0000000..1b0f576 --- /dev/null +++ b/clang/include/clang/AST/Stmt.h @@ -0,0 +1,1747 @@ +//===--- Stmt.h - Classes for representing statements -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Stmt interface and subclasses. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_STMT_H +#define LLVM_CLANG_AST_STMT_H + +#include "clang/Basic/LLVM.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/AST/PrettyPrinter.h" +#include "clang/AST/StmtIterator.h" +#include "clang/AST/DeclGroup.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Attr.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/raw_ostream.h" +#include <string> + +namespace llvm { + class FoldingSetNodeID; +} + +namespace clang { + class ASTContext; + class Expr; + class Decl; + class ParmVarDecl; + class QualType; + class IdentifierInfo; + class SourceManager; + class StringLiteral; + class SwitchStmt; + + //===--------------------------------------------------------------------===// + // ExprIterator - Iterators for iterating over Stmt* arrays that contain + // only Expr*. This is needed because AST nodes use Stmt* arrays to store + // references to children (to be compatible with StmtIterator). + //===--------------------------------------------------------------------===// + + class Stmt; + class Expr; + + class ExprIterator { + Stmt** I; + public: + ExprIterator(Stmt** i) : I(i) {} + ExprIterator() : I(0) {} + ExprIterator& operator++() { ++I; return *this; } + ExprIterator operator-(size_t i) { return I-i; } + ExprIterator operator+(size_t i) { return I+i; } + Expr* operator[](size_t idx); + // FIXME: Verify that this will correctly return a signed distance. + signed operator-(const ExprIterator& R) const { return I - R.I; } + Expr* operator*() const; + Expr* operator->() const; + bool operator==(const ExprIterator& R) const { return I == R.I; } + bool operator!=(const ExprIterator& R) const { return I != R.I; } + bool operator>(const ExprIterator& R) const { return I > R.I; } + bool operator>=(const ExprIterator& R) const { return I >= R.I; } + }; + + class ConstExprIterator { + const Stmt * const *I; + public: + ConstExprIterator(const Stmt * const *i) : I(i) {} + ConstExprIterator() : I(0) {} + ConstExprIterator& operator++() { ++I; return *this; } + ConstExprIterator operator+(size_t i) const { return I+i; } + ConstExprIterator operator-(size_t i) const { return I-i; } + const Expr * operator[](size_t idx) const; + signed operator-(const ConstExprIterator& R) const { return I - R.I; } + const Expr * operator*() const; + const Expr * operator->() const; + bool operator==(const ConstExprIterator& R) const { return I == R.I; } + bool operator!=(const ConstExprIterator& R) const { return I != R.I; } + bool operator>(const ConstExprIterator& R) const { return I > R.I; } + bool operator>=(const ConstExprIterator& R) const { return I >= R.I; } + }; + +//===----------------------------------------------------------------------===// +// AST classes for statements. +//===----------------------------------------------------------------------===// + +/// Stmt - This represents one statement. +/// +class Stmt { +public: + enum StmtClass { + NoStmtClass = 0, +#define STMT(CLASS, PARENT) CLASS##Class, +#define STMT_RANGE(BASE, FIRST, LAST) \ + first##BASE##Constant=FIRST##Class, last##BASE##Constant=LAST##Class, +#define LAST_STMT_RANGE(BASE, FIRST, LAST) \ + first##BASE##Constant=FIRST##Class, last##BASE##Constant=LAST##Class +#define ABSTRACT_STMT(STMT) +#include "clang/AST/StmtNodes.inc" + }; + + // Make vanilla 'new' and 'delete' illegal for Stmts. +protected: + void* operator new(size_t bytes) throw() { + llvm_unreachable("Stmts cannot be allocated with regular 'new'."); + } + void operator delete(void* data) throw() { + llvm_unreachable("Stmts cannot be released with regular 'delete'."); + } + + class StmtBitfields { + friend class Stmt; + + /// \brief The statement class. + unsigned sClass : 8; + }; + enum { NumStmtBits = 8 }; + + class CompoundStmtBitfields { + friend class CompoundStmt; + unsigned : NumStmtBits; + + unsigned NumStmts : 32 - NumStmtBits; + }; + + class ExprBitfields { + friend class Expr; + friend class DeclRefExpr; // computeDependence + friend class InitListExpr; // ctor + friend class DesignatedInitExpr; // ctor + friend class BlockDeclRefExpr; // ctor + friend class ASTStmtReader; // deserialization + friend class CXXNewExpr; // ctor + friend class DependentScopeDeclRefExpr; // ctor + friend class CXXConstructExpr; // ctor + friend class CallExpr; // ctor + friend class OffsetOfExpr; // ctor + friend class ObjCMessageExpr; // ctor + friend class ObjCArrayLiteral; // ctor + friend class ObjCDictionaryLiteral; // ctor + friend class ShuffleVectorExpr; // ctor + friend class ParenListExpr; // ctor + friend class CXXUnresolvedConstructExpr; // ctor + friend class CXXDependentScopeMemberExpr; // ctor + friend class OverloadExpr; // ctor + friend class PseudoObjectExpr; // ctor + friend class AtomicExpr; // ctor + unsigned : NumStmtBits; + + unsigned ValueKind : 2; + unsigned ObjectKind : 2; + unsigned TypeDependent : 1; + unsigned ValueDependent : 1; + unsigned InstantiationDependent : 1; + unsigned ContainsUnexpandedParameterPack : 1; + }; + enum { NumExprBits = 16 }; + + class CharacterLiteralBitfields { + friend class CharacterLiteral; + unsigned : NumExprBits; + + unsigned Kind : 2; + }; + + class FloatingLiteralBitfields { + friend class FloatingLiteral; + unsigned : NumExprBits; + + unsigned IsIEEE : 1; // Distinguishes between PPC128 and IEEE128. + unsigned IsExact : 1; + }; + + class UnaryExprOrTypeTraitExprBitfields { + friend class UnaryExprOrTypeTraitExpr; + unsigned : NumExprBits; + + unsigned Kind : 2; + unsigned IsType : 1; // true if operand is a type, false if an expression. + }; + + class DeclRefExprBitfields { + friend class DeclRefExpr; + friend class ASTStmtReader; // deserialization + unsigned : NumExprBits; + + unsigned HasQualifier : 1; + unsigned HasTemplateKWAndArgsInfo : 1; + unsigned HasFoundDecl : 1; + unsigned HadMultipleCandidates : 1; + unsigned RefersToEnclosingLocal : 1; + }; + + class CastExprBitfields { + friend class CastExpr; + unsigned : NumExprBits; + + unsigned Kind : 6; + unsigned BasePathSize : 32 - 6 - NumExprBits; + }; + + class CallExprBitfields { + friend class CallExpr; + unsigned : NumExprBits; + + unsigned NumPreArgs : 1; + }; + + class ExprWithCleanupsBitfields { + friend class ExprWithCleanups; + friend class ASTStmtReader; // deserialization + + unsigned : NumExprBits; + + unsigned NumObjects : 32 - NumExprBits; + }; + + class PseudoObjectExprBitfields { + friend class PseudoObjectExpr; + friend class ASTStmtReader; // deserialization + + unsigned : NumExprBits; + + // These don't need to be particularly wide, because they're + // strictly limited by the forms of expressions we permit. + unsigned NumSubExprs : 8; + unsigned ResultIndex : 32 - 8 - NumExprBits; + }; + + class ObjCIndirectCopyRestoreExprBitfields { + friend class ObjCIndirectCopyRestoreExpr; + unsigned : NumExprBits; + + unsigned ShouldCopy : 1; + }; + + class InitListExprBitfields { + friend class InitListExpr; + + unsigned : NumExprBits; + + /// Whether this initializer list originally had a GNU array-range + /// designator in it. This is a temporary marker used by CodeGen. + unsigned HadArrayRangeDesignator : 1; + + /// Whether this initializer list initializes a std::initializer_list + /// object. + unsigned InitializesStdInitializerList : 1; + }; + + class TypeTraitExprBitfields { + friend class TypeTraitExpr; + friend class ASTStmtReader; + friend class ASTStmtWriter; + + unsigned : NumExprBits; + + /// \brief The kind of type trait, which is a value of a TypeTrait enumerator. + unsigned Kind : 8; + + /// \brief If this expression is not value-dependent, this indicates whether + /// the trait evaluated true or false. + unsigned Value : 1; + + /// \brief The number of arguments to this type trait. + unsigned NumArgs : 32 - 8 - 1 - NumExprBits; + }; + + union { + // FIXME: this is wasteful on 64-bit platforms. + void *Aligner; + + StmtBitfields StmtBits; + CompoundStmtBitfields CompoundStmtBits; + ExprBitfields ExprBits; + CharacterLiteralBitfields CharacterLiteralBits; + FloatingLiteralBitfields FloatingLiteralBits; + UnaryExprOrTypeTraitExprBitfields UnaryExprOrTypeTraitExprBits; + DeclRefExprBitfields DeclRefExprBits; + CastExprBitfields CastExprBits; + CallExprBitfields CallExprBits; + ExprWithCleanupsBitfields ExprWithCleanupsBits; + PseudoObjectExprBitfields PseudoObjectExprBits; + ObjCIndirectCopyRestoreExprBitfields ObjCIndirectCopyRestoreExprBits; + InitListExprBitfields InitListExprBits; + TypeTraitExprBitfields TypeTraitExprBits; + }; + + friend class ASTStmtReader; + friend class ASTStmtWriter; + +public: + // Only allow allocation of Stmts using the allocator in ASTContext + // or by doing a placement new. + void* operator new(size_t bytes, ASTContext& C, + unsigned alignment = 8) throw() { + return ::operator new(bytes, C, alignment); + } + + void* operator new(size_t bytes, ASTContext* C, + unsigned alignment = 8) throw() { + return ::operator new(bytes, *C, alignment); + } + + void* operator new(size_t bytes, void* mem) throw() { + return mem; + } + + void operator delete(void*, ASTContext&, unsigned) throw() { } + void operator delete(void*, ASTContext*, unsigned) throw() { } + void operator delete(void*, std::size_t) throw() { } + void operator delete(void*, void*) throw() { } + +public: + /// \brief A placeholder type used to construct an empty shell of a + /// type, that will be filled in later (e.g., by some + /// de-serialization). + struct EmptyShell { }; + +private: + /// \brief Whether statistic collection is enabled. + static bool StatisticsEnabled; + +protected: + /// \brief Construct an empty statement. + explicit Stmt(StmtClass SC, EmptyShell) { + StmtBits.sClass = SC; + if (StatisticsEnabled) Stmt::addStmtClass(SC); + } + +public: + Stmt(StmtClass SC) { + StmtBits.sClass = SC; + if (StatisticsEnabled) Stmt::addStmtClass(SC); + } + + StmtClass getStmtClass() const { + return static_cast<StmtClass>(StmtBits.sClass); + } + const char *getStmtClassName() const; + + /// SourceLocation tokens are not useful in isolation - they are low level + /// value objects created/interpreted by SourceManager. We assume AST + /// clients will have a pointer to the respective SourceManager. + SourceRange getSourceRange() const LLVM_READONLY; + SourceLocation getLocStart() const LLVM_READONLY; + SourceLocation getLocEnd() const LLVM_READONLY; + + // global temp stats (until we have a per-module visitor) + static void addStmtClass(const StmtClass s); + static void EnableStatistics(); + static void PrintStats(); + + /// dump - This does a local dump of the specified AST fragment. It dumps the + /// specified node and a few nodes underneath it, but not the whole subtree. + /// This is useful in a debugger. + LLVM_ATTRIBUTE_USED void dump() const; + LLVM_ATTRIBUTE_USED void dump(SourceManager &SM) const; + void dump(raw_ostream &OS, SourceManager &SM) const; + + /// dumpAll - This does a dump of the specified AST fragment and all subtrees. + void dumpAll() const; + void dumpAll(SourceManager &SM) const; + + /// dumpPretty/printPretty - These two methods do a "pretty print" of the AST + /// back to its original source language syntax. + void dumpPretty(ASTContext& Context) const; + void printPretty(raw_ostream &OS, PrinterHelper *Helper, + const PrintingPolicy &Policy, + unsigned Indentation = 0) const { + printPretty(OS, *(ASTContext*)0, Helper, Policy, Indentation); + } + void printPretty(raw_ostream &OS, ASTContext &Context, + PrinterHelper *Helper, + const PrintingPolicy &Policy, + unsigned Indentation = 0) const; + + /// viewAST - Visualize an AST rooted at this Stmt* using GraphViz. Only + /// works on systems with GraphViz (Mac OS X) or dot+gv installed. + void viewAST() const; + + /// Skip past any implicit AST nodes which might surround this + /// statement, such as ExprWithCleanups or ImplicitCastExpr nodes. + Stmt *IgnoreImplicit(); + + const Stmt *stripLabelLikeStatements() const; + Stmt *stripLabelLikeStatements() { + return const_cast<Stmt*>( + const_cast<const Stmt*>(this)->stripLabelLikeStatements()); + } + + // Implement isa<T> support. + static bool classof(const Stmt *) { return true; } + + /// hasImplicitControlFlow - Some statements (e.g. short circuited operations) + /// contain implicit control-flow in the order their subexpressions + /// are evaluated. This predicate returns true if this statement has + /// such implicit control-flow. Such statements are also specially handled + /// within CFGs. + bool hasImplicitControlFlow() const; + + /// Child Iterators: All subclasses must implement 'children' + /// to permit easy iteration over the substatements/subexpessions of an + /// AST node. This permits easy iteration over all nodes in the AST. + typedef StmtIterator child_iterator; + typedef ConstStmtIterator const_child_iterator; + + typedef StmtRange child_range; + typedef ConstStmtRange const_child_range; + + child_range children(); + const_child_range children() const { + return const_cast<Stmt*>(this)->children(); + } + + child_iterator child_begin() { return children().first; } + child_iterator child_end() { return children().second; } + + const_child_iterator child_begin() const { return children().first; } + const_child_iterator child_end() const { return children().second; } + + /// \brief Produce a unique representation of the given statement. + /// + /// \brief ID once the profiling operation is complete, will contain + /// the unique representation of the given statement. + /// + /// \brief Context the AST context in which the statement resides + /// + /// \brief Canonical whether the profile should be based on the canonical + /// representation of this statement (e.g., where non-type template + /// parameters are identified by index/level rather than their + /// declaration pointers) or the exact representation of the statement as + /// written in the source. + void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, + bool Canonical) const; +}; + +/// DeclStmt - Adaptor class for mixing declarations with statements and +/// expressions. For example, CompoundStmt mixes statements, expressions +/// and declarations (variables, types). Another example is ForStmt, where +/// the first statement can be an expression or a declaration. +/// +class DeclStmt : public Stmt { + DeclGroupRef DG; + SourceLocation StartLoc, EndLoc; + +public: + DeclStmt(DeclGroupRef dg, SourceLocation startLoc, + SourceLocation endLoc) : Stmt(DeclStmtClass), DG(dg), + StartLoc(startLoc), EndLoc(endLoc) {} + + /// \brief Build an empty declaration statement. + explicit DeclStmt(EmptyShell Empty) : Stmt(DeclStmtClass, Empty) { } + + /// isSingleDecl - This method returns true if this DeclStmt refers + /// to a single Decl. + bool isSingleDecl() const { + return DG.isSingleDecl(); + } + + const Decl *getSingleDecl() const { return DG.getSingleDecl(); } + Decl *getSingleDecl() { return DG.getSingleDecl(); } + + const DeclGroupRef getDeclGroup() const { return DG; } + DeclGroupRef getDeclGroup() { return DG; } + void setDeclGroup(DeclGroupRef DGR) { DG = DGR; } + + SourceLocation getStartLoc() const { return StartLoc; } + void setStartLoc(SourceLocation L) { StartLoc = L; } + SourceLocation getEndLoc() const { return EndLoc; } + void setEndLoc(SourceLocation L) { EndLoc = L; } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(StartLoc, EndLoc); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == DeclStmtClass; + } + static bool classof(const DeclStmt *) { return true; } + + // Iterators over subexpressions. + child_range children() { + return child_range(child_iterator(DG.begin(), DG.end()), + child_iterator(DG.end(), DG.end())); + } + + typedef DeclGroupRef::iterator decl_iterator; + typedef DeclGroupRef::const_iterator const_decl_iterator; + + decl_iterator decl_begin() { return DG.begin(); } + decl_iterator decl_end() { return DG.end(); } + const_decl_iterator decl_begin() const { return DG.begin(); } + const_decl_iterator decl_end() const { return DG.end(); } +}; + +/// NullStmt - This is the null statement ";": C99 6.8.3p3. +/// +class NullStmt : public Stmt { + SourceLocation SemiLoc; + + /// \brief True if the null statement was preceded by an empty macro, e.g: + /// @code + /// #define CALL(x) + /// CALL(0); + /// @endcode + bool HasLeadingEmptyMacro; +public: + NullStmt(SourceLocation L, bool hasLeadingEmptyMacro = false) + : Stmt(NullStmtClass), SemiLoc(L), + HasLeadingEmptyMacro(hasLeadingEmptyMacro) {} + + /// \brief Build an empty null statement. + explicit NullStmt(EmptyShell Empty) : Stmt(NullStmtClass, Empty), + HasLeadingEmptyMacro(false) { } + + SourceLocation getSemiLoc() const { return SemiLoc; } + void setSemiLoc(SourceLocation L) { SemiLoc = L; } + + bool hasLeadingEmptyMacro() const { return HasLeadingEmptyMacro; } + + SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(SemiLoc); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == NullStmtClass; + } + static bool classof(const NullStmt *) { return true; } + + child_range children() { return child_range(); } + + friend class ASTStmtReader; + friend class ASTStmtWriter; +}; + +/// CompoundStmt - This represents a group of statements like { stmt stmt }. +/// +class CompoundStmt : public Stmt { + Stmt** Body; + SourceLocation LBracLoc, RBracLoc; +public: + CompoundStmt(ASTContext& C, Stmt **StmtStart, unsigned NumStmts, + SourceLocation LB, SourceLocation RB) + : Stmt(CompoundStmtClass), LBracLoc(LB), RBracLoc(RB) { + CompoundStmtBits.NumStmts = NumStmts; + assert(CompoundStmtBits.NumStmts == NumStmts && + "NumStmts doesn't fit in bits of CompoundStmtBits.NumStmts!"); + + if (NumStmts == 0) { + Body = 0; + return; + } + + Body = new (C) Stmt*[NumStmts]; + memcpy(Body, StmtStart, NumStmts * sizeof(*Body)); + } + + // \brief Build an empty compound statement. + explicit CompoundStmt(EmptyShell Empty) + : Stmt(CompoundStmtClass, Empty), Body(0) { + CompoundStmtBits.NumStmts = 0; + } + + void setStmts(ASTContext &C, Stmt **Stmts, unsigned NumStmts); + + bool body_empty() const { return CompoundStmtBits.NumStmts == 0; } + unsigned size() const { return CompoundStmtBits.NumStmts; } + + typedef Stmt** body_iterator; + body_iterator body_begin() { return Body; } + body_iterator body_end() { return Body + size(); } + Stmt *body_back() { return !body_empty() ? Body[size()-1] : 0; } + + void setLastStmt(Stmt *S) { + assert(!body_empty() && "setLastStmt"); + Body[size()-1] = S; + } + + typedef Stmt* const * const_body_iterator; + const_body_iterator body_begin() const { return Body; } + const_body_iterator body_end() const { return Body + size(); } + const Stmt *body_back() const { return !body_empty() ? Body[size()-1] : 0; } + + typedef std::reverse_iterator<body_iterator> reverse_body_iterator; + reverse_body_iterator body_rbegin() { + return reverse_body_iterator(body_end()); + } + reverse_body_iterator body_rend() { + return reverse_body_iterator(body_begin()); + } + + typedef std::reverse_iterator<const_body_iterator> + const_reverse_body_iterator; + + const_reverse_body_iterator body_rbegin() const { + return const_reverse_body_iterator(body_end()); + } + + const_reverse_body_iterator body_rend() const { + return const_reverse_body_iterator(body_begin()); + } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(LBracLoc, RBracLoc); + } + + SourceLocation getLBracLoc() const { return LBracLoc; } + void setLBracLoc(SourceLocation L) { LBracLoc = L; } + SourceLocation getRBracLoc() const { return RBracLoc; } + void setRBracLoc(SourceLocation L) { RBracLoc = L; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CompoundStmtClass; + } + static bool classof(const CompoundStmt *) { return true; } + + // Iterators + child_range children() { + return child_range(&Body[0], &Body[0]+CompoundStmtBits.NumStmts); + } + + const_child_range children() const { + return child_range(&Body[0], &Body[0]+CompoundStmtBits.NumStmts); + } +}; + +// SwitchCase is the base class for CaseStmt and DefaultStmt, +class SwitchCase : public Stmt { +protected: + // A pointer to the following CaseStmt or DefaultStmt class, + // used by SwitchStmt. + SwitchCase *NextSwitchCase; + + SwitchCase(StmtClass SC) : Stmt(SC), NextSwitchCase(0) {} + +public: + const SwitchCase *getNextSwitchCase() const { return NextSwitchCase; } + + SwitchCase *getNextSwitchCase() { return NextSwitchCase; } + + void setNextSwitchCase(SwitchCase *SC) { NextSwitchCase = SC; } + + Stmt *getSubStmt(); + const Stmt *getSubStmt() const { + return const_cast<SwitchCase*>(this)->getSubStmt(); + } + + SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CaseStmtClass || + T->getStmtClass() == DefaultStmtClass; + } + static bool classof(const SwitchCase *) { return true; } +}; + +class CaseStmt : public SwitchCase { + enum { LHS, RHS, SUBSTMT, END_EXPR }; + Stmt* SubExprs[END_EXPR]; // The expression for the RHS is Non-null for + // GNU "case 1 ... 4" extension + SourceLocation CaseLoc; + SourceLocation EllipsisLoc; + SourceLocation ColonLoc; +public: + CaseStmt(Expr *lhs, Expr *rhs, SourceLocation caseLoc, + SourceLocation ellipsisLoc, SourceLocation colonLoc) + : SwitchCase(CaseStmtClass) { + SubExprs[SUBSTMT] = 0; + SubExprs[LHS] = reinterpret_cast<Stmt*>(lhs); + SubExprs[RHS] = reinterpret_cast<Stmt*>(rhs); + CaseLoc = caseLoc; + EllipsisLoc = ellipsisLoc; + ColonLoc = colonLoc; + } + + /// \brief Build an empty switch case statement. + explicit CaseStmt(EmptyShell Empty) : SwitchCase(CaseStmtClass) { } + + SourceLocation getCaseLoc() const { return CaseLoc; } + void setCaseLoc(SourceLocation L) { CaseLoc = L; } + SourceLocation getEllipsisLoc() const { return EllipsisLoc; } + void setEllipsisLoc(SourceLocation L) { EllipsisLoc = L; } + SourceLocation getColonLoc() const { return ColonLoc; } + void setColonLoc(SourceLocation L) { ColonLoc = L; } + + Expr *getLHS() { return reinterpret_cast<Expr*>(SubExprs[LHS]); } + Expr *getRHS() { return reinterpret_cast<Expr*>(SubExprs[RHS]); } + Stmt *getSubStmt() { return SubExprs[SUBSTMT]; } + + const Expr *getLHS() const { + return reinterpret_cast<const Expr*>(SubExprs[LHS]); + } + const Expr *getRHS() const { + return reinterpret_cast<const Expr*>(SubExprs[RHS]); + } + const Stmt *getSubStmt() const { return SubExprs[SUBSTMT]; } + + void setSubStmt(Stmt *S) { SubExprs[SUBSTMT] = S; } + void setLHS(Expr *Val) { SubExprs[LHS] = reinterpret_cast<Stmt*>(Val); } + void setRHS(Expr *Val) { SubExprs[RHS] = reinterpret_cast<Stmt*>(Val); } + + + SourceRange getSourceRange() const LLVM_READONLY { + // Handle deeply nested case statements with iteration instead of recursion. + const CaseStmt *CS = this; + while (const CaseStmt *CS2 = dyn_cast<CaseStmt>(CS->getSubStmt())) + CS = CS2; + + return SourceRange(CaseLoc, CS->getSubStmt()->getLocEnd()); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == CaseStmtClass; + } + static bool classof(const CaseStmt *) { return true; } + + // Iterators + child_range children() { + return child_range(&SubExprs[0], &SubExprs[END_EXPR]); + } +}; + +class DefaultStmt : public SwitchCase { + Stmt* SubStmt; + SourceLocation DefaultLoc; + SourceLocation ColonLoc; +public: + DefaultStmt(SourceLocation DL, SourceLocation CL, Stmt *substmt) : + SwitchCase(DefaultStmtClass), SubStmt(substmt), DefaultLoc(DL), + ColonLoc(CL) {} + + /// \brief Build an empty default statement. + explicit DefaultStmt(EmptyShell) : SwitchCase(DefaultStmtClass) { } + + Stmt *getSubStmt() { return SubStmt; } + const Stmt *getSubStmt() const { return SubStmt; } + void setSubStmt(Stmt *S) { SubStmt = S; } + + SourceLocation getDefaultLoc() const { return DefaultLoc; } + void setDefaultLoc(SourceLocation L) { DefaultLoc = L; } + SourceLocation getColonLoc() const { return ColonLoc; } + void setColonLoc(SourceLocation L) { ColonLoc = L; } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(DefaultLoc, SubStmt->getLocEnd()); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == DefaultStmtClass; + } + static bool classof(const DefaultStmt *) { return true; } + + // Iterators + child_range children() { return child_range(&SubStmt, &SubStmt+1); } +}; + + +/// LabelStmt - Represents a label, which has a substatement. For example: +/// foo: return; +/// +class LabelStmt : public Stmt { + LabelDecl *TheDecl; + Stmt *SubStmt; + SourceLocation IdentLoc; +public: + LabelStmt(SourceLocation IL, LabelDecl *D, Stmt *substmt) + : Stmt(LabelStmtClass), TheDecl(D), SubStmt(substmt), IdentLoc(IL) { + } + + // \brief Build an empty label statement. + explicit LabelStmt(EmptyShell Empty) : Stmt(LabelStmtClass, Empty) { } + + SourceLocation getIdentLoc() const { return IdentLoc; } + LabelDecl *getDecl() const { return TheDecl; } + void setDecl(LabelDecl *D) { TheDecl = D; } + const char *getName() const; + Stmt *getSubStmt() { return SubStmt; } + const Stmt *getSubStmt() const { return SubStmt; } + void setIdentLoc(SourceLocation L) { IdentLoc = L; } + void setSubStmt(Stmt *SS) { SubStmt = SS; } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(IdentLoc, SubStmt->getLocEnd()); + } + child_range children() { return child_range(&SubStmt, &SubStmt+1); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == LabelStmtClass; + } + static bool classof(const LabelStmt *) { return true; } +}; + + +/// \brief Represents an attribute applied to a statement. +/// +/// Represents an attribute applied to a statement. For example: +/// [[omp::for(...)]] for (...) { ... } +/// +class AttributedStmt : public Stmt { + Stmt *SubStmt; + SourceLocation AttrLoc; + AttrVec Attrs; + // TODO: It can be done as Attr *Attrs[1]; and variable size array as in + // StringLiteral + + friend class ASTStmtReader; + +public: + AttributedStmt(SourceLocation loc, const AttrVec &attrs, Stmt *substmt) + : Stmt(AttributedStmtClass), SubStmt(substmt), AttrLoc(loc), Attrs(attrs) { + } + + // \brief Build an empty attributed statement. + explicit AttributedStmt(EmptyShell Empty) + : Stmt(AttributedStmtClass, Empty) { + } + + SourceLocation getAttrLoc() const { return AttrLoc; } + const AttrVec &getAttrs() const { return Attrs; } + Stmt *getSubStmt() { return SubStmt; } + const Stmt *getSubStmt() const { return SubStmt; } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(AttrLoc, SubStmt->getLocEnd()); + } + child_range children() { return child_range(&SubStmt, &SubStmt + 1); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == AttributedStmtClass; + } + static bool classof(const AttributedStmt *) { return true; } +}; + + +/// IfStmt - This represents an if/then/else. +/// +class IfStmt : public Stmt { + enum { VAR, COND, THEN, ELSE, END_EXPR }; + Stmt* SubExprs[END_EXPR]; + + SourceLocation IfLoc; + SourceLocation ElseLoc; + +public: + IfStmt(ASTContext &C, SourceLocation IL, VarDecl *var, Expr *cond, + Stmt *then, SourceLocation EL = SourceLocation(), Stmt *elsev = 0); + + /// \brief Build an empty if/then/else statement + explicit IfStmt(EmptyShell Empty) : Stmt(IfStmtClass, Empty) { } + + /// \brief Retrieve the variable declared in this "if" statement, if any. + /// + /// In the following example, "x" is the condition variable. + /// \code + /// if (int x = foo()) { + /// printf("x is %d", x); + /// } + /// \endcode + VarDecl *getConditionVariable() const; + void setConditionVariable(ASTContext &C, VarDecl *V); + + /// If this IfStmt has a condition variable, return the faux DeclStmt + /// associated with the creation of that condition variable. + const DeclStmt *getConditionVariableDeclStmt() const { + return reinterpret_cast<DeclStmt*>(SubExprs[VAR]); + } + + const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);} + void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt *>(E); } + const Stmt *getThen() const { return SubExprs[THEN]; } + void setThen(Stmt *S) { SubExprs[THEN] = S; } + const Stmt *getElse() const { return SubExprs[ELSE]; } + void setElse(Stmt *S) { SubExprs[ELSE] = S; } + + Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]); } + Stmt *getThen() { return SubExprs[THEN]; } + Stmt *getElse() { return SubExprs[ELSE]; } + + SourceLocation getIfLoc() const { return IfLoc; } + void setIfLoc(SourceLocation L) { IfLoc = L; } + SourceLocation getElseLoc() const { return ElseLoc; } + void setElseLoc(SourceLocation L) { ElseLoc = L; } + + SourceRange getSourceRange() const LLVM_READONLY { + if (SubExprs[ELSE]) + return SourceRange(IfLoc, SubExprs[ELSE]->getLocEnd()); + else + return SourceRange(IfLoc, SubExprs[THEN]->getLocEnd()); + } + + // Iterators over subexpressions. The iterators will include iterating + // over the initialization expression referenced by the condition variable. + child_range children() { + return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == IfStmtClass; + } + static bool classof(const IfStmt *) { return true; } +}; + +/// SwitchStmt - This represents a 'switch' stmt. +/// +class SwitchStmt : public Stmt { + enum { VAR, COND, BODY, END_EXPR }; + Stmt* SubExprs[END_EXPR]; + // This points to a linked list of case and default statements. + SwitchCase *FirstCase; + SourceLocation SwitchLoc; + + /// If the SwitchStmt is a switch on an enum value, this records whether + /// all the enum values were covered by CaseStmts. This value is meant to + /// be a hint for possible clients. + unsigned AllEnumCasesCovered : 1; + +public: + SwitchStmt(ASTContext &C, VarDecl *Var, Expr *cond); + + /// \brief Build a empty switch statement. + explicit SwitchStmt(EmptyShell Empty) : Stmt(SwitchStmtClass, Empty) { } + + /// \brief Retrieve the variable declared in this "switch" statement, if any. + /// + /// In the following example, "x" is the condition variable. + /// \code + /// switch (int x = foo()) { + /// case 0: break; + /// // ... + /// } + /// \endcode + VarDecl *getConditionVariable() const; + void setConditionVariable(ASTContext &C, VarDecl *V); + + /// If this SwitchStmt has a condition variable, return the faux DeclStmt + /// associated with the creation of that condition variable. + const DeclStmt *getConditionVariableDeclStmt() const { + return reinterpret_cast<DeclStmt*>(SubExprs[VAR]); + } + + const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);} + const Stmt *getBody() const { return SubExprs[BODY]; } + const SwitchCase *getSwitchCaseList() const { return FirstCase; } + + Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]);} + void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt *>(E); } + Stmt *getBody() { return SubExprs[BODY]; } + void setBody(Stmt *S) { SubExprs[BODY] = S; } + SwitchCase *getSwitchCaseList() { return FirstCase; } + + /// \brief Set the case list for this switch statement. + /// + /// The caller is responsible for incrementing the retain counts on + /// all of the SwitchCase statements in this list. + void setSwitchCaseList(SwitchCase *SC) { FirstCase = SC; } + + SourceLocation getSwitchLoc() const { return SwitchLoc; } + void setSwitchLoc(SourceLocation L) { SwitchLoc = L; } + + void setBody(Stmt *S, SourceLocation SL) { + SubExprs[BODY] = S; + SwitchLoc = SL; + } + void addSwitchCase(SwitchCase *SC) { + assert(!SC->getNextSwitchCase() + && "case/default already added to a switch"); + SC->setNextSwitchCase(FirstCase); + FirstCase = SC; + } + + /// Set a flag in the SwitchStmt indicating that if the 'switch (X)' is a + /// switch over an enum value then all cases have been explicitly covered. + void setAllEnumCasesCovered() { + AllEnumCasesCovered = 1; + } + + /// Returns true if the SwitchStmt is a switch of an enum value and all cases + /// have been explicitly covered. + bool isAllEnumCasesCovered() const { + return (bool) AllEnumCasesCovered; + } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(SwitchLoc, SubExprs[BODY]->getLocEnd()); + } + // Iterators + child_range children() { + return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == SwitchStmtClass; + } + static bool classof(const SwitchStmt *) { return true; } +}; + + +/// WhileStmt - This represents a 'while' stmt. +/// +class WhileStmt : public Stmt { + enum { VAR, COND, BODY, END_EXPR }; + Stmt* SubExprs[END_EXPR]; + SourceLocation WhileLoc; +public: + WhileStmt(ASTContext &C, VarDecl *Var, Expr *cond, Stmt *body, + SourceLocation WL); + + /// \brief Build an empty while statement. + explicit WhileStmt(EmptyShell Empty) : Stmt(WhileStmtClass, Empty) { } + + /// \brief Retrieve the variable declared in this "while" statement, if any. + /// + /// In the following example, "x" is the condition variable. + /// \code + /// while (int x = random()) { + /// // ... + /// } + /// \endcode + VarDecl *getConditionVariable() const; + void setConditionVariable(ASTContext &C, VarDecl *V); + + /// If this WhileStmt has a condition variable, return the faux DeclStmt + /// associated with the creation of that condition variable. + const DeclStmt *getConditionVariableDeclStmt() const { + return reinterpret_cast<DeclStmt*>(SubExprs[VAR]); + } + + Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]); } + const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);} + void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt*>(E); } + Stmt *getBody() { return SubExprs[BODY]; } + const Stmt *getBody() const { return SubExprs[BODY]; } + void setBody(Stmt *S) { SubExprs[BODY] = S; } + + SourceLocation getWhileLoc() const { return WhileLoc; } + void setWhileLoc(SourceLocation L) { WhileLoc = L; } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(WhileLoc, SubExprs[BODY]->getLocEnd()); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == WhileStmtClass; + } + static bool classof(const WhileStmt *) { return true; } + + // Iterators + child_range children() { + return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR); + } +}; + +/// DoStmt - This represents a 'do/while' stmt. +/// +class DoStmt : public Stmt { + enum { BODY, COND, END_EXPR }; + Stmt* SubExprs[END_EXPR]; + SourceLocation DoLoc; + SourceLocation WhileLoc; + SourceLocation RParenLoc; // Location of final ')' in do stmt condition. + +public: + DoStmt(Stmt *body, Expr *cond, SourceLocation DL, SourceLocation WL, + SourceLocation RP) + : Stmt(DoStmtClass), DoLoc(DL), WhileLoc(WL), RParenLoc(RP) { + SubExprs[COND] = reinterpret_cast<Stmt*>(cond); + SubExprs[BODY] = body; + } + + /// \brief Build an empty do-while statement. + explicit DoStmt(EmptyShell Empty) : Stmt(DoStmtClass, Empty) { } + + Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]); } + const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);} + void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt*>(E); } + Stmt *getBody() { return SubExprs[BODY]; } + const Stmt *getBody() const { return SubExprs[BODY]; } + void setBody(Stmt *S) { SubExprs[BODY] = S; } + + SourceLocation getDoLoc() const { return DoLoc; } + void setDoLoc(SourceLocation L) { DoLoc = L; } + SourceLocation getWhileLoc() const { return WhileLoc; } + void setWhileLoc(SourceLocation L) { WhileLoc = L; } + + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(DoLoc, RParenLoc); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == DoStmtClass; + } + static bool classof(const DoStmt *) { return true; } + + // Iterators + child_range children() { + return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR); + } +}; + + +/// ForStmt - This represents a 'for (init;cond;inc)' stmt. Note that any of +/// the init/cond/inc parts of the ForStmt will be null if they were not +/// specified in the source. +/// +class ForStmt : public Stmt { + enum { INIT, CONDVAR, COND, INC, BODY, END_EXPR }; + Stmt* SubExprs[END_EXPR]; // SubExprs[INIT] is an expression or declstmt. + SourceLocation ForLoc; + SourceLocation LParenLoc, RParenLoc; + +public: + ForStmt(ASTContext &C, Stmt *Init, Expr *Cond, VarDecl *condVar, Expr *Inc, + Stmt *Body, SourceLocation FL, SourceLocation LP, SourceLocation RP); + + /// \brief Build an empty for statement. + explicit ForStmt(EmptyShell Empty) : Stmt(ForStmtClass, Empty) { } + + Stmt *getInit() { return SubExprs[INIT]; } + + /// \brief Retrieve the variable declared in this "for" statement, if any. + /// + /// In the following example, "y" is the condition variable. + /// \code + /// for (int x = random(); int y = mangle(x); ++x) { + /// // ... + /// } + /// \endcode + VarDecl *getConditionVariable() const; + void setConditionVariable(ASTContext &C, VarDecl *V); + + /// If this ForStmt has a condition variable, return the faux DeclStmt + /// associated with the creation of that condition variable. + const DeclStmt *getConditionVariableDeclStmt() const { + return reinterpret_cast<DeclStmt*>(SubExprs[CONDVAR]); + } + + Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]); } + Expr *getInc() { return reinterpret_cast<Expr*>(SubExprs[INC]); } + Stmt *getBody() { return SubExprs[BODY]; } + + const Stmt *getInit() const { return SubExprs[INIT]; } + const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);} + const Expr *getInc() const { return reinterpret_cast<Expr*>(SubExprs[INC]); } + const Stmt *getBody() const { return SubExprs[BODY]; } + + void setInit(Stmt *S) { SubExprs[INIT] = S; } + void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt*>(E); } + void setInc(Expr *E) { SubExprs[INC] = reinterpret_cast<Stmt*>(E); } + void setBody(Stmt *S) { SubExprs[BODY] = S; } + + SourceLocation getForLoc() const { return ForLoc; } + void setForLoc(SourceLocation L) { ForLoc = L; } + SourceLocation getLParenLoc() const { return LParenLoc; } + void setLParenLoc(SourceLocation L) { LParenLoc = L; } + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(ForLoc, SubExprs[BODY]->getLocEnd()); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == ForStmtClass; + } + static bool classof(const ForStmt *) { return true; } + + // Iterators + child_range children() { + return child_range(&SubExprs[0], &SubExprs[0]+END_EXPR); + } +}; + +/// GotoStmt - This represents a direct goto. +/// +class GotoStmt : public Stmt { + LabelDecl *Label; + SourceLocation GotoLoc; + SourceLocation LabelLoc; +public: + GotoStmt(LabelDecl *label, SourceLocation GL, SourceLocation LL) + : Stmt(GotoStmtClass), Label(label), GotoLoc(GL), LabelLoc(LL) {} + + /// \brief Build an empty goto statement. + explicit GotoStmt(EmptyShell Empty) : Stmt(GotoStmtClass, Empty) { } + + LabelDecl *getLabel() const { return Label; } + void setLabel(LabelDecl *D) { Label = D; } + + SourceLocation getGotoLoc() const { return GotoLoc; } + void setGotoLoc(SourceLocation L) { GotoLoc = L; } + SourceLocation getLabelLoc() const { return LabelLoc; } + void setLabelLoc(SourceLocation L) { LabelLoc = L; } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(GotoLoc, LabelLoc); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == GotoStmtClass; + } + static bool classof(const GotoStmt *) { return true; } + + // Iterators + child_range children() { return child_range(); } +}; + +/// IndirectGotoStmt - This represents an indirect goto. +/// +class IndirectGotoStmt : public Stmt { + SourceLocation GotoLoc; + SourceLocation StarLoc; + Stmt *Target; +public: + IndirectGotoStmt(SourceLocation gotoLoc, SourceLocation starLoc, + Expr *target) + : Stmt(IndirectGotoStmtClass), GotoLoc(gotoLoc), StarLoc(starLoc), + Target((Stmt*)target) {} + + /// \brief Build an empty indirect goto statement. + explicit IndirectGotoStmt(EmptyShell Empty) + : Stmt(IndirectGotoStmtClass, Empty) { } + + void setGotoLoc(SourceLocation L) { GotoLoc = L; } + SourceLocation getGotoLoc() const { return GotoLoc; } + void setStarLoc(SourceLocation L) { StarLoc = L; } + SourceLocation getStarLoc() const { return StarLoc; } + + Expr *getTarget() { return reinterpret_cast<Expr*>(Target); } + const Expr *getTarget() const {return reinterpret_cast<const Expr*>(Target);} + void setTarget(Expr *E) { Target = reinterpret_cast<Stmt*>(E); } + + /// getConstantTarget - Returns the fixed target of this indirect + /// goto, if one exists. + LabelDecl *getConstantTarget(); + const LabelDecl *getConstantTarget() const { + return const_cast<IndirectGotoStmt*>(this)->getConstantTarget(); + } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(GotoLoc, Target->getLocEnd()); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == IndirectGotoStmtClass; + } + static bool classof(const IndirectGotoStmt *) { return true; } + + // Iterators + child_range children() { return child_range(&Target, &Target+1); } +}; + + +/// ContinueStmt - This represents a continue. +/// +class ContinueStmt : public Stmt { + SourceLocation ContinueLoc; +public: + ContinueStmt(SourceLocation CL) : Stmt(ContinueStmtClass), ContinueLoc(CL) {} + + /// \brief Build an empty continue statement. + explicit ContinueStmt(EmptyShell Empty) : Stmt(ContinueStmtClass, Empty) { } + + SourceLocation getContinueLoc() const { return ContinueLoc; } + void setContinueLoc(SourceLocation L) { ContinueLoc = L; } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(ContinueLoc); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ContinueStmtClass; + } + static bool classof(const ContinueStmt *) { return true; } + + // Iterators + child_range children() { return child_range(); } +}; + +/// BreakStmt - This represents a break. +/// +class BreakStmt : public Stmt { + SourceLocation BreakLoc; +public: + BreakStmt(SourceLocation BL) : Stmt(BreakStmtClass), BreakLoc(BL) {} + + /// \brief Build an empty break statement. + explicit BreakStmt(EmptyShell Empty) : Stmt(BreakStmtClass, Empty) { } + + SourceLocation getBreakLoc() const { return BreakLoc; } + void setBreakLoc(SourceLocation L) { BreakLoc = L; } + + SourceRange getSourceRange() const LLVM_READONLY { return SourceRange(BreakLoc); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == BreakStmtClass; + } + static bool classof(const BreakStmt *) { return true; } + + // Iterators + child_range children() { return child_range(); } +}; + + +/// ReturnStmt - This represents a return, optionally of an expression: +/// return; +/// return 4; +/// +/// Note that GCC allows return with no argument in a function declared to +/// return a value, and it allows returning a value in functions declared to +/// return void. We explicitly model this in the AST, which means you can't +/// depend on the return type of the function and the presence of an argument. +/// +class ReturnStmt : public Stmt { + Stmt *RetExpr; + SourceLocation RetLoc; + const VarDecl *NRVOCandidate; + +public: + ReturnStmt(SourceLocation RL) + : Stmt(ReturnStmtClass), RetExpr(0), RetLoc(RL), NRVOCandidate(0) { } + + ReturnStmt(SourceLocation RL, Expr *E, const VarDecl *NRVOCandidate) + : Stmt(ReturnStmtClass), RetExpr((Stmt*) E), RetLoc(RL), + NRVOCandidate(NRVOCandidate) {} + + /// \brief Build an empty return expression. + explicit ReturnStmt(EmptyShell Empty) : Stmt(ReturnStmtClass, Empty) { } + + const Expr *getRetValue() const; + Expr *getRetValue(); + void setRetValue(Expr *E) { RetExpr = reinterpret_cast<Stmt*>(E); } + + SourceLocation getReturnLoc() const { return RetLoc; } + void setReturnLoc(SourceLocation L) { RetLoc = L; } + + /// \brief Retrieve the variable that might be used for the named return + /// value optimization. + /// + /// The optimization itself can only be performed if the variable is + /// also marked as an NRVO object. + const VarDecl *getNRVOCandidate() const { return NRVOCandidate; } + void setNRVOCandidate(const VarDecl *Var) { NRVOCandidate = Var; } + + SourceRange getSourceRange() const LLVM_READONLY; + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ReturnStmtClass; + } + static bool classof(const ReturnStmt *) { return true; } + + // Iterators + child_range children() { + if (RetExpr) return child_range(&RetExpr, &RetExpr+1); + return child_range(); + } +}; + +/// AsmStmt - This represents a GNU inline-assembly statement extension. +/// +class AsmStmt : public Stmt { + SourceLocation AsmLoc, RParenLoc; + StringLiteral *AsmStr; + + bool IsSimple; + bool IsVolatile; + bool MSAsm; + + unsigned NumOutputs; + unsigned NumInputs; + unsigned NumClobbers; + + // FIXME: If we wanted to, we could allocate all of these in one big array. + IdentifierInfo **Names; + StringLiteral **Constraints; + Stmt **Exprs; + StringLiteral **Clobbers; + +public: + AsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple, bool isvolatile, + bool msasm, unsigned numoutputs, unsigned numinputs, + IdentifierInfo **names, StringLiteral **constraints, + Expr **exprs, StringLiteral *asmstr, unsigned numclobbers, + StringLiteral **clobbers, SourceLocation rparenloc); + + /// \brief Build an empty inline-assembly statement. + explicit AsmStmt(EmptyShell Empty) : Stmt(AsmStmtClass, Empty), + Names(0), Constraints(0), Exprs(0), Clobbers(0) { } + + SourceLocation getAsmLoc() const { return AsmLoc; } + void setAsmLoc(SourceLocation L) { AsmLoc = L; } + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } + + bool isVolatile() const { return IsVolatile; } + void setVolatile(bool V) { IsVolatile = V; } + bool isSimple() const { return IsSimple; } + void setSimple(bool V) { IsSimple = V; } + bool isMSAsm() const { return MSAsm; } + void setMSAsm(bool V) { MSAsm = V; } + + //===--- Asm String Analysis ---===// + + const StringLiteral *getAsmString() const { return AsmStr; } + StringLiteral *getAsmString() { return AsmStr; } + void setAsmString(StringLiteral *E) { AsmStr = E; } + + /// AsmStringPiece - this is part of a decomposed asm string specification + /// (for use with the AnalyzeAsmString function below). An asm string is + /// considered to be a concatenation of these parts. + class AsmStringPiece { + public: + enum Kind { + String, // String in .ll asm string form, "$" -> "$$" and "%%" -> "%". + Operand // Operand reference, with optional modifier %c4. + }; + private: + Kind MyKind; + std::string Str; + unsigned OperandNo; + public: + AsmStringPiece(const std::string &S) : MyKind(String), Str(S) {} + AsmStringPiece(unsigned OpNo, char Modifier) + : MyKind(Operand), Str(), OperandNo(OpNo) { + Str += Modifier; + } + + bool isString() const { return MyKind == String; } + bool isOperand() const { return MyKind == Operand; } + + const std::string &getString() const { + assert(isString()); + return Str; + } + + unsigned getOperandNo() const { + assert(isOperand()); + return OperandNo; + } + + /// getModifier - Get the modifier for this operand, if present. This + /// returns '\0' if there was no modifier. + char getModifier() const { + assert(isOperand()); + return Str[0]; + } + }; + + /// AnalyzeAsmString - Analyze the asm string of the current asm, decomposing + /// it into pieces. If the asm string is erroneous, emit errors and return + /// true, otherwise return false. This handles canonicalization and + /// translation of strings from GCC syntax to LLVM IR syntax, and handles + //// flattening of named references like %[foo] to Operand AsmStringPiece's. + unsigned AnalyzeAsmString(SmallVectorImpl<AsmStringPiece> &Pieces, + ASTContext &C, unsigned &DiagOffs) const; + + + //===--- Output operands ---===// + + unsigned getNumOutputs() const { return NumOutputs; } + + IdentifierInfo *getOutputIdentifier(unsigned i) const { + return Names[i]; + } + + StringRef getOutputName(unsigned i) const { + if (IdentifierInfo *II = getOutputIdentifier(i)) + return II->getName(); + + return StringRef(); + } + + /// getOutputConstraint - Return the constraint string for the specified + /// output operand. All output constraints are known to be non-empty (either + /// '=' or '+'). + StringRef getOutputConstraint(unsigned i) const; + + const StringLiteral *getOutputConstraintLiteral(unsigned i) const { + return Constraints[i]; + } + StringLiteral *getOutputConstraintLiteral(unsigned i) { + return Constraints[i]; + } + + Expr *getOutputExpr(unsigned i); + + const Expr *getOutputExpr(unsigned i) const { + return const_cast<AsmStmt*>(this)->getOutputExpr(i); + } + + /// isOutputPlusConstraint - Return true if the specified output constraint + /// is a "+" constraint (which is both an input and an output) or false if it + /// is an "=" constraint (just an output). + bool isOutputPlusConstraint(unsigned i) const { + return getOutputConstraint(i)[0] == '+'; + } + + /// getNumPlusOperands - Return the number of output operands that have a "+" + /// constraint. + unsigned getNumPlusOperands() const; + + //===--- Input operands ---===// + + unsigned getNumInputs() const { return NumInputs; } + + IdentifierInfo *getInputIdentifier(unsigned i) const { + return Names[i + NumOutputs]; + } + + StringRef getInputName(unsigned i) const { + if (IdentifierInfo *II = getInputIdentifier(i)) + return II->getName(); + + return StringRef(); + } + + /// getInputConstraint - Return the specified input constraint. Unlike output + /// constraints, these can be empty. + StringRef getInputConstraint(unsigned i) const; + + const StringLiteral *getInputConstraintLiteral(unsigned i) const { + return Constraints[i + NumOutputs]; + } + StringLiteral *getInputConstraintLiteral(unsigned i) { + return Constraints[i + NumOutputs]; + } + + Expr *getInputExpr(unsigned i); + void setInputExpr(unsigned i, Expr *E); + + const Expr *getInputExpr(unsigned i) const { + return const_cast<AsmStmt*>(this)->getInputExpr(i); + } + + void setOutputsAndInputsAndClobbers(ASTContext &C, + IdentifierInfo **Names, + StringLiteral **Constraints, + Stmt **Exprs, + unsigned NumOutputs, + unsigned NumInputs, + StringLiteral **Clobbers, + unsigned NumClobbers); + + //===--- Other ---===// + + /// getNamedOperand - Given a symbolic operand reference like %[foo], + /// translate this into a numeric value needed to reference the same operand. + /// This returns -1 if the operand name is invalid. + int getNamedOperand(StringRef SymbolicName) const; + + unsigned getNumClobbers() const { return NumClobbers; } + StringLiteral *getClobber(unsigned i) { return Clobbers[i]; } + const StringLiteral *getClobber(unsigned i) const { return Clobbers[i]; } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(AsmLoc, RParenLoc); + } + + static bool classof(const Stmt *T) {return T->getStmtClass() == AsmStmtClass;} + static bool classof(const AsmStmt *) { return true; } + + // Input expr iterators. + + typedef ExprIterator inputs_iterator; + typedef ConstExprIterator const_inputs_iterator; + + inputs_iterator begin_inputs() { + return &Exprs[0] + NumOutputs; + } + + inputs_iterator end_inputs() { + return &Exprs[0] + NumOutputs + NumInputs; + } + + const_inputs_iterator begin_inputs() const { + return &Exprs[0] + NumOutputs; + } + + const_inputs_iterator end_inputs() const { + return &Exprs[0] + NumOutputs + NumInputs; + } + + // Output expr iterators. + + typedef ExprIterator outputs_iterator; + typedef ConstExprIterator const_outputs_iterator; + + outputs_iterator begin_outputs() { + return &Exprs[0]; + } + outputs_iterator end_outputs() { + return &Exprs[0] + NumOutputs; + } + + const_outputs_iterator begin_outputs() const { + return &Exprs[0]; + } + const_outputs_iterator end_outputs() const { + return &Exprs[0] + NumOutputs; + } + + child_range children() { + return child_range(&Exprs[0], &Exprs[0] + NumOutputs + NumInputs); + } +}; + +class SEHExceptStmt : public Stmt { + SourceLocation Loc; + Stmt *Children[2]; + + enum { FILTER_EXPR, BLOCK }; + + SEHExceptStmt(SourceLocation Loc, + Expr *FilterExpr, + Stmt *Block); + + friend class ASTReader; + friend class ASTStmtReader; + explicit SEHExceptStmt(EmptyShell E) : Stmt(SEHExceptStmtClass, E) { } + +public: + static SEHExceptStmt* Create(ASTContext &C, + SourceLocation ExceptLoc, + Expr *FilterExpr, + Stmt *Block); + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(getExceptLoc(), getEndLoc()); + } + + SourceLocation getExceptLoc() const { return Loc; } + SourceLocation getEndLoc() const { return getBlock()->getLocEnd(); } + + Expr *getFilterExpr() const { + return reinterpret_cast<Expr*>(Children[FILTER_EXPR]); + } + + CompoundStmt *getBlock() const { + return llvm::cast<CompoundStmt>(Children[BLOCK]); + } + + child_range children() { + return child_range(Children,Children+2); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == SEHExceptStmtClass; + } + + static bool classof(SEHExceptStmt *) { return true; } + +}; + +class SEHFinallyStmt : public Stmt { + SourceLocation Loc; + Stmt *Block; + + SEHFinallyStmt(SourceLocation Loc, + Stmt *Block); + + friend class ASTReader; + friend class ASTStmtReader; + explicit SEHFinallyStmt(EmptyShell E) : Stmt(SEHFinallyStmtClass, E) { } + +public: + static SEHFinallyStmt* Create(ASTContext &C, + SourceLocation FinallyLoc, + Stmt *Block); + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(getFinallyLoc(), getEndLoc()); + } + + SourceLocation getFinallyLoc() const { return Loc; } + SourceLocation getEndLoc() const { return Block->getLocEnd(); } + + CompoundStmt *getBlock() const { return llvm::cast<CompoundStmt>(Block); } + + child_range children() { + return child_range(&Block,&Block+1); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == SEHFinallyStmtClass; + } + + static bool classof(SEHFinallyStmt *) { return true; } + +}; + +class SEHTryStmt : public Stmt { + bool IsCXXTry; + SourceLocation TryLoc; + Stmt *Children[2]; + + enum { TRY = 0, HANDLER = 1 }; + + SEHTryStmt(bool isCXXTry, // true if 'try' otherwise '__try' + SourceLocation TryLoc, + Stmt *TryBlock, + Stmt *Handler); + + friend class ASTReader; + friend class ASTStmtReader; + explicit SEHTryStmt(EmptyShell E) : Stmt(SEHTryStmtClass, E) { } + +public: + static SEHTryStmt* Create(ASTContext &C, + bool isCXXTry, + SourceLocation TryLoc, + Stmt *TryBlock, + Stmt *Handler); + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(getTryLoc(), getEndLoc()); + } + + SourceLocation getTryLoc() const { return TryLoc; } + SourceLocation getEndLoc() const { return Children[HANDLER]->getLocEnd(); } + + bool getIsCXXTry() const { return IsCXXTry; } + + CompoundStmt* getTryBlock() const { + return llvm::cast<CompoundStmt>(Children[TRY]); + } + + Stmt *getHandler() const { return Children[HANDLER]; } + + /// Returns 0 if not defined + SEHExceptStmt *getExceptHandler() const; + SEHFinallyStmt *getFinallyHandler() const; + + child_range children() { + return child_range(Children,Children+2); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == SEHTryStmtClass; + } + + static bool classof(SEHTryStmt *) { return true; } +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/AST/StmtCXX.h b/clang/include/clang/AST/StmtCXX.h new file mode 100644 index 0000000..a948722 --- /dev/null +++ b/clang/include/clang/AST/StmtCXX.h @@ -0,0 +1,295 @@ +//===--- StmtCXX.h - Classes for representing C++ statements ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the C++ statement AST node classes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_STMTCXX_H +#define LLVM_CLANG_AST_STMTCXX_H + +#include "clang/AST/Stmt.h" +#include "llvm/Support/Compiler.h" + +namespace clang { + +class VarDecl; + +/// CXXCatchStmt - This represents a C++ catch block. +/// +class CXXCatchStmt : public Stmt { + SourceLocation CatchLoc; + /// The exception-declaration of the type. + VarDecl *ExceptionDecl; + /// The handler block. + Stmt *HandlerBlock; + +public: + CXXCatchStmt(SourceLocation catchLoc, VarDecl *exDecl, Stmt *handlerBlock) + : Stmt(CXXCatchStmtClass), CatchLoc(catchLoc), ExceptionDecl(exDecl), + HandlerBlock(handlerBlock) {} + + CXXCatchStmt(EmptyShell Empty) + : Stmt(CXXCatchStmtClass), ExceptionDecl(0), HandlerBlock(0) {} + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(CatchLoc, HandlerBlock->getLocEnd()); + } + + SourceLocation getCatchLoc() const { return CatchLoc; } + VarDecl *getExceptionDecl() const { return ExceptionDecl; } + QualType getCaughtType() const; + Stmt *getHandlerBlock() const { return HandlerBlock; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXCatchStmtClass; + } + static bool classof(const CXXCatchStmt *) { return true; } + + child_range children() { return child_range(&HandlerBlock, &HandlerBlock+1); } + + friend class ASTStmtReader; +}; + +/// CXXTryStmt - A C++ try block, including all handlers. +/// +class CXXTryStmt : public Stmt { + SourceLocation TryLoc; + unsigned NumHandlers; + + CXXTryStmt(SourceLocation tryLoc, Stmt *tryBlock, Stmt **handlers, + unsigned numHandlers); + + CXXTryStmt(EmptyShell Empty, unsigned numHandlers) + : Stmt(CXXTryStmtClass), NumHandlers(numHandlers) { } + + Stmt const * const *getStmts() const { + return reinterpret_cast<Stmt const * const*>(this + 1); + } + Stmt **getStmts() { + return reinterpret_cast<Stmt **>(this + 1); + } + +public: + static CXXTryStmt *Create(ASTContext &C, SourceLocation tryLoc, + Stmt *tryBlock, Stmt **handlers, + unsigned numHandlers); + + static CXXTryStmt *Create(ASTContext &C, EmptyShell Empty, + unsigned numHandlers); + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(getTryLoc(), getEndLoc()); + } + + SourceLocation getTryLoc() const { return TryLoc; } + SourceLocation getEndLoc() const { + return getStmts()[NumHandlers]->getLocEnd(); + } + + CompoundStmt *getTryBlock() { + return llvm::cast<CompoundStmt>(getStmts()[0]); + } + const CompoundStmt *getTryBlock() const { + return llvm::cast<CompoundStmt>(getStmts()[0]); + } + + unsigned getNumHandlers() const { return NumHandlers; } + CXXCatchStmt *getHandler(unsigned i) { + return llvm::cast<CXXCatchStmt>(getStmts()[i + 1]); + } + const CXXCatchStmt *getHandler(unsigned i) const { + return llvm::cast<CXXCatchStmt>(getStmts()[i + 1]); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXTryStmtClass; + } + static bool classof(const CXXTryStmt *) { return true; } + + child_range children() { + return child_range(getStmts(), getStmts() + getNumHandlers() + 1); + } + + friend class ASTStmtReader; +}; + +/// CXXForRangeStmt - This represents C++0x [stmt.ranged]'s ranged for +/// statement, represented as 'for (range-declarator : range-expression)'. +/// +/// This is stored in a partially-desugared form to allow full semantic +/// analysis of the constituent components. The original syntactic components +/// can be extracted using getLoopVariable and getRangeInit. +class CXXForRangeStmt : public Stmt { + enum { RANGE, BEGINEND, COND, INC, LOOPVAR, BODY, END }; + // SubExprs[RANGE] is an expression or declstmt. + // SubExprs[COND] and SubExprs[INC] are expressions. + Stmt *SubExprs[END]; + SourceLocation ForLoc; + SourceLocation ColonLoc; + SourceLocation RParenLoc; +public: + CXXForRangeStmt(DeclStmt *Range, DeclStmt *BeginEnd, + Expr *Cond, Expr *Inc, DeclStmt *LoopVar, Stmt *Body, + SourceLocation FL, SourceLocation CL, SourceLocation RPL); + CXXForRangeStmt(EmptyShell Empty) : Stmt(CXXForRangeStmtClass, Empty) { } + + + VarDecl *getLoopVariable(); + Expr *getRangeInit(); + + const VarDecl *getLoopVariable() const; + const Expr *getRangeInit() const; + + + DeclStmt *getRangeStmt() { return cast<DeclStmt>(SubExprs[RANGE]); } + DeclStmt *getBeginEndStmt() { + return cast_or_null<DeclStmt>(SubExprs[BEGINEND]); + } + Expr *getCond() { return cast_or_null<Expr>(SubExprs[COND]); } + Expr *getInc() { return cast_or_null<Expr>(SubExprs[INC]); } + DeclStmt *getLoopVarStmt() { return cast<DeclStmt>(SubExprs[LOOPVAR]); } + Stmt *getBody() { return SubExprs[BODY]; } + + const DeclStmt *getRangeStmt() const { + return cast<DeclStmt>(SubExprs[RANGE]); + } + const DeclStmt *getBeginEndStmt() const { + return cast_or_null<DeclStmt>(SubExprs[BEGINEND]); + } + const Expr *getCond() const { + return cast_or_null<Expr>(SubExprs[COND]); + } + const Expr *getInc() const { + return cast_or_null<Expr>(SubExprs[INC]); + } + const DeclStmt *getLoopVarStmt() const { + return cast<DeclStmt>(SubExprs[LOOPVAR]); + } + const Stmt *getBody() const { return SubExprs[BODY]; } + + void setRangeInit(Expr *E) { SubExprs[RANGE] = reinterpret_cast<Stmt*>(E); } + void setRangeStmt(Stmt *S) { SubExprs[RANGE] = S; } + void setBeginEndStmt(Stmt *S) { SubExprs[BEGINEND] = S; } + void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt*>(E); } + void setInc(Expr *E) { SubExprs[INC] = reinterpret_cast<Stmt*>(E); } + void setLoopVarStmt(Stmt *S) { SubExprs[LOOPVAR] = S; } + void setBody(Stmt *S) { SubExprs[BODY] = S; } + + + SourceLocation getForLoc() const { return ForLoc; } + void setForLoc(SourceLocation Loc) { ForLoc = Loc; } + SourceLocation getColonLoc() const { return ColonLoc; } + void setColonLoc(SourceLocation Loc) { ColonLoc = Loc; } + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation Loc) { RParenLoc = Loc; } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(ForLoc, SubExprs[BODY]->getLocEnd()); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXForRangeStmtClass; + } + static bool classof(const CXXForRangeStmt *) { return true; } + + // Iterators + child_range children() { + return child_range(&SubExprs[0], &SubExprs[END]); + } +}; + +/// \brief Representation of a Microsoft __if_exists or __if_not_exists +/// statement with a dependent name. +/// +/// The __if_exists statement can be used to include a sequence of statements +/// in the program only when a particular dependent name does not exist. For +/// example: +/// +/// \code +/// template<typename T> +/// void call_foo(T &t) { +/// __if_exists (T::foo) { +/// t.foo(); // okay: only called when T::foo exists. +/// } +/// } +/// \endcode +/// +/// Similarly, the __if_not_exists statement can be used to include the +/// statements when a particular name does not exist. +/// +/// Note that this statement only captures __if_exists and __if_not_exists +/// statements whose name is dependent. All non-dependent cases are handled +/// directly in the parser, so that they don't introduce a new scope. Clang +/// introduces scopes in the dependent case to keep names inside the compound +/// statement from leaking out into the surround statements, which would +/// compromise the template instantiation model. This behavior differs from +/// Visual C++ (which never introduces a scope), but is a fairly reasonable +/// approximation of the VC++ behavior. +class MSDependentExistsStmt : public Stmt { + SourceLocation KeywordLoc; + bool IsIfExists; + NestedNameSpecifierLoc QualifierLoc; + DeclarationNameInfo NameInfo; + Stmt *SubStmt; + + friend class ASTReader; + friend class ASTStmtReader; + +public: + MSDependentExistsStmt(SourceLocation KeywordLoc, bool IsIfExists, + NestedNameSpecifierLoc QualifierLoc, + DeclarationNameInfo NameInfo, + CompoundStmt *SubStmt) + : Stmt(MSDependentExistsStmtClass), + KeywordLoc(KeywordLoc), IsIfExists(IsIfExists), + QualifierLoc(QualifierLoc), NameInfo(NameInfo), + SubStmt(reinterpret_cast<Stmt *>(SubStmt)) { } + + /// \brief Retrieve the location of the __if_exists or __if_not_exists + /// keyword. + SourceLocation getKeywordLoc() const { return KeywordLoc; } + + /// \brief Determine whether this is an __if_exists statement. + bool isIfExists() const { return IsIfExists; } + + /// \brief Determine whether this is an __if_exists statement. + bool isIfNotExists() const { return !IsIfExists; } + + /// \brief Retrieve the nested-name-specifier that qualifies this name, if + /// any. + NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; } + + /// \brief Retrieve the name of the entity we're testing for, along with + /// location information + DeclarationNameInfo getNameInfo() const { return NameInfo; } + + /// \brief Retrieve the compound statement that will be included in the + /// program only if the existence of the symbol matches the initial keyword. + CompoundStmt *getSubStmt() const { + return reinterpret_cast<CompoundStmt *>(SubStmt); + } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(KeywordLoc, SubStmt->getLocEnd()); + } + + child_range children() { + return child_range(&SubStmt, &SubStmt+1); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == MSDependentExistsStmtClass; + } + + static bool classof(MSDependentExistsStmt *) { return true; } +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/AST/StmtGraphTraits.h b/clang/include/clang/AST/StmtGraphTraits.h new file mode 100644 index 0000000..25d0152 --- /dev/null +++ b/clang/include/clang/AST/StmtGraphTraits.h @@ -0,0 +1,83 @@ +//===--- StmtGraphTraits.h - Graph Traits for the class Stmt ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines a template specialization of llvm::GraphTraits to +// treat ASTs (Stmt*) as graphs +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_STMT_GRAPHTRAITS_H +#define LLVM_CLANG_AST_STMT_GRAPHTRAITS_H + +#include "clang/AST/Stmt.h" +#include "llvm/ADT/GraphTraits.h" +#include "llvm/ADT/DepthFirstIterator.h" + +namespace llvm { + +//template <typename T> struct GraphTraits; + + +template <> struct GraphTraits<clang::Stmt*> { + typedef clang::Stmt NodeType; + typedef clang::Stmt::child_iterator ChildIteratorType; + typedef llvm::df_iterator<clang::Stmt*> nodes_iterator; + + static NodeType* getEntryNode(clang::Stmt* S) { return S; } + + static inline ChildIteratorType child_begin(NodeType* N) { + if (N) return N->child_begin(); + else return ChildIteratorType(); + } + + static inline ChildIteratorType child_end(NodeType* N) { + if (N) return N->child_end(); + else return ChildIteratorType(); + } + + static nodes_iterator nodes_begin(clang::Stmt* S) { + return df_begin(S); + } + + static nodes_iterator nodes_end(clang::Stmt* S) { + return df_end(S); + } +}; + + +template <> struct GraphTraits<const clang::Stmt*> { + typedef const clang::Stmt NodeType; + typedef clang::Stmt::const_child_iterator ChildIteratorType; + typedef llvm::df_iterator<const clang::Stmt*> nodes_iterator; + + static NodeType* getEntryNode(const clang::Stmt* S) { return S; } + + static inline ChildIteratorType child_begin(NodeType* N) { + if (N) return N->child_begin(); + else return ChildIteratorType(); + } + + static inline ChildIteratorType child_end(NodeType* N) { + if (N) return N->child_end(); + else return ChildIteratorType(); + } + + static nodes_iterator nodes_begin(const clang::Stmt* S) { + return df_begin(S); + } + + static nodes_iterator nodes_end(const clang::Stmt* S) { + return df_end(S); + } +}; + + +} // end namespace llvm + +#endif diff --git a/clang/include/clang/AST/StmtIterator.h b/clang/include/clang/AST/StmtIterator.h new file mode 100644 index 0000000..b933ed0 --- /dev/null +++ b/clang/include/clang/AST/StmtIterator.h @@ -0,0 +1,230 @@ +//===--- StmtIterator.h - Iterators for Statements --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the StmtIterator and ConstStmtIterator classes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_STMT_ITR_H +#define LLVM_CLANG_AST_STMT_ITR_H + +#include "llvm/Support/DataTypes.h" +#include <cassert> +#include <cstddef> +#include <iterator> +#include <utility> + +namespace clang { + +class Stmt; +class Decl; +class VariableArrayType; + +class StmtIteratorBase { +protected: + enum { DeclMode = 0x1, SizeOfTypeVAMode = 0x2, DeclGroupMode = 0x3, + Flags = 0x3 }; + + Stmt **stmt; + union { Decl *decl; Decl **DGI; }; + uintptr_t RawVAPtr; + Decl **DGE; + + bool inDecl() const { + return (RawVAPtr & Flags) == DeclMode; + } + + bool inDeclGroup() const { + return (RawVAPtr & Flags) == DeclGroupMode; + } + + bool inSizeOfTypeVA() const { + return (RawVAPtr & Flags) == SizeOfTypeVAMode; + } + + bool inStmt() const { + return (RawVAPtr & Flags) == 0; + } + + const VariableArrayType *getVAPtr() const { + return reinterpret_cast<const VariableArrayType*>(RawVAPtr & ~Flags); + } + + void setVAPtr(const VariableArrayType *P) { + assert (inDecl() || inDeclGroup() || inSizeOfTypeVA()); + RawVAPtr = reinterpret_cast<uintptr_t>(P) | (RawVAPtr & Flags); + } + + void NextDecl(bool ImmediateAdvance = true); + bool HandleDecl(Decl* D); + void NextVA(); + + Stmt*& GetDeclExpr() const; + + StmtIteratorBase(Stmt **s) : stmt(s), decl(0), RawVAPtr(0) {} + StmtIteratorBase(Decl *d, Stmt **s); + StmtIteratorBase(const VariableArrayType *t); + StmtIteratorBase(Decl **dgi, Decl **dge); + StmtIteratorBase() : stmt(0), decl(0), RawVAPtr(0) {} +}; + + +template <typename DERIVED, typename REFERENCE> +class StmtIteratorImpl : public StmtIteratorBase, + public std::iterator<std::forward_iterator_tag, + REFERENCE, ptrdiff_t, + REFERENCE, REFERENCE> { +protected: + StmtIteratorImpl(const StmtIteratorBase& RHS) : StmtIteratorBase(RHS) {} +public: + StmtIteratorImpl() {} + StmtIteratorImpl(Stmt **s) : StmtIteratorBase(s) {} + StmtIteratorImpl(Decl **dgi, Decl **dge) : StmtIteratorBase(dgi, dge) {} + StmtIteratorImpl(Decl *d, Stmt **s) : StmtIteratorBase(d, s) {} + StmtIteratorImpl(const VariableArrayType *t) : StmtIteratorBase(t) {} + + DERIVED& operator++() { + if (inStmt()) + ++stmt; + else if (getVAPtr()) + NextVA(); + else + NextDecl(); + + return static_cast<DERIVED&>(*this); + } + + DERIVED operator++(int) { + DERIVED tmp = static_cast<DERIVED&>(*this); + operator++(); + return tmp; + } + + bool operator==(const DERIVED& RHS) const { + return stmt == RHS.stmt && decl == RHS.decl && RawVAPtr == RHS.RawVAPtr; + } + + bool operator!=(const DERIVED& RHS) const { + return stmt != RHS.stmt || decl != RHS.decl || RawVAPtr != RHS.RawVAPtr; + } + + REFERENCE operator*() const { + return (REFERENCE) (inStmt() ? *stmt : GetDeclExpr()); + } + + REFERENCE operator->() const { return operator*(); } +}; + +struct StmtIterator : public StmtIteratorImpl<StmtIterator,Stmt*&> { + explicit StmtIterator() : StmtIteratorImpl<StmtIterator,Stmt*&>() {} + + StmtIterator(Stmt** S) : StmtIteratorImpl<StmtIterator,Stmt*&>(S) {} + + StmtIterator(Decl** dgi, Decl** dge) + : StmtIteratorImpl<StmtIterator,Stmt*&>(dgi, dge) {} + + StmtIterator(const VariableArrayType *t) + : StmtIteratorImpl<StmtIterator,Stmt*&>(t) {} + + StmtIterator(Decl* D, Stmt **s = 0) + : StmtIteratorImpl<StmtIterator,Stmt*&>(D, s) {} +}; + +struct ConstStmtIterator : public StmtIteratorImpl<ConstStmtIterator, + const Stmt*> { + explicit ConstStmtIterator() : + StmtIteratorImpl<ConstStmtIterator,const Stmt*>() {} + + ConstStmtIterator(const StmtIterator& RHS) : + StmtIteratorImpl<ConstStmtIterator,const Stmt*>(RHS) {} +}; + +/// A range of statement iterators. +/// +/// This class provides some extra functionality beyond std::pair +/// in order to allow the following idiom: +/// for (StmtRange range = stmt->children(); range; ++range) +struct StmtRange : std::pair<StmtIterator,StmtIterator> { + StmtRange() {} + StmtRange(const StmtIterator &begin, const StmtIterator &end) + : std::pair<StmtIterator,StmtIterator>(begin, end) {} + + bool empty() const { return first == second; } + operator bool() const { return !empty(); } + + Stmt *operator->() const { return first.operator->(); } + Stmt *&operator*() const { return first.operator*(); } + + StmtRange &operator++() { + assert(!empty() && "incrementing on empty range"); + ++first; + return *this; + } + + StmtRange operator++(int) { + assert(!empty() && "incrementing on empty range"); + StmtRange copy = *this; + ++first; + return copy; + } + + friend const StmtIterator &begin(const StmtRange &range) { + return range.first; + } + friend const StmtIterator &end(const StmtRange &range) { + return range.second; + } +}; + +/// A range of const statement iterators. +/// +/// This class provides some extra functionality beyond std::pair +/// in order to allow the following idiom: +/// for (ConstStmtRange range = stmt->children(); range; ++range) +struct ConstStmtRange : std::pair<ConstStmtIterator,ConstStmtIterator> { + ConstStmtRange() {} + ConstStmtRange(const ConstStmtIterator &begin, + const ConstStmtIterator &end) + : std::pair<ConstStmtIterator,ConstStmtIterator>(begin, end) {} + ConstStmtRange(const StmtRange &range) + : std::pair<ConstStmtIterator,ConstStmtIterator>(range.first, range.second) + {} + ConstStmtRange(const StmtIterator &begin, const StmtIterator &end) + : std::pair<ConstStmtIterator,ConstStmtIterator>(begin, end) {} + + bool empty() const { return first == second; } + operator bool() const { return !empty(); } + + const Stmt *operator->() const { return first.operator->(); } + const Stmt *operator*() const { return first.operator*(); } + + ConstStmtRange &operator++() { + assert(!empty() && "incrementing on empty range"); + ++first; + return *this; + } + + ConstStmtRange operator++(int) { + assert(!empty() && "incrementing on empty range"); + ConstStmtRange copy = *this; + ++first; + return copy; + } + + friend const ConstStmtIterator &begin(const ConstStmtRange &range) { + return range.first; + } + friend const ConstStmtIterator &end(const ConstStmtRange &range) { + return range.second; + } +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/AST/StmtObjC.h b/clang/include/clang/AST/StmtObjC.h new file mode 100644 index 0000000..a321041 --- /dev/null +++ b/clang/include/clang/AST/StmtObjC.h @@ -0,0 +1,381 @@ +//===--- StmtObjC.h - Classes for representing ObjC statements --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Objective-C statement AST node classes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_STMTOBJC_H +#define LLVM_CLANG_AST_STMTOBJC_H + +#include "clang/AST/Stmt.h" +#include "llvm/Support/Compiler.h" + +namespace clang { + +/// ObjCForCollectionStmt - This represents Objective-c's collection statement; +/// represented as 'for (element 'in' collection-expression)' stmt. +/// +class ObjCForCollectionStmt : public Stmt { + enum { ELEM, COLLECTION, BODY, END_EXPR }; + Stmt* SubExprs[END_EXPR]; // SubExprs[ELEM] is an expression or declstmt. + SourceLocation ForLoc; + SourceLocation RParenLoc; +public: + ObjCForCollectionStmt(Stmt *Elem, Expr *Collect, Stmt *Body, + SourceLocation FCL, SourceLocation RPL); + explicit ObjCForCollectionStmt(EmptyShell Empty) : + Stmt(ObjCForCollectionStmtClass, Empty) { } + + Stmt *getElement() { return SubExprs[ELEM]; } + Expr *getCollection() { + return reinterpret_cast<Expr*>(SubExprs[COLLECTION]); + } + Stmt *getBody() { return SubExprs[BODY]; } + + const Stmt *getElement() const { return SubExprs[ELEM]; } + const Expr *getCollection() const { + return reinterpret_cast<Expr*>(SubExprs[COLLECTION]); + } + const Stmt *getBody() const { return SubExprs[BODY]; } + + void setElement(Stmt *S) { SubExprs[ELEM] = S; } + void setCollection(Expr *E) { + SubExprs[COLLECTION] = reinterpret_cast<Stmt*>(E); + } + void setBody(Stmt *S) { SubExprs[BODY] = S; } + + SourceLocation getForLoc() const { return ForLoc; } + void setForLoc(SourceLocation Loc) { ForLoc = Loc; } + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation Loc) { RParenLoc = Loc; } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(ForLoc, SubExprs[BODY]->getLocEnd()); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCForCollectionStmtClass; + } + static bool classof(const ObjCForCollectionStmt *) { return true; } + + // Iterators + child_range children() { + return child_range(&SubExprs[0], &SubExprs[END_EXPR]); + } +}; + +/// ObjCAtCatchStmt - This represents objective-c's @catch statement. +class ObjCAtCatchStmt : public Stmt { +private: + VarDecl *ExceptionDecl; + Stmt *Body; + SourceLocation AtCatchLoc, RParenLoc; + +public: + ObjCAtCatchStmt(SourceLocation atCatchLoc, SourceLocation rparenloc, + VarDecl *catchVarDecl, + Stmt *atCatchStmt) + : Stmt(ObjCAtCatchStmtClass), ExceptionDecl(catchVarDecl), + Body(atCatchStmt), AtCatchLoc(atCatchLoc), RParenLoc(rparenloc) { } + + explicit ObjCAtCatchStmt(EmptyShell Empty) : + Stmt(ObjCAtCatchStmtClass, Empty) { } + + const Stmt *getCatchBody() const { return Body; } + Stmt *getCatchBody() { return Body; } + void setCatchBody(Stmt *S) { Body = S; } + + const VarDecl *getCatchParamDecl() const { + return ExceptionDecl; + } + VarDecl *getCatchParamDecl() { + return ExceptionDecl; + } + void setCatchParamDecl(VarDecl *D) { ExceptionDecl = D; } + + SourceLocation getAtCatchLoc() const { return AtCatchLoc; } + void setAtCatchLoc(SourceLocation Loc) { AtCatchLoc = Loc; } + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation Loc) { RParenLoc = Loc; } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(AtCatchLoc, Body->getLocEnd()); + } + + bool hasEllipsis() const { return getCatchParamDecl() == 0; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCAtCatchStmtClass; + } + static bool classof(const ObjCAtCatchStmt *) { return true; } + + child_range children() { return child_range(&Body, &Body + 1); } +}; + +/// ObjCAtFinallyStmt - This represent objective-c's @finally Statement +class ObjCAtFinallyStmt : public Stmt { + Stmt *AtFinallyStmt; + SourceLocation AtFinallyLoc; +public: + ObjCAtFinallyStmt(SourceLocation atFinallyLoc, Stmt *atFinallyStmt) + : Stmt(ObjCAtFinallyStmtClass), + AtFinallyStmt(atFinallyStmt), AtFinallyLoc(atFinallyLoc) {} + + explicit ObjCAtFinallyStmt(EmptyShell Empty) : + Stmt(ObjCAtFinallyStmtClass, Empty) { } + + const Stmt *getFinallyBody() const { return AtFinallyStmt; } + Stmt *getFinallyBody() { return AtFinallyStmt; } + void setFinallyBody(Stmt *S) { AtFinallyStmt = S; } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(AtFinallyLoc, AtFinallyStmt->getLocEnd()); + } + + SourceLocation getAtFinallyLoc() const { return AtFinallyLoc; } + void setAtFinallyLoc(SourceLocation Loc) { AtFinallyLoc = Loc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCAtFinallyStmtClass; + } + static bool classof(const ObjCAtFinallyStmt *) { return true; } + + child_range children() { + return child_range(&AtFinallyStmt, &AtFinallyStmt+1); + } +}; + +/// ObjCAtTryStmt - This represent objective-c's over-all +/// @try ... @catch ... @finally statement. +class ObjCAtTryStmt : public Stmt { +private: + // The location of the + SourceLocation AtTryLoc; + + // The number of catch blocks in this statement. + unsigned NumCatchStmts : 16; + + // Whether this statement has a @finally statement. + bool HasFinally : 1; + + /// \brief Retrieve the statements that are stored after this @try statement. + /// + /// The order of the statements in memory follows the order in the source, + /// with the @try body first, followed by the @catch statements (if any) and, + /// finally, the @finally (if it exists). + Stmt **getStmts() { return reinterpret_cast<Stmt **> (this + 1); } + const Stmt* const *getStmts() const { + return reinterpret_cast<const Stmt * const*> (this + 1); + } + + ObjCAtTryStmt(SourceLocation atTryLoc, Stmt *atTryStmt, + Stmt **CatchStmts, unsigned NumCatchStmts, + Stmt *atFinallyStmt); + + explicit ObjCAtTryStmt(EmptyShell Empty, unsigned NumCatchStmts, + bool HasFinally) + : Stmt(ObjCAtTryStmtClass, Empty), NumCatchStmts(NumCatchStmts), + HasFinally(HasFinally) { } + +public: + static ObjCAtTryStmt *Create(ASTContext &Context, SourceLocation atTryLoc, + Stmt *atTryStmt, + Stmt **CatchStmts, unsigned NumCatchStmts, + Stmt *atFinallyStmt); + static ObjCAtTryStmt *CreateEmpty(ASTContext &Context, + unsigned NumCatchStmts, + bool HasFinally); + + /// \brief Retrieve the location of the @ in the @try. + SourceLocation getAtTryLoc() const { return AtTryLoc; } + void setAtTryLoc(SourceLocation Loc) { AtTryLoc = Loc; } + + /// \brief Retrieve the @try body. + const Stmt *getTryBody() const { return getStmts()[0]; } + Stmt *getTryBody() { return getStmts()[0]; } + void setTryBody(Stmt *S) { getStmts()[0] = S; } + + /// \brief Retrieve the number of @catch statements in this try-catch-finally + /// block. + unsigned getNumCatchStmts() const { return NumCatchStmts; } + + /// \brief Retrieve a @catch statement. + const ObjCAtCatchStmt *getCatchStmt(unsigned I) const { + assert(I < NumCatchStmts && "Out-of-bounds @catch index"); + return cast_or_null<ObjCAtCatchStmt>(getStmts()[I + 1]); + } + + /// \brief Retrieve a @catch statement. + ObjCAtCatchStmt *getCatchStmt(unsigned I) { + assert(I < NumCatchStmts && "Out-of-bounds @catch index"); + return cast_or_null<ObjCAtCatchStmt>(getStmts()[I + 1]); + } + + /// \brief Set a particular catch statement. + void setCatchStmt(unsigned I, ObjCAtCatchStmt *S) { + assert(I < NumCatchStmts && "Out-of-bounds @catch index"); + getStmts()[I + 1] = S; + } + + /// Retrieve the @finally statement, if any. + const ObjCAtFinallyStmt *getFinallyStmt() const { + if (!HasFinally) + return 0; + + return cast_or_null<ObjCAtFinallyStmt>(getStmts()[1 + NumCatchStmts]); + } + ObjCAtFinallyStmt *getFinallyStmt() { + if (!HasFinally) + return 0; + + return cast_or_null<ObjCAtFinallyStmt>(getStmts()[1 + NumCatchStmts]); + } + void setFinallyStmt(Stmt *S) { + assert(HasFinally && "@try does not have a @finally slot!"); + getStmts()[1 + NumCatchStmts] = S; + } + + SourceRange getSourceRange() const LLVM_READONLY; + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCAtTryStmtClass; + } + static bool classof(const ObjCAtTryStmt *) { return true; } + + child_range children() { + return child_range(getStmts(), + getStmts() + 1 + NumCatchStmts + HasFinally); + } +}; + +/// ObjCAtSynchronizedStmt - This is for objective-c's @synchronized statement. +/// Example: @synchronized (sem) { +/// do-something; +/// } +/// +class ObjCAtSynchronizedStmt : public Stmt { +private: + enum { SYNC_EXPR, SYNC_BODY, END_EXPR }; + Stmt* SubStmts[END_EXPR]; + SourceLocation AtSynchronizedLoc; + +public: + ObjCAtSynchronizedStmt(SourceLocation atSynchronizedLoc, Stmt *synchExpr, + Stmt *synchBody) + : Stmt(ObjCAtSynchronizedStmtClass) { + SubStmts[SYNC_EXPR] = synchExpr; + SubStmts[SYNC_BODY] = synchBody; + AtSynchronizedLoc = atSynchronizedLoc; + } + explicit ObjCAtSynchronizedStmt(EmptyShell Empty) : + Stmt(ObjCAtSynchronizedStmtClass, Empty) { } + + SourceLocation getAtSynchronizedLoc() const { return AtSynchronizedLoc; } + void setAtSynchronizedLoc(SourceLocation Loc) { AtSynchronizedLoc = Loc; } + + const CompoundStmt *getSynchBody() const { + return reinterpret_cast<CompoundStmt*>(SubStmts[SYNC_BODY]); + } + CompoundStmt *getSynchBody() { + return reinterpret_cast<CompoundStmt*>(SubStmts[SYNC_BODY]); + } + void setSynchBody(Stmt *S) { SubStmts[SYNC_BODY] = S; } + + const Expr *getSynchExpr() const { + return reinterpret_cast<Expr*>(SubStmts[SYNC_EXPR]); + } + Expr *getSynchExpr() { + return reinterpret_cast<Expr*>(SubStmts[SYNC_EXPR]); + } + void setSynchExpr(Stmt *S) { SubStmts[SYNC_EXPR] = S; } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(AtSynchronizedLoc, getSynchBody()->getLocEnd()); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCAtSynchronizedStmtClass; + } + static bool classof(const ObjCAtSynchronizedStmt *) { return true; } + + child_range children() { + return child_range(&SubStmts[0], &SubStmts[0]+END_EXPR); + } +}; + +/// ObjCAtThrowStmt - This represents objective-c's @throw statement. +class ObjCAtThrowStmt : public Stmt { + Stmt *Throw; + SourceLocation AtThrowLoc; +public: + ObjCAtThrowStmt(SourceLocation atThrowLoc, Stmt *throwExpr) + : Stmt(ObjCAtThrowStmtClass), Throw(throwExpr) { + AtThrowLoc = atThrowLoc; + } + explicit ObjCAtThrowStmt(EmptyShell Empty) : + Stmt(ObjCAtThrowStmtClass, Empty) { } + + const Expr *getThrowExpr() const { return reinterpret_cast<Expr*>(Throw); } + Expr *getThrowExpr() { return reinterpret_cast<Expr*>(Throw); } + void setThrowExpr(Stmt *S) { Throw = S; } + + SourceLocation getThrowLoc() { return AtThrowLoc; } + void setThrowLoc(SourceLocation Loc) { AtThrowLoc = Loc; } + + SourceRange getSourceRange() const LLVM_READONLY { + if (Throw) + return SourceRange(AtThrowLoc, Throw->getLocEnd()); + else + return SourceRange(AtThrowLoc); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCAtThrowStmtClass; + } + static bool classof(const ObjCAtThrowStmt *) { return true; } + + child_range children() { return child_range(&Throw, &Throw+1); } +}; + +/// ObjCAutoreleasePoolStmt - This represent objective-c's +/// @autoreleasepool Statement +class ObjCAutoreleasePoolStmt : public Stmt { + Stmt *SubStmt; + SourceLocation AtLoc; +public: + ObjCAutoreleasePoolStmt(SourceLocation atLoc, + Stmt *subStmt) + : Stmt(ObjCAutoreleasePoolStmtClass), + SubStmt(subStmt), AtLoc(atLoc) {} + + explicit ObjCAutoreleasePoolStmt(EmptyShell Empty) : + Stmt(ObjCAutoreleasePoolStmtClass, Empty) { } + + const Stmt *getSubStmt() const { return SubStmt; } + Stmt *getSubStmt() { return SubStmt; } + void setSubStmt(Stmt *S) { SubStmt = S; } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(AtLoc, SubStmt->getLocEnd()); + } + + SourceLocation getAtLoc() const { return AtLoc; } + void setAtLoc(SourceLocation Loc) { AtLoc = Loc; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ObjCAutoreleasePoolStmtClass; + } + static bool classof(const ObjCAutoreleasePoolStmt *) { return true; } + + child_range children() { return child_range(&SubStmt, &SubStmt + 1); } +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/AST/StmtVisitor.h b/clang/include/clang/AST/StmtVisitor.h new file mode 100644 index 0000000..38c4c02 --- /dev/null +++ b/clang/include/clang/AST/StmtVisitor.h @@ -0,0 +1,189 @@ +//===--- StmtVisitor.h - Visitor for Stmt subclasses ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the StmtVisitor and ConstStmtVisitor interfaces. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_STMTVISITOR_H +#define LLVM_CLANG_AST_STMTVISITOR_H + +#include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprObjC.h" +#include "clang/AST/StmtCXX.h" +#include "clang/AST/StmtObjC.h" + +namespace clang { + +template <typename T> struct make_ptr { typedef T *type; }; +template <typename T> struct make_const_ptr { typedef const T *type; }; + +/// StmtVisitorBase - This class implements a simple visitor for Stmt +/// subclasses. Since Expr derives from Stmt, this also includes support for +/// visiting Exprs. +template<template <typename> class Ptr, typename ImplClass, typename RetTy=void> +class StmtVisitorBase { +public: + +#define PTR(CLASS) typename Ptr<CLASS>::type +#define DISPATCH(NAME, CLASS) \ + return static_cast<ImplClass*>(this)->Visit ## NAME(static_cast<PTR(CLASS)>(S)) + + RetTy Visit(PTR(Stmt) S) { + + // If we have a binary expr, dispatch to the subcode of the binop. A smart + // optimizer (e.g. LLVM) will fold this comparison into the switch stmt + // below. + if (PTR(BinaryOperator) BinOp = dyn_cast<BinaryOperator>(S)) { + switch (BinOp->getOpcode()) { + case BO_PtrMemD: DISPATCH(BinPtrMemD, BinaryOperator); + case BO_PtrMemI: DISPATCH(BinPtrMemI, BinaryOperator); + case BO_Mul: DISPATCH(BinMul, BinaryOperator); + case BO_Div: DISPATCH(BinDiv, BinaryOperator); + case BO_Rem: DISPATCH(BinRem, BinaryOperator); + case BO_Add: DISPATCH(BinAdd, BinaryOperator); + case BO_Sub: DISPATCH(BinSub, BinaryOperator); + case BO_Shl: DISPATCH(BinShl, BinaryOperator); + case BO_Shr: DISPATCH(BinShr, BinaryOperator); + + case BO_LT: DISPATCH(BinLT, BinaryOperator); + case BO_GT: DISPATCH(BinGT, BinaryOperator); + case BO_LE: DISPATCH(BinLE, BinaryOperator); + case BO_GE: DISPATCH(BinGE, BinaryOperator); + case BO_EQ: DISPATCH(BinEQ, BinaryOperator); + case BO_NE: DISPATCH(BinNE, BinaryOperator); + + case BO_And: DISPATCH(BinAnd, BinaryOperator); + case BO_Xor: DISPATCH(BinXor, BinaryOperator); + case BO_Or : DISPATCH(BinOr, BinaryOperator); + case BO_LAnd: DISPATCH(BinLAnd, BinaryOperator); + case BO_LOr : DISPATCH(BinLOr, BinaryOperator); + case BO_Assign: DISPATCH(BinAssign, BinaryOperator); + case BO_MulAssign: DISPATCH(BinMulAssign, CompoundAssignOperator); + case BO_DivAssign: DISPATCH(BinDivAssign, CompoundAssignOperator); + case BO_RemAssign: DISPATCH(BinRemAssign, CompoundAssignOperator); + case BO_AddAssign: DISPATCH(BinAddAssign, CompoundAssignOperator); + case BO_SubAssign: DISPATCH(BinSubAssign, CompoundAssignOperator); + case BO_ShlAssign: DISPATCH(BinShlAssign, CompoundAssignOperator); + case BO_ShrAssign: DISPATCH(BinShrAssign, CompoundAssignOperator); + case BO_AndAssign: DISPATCH(BinAndAssign, CompoundAssignOperator); + case BO_OrAssign: DISPATCH(BinOrAssign, CompoundAssignOperator); + case BO_XorAssign: DISPATCH(BinXorAssign, CompoundAssignOperator); + case BO_Comma: DISPATCH(BinComma, BinaryOperator); + } + } else if (PTR(UnaryOperator) UnOp = dyn_cast<UnaryOperator>(S)) { + switch (UnOp->getOpcode()) { + case UO_PostInc: DISPATCH(UnaryPostInc, UnaryOperator); + case UO_PostDec: DISPATCH(UnaryPostDec, UnaryOperator); + case UO_PreInc: DISPATCH(UnaryPreInc, UnaryOperator); + case UO_PreDec: DISPATCH(UnaryPreDec, UnaryOperator); + case UO_AddrOf: DISPATCH(UnaryAddrOf, UnaryOperator); + case UO_Deref: DISPATCH(UnaryDeref, UnaryOperator); + case UO_Plus: DISPATCH(UnaryPlus, UnaryOperator); + case UO_Minus: DISPATCH(UnaryMinus, UnaryOperator); + case UO_Not: DISPATCH(UnaryNot, UnaryOperator); + case UO_LNot: DISPATCH(UnaryLNot, UnaryOperator); + case UO_Real: DISPATCH(UnaryReal, UnaryOperator); + case UO_Imag: DISPATCH(UnaryImag, UnaryOperator); + case UO_Extension: DISPATCH(UnaryExtension, UnaryOperator); + } + } + + // Top switch stmt: dispatch to VisitFooStmt for each FooStmt. + switch (S->getStmtClass()) { + default: llvm_unreachable("Unknown stmt kind!"); +#define ABSTRACT_STMT(STMT) +#define STMT(CLASS, PARENT) \ + case Stmt::CLASS ## Class: DISPATCH(CLASS, CLASS); +#include "clang/AST/StmtNodes.inc" + } + } + + // If the implementation chooses not to implement a certain visit method, fall + // back on VisitExpr or whatever else is the superclass. +#define STMT(CLASS, PARENT) \ + RetTy Visit ## CLASS(PTR(CLASS) S) { DISPATCH(PARENT, PARENT); } +#include "clang/AST/StmtNodes.inc" + + // If the implementation doesn't implement binary operator methods, fall back + // on VisitBinaryOperator. +#define BINOP_FALLBACK(NAME) \ + RetTy VisitBin ## NAME(PTR(BinaryOperator) S) { \ + DISPATCH(BinaryOperator, BinaryOperator); \ + } + BINOP_FALLBACK(PtrMemD) BINOP_FALLBACK(PtrMemI) + BINOP_FALLBACK(Mul) BINOP_FALLBACK(Div) BINOP_FALLBACK(Rem) + BINOP_FALLBACK(Add) BINOP_FALLBACK(Sub) BINOP_FALLBACK(Shl) + BINOP_FALLBACK(Shr) + + BINOP_FALLBACK(LT) BINOP_FALLBACK(GT) BINOP_FALLBACK(LE) + BINOP_FALLBACK(GE) BINOP_FALLBACK(EQ) BINOP_FALLBACK(NE) + BINOP_FALLBACK(And) BINOP_FALLBACK(Xor) BINOP_FALLBACK(Or) + BINOP_FALLBACK(LAnd) BINOP_FALLBACK(LOr) + + BINOP_FALLBACK(Assign) + BINOP_FALLBACK(Comma) +#undef BINOP_FALLBACK + + // If the implementation doesn't implement compound assignment operator + // methods, fall back on VisitCompoundAssignOperator. +#define CAO_FALLBACK(NAME) \ + RetTy VisitBin ## NAME(PTR(CompoundAssignOperator) S) { \ + DISPATCH(CompoundAssignOperator, CompoundAssignOperator); \ + } + CAO_FALLBACK(MulAssign) CAO_FALLBACK(DivAssign) CAO_FALLBACK(RemAssign) + CAO_FALLBACK(AddAssign) CAO_FALLBACK(SubAssign) CAO_FALLBACK(ShlAssign) + CAO_FALLBACK(ShrAssign) CAO_FALLBACK(AndAssign) CAO_FALLBACK(OrAssign) + CAO_FALLBACK(XorAssign) +#undef CAO_FALLBACK + + // If the implementation doesn't implement unary operator methods, fall back + // on VisitUnaryOperator. +#define UNARYOP_FALLBACK(NAME) \ + RetTy VisitUnary ## NAME(PTR(UnaryOperator) S) { \ + DISPATCH(UnaryOperator, UnaryOperator); \ + } + UNARYOP_FALLBACK(PostInc) UNARYOP_FALLBACK(PostDec) + UNARYOP_FALLBACK(PreInc) UNARYOP_FALLBACK(PreDec) + UNARYOP_FALLBACK(AddrOf) UNARYOP_FALLBACK(Deref) + + UNARYOP_FALLBACK(Plus) UNARYOP_FALLBACK(Minus) + UNARYOP_FALLBACK(Not) UNARYOP_FALLBACK(LNot) + UNARYOP_FALLBACK(Real) UNARYOP_FALLBACK(Imag) + UNARYOP_FALLBACK(Extension) +#undef UNARYOP_FALLBACK + + // Base case, ignore it. :) + RetTy VisitStmt(PTR(Stmt) Node) { return RetTy(); } + +#undef PTR +#undef DISPATCH +}; + +/// StmtVisitor - This class implements a simple visitor for Stmt subclasses. +/// Since Expr derives from Stmt, this also includes support for visiting Exprs. +/// +/// This class does not preserve constness of Stmt pointers (see also +/// ConstStmtVisitor). +template<typename ImplClass, typename RetTy=void> +class StmtVisitor + : public StmtVisitorBase<make_ptr, ImplClass, RetTy> {}; + +/// ConstStmtVisitor - This class implements a simple visitor for Stmt +/// subclasses. Since Expr derives from Stmt, this also includes support for +/// visiting Exprs. +/// +/// This class preserves constness of Stmt pointers (see also StmtVisitor). +template<typename ImplClass, typename RetTy=void> +class ConstStmtVisitor + : public StmtVisitorBase<make_const_ptr, ImplClass, RetTy> {}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/AST/TemplateBase.h b/clang/include/clang/AST/TemplateBase.h new file mode 100644 index 0000000..65f5460 --- /dev/null +++ b/clang/include/clang/AST/TemplateBase.h @@ -0,0 +1,657 @@ +//===-- TemplateBase.h - Core classes for C++ templates ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides definitions which are common for all kinds of +// template representation. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_TEMPLATEBASE_H +#define LLVM_CLANG_AST_TEMPLATEBASE_H + +#include "clang/AST/Type.h" +#include "clang/AST/TemplateName.h" +#include "llvm/ADT/APSInt.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/ErrorHandling.h" + +namespace llvm { + class FoldingSetNodeID; +} + +namespace clang { + +class Decl; +class DiagnosticBuilder; +class Expr; +struct PrintingPolicy; +class TypeSourceInfo; + +/// \brief Represents a template argument within a class template +/// specialization. +class TemplateArgument { +public: + /// \brief The kind of template argument we're storing. + enum ArgKind { + /// \brief Represents an empty template argument, e.g., one that has not + /// been deduced. + Null = 0, + /// The template argument is a type. Its value is stored in the + /// TypeOrValue field. + Type, + /// The template argument is a declaration that was provided for a pointer + /// or reference non-type template parameter. + Declaration, + /// The template argument is an integral value stored in an llvm::APSInt + /// that was provided for an integral non-type template parameter. + Integral, + /// The template argument is a template name that was provided for a + /// template template parameter. + Template, + /// The template argument is a pack expansion of a template name that was + /// provided for a template template parameter. + TemplateExpansion, + /// The template argument is a value- or type-dependent expression + /// stored in an Expr*. + Expression, + /// The template argument is actually a parameter pack. Arguments are stored + /// in the Args struct. + Pack + }; + +private: + /// \brief The kind of template argument we're storing. + unsigned Kind; + + union { + uintptr_t TypeOrValue; + struct { + char Value[sizeof(llvm::APSInt)]; + void *Type; + } Integer; + struct { + const TemplateArgument *Args; + unsigned NumArgs; + } Args; + struct { + void *Name; + unsigned NumExpansions; + } TemplateArg; + }; + + TemplateArgument(TemplateName, bool); // DO NOT USE + +public: + /// \brief Construct an empty, invalid template argument. + TemplateArgument() : Kind(Null), TypeOrValue(0) { } + + /// \brief Construct a template type argument. + TemplateArgument(QualType T) : Kind(Type) { + TypeOrValue = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr()); + } + + /// \brief Construct a template argument that refers to a + /// declaration, which is either an external declaration or a + /// template declaration. + TemplateArgument(Decl *D) : Kind(Declaration) { + TypeOrValue = reinterpret_cast<uintptr_t>(D); + } + + /// \brief Construct an integral constant template argument. + TemplateArgument(const llvm::APSInt &Value, QualType Type) : Kind(Integral) { + // FIXME: Large integral values will get leaked. Do something + // similar to what we did with IntegerLiteral. + new (Integer.Value) llvm::APSInt(Value); + Integer.Type = Type.getAsOpaquePtr(); + } + + /// \brief Construct a template argument that is a template. + /// + /// This form of template argument is generally used for template template + /// parameters. However, the template name could be a dependent template + /// name that ends up being instantiated to a function template whose address + /// is taken. + /// + /// \param Name The template name. + TemplateArgument(TemplateName Name) : Kind(Template) + { + TemplateArg.Name = Name.getAsVoidPointer(); + TemplateArg.NumExpansions = 0; + } + + /// \brief Construct a template argument that is a template pack expansion. + /// + /// This form of template argument is generally used for template template + /// parameters. However, the template name could be a dependent template + /// name that ends up being instantiated to a function template whose address + /// is taken. + /// + /// \param Name The template name. + /// + /// \param NumExpansions The number of expansions that will be generated by + /// instantiating + TemplateArgument(TemplateName Name, llvm::Optional<unsigned> NumExpansions) + : Kind(TemplateExpansion) + { + TemplateArg.Name = Name.getAsVoidPointer(); + if (NumExpansions) + TemplateArg.NumExpansions = *NumExpansions + 1; + else + TemplateArg.NumExpansions = 0; + } + + /// \brief Construct a template argument that is an expression. + /// + /// This form of template argument only occurs in template argument + /// lists used for dependent types and for expression; it will not + /// occur in a non-dependent, canonical template argument list. + TemplateArgument(Expr *E) : Kind(Expression) { + TypeOrValue = reinterpret_cast<uintptr_t>(E); + } + + /// \brief Construct a template argument that is a template argument pack. + /// + /// We assume that storage for the template arguments provided + /// outlives the TemplateArgument itself. + TemplateArgument(const TemplateArgument *Args, unsigned NumArgs) : Kind(Pack){ + this->Args.Args = Args; + this->Args.NumArgs = NumArgs; + } + + /// \brief Copy constructor for a template argument. + TemplateArgument(const TemplateArgument &Other) : Kind(Other.Kind) { + // FIXME: Large integral values will get leaked. Do something + // similar to what we did with IntegerLiteral. + if (Kind == Integral) { + new (Integer.Value) llvm::APSInt(*Other.getAsIntegral()); + Integer.Type = Other.Integer.Type; + } else if (Kind == Pack) { + Args.NumArgs = Other.Args.NumArgs; + Args.Args = Other.Args.Args; + } else if (Kind == Template || Kind == TemplateExpansion) { + TemplateArg.Name = Other.TemplateArg.Name; + TemplateArg.NumExpansions = Other.TemplateArg.NumExpansions; + } else + TypeOrValue = Other.TypeOrValue; + } + + TemplateArgument& operator=(const TemplateArgument& Other) { + using llvm::APSInt; + + if (Kind == Other.Kind && Kind == Integral) { + // Copy integral values. + *this->getAsIntegral() = *Other.getAsIntegral(); + Integer.Type = Other.Integer.Type; + return *this; + } + + // Destroy the current integral value, if that's what we're holding. + if (Kind == Integral) + getAsIntegral()->~APSInt(); + + Kind = Other.Kind; + + if (Other.Kind == Integral) { + new (Integer.Value) llvm::APSInt(*Other.getAsIntegral()); + Integer.Type = Other.Integer.Type; + } else if (Other.Kind == Pack) { + Args.NumArgs = Other.Args.NumArgs; + Args.Args = Other.Args.Args; + } else if (Kind == Template || Kind == TemplateExpansion) { + TemplateArg.Name = Other.TemplateArg.Name; + TemplateArg.NumExpansions = Other.TemplateArg.NumExpansions; + } else { + TypeOrValue = Other.TypeOrValue; + } + + return *this; + } + + ~TemplateArgument() { + using llvm::APSInt; + + if (Kind == Integral) + getAsIntegral()->~APSInt(); + } + + /// \brief Create a new template argument pack by copying the given set of + /// template arguments. + static TemplateArgument CreatePackCopy(ASTContext &Context, + const TemplateArgument *Args, + unsigned NumArgs); + + /// \brief Return the kind of stored template argument. + ArgKind getKind() const { return (ArgKind)Kind; } + + /// \brief Determine whether this template argument has no value. + bool isNull() const { return Kind == Null; } + + /// \brief Whether this template argument is dependent on a template + /// parameter such that its result can change from one instantiation to + /// another. + bool isDependent() const; + + /// \brief Whether this template argument is dependent on a template + /// parameter. + bool isInstantiationDependent() const; + + /// \brief Whether this template argument contains an unexpanded + /// parameter pack. + bool containsUnexpandedParameterPack() const; + + /// \brief Determine whether this template argument is a pack expansion. + bool isPackExpansion() const; + + /// \brief Retrieve the template argument as a type. + QualType getAsType() const { + if (Kind != Type) + return QualType(); + + return QualType::getFromOpaquePtr(reinterpret_cast<void*>(TypeOrValue)); + } + + /// \brief Retrieve the template argument as a declaration. + Decl *getAsDecl() const { + if (Kind != Declaration) + return 0; + return reinterpret_cast<Decl *>(TypeOrValue); + } + + /// \brief Retrieve the template argument as a template name. + TemplateName getAsTemplate() const { + if (Kind != Template) + return TemplateName(); + + return TemplateName::getFromVoidPointer(TemplateArg.Name); + } + + /// \brief Retrieve the template argument as a template name; if the argument + /// is a pack expansion, return the pattern as a template name. + TemplateName getAsTemplateOrTemplatePattern() const { + if (Kind != Template && Kind != TemplateExpansion) + return TemplateName(); + + return TemplateName::getFromVoidPointer(TemplateArg.Name); + } + + /// \brief Retrieve the number of expansions that a template template argument + /// expansion will produce, if known. + llvm::Optional<unsigned> getNumTemplateExpansions() const; + + /// \brief Retrieve the template argument as an integral value. + llvm::APSInt *getAsIntegral() { + if (Kind != Integral) + return 0; + return reinterpret_cast<llvm::APSInt*>(&Integer.Value[0]); + } + + const llvm::APSInt *getAsIntegral() const { + return const_cast<TemplateArgument*>(this)->getAsIntegral(); + } + + /// \brief Retrieve the type of the integral value. + QualType getIntegralType() const { + if (Kind != Integral) + return QualType(); + + return QualType::getFromOpaquePtr(Integer.Type); + } + + void setIntegralType(QualType T) { + assert(Kind == Integral && + "Cannot set the integral type of a non-integral template argument"); + Integer.Type = T.getAsOpaquePtr(); + } + + /// \brief Retrieve the template argument as an expression. + Expr *getAsExpr() const { + if (Kind != Expression) + return 0; + + return reinterpret_cast<Expr *>(TypeOrValue); + } + + /// \brief Iterator that traverses the elements of a template argument pack. + typedef const TemplateArgument * pack_iterator; + + /// \brief Iterator referencing the first argument of a template argument + /// pack. + pack_iterator pack_begin() const { + assert(Kind == Pack); + return Args.Args; + } + + /// \brief Iterator referencing one past the last argument of a template + /// argument pack. + pack_iterator pack_end() const { + assert(Kind == Pack); + return Args.Args + Args.NumArgs; + } + + /// \brief The number of template arguments in the given template argument + /// pack. + unsigned pack_size() const { + assert(Kind == Pack); + return Args.NumArgs; + } + + /// Determines whether two template arguments are superficially the + /// same. + bool structurallyEquals(const TemplateArgument &Other) const; + + /// \brief When the template argument is a pack expansion, returns + /// the pattern of the pack expansion. + /// + /// \param Ellipsis Will be set to the location of the ellipsis. + TemplateArgument getPackExpansionPattern() const; + + /// \brief Print this template argument to the given output stream. + void print(const PrintingPolicy &Policy, raw_ostream &Out) const; + + /// \brief Used to insert TemplateArguments into FoldingSets. + void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) const; +}; + +/// Location information for a TemplateArgument. +struct TemplateArgumentLocInfo { +private: + union { + Expr *Expression; + TypeSourceInfo *Declarator; + struct { + // FIXME: We'd like to just use the qualifier in the TemplateName, + // but template arguments get canonicalized too quickly. + NestedNameSpecifier *Qualifier; + void *QualifierLocData; + unsigned TemplateNameLoc; + unsigned EllipsisLoc; + } Template; + }; + +public: + TemplateArgumentLocInfo(); + + TemplateArgumentLocInfo(TypeSourceInfo *TInfo) : Declarator(TInfo) {} + + TemplateArgumentLocInfo(Expr *E) : Expression(E) {} + + TemplateArgumentLocInfo(NestedNameSpecifierLoc QualifierLoc, + SourceLocation TemplateNameLoc, + SourceLocation EllipsisLoc) + { + Template.Qualifier = QualifierLoc.getNestedNameSpecifier(); + Template.QualifierLocData = QualifierLoc.getOpaqueData(); + Template.TemplateNameLoc = TemplateNameLoc.getRawEncoding(); + Template.EllipsisLoc = EllipsisLoc.getRawEncoding(); + } + + TypeSourceInfo *getAsTypeSourceInfo() const { + return Declarator; + } + + Expr *getAsExpr() const { + return Expression; + } + + NestedNameSpecifierLoc getTemplateQualifierLoc() const { + return NestedNameSpecifierLoc(Template.Qualifier, + Template.QualifierLocData); + } + + SourceLocation getTemplateNameLoc() const { + return SourceLocation::getFromRawEncoding(Template.TemplateNameLoc); + } + + SourceLocation getTemplateEllipsisLoc() const { + return SourceLocation::getFromRawEncoding(Template.EllipsisLoc); + } +}; + +/// Location wrapper for a TemplateArgument. TemplateArgument is to +/// TemplateArgumentLoc as Type is to TypeLoc. +class TemplateArgumentLoc { + TemplateArgument Argument; + TemplateArgumentLocInfo LocInfo; + +public: + TemplateArgumentLoc() {} + + TemplateArgumentLoc(const TemplateArgument &Argument, + TemplateArgumentLocInfo Opaque) + : Argument(Argument), LocInfo(Opaque) { + } + + TemplateArgumentLoc(const TemplateArgument &Argument, TypeSourceInfo *TInfo) + : Argument(Argument), LocInfo(TInfo) { + assert(Argument.getKind() == TemplateArgument::Type); + } + + TemplateArgumentLoc(const TemplateArgument &Argument, Expr *E) + : Argument(Argument), LocInfo(E) { + assert(Argument.getKind() == TemplateArgument::Expression); + } + + TemplateArgumentLoc(const TemplateArgument &Argument, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation TemplateNameLoc, + SourceLocation EllipsisLoc = SourceLocation()) + : Argument(Argument), LocInfo(QualifierLoc, TemplateNameLoc, EllipsisLoc) { + assert(Argument.getKind() == TemplateArgument::Template || + Argument.getKind() == TemplateArgument::TemplateExpansion); + } + + /// \brief - Fetches the primary location of the argument. + SourceLocation getLocation() const { + if (Argument.getKind() == TemplateArgument::Template || + Argument.getKind() == TemplateArgument::TemplateExpansion) + return getTemplateNameLoc(); + + return getSourceRange().getBegin(); + } + + /// \brief - Fetches the full source range of the argument. + SourceRange getSourceRange() const LLVM_READONLY; + + const TemplateArgument &getArgument() const { + return Argument; + } + + TemplateArgumentLocInfo getLocInfo() const { + return LocInfo; + } + + TypeSourceInfo *getTypeSourceInfo() const { + assert(Argument.getKind() == TemplateArgument::Type); + return LocInfo.getAsTypeSourceInfo(); + } + + Expr *getSourceExpression() const { + assert(Argument.getKind() == TemplateArgument::Expression); + return LocInfo.getAsExpr(); + } + + Expr *getSourceDeclExpression() const { + assert(Argument.getKind() == TemplateArgument::Declaration); + return LocInfo.getAsExpr(); + } + + NestedNameSpecifierLoc getTemplateQualifierLoc() const { + assert(Argument.getKind() == TemplateArgument::Template || + Argument.getKind() == TemplateArgument::TemplateExpansion); + return LocInfo.getTemplateQualifierLoc(); + } + + SourceLocation getTemplateNameLoc() const { + assert(Argument.getKind() == TemplateArgument::Template || + Argument.getKind() == TemplateArgument::TemplateExpansion); + return LocInfo.getTemplateNameLoc(); + } + + SourceLocation getTemplateEllipsisLoc() const { + assert(Argument.getKind() == TemplateArgument::TemplateExpansion); + return LocInfo.getTemplateEllipsisLoc(); + } + + /// \brief When the template argument is a pack expansion, returns + /// the pattern of the pack expansion. + /// + /// \param Ellipsis Will be set to the location of the ellipsis. + /// + /// \param NumExpansions Will be set to the number of expansions that will + /// be generated from this pack expansion, if known a priori. + TemplateArgumentLoc getPackExpansionPattern(SourceLocation &Ellipsis, + llvm::Optional<unsigned> &NumExpansions, + ASTContext &Context) const; +}; + +/// A convenient class for passing around template argument +/// information. Designed to be passed by reference. +class TemplateArgumentListInfo { + SmallVector<TemplateArgumentLoc, 8> Arguments; + SourceLocation LAngleLoc; + SourceLocation RAngleLoc; + + // This can leak if used in an AST node, use ASTTemplateArgumentListInfo + // instead. + void* operator new(size_t bytes, ASTContext& C); + +public: + TemplateArgumentListInfo() {} + + TemplateArgumentListInfo(SourceLocation LAngleLoc, + SourceLocation RAngleLoc) + : LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc) {} + + SourceLocation getLAngleLoc() const { return LAngleLoc; } + SourceLocation getRAngleLoc() const { return RAngleLoc; } + + void setLAngleLoc(SourceLocation Loc) { LAngleLoc = Loc; } + void setRAngleLoc(SourceLocation Loc) { RAngleLoc = Loc; } + + unsigned size() const { return Arguments.size(); } + + const TemplateArgumentLoc *getArgumentArray() const { + return Arguments.data(); + } + + const TemplateArgumentLoc &operator[](unsigned I) const { + return Arguments[I]; + } + + void addArgument(const TemplateArgumentLoc &Loc) { + Arguments.push_back(Loc); + } +}; + +/// \brief Represents an explicit template argument list in C++, e.g., +/// the "<int>" in "sort<int>". +/// This is safe to be used inside an AST node, in contrast with +/// TemplateArgumentListInfo. +struct ASTTemplateArgumentListInfo { + /// \brief The source location of the left angle bracket ('<'); + SourceLocation LAngleLoc; + + /// \brief The source location of the right angle bracket ('>'); + SourceLocation RAngleLoc; + + /// \brief The number of template arguments in TemplateArgs. + /// The actual template arguments (if any) are stored after the + /// ExplicitTemplateArgumentList structure. + unsigned NumTemplateArgs; + + /// \brief Retrieve the template arguments + TemplateArgumentLoc *getTemplateArgs() { + return reinterpret_cast<TemplateArgumentLoc *> (this + 1); + } + + /// \brief Retrieve the template arguments + const TemplateArgumentLoc *getTemplateArgs() const { + return reinterpret_cast<const TemplateArgumentLoc *> (this + 1); + } + + const TemplateArgumentLoc &operator[](unsigned I) const { + return getTemplateArgs()[I]; + } + + static const ASTTemplateArgumentListInfo *Create(ASTContext &C, + const TemplateArgumentListInfo &List); + + void initializeFrom(const TemplateArgumentListInfo &List); + void initializeFrom(const TemplateArgumentListInfo &List, + bool &Dependent, bool &InstantiationDependent, + bool &ContainsUnexpandedParameterPack); + void copyInto(TemplateArgumentListInfo &List) const; + static std::size_t sizeFor(unsigned NumTemplateArgs); +}; + +/// \brief Extends ASTTemplateArgumentListInfo with the source location +/// information for the template keyword; this is used as part of the +/// representation of qualified identifiers, such as S<T>::template apply<T>. +struct ASTTemplateKWAndArgsInfo : public ASTTemplateArgumentListInfo { + typedef ASTTemplateArgumentListInfo Base; + + // NOTE: the source location of the (optional) template keyword is + // stored after all template arguments. + + /// \brief Get the source location of the template keyword. + SourceLocation getTemplateKeywordLoc() const { + return *reinterpret_cast<const SourceLocation*> + (getTemplateArgs() + NumTemplateArgs); + } + + /// \brief Sets the source location of the template keyword. + void setTemplateKeywordLoc(SourceLocation TemplateKWLoc) { + *reinterpret_cast<SourceLocation*> + (getTemplateArgs() + NumTemplateArgs) = TemplateKWLoc; + } + + static const ASTTemplateKWAndArgsInfo* + Create(ASTContext &C, SourceLocation TemplateKWLoc, + const TemplateArgumentListInfo &List); + + void initializeFrom(SourceLocation TemplateKWLoc, + const TemplateArgumentListInfo &List); + void initializeFrom(SourceLocation TemplateKWLoc, + const TemplateArgumentListInfo &List, + bool &Dependent, bool &InstantiationDependent, + bool &ContainsUnexpandedParameterPack); + void initializeFrom(SourceLocation TemplateKWLoc); + + static std::size_t sizeFor(unsigned NumTemplateArgs); +}; + +const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + const TemplateArgument &Arg); + +inline TemplateSpecializationType::iterator + TemplateSpecializationType::end() const { + return getArgs() + getNumArgs(); +} + +inline DependentTemplateSpecializationType::iterator + DependentTemplateSpecializationType::end() const { + return getArgs() + getNumArgs(); +} + +inline const TemplateArgument & + TemplateSpecializationType::getArg(unsigned Idx) const { + assert(Idx < getNumArgs() && "Template argument out of range"); + return getArgs()[Idx]; +} + +inline const TemplateArgument & + DependentTemplateSpecializationType::getArg(unsigned Idx) const { + assert(Idx < getNumArgs() && "Template argument out of range"); + return getArgs()[Idx]; +} + +} // end namespace clang + +#endif diff --git a/clang/include/clang/AST/TemplateName.h b/clang/include/clang/AST/TemplateName.h new file mode 100644 index 0000000..7dc75b1 --- /dev/null +++ b/clang/include/clang/AST/TemplateName.h @@ -0,0 +1,558 @@ +//===--- TemplateName.h - C++ Template Name Representation-------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the TemplateName interface and subclasses. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_TEMPLATENAME_H +#define LLVM_CLANG_AST_TEMPLATENAME_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/PointerUnion.h" +#include "clang/Basic/OperatorKinds.h" + +namespace clang { + +class ASTContext; +class DependentTemplateName; +class DiagnosticBuilder; +class IdentifierInfo; +class NestedNameSpecifier; +class OverloadedTemplateStorage; +struct PrintingPolicy; +class QualifiedTemplateName; +class NamedDecl; +class SubstTemplateTemplateParmStorage; +class SubstTemplateTemplateParmPackStorage; +class TemplateArgument; +class TemplateDecl; +class TemplateTemplateParmDecl; + +/// \brief Implementation class used to describe either a set of overloaded +/// template names or an already-substituted template template parameter pack. +class UncommonTemplateNameStorage { +protected: + enum Kind { + Overloaded, + SubstTemplateTemplateParm, + SubstTemplateTemplateParmPack + }; + + union { + struct { + /// \brief A Kind. + unsigned Kind : 2; + + /// \brief The number of stored templates or template arguments, + /// depending on which subclass we have. + unsigned Size : 30; + } Bits; + + void *PointerAlignment; + }; + + UncommonTemplateNameStorage(Kind kind, unsigned size) { + Bits.Kind = kind; + Bits.Size = size; + } + +public: + unsigned size() const { return Bits.Size; } + + OverloadedTemplateStorage *getAsOverloadedStorage() { + return Bits.Kind == Overloaded + ? reinterpret_cast<OverloadedTemplateStorage *>(this) + : 0; + } + + SubstTemplateTemplateParmStorage *getAsSubstTemplateTemplateParm() { + return Bits.Kind == SubstTemplateTemplateParm + ? reinterpret_cast<SubstTemplateTemplateParmStorage *>(this) + : 0; + } + + SubstTemplateTemplateParmPackStorage *getAsSubstTemplateTemplateParmPack() { + return Bits.Kind == SubstTemplateTemplateParmPack + ? reinterpret_cast<SubstTemplateTemplateParmPackStorage *>(this) + : 0; + } +}; + +/// \brief A structure for storing the information associated with an +/// overloaded template name. +class OverloadedTemplateStorage : public UncommonTemplateNameStorage { + friend class ASTContext; + + OverloadedTemplateStorage(unsigned size) + : UncommonTemplateNameStorage(Overloaded, size) { } + + NamedDecl **getStorage() { + return reinterpret_cast<NamedDecl **>(this + 1); + } + NamedDecl * const *getStorage() const { + return reinterpret_cast<NamedDecl *const *>(this + 1); + } + +public: + typedef NamedDecl *const *iterator; + + iterator begin() const { return getStorage(); } + iterator end() const { return getStorage() + size(); } +}; + +/// \brief A structure for storing an already-substituted template template +/// parameter pack. +/// +/// This kind of template names occurs when the parameter pack has been +/// provided with a template template argument pack in a context where its +/// enclosing pack expansion could not be fully expanded. +class SubstTemplateTemplateParmPackStorage + : public UncommonTemplateNameStorage, public llvm::FoldingSetNode +{ + TemplateTemplateParmDecl *Parameter; + const TemplateArgument *Arguments; + +public: + SubstTemplateTemplateParmPackStorage(TemplateTemplateParmDecl *Parameter, + unsigned Size, + const TemplateArgument *Arguments) + : UncommonTemplateNameStorage(SubstTemplateTemplateParmPack, Size), + Parameter(Parameter), Arguments(Arguments) { } + + /// \brief Retrieve the template template parameter pack being substituted. + TemplateTemplateParmDecl *getParameterPack() const { + return Parameter; + } + + /// \brief Retrieve the template template argument pack with which this + /// parameter was substituted. + TemplateArgument getArgumentPack() const; + + void Profile(llvm::FoldingSetNodeID &ID, ASTContext &Context); + + static void Profile(llvm::FoldingSetNodeID &ID, + ASTContext &Context, + TemplateTemplateParmDecl *Parameter, + const TemplateArgument &ArgPack); +}; + +/// \brief Represents a C++ template name within the type system. +/// +/// A C++ template name refers to a template within the C++ type +/// system. In most cases, a template name is simply a reference to a +/// class template, e.g. +/// +/// \code +/// template<typename T> class X { }; +/// +/// X<int> xi; +/// \endcode +/// +/// Here, the 'X' in \c X<int> is a template name that refers to the +/// declaration of the class template X, above. Template names can +/// also refer to function templates, C++0x template aliases, etc. +/// +/// Some template names are dependent. For example, consider: +/// +/// \code +/// template<typename MetaFun, typename T1, typename T2> struct apply2 { +/// typedef typename MetaFun::template apply<T1, T2>::type type; +/// }; +/// \endcode +/// +/// Here, "apply" is treated as a template name within the typename +/// specifier in the typedef. "apply" is a nested template, and can +/// only be understood in the context of +class TemplateName { + typedef llvm::PointerUnion4<TemplateDecl *, + UncommonTemplateNameStorage *, + QualifiedTemplateName *, + DependentTemplateName *> StorageType; + + StorageType Storage; + + explicit TemplateName(void *Ptr) { + Storage = StorageType::getFromOpaqueValue(Ptr); + } + +public: + // \brief Kind of name that is actually stored. + enum NameKind { + /// \brief A single template declaration. + Template, + /// \brief A set of overloaded template declarations. + OverloadedTemplate, + /// \brief A qualified template name, where the qualification is kept + /// to describe the source code as written. + QualifiedTemplate, + /// \brief A dependent template name that has not been resolved to a + /// template (or set of templates). + DependentTemplate, + /// \brief A template template parameter that has been substituted + /// for some other template name. + SubstTemplateTemplateParm, + /// \brief A template template parameter pack that has been substituted for + /// a template template argument pack, but has not yet been expanded into + /// individual arguments. + SubstTemplateTemplateParmPack + }; + + TemplateName() : Storage() { } + explicit TemplateName(TemplateDecl *Template) : Storage(Template) { } + explicit TemplateName(OverloadedTemplateStorage *Storage) + : Storage(Storage) { } + explicit TemplateName(SubstTemplateTemplateParmStorage *Storage); + explicit TemplateName(SubstTemplateTemplateParmPackStorage *Storage) + : Storage(Storage) { } + explicit TemplateName(QualifiedTemplateName *Qual) : Storage(Qual) { } + explicit TemplateName(DependentTemplateName *Dep) : Storage(Dep) { } + + /// \brief Determine whether this template name is NULL. + bool isNull() const { return Storage.isNull(); } + + // \brief Get the kind of name that is actually stored. + NameKind getKind() const; + + /// \brief Retrieve the underlying template declaration that + /// this template name refers to, if known. + /// + /// \returns The template declaration that this template name refers + /// to, if any. If the template name does not refer to a specific + /// declaration because it is a dependent name, or if it refers to a + /// set of function templates, returns NULL. + TemplateDecl *getAsTemplateDecl() const; + + /// \brief Retrieve the underlying, overloaded function template + // declarations that this template name refers to, if known. + /// + /// \returns The set of overloaded function templates that this template + /// name refers to, if known. If the template name does not refer to a + /// specific set of function templates because it is a dependent name or + /// refers to a single template, returns NULL. + OverloadedTemplateStorage *getAsOverloadedTemplate() const { + if (UncommonTemplateNameStorage *Uncommon = + Storage.dyn_cast<UncommonTemplateNameStorage *>()) + return Uncommon->getAsOverloadedStorage(); + + return 0; + } + + /// \brief Retrieve the substituted template template parameter, if + /// known. + /// + /// \returns The storage for the substituted template template parameter, + /// if known. Otherwise, returns NULL. + SubstTemplateTemplateParmStorage *getAsSubstTemplateTemplateParm() const { + if (UncommonTemplateNameStorage *uncommon = + Storage.dyn_cast<UncommonTemplateNameStorage *>()) + return uncommon->getAsSubstTemplateTemplateParm(); + + return 0; + } + + /// \brief Retrieve the substituted template template parameter pack, if + /// known. + /// + /// \returns The storage for the substituted template template parameter pack, + /// if known. Otherwise, returns NULL. + SubstTemplateTemplateParmPackStorage * + getAsSubstTemplateTemplateParmPack() const { + if (UncommonTemplateNameStorage *Uncommon = + Storage.dyn_cast<UncommonTemplateNameStorage *>()) + return Uncommon->getAsSubstTemplateTemplateParmPack(); + + return 0; + } + + /// \brief Retrieve the underlying qualified template name + /// structure, if any. + QualifiedTemplateName *getAsQualifiedTemplateName() const { + return Storage.dyn_cast<QualifiedTemplateName *>(); + } + + /// \brief Retrieve the underlying dependent template name + /// structure, if any. + DependentTemplateName *getAsDependentTemplateName() const { + return Storage.dyn_cast<DependentTemplateName *>(); + } + + TemplateName getUnderlying() const; + + /// \brief Determines whether this is a dependent template name. + bool isDependent() const; + + /// \brief Determines whether this is a template name that somehow + /// depends on a template parameter. + bool isInstantiationDependent() const; + + /// \brief Determines whether this template name contains an + /// unexpanded parameter pack (for C++0x variadic templates). + bool containsUnexpandedParameterPack() const; + + /// \brief Print the template name. + /// + /// \param OS the output stream to which the template name will be + /// printed. + /// + /// \param SuppressNNS if true, don't print the + /// nested-name-specifier that precedes the template name (if it has + /// one). + void print(raw_ostream &OS, const PrintingPolicy &Policy, + bool SuppressNNS = false) const; + + /// \brief Debugging aid that dumps the template name to standard + /// error. + void dump() const; + + void Profile(llvm::FoldingSetNodeID &ID) { + ID.AddPointer(Storage.getOpaqueValue()); + } + + /// \brief Retrieve the template name as a void pointer. + void *getAsVoidPointer() const { return Storage.getOpaqueValue(); } + + /// \brief Build a template name from a void pointer. + static TemplateName getFromVoidPointer(void *Ptr) { + return TemplateName(Ptr); + } +}; + +/// Insertion operator for diagnostics. This allows sending TemplateName's +/// into a diagnostic with <<. +const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + TemplateName N); + +/// \brief A structure for storing the information associated with a +/// substituted template template parameter. +class SubstTemplateTemplateParmStorage + : public UncommonTemplateNameStorage, public llvm::FoldingSetNode { + friend class ASTContext; + + TemplateTemplateParmDecl *Parameter; + TemplateName Replacement; + + SubstTemplateTemplateParmStorage(TemplateTemplateParmDecl *parameter, + TemplateName replacement) + : UncommonTemplateNameStorage(SubstTemplateTemplateParm, 0), + Parameter(parameter), Replacement(replacement) {} + +public: + TemplateTemplateParmDecl *getParameter() const { return Parameter; } + TemplateName getReplacement() const { return Replacement; } + + void Profile(llvm::FoldingSetNodeID &ID); + + static void Profile(llvm::FoldingSetNodeID &ID, + TemplateTemplateParmDecl *parameter, + TemplateName replacement); +}; + +inline TemplateName::TemplateName(SubstTemplateTemplateParmStorage *Storage) + : Storage(Storage) { } + +inline TemplateName TemplateName::getUnderlying() const { + if (SubstTemplateTemplateParmStorage *subst + = getAsSubstTemplateTemplateParm()) + return subst->getReplacement().getUnderlying(); + return *this; +} + +/// \brief Represents a template name that was expressed as a +/// qualified name. +/// +/// This kind of template name refers to a template name that was +/// preceded by a nested name specifier, e.g., \c std::vector. Here, +/// the nested name specifier is "std::" and the template name is the +/// declaration for "vector". The QualifiedTemplateName class is only +/// used to provide "sugar" for template names that were expressed +/// with a qualified name, and has no semantic meaning. In this +/// manner, it is to TemplateName what ElaboratedType is to Type, +/// providing extra syntactic sugar for downstream clients. +class QualifiedTemplateName : public llvm::FoldingSetNode { + /// \brief The nested name specifier that qualifies the template name. + /// + /// The bit is used to indicate whether the "template" keyword was + /// present before the template name itself. Note that the + /// "template" keyword is always redundant in this case (otherwise, + /// the template name would be a dependent name and we would express + /// this name with DependentTemplateName). + llvm::PointerIntPair<NestedNameSpecifier *, 1> Qualifier; + + /// \brief The template declaration or set of overloaded function templates + /// that this qualified name refers to. + TemplateDecl *Template; + + friend class ASTContext; + + QualifiedTemplateName(NestedNameSpecifier *NNS, bool TemplateKeyword, + TemplateDecl *Template) + : Qualifier(NNS, TemplateKeyword? 1 : 0), + Template(Template) { } + +public: + /// \brief Return the nested name specifier that qualifies this name. + NestedNameSpecifier *getQualifier() const { return Qualifier.getPointer(); } + + /// \brief Whether the template name was prefixed by the "template" + /// keyword. + bool hasTemplateKeyword() const { return Qualifier.getInt(); } + + /// \brief The template declaration that this qualified name refers + /// to. + TemplateDecl *getDecl() const { return Template; } + + /// \brief The template declaration to which this qualified name + /// refers. + TemplateDecl *getTemplateDecl() const { return Template; } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getQualifier(), hasTemplateKeyword(), getTemplateDecl()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS, + bool TemplateKeyword, TemplateDecl *Template) { + ID.AddPointer(NNS); + ID.AddBoolean(TemplateKeyword); + ID.AddPointer(Template); + } +}; + +/// \brief Represents a dependent template name that cannot be +/// resolved prior to template instantiation. +/// +/// This kind of template name refers to a dependent template name, +/// including its nested name specifier (if any). For example, +/// DependentTemplateName can refer to "MetaFun::template apply", +/// where "MetaFun::" is the nested name specifier and "apply" is the +/// template name referenced. The "template" keyword is implied. +class DependentTemplateName : public llvm::FoldingSetNode { + /// \brief The nested name specifier that qualifies the template + /// name. + /// + /// The bit stored in this qualifier describes whether the \c Name field + /// is interpreted as an IdentifierInfo pointer (when clear) or as an + /// overloaded operator kind (when set). + llvm::PointerIntPair<NestedNameSpecifier *, 1, bool> Qualifier; + + /// \brief The dependent template name. + union { + /// \brief The identifier template name. + /// + /// Only valid when the bit on \c Qualifier is clear. + const IdentifierInfo *Identifier; + + /// \brief The overloaded operator name. + /// + /// Only valid when the bit on \c Qualifier is set. + OverloadedOperatorKind Operator; + }; + + /// \brief The canonical template name to which this dependent + /// template name refers. + /// + /// The canonical template name for a dependent template name is + /// another dependent template name whose nested name specifier is + /// canonical. + TemplateName CanonicalTemplateName; + + friend class ASTContext; + + DependentTemplateName(NestedNameSpecifier *Qualifier, + const IdentifierInfo *Identifier) + : Qualifier(Qualifier, false), Identifier(Identifier), + CanonicalTemplateName(this) { } + + DependentTemplateName(NestedNameSpecifier *Qualifier, + const IdentifierInfo *Identifier, + TemplateName Canon) + : Qualifier(Qualifier, false), Identifier(Identifier), + CanonicalTemplateName(Canon) { } + + DependentTemplateName(NestedNameSpecifier *Qualifier, + OverloadedOperatorKind Operator) + : Qualifier(Qualifier, true), Operator(Operator), + CanonicalTemplateName(this) { } + + DependentTemplateName(NestedNameSpecifier *Qualifier, + OverloadedOperatorKind Operator, + TemplateName Canon) + : Qualifier(Qualifier, true), Operator(Operator), + CanonicalTemplateName(Canon) { } + +public: + /// \brief Return the nested name specifier that qualifies this name. + NestedNameSpecifier *getQualifier() const { return Qualifier.getPointer(); } + + /// \brief Determine whether this template name refers to an identifier. + bool isIdentifier() const { return !Qualifier.getInt(); } + + /// \brief Returns the identifier to which this template name refers. + const IdentifierInfo *getIdentifier() const { + assert(isIdentifier() && "Template name isn't an identifier?"); + return Identifier; + } + + /// \brief Determine whether this template name refers to an overloaded + /// operator. + bool isOverloadedOperator() const { return Qualifier.getInt(); } + + /// \brief Return the overloaded operator to which this template name refers. + OverloadedOperatorKind getOperator() const { + assert(isOverloadedOperator() && + "Template name isn't an overloaded operator?"); + return Operator; + } + + void Profile(llvm::FoldingSetNodeID &ID) { + if (isIdentifier()) + Profile(ID, getQualifier(), getIdentifier()); + else + Profile(ID, getQualifier(), getOperator()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS, + const IdentifierInfo *Identifier) { + ID.AddPointer(NNS); + ID.AddBoolean(false); + ID.AddPointer(Identifier); + } + + static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS, + OverloadedOperatorKind Operator) { + ID.AddPointer(NNS); + ID.AddBoolean(true); + ID.AddInteger(Operator); + } +}; + +} // end namespace clang. + +namespace llvm { + +/// \brief The clang::TemplateName class is effectively a pointer. +template<> +class PointerLikeTypeTraits<clang::TemplateName> { +public: + static inline void *getAsVoidPointer(clang::TemplateName TN) { + return TN.getAsVoidPointer(); + } + + static inline clang::TemplateName getFromVoidPointer(void *Ptr) { + return clang::TemplateName::getFromVoidPointer(Ptr); + } + + // No bits are available! + enum { NumLowBitsAvailable = 0 }; +}; + +} // end namespace llvm. + +#endif diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h new file mode 100644 index 0000000..7b615c1 --- /dev/null +++ b/clang/include/clang/AST/Type.h @@ -0,0 +1,5022 @@ +//===--- Type.h - C Language Family Type Representation ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Type interface and subclasses. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_TYPE_H +#define LLVM_CLANG_AST_TYPE_H + +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/ExceptionSpecificationType.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/Linkage.h" +#include "clang/Basic/PartialDiagnostic.h" +#include "clang/Basic/Visibility.h" +#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/TemplateName.h" +#include "llvm/Support/type_traits.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/ADT/APSInt.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/PointerUnion.h" +#include "clang/Basic/LLVM.h" + +namespace clang { + enum { + TypeAlignmentInBits = 4, + TypeAlignment = 1 << TypeAlignmentInBits + }; + class Type; + class ExtQuals; + class QualType; +} + +namespace llvm { + template <typename T> + class PointerLikeTypeTraits; + template<> + class PointerLikeTypeTraits< ::clang::Type*> { + public: + static inline void *getAsVoidPointer(::clang::Type *P) { return P; } + static inline ::clang::Type *getFromVoidPointer(void *P) { + return static_cast< ::clang::Type*>(P); + } + enum { NumLowBitsAvailable = clang::TypeAlignmentInBits }; + }; + template<> + class PointerLikeTypeTraits< ::clang::ExtQuals*> { + public: + static inline void *getAsVoidPointer(::clang::ExtQuals *P) { return P; } + static inline ::clang::ExtQuals *getFromVoidPointer(void *P) { + return static_cast< ::clang::ExtQuals*>(P); + } + enum { NumLowBitsAvailable = clang::TypeAlignmentInBits }; + }; + + template <> + struct isPodLike<clang::QualType> { static const bool value = true; }; +} + +namespace clang { + class ASTContext; + class TypedefNameDecl; + class TemplateDecl; + class TemplateTypeParmDecl; + class NonTypeTemplateParmDecl; + class TemplateTemplateParmDecl; + class TagDecl; + class RecordDecl; + class CXXRecordDecl; + class EnumDecl; + class FieldDecl; + class FunctionDecl; + class ObjCInterfaceDecl; + class ObjCProtocolDecl; + class ObjCMethodDecl; + class UnresolvedUsingTypenameDecl; + class Expr; + class Stmt; + class SourceLocation; + class StmtIteratorBase; + class TemplateArgument; + class TemplateArgumentLoc; + class TemplateArgumentListInfo; + class ElaboratedType; + class ExtQuals; + class ExtQualsTypeCommonBase; + struct PrintingPolicy; + + template <typename> class CanQual; + typedef CanQual<Type> CanQualType; + + // Provide forward declarations for all of the *Type classes +#define TYPE(Class, Base) class Class##Type; +#include "clang/AST/TypeNodes.def" + +/// Qualifiers - The collection of all-type qualifiers we support. +/// Clang supports five independent qualifiers: +/// * C99: const, volatile, and restrict +/// * Embedded C (TR18037): address spaces +/// * Objective C: the GC attributes (none, weak, or strong) +class Qualifiers { +public: + enum TQ { // NOTE: These flags must be kept in sync with DeclSpec::TQ. + Const = 0x1, + Restrict = 0x2, + Volatile = 0x4, + CVRMask = Const | Volatile | Restrict + }; + + enum GC { + GCNone = 0, + Weak, + Strong + }; + + enum ObjCLifetime { + /// There is no lifetime qualification on this type. + OCL_None, + + /// This object can be modified without requiring retains or + /// releases. + OCL_ExplicitNone, + + /// Assigning into this object requires the old value to be + /// released and the new value to be retained. The timing of the + /// release of the old value is inexact: it may be moved to + /// immediately after the last known point where the value is + /// live. + OCL_Strong, + + /// Reading or writing from this object requires a barrier call. + OCL_Weak, + + /// Assigning into this object requires a lifetime extension. + OCL_Autoreleasing + }; + + enum { + /// The maximum supported address space number. + /// 24 bits should be enough for anyone. + MaxAddressSpace = 0xffffffu, + + /// The width of the "fast" qualifier mask. + FastWidth = 3, + + /// The fast qualifier mask. + FastMask = (1 << FastWidth) - 1 + }; + + Qualifiers() : Mask(0) {} + + static Qualifiers fromFastMask(unsigned Mask) { + Qualifiers Qs; + Qs.addFastQualifiers(Mask); + return Qs; + } + + static Qualifiers fromCVRMask(unsigned CVR) { + Qualifiers Qs; + Qs.addCVRQualifiers(CVR); + return Qs; + } + + // Deserialize qualifiers from an opaque representation. + static Qualifiers fromOpaqueValue(unsigned opaque) { + Qualifiers Qs; + Qs.Mask = opaque; + return Qs; + } + + // Serialize these qualifiers into an opaque representation. + unsigned getAsOpaqueValue() const { + return Mask; + } + + bool hasConst() const { return Mask & Const; } + void setConst(bool flag) { + Mask = (Mask & ~Const) | (flag ? Const : 0); + } + void removeConst() { Mask &= ~Const; } + void addConst() { Mask |= Const; } + + bool hasVolatile() const { return Mask & Volatile; } + void setVolatile(bool flag) { + Mask = (Mask & ~Volatile) | (flag ? Volatile : 0); + } + void removeVolatile() { Mask &= ~Volatile; } + void addVolatile() { Mask |= Volatile; } + + bool hasRestrict() const { return Mask & Restrict; } + void setRestrict(bool flag) { + Mask = (Mask & ~Restrict) | (flag ? Restrict : 0); + } + void removeRestrict() { Mask &= ~Restrict; } + void addRestrict() { Mask |= Restrict; } + + bool hasCVRQualifiers() const { return getCVRQualifiers(); } + unsigned getCVRQualifiers() const { return Mask & CVRMask; } + void setCVRQualifiers(unsigned mask) { + assert(!(mask & ~CVRMask) && "bitmask contains non-CVR bits"); + Mask = (Mask & ~CVRMask) | mask; + } + void removeCVRQualifiers(unsigned mask) { + assert(!(mask & ~CVRMask) && "bitmask contains non-CVR bits"); + Mask &= ~mask; + } + void removeCVRQualifiers() { + removeCVRQualifiers(CVRMask); + } + void addCVRQualifiers(unsigned mask) { + assert(!(mask & ~CVRMask) && "bitmask contains non-CVR bits"); + Mask |= mask; + } + + bool hasObjCGCAttr() const { return Mask & GCAttrMask; } + GC getObjCGCAttr() const { return GC((Mask & GCAttrMask) >> GCAttrShift); } + void setObjCGCAttr(GC type) { + Mask = (Mask & ~GCAttrMask) | (type << GCAttrShift); + } + void removeObjCGCAttr() { setObjCGCAttr(GCNone); } + void addObjCGCAttr(GC type) { + assert(type); + setObjCGCAttr(type); + } + Qualifiers withoutObjCGCAttr() const { + Qualifiers qs = *this; + qs.removeObjCGCAttr(); + return qs; + } + Qualifiers withoutObjCLifetime() const { + Qualifiers qs = *this; + qs.removeObjCLifetime(); + return qs; + } + + bool hasObjCLifetime() const { return Mask & LifetimeMask; } + ObjCLifetime getObjCLifetime() const { + return ObjCLifetime((Mask & LifetimeMask) >> LifetimeShift); + } + void setObjCLifetime(ObjCLifetime type) { + Mask = (Mask & ~LifetimeMask) | (type << LifetimeShift); + } + void removeObjCLifetime() { setObjCLifetime(OCL_None); } + void addObjCLifetime(ObjCLifetime type) { + assert(type); + assert(!hasObjCLifetime()); + Mask |= (type << LifetimeShift); + } + + /// True if the lifetime is neither None or ExplicitNone. + bool hasNonTrivialObjCLifetime() const { + ObjCLifetime lifetime = getObjCLifetime(); + return (lifetime > OCL_ExplicitNone); + } + + /// True if the lifetime is either strong or weak. + bool hasStrongOrWeakObjCLifetime() const { + ObjCLifetime lifetime = getObjCLifetime(); + return (lifetime == OCL_Strong || lifetime == OCL_Weak); + } + + bool hasAddressSpace() const { return Mask & AddressSpaceMask; } + unsigned getAddressSpace() const { return Mask >> AddressSpaceShift; } + void setAddressSpace(unsigned space) { + assert(space <= MaxAddressSpace); + Mask = (Mask & ~AddressSpaceMask) + | (((uint32_t) space) << AddressSpaceShift); + } + void removeAddressSpace() { setAddressSpace(0); } + void addAddressSpace(unsigned space) { + assert(space); + setAddressSpace(space); + } + + // Fast qualifiers are those that can be allocated directly + // on a QualType object. + bool hasFastQualifiers() const { return getFastQualifiers(); } + unsigned getFastQualifiers() const { return Mask & FastMask; } + void setFastQualifiers(unsigned mask) { + assert(!(mask & ~FastMask) && "bitmask contains non-fast qualifier bits"); + Mask = (Mask & ~FastMask) | mask; + } + void removeFastQualifiers(unsigned mask) { + assert(!(mask & ~FastMask) && "bitmask contains non-fast qualifier bits"); + Mask &= ~mask; + } + void removeFastQualifiers() { + removeFastQualifiers(FastMask); + } + void addFastQualifiers(unsigned mask) { + assert(!(mask & ~FastMask) && "bitmask contains non-fast qualifier bits"); + Mask |= mask; + } + + /// hasNonFastQualifiers - Return true if the set contains any + /// qualifiers which require an ExtQuals node to be allocated. + bool hasNonFastQualifiers() const { return Mask & ~FastMask; } + Qualifiers getNonFastQualifiers() const { + Qualifiers Quals = *this; + Quals.setFastQualifiers(0); + return Quals; + } + + /// hasQualifiers - Return true if the set contains any qualifiers. + bool hasQualifiers() const { return Mask; } + bool empty() const { return !Mask; } + + /// \brief Add the qualifiers from the given set to this set. + void addQualifiers(Qualifiers Q) { + // If the other set doesn't have any non-boolean qualifiers, just + // bit-or it in. + if (!(Q.Mask & ~CVRMask)) + Mask |= Q.Mask; + else { + Mask |= (Q.Mask & CVRMask); + if (Q.hasAddressSpace()) + addAddressSpace(Q.getAddressSpace()); + if (Q.hasObjCGCAttr()) + addObjCGCAttr(Q.getObjCGCAttr()); + if (Q.hasObjCLifetime()) + addObjCLifetime(Q.getObjCLifetime()); + } + } + + /// \brief Add the qualifiers from the given set to this set, given that + /// they don't conflict. + void addConsistentQualifiers(Qualifiers qs) { + assert(getAddressSpace() == qs.getAddressSpace() || + !hasAddressSpace() || !qs.hasAddressSpace()); + assert(getObjCGCAttr() == qs.getObjCGCAttr() || + !hasObjCGCAttr() || !qs.hasObjCGCAttr()); + assert(getObjCLifetime() == qs.getObjCLifetime() || + !hasObjCLifetime() || !qs.hasObjCLifetime()); + Mask |= qs.Mask; + } + + /// \brief Determines if these qualifiers compatibly include another set. + /// Generally this answers the question of whether an object with the other + /// qualifiers can be safely used as an object with these qualifiers. + bool compatiblyIncludes(Qualifiers other) const { + return + // Address spaces must match exactly. + getAddressSpace() == other.getAddressSpace() && + // ObjC GC qualifiers can match, be added, or be removed, but can't be + // changed. + (getObjCGCAttr() == other.getObjCGCAttr() || + !hasObjCGCAttr() || !other.hasObjCGCAttr()) && + // ObjC lifetime qualifiers must match exactly. + getObjCLifetime() == other.getObjCLifetime() && + // CVR qualifiers may subset. + (((Mask & CVRMask) | (other.Mask & CVRMask)) == (Mask & CVRMask)); + } + + /// \brief Determines if these qualifiers compatibly include another set of + /// qualifiers from the narrow perspective of Objective-C ARC lifetime. + /// + /// One set of Objective-C lifetime qualifiers compatibly includes the other + /// if the lifetime qualifiers match, or if both are non-__weak and the + /// including set also contains the 'const' qualifier. + bool compatiblyIncludesObjCLifetime(Qualifiers other) const { + if (getObjCLifetime() == other.getObjCLifetime()) + return true; + + if (getObjCLifetime() == OCL_Weak || other.getObjCLifetime() == OCL_Weak) + return false; + + return hasConst(); + } + + bool isSupersetOf(Qualifiers Other) const; + + /// \brief Determine whether this set of qualifiers is a strict superset of + /// another set of qualifiers, not considering qualifier compatibility. + bool isStrictSupersetOf(Qualifiers Other) const; + + bool operator==(Qualifiers Other) const { return Mask == Other.Mask; } + bool operator!=(Qualifiers Other) const { return Mask != Other.Mask; } + + operator bool() const { return hasQualifiers(); } + + Qualifiers &operator+=(Qualifiers R) { + addQualifiers(R); + return *this; + } + + // Union two qualifier sets. If an enumerated qualifier appears + // in both sets, use the one from the right. + friend Qualifiers operator+(Qualifiers L, Qualifiers R) { + L += R; + return L; + } + + Qualifiers &operator-=(Qualifiers R) { + Mask = Mask & ~(R.Mask); + return *this; + } + + /// \brief Compute the difference between two qualifier sets. + friend Qualifiers operator-(Qualifiers L, Qualifiers R) { + L -= R; + return L; + } + + std::string getAsString() const; + std::string getAsString(const PrintingPolicy &Policy) const { + std::string Buffer; + getAsStringInternal(Buffer, Policy); + return Buffer; + } + void getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const; + + void Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddInteger(Mask); + } + +private: + + // bits: |0 1 2|3 .. 4|5 .. 7|8 ... 31| + // |C R V|GCAttr|Lifetime|AddressSpace| + uint32_t Mask; + + static const uint32_t GCAttrMask = 0x18; + static const uint32_t GCAttrShift = 3; + static const uint32_t LifetimeMask = 0xE0; + static const uint32_t LifetimeShift = 5; + static const uint32_t AddressSpaceMask = ~(CVRMask|GCAttrMask|LifetimeMask); + static const uint32_t AddressSpaceShift = 8; +}; + +/// CallingConv - Specifies the calling convention that a function uses. +enum CallingConv { + CC_Default, + CC_C, // __attribute__((cdecl)) + CC_X86StdCall, // __attribute__((stdcall)) + CC_X86FastCall, // __attribute__((fastcall)) + CC_X86ThisCall, // __attribute__((thiscall)) + CC_X86Pascal, // __attribute__((pascal)) + CC_AAPCS, // __attribute__((pcs("aapcs"))) + CC_AAPCS_VFP // __attribute__((pcs("aapcs-vfp"))) +}; + +/// A std::pair-like structure for storing a qualified type split +/// into its local qualifiers and its locally-unqualified type. +struct SplitQualType { + /// The locally-unqualified type. + const Type *Ty; + + /// The local qualifiers. + Qualifiers Quals; + + SplitQualType() : Ty(0), Quals() {} + SplitQualType(const Type *ty, Qualifiers qs) : Ty(ty), Quals(qs) {} + + SplitQualType getSingleStepDesugaredType() const; // end of this file + + // Make llvm::tie work. + operator std::pair<const Type *,Qualifiers>() const { + return std::pair<const Type *,Qualifiers>(Ty, Quals); + } + + friend bool operator==(SplitQualType a, SplitQualType b) { + return a.Ty == b.Ty && a.Quals == b.Quals; + } + friend bool operator!=(SplitQualType a, SplitQualType b) { + return a.Ty != b.Ty || a.Quals != b.Quals; + } +}; + +/// QualType - For efficiency, we don't store CV-qualified types as nodes on +/// their own: instead each reference to a type stores the qualifiers. This +/// greatly reduces the number of nodes we need to allocate for types (for +/// example we only need one for 'int', 'const int', 'volatile int', +/// 'const volatile int', etc). +/// +/// As an added efficiency bonus, instead of making this a pair, we +/// just store the two bits we care about in the low bits of the +/// pointer. To handle the packing/unpacking, we make QualType be a +/// simple wrapper class that acts like a smart pointer. A third bit +/// indicates whether there are extended qualifiers present, in which +/// case the pointer points to a special structure. +class QualType { + // Thankfully, these are efficiently composable. + llvm::PointerIntPair<llvm::PointerUnion<const Type*,const ExtQuals*>, + Qualifiers::FastWidth> Value; + + const ExtQuals *getExtQualsUnsafe() const { + return Value.getPointer().get<const ExtQuals*>(); + } + + const Type *getTypePtrUnsafe() const { + return Value.getPointer().get<const Type*>(); + } + + const ExtQualsTypeCommonBase *getCommonPtr() const { + assert(!isNull() && "Cannot retrieve a NULL type pointer"); + uintptr_t CommonPtrVal + = reinterpret_cast<uintptr_t>(Value.getOpaqueValue()); + CommonPtrVal &= ~(uintptr_t)((1 << TypeAlignmentInBits) - 1); + return reinterpret_cast<ExtQualsTypeCommonBase*>(CommonPtrVal); + } + + friend class QualifierCollector; +public: + QualType() {} + + QualType(const Type *Ptr, unsigned Quals) + : Value(Ptr, Quals) {} + QualType(const ExtQuals *Ptr, unsigned Quals) + : Value(Ptr, Quals) {} + + unsigned getLocalFastQualifiers() const { return Value.getInt(); } + void setLocalFastQualifiers(unsigned Quals) { Value.setInt(Quals); } + + /// Retrieves a pointer to the underlying (unqualified) type. + /// This should really return a const Type, but it's not worth + /// changing all the users right now. + /// + /// This function requires that the type not be NULL. If the type might be + /// NULL, use the (slightly less efficient) \c getTypePtrOrNull(). + const Type *getTypePtr() const; + + const Type *getTypePtrOrNull() const; + + /// Retrieves a pointer to the name of the base type. + const IdentifierInfo *getBaseTypeIdentifier() const; + + /// Divides a QualType into its unqualified type and a set of local + /// qualifiers. + SplitQualType split() const; + + void *getAsOpaquePtr() const { return Value.getOpaqueValue(); } + static QualType getFromOpaquePtr(const void *Ptr) { + QualType T; + T.Value.setFromOpaqueValue(const_cast<void*>(Ptr)); + return T; + } + + const Type &operator*() const { + return *getTypePtr(); + } + + const Type *operator->() const { + return getTypePtr(); + } + + bool isCanonical() const; + bool isCanonicalAsParam() const; + + /// isNull - Return true if this QualType doesn't point to a type yet. + bool isNull() const { + return Value.getPointer().isNull(); + } + + /// \brief Determine whether this particular QualType instance has the + /// "const" qualifier set, without looking through typedefs that may have + /// added "const" at a different level. + bool isLocalConstQualified() const { + return (getLocalFastQualifiers() & Qualifiers::Const); + } + + /// \brief Determine whether this type is const-qualified. + bool isConstQualified() const; + + /// \brief Determine whether this particular QualType instance has the + /// "restrict" qualifier set, without looking through typedefs that may have + /// added "restrict" at a different level. + bool isLocalRestrictQualified() const { + return (getLocalFastQualifiers() & Qualifiers::Restrict); + } + + /// \brief Determine whether this type is restrict-qualified. + bool isRestrictQualified() const; + + /// \brief Determine whether this particular QualType instance has the + /// "volatile" qualifier set, without looking through typedefs that may have + /// added "volatile" at a different level. + bool isLocalVolatileQualified() const { + return (getLocalFastQualifiers() & Qualifiers::Volatile); + } + + /// \brief Determine whether this type is volatile-qualified. + bool isVolatileQualified() const; + + /// \brief Determine whether this particular QualType instance has any + /// qualifiers, without looking through any typedefs that might add + /// qualifiers at a different level. + bool hasLocalQualifiers() const { + return getLocalFastQualifiers() || hasLocalNonFastQualifiers(); + } + + /// \brief Determine whether this type has any qualifiers. + bool hasQualifiers() const; + + /// \brief Determine whether this particular QualType instance has any + /// "non-fast" qualifiers, e.g., those that are stored in an ExtQualType + /// instance. + bool hasLocalNonFastQualifiers() const { + return Value.getPointer().is<const ExtQuals*>(); + } + + /// \brief Retrieve the set of qualifiers local to this particular QualType + /// instance, not including any qualifiers acquired through typedefs or + /// other sugar. + Qualifiers getLocalQualifiers() const; + + /// \brief Retrieve the set of qualifiers applied to this type. + Qualifiers getQualifiers() const; + + /// \brief Retrieve the set of CVR (const-volatile-restrict) qualifiers + /// local to this particular QualType instance, not including any qualifiers + /// acquired through typedefs or other sugar. + unsigned getLocalCVRQualifiers() const { + return getLocalFastQualifiers(); + } + + /// \brief Retrieve the set of CVR (const-volatile-restrict) qualifiers + /// applied to this type. + unsigned getCVRQualifiers() const; + + bool isConstant(ASTContext& Ctx) const { + return QualType::isConstant(*this, Ctx); + } + + /// \brief Determine whether this is a Plain Old Data (POD) type (C++ 3.9p10). + bool isPODType(ASTContext &Context) const; + + /// isCXX11PODType() - Return true if this is a POD type according to the + /// more relaxed rules of the C++11 standard, regardless of the current + /// compilation's language. + /// (C++0x [basic.types]p9) + bool isCXX11PODType(ASTContext &Context) const; + + /// isTrivialType - Return true if this is a trivial type + /// (C++0x [basic.types]p9) + bool isTrivialType(ASTContext &Context) const; + + /// isTriviallyCopyableType - Return true if this is a trivially + /// copyable type (C++0x [basic.types]p9) + bool isTriviallyCopyableType(ASTContext &Context) const; + + // Don't promise in the API that anything besides 'const' can be + // easily added. + + /// addConst - add the specified type qualifier to this QualType. + void addConst() { + addFastQualifiers(Qualifiers::Const); + } + QualType withConst() const { + return withFastQualifiers(Qualifiers::Const); + } + + /// addVolatile - add the specified type qualifier to this QualType. + void addVolatile() { + addFastQualifiers(Qualifiers::Volatile); + } + QualType withVolatile() const { + return withFastQualifiers(Qualifiers::Volatile); + } + + /// Add the restrict qualifier to this QualType. + void addRestrict() { + addFastQualifiers(Qualifiers::Restrict); + } + QualType withRestrict() const { + return withFastQualifiers(Qualifiers::Restrict); + } + + QualType withCVRQualifiers(unsigned CVR) const { + return withFastQualifiers(CVR); + } + + void addFastQualifiers(unsigned TQs) { + assert(!(TQs & ~Qualifiers::FastMask) + && "non-fast qualifier bits set in mask!"); + Value.setInt(Value.getInt() | TQs); + } + + void removeLocalConst(); + void removeLocalVolatile(); + void removeLocalRestrict(); + void removeLocalCVRQualifiers(unsigned Mask); + + void removeLocalFastQualifiers() { Value.setInt(0); } + void removeLocalFastQualifiers(unsigned Mask) { + assert(!(Mask & ~Qualifiers::FastMask) && "mask has non-fast qualifiers"); + Value.setInt(Value.getInt() & ~Mask); + } + + // Creates a type with the given qualifiers in addition to any + // qualifiers already on this type. + QualType withFastQualifiers(unsigned TQs) const { + QualType T = *this; + T.addFastQualifiers(TQs); + return T; + } + + // Creates a type with exactly the given fast qualifiers, removing + // any existing fast qualifiers. + QualType withExactLocalFastQualifiers(unsigned TQs) const { + return withoutLocalFastQualifiers().withFastQualifiers(TQs); + } + + // Removes fast qualifiers, but leaves any extended qualifiers in place. + QualType withoutLocalFastQualifiers() const { + QualType T = *this; + T.removeLocalFastQualifiers(); + return T; + } + + QualType getCanonicalType() const; + + /// \brief Return this type with all of the instance-specific qualifiers + /// removed, but without removing any qualifiers that may have been applied + /// through typedefs. + QualType getLocalUnqualifiedType() const { return QualType(getTypePtr(), 0); } + + /// \brief Retrieve the unqualified variant of the given type, + /// removing as little sugar as possible. + /// + /// This routine looks through various kinds of sugar to find the + /// least-desugared type that is unqualified. For example, given: + /// + /// \code + /// typedef int Integer; + /// typedef const Integer CInteger; + /// typedef CInteger DifferenceType; + /// \endcode + /// + /// Executing \c getUnqualifiedType() on the type \c DifferenceType will + /// desugar until we hit the type \c Integer, which has no qualifiers on it. + /// + /// The resulting type might still be qualified if it's an array + /// type. To strip qualifiers even from within an array type, use + /// ASTContext::getUnqualifiedArrayType. + inline QualType getUnqualifiedType() const; + + /// getSplitUnqualifiedType - Retrieve the unqualified variant of the + /// given type, removing as little sugar as possible. + /// + /// Like getUnqualifiedType(), but also returns the set of + /// qualifiers that were built up. + /// + /// The resulting type might still be qualified if it's an array + /// type. To strip qualifiers even from within an array type, use + /// ASTContext::getUnqualifiedArrayType. + inline SplitQualType getSplitUnqualifiedType() const; + + /// \brief Determine whether this type is more qualified than the other + /// given type, requiring exact equality for non-CVR qualifiers. + bool isMoreQualifiedThan(QualType Other) const; + + /// \brief Determine whether this type is at least as qualified as the other + /// given type, requiring exact equality for non-CVR qualifiers. + bool isAtLeastAsQualifiedAs(QualType Other) const; + + QualType getNonReferenceType() const; + + /// \brief Determine the type of a (typically non-lvalue) expression with the + /// specified result type. + /// + /// This routine should be used for expressions for which the return type is + /// explicitly specified (e.g., in a cast or call) and isn't necessarily + /// an lvalue. It removes a top-level reference (since there are no + /// expressions of reference type) and deletes top-level cvr-qualifiers + /// from non-class types (in C++) or all types (in C). + QualType getNonLValueExprType(ASTContext &Context) const; + + /// getDesugaredType - Return the specified type with any "sugar" removed from + /// the type. This takes off typedefs, typeof's etc. If the outer level of + /// the type is already concrete, it returns it unmodified. This is similar + /// to getting the canonical type, but it doesn't remove *all* typedefs. For + /// example, it returns "T*" as "T*", (not as "int*"), because the pointer is + /// concrete. + /// + /// Qualifiers are left in place. + QualType getDesugaredType(const ASTContext &Context) const { + return getDesugaredType(*this, Context); + } + + SplitQualType getSplitDesugaredType() const { + return getSplitDesugaredType(*this); + } + + /// \brief Return the specified type with one level of "sugar" removed from + /// the type. + /// + /// This routine takes off the first typedef, typeof, etc. If the outer level + /// of the type is already concrete, it returns it unmodified. + QualType getSingleStepDesugaredType(const ASTContext &Context) const { + return getSingleStepDesugaredTypeImpl(*this, Context); + } + + /// IgnoreParens - Returns the specified type after dropping any + /// outer-level parentheses. + QualType IgnoreParens() const { + if (isa<ParenType>(*this)) + return QualType::IgnoreParens(*this); + return *this; + } + + /// operator==/!= - Indicate whether the specified types and qualifiers are + /// identical. + friend bool operator==(const QualType &LHS, const QualType &RHS) { + return LHS.Value == RHS.Value; + } + friend bool operator!=(const QualType &LHS, const QualType &RHS) { + return LHS.Value != RHS.Value; + } + std::string getAsString() const { + return getAsString(split()); + } + static std::string getAsString(SplitQualType split) { + return getAsString(split.Ty, split.Quals); + } + static std::string getAsString(const Type *ty, Qualifiers qs); + + std::string getAsString(const PrintingPolicy &Policy) const { + std::string S; + getAsStringInternal(S, Policy); + return S; + } + void getAsStringInternal(std::string &Str, + const PrintingPolicy &Policy) const { + return getAsStringInternal(split(), Str, Policy); + } + static void getAsStringInternal(SplitQualType split, std::string &out, + const PrintingPolicy &policy) { + return getAsStringInternal(split.Ty, split.Quals, out, policy); + } + static void getAsStringInternal(const Type *ty, Qualifiers qs, + std::string &out, + const PrintingPolicy &policy); + + void dump(const char *s) const; + void dump() const; + + void Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddPointer(getAsOpaquePtr()); + } + + /// getAddressSpace - Return the address space of this type. + inline unsigned getAddressSpace() const; + + /// getObjCGCAttr - Returns gc attribute of this type. + inline Qualifiers::GC getObjCGCAttr() const; + + /// isObjCGCWeak true when Type is objc's weak. + bool isObjCGCWeak() const { + return getObjCGCAttr() == Qualifiers::Weak; + } + + /// isObjCGCStrong true when Type is objc's strong. + bool isObjCGCStrong() const { + return getObjCGCAttr() == Qualifiers::Strong; + } + + /// getObjCLifetime - Returns lifetime attribute of this type. + Qualifiers::ObjCLifetime getObjCLifetime() const { + return getQualifiers().getObjCLifetime(); + } + + bool hasNonTrivialObjCLifetime() const { + return getQualifiers().hasNonTrivialObjCLifetime(); + } + + bool hasStrongOrWeakObjCLifetime() const { + return getQualifiers().hasStrongOrWeakObjCLifetime(); + } + + enum DestructionKind { + DK_none, + DK_cxx_destructor, + DK_objc_strong_lifetime, + DK_objc_weak_lifetime + }; + + /// isDestructedType - nonzero if objects of this type require + /// non-trivial work to clean up after. Non-zero because it's + /// conceivable that qualifiers (objc_gc(weak)?) could make + /// something require destruction. + DestructionKind isDestructedType() const { + return isDestructedTypeImpl(*this); + } + + /// \brief Determine whether expressions of the given type are forbidden + /// from being lvalues in C. + /// + /// The expression types that are forbidden to be lvalues are: + /// - 'void', but not qualified void + /// - function types + /// + /// The exact rule here is C99 6.3.2.1: + /// An lvalue is an expression with an object type or an incomplete + /// type other than void. + bool isCForbiddenLValueType() const; + + /// \brief Determine whether this type has trivial copy/move-assignment + /// semantics. + bool hasTrivialAssignment(ASTContext &Context, bool Copying) const; + +private: + // These methods are implemented in a separate translation unit; + // "static"-ize them to avoid creating temporary QualTypes in the + // caller. + static bool isConstant(QualType T, ASTContext& Ctx); + static QualType getDesugaredType(QualType T, const ASTContext &Context); + static SplitQualType getSplitDesugaredType(QualType T); + static SplitQualType getSplitUnqualifiedTypeImpl(QualType type); + static QualType getSingleStepDesugaredTypeImpl(QualType type, + const ASTContext &C); + static QualType IgnoreParens(QualType T); + static DestructionKind isDestructedTypeImpl(QualType type); +}; + +} // end clang. + +namespace llvm { +/// Implement simplify_type for QualType, so that we can dyn_cast from QualType +/// to a specific Type class. +template<> struct simplify_type<const ::clang::QualType> { + typedef const ::clang::Type *SimpleType; + static SimpleType getSimplifiedValue(const ::clang::QualType &Val) { + return Val.getTypePtr(); + } +}; +template<> struct simplify_type< ::clang::QualType> + : public simplify_type<const ::clang::QualType> {}; + +// Teach SmallPtrSet that QualType is "basically a pointer". +template<> +class PointerLikeTypeTraits<clang::QualType> { +public: + static inline void *getAsVoidPointer(clang::QualType P) { + return P.getAsOpaquePtr(); + } + static inline clang::QualType getFromVoidPointer(void *P) { + return clang::QualType::getFromOpaquePtr(P); + } + // Various qualifiers go in low bits. + enum { NumLowBitsAvailable = 0 }; +}; + +} // end namespace llvm + +namespace clang { + +/// \brief Base class that is common to both the \c ExtQuals and \c Type +/// classes, which allows \c QualType to access the common fields between the +/// two. +/// +class ExtQualsTypeCommonBase { + ExtQualsTypeCommonBase(const Type *baseType, QualType canon) + : BaseType(baseType), CanonicalType(canon) {} + + /// \brief The "base" type of an extended qualifiers type (\c ExtQuals) or + /// a self-referential pointer (for \c Type). + /// + /// This pointer allows an efficient mapping from a QualType to its + /// underlying type pointer. + const Type *const BaseType; + + /// \brief The canonical type of this type. A QualType. + QualType CanonicalType; + + friend class QualType; + friend class Type; + friend class ExtQuals; +}; + +/// ExtQuals - We can encode up to four bits in the low bits of a +/// type pointer, but there are many more type qualifiers that we want +/// to be able to apply to an arbitrary type. Therefore we have this +/// struct, intended to be heap-allocated and used by QualType to +/// store qualifiers. +/// +/// The current design tags the 'const', 'restrict', and 'volatile' qualifiers +/// in three low bits on the QualType pointer; a fourth bit records whether +/// the pointer is an ExtQuals node. The extended qualifiers (address spaces, +/// Objective-C GC attributes) are much more rare. +class ExtQuals : public ExtQualsTypeCommonBase, public llvm::FoldingSetNode { + // NOTE: changing the fast qualifiers should be straightforward as + // long as you don't make 'const' non-fast. + // 1. Qualifiers: + // a) Modify the bitmasks (Qualifiers::TQ and DeclSpec::TQ). + // Fast qualifiers must occupy the low-order bits. + // b) Update Qualifiers::FastWidth and FastMask. + // 2. QualType: + // a) Update is{Volatile,Restrict}Qualified(), defined inline. + // b) Update remove{Volatile,Restrict}, defined near the end of + // this header. + // 3. ASTContext: + // a) Update get{Volatile,Restrict}Type. + + /// Quals - the immutable set of qualifiers applied by this + /// node; always contains extended qualifiers. + Qualifiers Quals; + + ExtQuals *this_() { return this; } + +public: + ExtQuals(const Type *baseType, QualType canon, Qualifiers quals) + : ExtQualsTypeCommonBase(baseType, + canon.isNull() ? QualType(this_(), 0) : canon), + Quals(quals) + { + assert(Quals.hasNonFastQualifiers() + && "ExtQuals created with no fast qualifiers"); + assert(!Quals.hasFastQualifiers() + && "ExtQuals created with fast qualifiers"); + } + + Qualifiers getQualifiers() const { return Quals; } + + bool hasObjCGCAttr() const { return Quals.hasObjCGCAttr(); } + Qualifiers::GC getObjCGCAttr() const { return Quals.getObjCGCAttr(); } + + bool hasObjCLifetime() const { return Quals.hasObjCLifetime(); } + Qualifiers::ObjCLifetime getObjCLifetime() const { + return Quals.getObjCLifetime(); + } + + bool hasAddressSpace() const { return Quals.hasAddressSpace(); } + unsigned getAddressSpace() const { return Quals.getAddressSpace(); } + + const Type *getBaseType() const { return BaseType; } + +public: + void Profile(llvm::FoldingSetNodeID &ID) const { + Profile(ID, getBaseType(), Quals); + } + static void Profile(llvm::FoldingSetNodeID &ID, + const Type *BaseType, + Qualifiers Quals) { + assert(!Quals.hasFastQualifiers() && "fast qualifiers in ExtQuals hash!"); + ID.AddPointer(BaseType); + Quals.Profile(ID); + } +}; + +/// \brief The kind of C++0x ref-qualifier associated with a function type, +/// which determines whether a member function's "this" object can be an +/// lvalue, rvalue, or neither. +enum RefQualifierKind { + /// \brief No ref-qualifier was provided. + RQ_None = 0, + /// \brief An lvalue ref-qualifier was provided (\c &). + RQ_LValue, + /// \brief An rvalue ref-qualifier was provided (\c &&). + RQ_RValue +}; + +/// Type - This is the base class of the type hierarchy. A central concept +/// with types is that each type always has a canonical type. A canonical type +/// is the type with any typedef names stripped out of it or the types it +/// references. For example, consider: +/// +/// typedef int foo; +/// typedef foo* bar; +/// 'int *' 'foo *' 'bar' +/// +/// There will be a Type object created for 'int'. Since int is canonical, its +/// canonicaltype pointer points to itself. There is also a Type for 'foo' (a +/// TypedefType). Its CanonicalType pointer points to the 'int' Type. Next +/// there is a PointerType that represents 'int*', which, like 'int', is +/// canonical. Finally, there is a PointerType type for 'foo*' whose canonical +/// type is 'int*', and there is a TypedefType for 'bar', whose canonical type +/// is also 'int*'. +/// +/// Non-canonical types are useful for emitting diagnostics, without losing +/// information about typedefs being used. Canonical types are useful for type +/// comparisons (they allow by-pointer equality tests) and useful for reasoning +/// about whether something has a particular form (e.g. is a function type), +/// because they implicitly, recursively, strip all typedefs out of a type. +/// +/// Types, once created, are immutable. +/// +class Type : public ExtQualsTypeCommonBase { +public: + enum TypeClass { +#define TYPE(Class, Base) Class, +#define LAST_TYPE(Class) TypeLast = Class, +#define ABSTRACT_TYPE(Class, Base) +#include "clang/AST/TypeNodes.def" + TagFirst = Record, TagLast = Enum + }; + +private: + Type(const Type&); // DO NOT IMPLEMENT. + void operator=(const Type&); // DO NOT IMPLEMENT. + + /// Bitfields required by the Type class. + class TypeBitfields { + friend class Type; + template <class T> friend class TypePropertyCache; + + /// TypeClass bitfield - Enum that specifies what subclass this belongs to. + unsigned TC : 8; + + /// Dependent - Whether this type is a dependent type (C++ [temp.dep.type]). + /// Note that this should stay at the end of the ivars for Type so that + /// subclasses can pack their bitfields into the same word. + unsigned Dependent : 1; + + /// \brief Whether this type somehow involves a template parameter, even + /// if the resolution of the type does not depend on a template parameter. + unsigned InstantiationDependent : 1; + + /// \brief Whether this type is a variably-modified type (C99 6.7.5). + unsigned VariablyModified : 1; + + /// \brief Whether this type contains an unexpanded parameter pack + /// (for C++0x variadic templates). + unsigned ContainsUnexpandedParameterPack : 1; + + /// \brief Nonzero if the cache (i.e. the bitfields here starting + /// with 'Cache') is valid. If so, then this is a + /// LangOptions::VisibilityMode+1. + mutable unsigned CacheValidAndVisibility : 2; + + /// \brief True if the visibility was set explicitly in the source code. + mutable unsigned CachedExplicitVisibility : 1; + + /// \brief Linkage of this type. + mutable unsigned CachedLinkage : 2; + + /// \brief Whether this type involves and local or unnamed types. + mutable unsigned CachedLocalOrUnnamed : 1; + + /// \brief FromAST - Whether this type comes from an AST file. + mutable unsigned FromAST : 1; + + bool isCacheValid() const { + return (CacheValidAndVisibility != 0); + } + Visibility getVisibility() const { + assert(isCacheValid() && "getting linkage from invalid cache"); + return static_cast<Visibility>(CacheValidAndVisibility-1); + } + bool isVisibilityExplicit() const { + assert(isCacheValid() && "getting linkage from invalid cache"); + return CachedExplicitVisibility; + } + Linkage getLinkage() const { + assert(isCacheValid() && "getting linkage from invalid cache"); + return static_cast<Linkage>(CachedLinkage); + } + bool hasLocalOrUnnamedType() const { + assert(isCacheValid() && "getting linkage from invalid cache"); + return CachedLocalOrUnnamed; + } + }; + enum { NumTypeBits = 19 }; + +protected: + // These classes allow subclasses to somewhat cleanly pack bitfields + // into Type. + + class ArrayTypeBitfields { + friend class ArrayType; + + unsigned : NumTypeBits; + + /// IndexTypeQuals - CVR qualifiers from declarations like + /// 'int X[static restrict 4]'. For function parameters only. + unsigned IndexTypeQuals : 3; + + /// SizeModifier - storage class qualifiers from declarations like + /// 'int X[static restrict 4]'. For function parameters only. + /// Actually an ArrayType::ArraySizeModifier. + unsigned SizeModifier : 3; + }; + + class BuiltinTypeBitfields { + friend class BuiltinType; + + unsigned : NumTypeBits; + + /// The kind (BuiltinType::Kind) of builtin type this is. + unsigned Kind : 8; + }; + + class FunctionTypeBitfields { + friend class FunctionType; + + unsigned : NumTypeBits; + + /// Extra information which affects how the function is called, like + /// regparm and the calling convention. + unsigned ExtInfo : 8; + + /// TypeQuals - Used only by FunctionProtoType, put here to pack with the + /// other bitfields. + /// The qualifiers are part of FunctionProtoType because... + /// + /// C++ 8.3.5p4: The return type, the parameter type list and the + /// cv-qualifier-seq, [...], are part of the function type. + unsigned TypeQuals : 3; + + /// \brief The ref-qualifier associated with a \c FunctionProtoType. + /// + /// This is a value of type \c RefQualifierKind. + unsigned RefQualifier : 2; + }; + + class ObjCObjectTypeBitfields { + friend class ObjCObjectType; + + unsigned : NumTypeBits; + + /// NumProtocols - The number of protocols stored directly on this + /// object type. + unsigned NumProtocols : 32 - NumTypeBits; + }; + + class ReferenceTypeBitfields { + friend class ReferenceType; + + unsigned : NumTypeBits; + + /// True if the type was originally spelled with an lvalue sigil. + /// This is never true of rvalue references but can also be false + /// on lvalue references because of C++0x [dcl.typedef]p9, + /// as follows: + /// + /// typedef int &ref; // lvalue, spelled lvalue + /// typedef int &&rvref; // rvalue + /// ref &a; // lvalue, inner ref, spelled lvalue + /// ref &&a; // lvalue, inner ref + /// rvref &a; // lvalue, inner ref, spelled lvalue + /// rvref &&a; // rvalue, inner ref + unsigned SpelledAsLValue : 1; + + /// True if the inner type is a reference type. This only happens + /// in non-canonical forms. + unsigned InnerRef : 1; + }; + + class TypeWithKeywordBitfields { + friend class TypeWithKeyword; + + unsigned : NumTypeBits; + + /// An ElaboratedTypeKeyword. 8 bits for efficient access. + unsigned Keyword : 8; + }; + + class VectorTypeBitfields { + friend class VectorType; + + unsigned : NumTypeBits; + + /// VecKind - The kind of vector, either a generic vector type or some + /// target-specific vector type such as for AltiVec or Neon. + unsigned VecKind : 3; + + /// NumElements - The number of elements in the vector. + unsigned NumElements : 29 - NumTypeBits; + }; + + class AttributedTypeBitfields { + friend class AttributedType; + + unsigned : NumTypeBits; + + /// AttrKind - an AttributedType::Kind + unsigned AttrKind : 32 - NumTypeBits; + }; + + union { + TypeBitfields TypeBits; + ArrayTypeBitfields ArrayTypeBits; + AttributedTypeBitfields AttributedTypeBits; + BuiltinTypeBitfields BuiltinTypeBits; + FunctionTypeBitfields FunctionTypeBits; + ObjCObjectTypeBitfields ObjCObjectTypeBits; + ReferenceTypeBitfields ReferenceTypeBits; + TypeWithKeywordBitfields TypeWithKeywordBits; + VectorTypeBitfields VectorTypeBits; + }; + +private: + /// \brief Set whether this type comes from an AST file. + void setFromAST(bool V = true) const { + TypeBits.FromAST = V; + } + + template <class T> friend class TypePropertyCache; + +protected: + // silence VC++ warning C4355: 'this' : used in base member initializer list + Type *this_() { return this; } + Type(TypeClass tc, QualType canon, bool Dependent, + bool InstantiationDependent, bool VariablyModified, + bool ContainsUnexpandedParameterPack) + : ExtQualsTypeCommonBase(this, + canon.isNull() ? QualType(this_(), 0) : canon) { + TypeBits.TC = tc; + TypeBits.Dependent = Dependent; + TypeBits.InstantiationDependent = Dependent || InstantiationDependent; + TypeBits.VariablyModified = VariablyModified; + TypeBits.ContainsUnexpandedParameterPack = ContainsUnexpandedParameterPack; + TypeBits.CacheValidAndVisibility = 0; + TypeBits.CachedExplicitVisibility = false; + TypeBits.CachedLocalOrUnnamed = false; + TypeBits.CachedLinkage = NoLinkage; + TypeBits.FromAST = false; + } + friend class ASTContext; + + void setDependent(bool D = true) { + TypeBits.Dependent = D; + if (D) + TypeBits.InstantiationDependent = true; + } + void setInstantiationDependent(bool D = true) { + TypeBits.InstantiationDependent = D; } + void setVariablyModified(bool VM = true) { TypeBits.VariablyModified = VM; + } + void setContainsUnexpandedParameterPack(bool PP = true) { + TypeBits.ContainsUnexpandedParameterPack = PP; + } + +public: + TypeClass getTypeClass() const { return static_cast<TypeClass>(TypeBits.TC); } + + /// \brief Whether this type comes from an AST file. + bool isFromAST() const { return TypeBits.FromAST; } + + /// \brief Whether this type is or contains an unexpanded parameter + /// pack, used to support C++0x variadic templates. + /// + /// A type that contains a parameter pack shall be expanded by the + /// ellipsis operator at some point. For example, the typedef in the + /// following example contains an unexpanded parameter pack 'T': + /// + /// \code + /// template<typename ...T> + /// struct X { + /// typedef T* pointer_types; // ill-formed; T is a parameter pack. + /// }; + /// \endcode + /// + /// Note that this routine does not specify which + bool containsUnexpandedParameterPack() const { + return TypeBits.ContainsUnexpandedParameterPack; + } + + /// Determines if this type would be canonical if it had no further + /// qualification. + bool isCanonicalUnqualified() const { + return CanonicalType == QualType(this, 0); + } + + /// Pull a single level of sugar off of this locally-unqualified type. + /// Users should generally prefer SplitQualType::getSingleStepDesugaredType() + /// or QualType::getSingleStepDesugaredType(const ASTContext&). + QualType getLocallyUnqualifiedSingleStepDesugaredType() const; + + /// Types are partitioned into 3 broad categories (C99 6.2.5p1): + /// object types, function types, and incomplete types. + + /// isIncompleteType - Return true if this is an incomplete type. + /// A type that can describe objects, but which lacks information needed to + /// determine its size (e.g. void, or a fwd declared struct). Clients of this + /// routine will need to determine if the size is actually required. + /// + /// \brief Def If non-NULL, and the type refers to some kind of declaration + /// that can be completed (such as a C struct, C++ class, or Objective-C + /// class), will be set to the declaration. + bool isIncompleteType(NamedDecl **Def = 0) const; + + /// isIncompleteOrObjectType - Return true if this is an incomplete or object + /// type, in other words, not a function type. + bool isIncompleteOrObjectType() const { + return !isFunctionType(); + } + + /// \brief Determine whether this type is an object type. + bool isObjectType() const { + // C++ [basic.types]p8: + // An object type is a (possibly cv-qualified) type that is not a + // function type, not a reference type, and not a void type. + return !isReferenceType() && !isFunctionType() && !isVoidType(); + } + + /// isLiteralType - Return true if this is a literal type + /// (C++0x [basic.types]p10) + bool isLiteralType() const; + + /// \brief Test if this type is a standard-layout type. + /// (C++0x [basic.type]p9) + bool isStandardLayoutType() const; + + /// Helper methods to distinguish type categories. All type predicates + /// operate on the canonical type, ignoring typedefs and qualifiers. + + /// isBuiltinType - returns true if the type is a builtin type. + bool isBuiltinType() const; + + /// isSpecificBuiltinType - Test for a particular builtin type. + bool isSpecificBuiltinType(unsigned K) const; + + /// isPlaceholderType - Test for a type which does not represent an + /// actual type-system type but is instead used as a placeholder for + /// various convenient purposes within Clang. All such types are + /// BuiltinTypes. + bool isPlaceholderType() const; + const BuiltinType *getAsPlaceholderType() const; + + /// isSpecificPlaceholderType - Test for a specific placeholder type. + bool isSpecificPlaceholderType(unsigned K) const; + + /// isNonOverloadPlaceholderType - Test for a placeholder type + /// other than Overload; see BuiltinType::isNonOverloadPlaceholderType. + bool isNonOverloadPlaceholderType() const; + + /// isIntegerType() does *not* include complex integers (a GCC extension). + /// isComplexIntegerType() can be used to test for complex integers. + bool isIntegerType() const; // C99 6.2.5p17 (int, char, bool, enum) + bool isEnumeralType() const; + bool isBooleanType() const; + bool isCharType() const; + bool isWideCharType() const; + bool isChar16Type() const; + bool isChar32Type() const; + bool isAnyCharacterType() const; + bool isIntegralType(ASTContext &Ctx) const; + + /// \brief Determine whether this type is an integral or enumeration type. + bool isIntegralOrEnumerationType() const; + /// \brief Determine whether this type is an integral or unscoped enumeration + /// type. + bool isIntegralOrUnscopedEnumerationType() const; + + /// Floating point categories. + bool isRealFloatingType() const; // C99 6.2.5p10 (float, double, long double) + /// isComplexType() does *not* include complex integers (a GCC extension). + /// isComplexIntegerType() can be used to test for complex integers. + bool isComplexType() const; // C99 6.2.5p11 (complex) + bool isAnyComplexType() const; // C99 6.2.5p11 (complex) + Complex Int. + bool isFloatingType() const; // C99 6.2.5p11 (real floating + complex) + bool isHalfType() const; // OpenCL 6.1.1.1, NEON (IEEE 754-2008 half) + bool isRealType() const; // C99 6.2.5p17 (real floating + integer) + bool isArithmeticType() const; // C99 6.2.5p18 (integer + floating) + bool isVoidType() const; // C99 6.2.5p19 + bool isDerivedType() const; // C99 6.2.5p20 + bool isScalarType() const; // C99 6.2.5p21 (arithmetic + pointers) + bool isAggregateType() const; + bool isFundamentalType() const; + bool isCompoundType() const; + + // Type Predicates: Check to see if this type is structurally the specified + // type, ignoring typedefs and qualifiers. + bool isFunctionType() const; + bool isFunctionNoProtoType() const { return getAs<FunctionNoProtoType>(); } + bool isFunctionProtoType() const { return getAs<FunctionProtoType>(); } + bool isPointerType() const; + bool isAnyPointerType() const; // Any C pointer or ObjC object pointer + bool isBlockPointerType() const; + bool isVoidPointerType() const; + bool isReferenceType() const; + bool isLValueReferenceType() const; + bool isRValueReferenceType() const; + bool isFunctionPointerType() const; + bool isMemberPointerType() const; + bool isMemberFunctionPointerType() const; + bool isMemberDataPointerType() const; + bool isArrayType() const; + bool isConstantArrayType() const; + bool isIncompleteArrayType() const; + bool isVariableArrayType() const; + bool isDependentSizedArrayType() const; + bool isRecordType() const; + bool isClassType() const; + bool isStructureType() const; + bool isStructureOrClassType() const; + bool isUnionType() const; + bool isComplexIntegerType() const; // GCC _Complex integer type. + bool isVectorType() const; // GCC vector type. + bool isExtVectorType() const; // Extended vector type. + bool isObjCObjectPointerType() const; // pointer to ObjC object + bool isObjCRetainableType() const; // ObjC object or block pointer + bool isObjCLifetimeType() const; // (array of)* retainable type + bool isObjCIndirectLifetimeType() const; // (pointer to)* lifetime type + bool isObjCNSObjectType() const; // __attribute__((NSObject)) + // FIXME: change this to 'raw' interface type, so we can used 'interface' type + // for the common case. + bool isObjCObjectType() const; // NSString or typeof(*(id)0) + bool isObjCQualifiedInterfaceType() const; // NSString<foo> + bool isObjCQualifiedIdType() const; // id<foo> + bool isObjCQualifiedClassType() const; // Class<foo> + bool isObjCObjectOrInterfaceType() const; + bool isObjCIdType() const; // id + bool isObjCClassType() const; // Class + bool isObjCSelType() const; // Class + bool isObjCBuiltinType() const; // 'id' or 'Class' + bool isObjCARCBridgableType() const; + bool isCARCBridgableType() const; + bool isTemplateTypeParmType() const; // C++ template type parameter + bool isNullPtrType() const; // C++0x nullptr_t + bool isAtomicType() const; // C11 _Atomic() + + /// Determines if this type, which must satisfy + /// isObjCLifetimeType(), is implicitly __unsafe_unretained rather + /// than implicitly __strong. + bool isObjCARCImplicitlyUnretainedType() const; + + /// Return the implicit lifetime for this type, which must not be dependent. + Qualifiers::ObjCLifetime getObjCARCImplicitLifetime() const; + + enum ScalarTypeKind { + STK_CPointer, + STK_BlockPointer, + STK_ObjCObjectPointer, + STK_MemberPointer, + STK_Bool, + STK_Integral, + STK_Floating, + STK_IntegralComplex, + STK_FloatingComplex + }; + /// getScalarTypeKind - Given that this is a scalar type, classify it. + ScalarTypeKind getScalarTypeKind() const; + + /// isDependentType - Whether this type is a dependent type, meaning + /// that its definition somehow depends on a template parameter + /// (C++ [temp.dep.type]). + bool isDependentType() const { return TypeBits.Dependent; } + + /// \brief Determine whether this type is an instantiation-dependent type, + /// meaning that the type involves a template parameter (even if the + /// definition does not actually depend on the type substituted for that + /// template parameter). + bool isInstantiationDependentType() const { + return TypeBits.InstantiationDependent; + } + + /// \brief Whether this type is a variably-modified type (C99 6.7.5). + bool isVariablyModifiedType() const { return TypeBits.VariablyModified; } + + /// \brief Whether this type involves a variable-length array type + /// with a definite size. + bool hasSizedVLAType() const; + + /// \brief Whether this type is or contains a local or unnamed type. + bool hasUnnamedOrLocalType() const; + + bool isOverloadableType() const; + + /// \brief Determine wither this type is a C++ elaborated-type-specifier. + bool isElaboratedTypeSpecifier() const; + + bool canDecayToPointerType() const; + + /// hasPointerRepresentation - Whether this type is represented + /// natively as a pointer; this includes pointers, references, block + /// pointers, and Objective-C interface, qualified id, and qualified + /// interface types, as well as nullptr_t. + bool hasPointerRepresentation() const; + + /// hasObjCPointerRepresentation - Whether this type can represent + /// an objective pointer type for the purpose of GC'ability + bool hasObjCPointerRepresentation() const; + + /// \brief Determine whether this type has an integer representation + /// of some sort, e.g., it is an integer type or a vector. + bool hasIntegerRepresentation() const; + + /// \brief Determine whether this type has an signed integer representation + /// of some sort, e.g., it is an signed integer type or a vector. + bool hasSignedIntegerRepresentation() const; + + /// \brief Determine whether this type has an unsigned integer representation + /// of some sort, e.g., it is an unsigned integer type or a vector. + bool hasUnsignedIntegerRepresentation() const; + + /// \brief Determine whether this type has a floating-point representation + /// of some sort, e.g., it is a floating-point type or a vector thereof. + bool hasFloatingRepresentation() const; + + // Type Checking Functions: Check to see if this type is structurally the + // specified type, ignoring typedefs and qualifiers, and return a pointer to + // the best type we can. + const RecordType *getAsStructureType() const; + /// NOTE: getAs*ArrayType are methods on ASTContext. + const RecordType *getAsUnionType() const; + const ComplexType *getAsComplexIntegerType() const; // GCC complex int type. + // The following is a convenience method that returns an ObjCObjectPointerType + // for object declared using an interface. + const ObjCObjectPointerType *getAsObjCInterfacePointerType() const; + const ObjCObjectPointerType *getAsObjCQualifiedIdType() const; + const ObjCObjectPointerType *getAsObjCQualifiedClassType() const; + const ObjCObjectType *getAsObjCQualifiedInterfaceType() const; + const CXXRecordDecl *getCXXRecordDeclForPointerType() const; + + /// \brief Retrieves the CXXRecordDecl that this type refers to, either + /// because the type is a RecordType or because it is the injected-class-name + /// type of a class template or class template partial specialization. + CXXRecordDecl *getAsCXXRecordDecl() const; + + /// \brief Get the AutoType whose type will be deduced for a variable with + /// an initializer of this type. This looks through declarators like pointer + /// types, but not through decltype or typedefs. + AutoType *getContainedAutoType() const; + + /// Member-template getAs<specific type>'. Look through sugar for + /// an instance of <specific type>. This scheme will eventually + /// replace the specific getAsXXXX methods above. + /// + /// There are some specializations of this member template listed + /// immediately following this class. + template <typename T> const T *getAs() const; + + /// A variant of getAs<> for array types which silently discards + /// qualifiers from the outermost type. + const ArrayType *getAsArrayTypeUnsafe() const; + + /// Member-template castAs<specific type>. Look through sugar for + /// the underlying instance of <specific type>. + /// + /// This method has the same relationship to getAs<T> as cast<T> has + /// to dyn_cast<T>; which is to say, the underlying type *must* + /// have the intended type, and this method will never return null. + template <typename T> const T *castAs() const; + + /// A variant of castAs<> for array type which silently discards + /// qualifiers from the outermost type. + const ArrayType *castAsArrayTypeUnsafe() const; + + /// getBaseElementTypeUnsafe - Get the base element type of this + /// type, potentially discarding type qualifiers. This method + /// should never be used when type qualifiers are meaningful. + const Type *getBaseElementTypeUnsafe() const; + + /// getArrayElementTypeNoTypeQual - If this is an array type, return the + /// element type of the array, potentially with type qualifiers missing. + /// This method should never be used when type qualifiers are meaningful. + const Type *getArrayElementTypeNoTypeQual() const; + + /// getPointeeType - If this is a pointer, ObjC object pointer, or block + /// pointer, this returns the respective pointee. + QualType getPointeeType() const; + + /// getUnqualifiedDesugaredType() - Return the specified type with + /// any "sugar" removed from the type, removing any typedefs, + /// typeofs, etc., as well as any qualifiers. + const Type *getUnqualifiedDesugaredType() const; + + /// More type predicates useful for type checking/promotion + bool isPromotableIntegerType() const; // C99 6.3.1.1p2 + + /// isSignedIntegerType - Return true if this is an integer type that is + /// signed, according to C99 6.2.5p4 [char, signed char, short, int, long..], + /// or an enum decl which has a signed representation. + bool isSignedIntegerType() const; + + /// isUnsignedIntegerType - Return true if this is an integer type that is + /// unsigned, according to C99 6.2.5p6 [which returns true for _Bool], + /// or an enum decl which has an unsigned representation. + bool isUnsignedIntegerType() const; + + /// Determines whether this is an integer type that is signed or an + /// enumeration types whose underlying type is a signed integer type. + bool isSignedIntegerOrEnumerationType() const; + + /// Determines whether this is an integer type that is unsigned or an + /// enumeration types whose underlying type is a unsigned integer type. + bool isUnsignedIntegerOrEnumerationType() const; + + /// isConstantSizeType - Return true if this is not a variable sized type, + /// according to the rules of C99 6.7.5p3. It is not legal to call this on + /// incomplete types. + bool isConstantSizeType() const; + + /// isSpecifierType - Returns true if this type can be represented by some + /// set of type specifiers. + bool isSpecifierType() const; + + /// \brief Determine the linkage of this type. + Linkage getLinkage() const; + + /// \brief Determine the visibility of this type. + Visibility getVisibility() const; + + /// \brief Return true if the visibility was explicitly set is the code. + bool isVisibilityExplicit() const; + + /// \brief Determine the linkage and visibility of this type. + std::pair<Linkage,Visibility> getLinkageAndVisibility() const; + + /// \brief Note that the linkage is no longer known. + void ClearLinkageCache(); + + const char *getTypeClassName() const; + + QualType getCanonicalTypeInternal() const { + return CanonicalType; + } + CanQualType getCanonicalTypeUnqualified() const; // in CanonicalType.h + LLVM_ATTRIBUTE_USED void dump() const; + + static bool classof(const Type *) { return true; } + + friend class ASTReader; + friend class ASTWriter; +}; + +template <> inline const TypedefType *Type::getAs() const { + return dyn_cast<TypedefType>(this); +} + +// We can do canonical leaf types faster, because we don't have to +// worry about preserving child type decoration. +#define TYPE(Class, Base) +#define LEAF_TYPE(Class) \ +template <> inline const Class##Type *Type::getAs() const { \ + return dyn_cast<Class##Type>(CanonicalType); \ +} \ +template <> inline const Class##Type *Type::castAs() const { \ + return cast<Class##Type>(CanonicalType); \ +} +#include "clang/AST/TypeNodes.def" + + +/// BuiltinType - This class is used for builtin types like 'int'. Builtin +/// types are always canonical and have a literal name field. +class BuiltinType : public Type { +public: + enum Kind { +#define BUILTIN_TYPE(Id, SingletonId) Id, +#define LAST_BUILTIN_TYPE(Id) LastKind = Id +#include "clang/AST/BuiltinTypes.def" + }; + +public: + BuiltinType(Kind K) + : Type(Builtin, QualType(), /*Dependent=*/(K == Dependent), + /*InstantiationDependent=*/(K == Dependent), + /*VariablyModified=*/false, + /*Unexpanded paramter pack=*/false) { + BuiltinTypeBits.Kind = K; + } + + Kind getKind() const { return static_cast<Kind>(BuiltinTypeBits.Kind); } + const char *getName(const PrintingPolicy &Policy) const; + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + bool isInteger() const { + return getKind() >= Bool && getKind() <= Int128; + } + + bool isSignedInteger() const { + return getKind() >= Char_S && getKind() <= Int128; + } + + bool isUnsignedInteger() const { + return getKind() >= Bool && getKind() <= UInt128; + } + + bool isFloatingPoint() const { + return getKind() >= Half && getKind() <= LongDouble; + } + + /// Determines whether the given kind corresponds to a placeholder type. + static bool isPlaceholderTypeKind(Kind K) { + return K >= Overload; + } + + /// Determines whether this type is a placeholder type, i.e. a type + /// which cannot appear in arbitrary positions in a fully-formed + /// expression. + bool isPlaceholderType() const { + return isPlaceholderTypeKind(getKind()); + } + + /// Determines whether this type is a placeholder type other than + /// Overload. Most placeholder types require only syntactic + /// information about their context in order to be resolved (e.g. + /// whether it is a call expression), which means they can (and + /// should) be resolved in an earlier "phase" of analysis. + /// Overload expressions sometimes pick up further information + /// from their context, like whether the context expects a + /// specific function-pointer type, and so frequently need + /// special treatment. + bool isNonOverloadPlaceholderType() const { + return getKind() > Overload; + } + + static bool classof(const Type *T) { return T->getTypeClass() == Builtin; } + static bool classof(const BuiltinType *) { return true; } +}; + +/// ComplexType - C99 6.2.5p11 - Complex values. This supports the C99 complex +/// types (_Complex float etc) as well as the GCC integer complex extensions. +/// +class ComplexType : public Type, public llvm::FoldingSetNode { + QualType ElementType; + ComplexType(QualType Element, QualType CanonicalPtr) : + Type(Complex, CanonicalPtr, Element->isDependentType(), + Element->isInstantiationDependentType(), + Element->isVariablyModifiedType(), + Element->containsUnexpandedParameterPack()), + ElementType(Element) { + } + friend class ASTContext; // ASTContext creates these. + +public: + QualType getElementType() const { return ElementType; } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getElementType()); + } + static void Profile(llvm::FoldingSetNodeID &ID, QualType Element) { + ID.AddPointer(Element.getAsOpaquePtr()); + } + + static bool classof(const Type *T) { return T->getTypeClass() == Complex; } + static bool classof(const ComplexType *) { return true; } +}; + +/// ParenType - Sugar for parentheses used when specifying types. +/// +class ParenType : public Type, public llvm::FoldingSetNode { + QualType Inner; + + ParenType(QualType InnerType, QualType CanonType) : + Type(Paren, CanonType, InnerType->isDependentType(), + InnerType->isInstantiationDependentType(), + InnerType->isVariablyModifiedType(), + InnerType->containsUnexpandedParameterPack()), + Inner(InnerType) { + } + friend class ASTContext; // ASTContext creates these. + +public: + + QualType getInnerType() const { return Inner; } + + bool isSugared() const { return true; } + QualType desugar() const { return getInnerType(); } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getInnerType()); + } + static void Profile(llvm::FoldingSetNodeID &ID, QualType Inner) { + Inner.Profile(ID); + } + + static bool classof(const Type *T) { return T->getTypeClass() == Paren; } + static bool classof(const ParenType *) { return true; } +}; + +/// PointerType - C99 6.7.5.1 - Pointer Declarators. +/// +class PointerType : public Type, public llvm::FoldingSetNode { + QualType PointeeType; + + PointerType(QualType Pointee, QualType CanonicalPtr) : + Type(Pointer, CanonicalPtr, Pointee->isDependentType(), + Pointee->isInstantiationDependentType(), + Pointee->isVariablyModifiedType(), + Pointee->containsUnexpandedParameterPack()), + PointeeType(Pointee) { + } + friend class ASTContext; // ASTContext creates these. + +public: + + QualType getPointeeType() const { return PointeeType; } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getPointeeType()); + } + static void Profile(llvm::FoldingSetNodeID &ID, QualType Pointee) { + ID.AddPointer(Pointee.getAsOpaquePtr()); + } + + static bool classof(const Type *T) { return T->getTypeClass() == Pointer; } + static bool classof(const PointerType *) { return true; } +}; + +/// BlockPointerType - pointer to a block type. +/// This type is to represent types syntactically represented as +/// "void (^)(int)", etc. Pointee is required to always be a function type. +/// +class BlockPointerType : public Type, public llvm::FoldingSetNode { + QualType PointeeType; // Block is some kind of pointer type + BlockPointerType(QualType Pointee, QualType CanonicalCls) : + Type(BlockPointer, CanonicalCls, Pointee->isDependentType(), + Pointee->isInstantiationDependentType(), + Pointee->isVariablyModifiedType(), + Pointee->containsUnexpandedParameterPack()), + PointeeType(Pointee) { + } + friend class ASTContext; // ASTContext creates these. + +public: + + // Get the pointee type. Pointee is required to always be a function type. + QualType getPointeeType() const { return PointeeType; } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getPointeeType()); + } + static void Profile(llvm::FoldingSetNodeID &ID, QualType Pointee) { + ID.AddPointer(Pointee.getAsOpaquePtr()); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == BlockPointer; + } + static bool classof(const BlockPointerType *) { return true; } +}; + +/// ReferenceType - Base for LValueReferenceType and RValueReferenceType +/// +class ReferenceType : public Type, public llvm::FoldingSetNode { + QualType PointeeType; + +protected: + ReferenceType(TypeClass tc, QualType Referencee, QualType CanonicalRef, + bool SpelledAsLValue) : + Type(tc, CanonicalRef, Referencee->isDependentType(), + Referencee->isInstantiationDependentType(), + Referencee->isVariablyModifiedType(), + Referencee->containsUnexpandedParameterPack()), + PointeeType(Referencee) + { + ReferenceTypeBits.SpelledAsLValue = SpelledAsLValue; + ReferenceTypeBits.InnerRef = Referencee->isReferenceType(); + } + +public: + bool isSpelledAsLValue() const { return ReferenceTypeBits.SpelledAsLValue; } + bool isInnerRef() const { return ReferenceTypeBits.InnerRef; } + + QualType getPointeeTypeAsWritten() const { return PointeeType; } + QualType getPointeeType() const { + // FIXME: this might strip inner qualifiers; okay? + const ReferenceType *T = this; + while (T->isInnerRef()) + T = T->PointeeType->castAs<ReferenceType>(); + return T->PointeeType; + } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, PointeeType, isSpelledAsLValue()); + } + static void Profile(llvm::FoldingSetNodeID &ID, + QualType Referencee, + bool SpelledAsLValue) { + ID.AddPointer(Referencee.getAsOpaquePtr()); + ID.AddBoolean(SpelledAsLValue); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == LValueReference || + T->getTypeClass() == RValueReference; + } + static bool classof(const ReferenceType *) { return true; } +}; + +/// LValueReferenceType - C++ [dcl.ref] - Lvalue reference +/// +class LValueReferenceType : public ReferenceType { + LValueReferenceType(QualType Referencee, QualType CanonicalRef, + bool SpelledAsLValue) : + ReferenceType(LValueReference, Referencee, CanonicalRef, SpelledAsLValue) + {} + friend class ASTContext; // ASTContext creates these +public: + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + static bool classof(const Type *T) { + return T->getTypeClass() == LValueReference; + } + static bool classof(const LValueReferenceType *) { return true; } +}; + +/// RValueReferenceType - C++0x [dcl.ref] - Rvalue reference +/// +class RValueReferenceType : public ReferenceType { + RValueReferenceType(QualType Referencee, QualType CanonicalRef) : + ReferenceType(RValueReference, Referencee, CanonicalRef, false) { + } + friend class ASTContext; // ASTContext creates these +public: + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + static bool classof(const Type *T) { + return T->getTypeClass() == RValueReference; + } + static bool classof(const RValueReferenceType *) { return true; } +}; + +/// MemberPointerType - C++ 8.3.3 - Pointers to members +/// +class MemberPointerType : public Type, public llvm::FoldingSetNode { + QualType PointeeType; + /// The class of which the pointee is a member. Must ultimately be a + /// RecordType, but could be a typedef or a template parameter too. + const Type *Class; + + MemberPointerType(QualType Pointee, const Type *Cls, QualType CanonicalPtr) : + Type(MemberPointer, CanonicalPtr, + Cls->isDependentType() || Pointee->isDependentType(), + (Cls->isInstantiationDependentType() || + Pointee->isInstantiationDependentType()), + Pointee->isVariablyModifiedType(), + (Cls->containsUnexpandedParameterPack() || + Pointee->containsUnexpandedParameterPack())), + PointeeType(Pointee), Class(Cls) { + } + friend class ASTContext; // ASTContext creates these. + +public: + QualType getPointeeType() const { return PointeeType; } + + /// Returns true if the member type (i.e. the pointee type) is a + /// function type rather than a data-member type. + bool isMemberFunctionPointer() const { + return PointeeType->isFunctionProtoType(); + } + + /// Returns true if the member type (i.e. the pointee type) is a + /// data type rather than a function type. + bool isMemberDataPointer() const { + return !PointeeType->isFunctionProtoType(); + } + + const Type *getClass() const { return Class; } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getPointeeType(), getClass()); + } + static void Profile(llvm::FoldingSetNodeID &ID, QualType Pointee, + const Type *Class) { + ID.AddPointer(Pointee.getAsOpaquePtr()); + ID.AddPointer(Class); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == MemberPointer; + } + static bool classof(const MemberPointerType *) { return true; } +}; + +/// ArrayType - C99 6.7.5.2 - Array Declarators. +/// +class ArrayType : public Type, public llvm::FoldingSetNode { +public: + /// ArraySizeModifier - Capture whether this is a normal array (e.g. int X[4]) + /// an array with a static size (e.g. int X[static 4]), or an array + /// with a star size (e.g. int X[*]). + /// 'static' is only allowed on function parameters. + enum ArraySizeModifier { + Normal, Static, Star + }; +private: + /// ElementType - The element type of the array. + QualType ElementType; + +protected: + // C++ [temp.dep.type]p1: + // A type is dependent if it is... + // - an array type constructed from any dependent type or whose + // size is specified by a constant expression that is + // value-dependent, + ArrayType(TypeClass tc, QualType et, QualType can, + ArraySizeModifier sm, unsigned tq, + bool ContainsUnexpandedParameterPack) + : Type(tc, can, et->isDependentType() || tc == DependentSizedArray, + et->isInstantiationDependentType() || tc == DependentSizedArray, + (tc == VariableArray || et->isVariablyModifiedType()), + ContainsUnexpandedParameterPack), + ElementType(et) { + ArrayTypeBits.IndexTypeQuals = tq; + ArrayTypeBits.SizeModifier = sm; + } + + friend class ASTContext; // ASTContext creates these. + +public: + QualType getElementType() const { return ElementType; } + ArraySizeModifier getSizeModifier() const { + return ArraySizeModifier(ArrayTypeBits.SizeModifier); + } + Qualifiers getIndexTypeQualifiers() const { + return Qualifiers::fromCVRMask(getIndexTypeCVRQualifiers()); + } + unsigned getIndexTypeCVRQualifiers() const { + return ArrayTypeBits.IndexTypeQuals; + } + + static bool classof(const Type *T) { + return T->getTypeClass() == ConstantArray || + T->getTypeClass() == VariableArray || + T->getTypeClass() == IncompleteArray || + T->getTypeClass() == DependentSizedArray; + } + static bool classof(const ArrayType *) { return true; } +}; + +/// ConstantArrayType - This class represents the canonical version of +/// C arrays with a specified constant size. For example, the canonical +/// type for 'int A[4 + 4*100]' is a ConstantArrayType where the element +/// type is 'int' and the size is 404. +class ConstantArrayType : public ArrayType { + llvm::APInt Size; // Allows us to unique the type. + + ConstantArrayType(QualType et, QualType can, const llvm::APInt &size, + ArraySizeModifier sm, unsigned tq) + : ArrayType(ConstantArray, et, can, sm, tq, + et->containsUnexpandedParameterPack()), + Size(size) {} +protected: + ConstantArrayType(TypeClass tc, QualType et, QualType can, + const llvm::APInt &size, ArraySizeModifier sm, unsigned tq) + : ArrayType(tc, et, can, sm, tq, et->containsUnexpandedParameterPack()), + Size(size) {} + friend class ASTContext; // ASTContext creates these. +public: + const llvm::APInt &getSize() const { return Size; } + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + + /// \brief Determine the number of bits required to address a member of + // an array with the given element type and number of elements. + static unsigned getNumAddressingBits(ASTContext &Context, + QualType ElementType, + const llvm::APInt &NumElements); + + /// \brief Determine the maximum number of active bits that an array's size + /// can require, which limits the maximum size of the array. + static unsigned getMaxSizeBits(ASTContext &Context); + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getElementType(), getSize(), + getSizeModifier(), getIndexTypeCVRQualifiers()); + } + static void Profile(llvm::FoldingSetNodeID &ID, QualType ET, + const llvm::APInt &ArraySize, ArraySizeModifier SizeMod, + unsigned TypeQuals) { + ID.AddPointer(ET.getAsOpaquePtr()); + ID.AddInteger(ArraySize.getZExtValue()); + ID.AddInteger(SizeMod); + ID.AddInteger(TypeQuals); + } + static bool classof(const Type *T) { + return T->getTypeClass() == ConstantArray; + } + static bool classof(const ConstantArrayType *) { return true; } +}; + +/// IncompleteArrayType - This class represents C arrays with an unspecified +/// size. For example 'int A[]' has an IncompleteArrayType where the element +/// type is 'int' and the size is unspecified. +class IncompleteArrayType : public ArrayType { + + IncompleteArrayType(QualType et, QualType can, + ArraySizeModifier sm, unsigned tq) + : ArrayType(IncompleteArray, et, can, sm, tq, + et->containsUnexpandedParameterPack()) {} + friend class ASTContext; // ASTContext creates these. +public: + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + static bool classof(const Type *T) { + return T->getTypeClass() == IncompleteArray; + } + static bool classof(const IncompleteArrayType *) { return true; } + + friend class StmtIteratorBase; + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getElementType(), getSizeModifier(), + getIndexTypeCVRQualifiers()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, QualType ET, + ArraySizeModifier SizeMod, unsigned TypeQuals) { + ID.AddPointer(ET.getAsOpaquePtr()); + ID.AddInteger(SizeMod); + ID.AddInteger(TypeQuals); + } +}; + +/// VariableArrayType - This class represents C arrays with a specified size +/// which is not an integer-constant-expression. For example, 'int s[x+foo()]'. +/// Since the size expression is an arbitrary expression, we store it as such. +/// +/// Note: VariableArrayType's aren't uniqued (since the expressions aren't) and +/// should not be: two lexically equivalent variable array types could mean +/// different things, for example, these variables do not have the same type +/// dynamically: +/// +/// void foo(int x) { +/// int Y[x]; +/// ++x; +/// int Z[x]; +/// } +/// +class VariableArrayType : public ArrayType { + /// SizeExpr - An assignment expression. VLA's are only permitted within + /// a function block. + Stmt *SizeExpr; + /// Brackets - The left and right array brackets. + SourceRange Brackets; + + VariableArrayType(QualType et, QualType can, Expr *e, + ArraySizeModifier sm, unsigned tq, + SourceRange brackets) + : ArrayType(VariableArray, et, can, sm, tq, + et->containsUnexpandedParameterPack()), + SizeExpr((Stmt*) e), Brackets(brackets) {} + friend class ASTContext; // ASTContext creates these. + +public: + Expr *getSizeExpr() const { + // We use C-style casts instead of cast<> here because we do not wish + // to have a dependency of Type.h on Stmt.h/Expr.h. + return (Expr*) SizeExpr; + } + SourceRange getBracketsRange() const { return Brackets; } + SourceLocation getLBracketLoc() const { return Brackets.getBegin(); } + SourceLocation getRBracketLoc() const { return Brackets.getEnd(); } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + static bool classof(const Type *T) { + return T->getTypeClass() == VariableArray; + } + static bool classof(const VariableArrayType *) { return true; } + + friend class StmtIteratorBase; + + void Profile(llvm::FoldingSetNodeID &ID) { + llvm_unreachable("Cannot unique VariableArrayTypes."); + } +}; + +/// DependentSizedArrayType - This type represents an array type in +/// C++ whose size is a value-dependent expression. For example: +/// +/// \code +/// template<typename T, int Size> +/// class array { +/// T data[Size]; +/// }; +/// \endcode +/// +/// For these types, we won't actually know what the array bound is +/// until template instantiation occurs, at which point this will +/// become either a ConstantArrayType or a VariableArrayType. +class DependentSizedArrayType : public ArrayType { + const ASTContext &Context; + + /// \brief An assignment expression that will instantiate to the + /// size of the array. + /// + /// The expression itself might be NULL, in which case the array + /// type will have its size deduced from an initializer. + Stmt *SizeExpr; + + /// Brackets - The left and right array brackets. + SourceRange Brackets; + + DependentSizedArrayType(const ASTContext &Context, QualType et, QualType can, + Expr *e, ArraySizeModifier sm, unsigned tq, + SourceRange brackets); + + friend class ASTContext; // ASTContext creates these. + +public: + Expr *getSizeExpr() const { + // We use C-style casts instead of cast<> here because we do not wish + // to have a dependency of Type.h on Stmt.h/Expr.h. + return (Expr*) SizeExpr; + } + SourceRange getBracketsRange() const { return Brackets; } + SourceLocation getLBracketLoc() const { return Brackets.getBegin(); } + SourceLocation getRBracketLoc() const { return Brackets.getEnd(); } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + static bool classof(const Type *T) { + return T->getTypeClass() == DependentSizedArray; + } + static bool classof(const DependentSizedArrayType *) { return true; } + + friend class StmtIteratorBase; + + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, Context, getElementType(), + getSizeModifier(), getIndexTypeCVRQualifiers(), getSizeExpr()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, + QualType ET, ArraySizeModifier SizeMod, + unsigned TypeQuals, Expr *E); +}; + +/// DependentSizedExtVectorType - This type represent an extended vector type +/// where either the type or size is dependent. For example: +/// @code +/// template<typename T, int Size> +/// class vector { +/// typedef T __attribute__((ext_vector_type(Size))) type; +/// } +/// @endcode +class DependentSizedExtVectorType : public Type, public llvm::FoldingSetNode { + const ASTContext &Context; + Expr *SizeExpr; + /// ElementType - The element type of the array. + QualType ElementType; + SourceLocation loc; + + DependentSizedExtVectorType(const ASTContext &Context, QualType ElementType, + QualType can, Expr *SizeExpr, SourceLocation loc); + + friend class ASTContext; + +public: + Expr *getSizeExpr() const { return SizeExpr; } + QualType getElementType() const { return ElementType; } + SourceLocation getAttributeLoc() const { return loc; } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + static bool classof(const Type *T) { + return T->getTypeClass() == DependentSizedExtVector; + } + static bool classof(const DependentSizedExtVectorType *) { return true; } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, Context, getElementType(), getSizeExpr()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, + QualType ElementType, Expr *SizeExpr); +}; + + +/// VectorType - GCC generic vector type. This type is created using +/// __attribute__((vector_size(n)), where "n" specifies the vector size in +/// bytes; or from an Altivec __vector or vector declaration. +/// Since the constructor takes the number of vector elements, the +/// client is responsible for converting the size into the number of elements. +class VectorType : public Type, public llvm::FoldingSetNode { +public: + enum VectorKind { + GenericVector, // not a target-specific vector type + AltiVecVector, // is AltiVec vector + AltiVecPixel, // is AltiVec 'vector Pixel' + AltiVecBool, // is AltiVec 'vector bool ...' + NeonVector, // is ARM Neon vector + NeonPolyVector // is ARM Neon polynomial vector + }; +protected: + /// ElementType - The element type of the vector. + QualType ElementType; + + VectorType(QualType vecType, unsigned nElements, QualType canonType, + VectorKind vecKind); + + VectorType(TypeClass tc, QualType vecType, unsigned nElements, + QualType canonType, VectorKind vecKind); + + friend class ASTContext; // ASTContext creates these. + +public: + + QualType getElementType() const { return ElementType; } + unsigned getNumElements() const { return VectorTypeBits.NumElements; } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + VectorKind getVectorKind() const { + return VectorKind(VectorTypeBits.VecKind); + } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getElementType(), getNumElements(), + getTypeClass(), getVectorKind()); + } + static void Profile(llvm::FoldingSetNodeID &ID, QualType ElementType, + unsigned NumElements, TypeClass TypeClass, + VectorKind VecKind) { + ID.AddPointer(ElementType.getAsOpaquePtr()); + ID.AddInteger(NumElements); + ID.AddInteger(TypeClass); + ID.AddInteger(VecKind); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == Vector || T->getTypeClass() == ExtVector; + } + static bool classof(const VectorType *) { return true; } +}; + +/// ExtVectorType - Extended vector type. This type is created using +/// __attribute__((ext_vector_type(n)), where "n" is the number of elements. +/// Unlike vector_size, ext_vector_type is only allowed on typedef's. This +/// class enables syntactic extensions, like Vector Components for accessing +/// points, colors, and textures (modeled after OpenGL Shading Language). +class ExtVectorType : public VectorType { + ExtVectorType(QualType vecType, unsigned nElements, QualType canonType) : + VectorType(ExtVector, vecType, nElements, canonType, GenericVector) {} + friend class ASTContext; // ASTContext creates these. +public: + static int getPointAccessorIdx(char c) { + switch (c) { + default: return -1; + case 'x': return 0; + case 'y': return 1; + case 'z': return 2; + case 'w': return 3; + } + } + static int getNumericAccessorIdx(char c) { + switch (c) { + default: return -1; + case '0': return 0; + case '1': return 1; + case '2': return 2; + case '3': return 3; + case '4': return 4; + case '5': return 5; + case '6': return 6; + case '7': return 7; + case '8': return 8; + case '9': return 9; + case 'A': + case 'a': return 10; + case 'B': + case 'b': return 11; + case 'C': + case 'c': return 12; + case 'D': + case 'd': return 13; + case 'E': + case 'e': return 14; + case 'F': + case 'f': return 15; + } + } + + static int getAccessorIdx(char c) { + if (int idx = getPointAccessorIdx(c)+1) return idx-1; + return getNumericAccessorIdx(c); + } + + bool isAccessorWithinNumElements(char c) const { + if (int idx = getAccessorIdx(c)+1) + return unsigned(idx-1) < getNumElements(); + return false; + } + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + static bool classof(const Type *T) { + return T->getTypeClass() == ExtVector; + } + static bool classof(const ExtVectorType *) { return true; } +}; + +/// FunctionType - C99 6.7.5.3 - Function Declarators. This is the common base +/// class of FunctionNoProtoType and FunctionProtoType. +/// +class FunctionType : public Type { + // The type returned by the function. + QualType ResultType; + + public: + /// ExtInfo - A class which abstracts out some details necessary for + /// making a call. + /// + /// It is not actually used directly for storing this information in + /// a FunctionType, although FunctionType does currently use the + /// same bit-pattern. + /// + // If you add a field (say Foo), other than the obvious places (both, + // constructors, compile failures), what you need to update is + // * Operator== + // * getFoo + // * withFoo + // * functionType. Add Foo, getFoo. + // * ASTContext::getFooType + // * ASTContext::mergeFunctionTypes + // * FunctionNoProtoType::Profile + // * FunctionProtoType::Profile + // * TypePrinter::PrintFunctionProto + // * AST read and write + // * Codegen + class ExtInfo { + // Feel free to rearrange or add bits, but if you go over 8, + // you'll need to adjust both the Bits field below and + // Type::FunctionTypeBitfields. + + // | CC |noreturn|produces|regparm| + // |0 .. 2| 3 | 4 | 5 .. 7| + // + // regparm is either 0 (no regparm attribute) or the regparm value+1. + enum { CallConvMask = 0x7 }; + enum { NoReturnMask = 0x8 }; + enum { ProducesResultMask = 0x10 }; + enum { RegParmMask = ~(CallConvMask | NoReturnMask | ProducesResultMask), + RegParmOffset = 5 }; // Assumed to be the last field + + uint16_t Bits; + + ExtInfo(unsigned Bits) : Bits(static_cast<uint16_t>(Bits)) {} + + friend class FunctionType; + + public: + // Constructor with no defaults. Use this when you know that you + // have all the elements (when reading an AST file for example). + ExtInfo(bool noReturn, bool hasRegParm, unsigned regParm, CallingConv cc, + bool producesResult) { + assert((!hasRegParm || regParm < 7) && "Invalid regparm value"); + Bits = ((unsigned) cc) | + (noReturn ? NoReturnMask : 0) | + (producesResult ? ProducesResultMask : 0) | + (hasRegParm ? ((regParm + 1) << RegParmOffset) : 0); + } + + // Constructor with all defaults. Use when for example creating a + // function know to use defaults. + ExtInfo() : Bits(0) {} + + bool getNoReturn() const { return Bits & NoReturnMask; } + bool getProducesResult() const { return Bits & ProducesResultMask; } + bool getHasRegParm() const { return (Bits >> RegParmOffset) != 0; } + unsigned getRegParm() const { + unsigned RegParm = Bits >> RegParmOffset; + if (RegParm > 0) + --RegParm; + return RegParm; + } + CallingConv getCC() const { return CallingConv(Bits & CallConvMask); } + + bool operator==(ExtInfo Other) const { + return Bits == Other.Bits; + } + bool operator!=(ExtInfo Other) const { + return Bits != Other.Bits; + } + + // Note that we don't have setters. That is by design, use + // the following with methods instead of mutating these objects. + + ExtInfo withNoReturn(bool noReturn) const { + if (noReturn) + return ExtInfo(Bits | NoReturnMask); + else + return ExtInfo(Bits & ~NoReturnMask); + } + + ExtInfo withProducesResult(bool producesResult) const { + if (producesResult) + return ExtInfo(Bits | ProducesResultMask); + else + return ExtInfo(Bits & ~ProducesResultMask); + } + + ExtInfo withRegParm(unsigned RegParm) const { + assert(RegParm < 7 && "Invalid regparm value"); + return ExtInfo((Bits & ~RegParmMask) | + ((RegParm + 1) << RegParmOffset)); + } + + ExtInfo withCallingConv(CallingConv cc) const { + return ExtInfo((Bits & ~CallConvMask) | (unsigned) cc); + } + + void Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddInteger(Bits); + } + }; + +protected: + FunctionType(TypeClass tc, QualType res, + unsigned typeQuals, RefQualifierKind RefQualifier, + QualType Canonical, bool Dependent, + bool InstantiationDependent, + bool VariablyModified, bool ContainsUnexpandedParameterPack, + ExtInfo Info) + : Type(tc, Canonical, Dependent, InstantiationDependent, VariablyModified, + ContainsUnexpandedParameterPack), + ResultType(res) { + FunctionTypeBits.ExtInfo = Info.Bits; + FunctionTypeBits.TypeQuals = typeQuals; + FunctionTypeBits.RefQualifier = static_cast<unsigned>(RefQualifier); + } + unsigned getTypeQuals() const { return FunctionTypeBits.TypeQuals; } + + RefQualifierKind getRefQualifier() const { + return static_cast<RefQualifierKind>(FunctionTypeBits.RefQualifier); + } + +public: + + QualType getResultType() const { return ResultType; } + + bool getHasRegParm() const { return getExtInfo().getHasRegParm(); } + unsigned getRegParmType() const { return getExtInfo().getRegParm(); } + bool getNoReturnAttr() const { return getExtInfo().getNoReturn(); } + CallingConv getCallConv() const { return getExtInfo().getCC(); } + ExtInfo getExtInfo() const { return ExtInfo(FunctionTypeBits.ExtInfo); } + + /// \brief Determine the type of an expression that calls a function of + /// this type. + QualType getCallResultType(ASTContext &Context) const { + return getResultType().getNonLValueExprType(Context); + } + + static StringRef getNameForCallConv(CallingConv CC); + + static bool classof(const Type *T) { + return T->getTypeClass() == FunctionNoProto || + T->getTypeClass() == FunctionProto; + } + static bool classof(const FunctionType *) { return true; } +}; + +/// FunctionNoProtoType - Represents a K&R-style 'int foo()' function, which has +/// no information available about its arguments. +class FunctionNoProtoType : public FunctionType, public llvm::FoldingSetNode { + FunctionNoProtoType(QualType Result, QualType Canonical, ExtInfo Info) + : FunctionType(FunctionNoProto, Result, 0, RQ_None, Canonical, + /*Dependent=*/false, /*InstantiationDependent=*/false, + Result->isVariablyModifiedType(), + /*ContainsUnexpandedParameterPack=*/false, Info) {} + + friend class ASTContext; // ASTContext creates these. + +public: + // No additional state past what FunctionType provides. + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getResultType(), getExtInfo()); + } + static void Profile(llvm::FoldingSetNodeID &ID, QualType ResultType, + ExtInfo Info) { + Info.Profile(ID); + ID.AddPointer(ResultType.getAsOpaquePtr()); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == FunctionNoProto; + } + static bool classof(const FunctionNoProtoType *) { return true; } +}; + +/// FunctionProtoType - Represents a prototype with argument type info, e.g. +/// 'int foo(int)' or 'int foo(void)'. 'void' is represented as having no +/// arguments, not as having a single void argument. Such a type can have an +/// exception specification, but this specification is not part of the canonical +/// type. +class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode { +public: + /// ExtProtoInfo - Extra information about a function prototype. + struct ExtProtoInfo { + ExtProtoInfo() : + Variadic(false), HasTrailingReturn(false), TypeQuals(0), + ExceptionSpecType(EST_None), RefQualifier(RQ_None), + NumExceptions(0), Exceptions(0), NoexceptExpr(0), + ExceptionSpecDecl(0), ExceptionSpecTemplate(0), + ConsumedArguments(0) {} + + FunctionType::ExtInfo ExtInfo; + bool Variadic : 1; + bool HasTrailingReturn : 1; + unsigned char TypeQuals; + ExceptionSpecificationType ExceptionSpecType; + RefQualifierKind RefQualifier; + unsigned NumExceptions; + const QualType *Exceptions; + Expr *NoexceptExpr; + FunctionDecl *ExceptionSpecDecl; + FunctionDecl *ExceptionSpecTemplate; + const bool *ConsumedArguments; + }; + +private: + /// \brief Determine whether there are any argument types that + /// contain an unexpanded parameter pack. + static bool containsAnyUnexpandedParameterPack(const QualType *ArgArray, + unsigned numArgs) { + for (unsigned Idx = 0; Idx < numArgs; ++Idx) + if (ArgArray[Idx]->containsUnexpandedParameterPack()) + return true; + + return false; + } + + FunctionProtoType(QualType result, const QualType *args, unsigned numArgs, + QualType canonical, const ExtProtoInfo &epi); + + /// NumArgs - The number of arguments this function has, not counting '...'. + unsigned NumArgs : 17; + + /// NumExceptions - The number of types in the exception spec, if any. + unsigned NumExceptions : 9; + + /// ExceptionSpecType - The type of exception specification this function has. + unsigned ExceptionSpecType : 3; + + /// HasAnyConsumedArgs - Whether this function has any consumed arguments. + unsigned HasAnyConsumedArgs : 1; + + /// Variadic - Whether the function is variadic. + unsigned Variadic : 1; + + /// HasTrailingReturn - Whether this function has a trailing return type. + unsigned HasTrailingReturn : 1; + + // ArgInfo - There is an variable size array after the class in memory that + // holds the argument types. + + // Exceptions - There is another variable size array after ArgInfo that + // holds the exception types. + + // NoexceptExpr - Instead of Exceptions, there may be a single Expr* pointing + // to the expression in the noexcept() specifier. + + // ExceptionSpecDecl, ExceptionSpecTemplate - Instead of Exceptions, there may + // be a pair of FunctionDecl* pointing to the function which should be used to + // instantiate this function type's exception specification, and the function + // from which it should be instantiated. + + // ConsumedArgs - A variable size array, following Exceptions + // and of length NumArgs, holding flags indicating which arguments + // are consumed. This only appears if HasAnyConsumedArgs is true. + + friend class ASTContext; // ASTContext creates these. + + const bool *getConsumedArgsBuffer() const { + assert(hasAnyConsumedArgs()); + + // Find the end of the exceptions. + Expr * const *eh_end = reinterpret_cast<Expr * const *>(arg_type_end()); + if (getExceptionSpecType() != EST_ComputedNoexcept) + eh_end += NumExceptions; + else + eh_end += 1; // NoexceptExpr + + return reinterpret_cast<const bool*>(eh_end); + } + +public: + unsigned getNumArgs() const { return NumArgs; } + QualType getArgType(unsigned i) const { + assert(i < NumArgs && "Invalid argument number!"); + return arg_type_begin()[i]; + } + + ExtProtoInfo getExtProtoInfo() const { + ExtProtoInfo EPI; + EPI.ExtInfo = getExtInfo(); + EPI.Variadic = isVariadic(); + EPI.HasTrailingReturn = hasTrailingReturn(); + EPI.ExceptionSpecType = getExceptionSpecType(); + EPI.TypeQuals = static_cast<unsigned char>(getTypeQuals()); + EPI.RefQualifier = getRefQualifier(); + if (EPI.ExceptionSpecType == EST_Dynamic) { + EPI.NumExceptions = NumExceptions; + EPI.Exceptions = exception_begin(); + } else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) { + EPI.NoexceptExpr = getNoexceptExpr(); + } else if (EPI.ExceptionSpecType == EST_Uninstantiated) { + EPI.ExceptionSpecDecl = getExceptionSpecDecl(); + EPI.ExceptionSpecTemplate = getExceptionSpecTemplate(); + } + if (hasAnyConsumedArgs()) + EPI.ConsumedArguments = getConsumedArgsBuffer(); + return EPI; + } + + /// \brief Get the kind of exception specification on this function. + ExceptionSpecificationType getExceptionSpecType() const { + return static_cast<ExceptionSpecificationType>(ExceptionSpecType); + } + /// \brief Return whether this function has any kind of exception spec. + bool hasExceptionSpec() const { + return getExceptionSpecType() != EST_None; + } + /// \brief Return whether this function has a dynamic (throw) exception spec. + bool hasDynamicExceptionSpec() const { + return isDynamicExceptionSpec(getExceptionSpecType()); + } + /// \brief Return whether this function has a noexcept exception spec. + bool hasNoexceptExceptionSpec() const { + return isNoexceptExceptionSpec(getExceptionSpecType()); + } + /// \brief Result type of getNoexceptSpec(). + enum NoexceptResult { + NR_NoNoexcept, ///< There is no noexcept specifier. + NR_BadNoexcept, ///< The noexcept specifier has a bad expression. + NR_Dependent, ///< The noexcept specifier is dependent. + NR_Throw, ///< The noexcept specifier evaluates to false. + NR_Nothrow ///< The noexcept specifier evaluates to true. + }; + /// \brief Get the meaning of the noexcept spec on this function, if any. + NoexceptResult getNoexceptSpec(ASTContext &Ctx) const; + unsigned getNumExceptions() const { return NumExceptions; } + QualType getExceptionType(unsigned i) const { + assert(i < NumExceptions && "Invalid exception number!"); + return exception_begin()[i]; + } + Expr *getNoexceptExpr() const { + if (getExceptionSpecType() != EST_ComputedNoexcept) + return 0; + // NoexceptExpr sits where the arguments end. + return *reinterpret_cast<Expr *const *>(arg_type_end()); + } + /// \brief If this function type has an uninstantiated exception + /// specification, this is the function whose exception specification + /// is represented by this type. + FunctionDecl *getExceptionSpecDecl() const { + if (getExceptionSpecType() != EST_Uninstantiated) + return 0; + return reinterpret_cast<FunctionDecl * const *>(arg_type_end())[0]; + } + /// \brief If this function type has an uninstantiated exception + /// specification, this is the function whose exception specification + /// should be instantiated to find the exception specification for + /// this type. + FunctionDecl *getExceptionSpecTemplate() const { + if (getExceptionSpecType() != EST_Uninstantiated) + return 0; + return reinterpret_cast<FunctionDecl * const *>(arg_type_end())[1]; + } + bool isNothrow(ASTContext &Ctx) const { + ExceptionSpecificationType EST = getExceptionSpecType(); + assert(EST != EST_Delayed && EST != EST_Uninstantiated); + if (EST == EST_DynamicNone || EST == EST_BasicNoexcept) + return true; + if (EST != EST_ComputedNoexcept) + return false; + return getNoexceptSpec(Ctx) == NR_Nothrow; + } + + bool isVariadic() const { return Variadic; } + + /// \brief Determines whether this function prototype contains a + /// parameter pack at the end. + /// + /// A function template whose last parameter is a parameter pack can be + /// called with an arbitrary number of arguments, much like a variadic + /// function. + bool isTemplateVariadic() const; + + bool hasTrailingReturn() const { return HasTrailingReturn; } + + unsigned getTypeQuals() const { return FunctionType::getTypeQuals(); } + + + /// \brief Retrieve the ref-qualifier associated with this function type. + RefQualifierKind getRefQualifier() const { + return FunctionType::getRefQualifier(); + } + + typedef const QualType *arg_type_iterator; + arg_type_iterator arg_type_begin() const { + return reinterpret_cast<const QualType *>(this+1); + } + arg_type_iterator arg_type_end() const { return arg_type_begin()+NumArgs; } + + typedef const QualType *exception_iterator; + exception_iterator exception_begin() const { + // exceptions begin where arguments end + return arg_type_end(); + } + exception_iterator exception_end() const { + if (getExceptionSpecType() != EST_Dynamic) + return exception_begin(); + return exception_begin() + NumExceptions; + } + + bool hasAnyConsumedArgs() const { + return HasAnyConsumedArgs; + } + bool isArgConsumed(unsigned I) const { + assert(I < getNumArgs() && "argument index out of range!"); + if (hasAnyConsumedArgs()) + return getConsumedArgsBuffer()[I]; + return false; + } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + void printExceptionSpecification(std::string &S, + PrintingPolicy Policy) const; + + static bool classof(const Type *T) { + return T->getTypeClass() == FunctionProto; + } + static bool classof(const FunctionProtoType *) { return true; } + + void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx); + static void Profile(llvm::FoldingSetNodeID &ID, QualType Result, + arg_type_iterator ArgTys, unsigned NumArgs, + const ExtProtoInfo &EPI, const ASTContext &Context); +}; + + +/// \brief Represents the dependent type named by a dependently-scoped +/// typename using declaration, e.g. +/// using typename Base<T>::foo; +/// Template instantiation turns these into the underlying type. +class UnresolvedUsingType : public Type { + UnresolvedUsingTypenameDecl *Decl; + + UnresolvedUsingType(const UnresolvedUsingTypenameDecl *D) + : Type(UnresolvedUsing, QualType(), true, true, false, + /*ContainsUnexpandedParameterPack=*/false), + Decl(const_cast<UnresolvedUsingTypenameDecl*>(D)) {} + friend class ASTContext; // ASTContext creates these. +public: + + UnresolvedUsingTypenameDecl *getDecl() const { return Decl; } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + static bool classof(const Type *T) { + return T->getTypeClass() == UnresolvedUsing; + } + static bool classof(const UnresolvedUsingType *) { return true; } + + void Profile(llvm::FoldingSetNodeID &ID) { + return Profile(ID, Decl); + } + static void Profile(llvm::FoldingSetNodeID &ID, + UnresolvedUsingTypenameDecl *D) { + ID.AddPointer(D); + } +}; + + +class TypedefType : public Type { + TypedefNameDecl *Decl; +protected: + TypedefType(TypeClass tc, const TypedefNameDecl *D, QualType can) + : Type(tc, can, can->isDependentType(), + can->isInstantiationDependentType(), + can->isVariablyModifiedType(), + /*ContainsUnexpandedParameterPack=*/false), + Decl(const_cast<TypedefNameDecl*>(D)) { + assert(!isa<TypedefType>(can) && "Invalid canonical type"); + } + friend class ASTContext; // ASTContext creates these. +public: + + TypedefNameDecl *getDecl() const { return Decl; } + + bool isSugared() const { return true; } + QualType desugar() const; + + static bool classof(const Type *T) { return T->getTypeClass() == Typedef; } + static bool classof(const TypedefType *) { return true; } +}; + +/// TypeOfExprType (GCC extension). +class TypeOfExprType : public Type { + Expr *TOExpr; + +protected: + TypeOfExprType(Expr *E, QualType can = QualType()); + friend class ASTContext; // ASTContext creates these. +public: + Expr *getUnderlyingExpr() const { return TOExpr; } + + /// \brief Remove a single level of sugar. + QualType desugar() const; + + /// \brief Returns whether this type directly provides sugar. + bool isSugared() const; + + static bool classof(const Type *T) { return T->getTypeClass() == TypeOfExpr; } + static bool classof(const TypeOfExprType *) { return true; } +}; + +/// \brief Internal representation of canonical, dependent +/// typeof(expr) types. +/// +/// This class is used internally by the ASTContext to manage +/// canonical, dependent types, only. Clients will only see instances +/// of this class via TypeOfExprType nodes. +class DependentTypeOfExprType + : public TypeOfExprType, public llvm::FoldingSetNode { + const ASTContext &Context; + +public: + DependentTypeOfExprType(const ASTContext &Context, Expr *E) + : TypeOfExprType(E), Context(Context) { } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, Context, getUnderlyingExpr()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, + Expr *E); +}; + +/// TypeOfType (GCC extension). +class TypeOfType : public Type { + QualType TOType; + TypeOfType(QualType T, QualType can) + : Type(TypeOf, can, T->isDependentType(), + T->isInstantiationDependentType(), + T->isVariablyModifiedType(), + T->containsUnexpandedParameterPack()), + TOType(T) { + assert(!isa<TypedefType>(can) && "Invalid canonical type"); + } + friend class ASTContext; // ASTContext creates these. +public: + QualType getUnderlyingType() const { return TOType; } + + /// \brief Remove a single level of sugar. + QualType desugar() const { return getUnderlyingType(); } + + /// \brief Returns whether this type directly provides sugar. + bool isSugared() const { return true; } + + static bool classof(const Type *T) { return T->getTypeClass() == TypeOf; } + static bool classof(const TypeOfType *) { return true; } +}; + +/// DecltypeType (C++0x) +class DecltypeType : public Type { + Expr *E; + QualType UnderlyingType; + +protected: + DecltypeType(Expr *E, QualType underlyingType, QualType can = QualType()); + friend class ASTContext; // ASTContext creates these. +public: + Expr *getUnderlyingExpr() const { return E; } + QualType getUnderlyingType() const { return UnderlyingType; } + + /// \brief Remove a single level of sugar. + QualType desugar() const; + + /// \brief Returns whether this type directly provides sugar. + bool isSugared() const; + + static bool classof(const Type *T) { return T->getTypeClass() == Decltype; } + static bool classof(const DecltypeType *) { return true; } +}; + +/// \brief Internal representation of canonical, dependent +/// decltype(expr) types. +/// +/// This class is used internally by the ASTContext to manage +/// canonical, dependent types, only. Clients will only see instances +/// of this class via DecltypeType nodes. +class DependentDecltypeType : public DecltypeType, public llvm::FoldingSetNode { + const ASTContext &Context; + +public: + DependentDecltypeType(const ASTContext &Context, Expr *E); + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, Context, getUnderlyingExpr()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, + Expr *E); +}; + +/// \brief A unary type transform, which is a type constructed from another +class UnaryTransformType : public Type { +public: + enum UTTKind { + EnumUnderlyingType + }; + +private: + /// The untransformed type. + QualType BaseType; + /// The transformed type if not dependent, otherwise the same as BaseType. + QualType UnderlyingType; + + UTTKind UKind; +protected: + UnaryTransformType(QualType BaseTy, QualType UnderlyingTy, UTTKind UKind, + QualType CanonicalTy); + friend class ASTContext; +public: + bool isSugared() const { return !isDependentType(); } + QualType desugar() const { return UnderlyingType; } + + QualType getUnderlyingType() const { return UnderlyingType; } + QualType getBaseType() const { return BaseType; } + + UTTKind getUTTKind() const { return UKind; } + + static bool classof(const Type *T) { + return T->getTypeClass() == UnaryTransform; + } + static bool classof(const UnaryTransformType *) { return true; } +}; + +class TagType : public Type { + /// Stores the TagDecl associated with this type. The decl may point to any + /// TagDecl that declares the entity. + TagDecl * decl; + + friend class ASTReader; + +protected: + TagType(TypeClass TC, const TagDecl *D, QualType can); + +public: + TagDecl *getDecl() const; + + /// @brief Determines whether this type is in the process of being + /// defined. + bool isBeingDefined() const; + + static bool classof(const Type *T) { + return T->getTypeClass() >= TagFirst && T->getTypeClass() <= TagLast; + } + static bool classof(const TagType *) { return true; } +}; + +/// RecordType - This is a helper class that allows the use of isa/cast/dyncast +/// to detect TagType objects of structs/unions/classes. +class RecordType : public TagType { +protected: + explicit RecordType(const RecordDecl *D) + : TagType(Record, reinterpret_cast<const TagDecl*>(D), QualType()) { } + explicit RecordType(TypeClass TC, RecordDecl *D) + : TagType(TC, reinterpret_cast<const TagDecl*>(D), QualType()) { } + friend class ASTContext; // ASTContext creates these. +public: + + RecordDecl *getDecl() const { + return reinterpret_cast<RecordDecl*>(TagType::getDecl()); + } + + // FIXME: This predicate is a helper to QualType/Type. It needs to + // recursively check all fields for const-ness. If any field is declared + // const, it needs to return false. + bool hasConstFields() const { return false; } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + static bool classof(const Type *T) { return T->getTypeClass() == Record; } + static bool classof(const RecordType *) { return true; } +}; + +/// EnumType - This is a helper class that allows the use of isa/cast/dyncast +/// to detect TagType objects of enums. +class EnumType : public TagType { + explicit EnumType(const EnumDecl *D) + : TagType(Enum, reinterpret_cast<const TagDecl*>(D), QualType()) { } + friend class ASTContext; // ASTContext creates these. +public: + + EnumDecl *getDecl() const { + return reinterpret_cast<EnumDecl*>(TagType::getDecl()); + } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + static bool classof(const Type *T) { return T->getTypeClass() == Enum; } + static bool classof(const EnumType *) { return true; } +}; + +/// AttributedType - An attributed type is a type to which a type +/// attribute has been applied. The "modified type" is the +/// fully-sugared type to which the attributed type was applied; +/// generally it is not canonically equivalent to the attributed type. +/// The "equivalent type" is the minimally-desugared type which the +/// type is canonically equivalent to. +/// +/// For example, in the following attributed type: +/// int32_t __attribute__((vector_size(16))) +/// - the modified type is the TypedefType for int32_t +/// - the equivalent type is VectorType(16, int32_t) +/// - the canonical type is VectorType(16, int) +class AttributedType : public Type, public llvm::FoldingSetNode { +public: + // It is really silly to have yet another attribute-kind enum, but + // clang::attr::Kind doesn't currently cover the pure type attrs. + enum Kind { + // Expression operand. + attr_address_space, + attr_regparm, + attr_vector_size, + attr_neon_vector_type, + attr_neon_polyvector_type, + + FirstExprOperandKind = attr_address_space, + LastExprOperandKind = attr_neon_polyvector_type, + + // Enumerated operand (string or keyword). + attr_objc_gc, + attr_objc_ownership, + attr_pcs, + + FirstEnumOperandKind = attr_objc_gc, + LastEnumOperandKind = attr_pcs, + + // No operand. + attr_noreturn, + attr_cdecl, + attr_fastcall, + attr_stdcall, + attr_thiscall, + attr_pascal + }; + +private: + QualType ModifiedType; + QualType EquivalentType; + + friend class ASTContext; // creates these + + AttributedType(QualType canon, Kind attrKind, + QualType modified, QualType equivalent) + : Type(Attributed, canon, canon->isDependentType(), + canon->isInstantiationDependentType(), + canon->isVariablyModifiedType(), + canon->containsUnexpandedParameterPack()), + ModifiedType(modified), EquivalentType(equivalent) { + AttributedTypeBits.AttrKind = attrKind; + } + +public: + Kind getAttrKind() const { + return static_cast<Kind>(AttributedTypeBits.AttrKind); + } + + QualType getModifiedType() const { return ModifiedType; } + QualType getEquivalentType() const { return EquivalentType; } + + bool isSugared() const { return true; } + QualType desugar() const { return getEquivalentType(); } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getAttrKind(), ModifiedType, EquivalentType); + } + + static void Profile(llvm::FoldingSetNodeID &ID, Kind attrKind, + QualType modified, QualType equivalent) { + ID.AddInteger(attrKind); + ID.AddPointer(modified.getAsOpaquePtr()); + ID.AddPointer(equivalent.getAsOpaquePtr()); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == Attributed; + } + static bool classof(const AttributedType *T) { return true; } +}; + +class TemplateTypeParmType : public Type, public llvm::FoldingSetNode { + // Helper data collector for canonical types. + struct CanonicalTTPTInfo { + unsigned Depth : 15; + unsigned ParameterPack : 1; + unsigned Index : 16; + }; + + union { + // Info for the canonical type. + CanonicalTTPTInfo CanTTPTInfo; + // Info for the non-canonical type. + TemplateTypeParmDecl *TTPDecl; + }; + + /// Build a non-canonical type. + TemplateTypeParmType(TemplateTypeParmDecl *TTPDecl, QualType Canon) + : Type(TemplateTypeParm, Canon, /*Dependent=*/true, + /*InstantiationDependent=*/true, + /*VariablyModified=*/false, + Canon->containsUnexpandedParameterPack()), + TTPDecl(TTPDecl) { } + + /// Build the canonical type. + TemplateTypeParmType(unsigned D, unsigned I, bool PP) + : Type(TemplateTypeParm, QualType(this, 0), + /*Dependent=*/true, + /*InstantiationDependent=*/true, + /*VariablyModified=*/false, PP) { + CanTTPTInfo.Depth = D; + CanTTPTInfo.Index = I; + CanTTPTInfo.ParameterPack = PP; + } + + friend class ASTContext; // ASTContext creates these + + const CanonicalTTPTInfo& getCanTTPTInfo() const { + QualType Can = getCanonicalTypeInternal(); + return Can->castAs<TemplateTypeParmType>()->CanTTPTInfo; + } + +public: + unsigned getDepth() const { return getCanTTPTInfo().Depth; } + unsigned getIndex() const { return getCanTTPTInfo().Index; } + bool isParameterPack() const { return getCanTTPTInfo().ParameterPack; } + + TemplateTypeParmDecl *getDecl() const { + return isCanonicalUnqualified() ? 0 : TTPDecl; + } + + IdentifierInfo *getIdentifier() const; + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getDepth(), getIndex(), isParameterPack(), getDecl()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, unsigned Depth, + unsigned Index, bool ParameterPack, + TemplateTypeParmDecl *TTPDecl) { + ID.AddInteger(Depth); + ID.AddInteger(Index); + ID.AddBoolean(ParameterPack); + ID.AddPointer(TTPDecl); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == TemplateTypeParm; + } + static bool classof(const TemplateTypeParmType *T) { return true; } +}; + +/// \brief Represents the result of substituting a type for a template +/// type parameter. +/// +/// Within an instantiated template, all template type parameters have +/// been replaced with these. They are used solely to record that a +/// type was originally written as a template type parameter; +/// therefore they are never canonical. +class SubstTemplateTypeParmType : public Type, public llvm::FoldingSetNode { + // The original type parameter. + const TemplateTypeParmType *Replaced; + + SubstTemplateTypeParmType(const TemplateTypeParmType *Param, QualType Canon) + : Type(SubstTemplateTypeParm, Canon, Canon->isDependentType(), + Canon->isInstantiationDependentType(), + Canon->isVariablyModifiedType(), + Canon->containsUnexpandedParameterPack()), + Replaced(Param) { } + + friend class ASTContext; + +public: + /// Gets the template parameter that was substituted for. + const TemplateTypeParmType *getReplacedParameter() const { + return Replaced; + } + + /// Gets the type that was substituted for the template + /// parameter. + QualType getReplacementType() const { + return getCanonicalTypeInternal(); + } + + bool isSugared() const { return true; } + QualType desugar() const { return getReplacementType(); } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getReplacedParameter(), getReplacementType()); + } + static void Profile(llvm::FoldingSetNodeID &ID, + const TemplateTypeParmType *Replaced, + QualType Replacement) { + ID.AddPointer(Replaced); + ID.AddPointer(Replacement.getAsOpaquePtr()); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == SubstTemplateTypeParm; + } + static bool classof(const SubstTemplateTypeParmType *T) { return true; } +}; + +/// \brief Represents the result of substituting a set of types for a template +/// type parameter pack. +/// +/// When a pack expansion in the source code contains multiple parameter packs +/// and those parameter packs correspond to different levels of template +/// parameter lists, this type node is used to represent a template type +/// parameter pack from an outer level, which has already had its argument pack +/// substituted but that still lives within a pack expansion that itself +/// could not be instantiated. When actually performing a substitution into +/// that pack expansion (e.g., when all template parameters have corresponding +/// arguments), this type will be replaced with the \c SubstTemplateTypeParmType +/// at the current pack substitution index. +class SubstTemplateTypeParmPackType : public Type, public llvm::FoldingSetNode { + /// \brief The original type parameter. + const TemplateTypeParmType *Replaced; + + /// \brief A pointer to the set of template arguments that this + /// parameter pack is instantiated with. + const TemplateArgument *Arguments; + + /// \brief The number of template arguments in \c Arguments. + unsigned NumArguments; + + SubstTemplateTypeParmPackType(const TemplateTypeParmType *Param, + QualType Canon, + const TemplateArgument &ArgPack); + + friend class ASTContext; + +public: + IdentifierInfo *getIdentifier() const { return Replaced->getIdentifier(); } + + /// Gets the template parameter that was substituted for. + const TemplateTypeParmType *getReplacedParameter() const { + return Replaced; + } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + TemplateArgument getArgumentPack() const; + + void Profile(llvm::FoldingSetNodeID &ID); + static void Profile(llvm::FoldingSetNodeID &ID, + const TemplateTypeParmType *Replaced, + const TemplateArgument &ArgPack); + + static bool classof(const Type *T) { + return T->getTypeClass() == SubstTemplateTypeParmPack; + } + static bool classof(const SubstTemplateTypeParmPackType *T) { return true; } +}; + +/// \brief Represents a C++0x auto type. +/// +/// These types are usually a placeholder for a deduced type. However, within +/// templates and before the initializer is attached, there is no deduced type +/// and an auto type is type-dependent and canonical. +class AutoType : public Type, public llvm::FoldingSetNode { + AutoType(QualType DeducedType) + : Type(Auto, DeducedType.isNull() ? QualType(this, 0) : DeducedType, + /*Dependent=*/DeducedType.isNull(), + /*InstantiationDependent=*/DeducedType.isNull(), + /*VariablyModified=*/false, /*ContainsParameterPack=*/false) { + assert((DeducedType.isNull() || !DeducedType->isDependentType()) && + "deduced a dependent type for auto"); + } + + friend class ASTContext; // ASTContext creates these + +public: + bool isSugared() const { return isDeduced(); } + QualType desugar() const { return getCanonicalTypeInternal(); } + + QualType getDeducedType() const { + return isDeduced() ? getCanonicalTypeInternal() : QualType(); + } + bool isDeduced() const { + return !isDependentType(); + } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getDeducedType()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, + QualType Deduced) { + ID.AddPointer(Deduced.getAsOpaquePtr()); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == Auto; + } + static bool classof(const AutoType *T) { return true; } +}; + +/// \brief Represents a type template specialization; the template +/// must be a class template, a type alias template, or a template +/// template parameter. A template which cannot be resolved to one of +/// these, e.g. because it is written with a dependent scope +/// specifier, is instead represented as a +/// @c DependentTemplateSpecializationType. +/// +/// A non-dependent template specialization type is always "sugar", +/// typically for a @c RecordType. For example, a class template +/// specialization type of @c vector<int> will refer to a tag type for +/// the instantiation @c std::vector<int, std::allocator<int>> +/// +/// Template specializations are dependent if either the template or +/// any of the template arguments are dependent, in which case the +/// type may also be canonical. +/// +/// Instances of this type are allocated with a trailing array of +/// TemplateArguments, followed by a QualType representing the +/// non-canonical aliased type when the template is a type alias +/// template. +class TemplateSpecializationType + : public Type, public llvm::FoldingSetNode { + /// \brief The name of the template being specialized. This is + /// either a TemplateName::Template (in which case it is a + /// ClassTemplateDecl*, a TemplateTemplateParmDecl*, or a + /// TypeAliasTemplateDecl*), a + /// TemplateName::SubstTemplateTemplateParmPack, or a + /// TemplateName::SubstTemplateTemplateParm (in which case the + /// replacement must, recursively, be one of these). + TemplateName Template; + + /// \brief - The number of template arguments named in this class + /// template specialization. + unsigned NumArgs : 31; + + /// \brief Whether this template specialization type is a substituted + /// type alias. + bool TypeAlias : 1; + + TemplateSpecializationType(TemplateName T, + const TemplateArgument *Args, + unsigned NumArgs, QualType Canon, + QualType Aliased); + + friend class ASTContext; // ASTContext creates these + +public: + /// \brief Determine whether any of the given template arguments are + /// dependent. + static bool anyDependentTemplateArguments(const TemplateArgument *Args, + unsigned NumArgs, + bool &InstantiationDependent); + + static bool anyDependentTemplateArguments(const TemplateArgumentLoc *Args, + unsigned NumArgs, + bool &InstantiationDependent); + + static bool anyDependentTemplateArguments(const TemplateArgumentListInfo &, + bool &InstantiationDependent); + + /// \brief Print a template argument list, including the '<' and '>' + /// enclosing the template arguments. + static std::string PrintTemplateArgumentList(const TemplateArgument *Args, + unsigned NumArgs, + const PrintingPolicy &Policy, + bool SkipBrackets = false); + + static std::string PrintTemplateArgumentList(const TemplateArgumentLoc *Args, + unsigned NumArgs, + const PrintingPolicy &Policy); + + static std::string PrintTemplateArgumentList(const TemplateArgumentListInfo &, + const PrintingPolicy &Policy); + + /// True if this template specialization type matches a current + /// instantiation in the context in which it is found. + bool isCurrentInstantiation() const { + return isa<InjectedClassNameType>(getCanonicalTypeInternal()); + } + + /// \brief Determine if this template specialization type is for a type alias + /// template that has been substituted. + /// + /// Nearly every template specialization type whose template is an alias + /// template will be substituted. However, this is not the case when + /// the specialization contains a pack expansion but the template alias + /// does not have a corresponding parameter pack, e.g., + /// + /// \code + /// template<typename T, typename U, typename V> struct S; + /// template<typename T, typename U> using A = S<T, int, U>; + /// template<typename... Ts> struct X { + /// typedef A<Ts...> type; // not a type alias + /// }; + /// \endcode + bool isTypeAlias() const { return TypeAlias; } + + /// Get the aliased type, if this is a specialization of a type alias + /// template. + QualType getAliasedType() const { + assert(isTypeAlias() && "not a type alias template specialization"); + return *reinterpret_cast<const QualType*>(end()); + } + + typedef const TemplateArgument * iterator; + + iterator begin() const { return getArgs(); } + iterator end() const; // defined inline in TemplateBase.h + + /// \brief Retrieve the name of the template that we are specializing. + TemplateName getTemplateName() const { return Template; } + + /// \brief Retrieve the template arguments. + const TemplateArgument *getArgs() const { + return reinterpret_cast<const TemplateArgument *>(this + 1); + } + + /// \brief Retrieve the number of template arguments. + unsigned getNumArgs() const { return NumArgs; } + + /// \brief Retrieve a specific template argument as a type. + /// \precondition @c isArgType(Arg) + const TemplateArgument &getArg(unsigned Idx) const; // in TemplateBase.h + + bool isSugared() const { + return !isDependentType() || isCurrentInstantiation() || isTypeAlias(); + } + QualType desugar() const { return getCanonicalTypeInternal(); } + + void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx) { + Profile(ID, Template, getArgs(), NumArgs, Ctx); + if (isTypeAlias()) + getAliasedType().Profile(ID); + } + + static void Profile(llvm::FoldingSetNodeID &ID, TemplateName T, + const TemplateArgument *Args, + unsigned NumArgs, + const ASTContext &Context); + + static bool classof(const Type *T) { + return T->getTypeClass() == TemplateSpecialization; + } + static bool classof(const TemplateSpecializationType *T) { return true; } +}; + +/// \brief The injected class name of a C++ class template or class +/// template partial specialization. Used to record that a type was +/// spelled with a bare identifier rather than as a template-id; the +/// equivalent for non-templated classes is just RecordType. +/// +/// Injected class name types are always dependent. Template +/// instantiation turns these into RecordTypes. +/// +/// Injected class name types are always canonical. This works +/// because it is impossible to compare an injected class name type +/// with the corresponding non-injected template type, for the same +/// reason that it is impossible to directly compare template +/// parameters from different dependent contexts: injected class name +/// types can only occur within the scope of a particular templated +/// declaration, and within that scope every template specialization +/// will canonicalize to the injected class name (when appropriate +/// according to the rules of the language). +class InjectedClassNameType : public Type { + CXXRecordDecl *Decl; + + /// The template specialization which this type represents. + /// For example, in + /// template <class T> class A { ... }; + /// this is A<T>, whereas in + /// template <class X, class Y> class A<B<X,Y> > { ... }; + /// this is A<B<X,Y> >. + /// + /// It is always unqualified, always a template specialization type, + /// and always dependent. + QualType InjectedType; + + friend class ASTContext; // ASTContext creates these. + friend class ASTReader; // FIXME: ASTContext::getInjectedClassNameType is not + // currently suitable for AST reading, too much + // interdependencies. + InjectedClassNameType(CXXRecordDecl *D, QualType TST) + : Type(InjectedClassName, QualType(), /*Dependent=*/true, + /*InstantiationDependent=*/true, + /*VariablyModified=*/false, + /*ContainsUnexpandedParameterPack=*/false), + Decl(D), InjectedType(TST) { + assert(isa<TemplateSpecializationType>(TST)); + assert(!TST.hasQualifiers()); + assert(TST->isDependentType()); + } + +public: + QualType getInjectedSpecializationType() const { return InjectedType; } + const TemplateSpecializationType *getInjectedTST() const { + return cast<TemplateSpecializationType>(InjectedType.getTypePtr()); + } + + CXXRecordDecl *getDecl() const; + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + static bool classof(const Type *T) { + return T->getTypeClass() == InjectedClassName; + } + static bool classof(const InjectedClassNameType *T) { return true; } +}; + +/// \brief The kind of a tag type. +enum TagTypeKind { + /// \brief The "struct" keyword. + TTK_Struct, + /// \brief The "union" keyword. + TTK_Union, + /// \brief The "class" keyword. + TTK_Class, + /// \brief The "enum" keyword. + TTK_Enum +}; + +/// \brief The elaboration keyword that precedes a qualified type name or +/// introduces an elaborated-type-specifier. +enum ElaboratedTypeKeyword { + /// \brief The "struct" keyword introduces the elaborated-type-specifier. + ETK_Struct, + /// \brief The "union" keyword introduces the elaborated-type-specifier. + ETK_Union, + /// \brief The "class" keyword introduces the elaborated-type-specifier. + ETK_Class, + /// \brief The "enum" keyword introduces the elaborated-type-specifier. + ETK_Enum, + /// \brief The "typename" keyword precedes the qualified type name, e.g., + /// \c typename T::type. + ETK_Typename, + /// \brief No keyword precedes the qualified type name. + ETK_None +}; + +/// A helper class for Type nodes having an ElaboratedTypeKeyword. +/// The keyword in stored in the free bits of the base class. +/// Also provides a few static helpers for converting and printing +/// elaborated type keyword and tag type kind enumerations. +class TypeWithKeyword : public Type { +protected: + TypeWithKeyword(ElaboratedTypeKeyword Keyword, TypeClass tc, + QualType Canonical, bool Dependent, + bool InstantiationDependent, bool VariablyModified, + bool ContainsUnexpandedParameterPack) + : Type(tc, Canonical, Dependent, InstantiationDependent, VariablyModified, + ContainsUnexpandedParameterPack) { + TypeWithKeywordBits.Keyword = Keyword; + } + +public: + ElaboratedTypeKeyword getKeyword() const { + return static_cast<ElaboratedTypeKeyword>(TypeWithKeywordBits.Keyword); + } + + /// getKeywordForTypeSpec - Converts a type specifier (DeclSpec::TST) + /// into an elaborated type keyword. + static ElaboratedTypeKeyword getKeywordForTypeSpec(unsigned TypeSpec); + + /// getTagTypeKindForTypeSpec - Converts a type specifier (DeclSpec::TST) + /// into a tag type kind. It is an error to provide a type specifier + /// which *isn't* a tag kind here. + static TagTypeKind getTagTypeKindForTypeSpec(unsigned TypeSpec); + + /// getKeywordForTagDeclKind - Converts a TagTypeKind into an + /// elaborated type keyword. + static ElaboratedTypeKeyword getKeywordForTagTypeKind(TagTypeKind Tag); + + /// getTagTypeKindForKeyword - Converts an elaborated type keyword into + // a TagTypeKind. It is an error to provide an elaborated type keyword + /// which *isn't* a tag kind here. + static TagTypeKind getTagTypeKindForKeyword(ElaboratedTypeKeyword Keyword); + + static bool KeywordIsTagTypeKind(ElaboratedTypeKeyword Keyword); + + static const char *getKeywordName(ElaboratedTypeKeyword Keyword); + + static const char *getTagTypeKindName(TagTypeKind Kind) { + return getKeywordName(getKeywordForTagTypeKind(Kind)); + } + + class CannotCastToThisType {}; + static CannotCastToThisType classof(const Type *); +}; + +/// \brief Represents a type that was referred to using an elaborated type +/// keyword, e.g., struct S, or via a qualified name, e.g., N::M::type, +/// or both. +/// +/// This type is used to keep track of a type name as written in the +/// source code, including tag keywords and any nested-name-specifiers. +/// The type itself is always "sugar", used to express what was written +/// in the source code but containing no additional semantic information. +class ElaboratedType : public TypeWithKeyword, public llvm::FoldingSetNode { + + /// \brief The nested name specifier containing the qualifier. + NestedNameSpecifier *NNS; + + /// \brief The type that this qualified name refers to. + QualType NamedType; + + ElaboratedType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, + QualType NamedType, QualType CanonType) + : TypeWithKeyword(Keyword, Elaborated, CanonType, + NamedType->isDependentType(), + NamedType->isInstantiationDependentType(), + NamedType->isVariablyModifiedType(), + NamedType->containsUnexpandedParameterPack()), + NNS(NNS), NamedType(NamedType) { + assert(!(Keyword == ETK_None && NNS == 0) && + "ElaboratedType cannot have elaborated type keyword " + "and name qualifier both null."); + } + + friend class ASTContext; // ASTContext creates these + +public: + ~ElaboratedType(); + + /// \brief Retrieve the qualification on this type. + NestedNameSpecifier *getQualifier() const { return NNS; } + + /// \brief Retrieve the type named by the qualified-id. + QualType getNamedType() const { return NamedType; } + + /// \brief Remove a single level of sugar. + QualType desugar() const { return getNamedType(); } + + /// \brief Returns whether this type directly provides sugar. + bool isSugared() const { return true; } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getKeyword(), NNS, NamedType); + } + + static void Profile(llvm::FoldingSetNodeID &ID, ElaboratedTypeKeyword Keyword, + NestedNameSpecifier *NNS, QualType NamedType) { + ID.AddInteger(Keyword); + ID.AddPointer(NNS); + NamedType.Profile(ID); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == Elaborated; + } + static bool classof(const ElaboratedType *T) { return true; } +}; + +/// \brief Represents a qualified type name for which the type name is +/// dependent. +/// +/// DependentNameType represents a class of dependent types that involve a +/// dependent nested-name-specifier (e.g., "T::") followed by a (dependent) +/// name of a type. The DependentNameType may start with a "typename" (for a +/// typename-specifier), "class", "struct", "union", or "enum" (for a +/// dependent elaborated-type-specifier), or nothing (in contexts where we +/// know that we must be referring to a type, e.g., in a base class specifier). +class DependentNameType : public TypeWithKeyword, public llvm::FoldingSetNode { + + /// \brief The nested name specifier containing the qualifier. + NestedNameSpecifier *NNS; + + /// \brief The type that this typename specifier refers to. + const IdentifierInfo *Name; + + DependentNameType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, + const IdentifierInfo *Name, QualType CanonType) + : TypeWithKeyword(Keyword, DependentName, CanonType, /*Dependent=*/true, + /*InstantiationDependent=*/true, + /*VariablyModified=*/false, + NNS->containsUnexpandedParameterPack()), + NNS(NNS), Name(Name) { + assert(NNS->isDependent() && + "DependentNameType requires a dependent nested-name-specifier"); + } + + friend class ASTContext; // ASTContext creates these + +public: + /// \brief Retrieve the qualification on this type. + NestedNameSpecifier *getQualifier() const { return NNS; } + + /// \brief Retrieve the type named by the typename specifier as an + /// identifier. + /// + /// This routine will return a non-NULL identifier pointer when the + /// form of the original typename was terminated by an identifier, + /// e.g., "typename T::type". + const IdentifierInfo *getIdentifier() const { + return Name; + } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getKeyword(), NNS, Name); + } + + static void Profile(llvm::FoldingSetNodeID &ID, ElaboratedTypeKeyword Keyword, + NestedNameSpecifier *NNS, const IdentifierInfo *Name) { + ID.AddInteger(Keyword); + ID.AddPointer(NNS); + ID.AddPointer(Name); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == DependentName; + } + static bool classof(const DependentNameType *T) { return true; } +}; + +/// DependentTemplateSpecializationType - Represents a template +/// specialization type whose template cannot be resolved, e.g. +/// A<T>::template B<T> +class DependentTemplateSpecializationType : + public TypeWithKeyword, public llvm::FoldingSetNode { + + /// \brief The nested name specifier containing the qualifier. + NestedNameSpecifier *NNS; + + /// \brief The identifier of the template. + const IdentifierInfo *Name; + + /// \brief - The number of template arguments named in this class + /// template specialization. + unsigned NumArgs; + + const TemplateArgument *getArgBuffer() const { + return reinterpret_cast<const TemplateArgument*>(this+1); + } + TemplateArgument *getArgBuffer() { + return reinterpret_cast<TemplateArgument*>(this+1); + } + + DependentTemplateSpecializationType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier *NNS, + const IdentifierInfo *Name, + unsigned NumArgs, + const TemplateArgument *Args, + QualType Canon); + + friend class ASTContext; // ASTContext creates these + +public: + NestedNameSpecifier *getQualifier() const { return NNS; } + const IdentifierInfo *getIdentifier() const { return Name; } + + /// \brief Retrieve the template arguments. + const TemplateArgument *getArgs() const { + return getArgBuffer(); + } + + /// \brief Retrieve the number of template arguments. + unsigned getNumArgs() const { return NumArgs; } + + const TemplateArgument &getArg(unsigned Idx) const; // in TemplateBase.h + + typedef const TemplateArgument * iterator; + iterator begin() const { return getArgs(); } + iterator end() const; // inline in TemplateBase.h + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context) { + Profile(ID, Context, getKeyword(), NNS, Name, NumArgs, getArgs()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, + const ASTContext &Context, + ElaboratedTypeKeyword Keyword, + NestedNameSpecifier *Qualifier, + const IdentifierInfo *Name, + unsigned NumArgs, + const TemplateArgument *Args); + + static bool classof(const Type *T) { + return T->getTypeClass() == DependentTemplateSpecialization; + } + static bool classof(const DependentTemplateSpecializationType *T) { + return true; + } +}; + +/// \brief Represents a pack expansion of types. +/// +/// Pack expansions are part of C++0x variadic templates. A pack +/// expansion contains a pattern, which itself contains one or more +/// "unexpanded" parameter packs. When instantiated, a pack expansion +/// produces a series of types, each instantiated from the pattern of +/// the expansion, where the Ith instantiation of the pattern uses the +/// Ith arguments bound to each of the unexpanded parameter packs. The +/// pack expansion is considered to "expand" these unexpanded +/// parameter packs. +/// +/// \code +/// template<typename ...Types> struct tuple; +/// +/// template<typename ...Types> +/// struct tuple_of_references { +/// typedef tuple<Types&...> type; +/// }; +/// \endcode +/// +/// Here, the pack expansion \c Types&... is represented via a +/// PackExpansionType whose pattern is Types&. +class PackExpansionType : public Type, public llvm::FoldingSetNode { + /// \brief The pattern of the pack expansion. + QualType Pattern; + + /// \brief The number of expansions that this pack expansion will + /// generate when substituted (+1), or indicates that + /// + /// This field will only have a non-zero value when some of the parameter + /// packs that occur within the pattern have been substituted but others have + /// not. + unsigned NumExpansions; + + PackExpansionType(QualType Pattern, QualType Canon, + llvm::Optional<unsigned> NumExpansions) + : Type(PackExpansion, Canon, /*Dependent=*/true, + /*InstantiationDependent=*/true, + /*VariableModified=*/Pattern->isVariablyModifiedType(), + /*ContainsUnexpandedParameterPack=*/false), + Pattern(Pattern), + NumExpansions(NumExpansions? *NumExpansions + 1: 0) { } + + friend class ASTContext; // ASTContext creates these + +public: + /// \brief Retrieve the pattern of this pack expansion, which is the + /// type that will be repeatedly instantiated when instantiating the + /// pack expansion itself. + QualType getPattern() const { return Pattern; } + + /// \brief Retrieve the number of expansions that this pack expansion will + /// generate, if known. + llvm::Optional<unsigned> getNumExpansions() const { + if (NumExpansions) + return NumExpansions - 1; + + return llvm::Optional<unsigned>(); + } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getPattern(), getNumExpansions()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, QualType Pattern, + llvm::Optional<unsigned> NumExpansions) { + ID.AddPointer(Pattern.getAsOpaquePtr()); + ID.AddBoolean(NumExpansions); + if (NumExpansions) + ID.AddInteger(*NumExpansions); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == PackExpansion; + } + static bool classof(const PackExpansionType *T) { + return true; + } +}; + +/// ObjCObjectType - Represents a class type in Objective C. +/// Every Objective C type is a combination of a base type and a +/// list of protocols. +/// +/// Given the following declarations: +/// @class C; +/// @protocol P; +/// +/// 'C' is an ObjCInterfaceType C. It is sugar for an ObjCObjectType +/// with base C and no protocols. +/// +/// 'C<P>' is an ObjCObjectType with base C and protocol list [P]. +/// +/// 'id' is a TypedefType which is sugar for an ObjCPointerType whose +/// pointee is an ObjCObjectType with base BuiltinType::ObjCIdType +/// and no protocols. +/// +/// 'id<P>' is an ObjCPointerType whose pointee is an ObjCObjecType +/// with base BuiltinType::ObjCIdType and protocol list [P]. Eventually +/// this should get its own sugar class to better represent the source. +class ObjCObjectType : public Type { + // ObjCObjectType.NumProtocols - the number of protocols stored + // after the ObjCObjectPointerType node. + // + // These protocols are those written directly on the type. If + // protocol qualifiers ever become additive, the iterators will need + // to get kindof complicated. + // + // In the canonical object type, these are sorted alphabetically + // and uniqued. + + /// Either a BuiltinType or an InterfaceType or sugar for either. + QualType BaseType; + + ObjCProtocolDecl * const *getProtocolStorage() const { + return const_cast<ObjCObjectType*>(this)->getProtocolStorage(); + } + + ObjCProtocolDecl **getProtocolStorage(); + +protected: + ObjCObjectType(QualType Canonical, QualType Base, + ObjCProtocolDecl * const *Protocols, unsigned NumProtocols); + + enum Nonce_ObjCInterface { Nonce_ObjCInterface }; + ObjCObjectType(enum Nonce_ObjCInterface) + : Type(ObjCInterface, QualType(), false, false, false, false), + BaseType(QualType(this_(), 0)) { + ObjCObjectTypeBits.NumProtocols = 0; + } + +public: + /// getBaseType - Gets the base type of this object type. This is + /// always (possibly sugar for) one of: + /// - the 'id' builtin type (as opposed to the 'id' type visible to the + /// user, which is a typedef for an ObjCPointerType) + /// - the 'Class' builtin type (same caveat) + /// - an ObjCObjectType (currently always an ObjCInterfaceType) + QualType getBaseType() const { return BaseType; } + + bool isObjCId() const { + return getBaseType()->isSpecificBuiltinType(BuiltinType::ObjCId); + } + bool isObjCClass() const { + return getBaseType()->isSpecificBuiltinType(BuiltinType::ObjCClass); + } + bool isObjCUnqualifiedId() const { return qual_empty() && isObjCId(); } + bool isObjCUnqualifiedClass() const { return qual_empty() && isObjCClass(); } + bool isObjCUnqualifiedIdOrClass() const { + if (!qual_empty()) return false; + if (const BuiltinType *T = getBaseType()->getAs<BuiltinType>()) + return T->getKind() == BuiltinType::ObjCId || + T->getKind() == BuiltinType::ObjCClass; + return false; + } + bool isObjCQualifiedId() const { return !qual_empty() && isObjCId(); } + bool isObjCQualifiedClass() const { return !qual_empty() && isObjCClass(); } + + /// Gets the interface declaration for this object type, if the base type + /// really is an interface. + ObjCInterfaceDecl *getInterface() const; + + typedef ObjCProtocolDecl * const *qual_iterator; + + qual_iterator qual_begin() const { return getProtocolStorage(); } + qual_iterator qual_end() const { return qual_begin() + getNumProtocols(); } + + bool qual_empty() const { return getNumProtocols() == 0; } + + /// getNumProtocols - Return the number of qualifying protocols in this + /// interface type, or 0 if there are none. + unsigned getNumProtocols() const { return ObjCObjectTypeBits.NumProtocols; } + + /// \brief Fetch a protocol by index. + ObjCProtocolDecl *getProtocol(unsigned I) const { + assert(I < getNumProtocols() && "Out-of-range protocol access"); + return qual_begin()[I]; + } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + static bool classof(const Type *T) { + return T->getTypeClass() == ObjCObject || + T->getTypeClass() == ObjCInterface; + } + static bool classof(const ObjCObjectType *) { return true; } +}; + +/// ObjCObjectTypeImpl - A class providing a concrete implementation +/// of ObjCObjectType, so as to not increase the footprint of +/// ObjCInterfaceType. Code outside of ASTContext and the core type +/// system should not reference this type. +class ObjCObjectTypeImpl : public ObjCObjectType, public llvm::FoldingSetNode { + friend class ASTContext; + + // If anyone adds fields here, ObjCObjectType::getProtocolStorage() + // will need to be modified. + + ObjCObjectTypeImpl(QualType Canonical, QualType Base, + ObjCProtocolDecl * const *Protocols, + unsigned NumProtocols) + : ObjCObjectType(Canonical, Base, Protocols, NumProtocols) {} + +public: + void Profile(llvm::FoldingSetNodeID &ID); + static void Profile(llvm::FoldingSetNodeID &ID, + QualType Base, + ObjCProtocolDecl *const *protocols, + unsigned NumProtocols); +}; + +inline ObjCProtocolDecl **ObjCObjectType::getProtocolStorage() { + return reinterpret_cast<ObjCProtocolDecl**>( + static_cast<ObjCObjectTypeImpl*>(this) + 1); +} + +/// ObjCInterfaceType - Interfaces are the core concept in Objective-C for +/// object oriented design. They basically correspond to C++ classes. There +/// are two kinds of interface types, normal interfaces like "NSString" and +/// qualified interfaces, which are qualified with a protocol list like +/// "NSString<NSCopyable, NSAmazing>". +/// +/// ObjCInterfaceType guarantees the following properties when considered +/// as a subtype of its superclass, ObjCObjectType: +/// - There are no protocol qualifiers. To reinforce this, code which +/// tries to invoke the protocol methods via an ObjCInterfaceType will +/// fail to compile. +/// - It is its own base type. That is, if T is an ObjCInterfaceType*, +/// T->getBaseType() == QualType(T, 0). +class ObjCInterfaceType : public ObjCObjectType { + mutable ObjCInterfaceDecl *Decl; + + ObjCInterfaceType(const ObjCInterfaceDecl *D) + : ObjCObjectType(Nonce_ObjCInterface), + Decl(const_cast<ObjCInterfaceDecl*>(D)) {} + friend class ASTContext; // ASTContext creates these. + friend class ASTReader; + friend class ObjCInterfaceDecl; + +public: + /// getDecl - Get the declaration of this interface. + ObjCInterfaceDecl *getDecl() const { return Decl; } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + static bool classof(const Type *T) { + return T->getTypeClass() == ObjCInterface; + } + static bool classof(const ObjCInterfaceType *) { return true; } + + // Nonsense to "hide" certain members of ObjCObjectType within this + // class. People asking for protocols on an ObjCInterfaceType are + // not going to get what they want: ObjCInterfaceTypes are + // guaranteed to have no protocols. + enum { + qual_iterator, + qual_begin, + qual_end, + getNumProtocols, + getProtocol + }; +}; + +inline ObjCInterfaceDecl *ObjCObjectType::getInterface() const { + if (const ObjCInterfaceType *T = + getBaseType()->getAs<ObjCInterfaceType>()) + return T->getDecl(); + return 0; +} + +/// ObjCObjectPointerType - Used to represent a pointer to an +/// Objective C object. These are constructed from pointer +/// declarators when the pointee type is an ObjCObjectType (or sugar +/// for one). In addition, the 'id' and 'Class' types are typedefs +/// for these, and the protocol-qualified types 'id<P>' and 'Class<P>' +/// are translated into these. +/// +/// Pointers to pointers to Objective C objects are still PointerTypes; +/// only the first level of pointer gets it own type implementation. +class ObjCObjectPointerType : public Type, public llvm::FoldingSetNode { + QualType PointeeType; + + ObjCObjectPointerType(QualType Canonical, QualType Pointee) + : Type(ObjCObjectPointer, Canonical, false, false, false, false), + PointeeType(Pointee) {} + friend class ASTContext; // ASTContext creates these. + +public: + /// getPointeeType - Gets the type pointed to by this ObjC pointer. + /// The result will always be an ObjCObjectType or sugar thereof. + QualType getPointeeType() const { return PointeeType; } + + /// getObjCObjectType - Gets the type pointed to by this ObjC + /// pointer. This method always returns non-null. + /// + /// This method is equivalent to getPointeeType() except that + /// it discards any typedefs (or other sugar) between this + /// type and the "outermost" object type. So for: + /// @class A; @protocol P; @protocol Q; + /// typedef A<P> AP; + /// typedef A A1; + /// typedef A1<P> A1P; + /// typedef A1P<Q> A1PQ; + /// For 'A*', getObjectType() will return 'A'. + /// For 'A<P>*', getObjectType() will return 'A<P>'. + /// For 'AP*', getObjectType() will return 'A<P>'. + /// For 'A1*', getObjectType() will return 'A'. + /// For 'A1<P>*', getObjectType() will return 'A1<P>'. + /// For 'A1P*', getObjectType() will return 'A1<P>'. + /// For 'A1PQ*', getObjectType() will return 'A1<Q>', because + /// adding protocols to a protocol-qualified base discards the + /// old qualifiers (for now). But if it didn't, getObjectType() + /// would return 'A1P<Q>' (and we'd have to make iterating over + /// qualifiers more complicated). + const ObjCObjectType *getObjectType() const { + return PointeeType->castAs<ObjCObjectType>(); + } + + /// getInterfaceType - If this pointer points to an Objective C + /// @interface type, gets the type for that interface. Any protocol + /// qualifiers on the interface are ignored. + /// + /// \return null if the base type for this pointer is 'id' or 'Class' + const ObjCInterfaceType *getInterfaceType() const { + return getObjectType()->getBaseType()->getAs<ObjCInterfaceType>(); + } + + /// getInterfaceDecl - If this pointer points to an Objective @interface + /// type, gets the declaration for that interface. + /// + /// \return null if the base type for this pointer is 'id' or 'Class' + ObjCInterfaceDecl *getInterfaceDecl() const { + return getObjectType()->getInterface(); + } + + /// isObjCIdType - True if this is equivalent to the 'id' type, i.e. if + /// its object type is the primitive 'id' type with no protocols. + bool isObjCIdType() const { + return getObjectType()->isObjCUnqualifiedId(); + } + + /// isObjCClassType - True if this is equivalent to the 'Class' type, + /// i.e. if its object tive is the primitive 'Class' type with no protocols. + bool isObjCClassType() const { + return getObjectType()->isObjCUnqualifiedClass(); + } + + /// isObjCQualifiedIdType - True if this is equivalent to 'id<P>' for some + /// non-empty set of protocols. + bool isObjCQualifiedIdType() const { + return getObjectType()->isObjCQualifiedId(); + } + + /// isObjCQualifiedClassType - True if this is equivalent to 'Class<P>' for + /// some non-empty set of protocols. + bool isObjCQualifiedClassType() const { + return getObjectType()->isObjCQualifiedClass(); + } + + /// An iterator over the qualifiers on the object type. Provided + /// for convenience. This will always iterate over the full set of + /// protocols on a type, not just those provided directly. + typedef ObjCObjectType::qual_iterator qual_iterator; + + qual_iterator qual_begin() const { + return getObjectType()->qual_begin(); + } + qual_iterator qual_end() const { + return getObjectType()->qual_end(); + } + bool qual_empty() const { return getObjectType()->qual_empty(); } + + /// getNumProtocols - Return the number of qualifying protocols on + /// the object type. + unsigned getNumProtocols() const { + return getObjectType()->getNumProtocols(); + } + + /// \brief Retrieve a qualifying protocol by index on the object + /// type. + ObjCProtocolDecl *getProtocol(unsigned I) const { + return getObjectType()->getProtocol(I); + } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getPointeeType()); + } + static void Profile(llvm::FoldingSetNodeID &ID, QualType T) { + ID.AddPointer(T.getAsOpaquePtr()); + } + static bool classof(const Type *T) { + return T->getTypeClass() == ObjCObjectPointer; + } + static bool classof(const ObjCObjectPointerType *) { return true; } +}; + +class AtomicType : public Type, public llvm::FoldingSetNode { + QualType ValueType; + + AtomicType(QualType ValTy, QualType Canonical) + : Type(Atomic, Canonical, ValTy->isDependentType(), + ValTy->isInstantiationDependentType(), + ValTy->isVariablyModifiedType(), + ValTy->containsUnexpandedParameterPack()), + ValueType(ValTy) {} + friend class ASTContext; // ASTContext creates these. + + public: + /// getValueType - Gets the type contained by this atomic type, i.e. + /// the type returned by performing an atomic load of this atomic type. + QualType getValueType() const { return ValueType; } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getValueType()); + } + static void Profile(llvm::FoldingSetNodeID &ID, QualType T) { + ID.AddPointer(T.getAsOpaquePtr()); + } + static bool classof(const Type *T) { + return T->getTypeClass() == Atomic; + } + static bool classof(const AtomicType *) { return true; } +}; + +/// A qualifier set is used to build a set of qualifiers. +class QualifierCollector : public Qualifiers { +public: + QualifierCollector(Qualifiers Qs = Qualifiers()) : Qualifiers(Qs) {} + + /// Collect any qualifiers on the given type and return an + /// unqualified type. The qualifiers are assumed to be consistent + /// with those already in the type. + const Type *strip(QualType type) { + addFastQualifiers(type.getLocalFastQualifiers()); + if (!type.hasLocalNonFastQualifiers()) + return type.getTypePtrUnsafe(); + + const ExtQuals *extQuals = type.getExtQualsUnsafe(); + addConsistentQualifiers(extQuals->getQualifiers()); + return extQuals->getBaseType(); + } + + /// Apply the collected qualifiers to the given type. + QualType apply(const ASTContext &Context, QualType QT) const; + + /// Apply the collected qualifiers to the given type. + QualType apply(const ASTContext &Context, const Type* T) const; +}; + + +// Inline function definitions. + +inline SplitQualType SplitQualType::getSingleStepDesugaredType() const { + SplitQualType desugar = + Ty->getLocallyUnqualifiedSingleStepDesugaredType().split(); + desugar.Quals.addConsistentQualifiers(Quals); + return desugar; +} + +inline const Type *QualType::getTypePtr() const { + return getCommonPtr()->BaseType; +} + +inline const Type *QualType::getTypePtrOrNull() const { + return (isNull() ? 0 : getCommonPtr()->BaseType); +} + +inline SplitQualType QualType::split() const { + if (!hasLocalNonFastQualifiers()) + return SplitQualType(getTypePtrUnsafe(), + Qualifiers::fromFastMask(getLocalFastQualifiers())); + + const ExtQuals *eq = getExtQualsUnsafe(); + Qualifiers qs = eq->getQualifiers(); + qs.addFastQualifiers(getLocalFastQualifiers()); + return SplitQualType(eq->getBaseType(), qs); +} + +inline Qualifiers QualType::getLocalQualifiers() const { + Qualifiers Quals; + if (hasLocalNonFastQualifiers()) + Quals = getExtQualsUnsafe()->getQualifiers(); + Quals.addFastQualifiers(getLocalFastQualifiers()); + return Quals; +} + +inline Qualifiers QualType::getQualifiers() const { + Qualifiers quals = getCommonPtr()->CanonicalType.getLocalQualifiers(); + quals.addFastQualifiers(getLocalFastQualifiers()); + return quals; +} + +inline unsigned QualType::getCVRQualifiers() const { + unsigned cvr = getCommonPtr()->CanonicalType.getLocalCVRQualifiers(); + cvr |= getLocalCVRQualifiers(); + return cvr; +} + +inline QualType QualType::getCanonicalType() const { + QualType canon = getCommonPtr()->CanonicalType; + return canon.withFastQualifiers(getLocalFastQualifiers()); +} + +inline bool QualType::isCanonical() const { + return getTypePtr()->isCanonicalUnqualified(); +} + +inline bool QualType::isCanonicalAsParam() const { + if (!isCanonical()) return false; + if (hasLocalQualifiers()) return false; + + const Type *T = getTypePtr(); + if (T->isVariablyModifiedType() && T->hasSizedVLAType()) + return false; + + return !isa<FunctionType>(T) && !isa<ArrayType>(T); +} + +inline bool QualType::isConstQualified() const { + return isLocalConstQualified() || + getCommonPtr()->CanonicalType.isLocalConstQualified(); +} + +inline bool QualType::isRestrictQualified() const { + return isLocalRestrictQualified() || + getCommonPtr()->CanonicalType.isLocalRestrictQualified(); +} + + +inline bool QualType::isVolatileQualified() const { + return isLocalVolatileQualified() || + getCommonPtr()->CanonicalType.isLocalVolatileQualified(); +} + +inline bool QualType::hasQualifiers() const { + return hasLocalQualifiers() || + getCommonPtr()->CanonicalType.hasLocalQualifiers(); +} + +inline QualType QualType::getUnqualifiedType() const { + if (!getTypePtr()->getCanonicalTypeInternal().hasLocalQualifiers()) + return QualType(getTypePtr(), 0); + + return QualType(getSplitUnqualifiedTypeImpl(*this).Ty, 0); +} + +inline SplitQualType QualType::getSplitUnqualifiedType() const { + if (!getTypePtr()->getCanonicalTypeInternal().hasLocalQualifiers()) + return split(); + + return getSplitUnqualifiedTypeImpl(*this); +} + +inline void QualType::removeLocalConst() { + removeLocalFastQualifiers(Qualifiers::Const); +} + +inline void QualType::removeLocalRestrict() { + removeLocalFastQualifiers(Qualifiers::Restrict); +} + +inline void QualType::removeLocalVolatile() { + removeLocalFastQualifiers(Qualifiers::Volatile); +} + +inline void QualType::removeLocalCVRQualifiers(unsigned Mask) { + assert(!(Mask & ~Qualifiers::CVRMask) && "mask has non-CVR bits"); + assert((int)Qualifiers::CVRMask == (int)Qualifiers::FastMask); + + // Fast path: we don't need to touch the slow qualifiers. + removeLocalFastQualifiers(Mask); +} + +/// getAddressSpace - Return the address space of this type. +inline unsigned QualType::getAddressSpace() const { + return getQualifiers().getAddressSpace(); +} + +/// getObjCGCAttr - Return the gc attribute of this type. +inline Qualifiers::GC QualType::getObjCGCAttr() const { + return getQualifiers().getObjCGCAttr(); +} + +inline FunctionType::ExtInfo getFunctionExtInfo(const Type &t) { + if (const PointerType *PT = t.getAs<PointerType>()) { + if (const FunctionType *FT = PT->getPointeeType()->getAs<FunctionType>()) + return FT->getExtInfo(); + } else if (const FunctionType *FT = t.getAs<FunctionType>()) + return FT->getExtInfo(); + + return FunctionType::ExtInfo(); +} + +inline FunctionType::ExtInfo getFunctionExtInfo(QualType t) { + return getFunctionExtInfo(*t); +} + +/// isMoreQualifiedThan - Determine whether this type is more +/// qualified than the Other type. For example, "const volatile int" +/// is more qualified than "const int", "volatile int", and +/// "int". However, it is not more qualified than "const volatile +/// int". +inline bool QualType::isMoreQualifiedThan(QualType other) const { + Qualifiers myQuals = getQualifiers(); + Qualifiers otherQuals = other.getQualifiers(); + return (myQuals != otherQuals && myQuals.compatiblyIncludes(otherQuals)); +} + +/// isAtLeastAsQualifiedAs - Determine whether this type is at last +/// as qualified as the Other type. For example, "const volatile +/// int" is at least as qualified as "const int", "volatile int", +/// "int", and "const volatile int". +inline bool QualType::isAtLeastAsQualifiedAs(QualType other) const { + return getQualifiers().compatiblyIncludes(other.getQualifiers()); +} + +/// getNonReferenceType - If Type is a reference type (e.g., const +/// int&), returns the type that the reference refers to ("const +/// int"). Otherwise, returns the type itself. This routine is used +/// throughout Sema to implement C++ 5p6: +/// +/// If an expression initially has the type "reference to T" (8.3.2, +/// 8.5.3), the type is adjusted to "T" prior to any further +/// analysis, the expression designates the object or function +/// denoted by the reference, and the expression is an lvalue. +inline QualType QualType::getNonReferenceType() const { + if (const ReferenceType *RefType = (*this)->getAs<ReferenceType>()) + return RefType->getPointeeType(); + else + return *this; +} + +inline bool QualType::isCForbiddenLValueType() const { + return ((getTypePtr()->isVoidType() && !hasQualifiers()) || + getTypePtr()->isFunctionType()); +} + +/// \brief Tests whether the type is categorized as a fundamental type. +/// +/// \returns True for types specified in C++0x [basic.fundamental]. +inline bool Type::isFundamentalType() const { + return isVoidType() || + // FIXME: It's really annoying that we don't have an + // 'isArithmeticType()' which agrees with the standard definition. + (isArithmeticType() && !isEnumeralType()); +} + +/// \brief Tests whether the type is categorized as a compound type. +/// +/// \returns True for types specified in C++0x [basic.compound]. +inline bool Type::isCompoundType() const { + // C++0x [basic.compound]p1: + // Compound types can be constructed in the following ways: + // -- arrays of objects of a given type [...]; + return isArrayType() || + // -- functions, which have parameters of given types [...]; + isFunctionType() || + // -- pointers to void or objects or functions [...]; + isPointerType() || + // -- references to objects or functions of a given type. [...] + isReferenceType() || + // -- classes containing a sequence of objects of various types, [...]; + isRecordType() || + // -- unions, which are classes capable of containing objects of different + // types at different times; + isUnionType() || + // -- enumerations, which comprise a set of named constant values. [...]; + isEnumeralType() || + // -- pointers to non-static class members, [...]. + isMemberPointerType(); +} + +inline bool Type::isFunctionType() const { + return isa<FunctionType>(CanonicalType); +} +inline bool Type::isPointerType() const { + return isa<PointerType>(CanonicalType); +} +inline bool Type::isAnyPointerType() const { + return isPointerType() || isObjCObjectPointerType(); +} +inline bool Type::isBlockPointerType() const { + return isa<BlockPointerType>(CanonicalType); +} +inline bool Type::isReferenceType() const { + return isa<ReferenceType>(CanonicalType); +} +inline bool Type::isLValueReferenceType() const { + return isa<LValueReferenceType>(CanonicalType); +} +inline bool Type::isRValueReferenceType() const { + return isa<RValueReferenceType>(CanonicalType); +} +inline bool Type::isFunctionPointerType() const { + if (const PointerType *T = getAs<PointerType>()) + return T->getPointeeType()->isFunctionType(); + else + return false; +} +inline bool Type::isMemberPointerType() const { + return isa<MemberPointerType>(CanonicalType); +} +inline bool Type::isMemberFunctionPointerType() const { + if (const MemberPointerType* T = getAs<MemberPointerType>()) + return T->isMemberFunctionPointer(); + else + return false; +} +inline bool Type::isMemberDataPointerType() const { + if (const MemberPointerType* T = getAs<MemberPointerType>()) + return T->isMemberDataPointer(); + else + return false; +} +inline bool Type::isArrayType() const { + return isa<ArrayType>(CanonicalType); +} +inline bool Type::isConstantArrayType() const { + return isa<ConstantArrayType>(CanonicalType); +} +inline bool Type::isIncompleteArrayType() const { + return isa<IncompleteArrayType>(CanonicalType); +} +inline bool Type::isVariableArrayType() const { + return isa<VariableArrayType>(CanonicalType); +} +inline bool Type::isDependentSizedArrayType() const { + return isa<DependentSizedArrayType>(CanonicalType); +} +inline bool Type::isBuiltinType() const { + return isa<BuiltinType>(CanonicalType); +} +inline bool Type::isRecordType() const { + return isa<RecordType>(CanonicalType); +} +inline bool Type::isEnumeralType() const { + return isa<EnumType>(CanonicalType); +} +inline bool Type::isAnyComplexType() const { + return isa<ComplexType>(CanonicalType); +} +inline bool Type::isVectorType() const { + return isa<VectorType>(CanonicalType); +} +inline bool Type::isExtVectorType() const { + return isa<ExtVectorType>(CanonicalType); +} +inline bool Type::isObjCObjectPointerType() const { + return isa<ObjCObjectPointerType>(CanonicalType); +} +inline bool Type::isObjCObjectType() const { + return isa<ObjCObjectType>(CanonicalType); +} +inline bool Type::isObjCObjectOrInterfaceType() const { + return isa<ObjCInterfaceType>(CanonicalType) || + isa<ObjCObjectType>(CanonicalType); +} +inline bool Type::isAtomicType() const { + return isa<AtomicType>(CanonicalType); +} + +inline bool Type::isObjCQualifiedIdType() const { + if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>()) + return OPT->isObjCQualifiedIdType(); + return false; +} +inline bool Type::isObjCQualifiedClassType() const { + if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>()) + return OPT->isObjCQualifiedClassType(); + return false; +} +inline bool Type::isObjCIdType() const { + if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>()) + return OPT->isObjCIdType(); + return false; +} +inline bool Type::isObjCClassType() const { + if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>()) + return OPT->isObjCClassType(); + return false; +} +inline bool Type::isObjCSelType() const { + if (const PointerType *OPT = getAs<PointerType>()) + return OPT->getPointeeType()->isSpecificBuiltinType(BuiltinType::ObjCSel); + return false; +} +inline bool Type::isObjCBuiltinType() const { + return isObjCIdType() || isObjCClassType() || isObjCSelType(); +} +inline bool Type::isTemplateTypeParmType() const { + return isa<TemplateTypeParmType>(CanonicalType); +} + +inline bool Type::isSpecificBuiltinType(unsigned K) const { + if (const BuiltinType *BT = getAs<BuiltinType>()) + if (BT->getKind() == (BuiltinType::Kind) K) + return true; + return false; +} + +inline bool Type::isPlaceholderType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(this)) + return BT->isPlaceholderType(); + return false; +} + +inline const BuiltinType *Type::getAsPlaceholderType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(this)) + if (BT->isPlaceholderType()) + return BT; + return 0; +} + +inline bool Type::isSpecificPlaceholderType(unsigned K) const { + assert(BuiltinType::isPlaceholderTypeKind((BuiltinType::Kind) K)); + if (const BuiltinType *BT = dyn_cast<BuiltinType>(this)) + return (BT->getKind() == (BuiltinType::Kind) K); + return false; +} + +inline bool Type::isNonOverloadPlaceholderType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(this)) + return BT->isNonOverloadPlaceholderType(); + return false; +} + +inline bool Type::isVoidType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + return BT->getKind() == BuiltinType::Void; + return false; +} + +inline bool Type::isHalfType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + return BT->getKind() == BuiltinType::Half; + // FIXME: Should we allow complex __fp16? Probably not. + return false; +} + +inline bool Type::isNullPtrType() const { + if (const BuiltinType *BT = getAs<BuiltinType>()) + return BT->getKind() == BuiltinType::NullPtr; + return false; +} + +extern bool IsEnumDeclComplete(EnumDecl *); +extern bool IsEnumDeclScoped(EnumDecl *); + +inline bool Type::isIntegerType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + return BT->getKind() >= BuiltinType::Bool && + BT->getKind() <= BuiltinType::Int128; + if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) { + // Incomplete enum types are not treated as integer types. + // FIXME: In C++, enum types are never integer types. + return IsEnumDeclComplete(ET->getDecl()) && + !IsEnumDeclScoped(ET->getDecl()); + } + return false; +} + +inline bool Type::isScalarType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + return BT->getKind() > BuiltinType::Void && + BT->getKind() <= BuiltinType::NullPtr; + if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) + // Enums are scalar types, but only if they are defined. Incomplete enums + // are not treated as scalar types. + return IsEnumDeclComplete(ET->getDecl()); + return isa<PointerType>(CanonicalType) || + isa<BlockPointerType>(CanonicalType) || + isa<MemberPointerType>(CanonicalType) || + isa<ComplexType>(CanonicalType) || + isa<ObjCObjectPointerType>(CanonicalType); +} + +inline bool Type::isIntegralOrEnumerationType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + return BT->getKind() >= BuiltinType::Bool && + BT->getKind() <= BuiltinType::Int128; + + // Check for a complete enum type; incomplete enum types are not properly an + // enumeration type in the sense required here. + if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) + return IsEnumDeclComplete(ET->getDecl()); + + return false; +} + +inline bool Type::isBooleanType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + return BT->getKind() == BuiltinType::Bool; + return false; +} + +/// \brief Determines whether this is a type for which one can define +/// an overloaded operator. +inline bool Type::isOverloadableType() const { + return isDependentType() || isRecordType() || isEnumeralType(); +} + +/// \brief Determines whether this type can decay to a pointer type. +inline bool Type::canDecayToPointerType() const { + return isFunctionType() || isArrayType(); +} + +inline bool Type::hasPointerRepresentation() const { + return (isPointerType() || isReferenceType() || isBlockPointerType() || + isObjCObjectPointerType() || isNullPtrType()); +} + +inline bool Type::hasObjCPointerRepresentation() const { + return isObjCObjectPointerType(); +} + +inline const Type *Type::getBaseElementTypeUnsafe() const { + const Type *type = this; + while (const ArrayType *arrayType = type->getAsArrayTypeUnsafe()) + type = arrayType->getElementType().getTypePtr(); + return type; +} + +/// Insertion operator for diagnostics. This allows sending QualType's into a +/// diagnostic with <<. +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + QualType T) { + DB.AddTaggedVal(reinterpret_cast<intptr_t>(T.getAsOpaquePtr()), + DiagnosticsEngine::ak_qualtype); + return DB; +} + +/// Insertion operator for partial diagnostics. This allows sending QualType's +/// into a diagnostic with <<. +inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, + QualType T) { + PD.AddTaggedVal(reinterpret_cast<intptr_t>(T.getAsOpaquePtr()), + DiagnosticsEngine::ak_qualtype); + return PD; +} + +// Helper class template that is used by Type::getAs to ensure that one does +// not try to look through a qualified type to get to an array type. +template<typename T, + bool isArrayType = (llvm::is_same<T, ArrayType>::value || + llvm::is_base_of<ArrayType, T>::value)> +struct ArrayType_cannot_be_used_with_getAs { }; + +template<typename T> +struct ArrayType_cannot_be_used_with_getAs<T, true>; + +/// Member-template getAs<specific type>'. +template <typename T> const T *Type::getAs() const { + ArrayType_cannot_be_used_with_getAs<T> at; + (void)at; + + // If this is directly a T type, return it. + if (const T *Ty = dyn_cast<T>(this)) + return Ty; + + // If the canonical form of this type isn't the right kind, reject it. + if (!isa<T>(CanonicalType)) + return 0; + + // If this is a typedef for the type, strip the typedef off without + // losing all typedef information. + return cast<T>(getUnqualifiedDesugaredType()); +} + +inline const ArrayType *Type::getAsArrayTypeUnsafe() const { + // If this is directly an array type, return it. + if (const ArrayType *arr = dyn_cast<ArrayType>(this)) + return arr; + + // If the canonical form of this type isn't the right kind, reject it. + if (!isa<ArrayType>(CanonicalType)) + return 0; + + // If this is a typedef for the type, strip the typedef off without + // losing all typedef information. + return cast<ArrayType>(getUnqualifiedDesugaredType()); +} + +template <typename T> const T *Type::castAs() const { + ArrayType_cannot_be_used_with_getAs<T> at; + (void) at; + + assert(isa<T>(CanonicalType)); + if (const T *ty = dyn_cast<T>(this)) return ty; + return cast<T>(getUnqualifiedDesugaredType()); +} + +inline const ArrayType *Type::castAsArrayTypeUnsafe() const { + assert(isa<ArrayType>(CanonicalType)); + if (const ArrayType *arr = dyn_cast<ArrayType>(this)) return arr; + return cast<ArrayType>(getUnqualifiedDesugaredType()); +} + +} // end namespace clang + +#endif diff --git a/clang/include/clang/AST/TypeLoc.h b/clang/include/clang/AST/TypeLoc.h new file mode 100644 index 0000000..aab87be --- /dev/null +++ b/clang/include/clang/AST/TypeLoc.h @@ -0,0 +1,1817 @@ +//===--- TypeLoc.h - Type Source Info Wrapper -------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the TypeLoc interface and subclasses. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_TYPELOC_H +#define LLVM_CLANG_AST_TYPELOC_H + +#include "clang/AST/Type.h" +#include "clang/AST/Decl.h" +#include "clang/AST/TemplateBase.h" +#include "clang/Basic/Specifiers.h" +#include "llvm/Support/Compiler.h" + +namespace clang { + class ASTContext; + class ParmVarDecl; + class TypeSourceInfo; + class UnqualTypeLoc; + +// Predeclare all the type nodes. +#define ABSTRACT_TYPELOC(Class, Base) +#define TYPELOC(Class, Base) \ + class Class##TypeLoc; +#include "clang/AST/TypeLocNodes.def" + +/// \brief Base wrapper for a particular "section" of type source info. +/// +/// A client should use the TypeLoc subclasses through cast/dyn_cast in order to +/// get at the actual information. +class TypeLoc { +protected: + // The correctness of this relies on the property that, for Type *Ty, + // QualType(Ty, 0).getAsOpaquePtr() == (void*) Ty + const void *Ty; + void *Data; + +public: + /// The kinds of TypeLocs. Equivalent to the Type::TypeClass enum, + /// except it also defines a Qualified enum that corresponds to the + /// QualifiedLoc class. + enum TypeLocClass { +#define ABSTRACT_TYPE(Class, Base) +#define TYPE(Class, Base) \ + Class = Type::Class, +#include "clang/AST/TypeNodes.def" + Qualified + }; + + TypeLoc() : Ty(0), Data(0) { } + TypeLoc(QualType ty, void *opaqueData) + : Ty(ty.getAsOpaquePtr()), Data(opaqueData) { } + TypeLoc(const Type *ty, void *opaqueData) + : Ty(ty), Data(opaqueData) { } + + TypeLocClass getTypeLocClass() const { + if (getType().hasLocalQualifiers()) return Qualified; + return (TypeLocClass) getType()->getTypeClass(); + } + + bool isNull() const { return !Ty; } + operator bool() const { return Ty; } + + /// \brief Returns the size of type source info data block for the given type. + static unsigned getFullDataSizeForType(QualType Ty); + + /// \brief Get the type for which this source info wrapper provides + /// information. + QualType getType() const { + return QualType::getFromOpaquePtr(Ty); + } + + const Type *getTypePtr() const { + return QualType::getFromOpaquePtr(Ty).getTypePtr(); + } + + /// \brief Get the pointer where source information is stored. + void *getOpaqueData() const { + return Data; + } + + /// \brief Get the begin source location. + SourceLocation getBeginLoc() const; + + /// \brief Get the end source location. + SourceLocation getEndLoc() const; + + /// \brief Get the full source range. + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(getBeginLoc(), getEndLoc()); + } + SourceLocation getLocStart() const LLVM_READONLY { return getBeginLoc(); } + SourceLocation getLocEnd() const LLVM_READONLY { return getEndLoc(); } + + /// \brief Get the local source range. + SourceRange getLocalSourceRange() const { + return getLocalSourceRangeImpl(*this); + } + + /// \brief Returns the size of the type source info data block. + unsigned getFullDataSize() const { + return getFullDataSizeForType(getType()); + } + + /// \brief Get the next TypeLoc pointed by this TypeLoc, e.g for "int*" the + /// TypeLoc is a PointerLoc and next TypeLoc is for "int". + TypeLoc getNextTypeLoc() const { + return getNextTypeLocImpl(*this); + } + + /// \brief Skips past any qualifiers, if this is qualified. + UnqualTypeLoc getUnqualifiedLoc() const; // implemented in this header + + TypeLoc IgnoreParens() const { + if (isa<ParenTypeLoc>(this)) + return IgnoreParensImpl(*this); + return *this; + } + + /// \brief Initializes this to state that every location in this + /// type is the given location. + /// + /// This method exists to provide a simple transition for code that + /// relies on location-less types. + void initialize(ASTContext &Context, SourceLocation Loc) const { + initializeImpl(Context, *this, Loc); + } + + /// \brief Initializes this by copying its information from another + /// TypeLoc of the same type. + void initializeFullCopy(TypeLoc Other) const { + assert(getType() == Other.getType()); + size_t Size = getFullDataSize(); + memcpy(getOpaqueData(), Other.getOpaqueData(), Size); + } + + /// \brief Initializes this by copying its information from another + /// TypeLoc of the same type. The given size must be the full data + /// size. + void initializeFullCopy(TypeLoc Other, unsigned Size) const { + assert(getType() == Other.getType()); + assert(getFullDataSize() == Size); + memcpy(getOpaqueData(), Other.getOpaqueData(), Size); + } + + friend bool operator==(const TypeLoc &LHS, const TypeLoc &RHS) { + return LHS.Ty == RHS.Ty && LHS.Data == RHS.Data; + } + + friend bool operator!=(const TypeLoc &LHS, const TypeLoc &RHS) { + return !(LHS == RHS); + } + + static bool classof(const TypeLoc *TL) { return true; } + +private: + static void initializeImpl(ASTContext &Context, TypeLoc TL, + SourceLocation Loc); + static TypeLoc getNextTypeLocImpl(TypeLoc TL); + static TypeLoc IgnoreParensImpl(TypeLoc TL); + static SourceRange getLocalSourceRangeImpl(TypeLoc TL); +}; + +/// \brief Return the TypeLoc for a type source info. +inline TypeLoc TypeSourceInfo::getTypeLoc() const { + return TypeLoc(Ty, const_cast<void*>(static_cast<const void*>(this + 1))); +} + +/// \brief Wrapper of type source information for a type with +/// no direct qualifiers. +class UnqualTypeLoc : public TypeLoc { +public: + UnqualTypeLoc() {} + UnqualTypeLoc(const Type *Ty, void *Data) : TypeLoc(Ty, Data) {} + + const Type *getTypePtr() const { + return reinterpret_cast<const Type*>(Ty); + } + + TypeLocClass getTypeLocClass() const { + return (TypeLocClass) getTypePtr()->getTypeClass(); + } + + static bool classof(const TypeLoc *TL) { + return !TL->getType().hasLocalQualifiers(); + } + static bool classof(const UnqualTypeLoc *TL) { return true; } +}; + +/// \brief Wrapper of type source information for a type with +/// non-trivial direct qualifiers. +/// +/// Currently, we intentionally do not provide source location for +/// type qualifiers. +class QualifiedTypeLoc : public TypeLoc { +public: + SourceRange getLocalSourceRange() const { + return SourceRange(); + } + + UnqualTypeLoc getUnqualifiedLoc() const { + return UnqualTypeLoc(getTypePtr(), Data); + } + + /// Initializes the local data of this type source info block to + /// provide no information. + void initializeLocal(ASTContext &Context, SourceLocation Loc) { + // do nothing + } + + TypeLoc getNextTypeLoc() const { + return getUnqualifiedLoc(); + } + + /// \brief Returns the size of the type source info data block that is + /// specific to this type. + unsigned getLocalDataSize() const { + // In fact, we don't currently preserve any location information + // for qualifiers. + return 0; + } + + /// \brief Returns the size of the type source info data block. + unsigned getFullDataSize() const { + return getLocalDataSize() + + getFullDataSizeForType(getType().getLocalUnqualifiedType()); + } + + static bool classof(const TypeLoc *TL) { + return TL->getType().hasLocalQualifiers(); + } + static bool classof(const QualifiedTypeLoc *TL) { return true; } +}; + +inline UnqualTypeLoc TypeLoc::getUnqualifiedLoc() const { + if (isa<QualifiedTypeLoc>(this)) + return cast<QualifiedTypeLoc>(this)->getUnqualifiedLoc(); + return cast<UnqualTypeLoc>(*this); +} + +/// A metaprogramming base class for TypeLoc classes which correspond +/// to a particular Type subclass. It is accepted for a single +/// TypeLoc class to correspond to multiple Type classes. +/// +/// \param Base a class from which to derive +/// \param Derived the class deriving from this one +/// \param TypeClass the concrete Type subclass associated with this +/// location type +/// \param LocalData the structure type of local location data for +/// this type +/// +/// sizeof(LocalData) needs to be a multiple of sizeof(void*) or +/// else the world will end. +/// +/// TypeLocs with non-constant amounts of local data should override +/// getExtraLocalDataSize(); getExtraLocalData() will then point to +/// this extra memory. +/// +/// TypeLocs with an inner type should define +/// QualType getInnerType() const +/// and getInnerTypeLoc() will then point to this inner type's +/// location data. +/// +/// A word about hierarchies: this template is not designed to be +/// derived from multiple times in a hierarchy. It is also not +/// designed to be used for classes where subtypes might provide +/// different amounts of source information. It should be subclassed +/// only at the deepest portion of the hierarchy where all children +/// have identical source information; if that's an abstract type, +/// then further descendents should inherit from +/// InheritingConcreteTypeLoc instead. +template <class Base, class Derived, class TypeClass, class LocalData> +class ConcreteTypeLoc : public Base { + + const Derived *asDerived() const { + return static_cast<const Derived*>(this); + } + +public: + unsigned getLocalDataSize() const { + return sizeof(LocalData) + asDerived()->getExtraLocalDataSize(); + } + // Give a default implementation that's useful for leaf types. + unsigned getFullDataSize() const { + return asDerived()->getLocalDataSize() + getInnerTypeSize(); + } + + static bool classofType(const Type *Ty) { + return TypeClass::classof(Ty); + } + + static bool classof(const TypeLoc *TL) { + return Derived::classofType(TL->getTypePtr()); + } + static bool classof(const UnqualTypeLoc *TL) { + return Derived::classofType(TL->getTypePtr()); + } + static bool classof(const Derived *TL) { + return true; + } + + TypeLoc getNextTypeLoc() const { + return getNextTypeLoc(asDerived()->getInnerType()); + } + + const TypeClass *getTypePtr() const { + return cast<TypeClass>(Base::getTypePtr()); + } + +protected: + unsigned getExtraLocalDataSize() const { + return 0; + } + + LocalData *getLocalData() const { + return static_cast<LocalData*>(Base::Data); + } + + /// Gets a pointer past the Info structure; useful for classes with + /// local data that can't be captured in the Info (e.g. because it's + /// of variable size). + void *getExtraLocalData() const { + return getLocalData() + 1; + } + + void *getNonLocalData() const { + return static_cast<char*>(Base::Data) + asDerived()->getLocalDataSize(); + } + + struct HasNoInnerType {}; + HasNoInnerType getInnerType() const { return HasNoInnerType(); } + + TypeLoc getInnerTypeLoc() const { + return TypeLoc(asDerived()->getInnerType(), getNonLocalData()); + } + +private: + unsigned getInnerTypeSize() const { + return getInnerTypeSize(asDerived()->getInnerType()); + } + + unsigned getInnerTypeSize(HasNoInnerType _) const { + return 0; + } + + unsigned getInnerTypeSize(QualType _) const { + return getInnerTypeLoc().getFullDataSize(); + } + + TypeLoc getNextTypeLoc(HasNoInnerType _) const { + return TypeLoc(); + } + + TypeLoc getNextTypeLoc(QualType T) const { + return TypeLoc(T, getNonLocalData()); + } +}; + +/// A metaprogramming class designed for concrete subtypes of abstract +/// types where all subtypes share equivalently-structured source +/// information. See the note on ConcreteTypeLoc. +template <class Base, class Derived, class TypeClass> +class InheritingConcreteTypeLoc : public Base { +public: + static bool classofType(const Type *Ty) { + return TypeClass::classof(Ty); + } + + static bool classof(const TypeLoc *TL) { + return Derived::classofType(TL->getTypePtr()); + } + static bool classof(const UnqualTypeLoc *TL) { + return Derived::classofType(TL->getTypePtr()); + } + static bool classof(const Derived *TL) { + return true; + } + + const TypeClass *getTypePtr() const { + return cast<TypeClass>(Base::getTypePtr()); + } +}; + + +struct TypeSpecLocInfo { + SourceLocation NameLoc; +}; + +/// \brief A reasonable base class for TypeLocs that correspond to +/// types that are written as a type-specifier. +class TypeSpecTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, + TypeSpecTypeLoc, + Type, + TypeSpecLocInfo> { +public: + enum { LocalDataSize = sizeof(TypeSpecLocInfo) }; + + SourceLocation getNameLoc() const { + return this->getLocalData()->NameLoc; + } + void setNameLoc(SourceLocation Loc) { + this->getLocalData()->NameLoc = Loc; + } + SourceRange getLocalSourceRange() const { + return SourceRange(getNameLoc(), getNameLoc()); + } + void initializeLocal(ASTContext &Context, SourceLocation Loc) { + setNameLoc(Loc); + } + + static bool classof(const TypeLoc *TL); + static bool classof(const TypeSpecTypeLoc *TL) { return true; } +}; + + +struct BuiltinLocInfo { + SourceLocation BuiltinLoc; +}; + +/// \brief Wrapper for source info for builtin types. +class BuiltinTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, + BuiltinTypeLoc, + BuiltinType, + BuiltinLocInfo> { +public: + enum { LocalDataSize = sizeof(BuiltinLocInfo) }; + + SourceLocation getBuiltinLoc() const { + return getLocalData()->BuiltinLoc; + } + void setBuiltinLoc(SourceLocation Loc) { + getLocalData()->BuiltinLoc = Loc; + } + + SourceLocation getNameLoc() const { return getBuiltinLoc(); } + + WrittenBuiltinSpecs& getWrittenBuiltinSpecs() { + return *(static_cast<WrittenBuiltinSpecs*>(getExtraLocalData())); + } + const WrittenBuiltinSpecs& getWrittenBuiltinSpecs() const { + return *(static_cast<WrittenBuiltinSpecs*>(getExtraLocalData())); + } + + bool needsExtraLocalData() const { + BuiltinType::Kind bk = getTypePtr()->getKind(); + return (bk >= BuiltinType::UShort && bk <= BuiltinType::UInt128) + || (bk >= BuiltinType::Short && bk <= BuiltinType::LongDouble) + || bk == BuiltinType::UChar + || bk == BuiltinType::SChar; + } + + unsigned getExtraLocalDataSize() const { + return needsExtraLocalData() ? sizeof(WrittenBuiltinSpecs) : 0; + } + + SourceRange getLocalSourceRange() const { + return SourceRange(getBuiltinLoc(), getBuiltinLoc()); + } + + TypeSpecifierSign getWrittenSignSpec() const { + if (needsExtraLocalData()) + return static_cast<TypeSpecifierSign>(getWrittenBuiltinSpecs().Sign); + else + return TSS_unspecified; + } + bool hasWrittenSignSpec() const { + return getWrittenSignSpec() != TSS_unspecified; + } + void setWrittenSignSpec(TypeSpecifierSign written) { + if (needsExtraLocalData()) + getWrittenBuiltinSpecs().Sign = written; + } + + TypeSpecifierWidth getWrittenWidthSpec() const { + if (needsExtraLocalData()) + return static_cast<TypeSpecifierWidth>(getWrittenBuiltinSpecs().Width); + else + return TSW_unspecified; + } + bool hasWrittenWidthSpec() const { + return getWrittenWidthSpec() != TSW_unspecified; + } + void setWrittenWidthSpec(TypeSpecifierWidth written) { + if (needsExtraLocalData()) + getWrittenBuiltinSpecs().Width = written; + } + + TypeSpecifierType getWrittenTypeSpec() const; + bool hasWrittenTypeSpec() const { + return getWrittenTypeSpec() != TST_unspecified; + } + void setWrittenTypeSpec(TypeSpecifierType written) { + if (needsExtraLocalData()) + getWrittenBuiltinSpecs().Type = written; + } + + bool hasModeAttr() const { + if (needsExtraLocalData()) + return getWrittenBuiltinSpecs().ModeAttr; + else + return false; + } + void setModeAttr(bool written) { + if (needsExtraLocalData()) + getWrittenBuiltinSpecs().ModeAttr = written; + } + + void initializeLocal(ASTContext &Context, SourceLocation Loc) { + setBuiltinLoc(Loc); + if (needsExtraLocalData()) { + WrittenBuiltinSpecs &wbs = getWrittenBuiltinSpecs(); + wbs.Sign = TSS_unspecified; + wbs.Width = TSW_unspecified; + wbs.Type = TST_unspecified; + wbs.ModeAttr = false; + } + } +}; + + +/// \brief Wrapper for source info for typedefs. +class TypedefTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc, + TypedefTypeLoc, + TypedefType> { +public: + TypedefNameDecl *getTypedefNameDecl() const { + return getTypePtr()->getDecl(); + } +}; + +/// \brief Wrapper for source info for injected class names of class +/// templates. +class InjectedClassNameTypeLoc : + public InheritingConcreteTypeLoc<TypeSpecTypeLoc, + InjectedClassNameTypeLoc, + InjectedClassNameType> { +public: + CXXRecordDecl *getDecl() const { + return getTypePtr()->getDecl(); + } +}; + +/// \brief Wrapper for source info for unresolved typename using decls. +class UnresolvedUsingTypeLoc : + public InheritingConcreteTypeLoc<TypeSpecTypeLoc, + UnresolvedUsingTypeLoc, + UnresolvedUsingType> { +public: + UnresolvedUsingTypenameDecl *getDecl() const { + return getTypePtr()->getDecl(); + } +}; + +/// \brief Wrapper for source info for tag types. Note that this only +/// records source info for the name itself; a type written 'struct foo' +/// should be represented as an ElaboratedTypeLoc. We currently +/// only do that when C++ is enabled because of the expense of +/// creating an ElaboratedType node for so many type references in C. +class TagTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc, + TagTypeLoc, + TagType> { +public: + TagDecl *getDecl() const { return getTypePtr()->getDecl(); } + + /// \brief True if the tag was defined in this type specifier. + bool isDefinition() const { + TagDecl *D = getDecl(); + return D->isCompleteDefinition() && + (D->getIdentifier() == 0 || D->getLocation() == getNameLoc()); + } +}; + +/// \brief Wrapper for source info for record types. +class RecordTypeLoc : public InheritingConcreteTypeLoc<TagTypeLoc, + RecordTypeLoc, + RecordType> { +public: + RecordDecl *getDecl() const { return getTypePtr()->getDecl(); } +}; + +/// \brief Wrapper for source info for enum types. +class EnumTypeLoc : public InheritingConcreteTypeLoc<TagTypeLoc, + EnumTypeLoc, + EnumType> { +public: + EnumDecl *getDecl() const { return getTypePtr()->getDecl(); } +}; + +/// \brief Wrapper for template type parameters. +class TemplateTypeParmTypeLoc : + public InheritingConcreteTypeLoc<TypeSpecTypeLoc, + TemplateTypeParmTypeLoc, + TemplateTypeParmType> { +public: + TemplateTypeParmDecl *getDecl() const { return getTypePtr()->getDecl(); } +}; + +/// \brief Wrapper for substituted template type parameters. +class SubstTemplateTypeParmTypeLoc : + public InheritingConcreteTypeLoc<TypeSpecTypeLoc, + SubstTemplateTypeParmTypeLoc, + SubstTemplateTypeParmType> { +}; + + /// \brief Wrapper for substituted template type parameters. +class SubstTemplateTypeParmPackTypeLoc : + public InheritingConcreteTypeLoc<TypeSpecTypeLoc, + SubstTemplateTypeParmPackTypeLoc, + SubstTemplateTypeParmPackType> { +}; + +struct AttributedLocInfo { + union { + Expr *ExprOperand; + + /// A raw SourceLocation. + unsigned EnumOperandLoc; + }; + + SourceRange OperandParens; + + SourceLocation AttrLoc; +}; + +/// \brief Type source information for an attributed type. +class AttributedTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, + AttributedTypeLoc, + AttributedType, + AttributedLocInfo> { +public: + AttributedType::Kind getAttrKind() const { + return getTypePtr()->getAttrKind(); + } + + bool hasAttrExprOperand() const { + return (getAttrKind() >= AttributedType::FirstExprOperandKind && + getAttrKind() <= AttributedType::LastExprOperandKind); + } + + bool hasAttrEnumOperand() const { + return (getAttrKind() >= AttributedType::FirstEnumOperandKind && + getAttrKind() <= AttributedType::LastEnumOperandKind); + } + + bool hasAttrOperand() const { + return hasAttrExprOperand() || hasAttrEnumOperand(); + } + + /// The modified type, which is generally canonically different from + /// the attribute type. + /// int main(int, char**) __attribute__((noreturn)) + /// ~~~ ~~~~~~~~~~~~~ + TypeLoc getModifiedLoc() const { + return getInnerTypeLoc(); + } + + /// The location of the attribute name, i.e. + /// __attribute__((regparm(1000))) + /// ^~~~~~~ + SourceLocation getAttrNameLoc() const { + return getLocalData()->AttrLoc; + } + void setAttrNameLoc(SourceLocation loc) { + getLocalData()->AttrLoc = loc; + } + + /// The attribute's expression operand, if it has one. + /// void *cur_thread __attribute__((address_space(21))) + /// ^~ + Expr *getAttrExprOperand() const { + assert(hasAttrExprOperand()); + return getLocalData()->ExprOperand; + } + void setAttrExprOperand(Expr *e) { + assert(hasAttrExprOperand()); + getLocalData()->ExprOperand = e; + } + + /// The location of the attribute's enumerated operand, if it has one. + /// void * __attribute__((objc_gc(weak))) + /// ^~~~ + SourceLocation getAttrEnumOperandLoc() const { + assert(hasAttrEnumOperand()); + return SourceLocation::getFromRawEncoding(getLocalData()->EnumOperandLoc); + } + void setAttrEnumOperandLoc(SourceLocation loc) { + assert(hasAttrEnumOperand()); + getLocalData()->EnumOperandLoc = loc.getRawEncoding(); + } + + /// The location of the parentheses around the operand, if there is + /// an operand. + /// void * __attribute__((objc_gc(weak))) + /// ^ ^ + SourceRange getAttrOperandParensRange() const { + assert(hasAttrOperand()); + return getLocalData()->OperandParens; + } + void setAttrOperandParensRange(SourceRange range) { + assert(hasAttrOperand()); + getLocalData()->OperandParens = range; + } + + SourceRange getLocalSourceRange() const { + // Note that this does *not* include the range of the attribute + // enclosure, e.g.: + // __attribute__((foo(bar))) + // ^~~~~~~~~~~~~~~ ~~ + // or + // [[foo(bar)]] + // ^~ ~~ + // That enclosure doesn't necessarily belong to a single attribute + // anyway. + SourceRange range(getAttrNameLoc()); + if (hasAttrOperand()) + range.setEnd(getAttrOperandParensRange().getEnd()); + return range; + } + + void initializeLocal(ASTContext &Context, SourceLocation loc) { + setAttrNameLoc(loc); + if (hasAttrExprOperand()) { + setAttrOperandParensRange(SourceRange(loc)); + setAttrExprOperand(0); + } else if (hasAttrEnumOperand()) { + setAttrOperandParensRange(SourceRange(loc)); + setAttrEnumOperandLoc(loc); + } + } + + QualType getInnerType() const { + return getTypePtr()->getModifiedType(); + } +}; + + +struct ObjCProtocolListLocInfo { + SourceLocation LAngleLoc; + SourceLocation RAngleLoc; + bool HasBaseTypeAsWritten; +}; + +// A helper class for defining ObjC TypeLocs that can qualified with +// protocols. +// +// TypeClass basically has to be either ObjCInterfaceType or +// ObjCObjectPointerType. +class ObjCObjectTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, + ObjCObjectTypeLoc, + ObjCObjectType, + ObjCProtocolListLocInfo> { + // SourceLocations are stored after Info, one for each Protocol. + SourceLocation *getProtocolLocArray() const { + return (SourceLocation*) this->getExtraLocalData(); + } + +public: + SourceLocation getLAngleLoc() const { + return this->getLocalData()->LAngleLoc; + } + void setLAngleLoc(SourceLocation Loc) { + this->getLocalData()->LAngleLoc = Loc; + } + + SourceLocation getRAngleLoc() const { + return this->getLocalData()->RAngleLoc; + } + void setRAngleLoc(SourceLocation Loc) { + this->getLocalData()->RAngleLoc = Loc; + } + + unsigned getNumProtocols() const { + return this->getTypePtr()->getNumProtocols(); + } + + SourceLocation getProtocolLoc(unsigned i) const { + assert(i < getNumProtocols() && "Index is out of bounds!"); + return getProtocolLocArray()[i]; + } + void setProtocolLoc(unsigned i, SourceLocation Loc) { + assert(i < getNumProtocols() && "Index is out of bounds!"); + getProtocolLocArray()[i] = Loc; + } + + ObjCProtocolDecl *getProtocol(unsigned i) const { + assert(i < getNumProtocols() && "Index is out of bounds!"); + return *(this->getTypePtr()->qual_begin() + i); + } + + bool hasBaseTypeAsWritten() const { + return getLocalData()->HasBaseTypeAsWritten; + } + + void setHasBaseTypeAsWritten(bool HasBaseType) { + getLocalData()->HasBaseTypeAsWritten = HasBaseType; + } + + TypeLoc getBaseLoc() const { + return getInnerTypeLoc(); + } + + SourceRange getLocalSourceRange() const { + return SourceRange(getLAngleLoc(), getRAngleLoc()); + } + + void initializeLocal(ASTContext &Context, SourceLocation Loc) { + setHasBaseTypeAsWritten(true); + setLAngleLoc(Loc); + setRAngleLoc(Loc); + for (unsigned i = 0, e = getNumProtocols(); i != e; ++i) + setProtocolLoc(i, Loc); + } + + unsigned getExtraLocalDataSize() const { + return this->getNumProtocols() * sizeof(SourceLocation); + } + + QualType getInnerType() const { + return getTypePtr()->getBaseType(); + } +}; + + +struct ObjCInterfaceLocInfo { + SourceLocation NameLoc; +}; + +/// \brief Wrapper for source info for ObjC interfaces. +class ObjCInterfaceTypeLoc : public ConcreteTypeLoc<ObjCObjectTypeLoc, + ObjCInterfaceTypeLoc, + ObjCInterfaceType, + ObjCInterfaceLocInfo> { +public: + ObjCInterfaceDecl *getIFaceDecl() const { + return getTypePtr()->getDecl(); + } + + SourceLocation getNameLoc() const { + return getLocalData()->NameLoc; + } + + void setNameLoc(SourceLocation Loc) { + getLocalData()->NameLoc = Loc; + } + + SourceRange getLocalSourceRange() const { + return SourceRange(getNameLoc()); + } + + void initializeLocal(ASTContext &Context, SourceLocation Loc) { + setNameLoc(Loc); + } +}; + +struct ParenLocInfo { + SourceLocation LParenLoc; + SourceLocation RParenLoc; +}; + +class ParenTypeLoc + : public ConcreteTypeLoc<UnqualTypeLoc, ParenTypeLoc, ParenType, + ParenLocInfo> { +public: + SourceLocation getLParenLoc() const { + return this->getLocalData()->LParenLoc; + } + SourceLocation getRParenLoc() const { + return this->getLocalData()->RParenLoc; + } + void setLParenLoc(SourceLocation Loc) { + this->getLocalData()->LParenLoc = Loc; + } + void setRParenLoc(SourceLocation Loc) { + this->getLocalData()->RParenLoc = Loc; + } + + SourceRange getLocalSourceRange() const { + return SourceRange(getLParenLoc(), getRParenLoc()); + } + + void initializeLocal(ASTContext &Context, SourceLocation Loc) { + setLParenLoc(Loc); + setRParenLoc(Loc); + } + + TypeLoc getInnerLoc() const { + return getInnerTypeLoc(); + } + + QualType getInnerType() const { + return this->getTypePtr()->getInnerType(); + } +}; + + +struct PointerLikeLocInfo { + SourceLocation StarLoc; +}; + +/// A base class for +template <class Derived, class TypeClass, class LocalData = PointerLikeLocInfo> +class PointerLikeTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, Derived, + TypeClass, LocalData> { +public: + SourceLocation getSigilLoc() const { + return this->getLocalData()->StarLoc; + } + void setSigilLoc(SourceLocation Loc) { + this->getLocalData()->StarLoc = Loc; + } + + TypeLoc getPointeeLoc() const { + return this->getInnerTypeLoc(); + } + + SourceRange getLocalSourceRange() const { + return SourceRange(getSigilLoc(), getSigilLoc()); + } + + void initializeLocal(ASTContext &Context, SourceLocation Loc) { + setSigilLoc(Loc); + } + + QualType getInnerType() const { + return this->getTypePtr()->getPointeeType(); + } +}; + + +/// \brief Wrapper for source info for pointers. +class PointerTypeLoc : public PointerLikeTypeLoc<PointerTypeLoc, + PointerType> { +public: + SourceLocation getStarLoc() const { + return getSigilLoc(); + } + void setStarLoc(SourceLocation Loc) { + setSigilLoc(Loc); + } +}; + + +/// \brief Wrapper for source info for block pointers. +class BlockPointerTypeLoc : public PointerLikeTypeLoc<BlockPointerTypeLoc, + BlockPointerType> { +public: + SourceLocation getCaretLoc() const { + return getSigilLoc(); + } + void setCaretLoc(SourceLocation Loc) { + setSigilLoc(Loc); + } +}; + +struct MemberPointerLocInfo : public PointerLikeLocInfo { + TypeSourceInfo *ClassTInfo; +}; + +/// \brief Wrapper for source info for member pointers. +class MemberPointerTypeLoc : public PointerLikeTypeLoc<MemberPointerTypeLoc, + MemberPointerType, + MemberPointerLocInfo> { +public: + SourceLocation getStarLoc() const { + return getSigilLoc(); + } + void setStarLoc(SourceLocation Loc) { + setSigilLoc(Loc); + } + + const Type *getClass() const { + return getTypePtr()->getClass(); + } + TypeSourceInfo *getClassTInfo() const { + return getLocalData()->ClassTInfo; + } + void setClassTInfo(TypeSourceInfo* TI) { + getLocalData()->ClassTInfo = TI; + } + + void initializeLocal(ASTContext &Context, SourceLocation Loc) { + setSigilLoc(Loc); + setClassTInfo(0); + } + + SourceRange getLocalSourceRange() const { + if (TypeSourceInfo *TI = getClassTInfo()) + return SourceRange(TI->getTypeLoc().getBeginLoc(), getStarLoc()); + else + return SourceRange(getStarLoc()); + } +}; + +/// Wraps an ObjCPointerType with source location information. +class ObjCObjectPointerTypeLoc : + public PointerLikeTypeLoc<ObjCObjectPointerTypeLoc, + ObjCObjectPointerType> { +public: + SourceLocation getStarLoc() const { + return getSigilLoc(); + } + + void setStarLoc(SourceLocation Loc) { + setSigilLoc(Loc); + } +}; + + +class ReferenceTypeLoc : public PointerLikeTypeLoc<ReferenceTypeLoc, + ReferenceType> { +public: + QualType getInnerType() const { + return getTypePtr()->getPointeeTypeAsWritten(); + } +}; + +class LValueReferenceTypeLoc : + public InheritingConcreteTypeLoc<ReferenceTypeLoc, + LValueReferenceTypeLoc, + LValueReferenceType> { +public: + SourceLocation getAmpLoc() const { + return getSigilLoc(); + } + void setAmpLoc(SourceLocation Loc) { + setSigilLoc(Loc); + } +}; + +class RValueReferenceTypeLoc : + public InheritingConcreteTypeLoc<ReferenceTypeLoc, + RValueReferenceTypeLoc, + RValueReferenceType> { +public: + SourceLocation getAmpAmpLoc() const { + return getSigilLoc(); + } + void setAmpAmpLoc(SourceLocation Loc) { + setSigilLoc(Loc); + } +}; + + +struct FunctionLocInfo { + SourceLocation LocalRangeBegin; + SourceLocation LocalRangeEnd; + bool TrailingReturn; +}; + +/// \brief Wrapper for source info for functions. +class FunctionTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, + FunctionTypeLoc, + FunctionType, + FunctionLocInfo> { +public: + SourceLocation getLocalRangeBegin() const { + return getLocalData()->LocalRangeBegin; + } + void setLocalRangeBegin(SourceLocation L) { + getLocalData()->LocalRangeBegin = L; + } + + SourceLocation getLocalRangeEnd() const { + return getLocalData()->LocalRangeEnd; + } + void setLocalRangeEnd(SourceLocation L) { + getLocalData()->LocalRangeEnd = L; + } + + bool getTrailingReturn() const { + return getLocalData()->TrailingReturn; + } + void setTrailingReturn(bool Trailing) { + getLocalData()->TrailingReturn = Trailing; + } + + ArrayRef<ParmVarDecl *> getParams() const { + return ArrayRef<ParmVarDecl *>(getParmArray(), getNumArgs()); + } + + // ParmVarDecls* are stored after Info, one for each argument. + ParmVarDecl **getParmArray() const { + return (ParmVarDecl**) getExtraLocalData(); + } + + unsigned getNumArgs() const { + if (isa<FunctionNoProtoType>(getTypePtr())) + return 0; + return cast<FunctionProtoType>(getTypePtr())->getNumArgs(); + } + ParmVarDecl *getArg(unsigned i) const { return getParmArray()[i]; } + void setArg(unsigned i, ParmVarDecl *VD) { getParmArray()[i] = VD; } + + TypeLoc getResultLoc() const { + return getInnerTypeLoc(); + } + + SourceRange getLocalSourceRange() const { + return SourceRange(getLocalRangeBegin(), getLocalRangeEnd()); + } + + void initializeLocal(ASTContext &Context, SourceLocation Loc) { + setLocalRangeBegin(Loc); + setLocalRangeEnd(Loc); + setTrailingReturn(false); + for (unsigned i = 0, e = getNumArgs(); i != e; ++i) + setArg(i, NULL); + } + + /// \brief Returns the size of the type source info data block that is + /// specific to this type. + unsigned getExtraLocalDataSize() const { + return getNumArgs() * sizeof(ParmVarDecl*); + } + + QualType getInnerType() const { return getTypePtr()->getResultType(); } +}; + +class FunctionProtoTypeLoc : + public InheritingConcreteTypeLoc<FunctionTypeLoc, + FunctionProtoTypeLoc, + FunctionProtoType> { +}; + +class FunctionNoProtoTypeLoc : + public InheritingConcreteTypeLoc<FunctionTypeLoc, + FunctionNoProtoTypeLoc, + FunctionNoProtoType> { +}; + + +struct ArrayLocInfo { + SourceLocation LBracketLoc, RBracketLoc; + Expr *Size; +}; + +/// \brief Wrapper for source info for arrays. +class ArrayTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, + ArrayTypeLoc, + ArrayType, + ArrayLocInfo> { +public: + SourceLocation getLBracketLoc() const { + return getLocalData()->LBracketLoc; + } + void setLBracketLoc(SourceLocation Loc) { + getLocalData()->LBracketLoc = Loc; + } + + SourceLocation getRBracketLoc() const { + return getLocalData()->RBracketLoc; + } + void setRBracketLoc(SourceLocation Loc) { + getLocalData()->RBracketLoc = Loc; + } + + SourceRange getBracketsRange() const { + return SourceRange(getLBracketLoc(), getRBracketLoc()); + } + + Expr *getSizeExpr() const { + return getLocalData()->Size; + } + void setSizeExpr(Expr *Size) { + getLocalData()->Size = Size; + } + + TypeLoc getElementLoc() const { + return getInnerTypeLoc(); + } + + SourceRange getLocalSourceRange() const { + return SourceRange(getLBracketLoc(), getRBracketLoc()); + } + + void initializeLocal(ASTContext &Context, SourceLocation Loc) { + setLBracketLoc(Loc); + setRBracketLoc(Loc); + setSizeExpr(NULL); + } + + QualType getInnerType() const { return getTypePtr()->getElementType(); } +}; + +class ConstantArrayTypeLoc : + public InheritingConcreteTypeLoc<ArrayTypeLoc, + ConstantArrayTypeLoc, + ConstantArrayType> { +}; + +class IncompleteArrayTypeLoc : + public InheritingConcreteTypeLoc<ArrayTypeLoc, + IncompleteArrayTypeLoc, + IncompleteArrayType> { +}; + +class DependentSizedArrayTypeLoc : + public InheritingConcreteTypeLoc<ArrayTypeLoc, + DependentSizedArrayTypeLoc, + DependentSizedArrayType> { + +}; + +class VariableArrayTypeLoc : + public InheritingConcreteTypeLoc<ArrayTypeLoc, + VariableArrayTypeLoc, + VariableArrayType> { +}; + + +// Location information for a TemplateName. Rudimentary for now. +struct TemplateNameLocInfo { + SourceLocation NameLoc; +}; + +struct TemplateSpecializationLocInfo : TemplateNameLocInfo { + SourceLocation TemplateKWLoc; + SourceLocation LAngleLoc; + SourceLocation RAngleLoc; +}; + +class TemplateSpecializationTypeLoc : + public ConcreteTypeLoc<UnqualTypeLoc, + TemplateSpecializationTypeLoc, + TemplateSpecializationType, + TemplateSpecializationLocInfo> { +public: + SourceLocation getTemplateKeywordLoc() const { + return getLocalData()->TemplateKWLoc; + } + void setTemplateKeywordLoc(SourceLocation Loc) { + getLocalData()->TemplateKWLoc = Loc; + } + + SourceLocation getLAngleLoc() const { + return getLocalData()->LAngleLoc; + } + void setLAngleLoc(SourceLocation Loc) { + getLocalData()->LAngleLoc = Loc; + } + + SourceLocation getRAngleLoc() const { + return getLocalData()->RAngleLoc; + } + void setRAngleLoc(SourceLocation Loc) { + getLocalData()->RAngleLoc = Loc; + } + + unsigned getNumArgs() const { + return getTypePtr()->getNumArgs(); + } + void setArgLocInfo(unsigned i, TemplateArgumentLocInfo AI) { + getArgInfos()[i] = AI; + } + TemplateArgumentLocInfo getArgLocInfo(unsigned i) const { + return getArgInfos()[i]; + } + + TemplateArgumentLoc getArgLoc(unsigned i) const { + return TemplateArgumentLoc(getTypePtr()->getArg(i), getArgLocInfo(i)); + } + + SourceLocation getTemplateNameLoc() const { + return getLocalData()->NameLoc; + } + void setTemplateNameLoc(SourceLocation Loc) { + getLocalData()->NameLoc = Loc; + } + + /// \brief - Copy the location information from the given info. + void copy(TemplateSpecializationTypeLoc Loc) { + unsigned size = getFullDataSize(); + assert(size == Loc.getFullDataSize()); + + // We're potentially copying Expr references here. We don't + // bother retaining them because TypeSourceInfos live forever, so + // as long as the Expr was retained when originally written into + // the TypeLoc, we're okay. + memcpy(Data, Loc.Data, size); + } + + SourceRange getLocalSourceRange() const { + if (getTemplateKeywordLoc().isValid()) + return SourceRange(getTemplateKeywordLoc(), getRAngleLoc()); + else + return SourceRange(getTemplateNameLoc(), getRAngleLoc()); + } + + void initializeLocal(ASTContext &Context, SourceLocation Loc) { + setTemplateKeywordLoc(Loc); + setTemplateNameLoc(Loc); + setLAngleLoc(Loc); + setRAngleLoc(Loc); + initializeArgLocs(Context, getNumArgs(), getTypePtr()->getArgs(), + getArgInfos(), Loc); + } + + static void initializeArgLocs(ASTContext &Context, unsigned NumArgs, + const TemplateArgument *Args, + TemplateArgumentLocInfo *ArgInfos, + SourceLocation Loc); + + unsigned getExtraLocalDataSize() const { + return getNumArgs() * sizeof(TemplateArgumentLocInfo); + } + +private: + TemplateArgumentLocInfo *getArgInfos() const { + return static_cast<TemplateArgumentLocInfo*>(getExtraLocalData()); + } +}; + +//===----------------------------------------------------------------------===// +// +// All of these need proper implementations. +// +//===----------------------------------------------------------------------===// + +// FIXME: size expression and attribute locations (or keyword if we +// ever fully support altivec syntax). +class VectorTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc, + VectorTypeLoc, + VectorType> { +}; + +// FIXME: size expression and attribute locations. +class ExtVectorTypeLoc : public InheritingConcreteTypeLoc<VectorTypeLoc, + ExtVectorTypeLoc, + ExtVectorType> { +}; + +// FIXME: attribute locations. +// For some reason, this isn't a subtype of VectorType. +class DependentSizedExtVectorTypeLoc : + public InheritingConcreteTypeLoc<TypeSpecTypeLoc, + DependentSizedExtVectorTypeLoc, + DependentSizedExtVectorType> { +}; + +// FIXME: location of the '_Complex' keyword. +class ComplexTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc, + ComplexTypeLoc, + ComplexType> { +}; + +struct TypeofLocInfo { + SourceLocation TypeofLoc; + SourceLocation LParenLoc; + SourceLocation RParenLoc; +}; + +struct TypeOfExprTypeLocInfo : public TypeofLocInfo { +}; + +struct TypeOfTypeLocInfo : public TypeofLocInfo { + TypeSourceInfo* UnderlyingTInfo; +}; + +template <class Derived, class TypeClass, class LocalData = TypeofLocInfo> +class TypeofLikeTypeLoc + : public ConcreteTypeLoc<UnqualTypeLoc, Derived, TypeClass, LocalData> { +public: + SourceLocation getTypeofLoc() const { + return this->getLocalData()->TypeofLoc; + } + void setTypeofLoc(SourceLocation Loc) { + this->getLocalData()->TypeofLoc = Loc; + } + + SourceLocation getLParenLoc() const { + return this->getLocalData()->LParenLoc; + } + void setLParenLoc(SourceLocation Loc) { + this->getLocalData()->LParenLoc = Loc; + } + + SourceLocation getRParenLoc() const { + return this->getLocalData()->RParenLoc; + } + void setRParenLoc(SourceLocation Loc) { + this->getLocalData()->RParenLoc = Loc; + } + + SourceRange getParensRange() const { + return SourceRange(getLParenLoc(), getRParenLoc()); + } + void setParensRange(SourceRange range) { + setLParenLoc(range.getBegin()); + setRParenLoc(range.getEnd()); + } + + SourceRange getLocalSourceRange() const { + return SourceRange(getTypeofLoc(), getRParenLoc()); + } + + void initializeLocal(ASTContext &Context, SourceLocation Loc) { + setTypeofLoc(Loc); + setLParenLoc(Loc); + setRParenLoc(Loc); + } +}; + +class TypeOfExprTypeLoc : public TypeofLikeTypeLoc<TypeOfExprTypeLoc, + TypeOfExprType, + TypeOfExprTypeLocInfo> { +public: + Expr* getUnderlyingExpr() const { + return getTypePtr()->getUnderlyingExpr(); + } + // Reimplemented to account for GNU/C++ extension + // typeof unary-expression + // where there are no parentheses. + SourceRange getLocalSourceRange() const; +}; + +class TypeOfTypeLoc + : public TypeofLikeTypeLoc<TypeOfTypeLoc, TypeOfType, TypeOfTypeLocInfo> { +public: + QualType getUnderlyingType() const { + return this->getTypePtr()->getUnderlyingType(); + } + TypeSourceInfo* getUnderlyingTInfo() const { + return this->getLocalData()->UnderlyingTInfo; + } + void setUnderlyingTInfo(TypeSourceInfo* TI) const { + this->getLocalData()->UnderlyingTInfo = TI; + } +}; + +// FIXME: location of the 'decltype' and parens. +class DecltypeTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc, + DecltypeTypeLoc, + DecltypeType> { +public: + Expr *getUnderlyingExpr() const { return getTypePtr()->getUnderlyingExpr(); } +}; + +struct UnaryTransformTypeLocInfo { + // FIXME: While there's only one unary transform right now, future ones may + // need different representations + SourceLocation KWLoc, LParenLoc, RParenLoc; + TypeSourceInfo *UnderlyingTInfo; +}; + +class UnaryTransformTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, + UnaryTransformTypeLoc, + UnaryTransformType, + UnaryTransformTypeLocInfo> { +public: + SourceLocation getKWLoc() const { return getLocalData()->KWLoc; } + void setKWLoc(SourceLocation Loc) { getLocalData()->KWLoc = Loc; } + + SourceLocation getLParenLoc() const { return getLocalData()->LParenLoc; } + void setLParenLoc(SourceLocation Loc) { getLocalData()->LParenLoc = Loc; } + + SourceLocation getRParenLoc() const { return getLocalData()->RParenLoc; } + void setRParenLoc(SourceLocation Loc) { getLocalData()->RParenLoc = Loc; } + + TypeSourceInfo* getUnderlyingTInfo() const { + return getLocalData()->UnderlyingTInfo; + } + void setUnderlyingTInfo(TypeSourceInfo *TInfo) { + getLocalData()->UnderlyingTInfo = TInfo; + } + + SourceRange getLocalSourceRange() const { + return SourceRange(getKWLoc(), getRParenLoc()); + } + + SourceRange getParensRange() const { + return SourceRange(getLParenLoc(), getRParenLoc()); + } + void setParensRange(SourceRange Range) { + setLParenLoc(Range.getBegin()); + setRParenLoc(Range.getEnd()); + } + + void initializeLocal(ASTContext &Context, SourceLocation Loc) { + setKWLoc(Loc); + setRParenLoc(Loc); + setLParenLoc(Loc); + } +}; + +class AutoTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc, + AutoTypeLoc, + AutoType> { +}; + +struct ElaboratedLocInfo { + SourceLocation ElaboratedKWLoc; + /// \brief Data associated with the nested-name-specifier location. + void *QualifierData; +}; + +class ElaboratedTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, + ElaboratedTypeLoc, + ElaboratedType, + ElaboratedLocInfo> { +public: + SourceLocation getElaboratedKeywordLoc() const { + return this->getLocalData()->ElaboratedKWLoc; + } + void setElaboratedKeywordLoc(SourceLocation Loc) { + this->getLocalData()->ElaboratedKWLoc = Loc; + } + + NestedNameSpecifierLoc getQualifierLoc() const { + return NestedNameSpecifierLoc(getTypePtr()->getQualifier(), + getLocalData()->QualifierData); + } + + void setQualifierLoc(NestedNameSpecifierLoc QualifierLoc) { + assert(QualifierLoc.getNestedNameSpecifier() + == getTypePtr()->getQualifier() && + "Inconsistent nested-name-specifier pointer"); + getLocalData()->QualifierData = QualifierLoc.getOpaqueData(); + } + + SourceRange getLocalSourceRange() const { + if (getElaboratedKeywordLoc().isValid()) + if (getQualifierLoc()) + return SourceRange(getElaboratedKeywordLoc(), + getQualifierLoc().getEndLoc()); + else + return SourceRange(getElaboratedKeywordLoc()); + else + return getQualifierLoc().getSourceRange(); + } + + void initializeLocal(ASTContext &Context, SourceLocation Loc); + + TypeLoc getNamedTypeLoc() const { + return getInnerTypeLoc(); + } + + QualType getInnerType() const { + return getTypePtr()->getNamedType(); + } + + void copy(ElaboratedTypeLoc Loc) { + unsigned size = getFullDataSize(); + assert(size == Loc.getFullDataSize()); + memcpy(Data, Loc.Data, size); + } +}; + +// This is exactly the structure of an ElaboratedTypeLoc whose inner +// type is some sort of TypeDeclTypeLoc. +struct DependentNameLocInfo : ElaboratedLocInfo { + SourceLocation NameLoc; +}; + +class DependentNameTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, + DependentNameTypeLoc, + DependentNameType, + DependentNameLocInfo> { +public: + SourceLocation getElaboratedKeywordLoc() const { + return this->getLocalData()->ElaboratedKWLoc; + } + void setElaboratedKeywordLoc(SourceLocation Loc) { + this->getLocalData()->ElaboratedKWLoc = Loc; + } + + NestedNameSpecifierLoc getQualifierLoc() const { + return NestedNameSpecifierLoc(getTypePtr()->getQualifier(), + getLocalData()->QualifierData); + } + + void setQualifierLoc(NestedNameSpecifierLoc QualifierLoc) { + assert(QualifierLoc.getNestedNameSpecifier() + == getTypePtr()->getQualifier() && + "Inconsistent nested-name-specifier pointer"); + getLocalData()->QualifierData = QualifierLoc.getOpaqueData(); + } + + SourceLocation getNameLoc() const { + return this->getLocalData()->NameLoc; + } + void setNameLoc(SourceLocation Loc) { + this->getLocalData()->NameLoc = Loc; + } + + SourceRange getLocalSourceRange() const { + if (getElaboratedKeywordLoc().isValid()) + return SourceRange(getElaboratedKeywordLoc(), getNameLoc()); + else + return SourceRange(getQualifierLoc().getBeginLoc(), getNameLoc()); + } + + void copy(DependentNameTypeLoc Loc) { + unsigned size = getFullDataSize(); + assert(size == Loc.getFullDataSize()); + memcpy(Data, Loc.Data, size); + } + + void initializeLocal(ASTContext &Context, SourceLocation Loc); +}; + +struct DependentTemplateSpecializationLocInfo : DependentNameLocInfo { + SourceLocation TemplateKWLoc; + SourceLocation LAngleLoc; + SourceLocation RAngleLoc; + // followed by a TemplateArgumentLocInfo[] +}; + +class DependentTemplateSpecializationTypeLoc : + public ConcreteTypeLoc<UnqualTypeLoc, + DependentTemplateSpecializationTypeLoc, + DependentTemplateSpecializationType, + DependentTemplateSpecializationLocInfo> { +public: + SourceLocation getElaboratedKeywordLoc() const { + return this->getLocalData()->ElaboratedKWLoc; + } + void setElaboratedKeywordLoc(SourceLocation Loc) { + this->getLocalData()->ElaboratedKWLoc = Loc; + } + + NestedNameSpecifierLoc getQualifierLoc() const { + if (!getLocalData()->QualifierData) + return NestedNameSpecifierLoc(); + + return NestedNameSpecifierLoc(getTypePtr()->getQualifier(), + getLocalData()->QualifierData); + } + + void setQualifierLoc(NestedNameSpecifierLoc QualifierLoc) { + if (!QualifierLoc) { + // Even if we have a nested-name-specifier in the dependent + // template specialization type, we won't record the nested-name-specifier + // location information when this type-source location information is + // part of a nested-name-specifier. + getLocalData()->QualifierData = 0; + return; + } + + assert(QualifierLoc.getNestedNameSpecifier() + == getTypePtr()->getQualifier() && + "Inconsistent nested-name-specifier pointer"); + getLocalData()->QualifierData = QualifierLoc.getOpaqueData(); + } + + SourceLocation getTemplateKeywordLoc() const { + return getLocalData()->TemplateKWLoc; + } + void setTemplateKeywordLoc(SourceLocation Loc) { + getLocalData()->TemplateKWLoc = Loc; + } + + SourceLocation getTemplateNameLoc() const { + return this->getLocalData()->NameLoc; + } + void setTemplateNameLoc(SourceLocation Loc) { + this->getLocalData()->NameLoc = Loc; + } + + SourceLocation getLAngleLoc() const { + return this->getLocalData()->LAngleLoc; + } + void setLAngleLoc(SourceLocation Loc) { + this->getLocalData()->LAngleLoc = Loc; + } + + SourceLocation getRAngleLoc() const { + return this->getLocalData()->RAngleLoc; + } + void setRAngleLoc(SourceLocation Loc) { + this->getLocalData()->RAngleLoc = Loc; + } + + unsigned getNumArgs() const { + return getTypePtr()->getNumArgs(); + } + + void setArgLocInfo(unsigned i, TemplateArgumentLocInfo AI) { + getArgInfos()[i] = AI; + } + TemplateArgumentLocInfo getArgLocInfo(unsigned i) const { + return getArgInfos()[i]; + } + + TemplateArgumentLoc getArgLoc(unsigned i) const { + return TemplateArgumentLoc(getTypePtr()->getArg(i), getArgLocInfo(i)); + } + + SourceRange getLocalSourceRange() const { + if (getElaboratedKeywordLoc().isValid()) + return SourceRange(getElaboratedKeywordLoc(), getRAngleLoc()); + else if (getQualifierLoc()) + return SourceRange(getQualifierLoc().getBeginLoc(), getRAngleLoc()); + else if (getTemplateKeywordLoc().isValid()) + return SourceRange(getTemplateKeywordLoc(), getRAngleLoc()); + else + return SourceRange(getTemplateNameLoc(), getRAngleLoc()); + } + + void copy(DependentTemplateSpecializationTypeLoc Loc) { + unsigned size = getFullDataSize(); + assert(size == Loc.getFullDataSize()); + memcpy(Data, Loc.Data, size); + } + + void initializeLocal(ASTContext &Context, SourceLocation Loc); + + unsigned getExtraLocalDataSize() const { + return getNumArgs() * sizeof(TemplateArgumentLocInfo); + } + +private: + TemplateArgumentLocInfo *getArgInfos() const { + return static_cast<TemplateArgumentLocInfo*>(getExtraLocalData()); + } +}; + + +struct PackExpansionTypeLocInfo { + SourceLocation EllipsisLoc; +}; + +class PackExpansionTypeLoc + : public ConcreteTypeLoc<UnqualTypeLoc, PackExpansionTypeLoc, + PackExpansionType, PackExpansionTypeLocInfo> { +public: + SourceLocation getEllipsisLoc() const { + return this->getLocalData()->EllipsisLoc; + } + + void setEllipsisLoc(SourceLocation Loc) { + this->getLocalData()->EllipsisLoc = Loc; + } + + SourceRange getLocalSourceRange() const { + return SourceRange(getEllipsisLoc(), getEllipsisLoc()); + } + + void initializeLocal(ASTContext &Context, SourceLocation Loc) { + setEllipsisLoc(Loc); + } + + TypeLoc getPatternLoc() const { + return getInnerTypeLoc(); + } + + QualType getInnerType() const { + return this->getTypePtr()->getPattern(); + } +}; + +struct AtomicTypeLocInfo { + SourceLocation KWLoc, LParenLoc, RParenLoc; +}; + +class AtomicTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc, AtomicTypeLoc, + AtomicType, AtomicTypeLocInfo> { +public: + TypeLoc getValueLoc() const { + return this->getInnerTypeLoc(); + } + + SourceRange getLocalSourceRange() const { + return SourceRange(getKWLoc(), getRParenLoc()); + } + + SourceLocation getKWLoc() const { + return this->getLocalData()->KWLoc; + } + void setKWLoc(SourceLocation Loc) { + this->getLocalData()->KWLoc = Loc; + } + + SourceLocation getLParenLoc() const { + return this->getLocalData()->LParenLoc; + } + void setLParenLoc(SourceLocation Loc) { + this->getLocalData()->LParenLoc = Loc; + } + + SourceLocation getRParenLoc() const { + return this->getLocalData()->RParenLoc; + } + void setRParenLoc(SourceLocation Loc) { + this->getLocalData()->RParenLoc = Loc; + } + + SourceRange getParensRange() const { + return SourceRange(getLParenLoc(), getRParenLoc()); + } + void setParensRange(SourceRange Range) { + setLParenLoc(Range.getBegin()); + setRParenLoc(Range.getEnd()); + } + + void initializeLocal(ASTContext &Context, SourceLocation Loc) { + setKWLoc(Loc); + setLParenLoc(Loc); + setRParenLoc(Loc); + } + + QualType getInnerType() const { + return this->getTypePtr()->getValueType(); + } +}; + + +} + +#endif diff --git a/clang/include/clang/AST/TypeLocNodes.def b/clang/include/clang/AST/TypeLocNodes.def new file mode 100644 index 0000000..4590e48 --- /dev/null +++ b/clang/include/clang/AST/TypeLocNodes.def @@ -0,0 +1,41 @@ +//===-- TypeLocNodes.def - Metadata about TypeLoc wrappers ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the TypeLoc info database. Each node is +// enumerated by providing its core name (e.g., "Pointer" for "PointerTypeLoc") +// and base class (e.g., "DeclaratorLoc"). All nodes except QualifiedTypeLoc +// are associated +// +// TYPELOC(Class, Base) - A TypeLoc subclass. If UNQUAL_TYPELOC is +// provided, there will be exactly one of these, Qualified. +// +// UNQUAL_TYPELOC(Class, Base, Type) - An UnqualTypeLoc subclass. +// +// ABSTRACT_TYPELOC(Class) - Refers to TypeSpecLoc and DeclaratorLoc. +// +//===----------------------------------------------------------------------===// + +#ifndef UNQUAL_TYPELOC +# define UNQUAL_TYPELOC(Class, Base) TYPELOC(Class, Base) +#endif + +#ifndef ABSTRACT_TYPELOC +# define ABSTRACT_TYPELOC(Class, Base) UNQUAL_TYPELOC(Class, Base) +#endif + +TYPELOC(Qualified, TypeLoc) +#define TYPE(Class, Base) UNQUAL_TYPELOC(Class, Base##Loc) +#define ABSTRACT_TYPE(Class, Base) ABSTRACT_TYPELOC(Class, Base##Loc) +#include "clang/AST/TypeNodes.def" + +#undef DECLARATOR_TYPELOC +#undef TYPESPEC_TYPELOC +#undef ABSTRACT_TYPELOC +#undef UNQUAL_TYPELOC +#undef TYPELOC diff --git a/clang/include/clang/AST/TypeLocVisitor.h b/clang/include/clang/AST/TypeLocVisitor.h new file mode 100644 index 0000000..50fc439 --- /dev/null +++ b/clang/include/clang/AST/TypeLocVisitor.h @@ -0,0 +1,62 @@ +//===--- TypeLocVisitor.h - Visitor for TypeLoc subclasses ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the TypeLocVisitor interface. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_AST_TYPELOCVISITOR_H +#define LLVM_CLANG_AST_TYPELOCVISITOR_H + +#include "clang/AST/TypeLoc.h" +#include "clang/AST/TypeVisitor.h" +#include "llvm/Support/ErrorHandling.h" + +namespace clang { + +#define DISPATCH(CLASSNAME) \ + return static_cast<ImplClass*>(this)-> \ + Visit##CLASSNAME(cast<CLASSNAME>(TyLoc)) + +template<typename ImplClass, typename RetTy=void> +class TypeLocVisitor { +public: + RetTy Visit(TypeLoc TyLoc) { + switch (TyLoc.getTypeLocClass()) { +#define ABSTRACT_TYPELOC(CLASS, PARENT) +#define TYPELOC(CLASS, PARENT) \ + case TypeLoc::CLASS: DISPATCH(CLASS##TypeLoc); +#include "clang/AST/TypeLocNodes.def" + } + llvm_unreachable("unexpected type loc class!"); + } + + RetTy Visit(UnqualTypeLoc TyLoc) { + switch (TyLoc.getTypeLocClass()) { +#define ABSTRACT_TYPELOC(CLASS, PARENT) +#define TYPELOC(CLASS, PARENT) \ + case TypeLoc::CLASS: DISPATCH(CLASS##TypeLoc); +#include "clang/AST/TypeLocNodes.def" + } + llvm_unreachable("unexpected type loc class!"); + } + +#define TYPELOC(CLASS, PARENT) \ + RetTy Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \ + DISPATCH(PARENT); \ + } +#include "clang/AST/TypeLocNodes.def" + + RetTy VisitTypeLoc(TypeLoc TyLoc) { return RetTy(); } +}; + +#undef DISPATCH + +} // end namespace clang + +#endif // LLVM_CLANG_AST_TYPELOCVISITOR_H diff --git a/clang/include/clang/AST/TypeNodes.def b/clang/include/clang/AST/TypeNodes.def new file mode 100644 index 0000000..d5c485f --- /dev/null +++ b/clang/include/clang/AST/TypeNodes.def @@ -0,0 +1,127 @@ +//===-- TypeNodes.def - Metadata about Type AST nodes -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the AST type info database. Each type node is +// enumerated by providing its name (e.g., "Builtin" or "Enum") and +// base class (e.g., "Type" or "TagType"). Depending on where in the +// abstract syntax tree the type will show up, the enumeration uses +// one of four different macros: +// +// TYPE(Class, Base) - A type that can show up anywhere in the AST, +// and might be dependent, canonical, or non-canonical. All clients +// will need to understand these types. +// +// ABSTRACT_TYPE(Class, Base) - An abstract class that shows up in +// the type hierarchy but has no concrete instances. +// +// NON_CANONICAL_TYPE(Class, Base) - A type that can show up +// anywhere in the AST but will never be a part of a canonical +// type. Clients that only need to deal with canonical types +// (ignoring, e.g., typedefs and other type alises used for +// pretty-printing) can ignore these types. +// +// DEPENDENT_TYPE(Class, Base) - A type that will only show up +// within a C++ template that has not been instantiated, e.g., a +// type that is always dependent. Clients that do not need to deal +// with uninstantiated C++ templates can ignore these types. +// +// NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) - A type that +// is non-canonical unless it is dependent. Defaults to TYPE because +// it is neither reliably dependent nor reliably non-canonical. +// +// There is a sixth macro, independent of the others. Most clients +// will not need to use it. +// +// LEAF_TYPE(Class) - A type that never has inner types. Clients +// which can operate on such types more efficiently may wish to do so. +// +//===----------------------------------------------------------------------===// + +#ifndef ABSTRACT_TYPE +# define ABSTRACT_TYPE(Class, Base) TYPE(Class, Base) +#endif + +#ifndef NON_CANONICAL_TYPE +# define NON_CANONICAL_TYPE(Class, Base) TYPE(Class, Base) +#endif + +#ifndef DEPENDENT_TYPE +# define DEPENDENT_TYPE(Class, Base) TYPE(Class, Base) +#endif + +#ifndef NON_CANONICAL_UNLESS_DEPENDENT_TYPE +# define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) TYPE(Class, Base) +#endif + +TYPE(Builtin, Type) +TYPE(Complex, Type) +TYPE(Pointer, Type) +TYPE(BlockPointer, Type) +ABSTRACT_TYPE(Reference, Type) +TYPE(LValueReference, ReferenceType) +TYPE(RValueReference, ReferenceType) +TYPE(MemberPointer, Type) +ABSTRACT_TYPE(Array, Type) +TYPE(ConstantArray, ArrayType) +TYPE(IncompleteArray, ArrayType) +TYPE(VariableArray, ArrayType) +DEPENDENT_TYPE(DependentSizedArray, ArrayType) +DEPENDENT_TYPE(DependentSizedExtVector, Type) +TYPE(Vector, Type) +TYPE(ExtVector, VectorType) +ABSTRACT_TYPE(Function, Type) +TYPE(FunctionProto, FunctionType) +TYPE(FunctionNoProto, FunctionType) +DEPENDENT_TYPE(UnresolvedUsing, Type) +NON_CANONICAL_TYPE(Paren, Type) +NON_CANONICAL_TYPE(Typedef, Type) +NON_CANONICAL_UNLESS_DEPENDENT_TYPE(TypeOfExpr, Type) +NON_CANONICAL_UNLESS_DEPENDENT_TYPE(TypeOf, Type) +NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Decltype, Type) +NON_CANONICAL_UNLESS_DEPENDENT_TYPE(UnaryTransform, Type) +ABSTRACT_TYPE(Tag, Type) +TYPE(Record, TagType) +TYPE(Enum, TagType) +NON_CANONICAL_TYPE(Elaborated, Type) +NON_CANONICAL_TYPE(Attributed, Type) +DEPENDENT_TYPE(TemplateTypeParm, Type) +NON_CANONICAL_TYPE(SubstTemplateTypeParm, Type) +DEPENDENT_TYPE(SubstTemplateTypeParmPack, Type) +NON_CANONICAL_UNLESS_DEPENDENT_TYPE(TemplateSpecialization, Type) +NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Auto, Type) +DEPENDENT_TYPE(InjectedClassName, Type) +DEPENDENT_TYPE(DependentName, Type) +DEPENDENT_TYPE(DependentTemplateSpecialization, Type) +DEPENDENT_TYPE(PackExpansion, Type) +TYPE(ObjCObject, Type) +TYPE(ObjCInterface, ObjCObjectType) +TYPE(ObjCObjectPointer, Type) +TYPE(Atomic, Type) + +#ifdef LAST_TYPE +LAST_TYPE(Atomic) +#undef LAST_TYPE +#endif + +// These types are always leaves in the type hierarchy. +#ifdef LEAF_TYPE +LEAF_TYPE(Enum) +LEAF_TYPE(Builtin) +LEAF_TYPE(Record) +LEAF_TYPE(InjectedClassName) +LEAF_TYPE(ObjCInterface) +LEAF_TYPE(TemplateTypeParm) +#undef LEAF_TYPE +#endif + +#undef NON_CANONICAL_UNLESS_DEPENDENT_TYPE +#undef DEPENDENT_TYPE +#undef NON_CANONICAL_TYPE +#undef ABSTRACT_TYPE +#undef TYPE diff --git a/clang/include/clang/AST/TypeOrdering.h b/clang/include/clang/AST/TypeOrdering.h new file mode 100644 index 0000000..7cf0d5e --- /dev/null +++ b/clang/include/clang/AST/TypeOrdering.h @@ -0,0 +1,77 @@ +//===-------------- TypeOrdering.h - Total ordering for types -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides a function objects and specializations that +// allow QualType values to be sorted, used in std::maps, std::sets, +// llvm::DenseMaps, and llvm::DenseSets. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TYPE_ORDERING_H +#define LLVM_CLANG_TYPE_ORDERING_H + +#include "clang/AST/Type.h" +#include "clang/AST/CanonicalType.h" +#include <functional> + +namespace clang { + +/// QualTypeOrdering - Function object that provides a total ordering +/// on QualType values. +struct QualTypeOrdering : std::binary_function<QualType, QualType, bool> { + bool operator()(QualType T1, QualType T2) const { + return std::less<void*>()(T1.getAsOpaquePtr(), T2.getAsOpaquePtr()); + } +}; + +} + +namespace llvm { + template<class> struct DenseMapInfo; + + template<> struct DenseMapInfo<clang::QualType> { + static inline clang::QualType getEmptyKey() { return clang::QualType(); } + + static inline clang::QualType getTombstoneKey() { + using clang::QualType; + return QualType::getFromOpaquePtr(reinterpret_cast<clang::Type *>(-1)); + } + + static unsigned getHashValue(clang::QualType Val) { + return (unsigned)((uintptr_t)Val.getAsOpaquePtr()) ^ + ((unsigned)((uintptr_t)Val.getAsOpaquePtr() >> 9)); + } + + static bool isEqual(clang::QualType LHS, clang::QualType RHS) { + return LHS == RHS; + } + }; + + template<> struct DenseMapInfo<clang::CanQualType> { + static inline clang::CanQualType getEmptyKey() { + return clang::CanQualType(); + } + + static inline clang::CanQualType getTombstoneKey() { + using clang::CanQualType; + return CanQualType::getFromOpaquePtr(reinterpret_cast<clang::Type *>(-1)); + } + + static unsigned getHashValue(clang::CanQualType Val) { + return (unsigned)((uintptr_t)Val.getAsOpaquePtr()) ^ + ((unsigned)((uintptr_t)Val.getAsOpaquePtr() >> 9)); + } + + static bool isEqual(clang::CanQualType LHS, clang::CanQualType RHS) { + return LHS == RHS; + } + }; +} + +#endif diff --git a/clang/include/clang/AST/TypeVisitor.h b/clang/include/clang/AST/TypeVisitor.h new file mode 100644 index 0000000..242aa58 --- /dev/null +++ b/clang/include/clang/AST/TypeVisitor.h @@ -0,0 +1,53 @@ +//===--- TypeVisitor.h - Visitor for Type subclasses ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the TypeVisitor interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_TYPEVISITOR_H +#define LLVM_CLANG_AST_TYPEVISITOR_H + +#include "clang/AST/Type.h" + +namespace clang { + +#define DISPATCH(CLASS) \ + return static_cast<ImplClass*>(this)-> \ + Visit##CLASS(static_cast<const CLASS*>(T)) + +template<typename ImplClass, typename RetTy=void> +class TypeVisitor { +public: + RetTy Visit(const Type *T) { + // Top switch stmt: dispatch to VisitFooType for each FooType. + switch (T->getTypeClass()) { +#define ABSTRACT_TYPE(CLASS, PARENT) +#define TYPE(CLASS, PARENT) case Type::CLASS: DISPATCH(CLASS##Type); +#include "clang/AST/TypeNodes.def" + } + llvm_unreachable("Unknown type class!"); + } + + // If the implementation chooses not to implement a certain visit method, fall + // back on superclass. +#define TYPE(CLASS, PARENT) RetTy Visit##CLASS##Type(const CLASS##Type *T) { \ + DISPATCH(PARENT); \ +} +#include "clang/AST/TypeNodes.def" + + // Base case, ignore it. :) + RetTy VisitType(const Type*) { return RetTy(); } +}; + +#undef DISPATCH + +} // end namespace clang + +#endif diff --git a/clang/include/clang/AST/UnresolvedSet.h b/clang/include/clang/AST/UnresolvedSet.h new file mode 100644 index 0000000..0918dc4 --- /dev/null +++ b/clang/include/clang/AST/UnresolvedSet.h @@ -0,0 +1,186 @@ +//===-- UnresolvedSet.h - Unresolved sets of declarations ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the UnresolvedSet class, which is used to store +// collections of declarations in the AST. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_UNRESOLVEDSET_H +#define LLVM_CLANG_AST_UNRESOLVEDSET_H + +#include <iterator> +#include "llvm/ADT/SmallVector.h" +#include "clang/AST/DeclAccessPair.h" + +namespace clang { + +/// The iterator over UnresolvedSets. Serves as both the const and +/// non-const iterator. +class UnresolvedSetIterator { +private: + typedef SmallVectorImpl<DeclAccessPair> DeclsTy; + typedef DeclsTy::iterator IteratorTy; + + IteratorTy ir; + + friend class UnresolvedSetImpl; + friend class OverloadExpr; + explicit UnresolvedSetIterator(DeclsTy::iterator ir) : ir(ir) {} + explicit UnresolvedSetIterator(DeclsTy::const_iterator ir) : + ir(const_cast<DeclsTy::iterator>(ir)) {} + + IteratorTy getIterator() const { return ir; } + +public: + UnresolvedSetIterator() {} + + typedef std::iterator_traits<IteratorTy>::difference_type difference_type; + typedef NamedDecl *value_type; + typedef NamedDecl **pointer; + typedef NamedDecl *reference; + typedef std::iterator_traits<IteratorTy>::iterator_category iterator_category; + + NamedDecl *getDecl() const { return ir->getDecl(); } + AccessSpecifier getAccess() const { return ir->getAccess(); } + void setAccess(AccessSpecifier AS) { ir->setAccess(AS); } + DeclAccessPair getPair() const { return *ir; } + + NamedDecl *operator*() const { return getDecl(); } + + UnresolvedSetIterator &operator++() { ++ir; return *this; } + UnresolvedSetIterator operator++(int) { return UnresolvedSetIterator(ir++); } + UnresolvedSetIterator &operator--() { --ir; return *this; } + UnresolvedSetIterator operator--(int) { return UnresolvedSetIterator(ir--); } + + UnresolvedSetIterator &operator+=(difference_type d) { + ir += d; return *this; + } + UnresolvedSetIterator operator+(difference_type d) const { + return UnresolvedSetIterator(ir + d); + } + UnresolvedSetIterator &operator-=(difference_type d) { + ir -= d; return *this; + } + UnresolvedSetIterator operator-(difference_type d) const { + return UnresolvedSetIterator(ir - d); + } + value_type operator[](difference_type d) const { return *(*this + d); } + + difference_type operator-(const UnresolvedSetIterator &o) const { + return ir - o.ir; + } + + bool operator==(const UnresolvedSetIterator &o) const { return ir == o.ir; } + bool operator!=(const UnresolvedSetIterator &o) const { return ir != o.ir; } + bool operator<(const UnresolvedSetIterator &o) const { return ir < o.ir; } + bool operator<=(const UnresolvedSetIterator &o) const { return ir <= o.ir; } + bool operator>=(const UnresolvedSetIterator &o) const { return ir >= o.ir; } + bool operator>(const UnresolvedSetIterator &o) const { return ir > o.ir; } +}; + +/// UnresolvedSet - A set of unresolved declarations. +class UnresolvedSetImpl { + typedef UnresolvedSetIterator::DeclsTy DeclsTy; + + // Don't allow direct construction, and only permit subclassing by + // UnresolvedSet. +private: + template <unsigned N> friend class UnresolvedSet; + UnresolvedSetImpl() {} + UnresolvedSetImpl(const UnresolvedSetImpl &) {} + +public: + // We don't currently support assignment through this iterator, so we might + // as well use the same implementation twice. + typedef UnresolvedSetIterator iterator; + typedef UnresolvedSetIterator const_iterator; + + iterator begin() { return iterator(decls().begin()); } + iterator end() { return iterator(decls().end()); } + + const_iterator begin() const { return const_iterator(decls().begin()); } + const_iterator end() const { return const_iterator(decls().end()); } + + void addDecl(NamedDecl *D) { + addDecl(D, AS_none); + } + + void addDecl(NamedDecl *D, AccessSpecifier AS) { + decls().push_back(DeclAccessPair::make(D, AS)); + } + + /// Replaces the given declaration with the new one, once. + /// + /// \return true if the set changed + bool replace(const NamedDecl* Old, NamedDecl *New) { + for (DeclsTy::iterator I = decls().begin(), E = decls().end(); I != E; ++I) + if (I->getDecl() == Old) + return (I->setDecl(New), true); + return false; + } + + /// Replaces the declaration at the given iterator with the new one, + /// preserving the original access bits. + void replace(iterator I, NamedDecl *New) { + I.ir->setDecl(New); + } + + void replace(iterator I, NamedDecl *New, AccessSpecifier AS) { + I.ir->set(New, AS); + } + + void erase(unsigned I) { + decls()[I] = decls().back(); + decls().pop_back(); + } + + void erase(iterator I) { + *I.ir = decls().back(); + decls().pop_back(); + } + + void setAccess(iterator I, AccessSpecifier AS) { + I.ir->setAccess(AS); + } + + void clear() { decls().clear(); } + void set_size(unsigned N) { decls().set_size(N); } + + bool empty() const { return decls().empty(); } + unsigned size() const { return decls().size(); } + + void append(iterator I, iterator E) { + decls().append(I.ir, E.ir); + } + + DeclAccessPair &operator[](unsigned I) { return decls()[I]; } + const DeclAccessPair &operator[](unsigned I) const { return decls()[I]; } + +private: + // These work because the only permitted subclass is UnresolvedSetImpl + + DeclsTy &decls() { + return *reinterpret_cast<DeclsTy*>(this); + } + const DeclsTy &decls() const { + return *reinterpret_cast<const DeclsTy*>(this); + } +}; + +/// A set of unresolved declarations +template <unsigned InlineCapacity> class UnresolvedSet : + public UnresolvedSetImpl { + SmallVector<DeclAccessPair, InlineCapacity> Decls; +}; + + +} // namespace clang + +#endif diff --git a/clang/include/clang/AST/VTTBuilder.h b/clang/include/clang/AST/VTTBuilder.h new file mode 100644 index 0000000..6756dd1 --- /dev/null +++ b/clang/include/clang/AST/VTTBuilder.h @@ -0,0 +1,176 @@ +//===--- VTTBuilder.h - C++ VTT layout builder --------------------*- C++ -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This contains code dealing with generation of the layout of virtual table +// tables (VTT). +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_VTTBUILDER_H +#define LLVM_CLANG_AST_VTTBUILDER_H + +#include "clang/AST/BaseSubobject.h" +#include "clang/AST/CXXInheritance.h" +#include "clang/AST/GlobalDecl.h" +#include "clang/AST/RecordLayout.h" +#include "clang/Basic/ABI.h" +#include "llvm/ADT/SetVector.h" +#include <utility> + +namespace clang { + +class VTTVTable { + llvm::PointerIntPair<const CXXRecordDecl *, 1, bool> BaseAndIsVirtual; + CharUnits BaseOffset; + +public: + VTTVTable() {} + VTTVTable(const CXXRecordDecl *Base, CharUnits BaseOffset, bool BaseIsVirtual) + : BaseAndIsVirtual(Base, BaseIsVirtual), BaseOffset(BaseOffset) {} + VTTVTable(BaseSubobject Base, bool BaseIsVirtual) + : BaseAndIsVirtual(Base.getBase(), BaseIsVirtual), + BaseOffset(Base.getBaseOffset()) {} + + const CXXRecordDecl *getBase() const { + return BaseAndIsVirtual.getPointer(); + } + + CharUnits getBaseOffset() const { + return BaseOffset; + } + + bool isVirtual() const { + return BaseAndIsVirtual.getInt(); + } + + BaseSubobject getBaseSubobject() const { + return BaseSubobject(getBase(), getBaseOffset()); + } +}; + +struct VTTComponent { + uint64_t VTableIndex; + BaseSubobject VTableBase; + + VTTComponent() {} + VTTComponent(uint64_t VTableIndex, BaseSubobject VTableBase) + : VTableIndex(VTableIndex), VTableBase(VTableBase) {} +}; + +/// VTT builder - Class for building VTT layout information. +class VTTBuilder { + + ASTContext &Ctx; + + /// MostDerivedClass - The most derived class for which we're building this + /// vtable. + const CXXRecordDecl *MostDerivedClass; + + typedef SmallVector<VTTVTable, 64> VTTVTablesVectorTy; + + /// VTTVTables - The VTT vtables. + VTTVTablesVectorTy VTTVTables; + + typedef SmallVector<VTTComponent, 64> VTTComponentsVectorTy; + + /// VTTComponents - The VTT components. + VTTComponentsVectorTy VTTComponents; + + /// MostDerivedClassLayout - the AST record layout of the most derived class. + const ASTRecordLayout &MostDerivedClassLayout; + + typedef llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBasesSetTy; + + typedef llvm::DenseMap<BaseSubobject, uint64_t> AddressPointsMapTy; + + /// SubVTTIndicies - The sub-VTT indices for the bases of the most derived + /// class. + llvm::DenseMap<BaseSubobject, uint64_t> SubVTTIndicies; + + /// SecondaryVirtualPointerIndices - The secondary virtual pointer indices of + /// all subobjects of the most derived class. + llvm::DenseMap<BaseSubobject, uint64_t> SecondaryVirtualPointerIndices; + + /// GenerateDefinition - Whether the VTT builder should generate LLVM IR for + /// the VTT. + bool GenerateDefinition; + + /// AddVTablePointer - Add a vtable pointer to the VTT currently being built. + /// + /// \param AddressPoints - If the vtable is a construction vtable, this has + /// the address points for it. + void AddVTablePointer(BaseSubobject Base, uint64_t VTableIndex, + const CXXRecordDecl *VTableClass); + + /// LayoutSecondaryVTTs - Lay out the secondary VTTs of the given base + /// subobject. + void LayoutSecondaryVTTs(BaseSubobject Base); + + /// LayoutSecondaryVirtualPointers - Lay out the secondary virtual pointers + /// for the given base subobject. + /// + /// \param BaseIsMorallyVirtual whether the base subobject is a virtual base + /// or a direct or indirect base of a virtual base. + /// + /// \param AddressPoints - If the vtable is a construction vtable, this has + /// the address points for it. + void LayoutSecondaryVirtualPointers(BaseSubobject Base, + bool BaseIsMorallyVirtual, + uint64_t VTableIndex, + const CXXRecordDecl *VTableClass, + VisitedVirtualBasesSetTy &VBases); + + /// LayoutSecondaryVirtualPointers - Lay out the secondary virtual pointers + /// for the given base subobject. + /// + /// \param AddressPoints - If the vtable is a construction vtable, this has + /// the address points for it. + void LayoutSecondaryVirtualPointers(BaseSubobject Base, + uint64_t VTableIndex); + + /// LayoutVirtualVTTs - Lay out the VTTs for the virtual base classes of the + /// given record decl. + void LayoutVirtualVTTs(const CXXRecordDecl *RD, + VisitedVirtualBasesSetTy &VBases); + + /// LayoutVTT - Will lay out the VTT for the given subobject, including any + /// secondary VTTs, secondary virtual pointers and virtual VTTs. + void LayoutVTT(BaseSubobject Base, bool BaseIsVirtual); + +public: + VTTBuilder(ASTContext &Ctx, const CXXRecordDecl *MostDerivedClass, + bool GenerateDefinition); + + // getVTTComponents - Returns a reference to the VTT components. + const VTTComponentsVectorTy &getVTTComponents() const { + return VTTComponents; + } + + // getVTTVTables - Returns a reference to the VTT vtables. + const VTTVTablesVectorTy &getVTTVTables() const { + return VTTVTables; + } + + /// getSubVTTIndicies - Returns a reference to the sub-VTT indices. + const llvm::DenseMap<BaseSubobject, uint64_t> &getSubVTTIndicies() const { + return SubVTTIndicies; + } + + /// getSecondaryVirtualPointerIndices - Returns a reference to the secondary + /// virtual pointer indices. + const llvm::DenseMap<BaseSubobject, uint64_t> & + getSecondaryVirtualPointerIndices() const { + return SecondaryVirtualPointerIndices; + } + +}; + +} + +#endif diff --git a/clang/include/clang/AST/VTableBuilder.h b/clang/include/clang/AST/VTableBuilder.h new file mode 100644 index 0000000..392dad9 --- /dev/null +++ b/clang/include/clang/AST/VTableBuilder.h @@ -0,0 +1,357 @@ +//===--- VTableBuilder.h - C++ vtable layout builder --------------*- C++ -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This contains code dealing with generation of the layout of virtual tables. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_VTABLEBUILDER_H +#define LLVM_CLANG_AST_VTABLEBUILDER_H + +#include "clang/AST/BaseSubobject.h" +#include "clang/AST/CXXInheritance.h" +#include "clang/AST/GlobalDecl.h" +#include "clang/AST/RecordLayout.h" +#include "clang/Basic/ABI.h" +#include "llvm/ADT/SetVector.h" +#include <utility> + +namespace clang { + class CXXRecordDecl; + +/// VTableComponent - Represents a single component in a vtable. +class VTableComponent { +public: + enum Kind { + CK_VCallOffset, + CK_VBaseOffset, + CK_OffsetToTop, + CK_RTTI, + CK_FunctionPointer, + + /// CK_CompleteDtorPointer - A pointer to the complete destructor. + CK_CompleteDtorPointer, + + /// CK_DeletingDtorPointer - A pointer to the deleting destructor. + CK_DeletingDtorPointer, + + /// CK_UnusedFunctionPointer - In some cases, a vtable function pointer + /// will end up never being called. Such vtable function pointers are + /// represented as a CK_UnusedFunctionPointer. + CK_UnusedFunctionPointer + }; + + VTableComponent() { } + + static VTableComponent MakeVCallOffset(CharUnits Offset) { + return VTableComponent(CK_VCallOffset, Offset); + } + + static VTableComponent MakeVBaseOffset(CharUnits Offset) { + return VTableComponent(CK_VBaseOffset, Offset); + } + + static VTableComponent MakeOffsetToTop(CharUnits Offset) { + return VTableComponent(CK_OffsetToTop, Offset); + } + + static VTableComponent MakeRTTI(const CXXRecordDecl *RD) { + return VTableComponent(CK_RTTI, reinterpret_cast<uintptr_t>(RD)); + } + + static VTableComponent MakeFunction(const CXXMethodDecl *MD) { + assert(!isa<CXXDestructorDecl>(MD) && + "Don't use MakeFunction with destructors!"); + + return VTableComponent(CK_FunctionPointer, + reinterpret_cast<uintptr_t>(MD)); + } + + static VTableComponent MakeCompleteDtor(const CXXDestructorDecl *DD) { + return VTableComponent(CK_CompleteDtorPointer, + reinterpret_cast<uintptr_t>(DD)); + } + + static VTableComponent MakeDeletingDtor(const CXXDestructorDecl *DD) { + return VTableComponent(CK_DeletingDtorPointer, + reinterpret_cast<uintptr_t>(DD)); + } + + static VTableComponent MakeUnusedFunction(const CXXMethodDecl *MD) { + assert(!isa<CXXDestructorDecl>(MD) && + "Don't use MakeUnusedFunction with destructors!"); + return VTableComponent(CK_UnusedFunctionPointer, + reinterpret_cast<uintptr_t>(MD)); + } + + static VTableComponent getFromOpaqueInteger(uint64_t I) { + return VTableComponent(I); + } + + /// getKind - Get the kind of this vtable component. + Kind getKind() const { + return (Kind)(Value & 0x7); + } + + CharUnits getVCallOffset() const { + assert(getKind() == CK_VCallOffset && "Invalid component kind!"); + + return getOffset(); + } + + CharUnits getVBaseOffset() const { + assert(getKind() == CK_VBaseOffset && "Invalid component kind!"); + + return getOffset(); + } + + CharUnits getOffsetToTop() const { + assert(getKind() == CK_OffsetToTop && "Invalid component kind!"); + + return getOffset(); + } + + const CXXRecordDecl *getRTTIDecl() const { + assert(getKind() == CK_RTTI && "Invalid component kind!"); + + return reinterpret_cast<CXXRecordDecl *>(getPointer()); + } + + const CXXMethodDecl *getFunctionDecl() const { + assert(getKind() == CK_FunctionPointer); + + return reinterpret_cast<CXXMethodDecl *>(getPointer()); + } + + const CXXDestructorDecl *getDestructorDecl() const { + assert((getKind() == CK_CompleteDtorPointer || + getKind() == CK_DeletingDtorPointer) && "Invalid component kind!"); + + return reinterpret_cast<CXXDestructorDecl *>(getPointer()); + } + + const CXXMethodDecl *getUnusedFunctionDecl() const { + assert(getKind() == CK_UnusedFunctionPointer); + + return reinterpret_cast<CXXMethodDecl *>(getPointer()); + } + +private: + VTableComponent(Kind ComponentKind, CharUnits Offset) { + assert((ComponentKind == CK_VCallOffset || + ComponentKind == CK_VBaseOffset || + ComponentKind == CK_OffsetToTop) && "Invalid component kind!"); + assert(Offset.getQuantity() <= ((1LL << 56) - 1) && "Offset is too big!"); + + Value = ((Offset.getQuantity() << 3) | ComponentKind); + } + + VTableComponent(Kind ComponentKind, uintptr_t Ptr) { + assert((ComponentKind == CK_RTTI || + ComponentKind == CK_FunctionPointer || + ComponentKind == CK_CompleteDtorPointer || + ComponentKind == CK_DeletingDtorPointer || + ComponentKind == CK_UnusedFunctionPointer) && + "Invalid component kind!"); + + assert((Ptr & 7) == 0 && "Pointer not sufficiently aligned!"); + + Value = Ptr | ComponentKind; + } + + CharUnits getOffset() const { + assert((getKind() == CK_VCallOffset || getKind() == CK_VBaseOffset || + getKind() == CK_OffsetToTop) && "Invalid component kind!"); + + return CharUnits::fromQuantity(Value >> 3); + } + + uintptr_t getPointer() const { + assert((getKind() == CK_RTTI || + getKind() == CK_FunctionPointer || + getKind() == CK_CompleteDtorPointer || + getKind() == CK_DeletingDtorPointer || + getKind() == CK_UnusedFunctionPointer) && + "Invalid component kind!"); + + return static_cast<uintptr_t>(Value & ~7ULL); + } + + explicit VTableComponent(uint64_t Value) + : Value(Value) { } + + /// The kind is stored in the lower 3 bits of the value. For offsets, we + /// make use of the facts that classes can't be larger than 2^55 bytes, + /// so we store the offset in the lower part of the 61 bytes that remain. + /// (The reason that we're not simply using a PointerIntPair here is that we + /// need the offsets to be 64-bit, even when on a 32-bit machine). + int64_t Value; +}; + +class VTableLayout { +public: + typedef std::pair<uint64_t, ThunkInfo> VTableThunkTy; + typedef SmallVector<ThunkInfo, 1> ThunkInfoVectorTy; + + typedef const VTableComponent *vtable_component_iterator; + typedef const VTableThunkTy *vtable_thunk_iterator; + + typedef llvm::DenseMap<BaseSubobject, uint64_t> AddressPointsMapTy; +private: + uint64_t NumVTableComponents; + llvm::OwningArrayPtr<VTableComponent> VTableComponents; + + /// VTableThunks - Contains thunks needed by vtables. + uint64_t NumVTableThunks; + llvm::OwningArrayPtr<VTableThunkTy> VTableThunks; + + /// Address points - Address points for all vtables. + AddressPointsMapTy AddressPoints; + +public: + VTableLayout(uint64_t NumVTableComponents, + const VTableComponent *VTableComponents, + uint64_t NumVTableThunks, + const VTableThunkTy *VTableThunks, + const AddressPointsMapTy &AddressPoints); + ~VTableLayout(); + + uint64_t getNumVTableComponents() const { + return NumVTableComponents; + } + + vtable_component_iterator vtable_component_begin() const { + return VTableComponents.get(); + } + + vtable_component_iterator vtable_component_end() const { + return VTableComponents.get()+NumVTableComponents; + } + + uint64_t getNumVTableThunks() const { + return NumVTableThunks; + } + + vtable_thunk_iterator vtable_thunk_begin() const { + return VTableThunks.get(); + } + + vtable_thunk_iterator vtable_thunk_end() const { + return VTableThunks.get()+NumVTableThunks; + } + + uint64_t getAddressPoint(BaseSubobject Base) const { + assert(AddressPoints.count(Base) && + "Did not find address point!"); + + uint64_t AddressPoint = AddressPoints.lookup(Base); + assert(AddressPoint && "Address point must not be zero!"); + + return AddressPoint; + } + + const AddressPointsMapTy &getAddressPoints() const { + return AddressPoints; + } +}; + +class VTableContext { + ASTContext &Context; + +public: + typedef SmallVector<std::pair<uint64_t, ThunkInfo>, 1> + VTableThunksTy; + typedef SmallVector<ThunkInfo, 1> ThunkInfoVectorTy; + +private: + /// MethodVTableIndices - Contains the index (relative to the vtable address + /// point) where the function pointer for a virtual function is stored. + typedef llvm::DenseMap<GlobalDecl, int64_t> MethodVTableIndicesTy; + MethodVTableIndicesTy MethodVTableIndices; + + typedef llvm::DenseMap<const CXXRecordDecl *, const VTableLayout *> + VTableLayoutMapTy; + VTableLayoutMapTy VTableLayouts; + + /// NumVirtualFunctionPointers - Contains the number of virtual function + /// pointers in the vtable for a given record decl. + llvm::DenseMap<const CXXRecordDecl *, uint64_t> NumVirtualFunctionPointers; + + typedef std::pair<const CXXRecordDecl *, + const CXXRecordDecl *> ClassPairTy; + + /// VirtualBaseClassOffsetOffsets - Contains the vtable offset (relative to + /// the address point) in chars where the offsets for virtual bases of a class + /// are stored. + typedef llvm::DenseMap<ClassPairTy, CharUnits> + VirtualBaseClassOffsetOffsetsMapTy; + VirtualBaseClassOffsetOffsetsMapTy VirtualBaseClassOffsetOffsets; + + typedef llvm::DenseMap<const CXXMethodDecl *, ThunkInfoVectorTy> ThunksMapTy; + + /// Thunks - Contains all thunks that a given method decl will need. + ThunksMapTy Thunks; + + void ComputeMethodVTableIndices(const CXXRecordDecl *RD); + + /// ComputeVTableRelatedInformation - Compute and store all vtable related + /// information (vtable layout, vbase offset offsets, thunks etc) for the + /// given record decl. + void ComputeVTableRelatedInformation(const CXXRecordDecl *RD); + +public: + VTableContext(ASTContext &Context) : Context(Context) {} + ~VTableContext(); + + const VTableLayout &getVTableLayout(const CXXRecordDecl *RD) { + ComputeVTableRelatedInformation(RD); + assert(VTableLayouts.count(RD) && "No layout for this record decl!"); + + return *VTableLayouts[RD]; + } + + VTableLayout * + createConstructionVTableLayout(const CXXRecordDecl *MostDerivedClass, + CharUnits MostDerivedClassOffset, + bool MostDerivedClassIsVirtual, + const CXXRecordDecl *LayoutClass); + + const ThunkInfoVectorTy *getThunkInfo(const CXXMethodDecl *MD) { + ComputeVTableRelatedInformation(MD->getParent()); + + ThunksMapTy::const_iterator I = Thunks.find(MD); + if (I == Thunks.end()) { + // We did not find a thunk for this method. + return 0; + } + + return &I->second; + } + + /// getNumVirtualFunctionPointers - Return the number of virtual function + /// pointers in the vtable for a given record decl. + uint64_t getNumVirtualFunctionPointers(const CXXRecordDecl *RD); + + /// getMethodVTableIndex - Return the index (relative to the vtable address + /// point) where the function pointer for the given virtual function is + /// stored. + uint64_t getMethodVTableIndex(GlobalDecl GD); + + /// getVirtualBaseOffsetOffset - Return the offset in chars (relative to the + /// vtable address point) where the offset of the virtual base that contains + /// the given base is stored, otherwise, if no virtual base contains the given + /// class, return 0. Base must be a virtual base class or an unambigious + /// base. + CharUnits getVirtualBaseOffsetOffset(const CXXRecordDecl *RD, + const CXXRecordDecl *VBase); +}; + +} + +#endif diff --git a/clang/include/clang/Analysis/Analyses/.#Interval.h b/clang/include/clang/Analysis/Analyses/.#Interval.h new file mode 120000 index 0000000..235903b --- /dev/null +++ b/clang/include/clang/Analysis/Analyses/.#Interval.h @@ -0,0 +1 @@ +carlo@pc-4w14-0.cs.usyd.edu.au.1585:1347012043
\ No newline at end of file diff --git a/clang/include/clang/Analysis/Analyses/.#Interval_flymake.h b/clang/include/clang/Analysis/Analyses/.#Interval_flymake.h new file mode 120000 index 0000000..235903b --- /dev/null +++ b/clang/include/clang/Analysis/Analyses/.#Interval_flymake.h @@ -0,0 +1 @@ +carlo@pc-4w14-0.cs.usyd.edu.au.1585:1347012043
\ No newline at end of file diff --git a/clang/include/clang/Analysis/Analyses/.#LiveVariables.h b/clang/include/clang/Analysis/Analyses/.#LiveVariables.h new file mode 120000 index 0000000..235903b --- /dev/null +++ b/clang/include/clang/Analysis/Analyses/.#LiveVariables.h @@ -0,0 +1 @@ +carlo@pc-4w14-0.cs.usyd.edu.au.1585:1347012043
\ No newline at end of file diff --git a/clang/include/clang/Analysis/Analyses/.#LiveVariables_flymake.h b/clang/include/clang/Analysis/Analyses/.#LiveVariables_flymake.h new file mode 120000 index 0000000..235903b --- /dev/null +++ b/clang/include/clang/Analysis/Analyses/.#LiveVariables_flymake.h @@ -0,0 +1 @@ +carlo@pc-4w14-0.cs.usyd.edu.au.1585:1347012043
\ No newline at end of file diff --git a/clang/include/clang/Analysis/Analyses/CFGReachabilityAnalysis.h b/clang/include/clang/Analysis/Analyses/CFGReachabilityAnalysis.h new file mode 100644 index 0000000..a61d9e4 --- /dev/null +++ b/clang/include/clang/Analysis/Analyses/CFGReachabilityAnalysis.h @@ -0,0 +1,49 @@ +//==- CFGReachabilityAnalysis.h - Basic reachability analysis ----*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines a flow-sensitive, (mostly) path-insensitive reachability +// analysis based on Clang's CFGs. Clients can query if a given basic block +// is reachable within the CFG. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_ANALYSIS_CFG_REACHABILITY +#define CLANG_ANALYSIS_CFG_REACHABILITY + +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/DenseMap.h" + +namespace clang { + +class CFG; +class CFGBlock; + +// A class that performs reachability queries for CFGBlocks. Several internal +// checks in this checker require reachability information. The requests all +// tend to have a common destination, so we lazily do a predecessor search +// from the destination node and cache the results to prevent work +// duplication. +class CFGReverseBlockReachabilityAnalysis { + typedef llvm::BitVector ReachableSet; + typedef llvm::DenseMap<unsigned, ReachableSet> ReachableMap; + ReachableSet analyzed; + ReachableMap reachable; +public: + CFGReverseBlockReachabilityAnalysis(const CFG &cfg); + + /// Returns true if the block 'Dst' can be reached from block 'Src'. + bool isReachable(const CFGBlock *Src, const CFGBlock *Dst); + +private: + void mapReachability(const CFGBlock *Dst); +}; + +} + +#endif diff --git a/clang/include/clang/Analysis/Analyses/Dominators.h b/clang/include/clang/Analysis/Analyses/Dominators.h new file mode 100644 index 0000000..e9a431a --- /dev/null +++ b/clang/include/clang/Analysis/Analyses/Dominators.h @@ -0,0 +1,212 @@ +//==- Dominators.h - Implementation of dominators tree for Clang CFG C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the dominators tree functionality for Clang CFGs. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_DOMINATORS_H +#define LLVM_CLANG_DOMINATORS_H + +#include "clang/Analysis/AnalysisContext.h" + +#include "llvm/Module.h" +#include "llvm/ADT/GraphTraits.h" +#include "clang/Analysis/CFG.h" +#include "llvm/Analysis/Dominators.h" +#include "llvm/Analysis/DominatorInternals.h" + +namespace clang { + +class CFGBlock; +typedef llvm::DomTreeNodeBase<CFGBlock> DomTreeNode; + +/// \brief Concrete subclass of DominatorTreeBase for Clang +/// This class implements the dominators tree functionality given a Clang CFG. +/// +class DominatorTree : public ManagedAnalysis { + virtual void anchor(); +public: + llvm::DominatorTreeBase<CFGBlock>* DT; + + DominatorTree() { + DT = new llvm::DominatorTreeBase<CFGBlock>(false); + } + + ~DominatorTree() { + delete DT; + } + + llvm::DominatorTreeBase<CFGBlock>& getBase() { return *DT; } + + /// \brief This method returns the root CFGBlock of the dominators tree. + /// + inline CFGBlock *getRoot() const { + return DT->getRoot(); + } + + /// \brief This method returns the root DomTreeNode, which is the wrapper + /// for CFGBlock. + inline DomTreeNode *getRootNode() const { + return DT->getRootNode(); + } + + /// \brief This method compares two dominator trees. + /// The method returns false if the other dominator tree matches this + /// dominator tree, otherwise returns true. + /// + inline bool compare(DominatorTree &Other) const { + DomTreeNode *R = getRootNode(); + DomTreeNode *OtherR = Other.getRootNode(); + + if (!R || !OtherR || R->getBlock() != OtherR->getBlock()) + return true; + + if (DT->compare(Other.getBase())) + return true; + + return false; + } + + /// \brief This method builds the dominator tree for a given CFG + /// The CFG information is passed via AnalysisDeclContext + /// + void buildDominatorTree(AnalysisDeclContext &AC) { + cfg = AC.getCFG(); + DT->recalculate(*cfg); + } + + /// \brief This method dumps immediate dominators for each block, + /// mainly used for debug purposes. + /// + void dump() { + llvm::errs() << "Immediate dominance tree (Node#,IDom#):\n"; + for (CFG::const_iterator I = cfg->begin(), + E = cfg->end(); I != E; ++I) { + if(DT->getNode(*I)->getIDom()) + llvm::errs() << "(" << (*I)->getBlockID() + << "," + << DT->getNode(*I)->getIDom()->getBlock()->getBlockID() + << ")\n"; + else llvm::errs() << "(" << (*I)->getBlockID() + << "," << (*I)->getBlockID() << ")\n"; + } + } + + /// \brief This method tests if one CFGBlock dominates the other. + /// The method return true if A dominates B, false otherwise. + /// Note a block always dominates itself. + /// + inline bool dominates(const CFGBlock* A, const CFGBlock* B) const { + return DT->dominates(A, B); + } + + /// \brief This method tests if one CFGBlock properly dominates the other. + /// The method return true if A properly dominates B, false otherwise. + /// + bool properlyDominates(const CFGBlock*A, const CFGBlock*B) const { + return DT->properlyDominates(A, B); + } + + /// \brief This method finds the nearest common dominator CFG block + /// for CFG block A and B. If there is no such block then return NULL. + /// + inline CFGBlock *findNearestCommonDominator(CFGBlock *A, CFGBlock *B) { + return DT->findNearestCommonDominator(A, B); + } + + inline const CFGBlock *findNearestCommonDominator(const CFGBlock *A, + const CFGBlock *B) { + return DT->findNearestCommonDominator(A, B); + } + + /// \brief This method is used to update the dominator + /// tree information when a node's immediate dominator changes. + /// + inline void changeImmediateDominator(CFGBlock *N, CFGBlock *NewIDom) { + DT->changeImmediateDominator(N, NewIDom); + } + + /// \brief This method tests if the given CFGBlock can be reachable from root. + /// Returns true if reachable, false otherwise. + /// + bool isReachableFromEntry(const CFGBlock *A) { + return DT->isReachableFromEntry(A); + } + + /// \brief This method releases the memory held by the dominator tree. + /// + virtual void releaseMemory() { + DT->releaseMemory(); + } + + /// \brief This method converts the dominator tree to human readable form. + /// + virtual void print(raw_ostream &OS, const llvm::Module* M= 0) const { + DT->print(OS); + } + +private: + CFG *cfg; +}; + +inline void WriteAsOperand(raw_ostream &OS, const CFGBlock *BB, + bool t) { + OS << "BB#" << BB->getBlockID(); +} + +} // end namespace clang + +//===------------------------------------- +/// DominatorTree GraphTraits specialization so the DominatorTree can be +/// iterable by generic graph iterators. +/// +namespace llvm { +template <> struct GraphTraits< ::clang::DomTreeNode* > { + typedef ::clang::DomTreeNode NodeType; + typedef NodeType::iterator ChildIteratorType; + + static NodeType *getEntryNode(NodeType *N) { + return N; + } + static inline ChildIteratorType child_begin(NodeType *N) { + return N->begin(); + } + static inline ChildIteratorType child_end(NodeType *N) { + return N->end(); + } + + typedef df_iterator< ::clang::DomTreeNode* > nodes_iterator; + + static nodes_iterator nodes_begin(::clang::DomTreeNode *N) { + return df_begin(getEntryNode(N)); + } + + static nodes_iterator nodes_end(::clang::DomTreeNode *N) { + return df_end(getEntryNode(N)); + } +}; + +template <> struct GraphTraits< ::clang::DominatorTree* > + : public GraphTraits< ::clang::DomTreeNode* > { + static NodeType *getEntryNode(::clang::DominatorTree *DT) { + return DT->getRootNode(); + } + + static nodes_iterator nodes_begin(::clang::DominatorTree *N) { + return df_begin(getEntryNode(N)); + } + + static nodes_iterator nodes_end(::clang::DominatorTree *N) { + return df_end(getEntryNode(N)); + } +}; +} // end namespace llvm + +#endif diff --git a/clang/include/clang/Analysis/Analyses/FormatString.h b/clang/include/clang/Analysis/Analyses/FormatString.h new file mode 100644 index 0000000..9ec27ce --- /dev/null +++ b/clang/include/clang/Analysis/Analyses/FormatString.h @@ -0,0 +1,652 @@ +//= FormatString.h - Analysis of printf/fprintf format strings --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines APIs for analyzing the format strings of printf, fscanf, +// and friends. +// +// The structure of format strings for fprintf are described in C99 7.19.6.1. +// +// The structure of format strings for fscanf are described in C99 7.19.6.2. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FORMAT_H +#define LLVM_CLANG_FORMAT_H + +#include "clang/AST/CanonicalType.h" + +namespace clang { + +//===----------------------------------------------------------------------===// +/// Common components of both fprintf and fscanf format strings. +namespace analyze_format_string { + +/// Class representing optional flags with location and representation +/// information. +class OptionalFlag { +public: + OptionalFlag(const char *Representation) + : representation(Representation), flag(false) {} + bool isSet() { return flag; } + void set() { flag = true; } + void clear() { flag = false; } + void setPosition(const char *position) { + assert(position); + this->position = position; + } + const char *getPosition() const { + assert(position); + return position; + } + const char *toString() const { return representation; } + + // Overloaded operators for bool like qualities + operator bool() const { return flag; } + OptionalFlag& operator=(const bool &rhs) { + flag = rhs; + return *this; // Return a reference to myself. + } +private: + const char *representation; + const char *position; + bool flag; +}; + +/// Represents the length modifier in a format string in scanf/printf. +class LengthModifier { +public: + enum Kind { + None, + AsChar, // 'hh' + AsShort, // 'h' + AsLong, // 'l' + AsLongLong, // 'll' + AsQuad, // 'q' (BSD, deprecated, for 64-bit integer types) + AsIntMax, // 'j' + AsSizeT, // 'z' + AsPtrDiff, // 't' + AsLongDouble, // 'L' + AsAllocate, // for '%as', GNU extension to C90 scanf + AsMAllocate, // for '%ms', GNU extension to scanf + AsWideChar = AsLong // for '%ls', only makes sense for printf + }; + + LengthModifier() + : Position(0), kind(None) {} + LengthModifier(const char *pos, Kind k) + : Position(pos), kind(k) {} + + const char *getStart() const { + return Position; + } + + unsigned getLength() const { + switch (kind) { + default: + return 1; + case AsLongLong: + case AsChar: + return 2; + case None: + return 0; + } + } + + Kind getKind() const { return kind; } + void setKind(Kind k) { kind = k; } + + const char *toString() const; + +private: + const char *Position; + Kind kind; +}; + +class ConversionSpecifier { +public: + enum Kind { + InvalidSpecifier = 0, + // C99 conversion specifiers. + cArg, + dArg, + iArg, + IntArgBeg = cArg, IntArgEnd = iArg, + + oArg, + uArg, + xArg, + XArg, + UIntArgBeg = oArg, UIntArgEnd = XArg, + + fArg, + FArg, + eArg, + EArg, + gArg, + GArg, + aArg, + AArg, + DoubleArgBeg = fArg, DoubleArgEnd = AArg, + + sArg, + pArg, + nArg, + PercentArg, + CArg, + SArg, + + // ** Printf-specific ** + + // Objective-C specific specifiers. + ObjCObjArg, // '@' + ObjCBeg = ObjCObjArg, ObjCEnd = ObjCObjArg, + + // GlibC specific specifiers. + PrintErrno, // 'm' + + PrintfConvBeg = ObjCObjArg, PrintfConvEnd = PrintErrno, + + // ** Scanf-specific ** + ScanListArg, // '[' + ScanfConvBeg = ScanListArg, ScanfConvEnd = ScanListArg + }; + + ConversionSpecifier(bool isPrintf) + : IsPrintf(isPrintf), Position(0), EndScanList(0), kind(InvalidSpecifier) {} + + ConversionSpecifier(bool isPrintf, const char *pos, Kind k) + : IsPrintf(isPrintf), Position(pos), EndScanList(0), kind(k) {} + + const char *getStart() const { + return Position; + } + + StringRef getCharacters() const { + return StringRef(getStart(), getLength()); + } + + bool consumesDataArgument() const { + switch (kind) { + case PrintErrno: + assert(IsPrintf); + case PercentArg: + return false; + default: + return true; + } + } + + Kind getKind() const { return kind; } + void setKind(Kind k) { kind = k; } + unsigned getLength() const { + return EndScanList ? EndScanList - Position : 1; + } + + bool isUIntArg() const { return kind >= UIntArgBeg && kind <= UIntArgEnd; } + const char *toString() const; + + bool isPrintfKind() const { return IsPrintf; } + +protected: + bool IsPrintf; + const char *Position; + const char *EndScanList; + Kind kind; +}; + +class ArgTypeResult { +public: + enum Kind { UnknownTy, InvalidTy, SpecificTy, ObjCPointerTy, CPointerTy, + AnyCharTy, CStrTy, WCStrTy, WIntTy }; +private: + const Kind K; + QualType T; + const char *Name; + ArgTypeResult(bool) : K(InvalidTy), Name(0) {} +public: + ArgTypeResult(Kind k = UnknownTy) : K(k), Name(0) {} + ArgTypeResult(Kind k, const char *n) : K(k), Name(n) {} + ArgTypeResult(QualType t) : K(SpecificTy), T(t), Name(0) {} + ArgTypeResult(QualType t, const char *n) : K(SpecificTy), T(t), Name(n) {} + ArgTypeResult(CanQualType t) : K(SpecificTy), T(t), Name(0) {} + + static ArgTypeResult Invalid() { return ArgTypeResult(true); } + + bool isValid() const { return K != InvalidTy; } + + const QualType *getSpecificType() const { + return K == SpecificTy ? &T : 0; + } + + bool matchesType(ASTContext &C, QualType argTy) const; + + bool matchesAnyObjCObjectRef() const { return K == ObjCPointerTy; } + + QualType getRepresentativeType(ASTContext &C) const; + + std::string getRepresentativeTypeName(ASTContext &C) const; +}; + +class OptionalAmount { +public: + enum HowSpecified { NotSpecified, Constant, Arg, Invalid }; + + OptionalAmount(HowSpecified howSpecified, + unsigned amount, + const char *amountStart, + unsigned amountLength, + bool usesPositionalArg) + : start(amountStart), length(amountLength), hs(howSpecified), amt(amount), + UsesPositionalArg(usesPositionalArg), UsesDotPrefix(0) {} + + OptionalAmount(bool valid = true) + : start(0),length(0), hs(valid ? NotSpecified : Invalid), amt(0), + UsesPositionalArg(0), UsesDotPrefix(0) {} + + bool isInvalid() const { + return hs == Invalid; + } + + HowSpecified getHowSpecified() const { return hs; } + void setHowSpecified(HowSpecified h) { hs = h; } + + bool hasDataArgument() const { return hs == Arg; } + + unsigned getArgIndex() const { + assert(hasDataArgument()); + return amt; + } + + unsigned getConstantAmount() const { + assert(hs == Constant); + return amt; + } + + const char *getStart() const { + // We include the . character if it is given. + return start - UsesDotPrefix; + } + + unsigned getConstantLength() const { + assert(hs == Constant); + return length + UsesDotPrefix; + } + + ArgTypeResult getArgType(ASTContext &Ctx) const; + + void toString(raw_ostream &os) const; + + bool usesPositionalArg() const { return (bool) UsesPositionalArg; } + unsigned getPositionalArgIndex() const { + assert(hasDataArgument()); + return amt + 1; + } + + bool usesDotPrefix() const { return UsesDotPrefix; } + void setUsesDotPrefix() { UsesDotPrefix = true; } + +private: + const char *start; + unsigned length; + HowSpecified hs; + unsigned amt; + bool UsesPositionalArg : 1; + bool UsesDotPrefix; +}; + + +class FormatSpecifier { +protected: + LengthModifier LM; + OptionalAmount FieldWidth; + ConversionSpecifier CS; + /// Positional arguments, an IEEE extension: + /// IEEE Std 1003.1, 2004 Edition + /// http://www.opengroup.org/onlinepubs/009695399/functions/printf.html + bool UsesPositionalArg; + unsigned argIndex; +public: + FormatSpecifier(bool isPrintf) + : CS(isPrintf), UsesPositionalArg(false), argIndex(0) {} + + void setLengthModifier(LengthModifier lm) { + LM = lm; + } + + void setUsesPositionalArg() { UsesPositionalArg = true; } + + void setArgIndex(unsigned i) { + argIndex = i; + } + + unsigned getArgIndex() const { + return argIndex; + } + + unsigned getPositionalArgIndex() const { + return argIndex + 1; + } + + const LengthModifier &getLengthModifier() const { + return LM; + } + + const OptionalAmount &getFieldWidth() const { + return FieldWidth; + } + + void setFieldWidth(const OptionalAmount &Amt) { + FieldWidth = Amt; + } + + bool usesPositionalArg() const { return UsesPositionalArg; } + + bool hasValidLengthModifier() const; + + bool hasStandardLengthModifier() const; + + bool hasStandardConversionSpecifier(const LangOptions &LangOpt) const; + + bool hasStandardLengthConversionCombination() const; +}; + +} // end analyze_format_string namespace + +//===----------------------------------------------------------------------===// +/// Pieces specific to fprintf format strings. + +namespace analyze_printf { + +class PrintfConversionSpecifier : + public analyze_format_string::ConversionSpecifier { +public: + PrintfConversionSpecifier() + : ConversionSpecifier(true, 0, InvalidSpecifier) {} + + PrintfConversionSpecifier(const char *pos, Kind k) + : ConversionSpecifier(true, pos, k) {} + + bool isObjCArg() const { return kind >= ObjCBeg && kind <= ObjCEnd; } + bool isIntArg() const { return kind >= IntArgBeg && kind <= IntArgEnd; } + bool isDoubleArg() const { return kind >= DoubleArgBeg && + kind <= DoubleArgEnd; } + unsigned getLength() const { + // Conversion specifiers currently only are represented by + // single characters, but we be flexible. + return 1; + } + + static bool classof(const analyze_format_string::ConversionSpecifier *CS) { + return CS->isPrintfKind(); + } +}; + +using analyze_format_string::ArgTypeResult; +using analyze_format_string::LengthModifier; +using analyze_format_string::OptionalAmount; +using analyze_format_string::OptionalFlag; + +class PrintfSpecifier : public analyze_format_string::FormatSpecifier { + OptionalFlag HasThousandsGrouping; // ''', POSIX extension. + OptionalFlag IsLeftJustified; // '-' + OptionalFlag HasPlusPrefix; // '+' + OptionalFlag HasSpacePrefix; // ' ' + OptionalFlag HasAlternativeForm; // '#' + OptionalFlag HasLeadingZeroes; // '0' + OptionalAmount Precision; +public: + PrintfSpecifier() : + FormatSpecifier(/* isPrintf = */ true), + HasThousandsGrouping("'"), IsLeftJustified("-"), HasPlusPrefix("+"), + HasSpacePrefix(" "), HasAlternativeForm("#"), HasLeadingZeroes("0") {} + + static PrintfSpecifier Parse(const char *beg, const char *end); + + // Methods for incrementally constructing the PrintfSpecifier. + void setConversionSpecifier(const PrintfConversionSpecifier &cs) { + CS = cs; + } + void setHasThousandsGrouping(const char *position) { + HasThousandsGrouping = true; + HasThousandsGrouping.setPosition(position); + } + void setIsLeftJustified(const char *position) { + IsLeftJustified = true; + IsLeftJustified.setPosition(position); + } + void setHasPlusPrefix(const char *position) { + HasPlusPrefix = true; + HasPlusPrefix.setPosition(position); + } + void setHasSpacePrefix(const char *position) { + HasSpacePrefix = true; + HasSpacePrefix.setPosition(position); + } + void setHasAlternativeForm(const char *position) { + HasAlternativeForm = true; + HasAlternativeForm.setPosition(position); + } + void setHasLeadingZeros(const char *position) { + HasLeadingZeroes = true; + HasLeadingZeroes.setPosition(position); + } + void setUsesPositionalArg() { UsesPositionalArg = true; } + + // Methods for querying the format specifier. + + const PrintfConversionSpecifier &getConversionSpecifier() const { + return cast<PrintfConversionSpecifier>(CS); + } + + void setPrecision(const OptionalAmount &Amt) { + Precision = Amt; + Precision.setUsesDotPrefix(); + } + + const OptionalAmount &getPrecision() const { + return Precision; + } + + bool consumesDataArgument() const { + return getConversionSpecifier().consumesDataArgument(); + } + + /// \brief Returns the builtin type that a data argument + /// paired with this format specifier should have. This method + /// will return null if the format specifier does not have + /// a matching data argument or the matching argument matches + /// more than one type. + ArgTypeResult getArgType(ASTContext &Ctx, bool IsObjCLiteral) const; + + const OptionalFlag &hasThousandsGrouping() const { + return HasThousandsGrouping; + } + const OptionalFlag &isLeftJustified() const { return IsLeftJustified; } + const OptionalFlag &hasPlusPrefix() const { return HasPlusPrefix; } + const OptionalFlag &hasAlternativeForm() const { return HasAlternativeForm; } + const OptionalFlag &hasLeadingZeros() const { return HasLeadingZeroes; } + const OptionalFlag &hasSpacePrefix() const { return HasSpacePrefix; } + bool usesPositionalArg() const { return UsesPositionalArg; } + + /// Changes the specifier and length according to a QualType, retaining any + /// flags or options. Returns true on success, or false when a conversion + /// was not successful. + bool fixType(QualType QT, const LangOptions &LangOpt, ASTContext &Ctx, + bool IsObjCLiteral); + + void toString(raw_ostream &os) const; + + // Validation methods - to check if any element results in undefined behavior + bool hasValidPlusPrefix() const; + bool hasValidAlternativeForm() const; + bool hasValidLeadingZeros() const; + bool hasValidSpacePrefix() const; + bool hasValidLeftJustified() const; + bool hasValidThousandsGroupingPrefix() const; + + bool hasValidPrecision() const; + bool hasValidFieldWidth() const; +}; +} // end analyze_printf namespace + +//===----------------------------------------------------------------------===// +/// Pieces specific to fscanf format strings. + +namespace analyze_scanf { + +class ScanfConversionSpecifier : + public analyze_format_string::ConversionSpecifier { +public: + ScanfConversionSpecifier() + : ConversionSpecifier(false, 0, InvalidSpecifier) {} + + ScanfConversionSpecifier(const char *pos, Kind k) + : ConversionSpecifier(false, pos, k) {} + + void setEndScanList(const char *pos) { EndScanList = pos; } + + static bool classof(const analyze_format_string::ConversionSpecifier *CS) { + return !CS->isPrintfKind(); + } +}; + +using analyze_format_string::ArgTypeResult; +using analyze_format_string::LengthModifier; +using analyze_format_string::OptionalAmount; +using analyze_format_string::OptionalFlag; + +class ScanfArgTypeResult : public ArgTypeResult { +public: + enum Kind { UnknownTy, InvalidTy, CStrTy, WCStrTy, PtrToArgTypeResultTy }; +private: + Kind K; + ArgTypeResult A; + const char *Name; + QualType getRepresentativeType(ASTContext &C) const; +public: + ScanfArgTypeResult(Kind k = UnknownTy, const char* n = 0) : K(k), Name(n) {} + ScanfArgTypeResult(ArgTypeResult a, const char *n = 0) + : K(PtrToArgTypeResultTy), A(a), Name(n) { + assert(A.isValid()); + } + + static ScanfArgTypeResult Invalid() { return ScanfArgTypeResult(InvalidTy); } + + bool isValid() const { return K != InvalidTy; } + + bool matchesType(ASTContext& C, QualType argTy) const; + + std::string getRepresentativeTypeName(ASTContext& C) const; +}; + +class ScanfSpecifier : public analyze_format_string::FormatSpecifier { + OptionalFlag SuppressAssignment; // '*' +public: + ScanfSpecifier() : + FormatSpecifier(/* isPrintf = */ false), + SuppressAssignment("*") {} + + void setSuppressAssignment(const char *position) { + SuppressAssignment = true; + SuppressAssignment.setPosition(position); + } + + const OptionalFlag &getSuppressAssignment() const { + return SuppressAssignment; + } + + void setConversionSpecifier(const ScanfConversionSpecifier &cs) { + CS = cs; + } + + const ScanfConversionSpecifier &getConversionSpecifier() const { + return cast<ScanfConversionSpecifier>(CS); + } + + bool consumesDataArgument() const { + return CS.consumesDataArgument() && !SuppressAssignment; + } + + ScanfArgTypeResult getArgType(ASTContext &Ctx) const; + + bool fixType(QualType QT, const LangOptions &LangOpt, ASTContext &Ctx); + + void toString(raw_ostream &os) const; + + static ScanfSpecifier Parse(const char *beg, const char *end); +}; + +} // end analyze_scanf namespace + +//===----------------------------------------------------------------------===// +// Parsing and processing of format strings (both fprintf and fscanf). + +namespace analyze_format_string { + +enum PositionContext { FieldWidthPos = 0, PrecisionPos = 1 }; + +class FormatStringHandler { +public: + FormatStringHandler() {} + virtual ~FormatStringHandler(); + + virtual void HandleNullChar(const char *nullCharacter) {} + + virtual void HandlePosition(const char *startPos, unsigned posLen) {} + + virtual void HandleInvalidPosition(const char *startPos, unsigned posLen, + PositionContext p) {} + + virtual void HandleZeroPosition(const char *startPos, unsigned posLen) {} + + virtual void HandleIncompleteSpecifier(const char *startSpecifier, + unsigned specifierLen) {} + + // Printf-specific handlers. + + virtual bool HandleInvalidPrintfConversionSpecifier( + const analyze_printf::PrintfSpecifier &FS, + const char *startSpecifier, + unsigned specifierLen) { + return true; + } + + virtual bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS, + const char *startSpecifier, + unsigned specifierLen) { + return true; + } + + // Scanf-specific handlers. + + virtual bool HandleInvalidScanfConversionSpecifier( + const analyze_scanf::ScanfSpecifier &FS, + const char *startSpecifier, + unsigned specifierLen) { + return true; + } + + virtual bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS, + const char *startSpecifier, + unsigned specifierLen) { + return true; + } + + virtual void HandleIncompleteScanList(const char *start, const char *end) {} +}; + +bool ParsePrintfString(FormatStringHandler &H, + const char *beg, const char *end, const LangOptions &LO); + +bool ParseScanfString(FormatStringHandler &H, + const char *beg, const char *end, const LangOptions &LO); + +} // end analyze_format_string namespace +} // end clang namespace +#endif diff --git a/clang/include/clang/Analysis/Analyses/Interval.h b/clang/include/clang/Analysis/Analyses/Interval.h new file mode 100644 index 0000000..6c0d5cf --- /dev/null +++ b/clang/include/clang/Analysis/Analyses/Interval.h @@ -0,0 +1,50 @@ +//===- Interval.h - Integer Interval Analysis for Source CFGs -*- C++ --*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements Live Variables analysis for source-level CFGs. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_INTERVAL_ANALYSIS_H +#define LLVM_CLANG_INTERVAL_ANALYSIS_H + +#include "clang/Analysis/AnalysisContext.h" +#include "clang/AST/Decl.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/ImmutableSet.h" + +namespace clang { + +class CFG; +class CFGBlock; +class Stmt; +class DeclRefExpr; +class SourceManager; + +class IntervalAnalysis : public ManagedAnalysis { +public: + + IntervalAnalysis(AnalysisDeclContext &analysisContext); + virtual ~IntervalAnalysis(); + + void runOnAllBlocks(); + + static IntervalAnalysis *create(AnalysisDeclContext &analysisContext) { + return new IntervalAnalysis(analysisContext); + } + + static const void *getTag(); + +private: + AnalysisDeclContext* context; +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Analysis/Analyses/IntervalSolver/Complete.hpp b/clang/include/clang/Analysis/Analyses/IntervalSolver/Complete.hpp new file mode 100644 index 0000000..9acb9d0 --- /dev/null +++ b/clang/include/clang/Analysis/Analyses/IntervalSolver/Complete.hpp @@ -0,0 +1,125 @@ +#ifndef COMPLETE_HPP +#define COMPLETE_HPP + +#include <ostream> +#include <istream> + +template<typename T> +T infinity() { } + +template<typename T> +struct Complete { + Complete() + : _value(0), _infinity(false) { } + Complete(const T& value) + : _value(value), _infinity(false) { } + Complete(const T& value, const bool& infinity) + : _value(value), _infinity(infinity) { + assert(value != 0 || infinity == false); + } + Complete(const Complete& other) + : _value(other._value), _infinity(other._infinity) { } + + Complete& operator=(const Complete& other) { + _value = other._value; + _infinity = other._infinity; + return *this; + } + Complete& operator+=(const Complete& other) { + return (*this) = (*this) + other; + } + Complete& operator-=(const Complete& other) { + return (*this) = (*this) - other; + } + Complete& operator*=(const Complete& other) { + return (*this) = (*this) * other; + } + + Complete operator-() const { + return Complete<T>(- _value, _infinity); + } + Complete operator+(const Complete& other) const { + if (_infinity) { + return *this; + } else if (other._infinity) { + return other; + } else { + return Complete(_value + other._value, false); + } + } + Complete operator-(const Complete& other) const { + return *this + (- other); + } + Complete operator*(const Complete& other) const { + return Complete(_value * other._value, (_infinity || other._infinity)); + } + + bool operator!() const { + return _value == 0; + } + bool operator<(const Complete& other) const { + if (*this == other) + return false; + if (_infinity) { + return _value < 0; + } else if (other._infinity) { + return other._value > 0; + } else { + return _value < other._value; + } + } + bool operator>=(const Complete& other) const { + return !(*this < other); + } + bool operator>(const Complete& other) const { + return other < *this; + } + bool operator<=(const Complete& other) const { + return !(*this > other); + } + bool operator==(const Complete& other) const { + if (_infinity) { + return other._infinity && ((_value < 0 && other._value < 0) || + (_value > 0 && other._value > 0)); + } else { + return !other._infinity && (_value == other._value); + } + } + bool operator!=(const Complete& other) const { + return !(*this == other); + } + + template<typename Z> + friend std::istream& operator<<(std::istream&, Complete<Z>&); + template<typename Z> + friend std::ostream& operator<<(std::ostream&, const Complete<Z>&); + + private: + T _value; + bool _infinity; +}; + +template<typename Z> +std::istream& operator>>(std::istream& cin, Complete<Z>& num) { + Z value; + cin >> value; + num = Complete<Z>(value, false); + return cin; +} + +template<typename Z> +std::ostream& operator<<(std::ostream& cout, const Complete<Z>& num) { + if (num._infinity) { + cout << (num._value > 0 ? "inf" : "-inf"); + } else { + cout << num._value; + } + return cout; +} + +template<> +Complete<int> infinity() { + return Complete<int>(1, true); +} + +#endif diff --git a/clang/include/clang/Analysis/Analyses/IntervalSolver/EquationSystem.hpp b/clang/include/clang/Analysis/Analyses/IntervalSolver/EquationSystem.hpp new file mode 100644 index 0000000..d95366d --- /dev/null +++ b/clang/include/clang/Analysis/Analyses/IntervalSolver/EquationSystem.hpp @@ -0,0 +1,149 @@ +#ifndef EQUATION_SYSTEM_HPP +#define EQUATION_SYSTEM_HPP + +#include <vector> +#include <set> +#include <map> +#include "Operator.hpp" +#include "Expression.hpp" +#include "VariableAssignment.hpp" +#include "IdMap.hpp" + +template<typename Domain> +struct MaxStrategy; + +template<typename Domain> +struct EquationSystem { + EquationSystem() + : _expr_to_var(NULL) { } + + virtual ~EquationSystem() { + for (typename std::set<Expression<Domain>*>::iterator it = _expressions.begin(); + it != _expressions.end(); + ++it) { + delete *it; + } + for (typename std::set<Operator<Domain>*>::iterator it = _operators.begin(); + it != _operators.end(); + ++it) { + delete *it; + } + delete _expr_to_var; + } + + MaxExpression<Domain>& maxExpression(const std::vector<Expression<Domain>*>& arguments) { + unsigned int id = _max_expressions.size(); + Maximum<Domain>* max = new Maximum<Domain>(); + MaxExpression<Domain>* expr = new MaxExpression<Domain>(id, *max, arguments); + _operators.insert(max); + _max_expressions.push_back(expr); + _expressions.insert(expr); + return *expr; + } + MaxExpression<Domain>& maxExpression(unsigned int i) const { + return *_max_expressions[i]; + } + unsigned int maxExpressionCount() const { + return _max_expressions.size(); + } + + Expression<Domain>& expression(Operator<Domain>* op, const std::vector<Expression<Domain>*>& arguments) { + Expression<Domain>* expr = new OperatorExpression<Domain>(*op, arguments); + _operators.insert(op); + _expressions.insert(expr); + return *expr; + } + + Variable<Domain>& variable(const std::string& name) { + if (_variable_names.find(name) == _variable_names.end()) { + // not found - create a new variable and whatnot + unsigned int id = _variables.size(); + Variable<Domain>* var = new Variable<Domain>(id, name); + _variables.push_back(var); + _right_sides.push_back(NULL); + _expressions.insert(var); + _variable_names[name] = var; + return *var; + } else { + return *_variable_names[name]; + } + } + Variable<Domain>& variable(unsigned int id) const { + return *_variables[id]; + } + unsigned int variableCount() const { + return _variables.size(); + } + + Constant<Domain>& constant(const Domain& value) { + Constant<Domain>* constant = new Constant<Domain>(value); + _expressions.insert(constant); + return *constant; + } + + MaxExpression<Domain>* operator[](const Variable<Domain>& var) const { + return _right_sides[var.id()]; + } + MaxExpression<Domain>*& operator[](const Variable<Domain>& var) { + return _right_sides[var.id()]; + } + + void indexMaxExpressions() { + _expr_to_var = new IdMap<MaxExpression<Domain>,Variable<Domain>*>(maxExpressionCount(), NULL); + for (unsigned int i = 0, length = _right_sides.size(); i < length; ++i) { + if (_right_sides[i]) + _right_sides[i]->mapTo(*_variables[i], *_expr_to_var); + } + } + + Variable<Domain>* varFromExpr(const Expression<Domain>& expr) const { + assert(_expr_to_var != NULL); // ensure we've indexed + const MaxExpression<Domain>* maxExpr = expr.toMaxExpression();//dynamic_cast<const MaxExpression<Domain>*>(&expr); + if (maxExpr) { + return (*_expr_to_var)[*maxExpr]; + } else { + return NULL; + } + } + + virtual bool equalAssignments(const VariableAssignment<Domain>& l, const VariableAssignment<Domain>& r) const { + for (unsigned int i = 0, length = _variables.size(); + i < length; + ++i) { + const Variable<Domain>& var = *_variables[i]; + if (l[var] != r[var]) + return false; + } + return true; + } + + void print(std::ostream& cout) const { + for (unsigned int i = 0, length = _variables.size(); + i < length; + ++i) { + if (_right_sides[i]) + cout << *_variables[i] << " = " << *_right_sides[i] << std::endl; + else + cout << *_variables[i] << " = NULL" << std::endl; + } + } + + private: + std::set<Operator<Domain>*> _operators; + std::set<Expression<Domain>*> _expressions; + std::vector<Variable<Domain>*> _variables; + std::map<std::string, Variable<Domain>*> _variable_names; + IdMap<MaxExpression<Domain>, Variable<Domain>*>* _expr_to_var; + std::vector<MaxExpression<Domain>*> _max_expressions; + std::vector<MaxExpression<Domain>*> _right_sides; +}; + +template<typename T> +std::ostream& operator<<(std::ostream& cout, const EquationSystem<T>& system) { + system.print(cout); + return cout; +} + +#include "MaxStrategy.hpp" + +#endif diff --git a/clang/include/clang/Analysis/Analyses/IntervalSolver/Expression.hpp b/clang/include/clang/Analysis/Analyses/IntervalSolver/Expression.hpp new file mode 100644 index 0000000..ac9b052 --- /dev/null +++ b/clang/include/clang/Analysis/Analyses/IntervalSolver/Expression.hpp @@ -0,0 +1,203 @@ +#ifndef EXPRESSION_HPP +#define EXPRESSION_HPP + +#include <string> +#include <vector> +#include <sstream> +#include "IdMap.hpp" +#include "Operator.hpp" + +template<typename Domain> +struct VariableAssignment; + +template<typename Domain> +struct MaxStrategy; + +template<typename Domain> +struct Variable; + +template<typename Domain> +struct MaxExpression; + +template<typename Domain> +struct Expression { + virtual ~Expression() { } + + virtual const MaxExpression<Domain>* toMaxExpression() const { + return NULL; + } + + virtual Domain eval(const VariableAssignment<Domain>&) const = 0; + virtual Domain evalWithStrat(const VariableAssignment<Domain>& rho, + const MaxStrategy<Domain>&) const { + return eval(rho); + } + + virtual void mapTo(Variable<Domain>&, IdMap<MaxExpression<Domain>, Variable<Domain>*>&) const { + } + + virtual void print(std::ostream&) const = 0; +}; + +template<typename Domain> +struct Constant : public Expression<Domain> { + Constant(const Domain& value) + : _value(value) { } + + virtual Domain eval(const VariableAssignment<Domain>&) const { + return _value; + } + + void print(std::ostream& cout) const { + cout << _value; + } + + private: + Domain _value; +}; + +template<typename Domain> +struct Variable : public Expression<Domain> { + Variable(const unsigned int& id, const std::string& name) + : _id(id), _name(name) { } + + unsigned int id() const { + return _id; + } + std::string name() const { + return _name; + } + + virtual Domain eval(const VariableAssignment<Domain>& rho) const { + return rho[*this]; + } + + void print(std::ostream& cout) const { + cout << _name; + } + + private: + const unsigned int _id; + const std::string _name; +}; + +template<typename Domain> +struct OperatorExpression : public Expression<Domain> { + OperatorExpression(const Operator<Domain>& op, const std::vector<Expression<Domain>*>& arguments) + : _operator(op), _arguments(arguments) { + assert(!arguments.empty()); + } + + virtual Domain eval(const VariableAssignment<Domain>& rho) const { + std::vector<Domain> argumentValues; + for (typename std::vector<Expression<Domain>*>::const_iterator it = _arguments.begin(); + it != _arguments.end(); + ++it) { + argumentValues.push_back((*it)->eval(rho)); + } + return _operator.eval(argumentValues); + } + + virtual Domain evalWithStrat(const VariableAssignment<Domain>& rho, const MaxStrategy<Domain>& strat) const { + std::vector<Domain> argumentValues; + for (typename std::vector<Expression<Domain>*>::const_iterator it = _arguments.begin(); + it != _arguments.end(); + ++it) { + argumentValues.push_back((*it)->evalWithStrat(rho, strat)); + } + return _operator.eval(argumentValues); + } + + std::vector<Expression<Domain>*>& arguments() { + return _arguments; + } + + const std::vector<Expression<Domain>*>& arguments() const { + return _arguments; + } + + const Operator<Domain>& op() const { + return _operator; + } + + virtual void mapTo(Variable<Domain>& v, IdMap<MaxExpression<Domain>, Variable<Domain>*>& m) const { + for (unsigned int i = 0, length = _arguments.size(); + i < length; + ++i) { + _arguments[i]->mapTo(v, m); + } + } + + void print(std::ostream& cout) const { + cout << _operator << "("; + for (unsigned int i = 0, length = _arguments.size(); + i < length; + ++i) { + if (i > 0) + cout << ", "; + cout << *_arguments[i]; + } + cout << ")"; + } + + private: + const Operator<Domain>& _operator; + protected: + std::vector<Expression<Domain>*> _arguments; +}; + +template<typename Domain> +struct MaxExpression : public OperatorExpression<Domain> { + MaxExpression(const unsigned int& id, const Maximum<Domain>& op, const std::vector<Expression<Domain>*>& arguments) + : OperatorExpression<Domain>(op, arguments), _id(id) { } + + const MaxExpression* toMaxExpression() const { + return this; + } + + virtual Domain evalWithStrat(const VariableAssignment<Domain>& rho, const MaxStrategy<Domain>& strat) const { + return this->_arguments[strat.get(*this)]->evalWithStrat(rho, strat); + } + + unsigned int bestStrategy(const VariableAssignment<Domain>& rho, const MaxStrategy<Domain>& strat) const { + Domain bestValue = this->evalWithStrat(rho, strat); + unsigned int bestIndex = strat.get(*this); + + for (unsigned int i = 0, length = this->_arguments.size(); + i < length; + ++i) { + const Domain value = this->_arguments[i]->evalWithStrat(rho, strat); + if (bestValue < value) { + bestValue = value; + bestIndex = i; + } + } + return bestIndex; + } + + virtual void mapTo(Variable<Domain>& v, IdMap<MaxExpression<Domain>, Variable<Domain>*>& m) const { + m[*this] = &v; + for (unsigned int i = 0, length = this->_arguments.size(); + i < length; + ++i) { + this->_arguments[i]->mapTo(v, m); + } + } + + unsigned int id() const { + return _id; + } + + private: + const unsigned int _id; +}; + +template<typename T> +std::ostream& operator<<(std::ostream& cout, const Expression<T>& exp) { + exp.print(cout); + return cout; +} + +#include "VariableAssignment.hpp" + +#endif diff --git a/clang/include/clang/Analysis/Analyses/IntervalSolver/IdMap.hpp b/clang/include/clang/Analysis/Analyses/IntervalSolver/IdMap.hpp new file mode 100644 index 0000000..5e3aa3b --- /dev/null +++ b/clang/include/clang/Analysis/Analyses/IntervalSolver/IdMap.hpp @@ -0,0 +1,82 @@ +#ifndef ID_MAP_HPP +#define ID_MAP_HPP + +#include <ostream> + +template<typename T, typename V> +struct IdMap { + IdMap(unsigned int length, V initial) + : _length(length), _assignment(new V[length]) { + for (unsigned int i = 0; i < length; ++i) { + _assignment[i] = initial; + } + } + IdMap(const IdMap& other) + : _length(other._length), _assignment(new V[other._length]) { + for (unsigned int i = 0; i < _length; ++i) { + _assignment[i] = other._assignment[i]; + } + } + virtual ~IdMap() { + delete[] _assignment; + } + virtual IdMap& operator=(const IdMap& other) { + if (_length != other._length) { + delete[] _assignment; + _length = other._length; + _assignment = new V[_length]; + } + for (unsigned int i = 0; i < _length; ++i) { + _assignment[i] = other._assignment[i]; + } + return *this; + } + virtual const V& operator[] (const T& x) const { + if (x.id() >= _length) { + std::cout << "throw exception" << *(char*)NULL; + //throw "Array out of bounds"; + } + return _assignment[x.id()]; + } + virtual V& operator[] (const T& x) { + if (x.id() >= _length) { + std::cout << "throw exception" << *(char*)NULL; + //throw "Array out of bounds"; + } + return _assignment[x.id()]; + } + + virtual bool operator==(const IdMap& other) const { + if (_length != other._length) + return false; + for (unsigned int i = 0; i < _length; ++i) { + if (_assignment[i] != other._assignment[i]) { + return false; + } + } + return true; + } + virtual bool operator!=(const IdMap& other) const { + return !(*this == other); + } + + template<typename Q,typename Z> + friend std::ostream& operator<<(std::ostream& cout, const IdMap<Q, Z>& rho); + + protected: + unsigned int _length; + V* _assignment; +}; + +template<typename T, typename V> +std::ostream& operator<<(std::ostream& cout, const IdMap<T,V>& rho) { + cout << "{"; + for (unsigned int i = 0; i < rho._length; ++i) { + if (i != 0) cout << ", "; + cout << i << ": " << rho._assignment[i]; + } + cout << "}"; + return cout; +} + +#endif diff --git a/clang/include/clang/Analysis/Analyses/IntervalSolver/IdSet.hpp b/clang/include/clang/Analysis/Analyses/IntervalSolver/IdSet.hpp new file mode 100644 index 0000000..950b1e1 --- /dev/null +++ b/clang/include/clang/Analysis/Analyses/IntervalSolver/IdSet.hpp @@ -0,0 +1,116 @@ +#ifndef IDSET_HPP +#define IDSET_HPP + +#include <ostream> + +#define CELL_TYPE unsigned int +#define CELL_SIZE (8 * sizeof(CELL_TYPE)) +#define DIV_ROUND_UP(NUM, DEM) ((NUM + DEM - 1) / DEM) + +template<typename T> +class IdSet { + public: + IdSet() : _range(0) { } + IdSet(unsigned int length) + : _range(length) { } + + virtual ~IdSet() { + } + + IdSet(const IdSet& other) { + _range = other._range; + _set = other._set; + } + + IdSet& operator=(const IdSet& other) { + _range = other._range; + _set = other._set; + return *this; + } + + void invert() { + for (unsigned int i = 0; i < _range; ++i) { + iterator it = _set.find(i); + if (it == _set.end()) { + _set.insert(i); + } else { + _set.erase(it); + } + } + } + + IdSet inverse() const { + IdSet other(_range); + for (unsigned int i = 0; i < _range; ++i) { + if (_set.find(i) == _set.end()) { + other._set.insert(i); + } + } + return other; + } + + bool contains(const T& obj) const { + return _set.find(obj.id()) != _set.end(); + } + void insert(const T& obj) { + _set.insert(obj.id()); + } + void remove(const T& obj) { + _set.erase(obj.id()); + } + void clear() { + _set.clear(); + } + + void absorb(const IdSet& other) { + for (iterator it = other.begin(), end = other.end(); + it != end; + ++it) { + _set.insert(*it); + } + } + void filter(const IdSet& other) { + for (iterator it = other.begin(), end = other.end(); + it != end; + ++it) { + _set.erase(*it); + } + } + + bool operator==(const IdSet& other) const { + return _set == other._set; + } + bool operator!=(const IdSet& other) const { + return !(*this == other); + } + + typedef std::set<unsigned int>::const_iterator iterator; + iterator begin() const { + return _set.begin(); + } + iterator end() const { + return _set.end(); + } + + unsigned int size() const { + return _set.size(); + } + + private: + unsigned int _range; + std::set<unsigned int> _set; +}; + +template<typename T> +std::ostream& operator<<(std::ostream& cout, const IdSet<T>& set) { + cout << "{"; + for (typename IdSet<T>::iterator it = set.begin(); + it != set.end(); + ++it) { + cout << *it << ", "; + } + cout << "}"; + return cout; +} + +#endif diff --git a/clang/include/clang/Analysis/Analyses/IntervalSolver/Log.hpp b/clang/include/clang/Analysis/Analyses/IntervalSolver/Log.hpp new file mode 100644 index 0000000..f9af7f2 --- /dev/null +++ b/clang/include/clang/Analysis/Analyses/IntervalSolver/Log.hpp @@ -0,0 +1,32 @@ +#ifndef LOG_HPP +#define LOG_HPP + +#include <string> +#include <iostream> +#include <map> +#include <cstdio> + +namespace solver_log { + + struct Logger : public std::ostream { + Logger(std::streambuf*, const std::string&) + : std::ostream(NULL) { } + + bool enabled() const { + return false; + } + + bool enabled(bool) { + return false; + } + + private: + }; + + Logger strategy(std::cerr.rdbuf(), "strategy"); + Logger fixpoint(std::cerr.rdbuf(), "fixpoint"); + Logger debug(std::cerr.rdbuf(), "debug"); + +} + +#endif diff --git a/clang/include/clang/Analysis/Analyses/IntervalSolver/MaxStrategy.hpp b/clang/include/clang/Analysis/Analyses/IntervalSolver/MaxStrategy.hpp new file mode 100644 index 0000000..57dcdeb --- /dev/null +++ b/clang/include/clang/Analysis/Analyses/IntervalSolver/MaxStrategy.hpp @@ -0,0 +1,156 @@ +#ifndef MAX_EXPRESSION_HPP +#define MAX_EXPRESSION_HPP + +#include <ostream> +#include "Expression.hpp" +#include "EquationSystem.hpp" +#include "IdSet.hpp" + +template<typename Domain> +struct MaxStrategy { + virtual ~MaxStrategy() { } + virtual unsigned int get(const MaxExpression<Domain>& e) const = 0; +}; + +unsigned int stack_depth = 1; + +std::string indent() { + std::string result = ""; + for (unsigned int i = 0; i < stack_depth; ++i) { + result += '\t'; + } + return result; +} + +#include "VariableAssignment.hpp" + +template<typename Domain> +struct DynamicVariableAssignment; + +template<typename Domain> +struct DynamicMaxStrategy : public MaxStrategy<Domain> { + DynamicMaxStrategy( + const EquationSystem<Domain>& system + ) : _system(system), + _rho(NULL), + _values(system.maxExpressionCount(), 0), + _stable(system.maxExpressionCount()), + _influence(system.maxExpressionCount(), + IdSet<MaxExpression<Domain> >(system.maxExpressionCount())), + _var_influence(system.variableCount(), + IdSet<MaxExpression<Domain> >(system.maxExpressionCount())) + {} + + void setRho(DynamicVariableAssignment<Domain>& rho) { + _rho = ρ + } + + unsigned int get(const MaxExpression<Domain>& e) const { + solve(e); + return _values[e]; + } + + void invalidate(const Variable<Domain>& v) const { + solver_log::strategy << indent() << "Invalidating " << v << " - " << *_system[v] << std::endl; + _stable.filter(_var_influence[v]); + + IdSet<MaxExpression<Domain> > infl = _var_influence[v]; + _var_influence[v].clear(); + + for (typename IdSet<MaxExpression<Domain> >::iterator + it = infl.begin(), + end = infl.end(); + it != end; + ++it) { + solve(_system.maxExpression(*it)); + } + } + +private: + void solve(const MaxExpression<Domain>& x) const { + if (!_stable.contains(x)) { + _stable.insert(x); + solver_log::strategy << indent() << "Stabilise " << x << std::endl; + + stack_depth++; + unsigned int val = x.bestStrategy(DependencyAssignment(*this, *_rho, x), + DependencyStrategy(*this, x)); + stack_depth--; + + if (val != _values[x]) { + solver_log::strategy << x << " => " << *x.arguments()[val] << std::endl; + + IdSet<MaxExpression<Domain> > oldInfluence = _influence[x]; + _influence[x].clear(); + _values[x] = val; + + _rho->invalidate(*_system.varFromExpr(x)); + + _stable.filter(oldInfluence); + + for (typename IdSet<MaxExpression<Domain> >::iterator + it = oldInfluence.begin(), + end = oldInfluence.end(); + it != end; + ++it) { + solve(_system.maxExpression(*it)); + } + } else { + solver_log::strategy << indent() << x << " did not change" << std::endl; + } + } else { + solver_log::strategy << indent() << x << " is stable" << std::endl; + } + } + + struct DependencyAssignment : public VariableAssignment<Domain>{ + DependencyAssignment(const DynamicMaxStrategy& strat, + VariableAssignment<Domain>& rho, + const MaxExpression<Domain>& expr) + : _strat(strat), + _rho(rho), + _expr(expr) { + } + const Domain& operator[](const Variable<Domain>& var) const { + _strat._var_influence[var].insert(_expr); + return _rho[var]; + } + private: + const DynamicMaxStrategy& _strat; + VariableAssignment<Domain>& _rho; + const MaxExpression<Domain>& _expr; + }; + + struct DependencyStrategy : public MaxStrategy<Domain> { + DependencyStrategy(const DynamicMaxStrategy& strat, const MaxExpression<Domain>& expr) + : _strat(strat), + _expr(expr) { + } + unsigned int get(const MaxExpression<Domain>& e) const { + _strat.solve(e); + if (&_expr != &e) { + _strat._influence[e].insert(_expr); + } + return _strat._values[e]; + } + private: + const DynamicMaxStrategy& _strat; + const MaxExpression<Domain>& _expr; + }; + +private: + const EquationSystem<Domain>& _system; + mutable DynamicVariableAssignment<Domain>* _rho; + mutable IdMap<MaxExpression<Domain>,unsigned int> _values; + mutable IdSet<MaxExpression<Domain> > _stable; + mutable IdMap<MaxExpression<Domain>,IdSet<MaxExpression<Domain> > > _influence; + mutable IdMap<Variable<Domain>,IdSet<MaxExpression<Domain> > > _var_influence; +}; + +/*template<typename Domain> +std::ostream& operator<<(std::ostream& cout, const MaxStrategy<Domain>& strat) { + strat.print(cout); + return cout; +}*/ + +#endif diff --git a/clang/include/clang/Analysis/Analyses/IntervalSolver/Operator.hpp b/clang/include/clang/Analysis/Analyses/IntervalSolver/Operator.hpp new file mode 100644 index 0000000..08c66ff --- /dev/null +++ b/clang/include/clang/Analysis/Analyses/IntervalSolver/Operator.hpp @@ -0,0 +1,173 @@ +#ifndef OPERATOR_HPP +#define OPERATOR_HPP + +#include <vector> + +template<typename Domain> +struct Operator { + virtual ~Operator() { } + + virtual Domain eval(const std::vector<Domain>&) const = 0; + + virtual void print(std::ostream&) const = 0; +}; + +template<typename Domain> +struct Maximum : public Operator<Domain> { + virtual Domain eval(const std::vector<Domain>& arguments) const { + Domain result = -infinity<Domain>(); + for (typename std::vector<Domain>::const_iterator it = arguments.begin(); + it != arguments.end(); + ++it) { + result = (result < *it ? *it : result); + } + return result; + } + void print(std::ostream& cout) const { + cout << "max"; + } +}; + + +template<class T> +T minimum(const T& l, const T& r) { + return (l < r ? l : r); +} +template<typename Domain> +struct Minimum : public Operator<Domain> { + virtual Domain eval(const std::vector<Domain>& arguments) const { + Domain result = infinity<Domain>(); + for (typename std::vector<Domain>::const_iterator it = arguments.begin(); + it != arguments.end(); + ++it) { + result = minimum(*it, result); //*it < result ? *it : result); + } + return result; + } + void print(std::ostream& cout) const { + cout << "min"; + } +}; + +template<typename Domain> +struct Negation : public Operator<Domain> { + virtual Domain eval(const std::vector<Domain>& arguments) const { + if (arguments.size() > 1) + throw "Too many arguments to a negation."; + return -arguments[0]; + } + void print(std::ostream& cout) const { + cout << "-"; + } +}; + +template<typename Domain> +struct Addition : public Operator<Domain> { + virtual Domain eval(const std::vector<Domain>& arguments) const { + Domain result = 0; + for (typename std::vector<Domain>::const_iterator it = arguments.begin(); + it != arguments.end(); + ++it) { + result += *it; + } + return result; + } + void print(std::ostream& cout) const { + cout << "add"; + } +}; + +template<typename Domain> +struct Subtraction : public Operator<Domain> { + virtual Domain eval(const std::vector<Domain>& arguments) const { + Domain result = 0; + for (typename std::vector<Domain>::const_iterator it = arguments.begin(); + it != arguments.end(); + ++it) { + if (it == arguments.begin()) + result = *it; + else + result -= *it; + } + return result; + } + void print(std::ostream& cout) const { + cout << "sub"; + } +}; + +template<typename Domain> +struct Multiplication : public Operator<Domain> { + virtual Domain eval(const std::vector<Domain>& arguments) const { + Domain result = 1; + for (typename std::vector<Domain>::const_iterator it = arguments.begin(), + end = arguments.end(); + it != end; + ++it) { + result *= *it; + } + return result; + } + void print(std::ostream& cout) const { + cout << "mult"; + } +}; + +template<typename Domain> +struct Comma : public Operator<Domain> { + virtual Domain eval(const std::vector<Domain>& arguments) const { + if (arguments[0] == -infinity<Domain>()) { + return -infinity<Domain>(); + } + return arguments[1]; + } + void print(std::ostream& cout) const { + cout << "comma"; + } +}; + +template<typename Domain> +struct Guard : public Operator<Domain> { + virtual Domain eval(const std::vector<Domain>& arguments) const { + Domain result = arguments[2]; + if (arguments[0] < arguments[1]) { + result = -infinity<Domain>(); + } + return result; + } + void print(std::ostream& cout) const { + cout << "guard"; + } +}; + +/*#include "TemplateConstraintMatrix.hpp" + +template<typename Domain> +struct MinimumCostFlow : public Operator<Domain> { + MinimumCostFlow() { + } + Domain solve(const Domain& d) const { + + } + virtual Domain eval(const std::vector<Domain>& arguments) const { + if (arguments.size() != 1) + throw "Incorrect number of arguments."; + return solve(arguments[0]); + } + void print(std::ostream& cout) const { + cout << "minCostFlow"; + } +private: + TemplateConstraintMatrix& constraint; // T + std::vector<Domain> guard; // c + std::vector<std::vector<Domain>> multiplication; //A + unsigned int row; +};*/ + +template<typename T> +std::ostream& operator<<(std::ostream& cout, const Operator<T>& op) { + op.print(cout); + return cout; +} + +#endif diff --git a/clang/include/clang/Analysis/Analyses/IntervalSolver/VariableAssignment.hpp b/clang/include/clang/Analysis/Analyses/IntervalSolver/VariableAssignment.hpp new file mode 100644 index 0000000..ba5f650 --- /dev/null +++ b/clang/include/clang/Analysis/Analyses/IntervalSolver/VariableAssignment.hpp @@ -0,0 +1,104 @@ +#ifndef VARIABLE_ASSIGNMENT_HPP +#define VARIABLE_ASSIGNMENT_HPP + +#include "Expression.hpp" +#include "IdMap.hpp" + +template<typename Domain> +struct VariableAssignment { + virtual ~VariableAssignment() { } + virtual const Domain& operator[](const Variable<Domain>&) const = 0; +}; + +#include "EquationSystem.hpp" + +template<typename Domain> +struct DynamicMaxStrategy; + +template<typename Domain> +struct DynamicVariableAssignment : public VariableAssignment<Domain> { + DynamicVariableAssignment( + const EquationSystem<Domain>& system, + const DynamicMaxStrategy<Domain>& strat + ) : _system(system), + _strategy(strat), + _values(system.variableCount(), infinity<Domain>()), + _stable(system.variableCount()), + _influence(system.variableCount(), + IdSet<Variable<Domain> >(system.variableCount())) + { } + + const Domain& operator[](const Variable<Domain>& var) const { + solve(var); + return _values[var]; + } + + void invalidate(const Variable<Domain>& x) const { + solver_log::fixpoint << indent() << "Invalidating " << x << std::endl; + if (_stable.contains(x)) { + _stable.remove(x); + _values[x] = infinity<Domain>(); + + solve(x); + } + } + +private: + + void solve(const Variable<Domain>& x) const { + if (!_stable.contains(x)) { + _stable.insert(x); + solver_log::fixpoint << indent() << "Stabilise " << x << std::endl; + + stack_depth++; + if (!_system[x]) + return; + Domain val = _system[x]->evalWithStrat(DependencyAssignment(*this, x), + _strategy); + stack_depth--; + + if (val != _values[x]) { + solver_log::fixpoint << x << " = " << val << std::endl; + + IdSet<Variable<Domain> > oldInfluence = _influence[x]; + _influence[x].clear(); + _values[x] = val; + + _strategy.invalidate(x); + + _stable.filter(oldInfluence); + + for (typename IdSet<Variable<Domain> >::iterator it = oldInfluence.begin(); + it != oldInfluence.end(); + ++it) { + solve(_system.variable(*it)); + } + } else { + solver_log::fixpoint << indent() << x << " did not change" << std::endl; + } + } else { + solver_log::fixpoint << indent() << x << " is stable" << std::endl; + } + } + + struct DependencyAssignment : public VariableAssignment<Domain> { + DependencyAssignment(const DynamicVariableAssignment& assignment, const Variable<Domain>& var) + : _assignment(assignment), _var(var) { } + const Domain& operator[](const Variable<Domain>& x) const { + const Domain& result = _assignment[x]; + _assignment._influence[x].insert(_var); + return result; + } + private: + const DynamicVariableAssignment& _assignment; + const Variable<Domain>& _var; + }; + + const EquationSystem<Domain>& _system; + const DynamicMaxStrategy<Domain>& _strategy; + mutable IdMap<Variable<Domain>, Domain> _values; + mutable IdSet<Variable<Domain> > _stable; + mutable IdMap<Variable<Domain>,IdSet<Variable<Domain> > > _influence; +}; + +#endif diff --git a/clang/include/clang/Analysis/Analyses/LiveVariables.h b/clang/include/clang/Analysis/Analyses/LiveVariables.h new file mode 100644 index 0000000..c9f39b4 --- /dev/null +++ b/clang/include/clang/Analysis/Analyses/LiveVariables.h @@ -0,0 +1,120 @@ +//===- LiveVariables.h - Live Variable Analysis for Source CFGs -*- C++ --*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements Live Variables analysis for source-level CFGs. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIVEVARIABLES_H +#define LLVM_CLANG_LIVEVARIABLES_H + +#include "clang/Analysis/AnalysisContext.h" +#include "clang/AST/Decl.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/ImmutableSet.h" + +namespace clang { + +class CFG; +class CFGBlock; +class Stmt; +class DeclRefExpr; +class SourceManager; + +class LiveVariables : public ManagedAnalysis { +public: + class LivenessValues { + public: + + llvm::ImmutableSet<const Stmt *> liveStmts; + llvm::ImmutableSet<const VarDecl *> liveDecls; + + bool equals(const LivenessValues &V) const; + + LivenessValues() + : liveStmts(0), liveDecls(0) {} + + LivenessValues(llvm::ImmutableSet<const Stmt *> LiveStmts, + llvm::ImmutableSet<const VarDecl *> LiveDecls) + : liveStmts(LiveStmts), liveDecls(LiveDecls) {} + + ~LivenessValues() {} + + bool isLive(const Stmt *S) const; + bool isLive(const VarDecl *D) const; + + friend class LiveVariables; + }; + + class Observer { + virtual void anchor(); + public: + virtual ~Observer() {} + + /// A callback invoked right before invoking the + /// liveness transfer function on the given statement. + virtual void observeStmt(const Stmt *S, + const CFGBlock *currentBlock, + const LivenessValues& V) {} + + /// Called when the live variables analysis registers + /// that a variable is killed. + virtual void observerKill(const DeclRefExpr *DR) {} + }; + + + virtual ~LiveVariables(); + + /// Compute the liveness information for a given CFG. + static LiveVariables *computeLiveness(AnalysisDeclContext &analysisContext, + bool killAtAssign); + + /// Return true if a variable is live at the end of a + /// specified block. + bool isLive(const CFGBlock *B, const VarDecl *D); + + /// Returns true if a variable is live at the beginning of the + /// the statement. This query only works if liveness information + /// has been recorded at the statement level (see runOnAllBlocks), and + /// only returns liveness information for block-level expressions. + bool isLive(const Stmt *S, const VarDecl *D); + + /// Returns true the block-level expression "value" is live + /// before the given block-level expression (see runOnAllBlocks). + bool isLive(const Stmt *Loc, const Stmt *StmtVal); + + /// Print to stderr the liveness information associated with + /// each basic block. + void dumpBlockLiveness(const SourceManager& M); + + void runOnAllBlocks(Observer &obs); + + static LiveVariables *create(AnalysisDeclContext &analysisContext) { + return computeLiveness(analysisContext, true); + } + + static const void *getTag(); + +private: + LiveVariables(void *impl); + void *impl; +}; + +class RelaxedLiveVariables : public LiveVariables { +public: + static LiveVariables *create(AnalysisDeclContext &analysisContext) { + return computeLiveness(analysisContext, false); + } + + static const void *getTag(); +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Analysis/Analyses/PostOrderCFGView.h b/clang/include/clang/Analysis/Analyses/PostOrderCFGView.h new file mode 100644 index 0000000..4e3244e --- /dev/null +++ b/clang/include/clang/Analysis/Analyses/PostOrderCFGView.h @@ -0,0 +1,111 @@ +//===- PostOrderCFGView.h - Post order view of CFG blocks ---------*- C++ --*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements post order view of the blocks in a CFG. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_POSTORDER_CFGVIEW +#define LLVM_CLANG_POSTORDER_CFGVIEW + +#include <vector> +//#include <algorithm> + +#include "llvm/ADT/PostOrderIterator.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/BitVector.h" + +#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/CFG.h" + +namespace clang { + +class PostOrderCFGView : public ManagedAnalysis { + virtual void anchor(); +public: + /// \brief Implements a set of CFGBlocks using a BitVector. + /// + /// This class contains a minimal interface, primarily dictated by the SetType + /// template parameter of the llvm::po_iterator template, as used with + /// external storage. We also use this set to keep track of which CFGBlocks we + /// visit during the analysis. + class CFGBlockSet { + llvm::BitVector VisitedBlockIDs; + public: + // po_iterator requires this iterator, but the only interface needed is the + // value_type typedef. + struct iterator { typedef const CFGBlock *value_type; }; + + CFGBlockSet() {} + CFGBlockSet(const CFG *G) : VisitedBlockIDs(G->getNumBlockIDs(), false) {} + + /// \brief Set the bit associated with a particular CFGBlock. + /// This is the important method for the SetType template parameter. + bool insert(const CFGBlock *Block) { + // Note that insert() is called by po_iterator, which doesn't check to + // make sure that Block is non-null. Moreover, the CFGBlock iterator will + // occasionally hand out null pointers for pruned edges, so we catch those + // here. + if (Block == 0) + return false; // if an edge is trivially false. + if (VisitedBlockIDs.test(Block->getBlockID())) + return false; + VisitedBlockIDs.set(Block->getBlockID()); + return true; + } + + /// \brief Check if the bit for a CFGBlock has been already set. + /// This method is for tracking visited blocks in the main threadsafety + /// loop. Block must not be null. + bool alreadySet(const CFGBlock *Block) { + return VisitedBlockIDs.test(Block->getBlockID()); + } + }; + +private: + typedef llvm::po_iterator<const CFG*, CFGBlockSet, true> po_iterator; + std::vector<const CFGBlock*> Blocks; + + typedef llvm::DenseMap<const CFGBlock *, unsigned> BlockOrderTy; + BlockOrderTy BlockOrder; + +public: + typedef std::vector<const CFGBlock*>::reverse_iterator iterator; + + PostOrderCFGView(const CFG *cfg); + + iterator begin() { return Blocks.rbegin(); } + iterator end() { return Blocks.rend(); } + + bool empty() { return begin() == end(); } + + struct BlockOrderCompare; + friend struct BlockOrderCompare; + + struct BlockOrderCompare { + const PostOrderCFGView &POV; + public: + BlockOrderCompare(const PostOrderCFGView &pov) : POV(pov) {} + bool operator()(const CFGBlock *b1, const CFGBlock *b2) const; + }; + + BlockOrderCompare getComparator() const { + return BlockOrderCompare(*this); + } + + // Used by AnalyisContext to construct this object. + static const void *getTag(); + + static PostOrderCFGView *create(AnalysisDeclContext &analysisContext); +}; + +} // end clang namespace + +#endif + diff --git a/clang/include/clang/Analysis/Analyses/PseudoConstantAnalysis.h b/clang/include/clang/Analysis/Analyses/PseudoConstantAnalysis.h new file mode 100644 index 0000000..cb73850 --- /dev/null +++ b/clang/include/clang/Analysis/Analyses/PseudoConstantAnalysis.h @@ -0,0 +1,45 @@ +//== PseudoConstantAnalysis.h - Find Pseudo-constants in the AST -*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file tracks the usage of variables in a Decl body to see if they are +// never written to, implying that they constant. This is useful in static +// analysis to see if a developer might have intended a variable to be const. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_PSEUDOCONSTANTANALYSIS +#define LLVM_CLANG_ANALYSIS_PSEUDOCONSTANTANALYSIS + +#include "clang/AST/Stmt.h" + +namespace clang { + +class PseudoConstantAnalysis { +public: + PseudoConstantAnalysis(const Stmt *DeclBody); + ~PseudoConstantAnalysis(); + + bool isPseudoConstant(const VarDecl *VD); + bool wasReferenced(const VarDecl *VD); + +private: + void RunAnalysis(); + inline static const Decl *getDecl(const Expr *E); + + // for storing the result of analyzed ValueDecls + void *NonConstantsImpl; + void *UsedVarsImpl; + + const Stmt *DeclBody; + bool Analyzed; +}; + +} + +#endif diff --git a/clang/include/clang/Analysis/Analyses/ReachableCode.h b/clang/include/clang/Analysis/Analyses/ReachableCode.h new file mode 100644 index 0000000..30c5b2d --- /dev/null +++ b/clang/include/clang/Analysis/Analyses/ReachableCode.h @@ -0,0 +1,56 @@ +//===- ReachableCode.h -----------------------------------------*- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// A flow-sensitive, path-insensitive analysis of unreachable code. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_REACHABLECODE_H +#define LLVM_CLANG_REACHABLECODE_H + +#include "clang/Basic/SourceLocation.h" + +//===----------------------------------------------------------------------===// +// Forward declarations. +//===----------------------------------------------------------------------===// + +namespace llvm { + class BitVector; +} + +namespace clang { + class AnalysisDeclContext; + class CFGBlock; +} + +//===----------------------------------------------------------------------===// +// API. +//===----------------------------------------------------------------------===// + +namespace clang { +namespace reachable_code { + +class Callback { + virtual void anchor(); +public: + virtual ~Callback() {} + virtual void HandleUnreachable(SourceLocation L, SourceRange R1, + SourceRange R2) = 0; +}; + +/// ScanReachableFromBlock - Mark all blocks reachable from Start. +/// Returns the total number of blocks that were marked reachable. +unsigned ScanReachableFromBlock(const CFGBlock *Start, + llvm::BitVector &Reachable); + +void FindUnreachableCode(AnalysisDeclContext &AC, Callback &CB); + +}} // end namespace clang::reachable_code + +#endif diff --git a/clang/include/clang/Analysis/Analyses/ThreadSafety.h b/clang/include/clang/Analysis/Analyses/ThreadSafety.h new file mode 100644 index 0000000..26e258d --- /dev/null +++ b/clang/include/clang/Analysis/Analyses/ThreadSafety.h @@ -0,0 +1,159 @@ +//===- ThreadSafety.h ------------------------------------------*- C++ --*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// +// A intra-procedural analysis for thread safety (e.g. deadlocks and race +// conditions), based off of an annotation system. +// +// See http://clang.llvm.org/docs/LanguageExtensions.html#threadsafety for more +// information. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_THREADSAFETY_H +#define LLVM_CLANG_THREADSAFETY_H + +#include "clang/Analysis/AnalysisContext.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/StringRef.h" + +namespace clang { +namespace thread_safety { + +/// This enum distinguishes between different kinds of operations that may +/// need to be protected by locks. We use this enum in error handling. +enum ProtectedOperationKind { + POK_VarDereference, /// Dereferencing a variable (e.g. p in *p = 5;) + POK_VarAccess, /// Reading or writing a variable (e.g. x in x = 5;) + POK_FunctionCall /// Making a function call (e.g. fool()) +}; + +/// This enum distinguishes between different kinds of lock actions. For +/// example, it is an error to write a variable protected by shared version of a +/// mutex. +enum LockKind { + LK_Shared, /// Shared/reader lock of a mutex + LK_Exclusive /// Exclusive/writer lock of a mutex +}; + +/// This enum distinguishes between different ways to access (read or write) a +/// variable. +enum AccessKind { + AK_Read, /// Reading a variable + AK_Written /// Writing a variable +}; + +/// This enum distinguishes between different situations where we warn due to +/// inconsistent locking. +/// \enum SK_LockedSomeLoopIterations -- a mutex is locked for some but not all +/// loop iterations. +/// \enum SK_LockedSomePredecessors -- a mutex is locked in some but not all +/// predecessors of a CFGBlock. +/// \enum SK_LockedAtEndOfFunction -- a mutex is still locked at the end of a +/// function. +enum LockErrorKind { + LEK_LockedSomeLoopIterations, + LEK_LockedSomePredecessors, + LEK_LockedAtEndOfFunction +}; + +/// Handler class for thread safety warnings. +class ThreadSafetyHandler { +public: + typedef llvm::StringRef Name; + virtual ~ThreadSafetyHandler(); + + /// Warn about lock expressions which fail to resolve to lockable objects. + /// \param Loc -- the SourceLocation of the unresolved expression. + virtual void handleInvalidLockExp(SourceLocation Loc) {} + + /// Warn about unlock function calls that do not have a prior matching lock + /// expression. + /// \param LockName -- A StringRef name for the lock expression, to be printed + /// in the error message. + /// \param Loc -- The SourceLocation of the Unlock + virtual void handleUnmatchedUnlock(Name LockName, SourceLocation Loc) {} + + /// Warn about lock function calls for locks which are already held. + /// \param LockName -- A StringRef name for the lock expression, to be printed + /// in the error message. + /// \param Loc -- The location of the second lock expression. + virtual void handleDoubleLock(Name LockName, SourceLocation Loc) {} + + /// Warn about situations where a mutex is sometimes held and sometimes not. + /// The three situations are: + /// 1. a mutex is locked on an "if" branch but not the "else" branch, + /// 2, or a mutex is only held at the start of some loop iterations, + /// 3. or when a mutex is locked but not unlocked inside a function. + /// \param LockName -- A StringRef name for the lock expression, to be printed + /// in the error message. + /// \param LocLocked -- The location of the lock expression where the mutex is + /// locked + /// \param LocEndOfScope -- The location of the end of the scope where the + /// mutex is no longer held + /// \param LEK -- which of the three above cases we should warn for + virtual void handleMutexHeldEndOfScope(Name LockName, + SourceLocation LocLocked, + SourceLocation LocEndOfScope, + LockErrorKind LEK){} + + /// Warn when a mutex is held exclusively and shared at the same point. For + /// example, if a mutex is locked exclusively during an if branch and shared + /// during the else branch. + /// \param LockName -- A StringRef name for the lock expression, to be printed + /// in the error message. + /// \param Loc1 -- The location of the first lock expression. + /// \param Loc2 -- The location of the second lock expression. + virtual void handleExclusiveAndShared(Name LockName, SourceLocation Loc1, + SourceLocation Loc2) {} + + /// Warn when a protected operation occurs while no locks are held. + /// \param D -- The decl for the protected variable or function + /// \param POK -- The kind of protected operation (e.g. variable access) + /// \param AK -- The kind of access (i.e. read or write) that occurred + /// \param Loc -- The location of the protected operation. + virtual void handleNoMutexHeld(const NamedDecl *D, ProtectedOperationKind POK, + AccessKind AK, SourceLocation Loc) {} + + /// Warn when a protected operation occurs while the specific mutex protecting + /// the operation is not locked. + /// \param LockName -- A StringRef name for the lock expression, to be printed + /// in the error message. + /// \param D -- The decl for the protected variable or function + /// \param POK -- The kind of protected operation (e.g. variable access) + /// \param AK -- The kind of access (i.e. read or write) that occurred + /// \param Loc -- The location of the protected operation. + virtual void handleMutexNotHeld(const NamedDecl *D, + ProtectedOperationKind POK, Name LockName, + LockKind LK, SourceLocation Loc) {} + + /// Warn when a function is called while an excluded mutex is locked. For + /// example, the mutex may be locked inside the function. + /// \param FunName -- The name of the function + /// \param LockName -- A StringRef name for the lock expression, to be printed + /// in the error message. + /// \param Loc -- The location of the function call. + virtual void handleFunExcludesLock(Name FunName, Name LockName, + SourceLocation Loc) {} +}; + +/// \brief Check a function's CFG for thread-safety violations. +/// +/// We traverse the blocks in the CFG, compute the set of mutexes that are held +/// at the end of each block, and issue warnings for thread safety violations. +/// Each block in the CFG is traversed exactly once. +void runThreadSafetyAnalysis(AnalysisDeclContext &AC, + ThreadSafetyHandler &Handler); + +/// \brief Helper function that returns a LockKind required for the given level +/// of access. +LockKind getLockKindFromAccessKind(AccessKind AK); + +}} // end namespace clang::thread_safety +#endif diff --git a/clang/include/clang/Analysis/Analyses/UninitializedValues.h b/clang/include/clang/Analysis/Analyses/UninitializedValues.h new file mode 100644 index 0000000..4ee6698 --- /dev/null +++ b/clang/include/clang/Analysis/Analyses/UninitializedValues.h @@ -0,0 +1,53 @@ +//= UninitializedValues.h - Finding uses of uninitialized values -*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines APIs for invoking and reported uninitialized values +// warnings. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_UNINIT_VALS_H +#define LLVM_CLANG_UNINIT_VALS_H + +namespace clang { + +class AnalysisDeclContext; +class CFG; +class DeclContext; +class Expr; +class VarDecl; + +class UninitVariablesHandler { +public: + UninitVariablesHandler() {} + virtual ~UninitVariablesHandler(); + + /// Called when the uninitialized variable is used at the given expression. + virtual void handleUseOfUninitVariable(const Expr *ex, + const VarDecl *vd, + bool isAlwaysUninit) {} + + /// Called when the uninitialized variable analysis detects the + /// idiom 'int x = x'. All other uses of 'x' within the initializer + /// are handled by handleUseOfUninitVariable. + virtual void handleSelfInit(const VarDecl *vd) {} +}; + +struct UninitVariablesAnalysisStats { + unsigned NumVariablesAnalyzed; + unsigned NumBlockVisits; +}; + +void runUninitializedVariablesAnalysis(const DeclContext &dc, const CFG &cfg, + AnalysisDeclContext &ac, + UninitVariablesHandler &handler, + UninitVariablesAnalysisStats &stats); + +} +#endif diff --git a/clang/include/clang/Analysis/AnalysisContext.h b/clang/include/clang/Analysis/AnalysisContext.h new file mode 100644 index 0000000..6b6f8ef --- /dev/null +++ b/clang/include/clang/Analysis/AnalysisContext.h @@ -0,0 +1,432 @@ +//=== AnalysisContext.h - Analysis context for Path Sens analysis --*- C++ -*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines AnalysisDeclContext, a class that manages the analysis +// context data for path sensitive analysis. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_ANALYSISCONTEXT_H +#define LLVM_CLANG_ANALYSIS_ANALYSISCONTEXT_H + +#include "clang/AST/Decl.h" +#include "clang/AST/Expr.h" +#include "clang/Analysis/CFG.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/Support/Allocator.h" + +namespace clang { + +class Decl; +class Stmt; +class CFGReverseBlockReachabilityAnalysis; +class CFGStmtMap; +class LiveVariables; +class ManagedAnalysis; +class ParentMap; +class PseudoConstantAnalysis; +class ImplicitParamDecl; +class LocationContextManager; +class StackFrameContext; +class AnalysisDeclContextManager; +class LocationContext; + +namespace idx { class TranslationUnit; } + +/// The base class of a hierarchy of objects representing analyses tied +/// to AnalysisDeclContext. +class ManagedAnalysis { +protected: + ManagedAnalysis() {} +public: + virtual ~ManagedAnalysis(); + + // Subclasses need to implement: + // + // static const void *getTag(); + // + // Which returns a fixed pointer address to distinguish classes of + // analysis objects. They also need to implement: + // + // static [Derived*] create(AnalysisDeclContext &Ctx); + // + // which creates the analysis object given an AnalysisDeclContext. +}; + + +/// AnalysisDeclContext contains the context data for the function or method +/// under analysis. +class AnalysisDeclContext { + /// Backpoint to the AnalysisManager object that created this + /// AnalysisDeclContext. This may be null. + AnalysisDeclContextManager *Manager; + + const Decl *D; + + // TranslationUnit is NULL if we don't have multiple translation units. + idx::TranslationUnit *TU; + + OwningPtr<CFG> cfg, completeCFG; + OwningPtr<CFGStmtMap> cfgStmtMap; + + CFG::BuildOptions cfgBuildOptions; + CFG::BuildOptions::ForcedBlkExprs *forcedBlkExprs; + + bool builtCFG, builtCompleteCFG; + + OwningPtr<LiveVariables> liveness; + OwningPtr<LiveVariables> relaxedLiveness; + OwningPtr<ParentMap> PM; + OwningPtr<PseudoConstantAnalysis> PCA; + OwningPtr<CFGReverseBlockReachabilityAnalysis> CFA; + + llvm::BumpPtrAllocator A; + + llvm::DenseMap<const BlockDecl*,void*> *ReferencedBlockVars; + + void *ManagedAnalyses; + +public: + AnalysisDeclContext(AnalysisDeclContextManager *Mgr, + const Decl *D, + idx::TranslationUnit *TU); + + AnalysisDeclContext(AnalysisDeclContextManager *Mgr, + const Decl *D, + idx::TranslationUnit *TU, + const CFG::BuildOptions &BuildOptions); + + ~AnalysisDeclContext(); + + ASTContext &getASTContext() { return D->getASTContext(); } + const Decl *getDecl() const { return D; } + + idx::TranslationUnit *getTranslationUnit() const { return TU; } + + /// Return the build options used to construct the CFG. + CFG::BuildOptions &getCFGBuildOptions() { + return cfgBuildOptions; + } + + const CFG::BuildOptions &getCFGBuildOptions() const { + return cfgBuildOptions; + } + + /// getAddEHEdges - Return true iff we are adding exceptional edges from + /// callExprs. If this is false, then try/catch statements and blocks + /// reachable from them can appear to be dead in the CFG, analysis passes must + /// cope with that. + bool getAddEHEdges() const { return cfgBuildOptions.AddEHEdges; } + bool getUseUnoptimizedCFG() const { + return !cfgBuildOptions.PruneTriviallyFalseEdges; + } + bool getAddImplicitDtors() const { return cfgBuildOptions.AddImplicitDtors; } + bool getAddInitializers() const { return cfgBuildOptions.AddInitializers; } + + void registerForcedBlockExpression(const Stmt *stmt); + const CFGBlock *getBlockForRegisteredExpression(const Stmt *stmt); + + Stmt *getBody() const; + CFG *getCFG(); + + CFGStmtMap *getCFGStmtMap(); + + CFGReverseBlockReachabilityAnalysis *getCFGReachablityAnalysis(); + + /// Return a version of the CFG without any edges pruned. + CFG *getUnoptimizedCFG(); + + void dumpCFG(bool ShowColors); + + /// \brief Returns true if we have built a CFG for this analysis context. + /// Note that this doesn't correspond to whether or not a valid CFG exists, it + /// corresponds to whether we *attempted* to build one. + bool isCFGBuilt() const { return builtCFG; } + + ParentMap &getParentMap(); + PseudoConstantAnalysis *getPseudoConstantAnalysis(); + + typedef const VarDecl * const * referenced_decls_iterator; + + std::pair<referenced_decls_iterator, referenced_decls_iterator> + getReferencedBlockVars(const BlockDecl *BD); + + /// Return the ImplicitParamDecl* associated with 'self' if this + /// AnalysisDeclContext wraps an ObjCMethodDecl. Returns NULL otherwise. + const ImplicitParamDecl *getSelfDecl() const; + + const StackFrameContext *getStackFrame(LocationContext const *Parent, + const Stmt *S, + const CFGBlock *Blk, + unsigned Idx); + + /// Return the specified analysis object, lazily running the analysis if + /// necessary. Return NULL if the analysis could not run. + template <typename T> + T *getAnalysis() { + const void *tag = T::getTag(); + ManagedAnalysis *&data = getAnalysisImpl(tag); + if (!data) { + data = T::create(*this); + } + return static_cast<T*>(data); + } +private: + ManagedAnalysis *&getAnalysisImpl(const void* tag); + + LocationContextManager &getLocationContextManager(); +}; + +class LocationContext : public llvm::FoldingSetNode { +public: + enum ContextKind { StackFrame, Scope, Block }; + +private: + ContextKind Kind; + + // AnalysisDeclContext can't be const since some methods may modify its + // member. + AnalysisDeclContext *Ctx; + + const LocationContext *Parent; + +protected: + LocationContext(ContextKind k, AnalysisDeclContext *ctx, + const LocationContext *parent) + : Kind(k), Ctx(ctx), Parent(parent) {} + +public: + virtual ~LocationContext(); + + ContextKind getKind() const { return Kind; } + + AnalysisDeclContext *getAnalysisDeclContext() const { return Ctx; } + + idx::TranslationUnit *getTranslationUnit() const { + return Ctx->getTranslationUnit(); + } + + const LocationContext *getParent() const { return Parent; } + + bool isParentOf(const LocationContext *LC) const; + + const Decl *getDecl() const { return getAnalysisDeclContext()->getDecl(); } + + CFG *getCFG() const { return getAnalysisDeclContext()->getCFG(); } + + template <typename T> + T *getAnalysis() const { + return getAnalysisDeclContext()->getAnalysis<T>(); + } + + ParentMap &getParentMap() const { + return getAnalysisDeclContext()->getParentMap(); + } + + const ImplicitParamDecl *getSelfDecl() const { + return Ctx->getSelfDecl(); + } + + const StackFrameContext *getCurrentStackFrame() const; + const StackFrameContext * + getStackFrameForDeclContext(const DeclContext *DC) const; + + virtual void Profile(llvm::FoldingSetNodeID &ID) = 0; + + static bool classof(const LocationContext*) { return true; } + +public: + static void ProfileCommon(llvm::FoldingSetNodeID &ID, + ContextKind ck, + AnalysisDeclContext *ctx, + const LocationContext *parent, + const void *data); +}; + +class StackFrameContext : public LocationContext { + // The callsite where this stack frame is established. + const Stmt *CallSite; + + // The parent block of the callsite. + const CFGBlock *Block; + + // The index of the callsite in the CFGBlock. + unsigned Index; + + friend class LocationContextManager; + StackFrameContext(AnalysisDeclContext *ctx, const LocationContext *parent, + const Stmt *s, const CFGBlock *blk, + unsigned idx) + : LocationContext(StackFrame, ctx, parent), CallSite(s), + Block(blk), Index(idx) {} + +public: + ~StackFrameContext() {} + + const Stmt *getCallSite() const { return CallSite; } + + const CFGBlock *getCallSiteBlock() const { return Block; } + + unsigned getIndex() const { return Index; } + + void Profile(llvm::FoldingSetNodeID &ID); + + static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ctx, + const LocationContext *parent, const Stmt *s, + const CFGBlock *blk, unsigned idx) { + ProfileCommon(ID, StackFrame, ctx, parent, s); + ID.AddPointer(blk); + ID.AddInteger(idx); + } + + static bool classof(const LocationContext *Ctx) { + return Ctx->getKind() == StackFrame; + } +}; + +class ScopeContext : public LocationContext { + const Stmt *Enter; + + friend class LocationContextManager; + ScopeContext(AnalysisDeclContext *ctx, const LocationContext *parent, + const Stmt *s) + : LocationContext(Scope, ctx, parent), Enter(s) {} + +public: + ~ScopeContext() {} + + void Profile(llvm::FoldingSetNodeID &ID); + + static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ctx, + const LocationContext *parent, const Stmt *s) { + ProfileCommon(ID, Scope, ctx, parent, s); + } + + static bool classof(const LocationContext *Ctx) { + return Ctx->getKind() == Scope; + } +}; + +class BlockInvocationContext : public LocationContext { + // FIXME: Add back context-sensivity (we don't want libAnalysis to know + // about MemRegion). + const BlockDecl *BD; + + friend class LocationContextManager; + + BlockInvocationContext(AnalysisDeclContext *ctx, + const LocationContext *parent, + const BlockDecl *bd) + : LocationContext(Block, ctx, parent), BD(bd) {} + +public: + ~BlockInvocationContext() {} + + const BlockDecl *getBlockDecl() const { return BD; } + + void Profile(llvm::FoldingSetNodeID &ID); + + static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ctx, + const LocationContext *parent, const BlockDecl *bd) { + ProfileCommon(ID, Block, ctx, parent, bd); + } + + static bool classof(const LocationContext *Ctx) { + return Ctx->getKind() == Block; + } +}; + +class LocationContextManager { + llvm::FoldingSet<LocationContext> Contexts; +public: + ~LocationContextManager(); + + const StackFrameContext *getStackFrame(AnalysisDeclContext *ctx, + const LocationContext *parent, + const Stmt *s, + const CFGBlock *blk, unsigned idx); + + const ScopeContext *getScope(AnalysisDeclContext *ctx, + const LocationContext *parent, + const Stmt *s); + + /// Discard all previously created LocationContext objects. + void clear(); +private: + template <typename LOC, typename DATA> + const LOC *getLocationContext(AnalysisDeclContext *ctx, + const LocationContext *parent, + const DATA *d); +}; + +class AnalysisDeclContextManager { + typedef llvm::DenseMap<const Decl*, AnalysisDeclContext*> ContextMap; + + ContextMap Contexts; + LocationContextManager LocContexts; + CFG::BuildOptions cfgBuildOptions; + +public: + AnalysisDeclContextManager(bool useUnoptimizedCFG = false, + bool addImplicitDtors = false, + bool addInitializers = false); + + ~AnalysisDeclContextManager(); + + AnalysisDeclContext *getContext(const Decl *D, idx::TranslationUnit *TU = 0); + + bool getUseUnoptimizedCFG() const { + return !cfgBuildOptions.PruneTriviallyFalseEdges; + } + + CFG::BuildOptions &getCFGBuildOptions() { + return cfgBuildOptions; + } + + const StackFrameContext *getStackFrame(AnalysisDeclContext *Ctx, + LocationContext const *Parent, + const Stmt *S, + const CFGBlock *Blk, + unsigned Idx) { + return LocContexts.getStackFrame(Ctx, Parent, S, Blk, Idx); + } + + // Get the top level stack frame. + const StackFrameContext *getStackFrame(Decl const *D, + idx::TranslationUnit *TU) { + return LocContexts.getStackFrame(getContext(D, TU), 0, 0, 0, 0); + } + + // Get a stack frame with parent. + StackFrameContext const *getStackFrame(const Decl *D, + LocationContext const *Parent, + const Stmt *S, + const CFGBlock *Blk, + unsigned Idx) { + return LocContexts.getStackFrame(getContext(D), Parent, S, Blk, Idx); + } + + + /// Discard all previously created AnalysisDeclContexts. + void clear(); + +private: + friend class AnalysisDeclContext; + + LocationContextManager &getLocationContextManager() { + return LocContexts; + } +}; + +} // end clang namespace +#endif diff --git a/clang/include/clang/Analysis/AnalysisDiagnostic.h b/clang/include/clang/Analysis/AnalysisDiagnostic.h new file mode 100644 index 0000000..d4e1f5f --- /dev/null +++ b/clang/include/clang/Analysis/AnalysisDiagnostic.h @@ -0,0 +1,28 @@ +//===--- DiagnosticAnalysis.h - Diagnostics for libanalysis -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_DIAGNOSTICANALYSIS_H +#define LLVM_CLANG_DIAGNOSTICANALYSIS_H + +#include "clang/Basic/Diagnostic.h" + +namespace clang { + namespace diag { + enum { +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\ + SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM, +#define ANALYSISSTART +#include "clang/Basic/DiagnosticAnalysisKinds.inc" +#undef DIAG + NUM_BUILTIN_ANALYSIS_DIAGNOSTICS + }; + } // end namespace diag +} // end namespace clang + +#endif diff --git a/clang/include/clang/Analysis/CFG.h b/clang/include/clang/Analysis/CFG.h new file mode 100644 index 0000000..27b22b8 --- /dev/null +++ b/clang/include/clang/Analysis/CFG.h @@ -0,0 +1,938 @@ +//===--- CFG.h - Classes for representing and building CFGs------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the CFG and CFGBuilder classes for representing and +// building Control-Flow Graphs (CFGs) from ASTs. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_CFG_H +#define LLVM_CLANG_CFG_H + +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/GraphTraits.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/Casting.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/BitVector.h" +#include "clang/AST/Stmt.h" +#include "clang/Analysis/Support/BumpVector.h" +#include "clang/Basic/SourceLocation.h" +#include <cassert> +#include <iterator> + +namespace clang { + class CXXDestructorDecl; + class Decl; + class Stmt; + class Expr; + class FieldDecl; + class VarDecl; + class CXXCtorInitializer; + class CXXBaseSpecifier; + class CXXBindTemporaryExpr; + class CFG; + class PrinterHelper; + class LangOptions; + class ASTContext; + +/// CFGElement - Represents a top-level expression in a basic block. +class CFGElement { +public: + enum Kind { + // main kind + Invalid, + Statement, + Initializer, + // dtor kind + AutomaticObjectDtor, + BaseDtor, + MemberDtor, + TemporaryDtor, + DTOR_BEGIN = AutomaticObjectDtor, + DTOR_END = TemporaryDtor + }; + +protected: + // The int bits are used to mark the kind. + llvm::PointerIntPair<void *, 2> Data1; + llvm::PointerIntPair<void *, 2> Data2; + + CFGElement(Kind kind, const void *Ptr1, const void *Ptr2 = 0) + : Data1(const_cast<void*>(Ptr1), ((unsigned) kind) & 0x3), + Data2(const_cast<void*>(Ptr2), (((unsigned) kind) >> 2) & 0x3) {} + +public: + CFGElement() {} + + Kind getKind() const { + unsigned x = Data2.getInt(); + x <<= 2; + x |= Data1.getInt(); + return (Kind) x; + } + + bool isValid() const { return getKind() != Invalid; } + + operator bool() const { return isValid(); } + + template<class ElemTy> const ElemTy *getAs() const { + if (llvm::isa<ElemTy>(this)) + return static_cast<const ElemTy*>(this); + return 0; + } + + static bool classof(const CFGElement *E) { return true; } +}; + +class CFGStmt : public CFGElement { +public: + CFGStmt(Stmt *S) : CFGElement(Statement, S) {} + + const Stmt *getStmt() const { + return static_cast<const Stmt *>(Data1.getPointer()); + } + + static bool classof(const CFGElement *E) { + return E->getKind() == Statement; + } +}; + +/// CFGInitializer - Represents C++ base or member initializer from +/// constructor's initialization list. +class CFGInitializer : public CFGElement { +public: + CFGInitializer(CXXCtorInitializer *initializer) + : CFGElement(Initializer, initializer) {} + + CXXCtorInitializer* getInitializer() const { + return static_cast<CXXCtorInitializer*>(Data1.getPointer()); + } + + static bool classof(const CFGElement *E) { + return E->getKind() == Initializer; + } +}; + +/// CFGImplicitDtor - Represents C++ object destructor implicitly generated +/// by compiler on various occasions. +class CFGImplicitDtor : public CFGElement { +protected: + CFGImplicitDtor(Kind kind, const void *data1, const void *data2 = 0) + : CFGElement(kind, data1, data2) { + assert(kind >= DTOR_BEGIN && kind <= DTOR_END); + } + +public: + const CXXDestructorDecl *getDestructorDecl(ASTContext &astContext) const; + bool isNoReturn(ASTContext &astContext) const; + + static bool classof(const CFGElement *E) { + Kind kind = E->getKind(); + return kind >= DTOR_BEGIN && kind <= DTOR_END; + } +}; + +/// CFGAutomaticObjDtor - Represents C++ object destructor implicitly generated +/// for automatic object or temporary bound to const reference at the point +/// of leaving its local scope. +class CFGAutomaticObjDtor: public CFGImplicitDtor { +public: + CFGAutomaticObjDtor(const VarDecl *var, const Stmt *stmt) + : CFGImplicitDtor(AutomaticObjectDtor, var, stmt) {} + + const VarDecl *getVarDecl() const { + return static_cast<VarDecl*>(Data1.getPointer()); + } + + // Get statement end of which triggered the destructor call. + const Stmt *getTriggerStmt() const { + return static_cast<Stmt*>(Data2.getPointer()); + } + + static bool classof(const CFGElement *elem) { + return elem->getKind() == AutomaticObjectDtor; + } +}; + +/// CFGBaseDtor - Represents C++ object destructor implicitly generated for +/// base object in destructor. +class CFGBaseDtor : public CFGImplicitDtor { +public: + CFGBaseDtor(const CXXBaseSpecifier *base) + : CFGImplicitDtor(BaseDtor, base) {} + + const CXXBaseSpecifier *getBaseSpecifier() const { + return static_cast<const CXXBaseSpecifier*>(Data1.getPointer()); + } + + static bool classof(const CFGElement *E) { + return E->getKind() == BaseDtor; + } +}; + +/// CFGMemberDtor - Represents C++ object destructor implicitly generated for +/// member object in destructor. +class CFGMemberDtor : public CFGImplicitDtor { +public: + CFGMemberDtor(const FieldDecl *field) + : CFGImplicitDtor(MemberDtor, field, 0) {} + + const FieldDecl *getFieldDecl() const { + return static_cast<const FieldDecl*>(Data1.getPointer()); + } + + static bool classof(const CFGElement *E) { + return E->getKind() == MemberDtor; + } +}; + +/// CFGTemporaryDtor - Represents C++ object destructor implicitly generated +/// at the end of full expression for temporary object. +class CFGTemporaryDtor : public CFGImplicitDtor { +public: + CFGTemporaryDtor(CXXBindTemporaryExpr *expr) + : CFGImplicitDtor(TemporaryDtor, expr, 0) {} + + const CXXBindTemporaryExpr *getBindTemporaryExpr() const { + return static_cast<const CXXBindTemporaryExpr *>(Data1.getPointer()); + } + + static bool classof(const CFGElement *E) { + return E->getKind() == TemporaryDtor; + } +}; + +/// CFGTerminator - Represents CFGBlock terminator statement. +/// +/// TemporaryDtorsBranch bit is set to true if the terminator marks a branch +/// in control flow of destructors of temporaries. In this case terminator +/// statement is the same statement that branches control flow in evaluation +/// of matching full expression. +class CFGTerminator { + llvm::PointerIntPair<Stmt *, 1> Data; +public: + CFGTerminator() {} + CFGTerminator(Stmt *S, bool TemporaryDtorsBranch = false) + : Data(S, TemporaryDtorsBranch) {} + + Stmt *getStmt() { return Data.getPointer(); } + const Stmt *getStmt() const { return Data.getPointer(); } + + bool isTemporaryDtorsBranch() const { return Data.getInt(); } + + operator Stmt *() { return getStmt(); } + operator const Stmt *() const { return getStmt(); } + + Stmt *operator->() { return getStmt(); } + const Stmt *operator->() const { return getStmt(); } + + Stmt &operator*() { return *getStmt(); } + const Stmt &operator*() const { return *getStmt(); } + + operator bool() const { return getStmt(); } +}; + +/// CFGBlock - Represents a single basic block in a source-level CFG. +/// It consists of: +/// +/// (1) A set of statements/expressions (which may contain subexpressions). +/// (2) A "terminator" statement (not in the set of statements). +/// (3) A list of successors and predecessors. +/// +/// Terminator: The terminator represents the type of control-flow that occurs +/// at the end of the basic block. The terminator is a Stmt* referring to an +/// AST node that has control-flow: if-statements, breaks, loops, etc. +/// If the control-flow is conditional, the condition expression will appear +/// within the set of statements in the block (usually the last statement). +/// +/// Predecessors: the order in the set of predecessors is arbitrary. +/// +/// Successors: the order in the set of successors is NOT arbitrary. We +/// currently have the following orderings based on the terminator: +/// +/// Terminator Successor Ordering +/// ----------------------------------------------------- +/// if Then Block; Else Block +/// ? operator LHS expression; RHS expression +/// &&, || expression that uses result of && or ||, RHS +/// +/// But note that any of that may be NULL in case of optimized-out edges. +/// +class CFGBlock { + class ElementList { + typedef BumpVector<CFGElement> ImplTy; + ImplTy Impl; + public: + ElementList(BumpVectorContext &C) : Impl(C, 4) {} + + typedef std::reverse_iterator<ImplTy::iterator> iterator; + typedef std::reverse_iterator<ImplTy::const_iterator> const_iterator; + typedef ImplTy::iterator reverse_iterator; + typedef ImplTy::const_iterator const_reverse_iterator; + + void push_back(CFGElement e, BumpVectorContext &C) { Impl.push_back(e, C); } + reverse_iterator insert(reverse_iterator I, size_t Cnt, CFGElement E, + BumpVectorContext &C) { + return Impl.insert(I, Cnt, E, C); + } + + CFGElement front() const { return Impl.back(); } + CFGElement back() const { return Impl.front(); } + + iterator begin() { return Impl.rbegin(); } + iterator end() { return Impl.rend(); } + const_iterator begin() const { return Impl.rbegin(); } + const_iterator end() const { return Impl.rend(); } + reverse_iterator rbegin() { return Impl.begin(); } + reverse_iterator rend() { return Impl.end(); } + const_reverse_iterator rbegin() const { return Impl.begin(); } + const_reverse_iterator rend() const { return Impl.end(); } + + CFGElement operator[](size_t i) const { + assert(i < Impl.size()); + return Impl[Impl.size() - 1 - i]; + } + + size_t size() const { return Impl.size(); } + bool empty() const { return Impl.empty(); } + }; + + /// Stmts - The set of statements in the basic block. + ElementList Elements; + + /// Label - An (optional) label that prefixes the executable + /// statements in the block. When this variable is non-NULL, it is + /// either an instance of LabelStmt, SwitchCase or CXXCatchStmt. + Stmt *Label; + + /// Terminator - The terminator for a basic block that + /// indicates the type of control-flow that occurs between a block + /// and its successors. + CFGTerminator Terminator; + + /// LoopTarget - Some blocks are used to represent the "loop edge" to + /// the start of a loop from within the loop body. This Stmt* will be + /// refer to the loop statement for such blocks (and be null otherwise). + const Stmt *LoopTarget; + + /// BlockID - A numerical ID assigned to a CFGBlock during construction + /// of the CFG. + unsigned BlockID; + + /// Predecessors/Successors - Keep track of the predecessor / successor + /// CFG blocks. + typedef BumpVector<CFGBlock*> AdjacentBlocks; + AdjacentBlocks Preds; + AdjacentBlocks Succs; + + /// NoReturn - This bit is set when the basic block contains a function call + /// or implicit destructor that is attributed as 'noreturn'. In that case, + /// control cannot technically ever proceed past this block. All such blocks + /// will have a single immediate successor: the exit block. This allows them + /// to be easily reached from the exit block and using this bit quickly + /// recognized without scanning the contents of the block. + /// + /// Optimization Note: This bit could be profitably folded with Terminator's + /// storage if the memory usage of CFGBlock becomes an issue. + unsigned HasNoReturnElement : 1; + + /// Parent - The parent CFG that owns this CFGBlock. + CFG *Parent; + +public: + explicit CFGBlock(unsigned blockid, BumpVectorContext &C, CFG *parent) + : Elements(C), Label(NULL), Terminator(NULL), LoopTarget(NULL), + BlockID(blockid), Preds(C, 1), Succs(C, 1), HasNoReturnElement(false), + Parent(parent) {} + ~CFGBlock() {} + + // Statement iterators + typedef ElementList::iterator iterator; + typedef ElementList::const_iterator const_iterator; + typedef ElementList::reverse_iterator reverse_iterator; + typedef ElementList::const_reverse_iterator const_reverse_iterator; + + CFGElement front() const { return Elements.front(); } + CFGElement back() const { return Elements.back(); } + + iterator begin() { return Elements.begin(); } + iterator end() { return Elements.end(); } + const_iterator begin() const { return Elements.begin(); } + const_iterator end() const { return Elements.end(); } + + reverse_iterator rbegin() { return Elements.rbegin(); } + reverse_iterator rend() { return Elements.rend(); } + const_reverse_iterator rbegin() const { return Elements.rbegin(); } + const_reverse_iterator rend() const { return Elements.rend(); } + + unsigned size() const { return Elements.size(); } + bool empty() const { return Elements.empty(); } + + CFGElement operator[](size_t i) const { return Elements[i]; } + + // CFG iterators + typedef AdjacentBlocks::iterator pred_iterator; + typedef AdjacentBlocks::const_iterator const_pred_iterator; + typedef AdjacentBlocks::reverse_iterator pred_reverse_iterator; + typedef AdjacentBlocks::const_reverse_iterator const_pred_reverse_iterator; + + typedef AdjacentBlocks::iterator succ_iterator; + typedef AdjacentBlocks::const_iterator const_succ_iterator; + typedef AdjacentBlocks::reverse_iterator succ_reverse_iterator; + typedef AdjacentBlocks::const_reverse_iterator const_succ_reverse_iterator; + + pred_iterator pred_begin() { return Preds.begin(); } + pred_iterator pred_end() { return Preds.end(); } + const_pred_iterator pred_begin() const { return Preds.begin(); } + const_pred_iterator pred_end() const { return Preds.end(); } + + pred_reverse_iterator pred_rbegin() { return Preds.rbegin(); } + pred_reverse_iterator pred_rend() { return Preds.rend(); } + const_pred_reverse_iterator pred_rbegin() const { return Preds.rbegin(); } + const_pred_reverse_iterator pred_rend() const { return Preds.rend(); } + + succ_iterator succ_begin() { return Succs.begin(); } + succ_iterator succ_end() { return Succs.end(); } + const_succ_iterator succ_begin() const { return Succs.begin(); } + const_succ_iterator succ_end() const { return Succs.end(); } + + succ_reverse_iterator succ_rbegin() { return Succs.rbegin(); } + succ_reverse_iterator succ_rend() { return Succs.rend(); } + const_succ_reverse_iterator succ_rbegin() const { return Succs.rbegin(); } + const_succ_reverse_iterator succ_rend() const { return Succs.rend(); } + + unsigned succ_size() const { return Succs.size(); } + bool succ_empty() const { return Succs.empty(); } + + unsigned pred_size() const { return Preds.size(); } + bool pred_empty() const { return Preds.empty(); } + + + class FilterOptions { + public: + FilterOptions() { + IgnoreDefaultsWithCoveredEnums = 0; + } + + unsigned IgnoreDefaultsWithCoveredEnums : 1; + }; + + static bool FilterEdge(const FilterOptions &F, const CFGBlock *Src, + const CFGBlock *Dst); + + template <typename IMPL, bool IsPred> + class FilteredCFGBlockIterator { + private: + IMPL I, E; + const FilterOptions F; + const CFGBlock *From; + public: + explicit FilteredCFGBlockIterator(const IMPL &i, const IMPL &e, + const CFGBlock *from, + const FilterOptions &f) + : I(i), E(e), F(f), From(from) {} + + bool hasMore() const { return I != E; } + + FilteredCFGBlockIterator &operator++() { + do { ++I; } while (hasMore() && Filter(*I)); + return *this; + } + + const CFGBlock *operator*() const { return *I; } + private: + bool Filter(const CFGBlock *To) { + return IsPred ? FilterEdge(F, To, From) : FilterEdge(F, From, To); + } + }; + + typedef FilteredCFGBlockIterator<const_pred_iterator, true> + filtered_pred_iterator; + + typedef FilteredCFGBlockIterator<const_succ_iterator, false> + filtered_succ_iterator; + + filtered_pred_iterator filtered_pred_start_end(const FilterOptions &f) const { + return filtered_pred_iterator(pred_begin(), pred_end(), this, f); + } + + filtered_succ_iterator filtered_succ_start_end(const FilterOptions &f) const { + return filtered_succ_iterator(succ_begin(), succ_end(), this, f); + } + + // Manipulation of block contents + + void setTerminator(Stmt *Statement) { Terminator = Statement; } + void setLabel(Stmt *Statement) { Label = Statement; } + void setLoopTarget(const Stmt *loopTarget) { LoopTarget = loopTarget; } + void setHasNoReturnElement() { HasNoReturnElement = true; } + + CFGTerminator getTerminator() { return Terminator; } + const CFGTerminator getTerminator() const { return Terminator; } + + Stmt *getTerminatorCondition(); + + const Stmt *getTerminatorCondition() const { + return const_cast<CFGBlock*>(this)->getTerminatorCondition(); + } + + const Stmt *getLoopTarget() const { return LoopTarget; } + + Stmt *getLabel() { return Label; } + const Stmt *getLabel() const { return Label; } + + bool hasNoReturnElement() const { return HasNoReturnElement; } + + unsigned getBlockID() const { return BlockID; } + + CFG *getParent() const { return Parent; } + + void dump(const CFG *cfg, const LangOptions &LO, bool ShowColors = false) const; + void print(raw_ostream &OS, const CFG* cfg, const LangOptions &LO, + bool ShowColors) const; + void printTerminator(raw_ostream &OS, const LangOptions &LO) const; + + void addSuccessor(CFGBlock *Block, BumpVectorContext &C) { + if (Block) + Block->Preds.push_back(this, C); + Succs.push_back(Block, C); + } + + void appendStmt(Stmt *statement, BumpVectorContext &C) { + Elements.push_back(CFGStmt(statement), C); + } + + void appendInitializer(CXXCtorInitializer *initializer, + BumpVectorContext &C) { + Elements.push_back(CFGInitializer(initializer), C); + } + + void appendBaseDtor(const CXXBaseSpecifier *BS, BumpVectorContext &C) { + Elements.push_back(CFGBaseDtor(BS), C); + } + + void appendMemberDtor(FieldDecl *FD, BumpVectorContext &C) { + Elements.push_back(CFGMemberDtor(FD), C); + } + + void appendTemporaryDtor(CXXBindTemporaryExpr *E, BumpVectorContext &C) { + Elements.push_back(CFGTemporaryDtor(E), C); + } + + void appendAutomaticObjDtor(VarDecl *VD, Stmt *S, BumpVectorContext &C) { + Elements.push_back(CFGAutomaticObjDtor(VD, S), C); + } + + // Destructors must be inserted in reversed order. So insertion is in two + // steps. First we prepare space for some number of elements, then we insert + // the elements beginning at the last position in prepared space. + iterator beginAutomaticObjDtorsInsert(iterator I, size_t Cnt, + BumpVectorContext &C) { + return iterator(Elements.insert(I.base(), Cnt, CFGElement(), C)); + } + iterator insertAutomaticObjDtor(iterator I, VarDecl *VD, Stmt *S) { + *I = CFGAutomaticObjDtor(VD, S); + return ++I; + } +}; + +/// CFG - Represents a source-level, intra-procedural CFG that represents the +/// control-flow of a Stmt. The Stmt can represent an entire function body, +/// or a single expression. A CFG will always contain one empty block that +/// represents the Exit point of the CFG. A CFG will also contain a designated +/// Entry block. The CFG solely represents control-flow; it consists of +/// CFGBlocks which are simply containers of Stmt*'s in the AST the CFG +/// was constructed from. +class CFG { +public: + //===--------------------------------------------------------------------===// + // CFG Construction & Manipulation. + //===--------------------------------------------------------------------===// + + class BuildOptions { + llvm::BitVector alwaysAddMask; + public: + typedef llvm::DenseMap<const Stmt *, const CFGBlock*> ForcedBlkExprs; + ForcedBlkExprs **forcedBlkExprs; + + bool PruneTriviallyFalseEdges; + bool AddEHEdges; + bool AddInitializers; + bool AddImplicitDtors; + + bool alwaysAdd(const Stmt *stmt) const { + return alwaysAddMask[stmt->getStmtClass()]; + } + + BuildOptions &setAlwaysAdd(Stmt::StmtClass stmtClass, bool val = true) { + alwaysAddMask[stmtClass] = val; + return *this; + } + + BuildOptions &setAllAlwaysAdd() { + alwaysAddMask.set(); + return *this; + } + + BuildOptions() + : alwaysAddMask(Stmt::lastStmtConstant, false) + ,forcedBlkExprs(0), PruneTriviallyFalseEdges(true) + ,AddEHEdges(false) + ,AddInitializers(false) + ,AddImplicitDtors(false) {} + }; + + /// \brief Provides a custom implementation of the iterator class to have the + /// same interface as Function::iterator - iterator returns CFGBlock + /// (not a pointer to CFGBlock). + class graph_iterator { + public: + typedef const CFGBlock value_type; + typedef value_type& reference; + typedef value_type* pointer; + typedef BumpVector<CFGBlock*>::iterator ImplTy; + + graph_iterator(const ImplTy &i) : I(i) {} + + bool operator==(const graph_iterator &X) const { return I == X.I; } + bool operator!=(const graph_iterator &X) const { return I != X.I; } + + reference operator*() const { return **I; } + pointer operator->() const { return *I; } + operator CFGBlock* () { return *I; } + + graph_iterator &operator++() { ++I; return *this; } + graph_iterator &operator--() { --I; return *this; } + + private: + ImplTy I; + }; + + class const_graph_iterator { + public: + typedef const CFGBlock value_type; + typedef value_type& reference; + typedef value_type* pointer; + typedef BumpVector<CFGBlock*>::const_iterator ImplTy; + + const_graph_iterator(const ImplTy &i) : I(i) {} + + bool operator==(const const_graph_iterator &X) const { return I == X.I; } + bool operator!=(const const_graph_iterator &X) const { return I != X.I; } + + reference operator*() const { return **I; } + pointer operator->() const { return *I; } + operator CFGBlock* () const { return *I; } + + const_graph_iterator &operator++() { ++I; return *this; } + const_graph_iterator &operator--() { --I; return *this; } + + private: + ImplTy I; + }; + + /// buildCFG - Builds a CFG from an AST. The responsibility to free the + /// constructed CFG belongs to the caller. + static CFG* buildCFG(const Decl *D, Stmt *AST, ASTContext *C, + const BuildOptions &BO); + + /// createBlock - Create a new block in the CFG. The CFG owns the block; + /// the caller should not directly free it. + CFGBlock *createBlock(); + + /// setEntry - Set the entry block of the CFG. This is typically used + /// only during CFG construction. Most CFG clients expect that the + /// entry block has no predecessors and contains no statements. + void setEntry(CFGBlock *B) { Entry = B; } + + /// setIndirectGotoBlock - Set the block used for indirect goto jumps. + /// This is typically used only during CFG construction. + void setIndirectGotoBlock(CFGBlock *B) { IndirectGotoBlock = B; } + + //===--------------------------------------------------------------------===// + // Block Iterators + //===--------------------------------------------------------------------===// + + typedef BumpVector<CFGBlock*> CFGBlockListTy; + typedef CFGBlockListTy::iterator iterator; + typedef CFGBlockListTy::const_iterator const_iterator; + typedef std::reverse_iterator<iterator> reverse_iterator; + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + + CFGBlock & front() { return *Blocks.front(); } + CFGBlock & back() { return *Blocks.back(); } + + iterator begin() { return Blocks.begin(); } + iterator end() { return Blocks.end(); } + const_iterator begin() const { return Blocks.begin(); } + const_iterator end() const { return Blocks.end(); } + + graph_iterator nodes_begin() { return graph_iterator(Blocks.begin()); } + graph_iterator nodes_end() { return graph_iterator(Blocks.end()); } + const_graph_iterator nodes_begin() const { + return const_graph_iterator(Blocks.begin()); + } + const_graph_iterator nodes_end() const { + return const_graph_iterator(Blocks.end()); + } + + reverse_iterator rbegin() { return Blocks.rbegin(); } + reverse_iterator rend() { return Blocks.rend(); } + const_reverse_iterator rbegin() const { return Blocks.rbegin(); } + const_reverse_iterator rend() const { return Blocks.rend(); } + + CFGBlock & getEntry() { return *Entry; } + const CFGBlock & getEntry() const { return *Entry; } + CFGBlock & getExit() { return *Exit; } + const CFGBlock & getExit() const { return *Exit; } + + CFGBlock * getIndirectGotoBlock() { return IndirectGotoBlock; } + const CFGBlock * getIndirectGotoBlock() const { return IndirectGotoBlock; } + + typedef std::vector<const CFGBlock*>::const_iterator try_block_iterator; + try_block_iterator try_blocks_begin() const { + return TryDispatchBlocks.begin(); + } + try_block_iterator try_blocks_end() const { + return TryDispatchBlocks.end(); + } + + void addTryDispatchBlock(const CFGBlock *block) { + TryDispatchBlocks.push_back(block); + } + + //===--------------------------------------------------------------------===// + // Member templates useful for various batch operations over CFGs. + //===--------------------------------------------------------------------===// + + template <typename CALLBACK> + void VisitBlockStmts(CALLBACK& O) const { + for (const_iterator I=begin(), E=end(); I != E; ++I) + for (CFGBlock::const_iterator BI=(*I)->begin(), BE=(*I)->end(); + BI != BE; ++BI) { + if (const CFGStmt *stmt = BI->getAs<CFGStmt>()) + O(const_cast<Stmt*>(stmt->getStmt())); + } + } + + //===--------------------------------------------------------------------===// + // CFG Introspection. + //===--------------------------------------------------------------------===// + + struct BlkExprNumTy { + const signed Idx; + explicit BlkExprNumTy(signed idx) : Idx(idx) {} + explicit BlkExprNumTy() : Idx(-1) {} + operator bool() const { return Idx >= 0; } + operator unsigned() const { assert(Idx >=0); return (unsigned) Idx; } + }; + + bool isBlkExpr(const Stmt *S) { return getBlkExprNum(S); } + bool isBlkExpr(const Stmt *S) const { + return const_cast<CFG*>(this)->isBlkExpr(S); + } + BlkExprNumTy getBlkExprNum(const Stmt *S); + unsigned getNumBlkExprs(); + + /// getNumBlockIDs - Returns the total number of BlockIDs allocated (which + /// start at 0). + unsigned getNumBlockIDs() const { return NumBlockIDs; } + + /// size - Return the total number of CFGBlocks within the CFG + /// This is simply a renaming of the getNumBlockIDs(). This is necessary + /// because the dominator implementation needs such an interface. + unsigned size() const { return NumBlockIDs; } + + //===--------------------------------------------------------------------===// + // CFG Debugging: Pretty-Printing and Visualization. + //===--------------------------------------------------------------------===// + + void viewCFG(const LangOptions &LO) const; + void print(raw_ostream &OS, const LangOptions &LO, bool ShowColors) const; + void dump(const LangOptions &LO, bool ShowColors) const; + + //===--------------------------------------------------------------------===// + // Internal: constructors and data. + //===--------------------------------------------------------------------===// + + CFG() : Entry(NULL), Exit(NULL), IndirectGotoBlock(NULL), NumBlockIDs(0), + BlkExprMap(NULL), Blocks(BlkBVC, 10) {} + + ~CFG(); + + llvm::BumpPtrAllocator& getAllocator() { + return BlkBVC.getAllocator(); + } + + BumpVectorContext &getBumpVectorContext() { + return BlkBVC; + } + +private: + CFGBlock *Entry; + CFGBlock *Exit; + CFGBlock* IndirectGotoBlock; // Special block to contain collective dispatch + // for indirect gotos + unsigned NumBlockIDs; + + // BlkExprMap - An opaque pointer to prevent inclusion of DenseMap.h. + // It represents a map from Expr* to integers to record the set of + // block-level expressions and their "statement number" in the CFG. + void * BlkExprMap; + + BumpVectorContext BlkBVC; + + CFGBlockListTy Blocks; + + /// C++ 'try' statements are modeled with an indirect dispatch block. + /// This is the collection of such blocks present in the CFG. + std::vector<const CFGBlock *> TryDispatchBlocks; + +}; +} // end namespace clang + +//===----------------------------------------------------------------------===// +// GraphTraits specializations for CFG basic block graphs (source-level CFGs) +//===----------------------------------------------------------------------===// + +namespace llvm { + +/// Implement simplify_type for CFGTerminator, so that we can dyn_cast from +/// CFGTerminator to a specific Stmt class. +template <> struct simplify_type<const ::clang::CFGTerminator> { + typedef const ::clang::Stmt *SimpleType; + static SimpleType getSimplifiedValue(const ::clang::CFGTerminator &Val) { + return Val.getStmt(); + } +}; + +template <> struct simplify_type< ::clang::CFGTerminator> { + typedef ::clang::Stmt *SimpleType; + static SimpleType getSimplifiedValue(const ::clang::CFGTerminator &Val) { + return const_cast<SimpleType>(Val.getStmt()); + } +}; + +// Traits for: CFGBlock + +template <> struct GraphTraits< ::clang::CFGBlock *> { + typedef ::clang::CFGBlock NodeType; + typedef ::clang::CFGBlock::succ_iterator ChildIteratorType; + + static NodeType* getEntryNode(::clang::CFGBlock *BB) + { return BB; } + + static inline ChildIteratorType child_begin(NodeType* N) + { return N->succ_begin(); } + + static inline ChildIteratorType child_end(NodeType* N) + { return N->succ_end(); } +}; + +template <> struct GraphTraits< const ::clang::CFGBlock *> { + typedef const ::clang::CFGBlock NodeType; + typedef ::clang::CFGBlock::const_succ_iterator ChildIteratorType; + + static NodeType* getEntryNode(const clang::CFGBlock *BB) + { return BB; } + + static inline ChildIteratorType child_begin(NodeType* N) + { return N->succ_begin(); } + + static inline ChildIteratorType child_end(NodeType* N) + { return N->succ_end(); } +}; + +template <> struct GraphTraits<Inverse< ::clang::CFGBlock*> > { + typedef ::clang::CFGBlock NodeType; + typedef ::clang::CFGBlock::const_pred_iterator ChildIteratorType; + + static NodeType *getEntryNode(Inverse< ::clang::CFGBlock*> G) + { return G.Graph; } + + static inline ChildIteratorType child_begin(NodeType* N) + { return N->pred_begin(); } + + static inline ChildIteratorType child_end(NodeType* N) + { return N->pred_end(); } +}; + +template <> struct GraphTraits<Inverse<const ::clang::CFGBlock*> > { + typedef const ::clang::CFGBlock NodeType; + typedef ::clang::CFGBlock::const_pred_iterator ChildIteratorType; + + static NodeType *getEntryNode(Inverse<const ::clang::CFGBlock*> G) + { return G.Graph; } + + static inline ChildIteratorType child_begin(NodeType* N) + { return N->pred_begin(); } + + static inline ChildIteratorType child_end(NodeType* N) + { return N->pred_end(); } +}; + +// Traits for: CFG + +template <> struct GraphTraits< ::clang::CFG* > + : public GraphTraits< ::clang::CFGBlock *> { + + typedef ::clang::CFG::graph_iterator nodes_iterator; + + static NodeType *getEntryNode(::clang::CFG* F) { return &F->getEntry(); } + static nodes_iterator nodes_begin(::clang::CFG* F) { return F->nodes_begin();} + static nodes_iterator nodes_end(::clang::CFG* F) { return F->nodes_end(); } + static unsigned size(::clang::CFG* F) { return F->size(); } +}; + +template <> struct GraphTraits<const ::clang::CFG* > + : public GraphTraits<const ::clang::CFGBlock *> { + + typedef ::clang::CFG::const_graph_iterator nodes_iterator; + + static NodeType *getEntryNode( const ::clang::CFG* F) { + return &F->getEntry(); + } + static nodes_iterator nodes_begin( const ::clang::CFG* F) { + return F->nodes_begin(); + } + static nodes_iterator nodes_end( const ::clang::CFG* F) { + return F->nodes_end(); + } + static unsigned size(const ::clang::CFG* F) { + return F->size(); + } +}; + +template <> struct GraphTraits<Inverse< ::clang::CFG*> > + : public GraphTraits<Inverse< ::clang::CFGBlock*> > { + + typedef ::clang::CFG::graph_iterator nodes_iterator; + + static NodeType *getEntryNode( ::clang::CFG* F) { return &F->getExit(); } + static nodes_iterator nodes_begin( ::clang::CFG* F) {return F->nodes_begin();} + static nodes_iterator nodes_end( ::clang::CFG* F) { return F->nodes_end(); } +}; + +template <> struct GraphTraits<Inverse<const ::clang::CFG*> > + : public GraphTraits<Inverse<const ::clang::CFGBlock*> > { + + typedef ::clang::CFG::const_graph_iterator nodes_iterator; + + static NodeType *getEntryNode(const ::clang::CFG* F) { return &F->getExit(); } + static nodes_iterator nodes_begin(const ::clang::CFG* F) { + return F->nodes_begin(); + } + static nodes_iterator nodes_end(const ::clang::CFG* F) { + return F->nodes_end(); + } +}; +} // end llvm namespace +#endif diff --git a/clang/include/clang/Analysis/CFGStmtMap.h b/clang/include/clang/Analysis/CFGStmtMap.h new file mode 100644 index 0000000..6e8e140 --- /dev/null +++ b/clang/include/clang/Analysis/CFGStmtMap.h @@ -0,0 +1,52 @@ +//===--- CFGStmtMap.h - Map from Stmt* to CFGBlock* -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the CFGStmtMap class, which defines a mapping from +// Stmt* to CFGBlock* +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_CFGSTMTMAP_H +#define LLVM_CLANG_CFGSTMTMAP_H + +#include "clang/Analysis/CFG.h" + +namespace clang { + +class CFG; +class CFGBlock; +class ParentMap; +class Stmt; + +class CFGStmtMap { + ParentMap *PM; + void *M; + + CFGStmtMap(ParentMap *pm, void *m) : PM(pm), M(m) {} + +public: + ~CFGStmtMap(); + + /// Returns a new CFGMap for the given CFG. It is the caller's + /// responsibility to 'delete' this object when done using it. + static CFGStmtMap *Build(CFG* C, ParentMap *PM); + + /// Returns the CFGBlock the specified Stmt* appears in. For Stmt* that + /// are terminators, the CFGBlock is the block they appear as a terminator, + /// and not the block they appear as a block-level expression (e.g, '&&'). + /// CaseStmts and LabelStmts map to the CFGBlock they label. + CFGBlock *getBlock(Stmt * S); + + const CFGBlock *getBlock(const Stmt * S) const { + return const_cast<CFGStmtMap*>(this)->getBlock(const_cast<Stmt*>(S)); + } +}; + +} // end clang namespace +#endif diff --git a/clang/include/clang/Analysis/CallGraph.h b/clang/include/clang/Analysis/CallGraph.h new file mode 100644 index 0000000..9b68073 --- /dev/null +++ b/clang/include/clang/Analysis/CallGraph.h @@ -0,0 +1,257 @@ +//== CallGraph.h - AST-based Call graph ------------------------*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the AST-based CallGraph. +// +// A call graph for functions whose definitions/bodies are available in the +// current translation unit. The graph has a "virtual" root node that contains +// edges to all externally available functions. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_CALLGRAPH +#define LLVM_CLANG_ANALYSIS_CALLGRAPH + +#include "clang/AST/DeclBase.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/GraphTraits.h" +#include "llvm/ADT/SetVector.h" + +namespace clang { +class CallGraphNode; + +/// \class The AST-based call graph. +/// +/// The call graph extends itself with the given declarations by implementing +/// the recursive AST visitor, which constructs the graph by visiting the given +/// declarations. +class CallGraph : public RecursiveASTVisitor<CallGraph> { + friend class CallGraphNode; + + typedef llvm::DenseMap<const Decl *, CallGraphNode *> FunctionMapTy; + + /// FunctionMap owns all CallGraphNodes. + FunctionMapTy FunctionMap; + + /// This is a virtual root node that has edges to all the global functions - + /// 'main' or functions accessible from other translation units. + CallGraphNode *Root; + + /// The list of nodes that have no parent. These are unreachable from Root. + /// Declarations can get to this list due to impressions in the graph, for + /// example, we do not track functions whose addresses were taken. + llvm::SetVector<CallGraphNode *> ParentlessNodes; + +public: + CallGraph(); + ~CallGraph(); + + /// \brief Populate the call graph with the functions in the given + /// declaration. + /// + /// Recursively walks the declaration to find all the dependent Decls as well. + void addToCallGraph(Decl *D) { + TraverseDecl(D); + } + + /// \brief Determine if a declaration should be included in the graph. + static bool includeInGraph(const Decl *D); + + /// \brief Lookup the node for the given declaration. + CallGraphNode *getNode(const Decl *) const; + + /// \brief Lookup the node for the given declaration. If none found, insert + /// one into the graph. + CallGraphNode *getOrInsertNode(Decl *); + + /// Iterators through all the elements in the graph. Note, this gives + /// non-deterministic order. + typedef FunctionMapTy::iterator iterator; + typedef FunctionMapTy::const_iterator const_iterator; + iterator begin() { return FunctionMap.begin(); } + iterator end() { return FunctionMap.end(); } + const_iterator begin() const { return FunctionMap.begin(); } + const_iterator end() const { return FunctionMap.end(); } + + /// \brief Get the number of nodes in the graph. + unsigned size() const { return FunctionMap.size(); } + + /// \ brief Get the virtual root of the graph, all the functions available + /// externally are represented as callees of the node. + CallGraphNode *getRoot() const { return Root; } + + /// Iterators through all the nodes of the graph that have no parent. These + /// are the unreachable nodes, which are either unused or are due to us + /// failing to add a call edge due to the analysis imprecision. + typedef llvm::SetVector<CallGraphNode *>::iterator nodes_iterator; + typedef llvm::SetVector<CallGraphNode *>::const_iterator const_nodes_iterator; + nodes_iterator parentless_begin() { return ParentlessNodes.begin(); } + nodes_iterator parentless_end() { return ParentlessNodes.end(); } + const_nodes_iterator + parentless_begin() const { return ParentlessNodes.begin(); } + const_nodes_iterator + parentless_end() const { return ParentlessNodes.end(); } + + void print(raw_ostream &os) const; + void dump() const; + void viewGraph() const; + + /// Part of recursive declaration visitation. + bool VisitFunctionDecl(FunctionDecl *FD) { + // We skip function template definitions, as their semantics is + // only determined when they are instantiated. + if (includeInGraph(FD)) + // If this function has external linkage, anything could call it. + // Note, we are not precise here. For example, the function could have + // its address taken. + addNodeForDecl(FD, FD->isGlobal()); + return true; + } + + /// Part of recursive declaration visitation. + bool VisitObjCMethodDecl(ObjCMethodDecl *MD) { + if (includeInGraph(MD)) + addNodeForDecl(MD, true); + return true; + } + +private: + /// \brief Add the given declaration to the call graph. + void addNodeForDecl(Decl *D, bool IsGlobal); + + /// \brief Allocate a new node in the graph. + CallGraphNode *allocateNewNode(Decl *); +}; + +class CallGraphNode { +public: + typedef CallGraphNode* CallRecord; + +private: + /// \brief The function/method declaration. + Decl *FD; + + /// \brief The list of functions called from this node. + // Small vector might be more efficient since we are only tracking functions + // whose definition is in the current TU. + llvm::SmallVector<CallRecord, 5> CalledFunctions; + +public: + CallGraphNode(Decl *D) : FD(D) {} + + typedef llvm::SmallVector<CallRecord, 5>::iterator iterator; + typedef llvm::SmallVector<CallRecord, 5>::const_iterator const_iterator; + + /// Iterators through all the callees/children of the node. + inline iterator begin() { return CalledFunctions.begin(); } + inline iterator end() { return CalledFunctions.end(); } + inline const_iterator begin() const { return CalledFunctions.begin(); } + inline const_iterator end() const { return CalledFunctions.end(); } + + inline bool empty() const {return CalledFunctions.empty(); } + inline unsigned size() const {return CalledFunctions.size(); } + + void addCallee(CallGraphNode *N, CallGraph *CG) { + CalledFunctions.push_back(N); + CG->ParentlessNodes.remove(N); + } + + Decl *getDecl() const { return FD; } + + StringRef getName() const; + + void print(raw_ostream &os) const; + void dump() const; +}; + +} // end clang namespace + +// Graph traits for iteration, viewing. +namespace llvm { +template <> struct GraphTraits<clang::CallGraphNode*> { + typedef clang::CallGraphNode NodeType; + typedef clang::CallGraphNode::CallRecord CallRecordTy; + typedef std::pointer_to_unary_function<CallRecordTy, + clang::CallGraphNode*> CGNDerefFun; + static NodeType *getEntryNode(clang::CallGraphNode *CGN) { return CGN; } + typedef mapped_iterator<NodeType::iterator, CGNDerefFun> ChildIteratorType; + static inline ChildIteratorType child_begin(NodeType *N) { + return map_iterator(N->begin(), CGNDerefFun(CGNDeref)); + } + static inline ChildIteratorType child_end (NodeType *N) { + return map_iterator(N->end(), CGNDerefFun(CGNDeref)); + } + static clang::CallGraphNode *CGNDeref(CallRecordTy P) { + return P; + } +}; + +template <> struct GraphTraits<const clang::CallGraphNode*> { + typedef const clang::CallGraphNode NodeType; + typedef NodeType::const_iterator ChildIteratorType; + static NodeType *getEntryNode(const clang::CallGraphNode *CGN) { return CGN; } + static inline ChildIteratorType child_begin(NodeType *N) { return N->begin();} + static inline ChildIteratorType child_end (NodeType *N) { return N->end(); } +}; + +template <> struct GraphTraits<clang::CallGraph*> + : public GraphTraits<clang::CallGraphNode*> { + + static NodeType *getEntryNode(clang::CallGraph *CGN) { + return CGN->getRoot(); // Start at the external node! + } + typedef std::pair<const clang::Decl*, clang::CallGraphNode*> PairTy; + typedef std::pointer_to_unary_function<PairTy, clang::CallGraphNode&> DerefFun; + // nodes_iterator/begin/end - Allow iteration over all nodes in the graph + typedef mapped_iterator<clang::CallGraph::iterator, DerefFun> nodes_iterator; + + static nodes_iterator nodes_begin(clang::CallGraph *CG) { + return map_iterator(CG->begin(), DerefFun(CGdereference)); + } + static nodes_iterator nodes_end (clang::CallGraph *CG) { + return map_iterator(CG->end(), DerefFun(CGdereference)); + } + static clang::CallGraphNode &CGdereference(PairTy P) { + return *(P.second); + } + + static unsigned size(clang::CallGraph *CG) { + return CG->size(); + } +}; + +template <> struct GraphTraits<const clang::CallGraph*> : + public GraphTraits<const clang::CallGraphNode*> { + static NodeType *getEntryNode(const clang::CallGraph *CGN) { + return CGN->getRoot(); + } + typedef std::pair<const clang::Decl*, clang::CallGraphNode*> PairTy; + typedef std::pointer_to_unary_function<PairTy, clang::CallGraphNode&> DerefFun; + // nodes_iterator/begin/end - Allow iteration over all nodes in the graph + typedef mapped_iterator<clang::CallGraph::const_iterator, + DerefFun> nodes_iterator; + + static nodes_iterator nodes_begin(const clang::CallGraph *CG) { + return map_iterator(CG->begin(), DerefFun(CGdereference)); + } + static nodes_iterator nodes_end(const clang::CallGraph *CG) { + return map_iterator(CG->end(), DerefFun(CGdereference)); + } + static clang::CallGraphNode &CGdereference(PairTy P) { + return *(P.second); + } + + static unsigned size(const clang::CallGraph *CG) { + return CG->size(); + } +}; + +} // end llvm namespace + +#endif diff --git a/clang/include/clang/Analysis/DomainSpecific/CocoaConventions.h b/clang/include/clang/Analysis/DomainSpecific/CocoaConventions.h new file mode 100644 index 0000000..e6a2f13 --- /dev/null +++ b/clang/include/clang/Analysis/DomainSpecific/CocoaConventions.h @@ -0,0 +1,42 @@ +//===- CocoaConventions.h - Special handling of Cocoa conventions -*- C++ -*--// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements cocoa naming convention analysis. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_DS_COCOA +#define LLVM_CLANG_ANALYSIS_DS_COCOA + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/StringRef.h" + +namespace clang { +class FunctionDecl; +class QualType; + +namespace ento { +namespace cocoa { + + bool isRefType(QualType RetTy, StringRef Prefix, + StringRef Name = StringRef()); + + bool isCocoaObjectRef(QualType T); + +} + +namespace coreFoundation { + bool isCFObjectRef(QualType T); + + bool followsCreateRule(const FunctionDecl *FD); +} + +}} // end: "clang:ento" + +#endif diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowSolver.h b/clang/include/clang/Analysis/FlowSensitive/DataflowSolver.h new file mode 100644 index 0000000..017da63 --- /dev/null +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowSolver.h @@ -0,0 +1,343 @@ +//===--- DataflowSolver.h - Skeleton Dataflow Analysis Code -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines skeleton code for implementing dataflow analyses. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSES_DATAFLOW_SOLVER +#define LLVM_CLANG_ANALYSES_DATAFLOW_SOLVER + +#include "clang/Analysis/CFG.h" +#include "clang/Analysis/ProgramPoint.h" +#include "clang/Analysis/FlowSensitive/DataflowValues.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallVector.h" +#include "functional" // STL + +namespace clang { + +//===----------------------------------------------------------------------===// +/// DataflowWorkListTy - Data structure representing the worklist used for +/// dataflow algorithms. +//===----------------------------------------------------------------------===// + +class DataflowWorkListTy { + llvm::DenseMap<const CFGBlock*, unsigned char> BlockSet; + SmallVector<const CFGBlock *, 10> BlockQueue; +public: + /// enqueue - Add a block to the worklist. Blocks already on the + /// worklist are not added a second time. + void enqueue(const CFGBlock *B) { + unsigned char &x = BlockSet[B]; + if (x == 1) + return; + x = 1; + BlockQueue.push_back(B); + } + + /// dequeue - Remove a block from the worklist. + const CFGBlock *dequeue() { + assert(!BlockQueue.empty()); + const CFGBlock *B = BlockQueue.back(); + BlockQueue.pop_back(); + BlockSet[B] = 0; + return B; + } + + /// isEmpty - Return true if the worklist is empty. + bool isEmpty() const { return BlockQueue.empty(); } +}; + +//===----------------------------------------------------------------------===// +// BlockItrTraits - Traits classes that allow transparent iteration +// over successors/predecessors of a block depending on the direction +// of our dataflow analysis. +//===----------------------------------------------------------------------===// + +namespace dataflow { +template<typename Tag> struct ItrTraits {}; + +template <> struct ItrTraits<forward_analysis_tag> { + typedef CFGBlock::const_pred_iterator PrevBItr; + typedef CFGBlock::const_succ_iterator NextBItr; + typedef CFGBlock::const_iterator StmtItr; + + static PrevBItr PrevBegin(const CFGBlock *B) { return B->pred_begin(); } + static PrevBItr PrevEnd(const CFGBlock *B) { return B->pred_end(); } + + static NextBItr NextBegin(const CFGBlock *B) { return B->succ_begin(); } + static NextBItr NextEnd(const CFGBlock *B) { return B->succ_end(); } + + static StmtItr StmtBegin(const CFGBlock *B) { return B->begin(); } + static StmtItr StmtEnd(const CFGBlock *B) { return B->end(); } + + static BlockEdge PrevEdge(const CFGBlock *B, const CFGBlock *Prev) { + return BlockEdge(Prev, B, 0); + } + + static BlockEdge NextEdge(const CFGBlock *B, const CFGBlock *Next) { + return BlockEdge(B, Next, 0); + } +}; + +template <> struct ItrTraits<backward_analysis_tag> { + typedef CFGBlock::const_succ_iterator PrevBItr; + typedef CFGBlock::const_pred_iterator NextBItr; + typedef CFGBlock::const_reverse_iterator StmtItr; + + static PrevBItr PrevBegin(const CFGBlock *B) { return B->succ_begin(); } + static PrevBItr PrevEnd(const CFGBlock *B) { return B->succ_end(); } + + static NextBItr NextBegin(const CFGBlock *B) { return B->pred_begin(); } + static NextBItr NextEnd(const CFGBlock *B) { return B->pred_end(); } + + static StmtItr StmtBegin(const CFGBlock *B) { return B->rbegin(); } + static StmtItr StmtEnd(const CFGBlock *B) { return B->rend(); } + + static BlockEdge PrevEdge(const CFGBlock *B, const CFGBlock *Prev) { + return BlockEdge(B, Prev, 0); + } + + static BlockEdge NextEdge(const CFGBlock *B, const CFGBlock *Next) { + return BlockEdge(Next, B, 0); + } +}; +} // end namespace dataflow + +//===----------------------------------------------------------------------===// +/// DataflowSolverTy - Generic dataflow solver. +//===----------------------------------------------------------------------===// + +template <typename _DFValuesTy, // Usually a subclass of DataflowValues + typename _TransferFuncsTy, + typename _MergeOperatorTy, + typename _Equal = std::equal_to<typename _DFValuesTy::ValTy> > +class DataflowSolver { + + //===----------------------------------------------------===// + // Type declarations. + //===----------------------------------------------------===// + +public: + typedef _DFValuesTy DFValuesTy; + typedef _TransferFuncsTy TransferFuncsTy; + typedef _MergeOperatorTy MergeOperatorTy; + + typedef typename _DFValuesTy::AnalysisDirTag AnalysisDirTag; + typedef typename _DFValuesTy::ValTy ValTy; + typedef typename _DFValuesTy::EdgeDataMapTy EdgeDataMapTy; + typedef typename _DFValuesTy::BlockDataMapTy BlockDataMapTy; + + typedef dataflow::ItrTraits<AnalysisDirTag> ItrTraits; + typedef typename ItrTraits::NextBItr NextBItr; + typedef typename ItrTraits::PrevBItr PrevBItr; + typedef typename ItrTraits::StmtItr StmtItr; + + //===----------------------------------------------------===// + // External interface: constructing and running the solver. + //===----------------------------------------------------===// + +public: + DataflowSolver(DFValuesTy& d) : D(d), TF(d.getAnalysisData()) {} + ~DataflowSolver() {} + + /// runOnCFG - Computes dataflow values for all blocks in a CFG. + void runOnCFG(CFG& cfg, bool recordStmtValues = false) { + // Set initial dataflow values and boundary conditions. + D.InitializeValues(cfg); + // Solve the dataflow equations. This will populate D.EdgeDataMap + // with dataflow values. + SolveDataflowEquations(cfg, recordStmtValues); + } + + /// runOnBlock - Computes dataflow values for a given block. This + /// should usually be invoked only after previously computing + /// dataflow values using runOnCFG, as runOnBlock is intended to + /// only be used for querying the dataflow values within a block + /// with and Observer object. + void runOnBlock(const CFGBlock *B, bool recordStmtValues) { + BlockDataMapTy& M = D.getBlockDataMap(); + typename BlockDataMapTy::iterator I = M.find(B); + + if (I != M.end()) { + TF.getVal().copyValues(I->second); + ProcessBlock(B, recordStmtValues, AnalysisDirTag()); + } + } + + void runOnBlock(const CFGBlock &B, bool recordStmtValues) { + runOnBlock(&B, recordStmtValues); + } + void runOnBlock(CFG::iterator &I, bool recordStmtValues) { + runOnBlock(*I, recordStmtValues); + } + void runOnBlock(CFG::const_iterator &I, bool recordStmtValues) { + runOnBlock(*I, recordStmtValues); + } + + void runOnAllBlocks(const CFG& cfg, bool recordStmtValues = false) { + for (CFG::const_iterator I=cfg.begin(), E=cfg.end(); I!=E; ++I) + runOnBlock(I, recordStmtValues); + } + + //===----------------------------------------------------===// + // Internal solver logic. + //===----------------------------------------------------===// + +private: + + /// SolveDataflowEquations - Perform the actual worklist algorithm + /// to compute dataflow values. + void SolveDataflowEquations(CFG& cfg, bool recordStmtValues) { + EnqueueBlocksOnWorklist(cfg, AnalysisDirTag()); + + while (!WorkList.isEmpty()) { + const CFGBlock *B = WorkList.dequeue(); + ProcessMerge(cfg, B); + ProcessBlock(B, recordStmtValues, AnalysisDirTag()); + UpdateEdges(cfg, B, TF.getVal()); + } + } + + void EnqueueBlocksOnWorklist(CFG &cfg, dataflow::forward_analysis_tag) { + // Enqueue all blocks to ensure the dataflow values are computed + // for every block. Not all blocks are guaranteed to reach the exit block. + for (CFG::iterator I=cfg.begin(), E=cfg.end(); I!=E; ++I) + WorkList.enqueue(&**I); + } + + void EnqueueBlocksOnWorklist(CFG &cfg, dataflow::backward_analysis_tag) { + // Enqueue all blocks to ensure the dataflow values are computed + // for every block. Not all blocks are guaranteed to reach the exit block. + // Enqueue in reverse order since that will more likely match with + // the order they should ideally processed by the dataflow algorithm. + for (CFG::reverse_iterator I=cfg.rbegin(), E=cfg.rend(); I!=E; ++I) + WorkList.enqueue(&**I); + } + + void ProcessMerge(CFG& cfg, const CFGBlock *B) { + ValTy& V = TF.getVal(); + TF.SetTopValue(V); + + // Merge dataflow values from all predecessors of this block. + MergeOperatorTy Merge; + + EdgeDataMapTy& M = D.getEdgeDataMap(); + bool firstMerge = true; + bool noEdges = true; + for (PrevBItr I=ItrTraits::PrevBegin(B),E=ItrTraits::PrevEnd(B); I!=E; ++I){ + + CFGBlock *PrevBlk = *I; + + if (!PrevBlk) + continue; + + typename EdgeDataMapTy::iterator EI = + M.find(ItrTraits::PrevEdge(B, PrevBlk)); + + if (EI != M.end()) { + noEdges = false; + if (firstMerge) { + firstMerge = false; + V.copyValues(EI->second); + } + else + Merge(V, EI->second); + } + } + + bool isInitialized = true; + typename BlockDataMapTy::iterator BI = D.getBlockDataMap().find(B); + if(BI == D.getBlockDataMap().end()) { + isInitialized = false; + BI = D.getBlockDataMap().insert( std::make_pair(B,ValTy()) ).first; + } + // If no edges have been found, it means this is the first time the solver + // has been called on block B, we copy the initialization values (if any) + // as current value for V (which will be used as edge data) + if(noEdges && isInitialized) + Merge(V, BI->second); + + // Set the data for the block. + BI->second.copyValues(V); + } + + /// ProcessBlock - Process the transfer functions for a given block. + void ProcessBlock(const CFGBlock *B, bool recordStmtValues, + dataflow::forward_analysis_tag) { + + TF.setCurrentBlock(B); + + for (StmtItr I=ItrTraits::StmtBegin(B), E=ItrTraits::StmtEnd(B); I!=E;++I) { + CFGElement El = *I; + if (const CFGStmt *S = El.getAs<CFGStmt>()) + ProcessStmt(S->getStmt(), recordStmtValues, AnalysisDirTag()); + } + + TF.VisitTerminator(const_cast<CFGBlock*>(B)); + } + + void ProcessBlock(const CFGBlock *B, bool recordStmtValues, + dataflow::backward_analysis_tag) { + + TF.setCurrentBlock(B); + + TF.VisitTerminator(const_cast<CFGBlock*>(B)); + + for (StmtItr I=ItrTraits::StmtBegin(B), E=ItrTraits::StmtEnd(B); I!=E;++I) { + CFGElement El = *I; + if (const CFGStmt *S = El.getAs<CFGStmt>()) + ProcessStmt(S->getStmt(), recordStmtValues, AnalysisDirTag()); + } + } + + void ProcessStmt(const Stmt *S, bool record, dataflow::forward_analysis_tag) { + if (record) D.getStmtDataMap()[S] = TF.getVal(); + TF.BlockStmt_Visit(const_cast<Stmt*>(S)); + } + + void ProcessStmt(const Stmt *S, bool record, dataflow::backward_analysis_tag){ + TF.BlockStmt_Visit(const_cast<Stmt*>(S)); + if (record) D.getStmtDataMap()[S] = TF.getVal(); + } + + /// UpdateEdges - After processing the transfer functions for a + /// block, update the dataflow value associated with the block's + /// outgoing/incoming edges (depending on whether we do a + // forward/backward analysis respectively) + void UpdateEdges(CFG& cfg, const CFGBlock *B, ValTy& V) { + for (NextBItr I=ItrTraits::NextBegin(B), E=ItrTraits::NextEnd(B); I!=E; ++I) + if (CFGBlock *NextBlk = *I) + UpdateEdgeValue(ItrTraits::NextEdge(B, NextBlk),V, NextBlk); + } + + /// UpdateEdgeValue - Update the value associated with a given edge. + void UpdateEdgeValue(BlockEdge E, ValTy& V, const CFGBlock *TargetBlock) { + EdgeDataMapTy& M = D.getEdgeDataMap(); + typename EdgeDataMapTy::iterator I = M.find(E); + + if (I == M.end()) { // First computed value for this edge? + M[E].copyValues(V); + WorkList.enqueue(TargetBlock); + } + else if (!_Equal()(V,I->second)) { + I->second.copyValues(V); + WorkList.enqueue(TargetBlock); + } + } + +private: + DFValuesTy& D; + DataflowWorkListTy WorkList; + TransferFuncsTy TF; +}; + +} // end namespace clang +#endif diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowValues.h b/clang/include/clang/Analysis/FlowSensitive/DataflowValues.h new file mode 100644 index 0000000..f86b2b0 --- /dev/null +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowValues.h @@ -0,0 +1,172 @@ +//===--- DataflowValues.h - Data structure for dataflow values --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines a skeleton data structure for encapsulating the dataflow +// values for a CFG. Typically this is subclassed to provide methods for +// computing these values from a CFG. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSES_DATAFLOW_VALUES +#define LLVM_CLANG_ANALYSES_DATAFLOW_VALUES + +#include "clang/Analysis/CFG.h" +#include "clang/Analysis/ProgramPoint.h" +#include "llvm/ADT/DenseMap.h" + +//===----------------------------------------------------------------------===// +/// Dataflow Directional Tag Classes. These are used for tag dispatching +/// within the dataflow solver/transfer functions to determine what direction +/// a dataflow analysis flows. +//===----------------------------------------------------------------------===// + +namespace clang { +namespace dataflow { + struct forward_analysis_tag {}; + struct backward_analysis_tag {}; +} // end namespace dataflow + +//===----------------------------------------------------------------------===// +/// DataflowValues. Container class to store dataflow values for a CFG. +//===----------------------------------------------------------------------===// + +template <typename ValueTypes, + typename _AnalysisDirTag = dataflow::forward_analysis_tag > +class DataflowValues { + + //===--------------------------------------------------------------------===// + // Type declarations. + //===--------------------------------------------------------------------===// + +public: + typedef typename ValueTypes::ValTy ValTy; + typedef typename ValueTypes::AnalysisDataTy AnalysisDataTy; + typedef _AnalysisDirTag AnalysisDirTag; + typedef llvm::DenseMap<ProgramPoint, ValTy> EdgeDataMapTy; + typedef llvm::DenseMap<const CFGBlock*, ValTy> BlockDataMapTy; + typedef llvm::DenseMap<const Stmt*, ValTy> StmtDataMapTy; + + //===--------------------------------------------------------------------===// + // Predicates. + //===--------------------------------------------------------------------===// + +public: + /// isForwardAnalysis - Returns true if the dataflow values are computed + /// from a forward analysis. + bool isForwardAnalysis() { return isForwardAnalysis(AnalysisDirTag()); } + + /// isBackwardAnalysis - Returns true if the dataflow values are computed + /// from a backward analysis. + bool isBackwardAnalysis() { return !isForwardAnalysis(); } + +private: + bool isForwardAnalysis(dataflow::forward_analysis_tag) { return true; } + bool isForwardAnalysis(dataflow::backward_analysis_tag) { return false; } + + //===--------------------------------------------------------------------===// + // Initialization and accessors methods. + //===--------------------------------------------------------------------===// + +public: + DataflowValues() : StmtDataMap(NULL) {} + ~DataflowValues() { delete StmtDataMap; } + + /// InitializeValues - Invoked by the solver to initialize state needed for + /// dataflow analysis. This method is usually specialized by subclasses. + void InitializeValues(const CFG& cfg) {} + + + /// getEdgeData - Retrieves the dataflow values associated with a + /// CFG edge. + ValTy& getEdgeData(const BlockEdge &E) { + typename EdgeDataMapTy::iterator I = EdgeDataMap.find(E); + assert (I != EdgeDataMap.end() && "No data associated with Edge."); + return I->second; + } + + const ValTy& getEdgeData(const BlockEdge &E) const { + return reinterpret_cast<DataflowValues*>(this)->getEdgeData(E); + } + + /// getBlockData - Retrieves the dataflow values associated with a + /// specified CFGBlock. If the dataflow analysis is a forward analysis, + /// this data is associated with the END of the block. If the analysis + /// is a backwards analysis, it is associated with the ENTRY of the block. + ValTy& getBlockData(const CFGBlock *B) { + typename BlockDataMapTy::iterator I = BlockDataMap.find(B); + assert (I != BlockDataMap.end() && "No data associated with block."); + return I->second; + } + + const ValTy& getBlockData(const CFGBlock *B) const { + return const_cast<DataflowValues*>(this)->getBlockData(B); + } + + /// getStmtData - Retrieves the dataflow values associated with a + /// specified Stmt. If the dataflow analysis is a forward analysis, + /// this data corresponds to the point immediately before a Stmt. + /// If the analysis is a backwards analysis, it is associated with + /// the point after a Stmt. This data is only computed for block-level + /// expressions, and only when requested when the analysis is executed. + ValTy& getStmtData(const Stmt *S) { + assert (StmtDataMap && "Dataflow values were not computed for statements."); + typename StmtDataMapTy::iterator I = StmtDataMap->find(S); + assert (I != StmtDataMap->end() && "No data associated with statement."); + return I->second; + } + + const ValTy& getStmtData(const Stmt *S) const { + return const_cast<DataflowValues*>(this)->getStmtData(S); + } + + /// getEdgeDataMap - Retrieves the internal map between CFG edges and + /// dataflow values. Usually used by a dataflow solver to compute + /// values for blocks. + EdgeDataMapTy& getEdgeDataMap() { return EdgeDataMap; } + const EdgeDataMapTy& getEdgeDataMap() const { return EdgeDataMap; } + + /// getBlockDataMap - Retrieves the internal map between CFGBlocks and + /// dataflow values. If the dataflow analysis operates in the forward + /// direction, the values correspond to the dataflow values at the start + /// of the block. Otherwise, for a backward analysis, the values correpsond + /// to the dataflow values at the end of the block. + BlockDataMapTy& getBlockDataMap() { return BlockDataMap; } + const BlockDataMapTy& getBlockDataMap() const { return BlockDataMap; } + + /// getStmtDataMap - Retrieves the internal map between Stmts and + /// dataflow values. + StmtDataMapTy& getStmtDataMap() { + if (!StmtDataMap) StmtDataMap = new StmtDataMapTy(); + return *StmtDataMap; + } + + const StmtDataMapTy& getStmtDataMap() const { + return const_cast<DataflowValues*>(this)->getStmtDataMap(); + } + + /// getAnalysisData - Retrieves the meta data associated with a + /// dataflow analysis for analyzing a particular CFG. + /// This is typically consumed by transfer function code (via the solver). + /// This can also be used by subclasses to interpret the dataflow values. + AnalysisDataTy& getAnalysisData() { return AnalysisData; } + const AnalysisDataTy& getAnalysisData() const { return AnalysisData; } + + //===--------------------------------------------------------------------===// + // Internal data. + //===--------------------------------------------------------------------===// + +protected: + EdgeDataMapTy EdgeDataMap; + BlockDataMapTy BlockDataMap; + StmtDataMapTy* StmtDataMap; + AnalysisDataTy AnalysisData; +}; + +} // end namespace clang +#endif diff --git a/clang/include/clang/Analysis/ProgramPoint.h b/clang/include/clang/Analysis/ProgramPoint.h new file mode 100644 index 0000000..aa7a33c --- /dev/null +++ b/clang/include/clang/Analysis/ProgramPoint.h @@ -0,0 +1,490 @@ +//==- ProgramPoint.h - Program Points for Path-Sensitive Analysis --*- C++ -*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the interface ProgramPoint, which identifies a +// distinct location in a function. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_PROGRAM_POINT +#define LLVM_CLANG_ANALYSIS_PROGRAM_POINT + +#include "clang/Analysis/AnalysisContext.h" +#include "clang/Analysis/CFG.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/Support/Casting.h" +#include "llvm/ADT/StringRef.h" +#include <cassert> +#include <utility> +#include <string> + +namespace clang { + +class AnalysisDeclContext; +class FunctionDecl; +class LocationContext; +class ProgramPointTag; + +class ProgramPoint { +public: + enum Kind { BlockEdgeKind, + BlockEntranceKind, + BlockExitKind, + PreStmtKind, + PostStmtKind, + PreLoadKind, + PostLoadKind, + PreStoreKind, + PostStoreKind, + PostPurgeDeadSymbolsKind, + PostConditionKind, + PostLValueKind, + PostInitializerKind, + CallEnterKind, + CallExitKind, + MinPostStmtKind = PostStmtKind, + MaxPostStmtKind = CallExitKind, + EpsilonKind}; + +private: + llvm::PointerIntPair<const void *, 2, unsigned> Data1; + llvm::PointerIntPair<const void *, 2, unsigned> Data2; + + // The LocationContext could be NULL to allow ProgramPoint to be used in + // context insensitive analysis. + llvm::PointerIntPair<const LocationContext *, 2, unsigned> L; + + const ProgramPointTag *Tag; + + ProgramPoint(); + +protected: + ProgramPoint(const void *P, + Kind k, + const LocationContext *l, + const ProgramPointTag *tag = 0) + : Data1(P, ((unsigned) k) & 0x3), + Data2(0, (((unsigned) k) >> 2) & 0x3), + L(l, (((unsigned) k) >> 4) & 0x3), + Tag(tag) { + assert(getKind() == k); + assert(getLocationContext() == l); + assert(getData1() == P); + } + + ProgramPoint(const void *P1, + const void *P2, + Kind k, + const LocationContext *l, + const ProgramPointTag *tag = 0) + : Data1(P1, ((unsigned) k) & 0x3), + Data2(P2, (((unsigned) k) >> 2) & 0x3), + L(l, (((unsigned) k) >> 4) & 0x3), + Tag(tag) {} + +protected: + const void *getData1() const { return Data1.getPointer(); } + const void *getData2() const { return Data2.getPointer(); } + void setData2(const void *d) { Data2.setPointer(d); } + +public: + /// Create a new ProgramPoint object that is the same as the original + /// except for using the specified tag value. + ProgramPoint withTag(const ProgramPointTag *tag) const { + return ProgramPoint(getData1(), getData2(), getKind(), + getLocationContext(), tag); + } + + Kind getKind() const { + unsigned x = L.getInt(); + x <<= 2; + x |= Data2.getInt(); + x <<= 2; + x |= Data1.getInt(); + return (Kind) x; + } + + const ProgramPointTag *getTag() const { return Tag; } + + const LocationContext *getLocationContext() const { + return L.getPointer(); + } + + // For use with DenseMap. This hash is probably slow. + unsigned getHashValue() const { + llvm::FoldingSetNodeID ID; + Profile(ID); + return ID.ComputeHash(); + } + + static bool classof(const ProgramPoint*) { return true; } + + bool operator==(const ProgramPoint & RHS) const { + return Data1 == RHS.Data1 && + Data2 == RHS.Data2 && + L == RHS.L && + Tag == RHS.Tag; + } + + bool operator!=(const ProgramPoint &RHS) const { + return Data1 != RHS.Data1 || + Data2 != RHS.Data2 || + L != RHS.L || + Tag != RHS.Tag; + } + + void Profile(llvm::FoldingSetNodeID& ID) const { + ID.AddInteger((unsigned) getKind()); + ID.AddPointer(getData1()); + ID.AddPointer(getData2()); + ID.AddPointer(getLocationContext()); + ID.AddPointer(Tag); + } + + static ProgramPoint getProgramPoint(const Stmt *S, ProgramPoint::Kind K, + const LocationContext *LC, + const ProgramPointTag *tag); +}; + +class BlockEntrance : public ProgramPoint { +public: + BlockEntrance(const CFGBlock *B, const LocationContext *L, + const ProgramPointTag *tag = 0) + : ProgramPoint(B, BlockEntranceKind, L, tag) { + assert(B && "BlockEntrance requires non-null block"); + } + + const CFGBlock *getBlock() const { + return reinterpret_cast<const CFGBlock*>(getData1()); + } + + const CFGElement getFirstElement() const { + const CFGBlock *B = getBlock(); + return B->empty() ? CFGElement() : B->front(); + } + + static bool classof(const ProgramPoint* Location) { + return Location->getKind() == BlockEntranceKind; + } +}; + +class BlockExit : public ProgramPoint { +public: + BlockExit(const CFGBlock *B, const LocationContext *L) + : ProgramPoint(B, BlockExitKind, L) {} + + const CFGBlock *getBlock() const { + return reinterpret_cast<const CFGBlock*>(getData1()); + } + + const Stmt *getTerminator() const { + return getBlock()->getTerminator(); + } + + static bool classof(const ProgramPoint* Location) { + return Location->getKind() == BlockExitKind; + } +}; + +class StmtPoint : public ProgramPoint { +public: + StmtPoint(const Stmt *S, const void *p2, Kind k, const LocationContext *L, + const ProgramPointTag *tag) + : ProgramPoint(S, p2, k, L, tag) {} + + const Stmt *getStmt() const { return (const Stmt*) getData1(); } + + template <typename T> + const T* getStmtAs() const { return llvm::dyn_cast<T>(getStmt()); } + + static bool classof(const ProgramPoint* Location) { + unsigned k = Location->getKind(); + return k >= PreStmtKind && k <= MaxPostStmtKind; + } +}; + + +class PreStmt : public StmtPoint { +public: + PreStmt(const Stmt *S, const LocationContext *L, const ProgramPointTag *tag, + const Stmt *SubStmt = 0) + : StmtPoint(S, SubStmt, PreStmtKind, L, tag) {} + + const Stmt *getSubStmt() const { return (const Stmt*) getData2(); } + + static bool classof(const ProgramPoint* Location) { + return Location->getKind() == PreStmtKind; + } +}; + +class PostStmt : public StmtPoint { +protected: + PostStmt(const Stmt *S, const void *data, Kind k, const LocationContext *L, + const ProgramPointTag *tag = 0) + : StmtPoint(S, data, k, L, tag) {} + +public: + explicit PostStmt(const Stmt *S, Kind k, + const LocationContext *L, const ProgramPointTag *tag = 0) + : StmtPoint(S, NULL, k, L, tag) {} + + explicit PostStmt(const Stmt *S, const LocationContext *L, + const ProgramPointTag *tag = 0) + : StmtPoint(S, NULL, PostStmtKind, L, tag) {} + + static bool classof(const ProgramPoint* Location) { + unsigned k = Location->getKind(); + return k >= MinPostStmtKind && k <= MaxPostStmtKind; + } +}; + +// PostCondition represents the post program point of a branch condition. +class PostCondition : public PostStmt { +public: + PostCondition(const Stmt *S, const LocationContext *L, + const ProgramPointTag *tag = 0) + : PostStmt(S, PostConditionKind, L, tag) {} + + static bool classof(const ProgramPoint* Location) { + return Location->getKind() == PostConditionKind; + } +}; + +class LocationCheck : public StmtPoint { +protected: + LocationCheck(const Stmt *S, const LocationContext *L, + ProgramPoint::Kind K, const ProgramPointTag *tag) + : StmtPoint(S, NULL, K, L, tag) {} + + static bool classof(const ProgramPoint *location) { + unsigned k = location->getKind(); + return k == PreLoadKind || k == PreStoreKind; + } +}; + +class PreLoad : public LocationCheck { +public: + PreLoad(const Stmt *S, const LocationContext *L, + const ProgramPointTag *tag = 0) + : LocationCheck(S, L, PreLoadKind, tag) {} + + static bool classof(const ProgramPoint *location) { + return location->getKind() == PreLoadKind; + } +}; + +class PreStore : public LocationCheck { +public: + PreStore(const Stmt *S, const LocationContext *L, + const ProgramPointTag *tag = 0) + : LocationCheck(S, L, PreStoreKind, tag) {} + + static bool classof(const ProgramPoint *location) { + return location->getKind() == PreStoreKind; + } +}; + +class PostLoad : public PostStmt { +public: + PostLoad(const Stmt *S, const LocationContext *L, + const ProgramPointTag *tag = 0) + : PostStmt(S, PostLoadKind, L, tag) {} + + static bool classof(const ProgramPoint* Location) { + return Location->getKind() == PostLoadKind; + } +}; + +/// \class Represents a program point after a store evaluation. +class PostStore : public PostStmt { +public: + /// Construct the post store point. + /// \param Loc can be used to store the information about the location + /// used in the form it was uttered in the code. + PostStore(const Stmt *S, const LocationContext *L, const void *Loc, + const ProgramPointTag *tag = 0) + : PostStmt(S, PostStoreKind, L, tag) { + assert(getData2() == 0); + setData2(Loc); + } + + static bool classof(const ProgramPoint* Location) { + return Location->getKind() == PostStoreKind; + } + + /// \brief Returns the information about the location used in the store, + /// how it was uttered in the code. + const void *getLocationValue() const { + return getData2(); + } + +}; + +class PostLValue : public PostStmt { +public: + PostLValue(const Stmt *S, const LocationContext *L, + const ProgramPointTag *tag = 0) + : PostStmt(S, PostLValueKind, L, tag) {} + + static bool classof(const ProgramPoint* Location) { + return Location->getKind() == PostLValueKind; + } +}; + +class PostPurgeDeadSymbols : public PostStmt { +public: + PostPurgeDeadSymbols(const Stmt *S, const LocationContext *L, + const ProgramPointTag *tag = 0) + : PostStmt(S, PostPurgeDeadSymbolsKind, L, tag) {} + + static bool classof(const ProgramPoint* Location) { + return Location->getKind() == PostPurgeDeadSymbolsKind; + } +}; + +class BlockEdge : public ProgramPoint { +public: + BlockEdge(const CFGBlock *B1, const CFGBlock *B2, const LocationContext *L) + : ProgramPoint(B1, B2, BlockEdgeKind, L) { + assert(B1 && "BlockEdge: source block must be non-null"); + assert(B2 && "BlockEdge: destination block must be non-null"); + } + + const CFGBlock *getSrc() const { + return static_cast<const CFGBlock*>(getData1()); + } + + const CFGBlock *getDst() const { + return static_cast<const CFGBlock*>(getData2()); + } + + static bool classof(const ProgramPoint* Location) { + return Location->getKind() == BlockEdgeKind; + } +}; + +class PostInitializer : public ProgramPoint { +public: + PostInitializer(const CXXCtorInitializer *I, + const LocationContext *L) + : ProgramPoint(I, PostInitializerKind, L) {} + + static bool classof(const ProgramPoint *Location) { + return Location->getKind() == PostInitializerKind; + } +}; + +class CallEnter : public StmtPoint { +public: + CallEnter(const Stmt *stmt, const StackFrameContext *calleeCtx, + const LocationContext *callerCtx) + : StmtPoint(stmt, calleeCtx, CallEnterKind, callerCtx, 0) {} + + const Stmt *getCallExpr() const { + return static_cast<const Stmt *>(getData1()); + } + + const StackFrameContext *getCalleeContext() const { + return static_cast<const StackFrameContext *>(getData2()); + } + + static bool classof(const ProgramPoint *Location) { + return Location->getKind() == CallEnterKind; + } +}; + +class CallExit : public StmtPoint { +public: + // CallExit uses the callee's location context. + CallExit(const Stmt *S, const LocationContext *L) + : StmtPoint(S, 0, CallExitKind, L, 0) {} + + static bool classof(const ProgramPoint *Location) { + return Location->getKind() == CallExitKind; + } +}; + +/// This is a meta program point, which should be skipped by all the diagnostic +/// reasoning etc. +class EpsilonPoint : public ProgramPoint { +public: + EpsilonPoint(const LocationContext *L, const void *Data1, + const void *Data2 = 0, const ProgramPointTag *tag = 0) + : ProgramPoint(Data1, Data2, EpsilonKind, L, tag) {} + + const void *getData() const { return getData1(); } + + static bool classof(const ProgramPoint* Location) { + return Location->getKind() == EpsilonKind; + } +}; + +/// ProgramPoints can be "tagged" as representing points specific to a given +/// analysis entity. Tags are abstract annotations, with an associated +/// description and potentially other information. +class ProgramPointTag { +public: + ProgramPointTag(void *tagKind = 0) : TagKind(tagKind) {} + virtual ~ProgramPointTag(); + virtual StringRef getTagDescription() const = 0; + +protected: + /// Used to implement 'classof' in subclasses. + const void *getTagKind() { return TagKind; } + +private: + const void *TagKind; +}; + +class SimpleProgramPointTag : public ProgramPointTag { + std::string desc; +public: + SimpleProgramPointTag(StringRef description); + StringRef getTagDescription() const; +}; + +} // end namespace clang + + +namespace llvm { // Traits specialization for DenseMap + +template <> struct DenseMapInfo<clang::ProgramPoint> { + +static inline clang::ProgramPoint getEmptyKey() { + uintptr_t x = + reinterpret_cast<uintptr_t>(DenseMapInfo<void*>::getEmptyKey()) & ~0x7; + return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x), 0); +} + +static inline clang::ProgramPoint getTombstoneKey() { + uintptr_t x = + reinterpret_cast<uintptr_t>(DenseMapInfo<void*>::getTombstoneKey()) & ~0x7; + return clang::BlockEntrance(reinterpret_cast<clang::CFGBlock*>(x), 0); +} + +static unsigned getHashValue(const clang::ProgramPoint &Loc) { + return Loc.getHashValue(); +} + +static bool isEqual(const clang::ProgramPoint &L, + const clang::ProgramPoint &R) { + return L == R; +} + +}; + +template <> +struct isPodLike<clang::ProgramPoint> { static const bool value = true; }; + +} // end namespace llvm + +#endif diff --git a/clang/include/clang/Analysis/Support/BlkExprDeclBitVector.h b/clang/include/clang/Analysis/Support/BlkExprDeclBitVector.h new file mode 100644 index 0000000..d25b848 --- /dev/null +++ b/clang/include/clang/Analysis/Support/BlkExprDeclBitVector.h @@ -0,0 +1,307 @@ +// BlkExprDeclBitVector.h - Dataflow types for Bitvector Analysis --*- C++ --*-- +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides definition of dataflow types used by analyses such +// as LiveVariables and UninitializedValues. The underlying dataflow values +// are implemented as bitvectors, but the definitions in this file include +// the necessary boilerplate to use with our dataflow framework. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STMTDECLBVDVAL_H +#define LLVM_CLANG_STMTDECLBVDVAL_H + +#include "clang/Analysis/CFG.h" +#include "clang/AST/Decl.h" // for Decl* -> NamedDecl* conversion +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/DenseMap.h" + +namespace clang { + + class Stmt; + class ASTContext; + +struct DeclBitVector_Types { + + class Idx { + unsigned I; + public: + explicit Idx(unsigned i) : I(i) {} + Idx() : I(~0U) {} + + bool isValid() const { + return I != ~0U; + } + operator unsigned() const { + assert (isValid()); + return I; + } + }; + + //===--------------------------------------------------------------------===// + // AnalysisDataTy - Whole-function meta data. + //===--------------------------------------------------------------------===// + + class AnalysisDataTy { + public: + typedef llvm::DenseMap<const NamedDecl*, unsigned > DMapTy; + typedef DMapTy::const_iterator decl_iterator; + + protected: + DMapTy DMap; + unsigned NDecls; + + public: + + AnalysisDataTy() : NDecls(0) {} + virtual ~AnalysisDataTy() {} + + bool isTracked(const NamedDecl *SD) { return DMap.find(SD) != DMap.end(); } + + Idx getIdx(const NamedDecl *SD) const { + DMapTy::const_iterator I = DMap.find(SD); + return I == DMap.end() ? Idx() : Idx(I->second); + } + + unsigned getNumDecls() const { return NDecls; } + + void Register(const NamedDecl *SD) { + if (!isTracked(SD)) DMap[SD] = NDecls++; + } + + decl_iterator begin_decl() const { return DMap.begin(); } + decl_iterator end_decl() const { return DMap.end(); } + }; + + //===--------------------------------------------------------------------===// + // ValTy - Dataflow value. + //===--------------------------------------------------------------------===// + + class ValTy { + llvm::BitVector DeclBV; + public: + + void resetDeclValues(AnalysisDataTy& AD) { + DeclBV.resize(AD.getNumDecls()); + DeclBV.reset(); + } + + void setDeclValues(AnalysisDataTy& AD) { + DeclBV.resize(AD.getNumDecls()); + DeclBV.set(); + } + + void resetValues(AnalysisDataTy& AD) { + resetDeclValues(AD); + } + + bool operator==(const ValTy& RHS) const { + assert (sizesEqual(RHS)); + return DeclBV == RHS.DeclBV; + } + + void copyValues(const ValTy& RHS) { DeclBV = RHS.DeclBV; } + + llvm::BitVector::reference getBit(unsigned i) { + return DeclBV[i]; + } + + bool getBit(unsigned i) const { + return DeclBV[i]; + } + + llvm::BitVector::reference + operator()(const NamedDecl *ND, const AnalysisDataTy& AD) { + return getBit(AD.getIdx(ND)); + } + + bool operator()(const NamedDecl *ND, const AnalysisDataTy& AD) const { + return getBit(AD.getIdx(ND)); + } + + llvm::BitVector::reference getDeclBit(unsigned i) { return DeclBV[i]; } + const llvm::BitVector::reference getDeclBit(unsigned i) const { + return const_cast<llvm::BitVector&>(DeclBV)[i]; + } + + ValTy& operator|=(const ValTy& RHS) { + assert (sizesEqual(RHS)); + DeclBV |= RHS.DeclBV; + return *this; + } + + ValTy& operator&=(const ValTy& RHS) { + assert (sizesEqual(RHS)); + DeclBV &= RHS.DeclBV; + return *this; + } + + ValTy& OrDeclBits(const ValTy& RHS) { + return operator|=(RHS); + } + + ValTy& AndDeclBits(const ValTy& RHS) { + return operator&=(RHS); + } + + bool sizesEqual(const ValTy& RHS) const { + return DeclBV.size() == RHS.DeclBV.size(); + } + }; + + //===--------------------------------------------------------------------===// + // Some useful merge operations. + //===--------------------------------------------------------------------===// + + struct Union { void operator()(ValTy& Dst, ValTy& Src) { Dst |= Src; } }; + struct Intersect { void operator()(ValTy& Dst, ValTy& Src) { Dst &= Src; } }; +}; + + +struct StmtDeclBitVector_Types { + + //===--------------------------------------------------------------------===// + // AnalysisDataTy - Whole-function meta data. + //===--------------------------------------------------------------------===// + + class AnalysisDataTy : public DeclBitVector_Types::AnalysisDataTy { + ASTContext *ctx; + CFG* cfg; + public: + AnalysisDataTy() : ctx(0), cfg(0) {} + virtual ~AnalysisDataTy() {} + + void setContext(ASTContext &c) { ctx = &c; } + ASTContext &getContext() { + assert(ctx && "ASTContext should not be NULL."); + return *ctx; + } + + void setCFG(CFG& c) { cfg = &c; } + CFG& getCFG() { assert(cfg && "CFG should not be NULL."); return *cfg; } + + bool isTracked(const Stmt *S) { return cfg->isBlkExpr(S); } + using DeclBitVector_Types::AnalysisDataTy::isTracked; + + unsigned getIdx(const Stmt *S) const { + CFG::BlkExprNumTy I = cfg->getBlkExprNum(S); + assert(I && "Stmtession not tracked for bitvector."); + return I; + } + using DeclBitVector_Types::AnalysisDataTy::getIdx; + + unsigned getNumBlkExprs() const { return cfg->getNumBlkExprs(); } + }; + + //===--------------------------------------------------------------------===// + // ValTy - Dataflow value. + //===--------------------------------------------------------------------===// + + class ValTy : public DeclBitVector_Types::ValTy { + llvm::BitVector BlkExprBV; + typedef DeclBitVector_Types::ValTy ParentTy; + + static inline ParentTy& ParentRef(ValTy& X) { + return static_cast<ParentTy&>(X); + } + + static inline const ParentTy& ParentRef(const ValTy& X) { + return static_cast<const ParentTy&>(X); + } + + public: + + void resetBlkExprValues(AnalysisDataTy& AD) { + BlkExprBV.resize(AD.getNumBlkExprs()); + BlkExprBV.reset(); + } + + void setBlkExprValues(AnalysisDataTy& AD) { + BlkExprBV.resize(AD.getNumBlkExprs()); + BlkExprBV.set(); + } + + void resetValues(AnalysisDataTy& AD) { + resetDeclValues(AD); + resetBlkExprValues(AD); + } + + void setValues(AnalysisDataTy& AD) { + setDeclValues(AD); + setBlkExprValues(AD); + } + + bool operator==(const ValTy& RHS) const { + return ParentRef(*this) == ParentRef(RHS) + && BlkExprBV == RHS.BlkExprBV; + } + + void copyValues(const ValTy& RHS) { + ParentRef(*this).copyValues(ParentRef(RHS)); + BlkExprBV = RHS.BlkExprBV; + } + + llvm::BitVector::reference + operator()(const Stmt *S, const AnalysisDataTy& AD) { + return BlkExprBV[AD.getIdx(S)]; + } + const llvm::BitVector::reference + operator()(const Stmt *S, const AnalysisDataTy& AD) const { + return const_cast<ValTy&>(*this)(S,AD); + } + + using DeclBitVector_Types::ValTy::operator(); + + + llvm::BitVector::reference getStmtBit(unsigned i) { return BlkExprBV[i]; } + const llvm::BitVector::reference getStmtBit(unsigned i) const { + return const_cast<llvm::BitVector&>(BlkExprBV)[i]; + } + + ValTy& OrBlkExprBits(const ValTy& RHS) { + BlkExprBV |= RHS.BlkExprBV; + return *this; + } + + ValTy& AndBlkExprBits(const ValTy& RHS) { + BlkExprBV &= RHS.BlkExprBV; + return *this; + } + + ValTy& operator|=(const ValTy& RHS) { + assert (sizesEqual(RHS)); + ParentRef(*this) |= ParentRef(RHS); + BlkExprBV |= RHS.BlkExprBV; + return *this; + } + + ValTy& operator&=(const ValTy& RHS) { + assert (sizesEqual(RHS)); + ParentRef(*this) &= ParentRef(RHS); + BlkExprBV &= RHS.BlkExprBV; + return *this; + } + + bool sizesEqual(const ValTy& RHS) const { + return ParentRef(*this).sizesEqual(ParentRef(RHS)) + && BlkExprBV.size() == RHS.BlkExprBV.size(); + } + }; + + //===--------------------------------------------------------------------===// + // Some useful merge operations. + //===--------------------------------------------------------------------===// + + struct Union { void operator()(ValTy& Dst, ValTy& Src) { Dst |= Src; } }; + struct Intersect { void operator()(ValTy& Dst, ValTy& Src) { Dst &= Src; } }; + +}; +} // end namespace clang + +#endif diff --git a/clang/include/clang/Analysis/Support/BumpVector.h b/clang/include/clang/Analysis/Support/BumpVector.h new file mode 100644 index 0000000..83532e6 --- /dev/null +++ b/clang/include/clang/Analysis/Support/BumpVector.h @@ -0,0 +1,244 @@ +//===-- BumpVector.h - Vector-like ADT that uses bump allocation --*- C++ -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides BumpVector, a vector-like ADT whose contents are +// allocated from a BumpPtrAllocator. +// +//===----------------------------------------------------------------------===// + +// FIXME: Most of this is copy-and-paste from SmallVector.h. We can +// refactor this core logic into something common that is shared between +// the two. The main thing that is different is the allocation strategy. + +#ifndef LLVM_CLANG_BUMP_VECTOR +#define LLVM_CLANG_BUMP_VECTOR + +#include "llvm/Support/type_traits.h" +#include "llvm/Support/Allocator.h" +#include "llvm/ADT/PointerIntPair.h" +#include <algorithm> +#include <cstring> +#include <iterator> +#include <memory> + +namespace clang { + +class BumpVectorContext { + llvm::PointerIntPair<llvm::BumpPtrAllocator*, 1> Alloc; +public: + /// Construct a new BumpVectorContext that creates a new BumpPtrAllocator + /// and destroys it when the BumpVectorContext object is destroyed. + BumpVectorContext() : Alloc(new llvm::BumpPtrAllocator(), 1) {} + + /// Construct a new BumpVectorContext that reuses an existing + /// BumpPtrAllocator. This BumpPtrAllocator is not destroyed when the + /// BumpVectorContext object is destroyed. + BumpVectorContext(llvm::BumpPtrAllocator &A) : Alloc(&A, 0) {} + + ~BumpVectorContext() { + if (Alloc.getInt()) + delete Alloc.getPointer(); + } + + llvm::BumpPtrAllocator &getAllocator() { return *Alloc.getPointer(); } +}; + +template<typename T> +class BumpVector { + T *Begin, *End, *Capacity; +public: + // Default ctor - Initialize to empty. + explicit BumpVector(BumpVectorContext &C, unsigned N) + : Begin(NULL), End(NULL), Capacity(NULL) { + reserve(C, N); + } + + ~BumpVector() { + if (llvm::is_class<T>::value) { + // Destroy the constructed elements in the vector. + destroy_range(Begin, End); + } + } + + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef T value_type; + typedef T* iterator; + typedef const T* const_iterator; + + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + typedef std::reverse_iterator<iterator> reverse_iterator; + + typedef T& reference; + typedef const T& const_reference; + typedef T* pointer; + typedef const T* const_pointer; + + // forward iterator creation methods. + iterator begin() { return Begin; } + const_iterator begin() const { return Begin; } + iterator end() { return End; } + const_iterator end() const { return End; } + + // reverse iterator creation methods. + reverse_iterator rbegin() { return reverse_iterator(end()); } + const_reverse_iterator rbegin() const{ return const_reverse_iterator(end()); } + reverse_iterator rend() { return reverse_iterator(begin()); } + const_reverse_iterator rend() const { return const_reverse_iterator(begin());} + + bool empty() const { return Begin == End; } + size_type size() const { return End-Begin; } + + reference operator[](unsigned idx) { + assert(Begin + idx < End); + return Begin[idx]; + } + const_reference operator[](unsigned idx) const { + assert(Begin + idx < End); + return Begin[idx]; + } + + reference front() { + return begin()[0]; + } + const_reference front() const { + return begin()[0]; + } + + reference back() { + return end()[-1]; + } + const_reference back() const { + return end()[-1]; + } + + void pop_back() { + --End; + End->~T(); + } + + T pop_back_val() { + T Result = back(); + pop_back(); + return Result; + } + + void clear() { + if (llvm::is_class<T>::value) { + destroy_range(Begin, End); + } + End = Begin; + } + + /// data - Return a pointer to the vector's buffer, even if empty(). + pointer data() { + return pointer(Begin); + } + + /// data - Return a pointer to the vector's buffer, even if empty(). + const_pointer data() const { + return const_pointer(Begin); + } + + void push_back(const_reference Elt, BumpVectorContext &C) { + if (End < Capacity) { + Retry: + new (End) T(Elt); + ++End; + return; + } + grow(C); + goto Retry; + } + + /// insert - Insert some number of copies of element into a position. Return + /// iterator to position after last inserted copy. + iterator insert(iterator I, size_t Cnt, const_reference E, + BumpVectorContext &C) { + assert (I >= Begin && I <= End && "Iterator out of bounds."); + if (End + Cnt <= Capacity) { + Retry: + move_range_right(I, End, Cnt); + construct_range(I, I + Cnt, E); + End += Cnt; + return I + Cnt; + } + ptrdiff_t D = I - Begin; + grow(C, size() + Cnt); + I = Begin + D; + goto Retry; + } + + void reserve(BumpVectorContext &C, unsigned N) { + if (unsigned(Capacity-Begin) < N) + grow(C, N); + } + + /// capacity - Return the total number of elements in the currently allocated + /// buffer. + size_t capacity() const { return Capacity - Begin; } + +private: + /// grow - double the size of the allocated memory, guaranteeing space for at + /// least one more element or MinSize if specified. + void grow(BumpVectorContext &C, size_type MinSize = 1); + + void construct_range(T *S, T *E, const T &Elt) { + for (; S != E; ++S) + new (S) T(Elt); + } + + void destroy_range(T *S, T *E) { + while (S != E) { + --E; + E->~T(); + } + } + + void move_range_right(T *S, T *E, size_t D) { + for (T *I = E + D - 1, *IL = S + D - 1; I != IL; --I) { + --E; + new (I) T(*E); + E->~T(); + } + } +}; + +// Define this out-of-line to dissuade the C++ compiler from inlining it. +template <typename T> +void BumpVector<T>::grow(BumpVectorContext &C, size_t MinSize) { + size_t CurCapacity = Capacity-Begin; + size_t CurSize = size(); + size_t NewCapacity = 2*CurCapacity; + if (NewCapacity < MinSize) + NewCapacity = MinSize; + + // Allocate the memory from the BumpPtrAllocator. + T *NewElts = C.getAllocator().template Allocate<T>(NewCapacity); + + // Copy the elements over. + if (llvm::is_class<T>::value) { + std::uninitialized_copy(Begin, End, NewElts); + // Destroy the original elements. + destroy_range(Begin, End); + } + else { + // Use memcpy for PODs (std::uninitialized_copy optimizes to memmove). + memcpy(NewElts, Begin, CurSize * sizeof(T)); + } + + // For now, leak 'Begin'. We can add it back to a freelist in + // BumpVectorContext. + Begin = NewElts; + End = NewElts+CurSize; + Capacity = Begin+NewCapacity; +} + +} // end: clang namespace +#endif // end: LLVM_CLANG_BUMP_VECTOR diff --git a/clang/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h b/clang/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h new file mode 100644 index 0000000..97eb287 --- /dev/null +++ b/clang/include/clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h @@ -0,0 +1,103 @@ +//= CFGRecStmtDeclVisitor - Recursive visitor of CFG stmts/decls -*- C++ --*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the template class CFGRecStmtDeclVisitor, which extends +// CFGRecStmtVisitor by implementing (typed) visitation of decls. +// +// FIXME: This may not be fully complete. We currently explore only subtypes +// of ScopedDecl. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_CFG_REC_STMT_DECL_VISITOR_H +#define LLVM_CLANG_ANALYSIS_CFG_REC_STMT_DECL_VISITOR_H + +#include "clang/Analysis/Visitors/CFGRecStmtVisitor.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclCXX.h" + +#define DISPATCH_CASE(CLASS) \ +case Decl::CLASS: \ +static_cast<ImplClass*>(this)->Visit##CLASS##Decl( \ + static_cast<CLASS##Decl*>(D)); \ +break; + +#define DEFAULT_DISPATCH(CLASS) void Visit##CLASS##Decl(CLASS##Decl *D) {} +#define DEFAULT_DISPATCH_VARDECL(CLASS) void Visit##CLASS##Decl(CLASS##Decl *D)\ + { static_cast<ImplClass*>(this)->VisitVarDecl(D); } + + +namespace clang { +template <typename ImplClass> +class CFGRecStmtDeclVisitor : public CFGRecStmtVisitor<ImplClass> { +public: + + void VisitDeclRefExpr(DeclRefExpr *DR) { + static_cast<ImplClass*>(this)->VisitDecl(DR->getDecl()); + } + + void VisitDeclStmt(DeclStmt *DS) { + for (DeclStmt::decl_iterator DI = DS->decl_begin(), DE = DS->decl_end(); + DI != DE; ++DI) { + Decl *D = *DI; + static_cast<ImplClass*>(this)->VisitDecl(D); + // Visit the initializer. + if (VarDecl *VD = dyn_cast<VarDecl>(D)) + if (Expr *I = VD->getInit()) + static_cast<ImplClass*>(this)->Visit(I); + } + } + + void VisitDecl(Decl *D) { + switch (D->getKind()) { + DISPATCH_CASE(Function) + DISPATCH_CASE(CXXMethod) + DISPATCH_CASE(Var) + DISPATCH_CASE(ParmVar) // FIXME: (same) + DISPATCH_CASE(ImplicitParam) + DISPATCH_CASE(EnumConstant) + DISPATCH_CASE(Typedef) + DISPATCH_CASE(Record) // FIXME: Refine. VisitStructDecl? + DISPATCH_CASE(CXXRecord) + DISPATCH_CASE(Enum) + DISPATCH_CASE(Field) + DISPATCH_CASE(UsingDirective) + DISPATCH_CASE(Using) + default: + llvm_unreachable("Subtype of ScopedDecl not handled."); + } + } + + DEFAULT_DISPATCH(Var) + DEFAULT_DISPATCH(Function) + DEFAULT_DISPATCH(CXXMethod) + DEFAULT_DISPATCH_VARDECL(ParmVar) + DEFAULT_DISPATCH(ImplicitParam) + DEFAULT_DISPATCH(EnumConstant) + DEFAULT_DISPATCH(Typedef) + DEFAULT_DISPATCH(Record) + DEFAULT_DISPATCH(Enum) + DEFAULT_DISPATCH(Field) + DEFAULT_DISPATCH(ObjCInterface) + DEFAULT_DISPATCH(ObjCMethod) + DEFAULT_DISPATCH(ObjCProtocol) + DEFAULT_DISPATCH(ObjCCategory) + DEFAULT_DISPATCH(UsingDirective) + DEFAULT_DISPATCH(Using) + + void VisitCXXRecordDecl(CXXRecordDecl *D) { + static_cast<ImplClass*>(this)->VisitRecordDecl(D); + } +}; + +} // end namespace clang + +#undef DISPATCH_CASE +#undef DEFAULT_DISPATCH +#endif diff --git a/clang/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h b/clang/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h new file mode 100644 index 0000000..4d1cabf --- /dev/null +++ b/clang/include/clang/Analysis/Visitors/CFGRecStmtVisitor.h @@ -0,0 +1,59 @@ +//==- CFGRecStmtVisitor - Recursive visitor of CFG statements ---*- C++ --*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the template class CFGRecStmtVisitor, which extends +// CFGStmtVisitor by implementing a default recursive visit of all statements. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_CFG_REC_STMT_VISITOR_H +#define LLVM_CLANG_ANALYSIS_CFG_REC_STMT_VISITOR_H + +#include "clang/Analysis/Visitors/CFGStmtVisitor.h" + +namespace clang { +template <typename ImplClass> +class CFGRecStmtVisitor : public CFGStmtVisitor<ImplClass,void> { +public: + + void VisitStmt(Stmt *S) { + static_cast< ImplClass* >(this)->VisitChildren(S); + } + + void VisitCompoundStmt(CompoundStmt *S) { + // Do nothing. Everything in a CompoundStmt is inlined + // into the CFG. + } + + void VisitConditionVariableInit(Stmt *S) { + assert(S == this->getCurrentBlkStmt()); + VarDecl *CondVar = 0; + switch (S->getStmtClass()) { +#define CONDVAR_CASE(CLASS) \ +case Stmt::CLASS ## Class:\ +CondVar = cast<CLASS>(S)->getConditionVariable();\ +break; + CONDVAR_CASE(IfStmt) + CONDVAR_CASE(ForStmt) + CONDVAR_CASE(SwitchStmt) + CONDVAR_CASE(WhileStmt) +#undef CONDVAR_CASE + default: + llvm_unreachable("Infeasible"); + } + static_cast<ImplClass*>(this)->Visit(CondVar->getInit()); + } + + // Defining operator() allows the visitor to be used as a C++ style functor. + void operator()(Stmt *S) { static_cast<ImplClass*>(this)->BlockStmt_Visit(S);} +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Analysis/Visitors/CFGStmtVisitor.h b/clang/include/clang/Analysis/Visitors/CFGStmtVisitor.h new file mode 100644 index 0000000..b354ba7 --- /dev/null +++ b/clang/include/clang/Analysis/Visitors/CFGStmtVisitor.h @@ -0,0 +1,175 @@ +//===--- CFGStmtVisitor.h - Visitor for Stmts in a CFG ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the CFGStmtVisitor interface, which extends +// StmtVisitor. This interface is useful for visiting statements in a CFG +// where some statements have implicit control-flow and thus should +// be treated specially. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_CFGSTMTVISITOR_H +#define LLVM_CLANG_ANALYSIS_CFGSTMTVISITOR_H + +#include "clang/AST/StmtVisitor.h" +#include "clang/Analysis/CFG.h" + +namespace clang { + +#define DISPATCH_CASE(CLASS) \ +case Stmt::CLASS ## Class: return \ +static_cast<ImplClass*>(this)->BlockStmt_Visit ## CLASS(static_cast<CLASS*>(S)); + +#define DEFAULT_BLOCKSTMT_VISIT(CLASS) RetTy BlockStmt_Visit ## CLASS(CLASS *S)\ +{ return\ + static_cast<ImplClass*>(this)->BlockStmt_VisitImplicitControlFlowExpr(\ + cast<Expr>(S)); } + +template <typename ImplClass, typename RetTy=void> +class CFGStmtVisitor : public StmtVisitor<ImplClass,RetTy> { + Stmt *CurrentBlkStmt; + + struct NullifyStmt { + Stmt*& S; + + NullifyStmt(Stmt*& s) : S(s) {} + ~NullifyStmt() { S = NULL; } + }; + +public: + CFGStmtVisitor() : CurrentBlkStmt(NULL) {} + + Stmt *getCurrentBlkStmt() const { return CurrentBlkStmt; } + + RetTy Visit(Stmt *S) { + if (S == CurrentBlkStmt || + !static_cast<ImplClass*>(this)->getCFG().isBlkExpr(S)) + return StmtVisitor<ImplClass,RetTy>::Visit(S); + else + return RetTy(); + } + + /// VisitConditionVariableInit - Handle the initialization of condition + /// variables at branches. Valid statements include IfStmt, ForStmt, + /// WhileStmt, and SwitchStmt. + RetTy VisitConditionVariableInit(Stmt *S) { + return RetTy(); + } + + /// BlockVisit_XXX - Visitor methods for visiting the "root" statements in + /// CFGBlocks. Root statements are the statements that appear explicitly in + /// the list of statements in a CFGBlock. For substatements, or when there + /// is no implementation provided for a BlockStmt_XXX method, we default + /// to using StmtVisitor's Visit method. + RetTy BlockStmt_Visit(Stmt *S) { + CurrentBlkStmt = S; + NullifyStmt cleanup(CurrentBlkStmt); + + switch (S->getStmtClass()) { + case Stmt::IfStmtClass: + case Stmt::ForStmtClass: + case Stmt::WhileStmtClass: + case Stmt::SwitchStmtClass: + return static_cast<ImplClass*>(this)->VisitConditionVariableInit(S); + + DISPATCH_CASE(StmtExpr) + DISPATCH_CASE(ConditionalOperator) + DISPATCH_CASE(BinaryConditionalOperator) + DISPATCH_CASE(ObjCForCollectionStmt) + DISPATCH_CASE(CXXForRangeStmt) + + case Stmt::BinaryOperatorClass: { + BinaryOperator* B = cast<BinaryOperator>(S); + if (B->isLogicalOp()) + return static_cast<ImplClass*>(this)->BlockStmt_VisitLogicalOp(B); + else if (B->getOpcode() == BO_Comma) + return static_cast<ImplClass*>(this)->BlockStmt_VisitComma(B); + // Fall through. + } + + default: + if (isa<Expr>(S)) + return + static_cast<ImplClass*>(this)->BlockStmt_VisitExpr(cast<Expr>(S)); + else + return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(S); + } + } + + DEFAULT_BLOCKSTMT_VISIT(StmtExpr) + DEFAULT_BLOCKSTMT_VISIT(ConditionalOperator) + DEFAULT_BLOCKSTMT_VISIT(BinaryConditionalOperator) + + RetTy BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) { + return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(S); + } + + RetTy BlockStmt_VisitCXXForRangeStmt(CXXForRangeStmt *S) { + return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(S); + } + + RetTy BlockStmt_VisitImplicitControlFlowExpr(Expr *E) { + return static_cast<ImplClass*>(this)->BlockStmt_VisitExpr(E); + } + + RetTy BlockStmt_VisitExpr(Expr *E) { + return static_cast<ImplClass*>(this)->BlockStmt_VisitStmt(E); + } + + RetTy BlockStmt_VisitStmt(Stmt *S) { + return static_cast<ImplClass*>(this)->Visit(S); + } + + RetTy BlockStmt_VisitLogicalOp(BinaryOperator* B) { + return + static_cast<ImplClass*>(this)->BlockStmt_VisitImplicitControlFlowExpr(B); + } + + RetTy BlockStmt_VisitComma(BinaryOperator* B) { + return + static_cast<ImplClass*>(this)->BlockStmt_VisitImplicitControlFlowExpr(B); + } + + //===--------------------------------------------------------------------===// + // Utility methods. Not called by default (but subclasses may use them). + //===--------------------------------------------------------------------===// + + /// VisitChildren: Call "Visit" on each child of S. + void VisitChildren(Stmt *S) { + + switch (S->getStmtClass()) { + default: + break; + + case Stmt::StmtExprClass: { + CompoundStmt *CS = cast<StmtExpr>(S)->getSubStmt(); + if (CS->body_empty()) return; + static_cast<ImplClass*>(this)->Visit(CS->body_back()); + return; + } + + case Stmt::BinaryOperatorClass: { + BinaryOperator* B = cast<BinaryOperator>(S); + if (B->getOpcode() != BO_Comma) break; + static_cast<ImplClass*>(this)->Visit(B->getRHS()); + return; + } + } + + for (Stmt::child_range I = S->children(); I; ++I) + if (*I) static_cast<ImplClass*>(this)->Visit(*I); + } +}; + +#undef DEFAULT_BLOCKSTMT_VISIT +#undef DISPATCH_CASE + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Basic/ABI.h b/clang/include/clang/Basic/ABI.h new file mode 100644 index 0000000..018f500 --- /dev/null +++ b/clang/include/clang/Basic/ABI.h @@ -0,0 +1,126 @@ +//===----- ABI.h - ABI related declarations ---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// These enums/classes describe ABI related information about constructors, +// destructors and thunks. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_BASIC_ABI_H +#define CLANG_BASIC_ABI_H + +#include "llvm/Support/DataTypes.h" + +namespace clang { + +/// CXXCtorType - C++ constructor types +enum CXXCtorType { + Ctor_Complete, // Complete object ctor + Ctor_Base, // Base object ctor + Ctor_CompleteAllocating // Complete object allocating ctor +}; + +/// CXXDtorType - C++ destructor types +enum CXXDtorType { + Dtor_Deleting, // Deleting dtor + Dtor_Complete, // Complete object dtor + Dtor_Base // Base object dtor +}; + +/// ReturnAdjustment - A return adjustment. +struct ReturnAdjustment { + /// NonVirtual - The non-virtual adjustment from the derived object to its + /// nearest virtual base. + int64_t NonVirtual; + + /// VBaseOffsetOffset - The offset (in bytes), relative to the address point + /// of the virtual base class offset. + int64_t VBaseOffsetOffset; + + ReturnAdjustment() : NonVirtual(0), VBaseOffsetOffset(0) { } + + bool isEmpty() const { return !NonVirtual && !VBaseOffsetOffset; } + + friend bool operator==(const ReturnAdjustment &LHS, + const ReturnAdjustment &RHS) { + return LHS.NonVirtual == RHS.NonVirtual && + LHS.VBaseOffsetOffset == RHS.VBaseOffsetOffset; + } + + friend bool operator<(const ReturnAdjustment &LHS, + const ReturnAdjustment &RHS) { + if (LHS.NonVirtual < RHS.NonVirtual) + return true; + + return LHS.NonVirtual == RHS.NonVirtual && + LHS.VBaseOffsetOffset < RHS.VBaseOffsetOffset; + } +}; + +/// ThisAdjustment - A 'this' pointer adjustment. +struct ThisAdjustment { + /// NonVirtual - The non-virtual adjustment from the derived object to its + /// nearest virtual base. + int64_t NonVirtual; + + /// VCallOffsetOffset - The offset (in bytes), relative to the address point, + /// of the virtual call offset. + int64_t VCallOffsetOffset; + + ThisAdjustment() : NonVirtual(0), VCallOffsetOffset(0) { } + + bool isEmpty() const { return !NonVirtual && !VCallOffsetOffset; } + + friend bool operator==(const ThisAdjustment &LHS, + const ThisAdjustment &RHS) { + return LHS.NonVirtual == RHS.NonVirtual && + LHS.VCallOffsetOffset == RHS.VCallOffsetOffset; + } + + friend bool operator<(const ThisAdjustment &LHS, + const ThisAdjustment &RHS) { + if (LHS.NonVirtual < RHS.NonVirtual) + return true; + + return LHS.NonVirtual == RHS.NonVirtual && + LHS.VCallOffsetOffset < RHS.VCallOffsetOffset; + } +}; + +/// ThunkInfo - The 'this' pointer adjustment as well as an optional return +/// adjustment for a thunk. +struct ThunkInfo { + /// This - The 'this' pointer adjustment. + ThisAdjustment This; + + /// Return - The return adjustment. + ReturnAdjustment Return; + + ThunkInfo() { } + + ThunkInfo(const ThisAdjustment &This, const ReturnAdjustment &Return) + : This(This), Return(Return) { } + + friend bool operator==(const ThunkInfo &LHS, const ThunkInfo &RHS) { + return LHS.This == RHS.This && LHS.Return == RHS.Return; + } + + friend bool operator<(const ThunkInfo &LHS, const ThunkInfo &RHS) { + if (LHS.This < RHS.This) + return true; + + return LHS.This == RHS.This && LHS.Return < RHS.Return; + } + + bool isEmpty() const { return This.isEmpty() && Return.isEmpty(); } +}; + +} // end namespace clang + +#endif // CLANG_BASIC_ABI_H diff --git a/clang/include/clang/Basic/AddressSpaces.h b/clang/include/clang/Basic/AddressSpaces.h new file mode 100644 index 0000000..d44a9c3 --- /dev/null +++ b/clang/include/clang/Basic/AddressSpaces.h @@ -0,0 +1,44 @@ +//===--- AddressSpaces.h - Language-specific address spaces -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides definitions for the various language-specific address +// spaces. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_ADDRESSSPACES_H +#define LLVM_CLANG_BASIC_ADDRESSSPACES_H + +namespace clang { + +namespace LangAS { + +/// This enum defines the set of possible language-specific address spaces. +/// It uses a high starting offset so as not to conflict with any address +/// space used by a target. +enum ID { + Offset = 0xFFFF00, + + opencl_global = Offset, + opencl_local, + opencl_constant, + + Last, + Count = Last-Offset +}; + +/// The type of a lookup table which maps from language-specific address spaces +/// to target-specific ones. +typedef unsigned Map[Count]; + +} + +} + +#endif diff --git a/clang/include/clang/Basic/AllDiagnostics.h b/clang/include/clang/Basic/AllDiagnostics.h new file mode 100644 index 0000000..7e77435 --- /dev/null +++ b/clang/include/clang/Basic/AllDiagnostics.h @@ -0,0 +1,39 @@ +//===--- AllDiagnostics.h - Aggregate Diagnostic headers --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file includes all the separate Diagnostic headers & some related +// helpers. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ALL_DIAGNOSTICS_H +#define LLVM_CLANG_ALL_DIAGNOSTICS_H + +#include "clang/AST/ASTDiagnostic.h" +#include "clang/Analysis/AnalysisDiagnostic.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Lex/LexDiagnostic.h" +#include "clang/Parse/ParseDiagnostic.h" +#include "clang/Sema/SemaDiagnostic.h" +#include "clang/Serialization/SerializationDiagnostic.h" + +namespace clang { +template <size_t SizeOfStr, typename FieldType> +class StringSizerHelper { + char FIELD_TOO_SMALL[SizeOfStr <= FieldType(~0U) ? 1 : -1]; +public: + enum { Size = SizeOfStr }; +}; +} // end namespace clang + +#define STR_SIZE(str, fieldTy) clang::StringSizerHelper<sizeof(str)-1, \ + fieldTy>::Size + +#endif diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td new file mode 100644 index 0000000..e8e0f35 --- /dev/null +++ b/clang/include/clang/Basic/Attr.td @@ -0,0 +1,716 @@ +//////////////////////////////////////////////////////////////////////////////// +// Note: This file is a work in progress. Please do not apply non-trivial +// updates unless you have talked to Sean Hunt <rideau3@gmail.com> prior. +// Merely adding a new attribute is a trivial update. +//////////////////////////////////////////////////////////////////////////////// + +// An attribute's subject is whatever it appertains to. In this file, it is +// more accurately a list of things that an attribute can appertain to. All +// Decls and Stmts are possibly AttrSubjects (even though the syntax may not +// allow attributes on a given Decl or Stmt). +class AttrSubject; + +include "clang/Basic/DeclNodes.td" +include "clang/Basic/StmtNodes.td" + +// A subset-subject is an AttrSubject constrained to operate only on some subset +// of that subject. +// +// The description is used in output messages to specify what the subject +// represents. FIXME: Deal with translation issues. +// +// The code fragment is a boolean expression that will confirm that the subject +// meets the requirements; the subject will have the name S, and will have the +// type specified by the base. It should be a simple boolean expression. +class SubsetSubject<AttrSubject base, string description, code check> + : AttrSubject { + AttrSubject Base = base; + string Description = description; + code CheckCode = check; +} + +// This is the type of a variable which C++0x defines [[aligned()]] as being +// a possible subject. +def NormalVar : SubsetSubject<Var, "non-register, non-parameter variable", + [{S->getStorageClass() != VarDecl::Register && + S->getKind() != Decl::ImplicitParam && + S->getKind() != Decl::ParmVar && + S->getKind() != Decl::NonTypeTemplateParm}]>; +def CXXVirtualMethod : SubsetSubject<CXXRecord, "virtual member function", + [{S->isVirtual()}]>; +def NonBitField : SubsetSubject<Field, "non-bit field", + [{!S->isBitField()}]>; + +// A single argument to an attribute +class Argument<string name> { + string Name = name; +} + +class BoolArgument<string name> : Argument<name>; +class IdentifierArgument<string name> : Argument<name>; +class IntArgument<string name> : Argument<name>; +class StringArgument<string name> : Argument<name>; +class ExprArgument<string name> : Argument<name>; +class FunctionArgument<string name> : Argument<name>; +class TypeArgument<string name> : Argument<name>; +class UnsignedArgument<string name> : Argument<name>; +class SourceLocArgument<string name> : Argument<name>; +class VariadicUnsignedArgument<string name> : Argument<name>; +class VariadicExprArgument<string name> : Argument<name>; + +// A version of the form major.minor[.subminor]. +class VersionArgument<string name> : Argument<name>; + +// This one's a doozy, so it gets its own special type +// It can be an unsigned integer, or a type. Either can +// be dependent. +class AlignedArgument<string name> : Argument<name>; + +// An integer argument with a default value +class DefaultIntArgument<string name, int default> : IntArgument<name> { + int Default = default; +} + +// This argument is more complex, it includes the enumerator type name, +// a list of strings to accept, and a list of enumerators to map them to. +class EnumArgument<string name, string type, list<string> values, + list<string> enums> : Argument<name> { + string Type = type; + list<string> Values = values; + list<string> Enums = enums; +} + +class Attr { + // The various ways in which an attribute can be spelled in source + list<string> Spellings; + // The things to which an attribute can appertain + list<AttrSubject> Subjects; + // The arguments allowed on an attribute + list<Argument> Args = []; + // The namespaces in which the attribute appears in C++0x attributes. + // The attribute will not be permitted in C++0x attribute-specifiers if + // this is empty; the empty string can be used as a namespace. + list<string> Namespaces = []; + // Set to true for attributes with arguments which require delayed parsing. + bit LateParsed = 0; + // Set to true for attributes which must be instantiated within templates + bit TemplateDependent = 0; + // Set to true for attributes which have handler in Sema. + bit SemaHandler = 1; + // Any additional text that should be included verbatim in the class. + code AdditionalMembers = [{}]; +} + +/// An inheritable attribute is inherited by later redeclarations. +class InheritableAttr : Attr; + +/// An inheritable parameter attribute is inherited by later +/// redeclarations, even when it's written on a parameter. +class InheritableParamAttr : InheritableAttr; + +// +// Attributes begin here +// + +def Alias : InheritableAttr { + let Spellings = ["alias"]; + let Args = [StringArgument<"Aliasee">]; +} + +def Aligned : InheritableAttr { + let Spellings = ["aligned"]; + let Subjects = [NonBitField, NormalVar, Tag]; + let Args = [AlignedArgument<"Alignment">]; + let Namespaces = ["", "std"]; +} + +def AlignMac68k : InheritableAttr { + let Spellings = []; + let SemaHandler = 0; +} + +def AlwaysInline : InheritableAttr { + let Spellings = ["always_inline"]; +} + +def AnalyzerNoReturn : InheritableAttr { + let Spellings = ["analyzer_noreturn"]; +} + +def Annotate : InheritableParamAttr { + let Spellings = ["annotate"]; + let Args = [StringArgument<"Annotation">]; +} + +def AsmLabel : InheritableAttr { + let Spellings = []; + let Args = [StringArgument<"Label">]; + let SemaHandler = 0; +} + +def Availability : InheritableAttr { + let Spellings = ["availability"]; + let Args = [IdentifierArgument<"platform">, VersionArgument<"introduced">, + VersionArgument<"deprecated">, VersionArgument<"obsoleted">, + BoolArgument<"unavailable">, StringArgument<"message">]; + let AdditionalMembers = +[{static llvm::StringRef getPrettyPlatformName(llvm::StringRef Platform) { + return llvm::StringSwitch<llvm::StringRef>(Platform) + .Case("ios", "iOS") + .Case("macosx", "Mac OS X") + .Default(llvm::StringRef()); +} }]; +} + +def Blocks : InheritableAttr { + let Spellings = ["blocks"]; + let Args = [EnumArgument<"Type", "BlockType", ["byref"], ["ByRef"]>]; +} + +def CarriesDependency : InheritableParamAttr { + let Spellings = ["carries_dependency"]; + let Subjects = [ParmVar, Function]; + let Namespaces = ["", "std"]; +} + +def CDecl : InheritableAttr { + let Spellings = ["cdecl", "__cdecl"]; +} + +// cf_audited_transfer indicates that the given function has been +// audited and has been marked with the appropriate cf_consumed and +// cf_returns_retained attributes. It is generally applied by +// '#pragma clang arc_cf_code_audited' rather than explicitly. +def CFAuditedTransfer : InheritableAttr { + let Spellings = ["cf_audited_transfer"]; + let Subjects = [Function]; +} + +// cf_unknown_transfer is an explicit opt-out of cf_audited_transfer. +// It indicates that the function has unknown or unautomatable +// transfer semantics. +def CFUnknownTransfer : InheritableAttr { + let Spellings = ["cf_unknown_transfer"]; + let Subjects = [Function]; +} + +def CFReturnsRetained : InheritableAttr { + let Spellings = ["cf_returns_retained"]; + let Subjects = [ObjCMethod, Function]; +} + +def CFReturnsNotRetained : InheritableAttr { + let Spellings = ["cf_returns_not_retained"]; + let Subjects = [ObjCMethod, Function]; +} + +def CFConsumed : InheritableParamAttr { + let Spellings = ["cf_consumed"]; + let Subjects = [ParmVar]; +} + +def Cleanup : InheritableAttr { + let Spellings = ["cleanup"]; + let Args = [FunctionArgument<"FunctionDecl">]; +} + +def Common : InheritableAttr { + let Spellings = ["common"]; +} + +def Const : InheritableAttr { + let Spellings = ["const"]; +} + +def Constructor : InheritableAttr { + let Spellings = ["constructor"]; + let Args = [IntArgument<"Priority">]; +} + +def CUDAConstant : InheritableAttr { + let Spellings = ["constant"]; +} + +def CUDADevice : Attr { + let Spellings = ["device"]; +} + +def CUDAGlobal : InheritableAttr { + let Spellings = ["global"]; +} + +def CUDAHost : Attr { + let Spellings = ["host"]; +} + +def CUDALaunchBounds : InheritableAttr { + let Spellings = ["launch_bounds"]; + let Args = [IntArgument<"MaxThreads">, DefaultIntArgument<"MinBlocks", 0>]; +} + +def CUDAShared : InheritableAttr { + let Spellings = ["shared"]; +} + +def OpenCLKernel : Attr { + let Spellings = ["opencl_kernel_function"]; +} + +def Deprecated : InheritableAttr { + let Spellings = ["deprecated"]; + let Args = [StringArgument<"Message">]; +} + +def Destructor : InheritableAttr { + let Spellings = ["destructor"]; + let Args = [IntArgument<"Priority">]; +} + +def DLLExport : InheritableAttr { + let Spellings = ["dllexport"]; +} + +def DLLImport : InheritableAttr { + let Spellings = ["dllimport"]; +} + +def FastCall : InheritableAttr { + let Spellings = ["fastcall", "__fastcall"]; +} + +def Final : InheritableAttr { + let Spellings = []; + let SemaHandler = 0; +} + +def MsStruct : InheritableAttr { + let Spellings = ["__ms_struct__"]; +} + +def Format : InheritableAttr { + let Spellings = ["format"]; + let Args = [StringArgument<"Type">, IntArgument<"FormatIdx">, + IntArgument<"FirstArg">]; +} + +def FormatArg : InheritableAttr { + let Spellings = ["format_arg"]; + let Args = [IntArgument<"FormatIdx">]; +} + +def GNUInline : InheritableAttr { + let Spellings = ["gnu_inline"]; +} + +def IBAction : InheritableAttr { + let Spellings = ["ibaction"]; +} + +def IBOutlet : InheritableAttr { + let Spellings = ["iboutlet"]; +} + +def IBOutletCollection : InheritableAttr { + let Spellings = ["iboutletcollection"]; + let Args = [TypeArgument<"Interface">, SourceLocArgument<"InterfaceLoc">]; +} + +def Malloc : InheritableAttr { + let Spellings = ["malloc"]; +} + +def MaxFieldAlignment : InheritableAttr { + let Spellings = []; + let Args = [UnsignedArgument<"Alignment">]; + let SemaHandler = 0; +} + +def MayAlias : InheritableAttr { + let Spellings = ["may_alias"]; +} + +def MSP430Interrupt : InheritableAttr { + let Spellings = []; + let Args = [UnsignedArgument<"Number">]; + let SemaHandler = 0; +} + +def MBlazeInterruptHandler : InheritableAttr { + let Spellings = []; + let SemaHandler = 0; +} + +def MBlazeSaveVolatiles : InheritableAttr { + let Spellings = []; + let SemaHandler = 0; +} + +def Naked : InheritableAttr { + let Spellings = ["naked"]; +} + +def ReturnsTwice : InheritableAttr { + let Spellings = ["returns_twice"]; +} + +def NoCommon : InheritableAttr { + let Spellings = ["nocommon"]; +} + +def NoDebug : InheritableAttr { + let Spellings = ["nodebug"]; +} + +def NoInline : InheritableAttr { + let Spellings = ["noinline"]; +} + +def NonNull : InheritableAttr { + let Spellings = ["nonnull"]; + let Args = [VariadicUnsignedArgument<"Args">]; + let AdditionalMembers = +[{bool isNonNull(unsigned idx) const { + for (args_iterator i = args_begin(), e = args_end(); + i != e; ++i) + if (*i == idx) + return true; + return false; + } }]; +} + +def NoReturn : InheritableAttr { + let Spellings = ["noreturn"]; + // FIXME: Does GCC allow this on the function instead? + let Subjects = [Function]; + let Namespaces = ["", "std"]; +} + +def NoInstrumentFunction : InheritableAttr { + let Spellings = ["no_instrument_function"]; + let Subjects = [Function]; +} + +def NoThrow : InheritableAttr { + let Spellings = ["nothrow"]; +} + +def NSBridged : InheritableAttr { + let Spellings = ["ns_bridged"]; + let Subjects = [Record]; + let Args = [IdentifierArgument<"BridgedType">]; +} + +def NSReturnsRetained : InheritableAttr { + let Spellings = ["ns_returns_retained"]; + let Subjects = [ObjCMethod, Function]; +} + +def NSReturnsNotRetained : InheritableAttr { + let Spellings = ["ns_returns_not_retained"]; + let Subjects = [ObjCMethod, Function]; +} + +def NSReturnsAutoreleased : InheritableAttr { + let Spellings = ["ns_returns_autoreleased"]; + let Subjects = [ObjCMethod, Function]; +} + +def NSConsumesSelf : InheritableAttr { + let Spellings = ["ns_consumes_self"]; + let Subjects = [ObjCMethod]; +} + +def NSConsumed : InheritableParamAttr { + let Spellings = ["ns_consumed"]; + let Subjects = [ParmVar]; +} + +def ObjCException : InheritableAttr { + let Spellings = ["objc_exception"]; +} + +def ObjCMethodFamily : InheritableAttr { + let Spellings = ["objc_method_family"]; + let Subjects = [ObjCMethod]; + let Args = [EnumArgument<"Family", "FamilyKind", + ["none", "alloc", "copy", "init", "mutableCopy", "new"], + ["OMF_None", "OMF_alloc", "OMF_copy", "OMF_init", + "OMF_mutableCopy", "OMF_new"]>]; +} + +def ObjCNSObject : InheritableAttr { + let Spellings = ["NSObject"]; +} + +def ObjCPreciseLifetime : Attr { + let Spellings = ["objc_precise_lifetime"]; + let Subjects = [Var]; +} + +def ObjCReturnsInnerPointer : Attr { + let Spellings = ["objc_returns_inner_pointer"]; + let Subjects = [ObjCMethod]; +} + +def ObjCRootClass : Attr { + let Spellings = ["objc_root_class"]; + let Subjects = [ObjCInterface]; +} + +def Overloadable : Attr { + let Spellings = ["overloadable"]; +} + +def Override : InheritableAttr { + let Spellings = []; + let SemaHandler = 0; +} + +def Ownership : InheritableAttr { + let Spellings = ["ownership_holds", "ownership_returns", "ownership_takes"]; + let Args = [EnumArgument<"OwnKind", "OwnershipKind", + ["ownership_holds", "ownership_returns", "ownership_takes"], + ["Holds", "Returns", "Takes"]>, + StringArgument<"Module">, VariadicUnsignedArgument<"Args">]; +} + +def Packed : InheritableAttr { + let Spellings = ["packed"]; +} + +def Pcs : InheritableAttr { + let Spellings = ["pcs"]; + let Args = [EnumArgument<"PCS", "PCSType", + ["aapcs", "aapcs-vfp"], + ["AAPCS", "AAPCS_VFP"]>]; +} + +def Pure : InheritableAttr { + let Spellings = ["pure"]; +} + +def Regparm : InheritableAttr { + let Spellings = ["regparm"]; + let Args = [UnsignedArgument<"NumParams">]; +} + +def ReqdWorkGroupSize : InheritableAttr { + let Spellings = ["reqd_work_group_size"]; + let Args = [UnsignedArgument<"XDim">, UnsignedArgument<"YDim">, + UnsignedArgument<"ZDim">]; +} + +def InitPriority : InheritableAttr { + let Spellings = ["init_priority"]; + let Args = [UnsignedArgument<"Priority">]; +} + +def Section : InheritableAttr { + let Spellings = ["section"]; + let Args = [StringArgument<"Name">]; +} + +def Sentinel : InheritableAttr { + let Spellings = ["sentinel"]; + let Args = [DefaultIntArgument<"Sentinel", 0>, + DefaultIntArgument<"NullPos", 0>]; +} + +def StdCall : InheritableAttr { + let Spellings = ["stdcall", "__stdcall"]; +} + +def ThisCall : InheritableAttr { + let Spellings = ["thiscall", "__thiscall"]; +} + +def Pascal : InheritableAttr { + let Spellings = ["pascal", "__pascal"]; +} + +def TransparentUnion : InheritableAttr { + let Spellings = ["transparent_union"]; +} + +def Unavailable : InheritableAttr { + let Spellings = ["unavailable"]; + let Args = [StringArgument<"Message">]; +} + +def ArcWeakrefUnavailable : InheritableAttr { + let Spellings = ["objc_arc_weak_reference_unavailable"]; + let Subjects = [ObjCInterface]; +} + +def ObjCRequiresPropertyDefs : InheritableAttr { + let Spellings = ["objc_requires_property_definitions"]; + let Subjects = [ObjCInterface]; +} + +def Unused : InheritableAttr { + let Spellings = ["unused"]; +} + +def Used : InheritableAttr { + let Spellings = ["used"]; +} + +def Uuid : InheritableAttr { + let Spellings = ["uuid"]; + let Args = [StringArgument<"Guid">]; + let Subjects = [CXXRecord]; +} + +def Visibility : InheritableAttr { + let Spellings = ["visibility"]; + let Args = [EnumArgument<"Visibility", "VisibilityType", + ["default", "hidden", "internal", "protected"], + ["Default", "Hidden", "Hidden", "Protected"]>]; +} + +def VecReturn : InheritableAttr { + let Spellings = ["vecreturn"]; + let Subjects = [CXXRecord]; +} + +def WarnUnusedResult : InheritableAttr { + let Spellings = ["warn_unused_result"]; +} + +def Weak : InheritableAttr { + let Spellings = ["weak"]; +} + +def WeakImport : InheritableAttr { + let Spellings = ["weak_import"]; +} + +def WeakRef : InheritableAttr { + let Spellings = ["weakref"]; +} + +def X86ForceAlignArgPointer : InheritableAttr { + let Spellings = []; +} + +// AddressSafety attribute (e.g. for AddressSanitizer) +def NoAddressSafetyAnalysis : InheritableAttr { + let Spellings = ["no_address_safety_analysis"]; +} + +// C/C++ Thread safety attributes (e.g. for deadlock, data race checking) + +def GuardedVar : InheritableAttr { + let Spellings = ["guarded_var"]; +} + +def PtGuardedVar : InheritableAttr { + let Spellings = ["pt_guarded_var"]; +} + +def Lockable : InheritableAttr { + let Spellings = ["lockable"]; +} + +def ScopedLockable : InheritableAttr { + let Spellings = ["scoped_lockable"]; +} + +def NoThreadSafetyAnalysis : InheritableAttr { + let Spellings = ["no_thread_safety_analysis"]; +} + +def GuardedBy : InheritableAttr { + let Spellings = ["guarded_by"]; + let Args = [ExprArgument<"Arg">]; + let LateParsed = 1; + let TemplateDependent = 1; +} + +def PtGuardedBy : InheritableAttr { + let Spellings = ["pt_guarded_by"]; + let Args = [ExprArgument<"Arg">]; + let LateParsed = 1; + let TemplateDependent = 1; +} + +def AcquiredAfter : InheritableAttr { + let Spellings = ["acquired_after"]; + let Args = [VariadicExprArgument<"Args">]; + let LateParsed = 1; + let TemplateDependent = 1; +} + +def AcquiredBefore : InheritableAttr { + let Spellings = ["acquired_before"]; + let Args = [VariadicExprArgument<"Args">]; + let LateParsed = 1; + let TemplateDependent = 1; +} + +def ExclusiveLockFunction : InheritableAttr { + let Spellings = ["exclusive_lock_function"]; + let Args = [VariadicExprArgument<"Args">]; + let LateParsed = 1; + let TemplateDependent = 1; +} + +def SharedLockFunction : InheritableAttr { + let Spellings = ["shared_lock_function"]; + let Args = [VariadicExprArgument<"Args">]; + let LateParsed = 1; + let TemplateDependent = 1; +} + +// The first argument is an integer or boolean value specifying the return value +// of a successful lock acquisition. +def ExclusiveTrylockFunction : InheritableAttr { + let Spellings = ["exclusive_trylock_function"]; + let Args = [ExprArgument<"SuccessValue">, VariadicExprArgument<"Args">]; + let LateParsed = 1; + let TemplateDependent = 1; +} + +// The first argument is an integer or boolean value specifying the return value +// of a successful lock acquisition. +def SharedTrylockFunction : InheritableAttr { + let Spellings = ["shared_trylock_function"]; + let Args = [ExprArgument<"SuccessValue">, VariadicExprArgument<"Args">]; + let LateParsed = 1; + let TemplateDependent = 1; +} + +def UnlockFunction : InheritableAttr { + let Spellings = ["unlock_function"]; + let Args = [VariadicExprArgument<"Args">]; + let LateParsed = 1; + let TemplateDependent = 1; +} + +def LockReturned : InheritableAttr { + let Spellings = ["lock_returned"]; + let Args = [ExprArgument<"Arg">]; + let LateParsed = 1; + let TemplateDependent = 1; +} + +def LocksExcluded : InheritableAttr { + let Spellings = ["locks_excluded"]; + let Args = [VariadicExprArgument<"Args">]; + let LateParsed = 1; + let TemplateDependent = 1; +} + +def ExclusiveLocksRequired : InheritableAttr { + let Spellings = ["exclusive_locks_required"]; + let Args = [VariadicExprArgument<"Args">]; + let LateParsed = 1; + let TemplateDependent = 1; +} + +def SharedLocksRequired : InheritableAttr { + let Spellings = ["shared_locks_required"]; + let Args = [VariadicExprArgument<"Args">]; + let LateParsed = 1; + let TemplateDependent = 1; +} diff --git a/clang/include/clang/Basic/AttrKinds.h b/clang/include/clang/Basic/AttrKinds.h new file mode 100644 index 0000000..9d5ae58 --- /dev/null +++ b/clang/include/clang/Basic/AttrKinds.h @@ -0,0 +1,33 @@ +//===----- Attr.h - Enum values for C Attribute Kinds ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the attr::Kind enum +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ATTRKINDS_H +#define LLVM_CLANG_ATTRKINDS_H + +namespace clang { + +namespace attr { + +// Kind - This is a list of all the recognized kinds of attributes. +enum Kind { +#define ATTR(X) X, +#define LAST_INHERITABLE_ATTR(X) X, LAST_INHERITABLE = X, +#define LAST_INHERITABLE_PARAM_ATTR(X) X, LAST_INHERITABLE_PARAM = X, +#include "clang/Basic/AttrList.inc" + NUM_ATTRS +}; + +} // end namespace attr +} // end namespace clang + +#endif diff --git a/clang/include/clang/Basic/Builtins.def b/clang/include/clang/Basic/Builtins.def new file mode 100644 index 0000000..d1af218 --- /dev/null +++ b/clang/include/clang/Basic/Builtins.def @@ -0,0 +1,836 @@ +//===--- Builtins.def - Builtin function info database ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the standard builtin function database. Users of this file +// must define the BUILTIN macro to make use of this information. +// +//===----------------------------------------------------------------------===// + +// FIXME: This should really be a .td file, but that requires modifying tblgen. +// Perhaps tblgen should have plugins. + +// The first value provided to the macro specifies the function name of the +// builtin, and results in a clang::builtin::BIXX enum value for XX. + +// The second value provided to the macro specifies the type of the function +// (result value, then each argument) as follows: +// v -> void +// b -> boolean +// c -> char +// s -> short +// i -> int +// f -> float +// d -> double +// z -> size_t +// F -> constant CFString +// G -> id +// H -> SEL +// a -> __builtin_va_list +// A -> "reference" to __builtin_va_list +// V -> Vector, following num elements and a base type. +// X -> _Complex, followed by the base type. +// Y -> ptrdiff_t +// P -> FILE +// J -> jmp_buf +// SJ -> sigjmp_buf +// K -> ucontext_t +// . -> "...". This may only occur at the end of the function list. +// +// Types may be prefixed with the following modifiers: +// L -> long (e.g. Li for 'long int') +// LL -> long long +// LLL -> __int128_t (e.g. LLLi) +// S -> signed +// U -> unsigned +// I -> Required to constant fold to an integer constant expression. +// +// Types may be postfixed with the following modifiers: +// * -> pointer (optionally followed by an address space number) +// & -> reference (optionally followed by an address space number) +// C -> const +// D -> volatile + +// The third value provided to the macro specifies information about attributes +// of the function. These must be kept in sync with the predicates in the +// Builtin::Context class. Currently we have: +// n -> nothrow +// r -> noreturn +// c -> const +// t -> signature is meaningless, use custom typechecking +// F -> this is a libc/libm function with a '__builtin_' prefix added. +// f -> this is a libc/libm function without the '__builtin_' prefix. It can +// be followed by ':headername:' to state which header this function +// comes from. +// p:N: -> this is a printf-like function whose Nth argument is the format +// string. +// P:N: -> similar to the p:N: attribute, but the function is like vprintf +// in that it accepts its arguments as a va_list rather than +// through an ellipsis +// s:N: -> this is a scanf-like function whose Nth argument is the format +// string. +// S:N: -> similar to the s:N: attribute, but the function is like vscanf +// in that it accepts its arguments as a va_list rather than +// through an ellipsis +// e -> const, but only when -fmath-errno=0 +// j -> returns_twice (like setjmp) +// FIXME: gcc has nonnull + +#if defined(BUILTIN) && !defined(LIBBUILTIN) +# define LIBBUILTIN(ID, TYPE, ATTRS, HEADER, BUILTIN_LANG) BUILTIN(ID, TYPE, ATTRS) +#endif + +// Standard libc/libm functions: +BUILTIN(__builtin_atan2 , "ddd" , "Fnc") +BUILTIN(__builtin_atan2f, "fff" , "Fnc") +BUILTIN(__builtin_atan2l, "LdLdLd", "Fnc") +BUILTIN(__builtin_abs , "ii" , "ncF") +BUILTIN(__builtin_copysign, "ddd", "ncF") +BUILTIN(__builtin_copysignf, "fff", "ncF") +BUILTIN(__builtin_copysignl, "LdLdLd", "ncF") +BUILTIN(__builtin_fabs , "dd" , "ncF") +BUILTIN(__builtin_fabsf, "ff" , "ncF") +BUILTIN(__builtin_fabsl, "LdLd", "ncF") +BUILTIN(__builtin_fmod , "ddd" , "Fnc") +BUILTIN(__builtin_fmodf, "fff" , "Fnc") +BUILTIN(__builtin_fmodl, "LdLdLd", "Fnc") +BUILTIN(__builtin_frexp , "ddi*" , "Fn") +BUILTIN(__builtin_frexpf, "ffi*" , "Fn") +BUILTIN(__builtin_frexpl, "LdLdi*", "Fn") +BUILTIN(__builtin_huge_val, "d", "nc") +BUILTIN(__builtin_huge_valf, "f", "nc") +BUILTIN(__builtin_huge_vall, "Ld", "nc") +BUILTIN(__builtin_inf , "d" , "nc") +BUILTIN(__builtin_inff , "f" , "nc") +BUILTIN(__builtin_infl , "Ld" , "nc") +BUILTIN(__builtin_labs , "LiLi" , "Fnc") +BUILTIN(__builtin_llabs, "LLiLLi", "Fnc") +BUILTIN(__builtin_ldexp , "ddi" , "Fnc") +BUILTIN(__builtin_ldexpf, "ffi" , "Fnc") +BUILTIN(__builtin_ldexpl, "LdLdi", "Fnc") +BUILTIN(__builtin_modf , "ddd*" , "Fn") +BUILTIN(__builtin_modff, "fff*" , "Fn") +BUILTIN(__builtin_modfl, "LdLdLd*", "Fn") +BUILTIN(__builtin_nan, "dcC*" , "ncF") +BUILTIN(__builtin_nanf, "fcC*" , "ncF") +BUILTIN(__builtin_nanl, "LdcC*", "ncF") +BUILTIN(__builtin_nans, "dcC*" , "ncF") +BUILTIN(__builtin_nansf, "fcC*" , "ncF") +BUILTIN(__builtin_nansl, "LdcC*", "ncF") +BUILTIN(__builtin_powi , "ddi" , "Fnc") +BUILTIN(__builtin_powif, "ffi" , "Fnc") +BUILTIN(__builtin_powil, "LdLdi", "Fnc") +BUILTIN(__builtin_pow , "ddd" , "Fnc") +BUILTIN(__builtin_powf, "fff" , "Fnc") +BUILTIN(__builtin_powl, "LdLdLd", "Fnc") + +// Standard unary libc/libm functions with double/float/long double variants: +BUILTIN(__builtin_acos , "dd" , "Fnc") +BUILTIN(__builtin_acosf, "ff" , "Fnc") +BUILTIN(__builtin_acosl, "LdLd", "Fnc") +BUILTIN(__builtin_acosh , "dd" , "Fnc") +BUILTIN(__builtin_acoshf, "ff" , "Fnc") +BUILTIN(__builtin_acoshl, "LdLd", "Fnc") +BUILTIN(__builtin_asin , "dd" , "Fnc") +BUILTIN(__builtin_asinf, "ff" , "Fnc") +BUILTIN(__builtin_asinl, "LdLd", "Fnc") +BUILTIN(__builtin_asinh , "dd" , "Fnc") +BUILTIN(__builtin_asinhf, "ff" , "Fnc") +BUILTIN(__builtin_asinhl, "LdLd", "Fnc") +BUILTIN(__builtin_atan , "dd" , "Fnc") +BUILTIN(__builtin_atanf, "ff" , "Fnc") +BUILTIN(__builtin_atanl, "LdLd", "Fnc") +BUILTIN(__builtin_atanh , "dd", "Fnc") +BUILTIN(__builtin_atanhf, "ff", "Fnc") +BUILTIN(__builtin_atanhl, "LdLd", "Fnc") +BUILTIN(__builtin_cbrt , "dd", "Fnc") +BUILTIN(__builtin_cbrtf, "ff", "Fnc") +BUILTIN(__builtin_cbrtl, "LdLd", "Fnc") +BUILTIN(__builtin_ceil , "dd" , "Fnc") +BUILTIN(__builtin_ceilf, "ff" , "Fnc") +BUILTIN(__builtin_ceill, "LdLd", "Fnc") +BUILTIN(__builtin_cos , "dd" , "Fnc") +BUILTIN(__builtin_cosf, "ff" , "Fnc") +BUILTIN(__builtin_cosh , "dd" , "Fnc") +BUILTIN(__builtin_coshf, "ff" , "Fnc") +BUILTIN(__builtin_coshl, "LdLd", "Fnc") +BUILTIN(__builtin_cosl, "LdLd", "Fnc") +BUILTIN(__builtin_erf , "dd", "Fnc") +BUILTIN(__builtin_erff, "ff", "Fnc") +BUILTIN(__builtin_erfl, "LdLd", "Fnc") +BUILTIN(__builtin_erfc , "dd", "Fnc") +BUILTIN(__builtin_erfcf, "ff", "Fnc") +BUILTIN(__builtin_erfcl, "LdLd", "Fnc") +BUILTIN(__builtin_exp , "dd" , "Fnc") +BUILTIN(__builtin_expf, "ff" , "Fnc") +BUILTIN(__builtin_expl, "LdLd", "Fnc") +BUILTIN(__builtin_exp2 , "dd" , "Fnc") +BUILTIN(__builtin_exp2f, "ff" , "Fnc") +BUILTIN(__builtin_exp2l, "LdLd", "Fnc") +BUILTIN(__builtin_expm1 , "dd", "Fnc") +BUILTIN(__builtin_expm1f, "ff", "Fnc") +BUILTIN(__builtin_expm1l, "LdLd", "Fnc") +BUILTIN(__builtin_fdim, "ddd", "Fnc") +BUILTIN(__builtin_fdimf, "fff", "Fnc") +BUILTIN(__builtin_fdiml, "LdLdLd", "Fnc") +BUILTIN(__builtin_floor , "dd" , "Fnc") +BUILTIN(__builtin_floorf, "ff" , "Fnc") +BUILTIN(__builtin_floorl, "LdLd", "Fnc") +BUILTIN(__builtin_fma, "dddd", "Fnc") +BUILTIN(__builtin_fmaf, "ffff", "Fnc") +BUILTIN(__builtin_fmal, "LdLdLdLd", "Fnc") +BUILTIN(__builtin_fmax, "ddd", "Fnc") +BUILTIN(__builtin_fmaxf, "fff", "Fnc") +BUILTIN(__builtin_fmaxl, "LdLdLd", "Fnc") +BUILTIN(__builtin_fmin, "ddd", "Fnc") +BUILTIN(__builtin_fminf, "fff", "Fnc") +BUILTIN(__builtin_fminl, "LdLdLd", "Fnc") +BUILTIN(__builtin_hypot , "ddd" , "Fnc") +BUILTIN(__builtin_hypotf, "fff" , "Fnc") +BUILTIN(__builtin_hypotl, "LdLdLd", "Fnc") +BUILTIN(__builtin_ilogb , "id", "Fnc") +BUILTIN(__builtin_ilogbf, "if", "Fnc") +BUILTIN(__builtin_ilogbl, "iLd", "Fnc") +BUILTIN(__builtin_lgamma , "dd", "Fnc") +BUILTIN(__builtin_lgammaf, "ff", "Fnc") +BUILTIN(__builtin_lgammal, "LdLd", "Fnc") +BUILTIN(__builtin_llrint, "LLid", "Fnc") +BUILTIN(__builtin_llrintf, "LLif", "Fnc") +BUILTIN(__builtin_llrintl, "LLiLd", "Fnc") +BUILTIN(__builtin_llround , "LLid", "Fnc") +BUILTIN(__builtin_llroundf, "LLif", "Fnc") +BUILTIN(__builtin_llroundl, "LLiLd", "Fnc") +BUILTIN(__builtin_log , "dd" , "Fnc") +BUILTIN(__builtin_log10 , "dd" , "Fnc") +BUILTIN(__builtin_log10f, "ff" , "Fnc") +BUILTIN(__builtin_log10l, "LdLd", "Fnc") +BUILTIN(__builtin_log1p , "dd" , "Fnc") +BUILTIN(__builtin_log1pf, "ff" , "Fnc") +BUILTIN(__builtin_log1pl, "LdLd", "Fnc") +BUILTIN(__builtin_log2, "dd" , "Fnc") +BUILTIN(__builtin_log2f, "ff" , "Fnc") +BUILTIN(__builtin_log2l, "LdLd" , "Fnc") +BUILTIN(__builtin_logb , "dd", "Fnc") +BUILTIN(__builtin_logbf, "ff", "Fnc") +BUILTIN(__builtin_logbl, "LdLd", "Fnc") +BUILTIN(__builtin_logf, "ff" , "Fnc") +BUILTIN(__builtin_logl, "LdLd", "Fnc") +BUILTIN(__builtin_lrint , "Lid", "Fnc") +BUILTIN(__builtin_lrintf, "Lif", "Fnc") +BUILTIN(__builtin_lrintl, "LiLd", "Fnc") +BUILTIN(__builtin_lround , "Lid", "Fnc") +BUILTIN(__builtin_lroundf, "Lif", "Fnc") +BUILTIN(__builtin_lroundl, "LiLd", "Fnc") +BUILTIN(__builtin_nearbyint , "dd", "Fnc") +BUILTIN(__builtin_nearbyintf, "ff", "Fnc") +BUILTIN(__builtin_nearbyintl, "LdLd", "Fnc") +BUILTIN(__builtin_nextafter , "ddd", "Fnc") +BUILTIN(__builtin_nextafterf, "fff", "Fnc") +BUILTIN(__builtin_nextafterl, "LdLdLd", "Fnc") +BUILTIN(__builtin_nexttoward , "ddd", "Fnc") +BUILTIN(__builtin_nexttowardf, "fff", "Fnc") +BUILTIN(__builtin_nexttowardl, "LdLdLd", "Fnc") +BUILTIN(__builtin_remainder , "ddd", "Fnc") +BUILTIN(__builtin_remainderf, "fff", "Fnc") +BUILTIN(__builtin_remainderl, "LdLdLd", "Fnc") +BUILTIN(__builtin_remquo , "dddi*", "Fn") +BUILTIN(__builtin_remquof, "fffi*", "Fn") +BUILTIN(__builtin_remquol, "LdLdLdi*", "Fn") +BUILTIN(__builtin_rint , "dd", "Fnc") +BUILTIN(__builtin_rintf, "ff", "Fnc") +BUILTIN(__builtin_rintl, "LdLd", "Fnc") +BUILTIN(__builtin_round, "dd" , "Fnc") +BUILTIN(__builtin_roundf, "ff" , "Fnc") +BUILTIN(__builtin_roundl, "LdLd" , "Fnc") +BUILTIN(__builtin_scalbln , "ddLi", "Fnc") +BUILTIN(__builtin_scalblnf, "ffLi", "Fnc") +BUILTIN(__builtin_scalblnl, "LdLdLi", "Fnc") +BUILTIN(__builtin_scalbn , "ddi", "Fnc") +BUILTIN(__builtin_scalbnf, "ffi", "Fnc") +BUILTIN(__builtin_scalbnl, "LdLdi", "Fnc") +BUILTIN(__builtin_sin , "dd" , "Fnc") +BUILTIN(__builtin_sinf, "ff" , "Fnc") +BUILTIN(__builtin_sinh , "dd" , "Fnc") +BUILTIN(__builtin_sinhf, "ff" , "Fnc") +BUILTIN(__builtin_sinhl, "LdLd", "Fnc") +BUILTIN(__builtin_sinl, "LdLd", "Fnc") +BUILTIN(__builtin_sqrt , "dd" , "Fnc") +BUILTIN(__builtin_sqrtf, "ff" , "Fnc") +BUILTIN(__builtin_sqrtl, "LdLd", "Fnc") +BUILTIN(__builtin_tan , "dd" , "Fnc") +BUILTIN(__builtin_tanf, "ff" , "Fnc") +BUILTIN(__builtin_tanh , "dd" , "Fnc") +BUILTIN(__builtin_tanhf, "ff" , "Fnc") +BUILTIN(__builtin_tanhl, "LdLd", "Fnc") +BUILTIN(__builtin_tanl, "LdLd", "Fnc") +BUILTIN(__builtin_tgamma , "dd", "Fnc") +BUILTIN(__builtin_tgammaf, "ff", "Fnc") +BUILTIN(__builtin_tgammal, "LdLd", "Fnc") +BUILTIN(__builtin_trunc , "dd", "Fnc") +BUILTIN(__builtin_truncf, "ff", "Fnc") +BUILTIN(__builtin_truncl, "LdLd", "Fnc") + +// C99 complex builtins +BUILTIN(__builtin_cabs, "dXd", "Fnc") +BUILTIN(__builtin_cabsf, "fXf", "Fnc") +BUILTIN(__builtin_cabsl, "LdXLd", "Fnc") +BUILTIN(__builtin_cacos, "XdXd", "Fnc") +BUILTIN(__builtin_cacosf, "XfXf", "Fnc") +BUILTIN(__builtin_cacosh, "XdXd", "Fnc") +BUILTIN(__builtin_cacoshf, "XfXf", "Fnc") +BUILTIN(__builtin_cacoshl, "XLdXLd", "Fnc") +BUILTIN(__builtin_cacosl, "XLdXLd", "Fnc") +BUILTIN(__builtin_carg, "dXd", "Fnc") +BUILTIN(__builtin_cargf, "fXf", "Fnc") +BUILTIN(__builtin_cargl, "LdXLd", "Fnc") +BUILTIN(__builtin_casin, "XdXd", "Fnc") +BUILTIN(__builtin_casinf, "XfXf", "Fnc") +BUILTIN(__builtin_casinh, "XdXd", "Fnc") +BUILTIN(__builtin_casinhf, "XfXf", "Fnc") +BUILTIN(__builtin_casinhl, "XLdXLd", "Fnc") +BUILTIN(__builtin_casinl, "XLdXLd", "Fnc") +BUILTIN(__builtin_catan, "XdXd", "Fnc") +BUILTIN(__builtin_catanf, "XfXf", "Fnc") +BUILTIN(__builtin_catanh, "XdXd", "Fnc") +BUILTIN(__builtin_catanhf, "XfXf", "Fnc") +BUILTIN(__builtin_catanhl, "XLdXLd", "Fnc") +BUILTIN(__builtin_catanl, "XLdXLd", "Fnc") +BUILTIN(__builtin_ccos, "XdXd", "Fnc") +BUILTIN(__builtin_ccosf, "XfXf", "Fnc") +BUILTIN(__builtin_ccosl, "XLdXLd", "Fnc") +BUILTIN(__builtin_ccosh, "XdXd", "Fnc") +BUILTIN(__builtin_ccoshf, "XfXf", "Fnc") +BUILTIN(__builtin_ccoshl, "XLdXLd", "Fnc") +BUILTIN(__builtin_cexp, "XdXd", "Fnc") +BUILTIN(__builtin_cexpf, "XfXf", "Fnc") +BUILTIN(__builtin_cexpl, "XLdXLd", "Fnc") +BUILTIN(__builtin_cimag, "dXd", "Fnc") +BUILTIN(__builtin_cimagf, "fXf", "Fnc") +BUILTIN(__builtin_cimagl, "LdXLd", "Fnc") +BUILTIN(__builtin_conj, "XdXd", "Fnc") +BUILTIN(__builtin_conjf, "XfXf", "Fnc") +BUILTIN(__builtin_conjl, "XLdXLd", "Fnc") +BUILTIN(__builtin_clog, "XdXd", "Fnc") +BUILTIN(__builtin_clogf, "XfXf", "Fnc") +BUILTIN(__builtin_clogl, "XLdXLd", "Fnc") +BUILTIN(__builtin_cproj, "XdXd", "Fnc") +BUILTIN(__builtin_cprojf, "XfXf", "Fnc") +BUILTIN(__builtin_cprojl, "XLdXLd", "Fnc") +BUILTIN(__builtin_cpow, "XdXdXd", "Fnc") +BUILTIN(__builtin_cpowf, "XfXfXf", "Fnc") +BUILTIN(__builtin_cpowl, "XLdXLdXLd", "Fnc") +BUILTIN(__builtin_creal, "dXd", "Fnc") +BUILTIN(__builtin_crealf, "fXf", "Fnc") +BUILTIN(__builtin_creall, "LdXLd", "Fnc") +BUILTIN(__builtin_csin, "XdXd", "Fnc") +BUILTIN(__builtin_csinf, "XfXf", "Fnc") +BUILTIN(__builtin_csinl, "XLdXLd", "Fnc") +BUILTIN(__builtin_csinh, "XdXd", "Fnc") +BUILTIN(__builtin_csinhf, "XfXf", "Fnc") +BUILTIN(__builtin_csinhl, "XLdXLd", "Fnc") +BUILTIN(__builtin_csqrt, "XdXd", "Fnc") +BUILTIN(__builtin_csqrtf, "XfXf", "Fnc") +BUILTIN(__builtin_csqrtl, "XLdXLd", "Fnc") +BUILTIN(__builtin_ctan, "XdXd", "Fnc") +BUILTIN(__builtin_ctanf, "XfXf", "Fnc") +BUILTIN(__builtin_ctanl, "XLdXLd", "Fnc") +BUILTIN(__builtin_ctanh, "XdXd", "Fnc") +BUILTIN(__builtin_ctanhf, "XfXf", "Fnc") +BUILTIN(__builtin_ctanhl, "XLdXLd", "Fnc") + +// FP Comparisons. +BUILTIN(__builtin_isgreater , "i.", "nc") +BUILTIN(__builtin_isgreaterequal, "i.", "nc") +BUILTIN(__builtin_isless , "i.", "nc") +BUILTIN(__builtin_islessequal , "i.", "nc") +BUILTIN(__builtin_islessgreater , "i.", "nc") +BUILTIN(__builtin_isunordered , "i.", "nc") + +// Unary FP classification +BUILTIN(__builtin_fpclassify, "iiiii.", "nc") +BUILTIN(__builtin_isfinite, "i.", "nc") +BUILTIN(__builtin_isinf, "i.", "nc") +BUILTIN(__builtin_isinf_sign, "i.", "nc") +BUILTIN(__builtin_isnan, "i.", "nc") +BUILTIN(__builtin_isnormal, "i.", "nc") + +// FP signbit builtins +BUILTIN(__builtin_signbit, "id", "nc") +BUILTIN(__builtin_signbitf, "if", "nc") +BUILTIN(__builtin_signbitl, "iLd", "nc") + +// Builtins for arithmetic. +BUILTIN(__builtin_clzs , "iUs" , "nc") +BUILTIN(__builtin_clz , "iUi" , "nc") +BUILTIN(__builtin_clzl , "iULi" , "nc") +BUILTIN(__builtin_clzll, "iULLi", "nc") +// TODO: int clzimax(uintmax_t) +BUILTIN(__builtin_ctzs , "iUs" , "nc") +BUILTIN(__builtin_ctz , "iUi" , "nc") +BUILTIN(__builtin_ctzl , "iULi" , "nc") +BUILTIN(__builtin_ctzll, "iULLi", "nc") +// TODO: int ctzimax(uintmax_t) +BUILTIN(__builtin_ffs , "iUi" , "nc") +BUILTIN(__builtin_ffsl , "iULi" , "nc") +BUILTIN(__builtin_ffsll, "iULLi", "nc") +BUILTIN(__builtin_parity , "iUi" , "nc") +BUILTIN(__builtin_parityl , "iULi" , "nc") +BUILTIN(__builtin_parityll, "iULLi", "nc") +BUILTIN(__builtin_popcount , "iUi" , "nc") +BUILTIN(__builtin_popcountl , "iULi" , "nc") +BUILTIN(__builtin_popcountll, "iULLi", "nc") + +// FIXME: These type signatures are not correct for targets with int != 32-bits +// or with ULL != 64-bits. +BUILTIN(__builtin_bswap32, "UiUi", "nc") +BUILTIN(__builtin_bswap64, "ULLiULLi", "nc") + +// Random GCC builtins +BUILTIN(__builtin_constant_p, "i.", "nct") +BUILTIN(__builtin_classify_type, "i.", "nct") +BUILTIN(__builtin___CFStringMakeConstantString, "FC*cC*", "nc") +BUILTIN(__builtin___NSStringMakeConstantString, "FC*cC*", "nc") +BUILTIN(__builtin_va_start, "vA.", "nt") +BUILTIN(__builtin_va_end, "vA", "n") +BUILTIN(__builtin_va_copy, "vAA", "n") +BUILTIN(__builtin_stdarg_start, "vA.", "n") +BUILTIN(__builtin_bcmp, "iv*v*z", "n") +BUILTIN(__builtin_bcopy, "vv*v*z", "n") +BUILTIN(__builtin_bzero, "vv*z", "nF") +BUILTIN(__builtin_fprintf, "iP*cC*.", "Fp:1:") +BUILTIN(__builtin_memchr, "v*vC*iz", "nF") +BUILTIN(__builtin_memcmp, "ivC*vC*z", "nF") +BUILTIN(__builtin_memcpy, "v*v*vC*z", "nF") +BUILTIN(__builtin_memmove, "v*v*vC*z", "nF") +BUILTIN(__builtin_mempcpy, "v*v*vC*z", "nF") +BUILTIN(__builtin_memset, "v*v*iz", "nF") +BUILTIN(__builtin_printf, "icC*.", "Fp:0:") +BUILTIN(__builtin_stpcpy, "c*c*cC*", "nF") +BUILTIN(__builtin_stpncpy, "c*c*cC*z", "nF") +BUILTIN(__builtin_strcasecmp, "icC*cC*", "nF") +BUILTIN(__builtin_strcat, "c*c*cC*", "nF") +BUILTIN(__builtin_strchr, "c*cC*i", "nF") +BUILTIN(__builtin_strcmp, "icC*cC*", "nF") +BUILTIN(__builtin_strcpy, "c*c*cC*", "nF") +BUILTIN(__builtin_strcspn, "zcC*cC*", "nF") +BUILTIN(__builtin_strdup, "c*cC*", "nF") +BUILTIN(__builtin_strlen, "zcC*", "nF") +BUILTIN(__builtin_strncasecmp, "icC*cC*z", "nF") +BUILTIN(__builtin_strncat, "c*c*cC*z", "nF") +BUILTIN(__builtin_strncmp, "icC*cC*z", "nF") +BUILTIN(__builtin_strncpy, "c*c*cC*z", "nF") +BUILTIN(__builtin_strndup, "c*cC*z", "nF") +BUILTIN(__builtin_strpbrk, "c*cC*cC*", "nF") +BUILTIN(__builtin_strrchr, "c*cC*i", "nF") +BUILTIN(__builtin_strspn, "zcC*cC*", "nF") +BUILTIN(__builtin_strstr, "c*cC*cC*", "nF") +BUILTIN(__builtin_return_address, "v*IUi", "n") +BUILTIN(__builtin_extract_return_addr, "v*v*", "n") +BUILTIN(__builtin_frame_address, "v*IUi", "n") +BUILTIN(__builtin_flt_rounds, "i", "nc") +BUILTIN(__builtin_setjmp, "iv**", "j") +BUILTIN(__builtin_longjmp, "vv**i", "r") +BUILTIN(__builtin_unwind_init, "v", "") +BUILTIN(__builtin_eh_return_data_regno, "iIi", "nc") +BUILTIN(__builtin_snprintf, "ic*zcC*.", "nFp:2:") +BUILTIN(__builtin_vsprintf, "ic*cC*a", "nFP:1:") +BUILTIN(__builtin_vsnprintf, "ic*zcC*a", "nFP:2:") + +// GCC exception builtins +BUILTIN(__builtin_eh_return, "vzv*", "r") // FIXME: Takes intptr_t, not size_t! +BUILTIN(__builtin_frob_return_addr, "v*v*", "n") +BUILTIN(__builtin_dwarf_cfa, "v*", "n") +BUILTIN(__builtin_init_dwarf_reg_size_table, "vv*", "n") +BUILTIN(__builtin_dwarf_sp_column, "Ui", "n") +BUILTIN(__builtin_extend_pointer, "ULLiv*", "n") // _Unwind_Word == uint64_t + +// GCC Object size checking builtins +BUILTIN(__builtin_object_size, "zvC*i", "n") +BUILTIN(__builtin___memcpy_chk, "v*v*vC*zz", "nF") +BUILTIN(__builtin___memccpy_chk, "v*v*vC*iz", "nF") +BUILTIN(__builtin___memmove_chk, "v*v*vC*zz", "nF") +BUILTIN(__builtin___mempcpy_chk, "v*v*vC*zz", "nF") +BUILTIN(__builtin___memset_chk, "v*v*izz", "nF") +BUILTIN(__builtin___stpcpy_chk, "c*c*cC*z", "nF") +BUILTIN(__builtin___strcat_chk, "c*c*cC*z", "nF") +BUILTIN(__builtin___strcpy_chk, "c*c*cC*z", "nF") +BUILTIN(__builtin___strlcat_chk, "c*c*cC*zz", "nF") +BUILTIN(__builtin___strlcpy_chk, "c*c*cC*zz", "nF") +BUILTIN(__builtin___strncat_chk, "c*c*cC*zz", "nF") +BUILTIN(__builtin___strncpy_chk, "c*c*cC*zz", "nF") +BUILTIN(__builtin___stpncpy_chk, "c*c*cC*zz", "nF") +BUILTIN(__builtin___snprintf_chk, "ic*zizcC*.", "Fp:4:") +BUILTIN(__builtin___sprintf_chk, "ic*izcC*.", "Fp:3:") +BUILTIN(__builtin___vsnprintf_chk, "ic*zizcC*a", "FP:4:") +BUILTIN(__builtin___vsprintf_chk, "ic*izcC*a", "FP:3:") +BUILTIN(__builtin___fprintf_chk, "iP*icC*.", "Fp:2:") +BUILTIN(__builtin___printf_chk, "iicC*.", "Fp:1:") +BUILTIN(__builtin___vfprintf_chk, "iP*icC*a", "FP:2:") +BUILTIN(__builtin___vprintf_chk, "iicC*a", "FP:1:") + +BUILTIN(__builtin_expect, "LiLiLi" , "nc") +BUILTIN(__builtin_prefetch, "vvC*.", "nc") +BUILTIN(__builtin_trap, "v", "nr") +BUILTIN(__builtin_unreachable, "v", "nr") +BUILTIN(__builtin_shufflevector, "v." , "nc") +BUILTIN(__builtin_alloca, "v*z" , "n") + +// "Overloaded" Atomic operator builtins. These are overloaded to support data +// types of i8, i16, i32, i64, and i128. The front-end sees calls to the +// non-suffixed version of these (which has a bogus type) and transforms them to +// the right overloaded version in Sema (plus casts). + +// FIXME: These assume that char -> i8, short -> i16, int -> i32, +// long long -> i64. + +BUILTIN(__sync_fetch_and_add, "v.", "t") +BUILTIN(__sync_fetch_and_add_1, "ccD*c.", "nt") +BUILTIN(__sync_fetch_and_add_2, "ssD*s.", "nt") +BUILTIN(__sync_fetch_and_add_4, "iiD*i.", "nt") +BUILTIN(__sync_fetch_and_add_8, "LLiLLiD*LLi.", "nt") +BUILTIN(__sync_fetch_and_add_16, "LLLiLLLiD*LLLi.", "nt") + +BUILTIN(__sync_fetch_and_sub, "v.", "t") +BUILTIN(__sync_fetch_and_sub_1, "ccD*c.", "nt") +BUILTIN(__sync_fetch_and_sub_2, "ssD*s.", "nt") +BUILTIN(__sync_fetch_and_sub_4, "iiD*i.", "nt") +BUILTIN(__sync_fetch_and_sub_8, "LLiLLiD*LLi.", "nt") +BUILTIN(__sync_fetch_and_sub_16, "LLLiLLLiD*LLLi.", "nt") + +BUILTIN(__sync_fetch_and_or, "v.", "t") +BUILTIN(__sync_fetch_and_or_1, "ccD*c.", "nt") +BUILTIN(__sync_fetch_and_or_2, "ssD*s.", "nt") +BUILTIN(__sync_fetch_and_or_4, "iiD*i.", "nt") +BUILTIN(__sync_fetch_and_or_8, "LLiLLiD*LLi.", "nt") +BUILTIN(__sync_fetch_and_or_16, "LLLiLLLiD*LLLi.", "nt") + +BUILTIN(__sync_fetch_and_and, "v.", "t") +BUILTIN(__sync_fetch_and_and_1, "ccD*c.", "tn") +BUILTIN(__sync_fetch_and_and_2, "ssD*s.", "tn") +BUILTIN(__sync_fetch_and_and_4, "iiD*i.", "tn") +BUILTIN(__sync_fetch_and_and_8, "LLiLLiD*LLi.", "tn") +BUILTIN(__sync_fetch_and_and_16, "LLLiLLLiD*LLLi.", "tn") + +BUILTIN(__sync_fetch_and_xor, "v.", "t") +BUILTIN(__sync_fetch_and_xor_1, "ccD*c.", "tn") +BUILTIN(__sync_fetch_and_xor_2, "ssD*s.", "tn") +BUILTIN(__sync_fetch_and_xor_4, "iiD*i.", "tn") +BUILTIN(__sync_fetch_and_xor_8, "LLiLLiD*LLi.", "tn") +BUILTIN(__sync_fetch_and_xor_16, "LLLiLLLiD*LLLi.", "tn") + + +BUILTIN(__sync_add_and_fetch, "v.", "t") +BUILTIN(__sync_add_and_fetch_1, "ccD*c.", "tn") +BUILTIN(__sync_add_and_fetch_2, "ssD*s.", "tn") +BUILTIN(__sync_add_and_fetch_4, "iiD*i.", "tn") +BUILTIN(__sync_add_and_fetch_8, "LLiLLiD*LLi.", "tn") +BUILTIN(__sync_add_and_fetch_16, "LLLiLLLiD*LLLi.", "tn") + +BUILTIN(__sync_sub_and_fetch, "v.", "t") +BUILTIN(__sync_sub_and_fetch_1, "ccD*c.", "tn") +BUILTIN(__sync_sub_and_fetch_2, "ssD*s.", "tn") +BUILTIN(__sync_sub_and_fetch_4, "iiD*i.", "tn") +BUILTIN(__sync_sub_and_fetch_8, "LLiLLiD*LLi.", "tn") +BUILTIN(__sync_sub_and_fetch_16, "LLLiLLLiD*LLLi.", "tn") + +BUILTIN(__sync_or_and_fetch, "v.", "t") +BUILTIN(__sync_or_and_fetch_1, "ccD*c.", "tn") +BUILTIN(__sync_or_and_fetch_2, "ssD*s.", "tn") +BUILTIN(__sync_or_and_fetch_4, "iiD*i.", "tn") +BUILTIN(__sync_or_and_fetch_8, "LLiLLiD*LLi.", "tn") +BUILTIN(__sync_or_and_fetch_16, "LLLiLLLiD*LLLi.", "tn") + +BUILTIN(__sync_and_and_fetch, "v.", "t") +BUILTIN(__sync_and_and_fetch_1, "ccD*c.", "tn") +BUILTIN(__sync_and_and_fetch_2, "ssD*s.", "tn") +BUILTIN(__sync_and_and_fetch_4, "iiD*i.", "tn") +BUILTIN(__sync_and_and_fetch_8, "LLiLLiD*LLi.", "tn") +BUILTIN(__sync_and_and_fetch_16, "LLLiLLLiD*LLLi.", "tn") + +BUILTIN(__sync_xor_and_fetch, "v.", "t") +BUILTIN(__sync_xor_and_fetch_1, "ccD*c.", "tn") +BUILTIN(__sync_xor_and_fetch_2, "ssD*s.", "tn") +BUILTIN(__sync_xor_and_fetch_4, "iiD*i.", "tn") +BUILTIN(__sync_xor_and_fetch_8, "LLiLLiD*LLi.", "tn") +BUILTIN(__sync_xor_and_fetch_16, "LLLiLLLiD*LLLi.", "tn") + +BUILTIN(__sync_bool_compare_and_swap, "v.", "t") +BUILTIN(__sync_bool_compare_and_swap_1, "bcD*cc.", "tn") +BUILTIN(__sync_bool_compare_and_swap_2, "bsD*ss.", "tn") +BUILTIN(__sync_bool_compare_and_swap_4, "biD*ii.", "tn") +BUILTIN(__sync_bool_compare_and_swap_8, "bLLiD*LLiLLi.", "tn") +BUILTIN(__sync_bool_compare_and_swap_16, "bLLLiD*LLLiLLLi.", "tn") + +BUILTIN(__sync_val_compare_and_swap, "v.", "t") +BUILTIN(__sync_val_compare_and_swap_1, "ccD*cc.", "tn") +BUILTIN(__sync_val_compare_and_swap_2, "ssD*ss.", "tn") +BUILTIN(__sync_val_compare_and_swap_4, "iiD*ii.", "tn") +BUILTIN(__sync_val_compare_and_swap_8, "LLiLLiD*LLiLLi.", "tn") +BUILTIN(__sync_val_compare_and_swap_16, "LLLiLLLiD*LLLiLLLi.", "tn") + +BUILTIN(__sync_lock_test_and_set, "v.", "t") +BUILTIN(__sync_lock_test_and_set_1, "ccD*c.", "tn") +BUILTIN(__sync_lock_test_and_set_2, "ssD*s.", "tn") +BUILTIN(__sync_lock_test_and_set_4, "iiD*i.", "tn") +BUILTIN(__sync_lock_test_and_set_8, "LLiLLiD*LLi.", "tn") +BUILTIN(__sync_lock_test_and_set_16, "LLLiLLLiD*LLLi.", "tn") + +BUILTIN(__sync_lock_release, "v.", "t") +BUILTIN(__sync_lock_release_1, "vcD*.", "tn") +BUILTIN(__sync_lock_release_2, "vsD*.", "tn") +BUILTIN(__sync_lock_release_4, "viD*.", "tn") +BUILTIN(__sync_lock_release_8, "vLLiD*.", "tn") +BUILTIN(__sync_lock_release_16, "vLLLiD*.", "tn") + +BUILTIN(__sync_swap, "v.", "t") +BUILTIN(__sync_swap_1, "ccD*c.", "tn") +BUILTIN(__sync_swap_2, "ssD*s.", "tn") +BUILTIN(__sync_swap_4, "iiD*i.", "tn") +BUILTIN(__sync_swap_8, "LLiLLiD*LLi.", "tn") +BUILTIN(__sync_swap_16, "LLLiLLLiD*LLLi.", "tn") + +// Some of our atomics builtins are handled by AtomicExpr rather than +// as normal builtin CallExprs. This macro is used for such builtins. +#ifndef ATOMIC_BUILTIN +#define ATOMIC_BUILTIN(ID, TYPE, ATTRS) BUILTIN(ID, TYPE, ATTRS) +#endif + +// C11 _Atomic operations for <stdatomic.h>. +ATOMIC_BUILTIN(__c11_atomic_init, "v.", "t") +ATOMIC_BUILTIN(__c11_atomic_load, "v.", "t") +ATOMIC_BUILTIN(__c11_atomic_store, "v.", "t") +ATOMIC_BUILTIN(__c11_atomic_exchange, "v.", "t") +ATOMIC_BUILTIN(__c11_atomic_compare_exchange_strong, "v.", "t") +ATOMIC_BUILTIN(__c11_atomic_compare_exchange_weak, "v.", "t") +ATOMIC_BUILTIN(__c11_atomic_fetch_add, "v.", "t") +ATOMIC_BUILTIN(__c11_atomic_fetch_sub, "v.", "t") +ATOMIC_BUILTIN(__c11_atomic_fetch_and, "v.", "t") +ATOMIC_BUILTIN(__c11_atomic_fetch_or, "v.", "t") +ATOMIC_BUILTIN(__c11_atomic_fetch_xor, "v.", "t") +BUILTIN(__c11_atomic_thread_fence, "vi", "n") +BUILTIN(__c11_atomic_signal_fence, "vi", "n") +BUILTIN(__c11_atomic_is_lock_free, "iz", "n") + +// GNU atomic builtins. +ATOMIC_BUILTIN(__atomic_load, "v.", "t") +ATOMIC_BUILTIN(__atomic_load_n, "v.", "t") +ATOMIC_BUILTIN(__atomic_store, "v.", "t") +ATOMIC_BUILTIN(__atomic_store_n, "v.", "t") +ATOMIC_BUILTIN(__atomic_exchange, "v.", "t") +ATOMIC_BUILTIN(__atomic_exchange_n, "v.", "t") +ATOMIC_BUILTIN(__atomic_compare_exchange, "v.", "t") +ATOMIC_BUILTIN(__atomic_compare_exchange_n, "v.", "t") +ATOMIC_BUILTIN(__atomic_fetch_add, "v.", "t") +ATOMIC_BUILTIN(__atomic_fetch_sub, "v.", "t") +ATOMIC_BUILTIN(__atomic_fetch_and, "v.", "t") +ATOMIC_BUILTIN(__atomic_fetch_or, "v.", "t") +ATOMIC_BUILTIN(__atomic_fetch_xor, "v.", "t") +ATOMIC_BUILTIN(__atomic_fetch_nand, "v.", "t") +ATOMIC_BUILTIN(__atomic_add_fetch, "v.", "t") +ATOMIC_BUILTIN(__atomic_sub_fetch, "v.", "t") +ATOMIC_BUILTIN(__atomic_and_fetch, "v.", "t") +ATOMIC_BUILTIN(__atomic_or_fetch, "v.", "t") +ATOMIC_BUILTIN(__atomic_xor_fetch, "v.", "t") +ATOMIC_BUILTIN(__atomic_nand_fetch, "v.", "t") +BUILTIN(__atomic_test_and_set, "bvD*i", "n") +BUILTIN(__atomic_clear, "vvD*i", "n") +BUILTIN(__atomic_thread_fence, "vi", "n") +BUILTIN(__atomic_signal_fence, "vi", "n") +BUILTIN(__atomic_always_lock_free, "izvCD*", "n") +BUILTIN(__atomic_is_lock_free, "izvCD*", "n") + +#undef ATOMIC_BUILTIN + +// Non-overloaded atomic builtins. +BUILTIN(__sync_synchronize, "v.", "n") +// GCC does not support these, they are a Clang extension. +BUILTIN(__sync_fetch_and_min, "iiD*i", "n") +BUILTIN(__sync_fetch_and_max, "iiD*i", "n") +BUILTIN(__sync_fetch_and_umin, "UiUiD*Ui", "n") +BUILTIN(__sync_fetch_and_umax, "UiUiD*Ui", "n") + +// Random libc builtins. +BUILTIN(__builtin_abort, "v", "Fnr") +BUILTIN(__builtin_index, "c*cC*i", "Fn") +BUILTIN(__builtin_rindex, "c*cC*i", "Fn") + +// Microsoft builtins. +BUILTIN(__assume, "vb", "n") +BUILTIN(__noop, "v.", "n") +BUILTIN(__debugbreak, "v", "n") + + +// C99 library functions +// C99 stdlib.h +LIBBUILTIN(abort, "v", "fr", "stdlib.h", ALL_LANGUAGES) +LIBBUILTIN(calloc, "v*zz", "f", "stdlib.h", ALL_LANGUAGES) +LIBBUILTIN(exit, "vi", "fr", "stdlib.h", ALL_LANGUAGES) +LIBBUILTIN(_Exit, "vi", "fr", "stdlib.h", ALL_LANGUAGES) +LIBBUILTIN(malloc, "v*z", "f", "stdlib.h", ALL_LANGUAGES) +LIBBUILTIN(realloc, "v*v*z", "f", "stdlib.h", ALL_LANGUAGES) +// C99 string.h +LIBBUILTIN(memcpy, "v*v*vC*z", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(memcmp, "ivC*vC*z", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(memmove, "v*v*vC*z", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strcpy, "c*c*cC*", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strncpy, "c*c*cC*z", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strcmp, "icC*cC*", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strncmp, "icC*cC*z", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strcat, "c*c*cC*", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strncat, "c*c*cC*z", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strxfrm, "zc*cC*z", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(memchr, "v*vC*iz", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strchr, "c*cC*i", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strcspn, "zcC*cC*", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strpbrk, "c*cC*cC*", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strrchr, "c*cC*i", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strspn, "zcC*cC*", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strstr, "c*cC*cC*", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strtok, "c*c*cC*", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(memset, "v*v*iz", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strerror, "c*i", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strlen, "zcC*", "f", "string.h", ALL_LANGUAGES) +// C99 stdio.h +LIBBUILTIN(printf, "icC*.", "fp:0:", "stdio.h", ALL_LANGUAGES) +LIBBUILTIN(fprintf, "iP*cC*.", "fp:1:", "stdio.h", ALL_LANGUAGES) +LIBBUILTIN(snprintf, "ic*zcC*.", "fp:2:", "stdio.h", ALL_LANGUAGES) +LIBBUILTIN(sprintf, "ic*cC*.", "fp:1:", "stdio.h", ALL_LANGUAGES) +LIBBUILTIN(vprintf, "icC*a", "fP:0:", "stdio.h", ALL_LANGUAGES) +LIBBUILTIN(vfprintf, "i.", "fP:1:", "stdio.h", ALL_LANGUAGES) +LIBBUILTIN(vsnprintf, "ic*zcC*a", "fP:2:", "stdio.h", ALL_LANGUAGES) +LIBBUILTIN(vsprintf, "ic*cC*a", "fP:1:", "stdio.h", ALL_LANGUAGES) +LIBBUILTIN(scanf, "icC*R.", "fs:0:", "stdio.h", ALL_LANGUAGES) +LIBBUILTIN(fscanf, "iP*RcC*R.", "fs:1:", "stdio.h", ALL_LANGUAGES) +LIBBUILTIN(sscanf, "icC*RcC*R.", "fs:1:", "stdio.h", ALL_LANGUAGES) +LIBBUILTIN(vscanf, "icC*Ra", "fS:0:", "stdio.h", ALL_LANGUAGES) +LIBBUILTIN(vfscanf, "iP*RcC*Ra", "fS:1:", "stdio.h", ALL_LANGUAGES) +LIBBUILTIN(vsscanf, "icC*RcC*Ra", "fS:1:", "stdio.h", ALL_LANGUAGES) +// C99 +LIBBUILTIN(longjmp, "vJi", "fr", "setjmp.h", ALL_LANGUAGES) + +// Non-C library functions +// FIXME: Non-C-standard stuff shouldn't be builtins in non-GNU mode! +LIBBUILTIN(alloca, "v*z", "f", "stdlib.h", ALL_LANGUAGES) +// POSIX string.h +LIBBUILTIN(stpcpy, "c*c*cC*", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(stpncpy, "c*c*cC*z", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strdup, "c*cC*", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strndup, "c*cC*z", "f", "string.h", ALL_LANGUAGES) +// POSIX strings.h +LIBBUILTIN(index, "c*cC*i", "f", "strings.h", ALL_LANGUAGES) +LIBBUILTIN(rindex, "c*cC*i", "f", "strings.h", ALL_LANGUAGES) +LIBBUILTIN(bzero, "vv*z", "f", "strings.h", ALL_LANGUAGES) +LIBBUILTIN(strcasecmp, "icC*cC*", "f", "strings.h", ALL_LANGUAGES) +LIBBUILTIN(strncasecmp, "icC*cC*z", "f", "strings.h", ALL_LANGUAGES) +// POSIX unistd.h +LIBBUILTIN(_exit, "vi", "fr", "unistd.h", ALL_LANGUAGES) +LIBBUILTIN(vfork, "i", "fj", "unistd.h", ALL_LANGUAGES) +// POSIX setjmp.h + +// In some systems setjmp is a macro that expands to _setjmp. We undefine +// it here to avoid having two identical LIBBUILTIN entries. +#undef setjmp +LIBBUILTIN(_setjmp, "iJ", "fj", "setjmp.h", ALL_LANGUAGES) +LIBBUILTIN(__sigsetjmp, "iSJi", "fj", "setjmp.h", ALL_LANGUAGES) +LIBBUILTIN(setjmp, "iJ", "fj", "setjmp.h", ALL_LANGUAGES) +LIBBUILTIN(sigsetjmp, "iSJi", "fj", "setjmp.h", ALL_LANGUAGES) +LIBBUILTIN(setjmp_syscall, "iJ", "fj", "setjmp.h", ALL_LANGUAGES) +LIBBUILTIN(savectx, "iJ", "fj", "setjmp.h", ALL_LANGUAGES) +LIBBUILTIN(qsetjmp, "iJ", "fj", "setjmp.h", ALL_LANGUAGES) +LIBBUILTIN(getcontext, "iK*", "fj", "setjmp.h", ALL_LANGUAGES) + +LIBBUILTIN(_longjmp, "vJi", "fr", "setjmp.h", ALL_LANGUAGES) +LIBBUILTIN(siglongjmp, "vSJi", "fr", "setjmp.h", ALL_LANGUAGES) +// non-standard but very common +LIBBUILTIN(strlcpy, "zc*cC*z", "f", "string.h", ALL_LANGUAGES) +LIBBUILTIN(strlcat, "zc*cC*z", "f", "string.h", ALL_LANGUAGES) +// id objc_msgSend(id, SEL, ...) +LIBBUILTIN(objc_msgSend, "GGH.", "f", "objc/message.h", OBJC_LANG) + +// long double objc_msgSend_fpret(id self, SEL op, ...) +LIBBUILTIN(objc_msgSend_fpret, "LdGH.", "f", "objc/message.h", OBJC_LANG) +// _Complex long double objc_msgSend_fp2ret(id self, SEL op, ...) +LIBBUILTIN(objc_msgSend_fp2ret, "XLdGH.", "f", "objc/message.h", OBJC_LANG) +// id objc_msgSend_stret (id, SEL, ...) +LIBBUILTIN(objc_msgSend_stret, "GGH.", "f", "objc/message.h", OBJC_LANG) +// id objc_msgSendSuper(struct objc_super *super, SEL op, ...) +LIBBUILTIN(objc_msgSendSuper, "Gv*H.", "f", "objc/message.h", OBJC_LANG) +// void objc_msgSendSuper_stret(struct objc_super *super, SEL op, ...) +LIBBUILTIN(objc_msgSendSuper_stret, "vv*H.", "f", "objc/message.h", OBJC_LANG) +// id objc_getClass(const char *name) +LIBBUILTIN(objc_getClass, "GcC*", "f", "objc/runtime.h", OBJC_LANG) +// id objc_getMetaClass(const char *name) +LIBBUILTIN(objc_getMetaClass, "GcC*", "f", "objc/runtime.h", OBJC_LANG) +// void objc_enumerationMutation(id) +LIBBUILTIN(objc_enumerationMutation, "vG", "f", "objc/runtime.h", OBJC_LANG) + +// id objc_read_weak(id *location) +LIBBUILTIN(objc_read_weak, "GG*", "f", "objc/objc-auto.h", OBJC_LANG) +// id objc_assign_weak(id value, id *location) +LIBBUILTIN(objc_assign_weak, "GGG*", "f", "objc/objc-auto.h", OBJC_LANG) +// id objc_assign_ivar(id value, id dest, ptrdiff_t offset) +LIBBUILTIN(objc_assign_ivar, "GGGY", "f", "objc/objc-auto.h", OBJC_LANG) +// id objc_assign_global(id val, id *dest) +LIBBUILTIN(objc_assign_global, "GGG*", "f", "objc/objc-auto.h", OBJC_LANG) +// id objc_assign_strongCast(id val, id *dest +LIBBUILTIN(objc_assign_strongCast, "GGG*", "f", "objc/objc-auto.h", OBJC_LANG) + +// id objc_exception_extract(void *localExceptionData) +LIBBUILTIN(objc_exception_extract, "Gv*", "f", "objc/objc-exception.h", OBJC_LANG) +// void objc_exception_try_enter(void *localExceptionData) +LIBBUILTIN(objc_exception_try_enter, "vv*", "f", "objc/objc-exception.h", OBJC_LANG) +// void objc_exception_try_exit(void *localExceptionData) +LIBBUILTIN(objc_exception_try_exit, "vv*", "f", "objc/objc-exception.h", OBJC_LANG) +// int objc_exception_match(Class exceptionClass, id exception) +LIBBUILTIN(objc_exception_match, "iGG", "f", "objc/objc-exception.h", OBJC_LANG) +// void objc_exception_throw(id exception) +LIBBUILTIN(objc_exception_throw, "vG", "f", "objc/objc-exception.h", OBJC_LANG) + +// int objc_sync_enter(id obj) +LIBBUILTIN(objc_sync_enter, "iG", "f", "objc/objc-sync.h", OBJC_LANG) +// int objc_sync_exit(id obj) +LIBBUILTIN(objc_sync_exit, "iG", "f", "objc/objc-sync.h", OBJC_LANG) + +BUILTIN(__builtin_objc_memmove_collectable, "v*v*vC*z", "nF") + +// void NSLog(NSString *fmt, ...) +LIBBUILTIN(NSLog, "vG.", "fp:0:", "Foundation/NSObjCRuntime.h", OBJC_LANG) +// void NSLogv(NSString *fmt, va_list args) +LIBBUILTIN(NSLogv, "vGa", "fP:0:", "Foundation/NSObjCRuntime.h", OBJC_LANG) + +// Builtin math library functions +LIBBUILTIN(pow, "ddd", "fe", "math.h", ALL_LANGUAGES) +LIBBUILTIN(powl, "LdLdLd", "fe", "math.h", ALL_LANGUAGES) +LIBBUILTIN(powf, "fff", "fe", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(sqrt, "dd", "fe", "math.h", ALL_LANGUAGES) +LIBBUILTIN(sqrtl, "LdLd", "fe", "math.h", ALL_LANGUAGES) +LIBBUILTIN(sqrtf, "ff", "fe", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(sin, "dd", "fe", "math.h", ALL_LANGUAGES) +LIBBUILTIN(sinl, "LdLd", "fe", "math.h", ALL_LANGUAGES) +LIBBUILTIN(sinf, "ff", "fe", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(cos, "dd", "fe", "math.h", ALL_LANGUAGES) +LIBBUILTIN(cosl, "LdLd", "fe", "math.h", ALL_LANGUAGES) +LIBBUILTIN(cosf, "ff", "fe", "math.h", ALL_LANGUAGES) + +LIBBUILTIN(fma, "dddd", "fc", "math.h", ALL_LANGUAGES) +LIBBUILTIN(fmal, "LdLdLdLd", "fc", "math.h", ALL_LANGUAGES) +LIBBUILTIN(fmaf, "ffff", "fc", "math.h", ALL_LANGUAGES) + +// Blocks runtime Builtin math library functions +LIBBUILTIN(_Block_object_assign, "vv*vC*iC", "f", "Blocks.h", ALL_LANGUAGES) +LIBBUILTIN(_Block_object_dispose, "vvC*iC", "f", "Blocks.h", ALL_LANGUAGES) +// FIXME: Also declare NSConcreteGlobalBlock and NSConcreteStackBlock. + +// Annotation function +BUILTIN(__builtin_annotation, "UiUicC*", "nc") + +#undef BUILTIN +#undef LIBBUILTIN diff --git a/clang/include/clang/Basic/Builtins.h b/clang/include/clang/Basic/Builtins.h new file mode 100644 index 0000000..5afa020 --- /dev/null +++ b/clang/include/clang/Basic/Builtins.h @@ -0,0 +1,163 @@ +//===--- Builtins.h - Builtin function header -------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines enum values for all the target-independent builtin +// functions. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_BUILTINS_H +#define LLVM_CLANG_BASIC_BUILTINS_H + +#include "clang/Basic/LLVM.h" +#include <cstring> + +// VC++ defines 'alloca' as an object-like macro, which interferes with our +// builtins. +#undef alloca + +namespace clang { + class TargetInfo; + class IdentifierTable; + class ASTContext; + class QualType; + class LangOptions; + + enum LanguageID { + C_LANG = 0x1, // builtin for c only. + CXX_LANG = 0x2, // builtin for cplusplus only. + OBJC_LANG = 0x4, // builtin for objective-c and objective-c++ + ALL_LANGUAGES = (C_LANG|CXX_LANG|OBJC_LANG) //builtin is for all languages. + }; + +namespace Builtin { +enum ID { + NotBuiltin = 0, // This is not a builtin function. +#define BUILTIN(ID, TYPE, ATTRS) BI##ID, +#include "clang/Basic/Builtins.def" + FirstTSBuiltin +}; + +struct Info { + const char *Name, *Type, *Attributes, *HeaderName; + LanguageID builtin_lang; + + bool operator==(const Info &RHS) const { + return !strcmp(Name, RHS.Name) && + !strcmp(Type, RHS.Type) && + !strcmp(Attributes, RHS.Attributes); + } + bool operator!=(const Info &RHS) const { return !(*this == RHS); } +}; + +/// Builtin::Context - This holds information about target-independent and +/// target-specific builtins, allowing easy queries by clients. +class Context { + const Info *TSRecords; + unsigned NumTSRecords; +public: + Context(); + + /// \brief Perform target-specific initialization + void InitializeTarget(const TargetInfo &Target); + + /// InitializeBuiltins - Mark the identifiers for all the builtins with their + /// appropriate builtin ID # and mark any non-portable builtin identifiers as + /// such. + void InitializeBuiltins(IdentifierTable &Table, const LangOptions& LangOpts); + + /// \brief Popular the vector with the names of all of the builtins. + void GetBuiltinNames(SmallVectorImpl<const char *> &Names, + bool NoBuiltins); + + /// Builtin::GetName - Return the identifier name for the specified builtin, + /// e.g. "__builtin_abs". + const char *GetName(unsigned ID) const { + return GetRecord(ID).Name; + } + + /// GetTypeString - Get the type descriptor string for the specified builtin. + const char *GetTypeString(unsigned ID) const { + return GetRecord(ID).Type; + } + + /// isConst - Return true if this function has no side effects and doesn't + /// read memory. + bool isConst(unsigned ID) const { + return strchr(GetRecord(ID).Attributes, 'c') != 0; + } + + /// isNoThrow - Return true if we know this builtin never throws an exception. + bool isNoThrow(unsigned ID) const { + return strchr(GetRecord(ID).Attributes, 'n') != 0; + } + + /// isNoReturn - Return true if we know this builtin never returns. + bool isNoReturn(unsigned ID) const { + return strchr(GetRecord(ID).Attributes, 'r') != 0; + } + + /// isReturnsTwice - Return true if we know this builtin can return twice. + bool isReturnsTwice(unsigned ID) const { + return strchr(GetRecord(ID).Attributes, 'j') != 0; + } + + /// isLibFunction - Return true if this is a builtin for a libc/libm function, + /// with a "__builtin_" prefix (e.g. __builtin_abs). + bool isLibFunction(unsigned ID) const { + return strchr(GetRecord(ID).Attributes, 'F') != 0; + } + + /// \brief Determines whether this builtin is a predefined libc/libm + /// function, such as "malloc", where we know the signature a + /// priori. + bool isPredefinedLibFunction(unsigned ID) const { + return strchr(GetRecord(ID).Attributes, 'f') != 0; + } + + /// \brief Determines whether this builtin has custom typechecking. + bool hasCustomTypechecking(unsigned ID) const { + return strchr(GetRecord(ID).Attributes, 't') != 0; + } + + /// \brief Completely forget that the given ID was ever considered a builtin, + /// e.g., because the user provided a conflicting signature. + void ForgetBuiltin(unsigned ID, IdentifierTable &Table); + + /// \brief If this is a library function that comes from a specific + /// header, retrieve that header name. + const char *getHeaderName(unsigned ID) const { + return GetRecord(ID).HeaderName; + } + + /// \brief Determine whether this builtin is like printf in its + /// formatting rules and, if so, set the index to the format string + /// argument and whether this function as a va_list argument. + bool isPrintfLike(unsigned ID, unsigned &FormatIdx, bool &HasVAListArg); + + /// \brief Determine whether this builtin is like scanf in its + /// formatting rules and, if so, set the index to the format string + /// argument and whether this function as a va_list argument. + bool isScanfLike(unsigned ID, unsigned &FormatIdx, bool &HasVAListArg); + + /// isConstWithoutErrno - Return true if this function has no side + /// effects and doesn't read memory, except for possibly errno. Such + /// functions can be const when the MathErrno lang option is + /// disabled. + bool isConstWithoutErrno(unsigned ID) const { + return strchr(GetRecord(ID).Attributes, 'e') != 0; + } + +private: + const Info &GetRecord(unsigned ID) const; +}; + +} +} // end namespace clang +#endif diff --git a/clang/include/clang/Basic/BuiltinsARM.def b/clang/include/clang/Basic/BuiltinsARM.def new file mode 100644 index 0000000..888e529 --- /dev/null +++ b/clang/include/clang/Basic/BuiltinsARM.def @@ -0,0 +1,52 @@ +//===--- BuiltinsARM.def - ARM Builtin function database ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ARM-specific builtin function database. Users of +// this file must define the BUILTIN macro to make use of this information. +// +//===----------------------------------------------------------------------===// + +// The format of this database matches clang/Basic/Builtins.def. + +// In libgcc +BUILTIN(__clear_cache, "v.", "") +BUILTIN(__builtin_thread_pointer, "v*", "") + +// Saturating arithmetic +BUILTIN(__builtin_arm_qadd, "iii", "nc") +BUILTIN(__builtin_arm_qsub, "iii", "nc") +BUILTIN(__builtin_arm_ssat, "iiUi", "nc") +BUILTIN(__builtin_arm_usat, "UiUiUi", "nc") + +// Store and load exclusive doubleword +BUILTIN(__builtin_arm_ldrexd, "LLUiv*", "") +BUILTIN(__builtin_arm_strexd, "iLLUiv*", "") + +// VFP +BUILTIN(__builtin_arm_get_fpscr, "Ui", "nc") +BUILTIN(__builtin_arm_set_fpscr, "vUi", "nc") +BUILTIN(__builtin_arm_vcvtr_f, "ffi", "nc") +BUILTIN(__builtin_arm_vcvtr_d, "fdi", "nc") + +// Coprocessor +BUILTIN(__builtin_arm_mcr, "vUiUiUiUiUiUi", "") +BUILTIN(__builtin_arm_mcr2, "vUiUiUiUiUiUi", "") +BUILTIN(__builtin_arm_mrc, "UiUiUiUiUiUi", "") +BUILTIN(__builtin_arm_mrc2, "UiUiUiUiUiUi", "") +BUILTIN(__builtin_arm_cdp, "vUiUiUiUiUiUi", "") +BUILTIN(__builtin_arm_cdp2, "vUiUiUiUiUiUi", "") +BUILTIN(__builtin_arm_mcrr, "vUiUiUiUiUi", "") +BUILTIN(__builtin_arm_mcrr2, "vUiUiUiUiUi", "") + +// NEON +#define GET_NEON_BUILTINS +#include "clang/Basic/arm_neon.inc" +#undef GET_NEON_BUILTINS + +#undef BUILTIN diff --git a/clang/include/clang/Basic/BuiltinsHexagon.def b/clang/include/clang/Basic/BuiltinsHexagon.def new file mode 100644 index 0000000..334224f --- /dev/null +++ b/clang/include/clang/Basic/BuiltinsHexagon.def @@ -0,0 +1,689 @@ +//==--- BuiltinsHexagon.def - Hexagon Builtin function database --*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the X86-specific builtin function database. Users of +// this file must define the BUILTIN macro to make use of this information. +// +//===----------------------------------------------------------------------===// + +BUILTIN(__builtin_HEXAGON_C2_cmpeq, "bii", "") +BUILTIN(__builtin_HEXAGON_C2_cmpgt, "bii", "") +BUILTIN(__builtin_HEXAGON_C2_cmpgtu, "bii", "") +BUILTIN(__builtin_HEXAGON_C2_cmpeqp, "bLLiLLi", "") +BUILTIN(__builtin_HEXAGON_C2_cmpgtp, "bLLiLLi", "") +BUILTIN(__builtin_HEXAGON_C2_cmpgtup, "bLLiLLi", "") +BUILTIN(__builtin_HEXAGON_C2_bitsset, "bii", "") +BUILTIN(__builtin_HEXAGON_C2_bitsclr, "bii", "") +BUILTIN(__builtin_HEXAGON_C2_cmpeqi, "bii", "") +BUILTIN(__builtin_HEXAGON_C2_cmpgti, "bii", "") +BUILTIN(__builtin_HEXAGON_C2_cmpgtui, "bii", "") +BUILTIN(__builtin_HEXAGON_C2_cmpgei, "bii", "") +BUILTIN(__builtin_HEXAGON_C2_cmpgeui, "bii", "") +BUILTIN(__builtin_HEXAGON_C2_cmplt, "bii", "") +BUILTIN(__builtin_HEXAGON_C2_cmpltu, "bii", "") +BUILTIN(__builtin_HEXAGON_C2_bitsclri, "bii", "") +BUILTIN(__builtin_HEXAGON_C2_and, "bii", "") +BUILTIN(__builtin_HEXAGON_C2_or, "bii", "") +BUILTIN(__builtin_HEXAGON_C2_xor, "bii", "") +BUILTIN(__builtin_HEXAGON_C2_andn, "bii", "") +BUILTIN(__builtin_HEXAGON_C2_not, "bi", "") +BUILTIN(__builtin_HEXAGON_C2_orn, "bii", "") +BUILTIN(__builtin_HEXAGON_C2_pxfer_map, "bi", "") +BUILTIN(__builtin_HEXAGON_C2_any8, "bi", "") +BUILTIN(__builtin_HEXAGON_C2_all8, "bi", "") +BUILTIN(__builtin_HEXAGON_C2_vitpack, "iii", "") +BUILTIN(__builtin_HEXAGON_C2_mux, "iiii", "") +BUILTIN(__builtin_HEXAGON_C2_muxii, "iiii", "") +BUILTIN(__builtin_HEXAGON_C2_muxir, "iiii", "") +BUILTIN(__builtin_HEXAGON_C2_muxri, "iiii", "") +BUILTIN(__builtin_HEXAGON_C2_vmux, "LLiiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_C2_mask, "LLii", "") +BUILTIN(__builtin_HEXAGON_A2_vcmpbeq, "bLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vcmpbgtu, "bLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vcmpheq, "bLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vcmphgt, "bLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vcmphgtu, "bLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vcmpweq, "bLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vcmpwgt, "bLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vcmpwgtu, "bLLiLLi", "") +BUILTIN(__builtin_HEXAGON_C2_tfrpr, "ii", "") +BUILTIN(__builtin_HEXAGON_C2_tfrrp, "bi", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_acc_hh_s0, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_acc_hh_s1, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_acc_hl_s0, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_acc_hl_s1, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_acc_lh_s0, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_acc_lh_s1, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_acc_ll_s0, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_acc_ll_s1, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_nac_hh_s0, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_nac_hh_s1, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_nac_hl_s0, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_nac_hl_s1, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_nac_lh_s0, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_nac_lh_s1, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_nac_ll_s0, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_nac_ll_s1, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_acc_sat_hh_s0, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_acc_sat_hh_s1, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_acc_sat_hl_s0, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_acc_sat_hl_s1, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_acc_sat_lh_s0, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_acc_sat_lh_s1, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_acc_sat_ll_s0, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_acc_sat_ll_s1, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_nac_sat_hh_s0, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_nac_sat_hh_s1, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_nac_sat_hl_s0, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_nac_sat_hl_s1, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_nac_sat_lh_s0, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_nac_sat_lh_s1, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_nac_sat_ll_s0, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_nac_sat_ll_s1, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_hh_s0, "iii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_hh_s1, "iii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_hl_s0, "iii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_hl_s1, "iii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_lh_s0, "iii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_lh_s1, "iii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_ll_s0, "iii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_ll_s1, "iii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_sat_hh_s0, "iii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_sat_hh_s1, "iii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_sat_hl_s0, "iii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_sat_hl_s1, "iii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_sat_lh_s0, "iii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_sat_lh_s1, "iii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_sat_ll_s0, "iii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_sat_ll_s1, "iii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_rnd_hh_s0, "iii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_rnd_hh_s1, "iii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_rnd_hl_s0, "iii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_rnd_hl_s1, "iii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_rnd_lh_s0, "iii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_rnd_lh_s1, "iii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_rnd_ll_s0, "iii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_rnd_ll_s1, "iii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_sat_rnd_hh_s0, "iii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_sat_rnd_hh_s1, "iii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_sat_rnd_hl_s0, "iii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_sat_rnd_hl_s1, "iii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_sat_rnd_lh_s0, "iii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_sat_rnd_lh_s1, "iii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_sat_rnd_ll_s0, "iii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_sat_rnd_ll_s1, "iii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyd_acc_hh_s0, "LLiLLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyd_acc_hh_s1, "LLiLLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyd_acc_hl_s0, "LLiLLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyd_acc_hl_s1, "LLiLLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyd_acc_lh_s0, "LLiLLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyd_acc_lh_s1, "LLiLLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyd_acc_ll_s0, "LLiLLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyd_acc_ll_s1, "LLiLLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyd_nac_hh_s0, "LLiLLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyd_nac_hh_s1, "LLiLLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyd_nac_hl_s0, "LLiLLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyd_nac_hl_s1, "LLiLLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyd_nac_lh_s0, "LLiLLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyd_nac_lh_s1, "LLiLLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyd_nac_ll_s0, "LLiLLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyd_nac_ll_s1, "LLiLLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyd_hh_s0, "LLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyd_hh_s1, "LLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyd_hl_s0, "LLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyd_hl_s1, "LLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyd_lh_s0, "LLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyd_lh_s1, "LLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyd_ll_s0, "LLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyd_ll_s1, "LLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyd_rnd_hh_s0, "LLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyd_rnd_hh_s1, "LLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyd_rnd_hl_s0, "LLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyd_rnd_hl_s1, "LLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyd_rnd_lh_s0, "LLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyd_rnd_lh_s1, "LLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyd_rnd_ll_s0, "LLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyd_rnd_ll_s1, "LLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyu_acc_hh_s0, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyu_acc_hh_s1, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyu_acc_hl_s0, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyu_acc_hl_s1, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyu_acc_lh_s0, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyu_acc_lh_s1, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyu_acc_ll_s0, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyu_acc_ll_s1, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyu_nac_hh_s0, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyu_nac_hh_s1, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyu_nac_hl_s0, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyu_nac_hl_s1, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyu_nac_lh_s0, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyu_nac_lh_s1, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyu_nac_ll_s0, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyu_nac_ll_s1, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyu_hh_s0, "Uiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyu_hh_s1, "Uiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyu_hl_s0, "Uiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyu_hl_s1, "Uiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyu_lh_s0, "Uiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyu_lh_s1, "Uiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyu_ll_s0, "Uiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyu_ll_s1, "Uiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyud_acc_hh_s0, "LLiLLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyud_acc_hh_s1, "LLiLLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyud_acc_hl_s0, "LLiLLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyud_acc_hl_s1, "LLiLLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyud_acc_lh_s0, "LLiLLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyud_acc_lh_s1, "LLiLLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyud_acc_ll_s0, "LLiLLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyud_acc_ll_s1, "LLiLLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyud_nac_hh_s0, "LLiLLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyud_nac_hh_s1, "LLiLLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyud_nac_hl_s0, "LLiLLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyud_nac_hl_s1, "LLiLLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyud_nac_lh_s0, "LLiLLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyud_nac_lh_s1, "LLiLLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyud_nac_ll_s0, "LLiLLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyud_nac_ll_s1, "LLiLLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyud_hh_s0, "ULLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyud_hh_s1, "ULLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyud_hl_s0, "ULLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyud_hl_s1, "ULLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyud_lh_s0, "ULLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyud_lh_s1, "ULLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyud_ll_s0, "ULLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyud_ll_s1, "ULLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpysmi, "iii", "") +BUILTIN(__builtin_HEXAGON_M2_macsip, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_macsin, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_dpmpyss_s0, "LLiii", "") +BUILTIN(__builtin_HEXAGON_M2_dpmpyss_acc_s0, "LLiLLiii", "") +BUILTIN(__builtin_HEXAGON_M2_dpmpyss_nac_s0, "LLiLLiii", "") +BUILTIN(__builtin_HEXAGON_M2_dpmpyuu_s0, "ULLiii", "") +BUILTIN(__builtin_HEXAGON_M2_dpmpyuu_acc_s0, "LLiLLiii", "") +BUILTIN(__builtin_HEXAGON_M2_dpmpyuu_nac_s0, "LLiLLiii", "") +BUILTIN(__builtin_HEXAGON_M2_mpy_up, "iii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyu_up, "Uiii", "") +BUILTIN(__builtin_HEXAGON_M2_dpmpyss_rnd_s0, "iii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyi, "iii", "") +BUILTIN(__builtin_HEXAGON_M2_mpyui, "iii", "") +BUILTIN(__builtin_HEXAGON_M2_maci, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_acci, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_accii, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_nacci, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_naccii, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_subacc, "iiii", "") +BUILTIN(__builtin_HEXAGON_M2_vmpy2s_s0, "LLiii", "") +BUILTIN(__builtin_HEXAGON_M2_vmpy2s_s1, "LLiii", "") +BUILTIN(__builtin_HEXAGON_M2_vmac2s_s0, "LLiLLiii", "") +BUILTIN(__builtin_HEXAGON_M2_vmac2s_s1, "LLiLLiii", "") +BUILTIN(__builtin_HEXAGON_M2_vmpy2s_s0pack, "iii", "") +BUILTIN(__builtin_HEXAGON_M2_vmpy2s_s1pack, "iii", "") +BUILTIN(__builtin_HEXAGON_M2_vmac2, "LLiLLiii", "") +BUILTIN(__builtin_HEXAGON_M2_vmpy2es_s0, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_vmpy2es_s1, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_vmac2es_s0, "LLiLLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_vmac2es_s1, "LLiLLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_vmac2es, "LLiLLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_vrmac_s0, "LLiLLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_vrmpy_s0, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_vdmpyrs_s0, "iLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_vdmpyrs_s1, "iLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_vdmacs_s0, "LLiLLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_vdmacs_s1, "LLiLLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_vdmpys_s0, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_vdmpys_s1, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_cmpyrs_s0, "iii", "") +BUILTIN(__builtin_HEXAGON_M2_cmpyrs_s1, "iii", "") +BUILTIN(__builtin_HEXAGON_M2_cmpyrsc_s0, "iii", "") +BUILTIN(__builtin_HEXAGON_M2_cmpyrsc_s1, "iii", "") +BUILTIN(__builtin_HEXAGON_M2_cmacs_s0, "LLiLLiii", "") +BUILTIN(__builtin_HEXAGON_M2_cmacs_s1, "LLiLLiii", "") +BUILTIN(__builtin_HEXAGON_M2_cmacsc_s0, "LLiLLiii", "") +BUILTIN(__builtin_HEXAGON_M2_cmacsc_s1, "LLiLLiii", "") +BUILTIN(__builtin_HEXAGON_M2_cmpys_s0, "LLiii", "") +BUILTIN(__builtin_HEXAGON_M2_cmpys_s1, "LLiii", "") +BUILTIN(__builtin_HEXAGON_M2_cmpysc_s0, "LLiii", "") +BUILTIN(__builtin_HEXAGON_M2_cmpysc_s1, "LLiii", "") +BUILTIN(__builtin_HEXAGON_M2_cnacs_s0, "LLiLLiii", "") +BUILTIN(__builtin_HEXAGON_M2_cnacs_s1, "LLiLLiii", "") +BUILTIN(__builtin_HEXAGON_M2_cnacsc_s0, "LLiLLiii", "") +BUILTIN(__builtin_HEXAGON_M2_cnacsc_s1, "LLiLLiii", "") +BUILTIN(__builtin_HEXAGON_M2_vrcmpys_s1, "LLiLLii", "") +BUILTIN(__builtin_HEXAGON_M2_vrcmpys_acc_s1, "LLiLLiLLii", "") +BUILTIN(__builtin_HEXAGON_M2_vrcmpys_s1rp, "iLLii", "") +BUILTIN(__builtin_HEXAGON_M2_mmacls_s0, "LLiLLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_mmacls_s1, "LLiLLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_mmachs_s0, "LLiLLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_mmachs_s1, "LLiLLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_mmpyl_s0, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_mmpyl_s1, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_mmpyh_s0, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_mmpyh_s1, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_mmacls_rs0, "LLiLLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_mmacls_rs1, "LLiLLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_mmachs_rs0, "LLiLLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_mmachs_rs1, "LLiLLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_mmpyl_rs0, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_mmpyl_rs1, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_mmpyh_rs0, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_mmpyh_rs1, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_hmmpyl_rs1, "iii", "") +BUILTIN(__builtin_HEXAGON_M2_hmmpyh_rs1, "iii", "") +BUILTIN(__builtin_HEXAGON_M2_mmaculs_s0, "LLiLLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_mmaculs_s1, "LLiLLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_mmacuhs_s0, "LLiLLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_mmacuhs_s1, "LLiLLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_mmpyul_s0, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_mmpyul_s1, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_mmpyuh_s0, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_mmpyuh_s1, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_mmaculs_rs0, "LLiLLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_mmaculs_rs1, "LLiLLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_mmacuhs_rs0, "LLiLLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_mmacuhs_rs1, "LLiLLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_mmpyul_rs0, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_mmpyul_rs1, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_mmpyuh_rs0, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_mmpyuh_rs1, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_vrcmaci_s0, "LLiLLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_vrcmacr_s0, "LLiLLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_vrcmaci_s0c, "LLiLLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_vrcmacr_s0c, "LLiLLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_cmaci_s0, "LLiLLiii", "") +BUILTIN(__builtin_HEXAGON_M2_cmacr_s0, "LLiLLiii", "") +BUILTIN(__builtin_HEXAGON_M2_vrcmpyi_s0, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_vrcmpyr_s0, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_vrcmpyi_s0c, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_vrcmpyr_s0c, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_cmpyi_s0, "LLiii", "") +BUILTIN(__builtin_HEXAGON_M2_cmpyr_s0, "LLiii", "") +BUILTIN(__builtin_HEXAGON_M2_vcmpy_s0_sat_i, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_vcmpy_s0_sat_r, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_vcmpy_s1_sat_i, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_vcmpy_s1_sat_r, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_vcmac_s0_sat_i, "LLiLLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_vcmac_s0_sat_r, "LLiLLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_S2_vcrotate, "LLiLLii", "") +BUILTIN(__builtin_HEXAGON_A2_add, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_sub, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_addsat, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_subsat, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_addi, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_addh_l16_ll, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_addh_l16_hl, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_addh_l16_sat_ll, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_addh_l16_sat_hl, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_subh_l16_ll, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_subh_l16_hl, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_subh_l16_sat_ll, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_subh_l16_sat_hl, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_addh_h16_ll, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_addh_h16_lh, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_addh_h16_hl, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_addh_h16_hh, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_addh_h16_sat_ll, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_addh_h16_sat_lh, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_addh_h16_sat_hl, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_addh_h16_sat_hh, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_subh_h16_ll, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_subh_h16_lh, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_subh_h16_hl, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_subh_h16_hh, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_subh_h16_sat_ll, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_subh_h16_sat_lh, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_subh_h16_sat_hl, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_subh_h16_sat_hh, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_aslh, "ii", "") +BUILTIN(__builtin_HEXAGON_A2_asrh, "ii", "") +BUILTIN(__builtin_HEXAGON_A2_addp, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_addpsat, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_addsp, "LLiiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_subp, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_neg, "ii", "") +BUILTIN(__builtin_HEXAGON_A2_negsat, "ii", "") +BUILTIN(__builtin_HEXAGON_A2_abs, "ii", "") +BUILTIN(__builtin_HEXAGON_A2_abssat, "ii", "") +BUILTIN(__builtin_HEXAGON_A2_vconj, "LLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_negp, "LLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_absp, "LLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_max, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_maxu, "Uiii", "") +BUILTIN(__builtin_HEXAGON_A2_min, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_minu, "Uiii", "") +BUILTIN(__builtin_HEXAGON_A2_maxp, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_maxup, "ULLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_minp, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_minup, "ULLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_tfr, "ii", "") +BUILTIN(__builtin_HEXAGON_A2_tfrsi, "ii", "") +BUILTIN(__builtin_HEXAGON_A2_tfrp, "LLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_tfrpi, "LLii", "") +BUILTIN(__builtin_HEXAGON_A2_zxtb, "ii", "") +BUILTIN(__builtin_HEXAGON_A2_sxtb, "ii", "") +BUILTIN(__builtin_HEXAGON_A2_zxth, "ii", "") +BUILTIN(__builtin_HEXAGON_A2_sxth, "ii", "") +BUILTIN(__builtin_HEXAGON_A2_combinew, "LLiii", "") +BUILTIN(__builtin_HEXAGON_A2_combineii, "LLiii", "") +BUILTIN(__builtin_HEXAGON_A2_combine_hh, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_combine_hl, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_combine_lh, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_combine_ll, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_tfril, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_tfrih, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_and, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_or, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_xor, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_not, "ii", "") +BUILTIN(__builtin_HEXAGON_M2_xor_xacc, "iiii", "") +BUILTIN(__builtin_HEXAGON_A2_subri, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_andir, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_orir, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_andp, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_orp, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_xorp, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_notp, "LLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_sxtw, "LLii", "") +BUILTIN(__builtin_HEXAGON_A2_sat, "iLLi", "") +BUILTIN(__builtin_HEXAGON_A2_sath, "ii", "") +BUILTIN(__builtin_HEXAGON_A2_satuh, "ii", "") +BUILTIN(__builtin_HEXAGON_A2_satub, "ii", "") +BUILTIN(__builtin_HEXAGON_A2_satb, "ii", "") +BUILTIN(__builtin_HEXAGON_A2_vaddub, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vaddubs, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vaddh, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vaddhs, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vadduhs, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vaddw, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vaddws, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_svavgh, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_svavghs, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_svnavgh, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_svaddh, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_svaddhs, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_svadduhs, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_svsubh, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_svsubhs, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_svsubuhs, "iii", "") +BUILTIN(__builtin_HEXAGON_A2_vraddub, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vraddub_acc, "LLiLLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_vradduh, "iLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vsubub, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vsububs, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vsubh, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vsubhs, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vsubuhs, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vsubw, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vsubws, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vabsh, "LLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vabshsat, "LLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vabsw, "LLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vabswsat, "LLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_vabsdiffw, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_M2_vabsdiffh, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vrsadub, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vrsadub_acc, "LLiLLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vavgub, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vavguh, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vavgh, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vnavgh, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vavgw, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vnavgw, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vavgwr, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vnavgwr, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vavgwcr, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vnavgwcr, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vavghcr, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vnavghcr, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vavguw, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vavguwr, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vavgubr, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vavguhr, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vavghr, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vnavghr, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vminh, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vmaxh, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vminub, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vmaxub, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vminuh, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vmaxuh, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vminw, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vmaxw, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vminuw, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A2_vmaxuw, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_S2_asr_r_r, "iii", "") +BUILTIN(__builtin_HEXAGON_S2_asl_r_r, "iii", "") +BUILTIN(__builtin_HEXAGON_S2_lsr_r_r, "iii", "") +BUILTIN(__builtin_HEXAGON_S2_lsl_r_r, "iii", "") +BUILTIN(__builtin_HEXAGON_S2_asr_r_p, "LLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_asl_r_p, "LLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_lsr_r_p, "LLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_lsl_r_p, "LLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_asr_r_r_acc, "iiii", "") +BUILTIN(__builtin_HEXAGON_S2_asl_r_r_acc, "iiii", "") +BUILTIN(__builtin_HEXAGON_S2_lsr_r_r_acc, "iiii", "") +BUILTIN(__builtin_HEXAGON_S2_lsl_r_r_acc, "iiii", "") +BUILTIN(__builtin_HEXAGON_S2_asr_r_p_acc, "LLiLLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_asl_r_p_acc, "LLiLLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_lsr_r_p_acc, "LLiLLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_lsl_r_p_acc, "LLiLLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_asr_r_r_nac, "iiii", "") +BUILTIN(__builtin_HEXAGON_S2_asl_r_r_nac, "iiii", "") +BUILTIN(__builtin_HEXAGON_S2_lsr_r_r_nac, "iiii", "") +BUILTIN(__builtin_HEXAGON_S2_lsl_r_r_nac, "iiii", "") +BUILTIN(__builtin_HEXAGON_S2_asr_r_p_nac, "LLiLLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_asl_r_p_nac, "LLiLLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_lsr_r_p_nac, "LLiLLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_lsl_r_p_nac, "LLiLLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_asr_r_r_and, "iiii", "") +BUILTIN(__builtin_HEXAGON_S2_asl_r_r_and, "iiii", "") +BUILTIN(__builtin_HEXAGON_S2_lsr_r_r_and, "iiii", "") +BUILTIN(__builtin_HEXAGON_S2_lsl_r_r_and, "iiii", "") +BUILTIN(__builtin_HEXAGON_S2_asr_r_r_or, "iiii", "") +BUILTIN(__builtin_HEXAGON_S2_asl_r_r_or, "iiii", "") +BUILTIN(__builtin_HEXAGON_S2_lsr_r_r_or, "iiii", "") +BUILTIN(__builtin_HEXAGON_S2_lsl_r_r_or, "iiii", "") +BUILTIN(__builtin_HEXAGON_S2_asr_r_p_and, "LLiLLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_asl_r_p_and, "LLiLLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_lsr_r_p_and, "LLiLLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_lsl_r_p_and, "LLiLLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_asr_r_p_or, "LLiLLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_asl_r_p_or, "LLiLLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_lsr_r_p_or, "LLiLLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_lsl_r_p_or, "LLiLLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_asr_r_r_sat, "iii", "") +BUILTIN(__builtin_HEXAGON_S2_asl_r_r_sat, "iii", "") +BUILTIN(__builtin_HEXAGON_S2_asr_i_r, "iii", "") +BUILTIN(__builtin_HEXAGON_S2_lsr_i_r, "iii", "") +BUILTIN(__builtin_HEXAGON_S2_asl_i_r, "iii", "") +BUILTIN(__builtin_HEXAGON_S2_asr_i_p, "LLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_lsr_i_p, "LLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_asl_i_p, "LLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_asr_i_r_acc, "iiii", "") +BUILTIN(__builtin_HEXAGON_S2_lsr_i_r_acc, "iiii", "") +BUILTIN(__builtin_HEXAGON_S2_asl_i_r_acc, "iiii", "") +BUILTIN(__builtin_HEXAGON_S2_asr_i_p_acc, "LLiLLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_lsr_i_p_acc, "LLiLLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_asl_i_p_acc, "LLiLLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_asr_i_r_nac, "iiii", "") +BUILTIN(__builtin_HEXAGON_S2_lsr_i_r_nac, "iiii", "") +BUILTIN(__builtin_HEXAGON_S2_asl_i_r_nac, "iiii", "") +BUILTIN(__builtin_HEXAGON_S2_asr_i_p_nac, "LLiLLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_lsr_i_p_nac, "LLiLLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_asl_i_p_nac, "LLiLLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_lsr_i_r_xacc, "iiii", "") +BUILTIN(__builtin_HEXAGON_S2_asl_i_r_xacc, "iiii", "") +BUILTIN(__builtin_HEXAGON_S2_lsr_i_p_xacc, "LLiLLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_asl_i_p_xacc, "LLiLLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_asr_i_r_and, "iiii", "") +BUILTIN(__builtin_HEXAGON_S2_lsr_i_r_and, "iiii", "") +BUILTIN(__builtin_HEXAGON_S2_asl_i_r_and, "iiii", "") +BUILTIN(__builtin_HEXAGON_S2_asr_i_r_or, "iiii", "") +BUILTIN(__builtin_HEXAGON_S2_lsr_i_r_or, "iiii", "") +BUILTIN(__builtin_HEXAGON_S2_asl_i_r_or, "iiii", "") +BUILTIN(__builtin_HEXAGON_S2_asr_i_p_and, "LLiLLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_lsr_i_p_and, "LLiLLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_asl_i_p_and, "LLiLLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_asr_i_p_or, "LLiLLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_lsr_i_p_or, "LLiLLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_asl_i_p_or, "LLiLLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_asl_i_r_sat, "iii", "") +BUILTIN(__builtin_HEXAGON_S2_asr_i_r_rnd, "iii", "") +BUILTIN(__builtin_HEXAGON_S2_asr_i_r_rnd_goodsyntax, "iii", "") +BUILTIN(__builtin_HEXAGON_S2_addasl_rrri, "iiii", "") +BUILTIN(__builtin_HEXAGON_S2_valignib, "LLiLLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_valignrb, "LLiLLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_vspliceib, "LLiLLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_vsplicerb, "LLiLLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_vsplatrh, "LLii", "") +BUILTIN(__builtin_HEXAGON_S2_vsplatrb, "ii", "") +BUILTIN(__builtin_HEXAGON_S2_insert, "iiiii", "") +BUILTIN(__builtin_HEXAGON_S2_tableidxb_goodsyntax, "iiiii", "") +BUILTIN(__builtin_HEXAGON_S2_tableidxh_goodsyntax, "iiiii", "") +BUILTIN(__builtin_HEXAGON_S2_tableidxw_goodsyntax, "iiiii", "") +BUILTIN(__builtin_HEXAGON_S2_tableidxd_goodsyntax, "iiiii", "") +BUILTIN(__builtin_HEXAGON_S2_extractu, "iiii", "") +BUILTIN(__builtin_HEXAGON_S2_insertp, "LLiLLiLLiii", "") +BUILTIN(__builtin_HEXAGON_S2_extractup, "LLiLLiii", "") +BUILTIN(__builtin_HEXAGON_S2_insert_rp, "iiiLLi", "") +BUILTIN(__builtin_HEXAGON_S2_extractu_rp, "iiLLi", "") +BUILTIN(__builtin_HEXAGON_S2_insertp_rp, "LLiLLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_S2_extractup_rp, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_S2_tstbit_i, "bii", "") +BUILTIN(__builtin_HEXAGON_S2_setbit_i, "iii", "") +BUILTIN(__builtin_HEXAGON_S2_togglebit_i, "iii", "") +BUILTIN(__builtin_HEXAGON_S2_clrbit_i, "iii", "") +BUILTIN(__builtin_HEXAGON_S2_tstbit_r, "bii", "") +BUILTIN(__builtin_HEXAGON_S2_setbit_r, "iii", "") +BUILTIN(__builtin_HEXAGON_S2_togglebit_r, "iii", "") +BUILTIN(__builtin_HEXAGON_S2_clrbit_r, "iii", "") +BUILTIN(__builtin_HEXAGON_S2_asr_i_vh, "LLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_lsr_i_vh, "LLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_asl_i_vh, "LLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_asr_r_vh, "LLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_asl_r_vh, "LLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_lsr_r_vh, "LLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_lsl_r_vh, "LLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_asr_i_vw, "LLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_asr_i_svw_trun, "iLLii", "") +BUILTIN(__builtin_HEXAGON_S2_asr_r_svw_trun, "iLLii", "") +BUILTIN(__builtin_HEXAGON_S2_lsr_i_vw, "LLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_asl_i_vw, "LLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_asr_r_vw, "LLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_asl_r_vw, "LLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_lsr_r_vw, "LLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_lsl_r_vw, "LLiLLii", "") +BUILTIN(__builtin_HEXAGON_S2_vrndpackwh, "iLLi", "") +BUILTIN(__builtin_HEXAGON_S2_vrndpackwhs, "iLLi", "") +BUILTIN(__builtin_HEXAGON_S2_vsxtbh, "LLii", "") +BUILTIN(__builtin_HEXAGON_S2_vzxtbh, "LLii", "") +BUILTIN(__builtin_HEXAGON_S2_vsathub, "iLLi", "") +BUILTIN(__builtin_HEXAGON_S2_svsathub, "ii", "") +BUILTIN(__builtin_HEXAGON_S2_svsathb, "ii", "") +BUILTIN(__builtin_HEXAGON_S2_vsathb, "iLLi", "") +BUILTIN(__builtin_HEXAGON_S2_vtrunohb, "iLLi", "") +BUILTIN(__builtin_HEXAGON_S2_vtrunewh, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_S2_vtrunowh, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_S2_vtrunehb, "iLLi", "") +BUILTIN(__builtin_HEXAGON_S2_vsxthw, "LLii", "") +BUILTIN(__builtin_HEXAGON_S2_vzxthw, "LLii", "") +BUILTIN(__builtin_HEXAGON_S2_vsatwh, "iLLi", "") +BUILTIN(__builtin_HEXAGON_S2_vsatwuh, "iLLi", "") +BUILTIN(__builtin_HEXAGON_S2_packhl, "LLiii", "") +BUILTIN(__builtin_HEXAGON_A2_swiz, "ii", "") +BUILTIN(__builtin_HEXAGON_S2_vsathub_nopack, "LLiLLi", "") +BUILTIN(__builtin_HEXAGON_S2_vsathb_nopack, "LLiLLi", "") +BUILTIN(__builtin_HEXAGON_S2_vsatwh_nopack, "LLiLLi", "") +BUILTIN(__builtin_HEXAGON_S2_vsatwuh_nopack, "LLiLLi", "") +BUILTIN(__builtin_HEXAGON_S2_shuffob, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_S2_shuffeb, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_S2_shuffoh, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_S2_shuffeh, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_S2_parityp, "iLLiLLi", "") +BUILTIN(__builtin_HEXAGON_S2_lfsp, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_S2_clbnorm, "ii", "") +BUILTIN(__builtin_HEXAGON_S2_clb, "ii", "") +BUILTIN(__builtin_HEXAGON_S2_cl0, "ii", "") +BUILTIN(__builtin_HEXAGON_S2_cl1, "ii", "") +BUILTIN(__builtin_HEXAGON_S2_clbp, "iLLi", "") +BUILTIN(__builtin_HEXAGON_S2_cl0p, "iLLi", "") +BUILTIN(__builtin_HEXAGON_S2_cl1p, "iLLi", "") +BUILTIN(__builtin_HEXAGON_S2_brev, "ii", "") +BUILTIN(__builtin_HEXAGON_S2_ct0, "ii", "") +BUILTIN(__builtin_HEXAGON_S2_ct1, "ii", "") +BUILTIN(__builtin_HEXAGON_S2_interleave, "LLiLLi", "") +BUILTIN(__builtin_HEXAGON_S2_deinterleave, "LLiLLi", "") + +BUILTIN(__builtin_SI_to_SXTHI_asrh, "ii", "") + +BUILTIN(__builtin_M2_vrcmpys_s1, "LLiLLii", "") +BUILTIN(__builtin_M2_vrcmpys_acc_s1, "LLiLLiLLii", "") +BUILTIN(__builtin_M2_vrcmpys_s1rp, "iLLii", "") + +BUILTIN(__builtin_M2_vradduh, "iLLiLLi", "") +BUILTIN(__builtin_A2_addsp, "LLiiLLi", "") +BUILTIN(__builtin_A2_addpsat, "LLiLLiLLi", "") + +BUILTIN(__builtin_A2_maxp, "LLiLLiLLi", "") +BUILTIN(__builtin_A2_maxup, "LLiLLiLLi", "") + +BUILTIN(__builtin_HEXAGON_A4_orn, "iii", "") +BUILTIN(__builtin_HEXAGON_A4_andn, "iii", "") +BUILTIN(__builtin_HEXAGON_A4_ornp, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A4_andnp, "LLiLLiLLi", "") +BUILTIN(__builtin_HEXAGON_A4_combineir, "LLiii", "") +BUILTIN(__builtin_HEXAGON_A4_combineri, "LLiii", "") +BUILTIN(__builtin_HEXAGON_C4_cmpneqi, "bii", "") +BUILTIN(__builtin_HEXAGON_C4_cmpneq, "bii", "") +BUILTIN(__builtin_HEXAGON_C4_cmpltei, "bii", "") +BUILTIN(__builtin_HEXAGON_C4_cmplte, "bii", "") +BUILTIN(__builtin_HEXAGON_C4_cmplteui, "bii", "") +BUILTIN(__builtin_HEXAGON_C4_cmplteu, "bii", "") +BUILTIN(__builtin_HEXAGON_A4_rcmpneq, "iii", "") +BUILTIN(__builtin_HEXAGON_A4_rcmpneqi, "iii", "") +BUILTIN(__builtin_HEXAGON_A4_rcmpeq, "iii", "") +BUILTIN(__builtin_HEXAGON_A4_rcmpeqi, "iii", "") +BUILTIN(__builtin_HEXAGON_C4_fastcorner9, "bii", "") +BUILTIN(__builtin_HEXAGON_C4_fastcorner9_not, "bii", "") +BUILTIN(__builtin_HEXAGON_C4_and_andn, "biii", "") +BUILTIN(__builtin_HEXAGON_C4_and_and, "biii", "") +BUILTIN(__builtin_HEXAGON_C4_and_orn, "biii", "") +BUILTIN(__builtin_HEXAGON_C4_and_or, "biii", "") +BUILTIN(__builtin_HEXAGON_C4_or_andn, "biii", "") +BUILTIN(__builtin_HEXAGON_C4_or_and, "biii", "") +BUILTIN(__builtin_HEXAGON_C4_or_orn, "biii", "") +BUILTIN(__builtin_HEXAGON_C4_or_or, "biii", "") +BUILTIN(__builtin_HEXAGON_S4_addaddi, "iiii", "") +BUILTIN(__builtin_HEXAGON_S4_subaddi, "iiii", "") +BUILTIN(__builtin_HEXAGON_M4_xor_xacc, "LLiLLiLLiLLi", "") + +BUILTIN(__builtin_HEXAGON_M4_and_and, "iiii", "") +BUILTIN(__builtin_HEXAGON_M4_and_or, "iiii", "") +BUILTIN(__builtin_HEXAGON_M4_and_xor, "iiii", "") +BUILTIN(__builtin_HEXAGON_M4_and_andn, "iiii", "") +BUILTIN(__builtin_HEXAGON_M4_xor_and, "iiii", "") +BUILTIN(__builtin_HEXAGON_M4_xor_or, "iiii", "") +BUILTIN(__builtin_HEXAGON_M4_xor_andn, "iiii", "") +BUILTIN(__builtin_HEXAGON_M4_or_and, "iiii", "") +BUILTIN(__builtin_HEXAGON_M4_or_or, "iiii", "") +BUILTIN(__builtin_HEXAGON_M4_or_xor, "iiii", "") +BUILTIN(__builtin_HEXAGON_M4_or_andn, "iiii", "") +BUILTIN(__builtin_HEXAGON_S4_or_andix, "iiii", "") +BUILTIN(__builtin_HEXAGON_S4_or_andi, "iiii", "") +BUILTIN(__builtin_HEXAGON_S4_or_ori, "iiii", "") + +BUILTIN(__builtin_HEXAGON_A4_modwrapu, "iii", "") + +BUILTIN(__builtin_HEXAGON_A4_cround_ri, "iii", "") +BUILTIN(__builtin_HEXAGON_A4_cround_rr, "iii", "") +BUILTIN(__builtin_HEXAGON_A4_round_ri, "iii", "") +BUILTIN(__builtin_HEXAGON_A4_round_rr, "iii", "") +BUILTIN(__builtin_HEXAGON_A4_round_ri_sat, "iii", "") +BUILTIN(__builtin_HEXAGON_A4_round_rr_sat, "iii", "") + +#undef BUILTIN diff --git a/clang/include/clang/Basic/BuiltinsPPC.def b/clang/include/clang/Basic/BuiltinsPPC.def new file mode 100644 index 0000000..8a751e4 --- /dev/null +++ b/clang/include/clang/Basic/BuiltinsPPC.def @@ -0,0 +1,209 @@ +//===--- BuiltinsPPC.def - PowerPC Builtin function database ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the PowerPC-specific builtin function database. Users of +// this file must define the BUILTIN macro to make use of this information. +// +//===----------------------------------------------------------------------===// + +// FIXME: this needs to be the full list supported by GCC. Right now, I'm just +// adding stuff on demand. + +// The format of this database matches clang/Basic/Builtins.def. + +// This is just a placeholder, the types and attributes are wrong. +BUILTIN(__builtin_altivec_vaddcuw, "V4UiV4UiV4Ui", "") + +BUILTIN(__builtin_altivec_vaddsbs, "V16ScV16ScV16Sc", "") +BUILTIN(__builtin_altivec_vaddubs, "V16UcV16UcV16Uc", "") +BUILTIN(__builtin_altivec_vaddshs, "V8SsV8SsV8Ss", "") +BUILTIN(__builtin_altivec_vadduhs, "V8UsV8UsV8Us", "") +BUILTIN(__builtin_altivec_vaddsws, "V4SiV4SiV4Si", "") +BUILTIN(__builtin_altivec_vadduws, "V4UiV4UiV4Ui", "") + +BUILTIN(__builtin_altivec_vsubsbs, "V16ScV16ScV16Sc", "") +BUILTIN(__builtin_altivec_vsububs, "V16UcV16UcV16Uc", "") +BUILTIN(__builtin_altivec_vsubshs, "V8SsV8SsV8Ss", "") +BUILTIN(__builtin_altivec_vsubuhs, "V8UsV8UsV8Us", "") +BUILTIN(__builtin_altivec_vsubsws, "V4SiV4SiV4Si", "") +BUILTIN(__builtin_altivec_vsubuws, "V4UiV4UiV4Ui", "") + +BUILTIN(__builtin_altivec_vavgsb, "V16ScV16ScV16Sc", "") +BUILTIN(__builtin_altivec_vavgub, "V16UcV16UcV16Uc", "") +BUILTIN(__builtin_altivec_vavgsh, "V8SsV8SsV8Ss", "") +BUILTIN(__builtin_altivec_vavguh, "V8UsV8UsV8Us", "") +BUILTIN(__builtin_altivec_vavgsw, "V4SiV4SiV4Si", "") +BUILTIN(__builtin_altivec_vavguw, "V4UiV4UiV4Ui", "") + +BUILTIN(__builtin_altivec_vrfip, "V4fV4f", "") + +BUILTIN(__builtin_altivec_vcfsx, "V4fV4ii", "") +BUILTIN(__builtin_altivec_vcfux, "V4fV4ii", "") +BUILTIN(__builtin_altivec_vctsxs, "V4SiV4fi", "") +BUILTIN(__builtin_altivec_vctuxs, "V4UiV4fi", "") + +BUILTIN(__builtin_altivec_dss, "vUi", "") +BUILTIN(__builtin_altivec_dssall, "v", "") +BUILTIN(__builtin_altivec_dst, "vvC*iUi", "") +BUILTIN(__builtin_altivec_dstt, "vvC*iUi", "") +BUILTIN(__builtin_altivec_dstst, "vvC*iUi", "") +BUILTIN(__builtin_altivec_dststt, "vvC*iUi", "") + +BUILTIN(__builtin_altivec_vexptefp, "V4fV4f", "") + +BUILTIN(__builtin_altivec_vrfim, "V4fV4f", "") + +BUILTIN(__builtin_altivec_lvx, "V4iivC*", "") +BUILTIN(__builtin_altivec_lvxl, "V4iivC*", "") +BUILTIN(__builtin_altivec_lvebx, "V16civC*", "") +BUILTIN(__builtin_altivec_lvehx, "V8sivC*", "") +BUILTIN(__builtin_altivec_lvewx, "V4iivC*", "") + +BUILTIN(__builtin_altivec_vlogefp, "V4fV4f", "") + +BUILTIN(__builtin_altivec_lvsl, "V16cUcvC*", "") +BUILTIN(__builtin_altivec_lvsr, "V16cUcvC*", "") + +BUILTIN(__builtin_altivec_vmaddfp, "V4fV4fV4fV4f", "") +BUILTIN(__builtin_altivec_vmhaddshs, "V8sV8sV8sV8s", "") +BUILTIN(__builtin_altivec_vmhraddshs, "V8sV8sV8sV8s", "") + +BUILTIN(__builtin_altivec_vmsumubm, "V4UiV16UcV16UcV4Ui", "") +BUILTIN(__builtin_altivec_vmsummbm, "V4SiV16ScV16UcV4Si", "") +BUILTIN(__builtin_altivec_vmsumuhm, "V4UiV8UsV8UsV4Ui", "") +BUILTIN(__builtin_altivec_vmsumshm, "V4SiV8SsV8SsV4Si", "") +BUILTIN(__builtin_altivec_vmsumuhs, "V4UiV8UsV8UsV4Ui", "") +BUILTIN(__builtin_altivec_vmsumshs, "V4SiV8SsV8SsV4Si", "") + +BUILTIN(__builtin_altivec_vmuleub, "V8UsV16UcV16Uc", "") +BUILTIN(__builtin_altivec_vmulesb, "V8SsV16ScV16Sc", "") +BUILTIN(__builtin_altivec_vmuleuh, "V4UiV8UsV8Us", "") +BUILTIN(__builtin_altivec_vmulesh, "V4SiV8SsV8Ss", "") +BUILTIN(__builtin_altivec_vmuloub, "V8UsV16UcV16Uc", "") +BUILTIN(__builtin_altivec_vmulosb, "V8SsV16ScV16Sc", "") +BUILTIN(__builtin_altivec_vmulouh, "V4UiV8UsV8Us", "") +BUILTIN(__builtin_altivec_vmulosh, "V4SiV8SsV8Ss", "") + +BUILTIN(__builtin_altivec_vnmsubfp, "V4fV4fV4fV4f", "") + +BUILTIN(__builtin_altivec_vpkpx, "V8sV4UiV4Ui", "") +BUILTIN(__builtin_altivec_vpkuhus, "V16UcV8UsV8Us", "") +BUILTIN(__builtin_altivec_vpkshss, "V16ScV8SsV8Ss", "") +BUILTIN(__builtin_altivec_vpkuwus, "V8UsV4UiV4Ui", "") +BUILTIN(__builtin_altivec_vpkswss, "V8SsV4SiV4Si", "") +BUILTIN(__builtin_altivec_vpkshus, "V16UcV8SsV8Ss", "") +BUILTIN(__builtin_altivec_vpkswus, "V8UsV4SiV4Si", "") + +BUILTIN(__builtin_altivec_vperm_4si, "V4iV4iV4iV16Uc", "") + +BUILTIN(__builtin_altivec_stvx, "vV4iiv*", "") +BUILTIN(__builtin_altivec_stvxl, "vV4iiv*", "") +BUILTIN(__builtin_altivec_stvebx, "vV16civ*", "") +BUILTIN(__builtin_altivec_stvehx, "vV8siv*", "") +BUILTIN(__builtin_altivec_stvewx, "vV4iiv*", "") + +BUILTIN(__builtin_altivec_vcmpbfp, "V4iV4fV4f", "") + +BUILTIN(__builtin_altivec_vcmpgefp, "V4iV4fV4f", "") + +BUILTIN(__builtin_altivec_vcmpequb, "V16cV16cV16c", "") +BUILTIN(__builtin_altivec_vcmpequh, "V8sV8sV8s", "") +BUILTIN(__builtin_altivec_vcmpequw, "V4iV4iV4i", "") +BUILTIN(__builtin_altivec_vcmpeqfp, "V4iV4fV4f", "") + +BUILTIN(__builtin_altivec_vcmpgtsb, "V16cV16ScV16Sc", "") +BUILTIN(__builtin_altivec_vcmpgtub, "V16cV16UcV16Uc", "") +BUILTIN(__builtin_altivec_vcmpgtsh, "V8sV8SsV8Ss", "") +BUILTIN(__builtin_altivec_vcmpgtuh, "V8sV8UsV8Us", "") +BUILTIN(__builtin_altivec_vcmpgtsw, "V4iV4SiV4Si", "") +BUILTIN(__builtin_altivec_vcmpgtuw, "V4iV4UiV4Ui", "") +BUILTIN(__builtin_altivec_vcmpgtfp, "V4iV4fV4f", "") + +BUILTIN(__builtin_altivec_vmaxsb, "V16ScV16ScV16Sc", "") +BUILTIN(__builtin_altivec_vmaxub, "V16UcV16UcV16Uc", "") +BUILTIN(__builtin_altivec_vmaxsh, "V8SsV8SsV8Ss", "") +BUILTIN(__builtin_altivec_vmaxuh, "V8UsV8UsV8Us", "") +BUILTIN(__builtin_altivec_vmaxsw, "V4SiV4SiV4Si", "") +BUILTIN(__builtin_altivec_vmaxuw, "V4UiV4UiV4Ui", "") +BUILTIN(__builtin_altivec_vmaxfp, "V4fV4fV4f", "") + +BUILTIN(__builtin_altivec_mfvscr, "V8Us", "") + +BUILTIN(__builtin_altivec_vminsb, "V16ScV16ScV16Sc", "") +BUILTIN(__builtin_altivec_vminub, "V16UcV16UcV16Uc", "") +BUILTIN(__builtin_altivec_vminsh, "V8SsV8SsV8Ss", "") +BUILTIN(__builtin_altivec_vminuh, "V8UsV8UsV8Us", "") +BUILTIN(__builtin_altivec_vminsw, "V4SiV4SiV4Si", "") +BUILTIN(__builtin_altivec_vminuw, "V4UiV4UiV4Ui", "") +BUILTIN(__builtin_altivec_vminfp, "V4fV4fV4f", "") + +BUILTIN(__builtin_altivec_mtvscr, "vV4i", "") + +BUILTIN(__builtin_altivec_vrefp, "V4fV4f", "") + +BUILTIN(__builtin_altivec_vrlb, "V16cV16cV16Uc", "") +BUILTIN(__builtin_altivec_vrlh, "V8sV8sV8Us", "") +BUILTIN(__builtin_altivec_vrlw, "V4iV4iV4Ui", "") + +BUILTIN(__builtin_altivec_vsel_4si, "V4iV4iV4iV4Ui", "") + +BUILTIN(__builtin_altivec_vsl, "V4iV4iV4i", "") +BUILTIN(__builtin_altivec_vslo, "V4iV4iV4i", "") + +BUILTIN(__builtin_altivec_vsrab, "V16cV16cV16Uc", "") +BUILTIN(__builtin_altivec_vsrah, "V8sV8sV8Us", "") +BUILTIN(__builtin_altivec_vsraw, "V4iV4iV4Ui", "") + +BUILTIN(__builtin_altivec_vsr, "V4iV4iV4i", "") +BUILTIN(__builtin_altivec_vsro, "V4iV4iV4i", "") + +BUILTIN(__builtin_altivec_vrfin, "V4fV4f", "") + +BUILTIN(__builtin_altivec_vrsqrtefp, "V4fV4f", "") + +BUILTIN(__builtin_altivec_vsubcuw, "V4UiV4UiV4Ui", "") + +BUILTIN(__builtin_altivec_vsum4sbs, "V4SiV16ScV4Si", "") +BUILTIN(__builtin_altivec_vsum4ubs, "V4UiV16UcV4Ui", "") +BUILTIN(__builtin_altivec_vsum4shs, "V4SiV8SsV4Si", "") + +BUILTIN(__builtin_altivec_vsum2sws, "V4SiV4SiV4Si", "") + +BUILTIN(__builtin_altivec_vsumsws, "V4SiV4SiV4Si", "") + +BUILTIN(__builtin_altivec_vrfiz, "V4fV4f", "") + +BUILTIN(__builtin_altivec_vupkhsb, "V8sV16c", "") +BUILTIN(__builtin_altivec_vupkhpx, "V4UiV8s", "") +BUILTIN(__builtin_altivec_vupkhsh, "V4iV8s", "") + +BUILTIN(__builtin_altivec_vupklsb, "V8sV16c", "") +BUILTIN(__builtin_altivec_vupklpx, "V4UiV8s", "") +BUILTIN(__builtin_altivec_vupklsh, "V4iV8s", "") + +BUILTIN(__builtin_altivec_vcmpbfp_p, "iiV4fV4f", "") + +BUILTIN(__builtin_altivec_vcmpgefp_p, "iiV4fV4f", "") + +BUILTIN(__builtin_altivec_vcmpequb_p, "iiV16cV16c", "") +BUILTIN(__builtin_altivec_vcmpequh_p, "iiV8sV8s", "") +BUILTIN(__builtin_altivec_vcmpequw_p, "iiV4iV4i", "") +BUILTIN(__builtin_altivec_vcmpeqfp_p, "iiV4fV4f", "") + +BUILTIN(__builtin_altivec_vcmpgtsb_p, "iiV16ScV16Sc", "") +BUILTIN(__builtin_altivec_vcmpgtub_p, "iiV16UcV16Uc", "") +BUILTIN(__builtin_altivec_vcmpgtsh_p, "iiV8SsV8Ss", "") +BUILTIN(__builtin_altivec_vcmpgtuh_p, "iiV8UsV8Us", "") +BUILTIN(__builtin_altivec_vcmpgtsw_p, "iiV4SiV4Si", "") +BUILTIN(__builtin_altivec_vcmpgtuw_p, "iiV4UiV4Ui", "") +BUILTIN(__builtin_altivec_vcmpgtfp_p, "iiV4fV4f", "") + +// FIXME: Obviously incomplete. + +#undef BUILTIN diff --git a/clang/include/clang/Basic/BuiltinsPTX.def b/clang/include/clang/Basic/BuiltinsPTX.def new file mode 100644 index 0000000..f90a43f --- /dev/null +++ b/clang/include/clang/Basic/BuiltinsPTX.def @@ -0,0 +1,62 @@ +//===--- BuiltinsPTX.def - PTX Builtin function database ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the PTX-specific builtin function database. Users of +// this file must define the BUILTIN macro to make use of this information. +// +//===----------------------------------------------------------------------===// + +// The format of this database matches clang/Basic/Builtins.def. + +BUILTIN(__builtin_ptx_read_tid_x, "i", "nc") +BUILTIN(__builtin_ptx_read_tid_y, "i", "nc") +BUILTIN(__builtin_ptx_read_tid_z, "i", "nc") +BUILTIN(__builtin_ptx_read_tid_w, "i", "nc") + +BUILTIN(__builtin_ptx_read_ntid_x, "i", "nc") +BUILTIN(__builtin_ptx_read_ntid_y, "i", "nc") +BUILTIN(__builtin_ptx_read_ntid_z, "i", "nc") +BUILTIN(__builtin_ptx_read_ntid_w, "i", "nc") + +BUILTIN(__builtin_ptx_read_ctaid_x, "i", "nc") +BUILTIN(__builtin_ptx_read_ctaid_y, "i", "nc") +BUILTIN(__builtin_ptx_read_ctaid_z, "i", "nc") +BUILTIN(__builtin_ptx_read_ctaid_w, "i", "nc") + +BUILTIN(__builtin_ptx_read_nctaid_x, "i", "nc") +BUILTIN(__builtin_ptx_read_nctaid_y, "i", "nc") +BUILTIN(__builtin_ptx_read_nctaid_z, "i", "nc") +BUILTIN(__builtin_ptx_read_nctaid_w, "i", "nc") + +BUILTIN(__builtin_ptx_read_laneid, "i", "nc") +BUILTIN(__builtin_ptx_read_warpid, "i", "nc") +BUILTIN(__builtin_ptx_read_nwarpid, "i", "nc") + +BUILTIN(__builtin_ptx_read_smid, "i", "nc") +BUILTIN(__builtin_ptx_read_nsmid, "i", "nc") +BUILTIN(__builtin_ptx_read_gridid, "i", "nc") + +BUILTIN(__builtin_ptx_read_lanemask_eq, "i", "nc") +BUILTIN(__builtin_ptx_read_lanemask_le, "i", "nc") +BUILTIN(__builtin_ptx_read_lanemask_lt, "i", "nc") +BUILTIN(__builtin_ptx_read_lanemask_ge, "i", "nc") +BUILTIN(__builtin_ptx_read_lanemask_gt, "i", "nc") + +BUILTIN(__builtin_ptx_read_clock, "i", "n") +BUILTIN(__builtin_ptx_read_clock64, "Li", "n") + +BUILTIN(__builtin_ptx_read_pm0, "i", "n") +BUILTIN(__builtin_ptx_read_pm1, "i", "n") +BUILTIN(__builtin_ptx_read_pm2, "i", "n") +BUILTIN(__builtin_ptx_read_pm3, "i", "n") + +BUILTIN(__builtin_ptx_bar_sync, "vi", "n") + + +#undef BUILTIN diff --git a/clang/include/clang/Basic/BuiltinsX86.def b/clang/include/clang/Basic/BuiltinsX86.def new file mode 100644 index 0000000..4aea980 --- /dev/null +++ b/clang/include/clang/Basic/BuiltinsX86.def @@ -0,0 +1,635 @@ +//===--- BuiltinsX86.def - X86 Builtin function database --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the X86-specific builtin function database. Users of +// this file must define the BUILTIN macro to make use of this information. +// +//===----------------------------------------------------------------------===// + +// The format of this database matches clang/Basic/Builtins.def. + +// FIXME: In GCC, these builtins are defined depending on whether support for +// MMX/SSE/etc is turned on. We should do this too. + +// FIXME: Ideally we would be able to pull this information from what +// LLVM already knows about X86 builtins. We need to match the LLVM +// definition anyway, since code generation will lower to the +// intrinsic if one exists. + +// FIXME: Are these nothrow/const? + +// 3DNow! +// +BUILTIN(__builtin_ia32_femms, "v", "") +BUILTIN(__builtin_ia32_pavgusb, "V8cV8cV8c", "nc") +BUILTIN(__builtin_ia32_pf2id, "V2iV2f", "nc") +BUILTIN(__builtin_ia32_pfacc, "V2fV2fV2f", "nc") +BUILTIN(__builtin_ia32_pfadd, "V2fV2fV2f", "nc") +BUILTIN(__builtin_ia32_pfcmpeq, "V2iV2fV2f", "nc") +BUILTIN(__builtin_ia32_pfcmpge, "V2iV2fV2f", "nc") +BUILTIN(__builtin_ia32_pfcmpgt, "V2iV2fV2f", "nc") +BUILTIN(__builtin_ia32_pfmax, "V2fV2fV2f", "nc") +BUILTIN(__builtin_ia32_pfmin, "V2fV2fV2f", "nc") +BUILTIN(__builtin_ia32_pfmul, "V2fV2fV2f", "nc") +BUILTIN(__builtin_ia32_pfrcp, "V2fV2f", "nc") +BUILTIN(__builtin_ia32_pfrcpit1, "V2fV2fV2f", "nc") +BUILTIN(__builtin_ia32_pfrcpit2, "V2fV2fV2f", "nc") +BUILTIN(__builtin_ia32_pfrsqrt, "V2fV2f", "nc") +BUILTIN(__builtin_ia32_pfrsqit1, "V2fV2fV2f", "nc") +BUILTIN(__builtin_ia32_pfsub, "V2fV2fV2f", "nc") +BUILTIN(__builtin_ia32_pfsubr, "V2fV2fV2f", "nc") +BUILTIN(__builtin_ia32_pi2fd, "V2fV2i", "nc") +BUILTIN(__builtin_ia32_pmulhrw, "V4sV4sV4s", "nc") +// 3DNow! Extensions (3dnowa). +BUILTIN(__builtin_ia32_pf2iw, "V2iV2f", "nc") +BUILTIN(__builtin_ia32_pfnacc, "V2fV2fV2f", "nc") +BUILTIN(__builtin_ia32_pfpnacc, "V2fV2fV2f", "nc") +BUILTIN(__builtin_ia32_pi2fw, "V2fV2i", "nc") +BUILTIN(__builtin_ia32_pswapdsf, "V2fV2f", "nc") +BUILTIN(__builtin_ia32_pswapdsi, "V2iV2i", "nc") + +// MMX +// +// All MMX instructions will be generated via builtins. Any MMX vector +// types (<1 x i64>, <2 x i32>, etc.) that aren't used by these builtins will be +// expanded by the back-end. +BUILTIN(__builtin_ia32_emms, "v", "") +BUILTIN(__builtin_ia32_paddb, "V8cV8cV8c", "") +BUILTIN(__builtin_ia32_paddw, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_paddd, "V2iV2iV2i", "") +BUILTIN(__builtin_ia32_paddsb, "V8cV8cV8c", "") +BUILTIN(__builtin_ia32_paddsw, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_paddusb, "V8cV8cV8c", "") +BUILTIN(__builtin_ia32_paddusw, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_psubb, "V8cV8cV8c", "") +BUILTIN(__builtin_ia32_psubw, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_psubd, "V2iV2iV2i", "") +BUILTIN(__builtin_ia32_psubsb, "V8cV8cV8c", "") +BUILTIN(__builtin_ia32_psubsw, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_psubusb, "V8cV8cV8c", "") +BUILTIN(__builtin_ia32_psubusw, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_pmulhw, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_pmullw, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_pmaddwd, "V2iV4sV4s", "") +BUILTIN(__builtin_ia32_pand, "V1LLiV1LLiV1LLi", "") +BUILTIN(__builtin_ia32_pandn, "V1LLiV1LLiV1LLi", "") +BUILTIN(__builtin_ia32_por, "V1LLiV1LLiV1LLi", "") +BUILTIN(__builtin_ia32_pxor, "V1LLiV1LLiV1LLi", "") +BUILTIN(__builtin_ia32_psllw, "V4sV4sV1LLi", "") +BUILTIN(__builtin_ia32_pslld, "V2iV2iV1LLi", "") +BUILTIN(__builtin_ia32_psllq, "V1LLiV1LLiV1LLi", "") +BUILTIN(__builtin_ia32_psrlw, "V4sV4sV1LLi", "") +BUILTIN(__builtin_ia32_psrld, "V2iV2iV1LLi", "") +BUILTIN(__builtin_ia32_psrlq, "V1LLiV1LLiV1LLi", "") +BUILTIN(__builtin_ia32_psraw, "V4sV4sV1LLi", "") +BUILTIN(__builtin_ia32_psrad, "V2iV2iV1LLi", "") +BUILTIN(__builtin_ia32_psllwi, "V4sV4si", "") +BUILTIN(__builtin_ia32_pslldi, "V2iV2ii", "") +BUILTIN(__builtin_ia32_psllqi, "V1LLiV1LLii", "") +BUILTIN(__builtin_ia32_psrlwi, "V4sV4si", "") +BUILTIN(__builtin_ia32_psrldi, "V2iV2ii", "") +BUILTIN(__builtin_ia32_psrlqi, "V1LLiV1LLii", "") +BUILTIN(__builtin_ia32_psrawi, "V4sV4si", "") +BUILTIN(__builtin_ia32_psradi, "V2iV2ii", "") +BUILTIN(__builtin_ia32_packsswb, "V8cV4sV4s", "") +BUILTIN(__builtin_ia32_packssdw, "V4sV2iV2i", "") +BUILTIN(__builtin_ia32_packuswb, "V8cV4sV4s", "") +BUILTIN(__builtin_ia32_punpckhbw, "V8cV8cV8c", "") +BUILTIN(__builtin_ia32_punpckhwd, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_punpckhdq, "V2iV2iV2i", "") +BUILTIN(__builtin_ia32_punpcklbw, "V8cV8cV8c", "") +BUILTIN(__builtin_ia32_punpcklwd, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_punpckldq, "V2iV2iV2i", "") +BUILTIN(__builtin_ia32_pcmpeqb, "V8cV8cV8c", "") +BUILTIN(__builtin_ia32_pcmpeqw, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_pcmpeqd, "V2iV2iV2i", "") +BUILTIN(__builtin_ia32_pcmpgtb, "V8cV8cV8c", "") +BUILTIN(__builtin_ia32_pcmpgtw, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_pcmpgtd, "V2iV2iV2i", "") +BUILTIN(__builtin_ia32_maskmovq, "vV8cV8cc*", "") +BUILTIN(__builtin_ia32_movntq, "vV1LLi*V1LLi", "") +BUILTIN(__builtin_ia32_vec_init_v2si, "V2iii", "") +BUILTIN(__builtin_ia32_vec_init_v4hi, "V4sssss", "") +BUILTIN(__builtin_ia32_vec_init_v8qi, "V8ccccccccc", "") +BUILTIN(__builtin_ia32_vec_ext_v2si, "iV2ii", "") + +// MMX2 (MMX+SSE) intrinsics +BUILTIN(__builtin_ia32_cvtpi2ps, "V4fV4fV2i", "") +BUILTIN(__builtin_ia32_cvtps2pi, "V2iV4f", "") +BUILTIN(__builtin_ia32_cvttps2pi, "V2iV4f", "") +BUILTIN(__builtin_ia32_pavgb, "V8cV8cV8c", "") +BUILTIN(__builtin_ia32_pavgw, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_pmaxsw, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_pmaxub, "V8cV8cV8c", "") +BUILTIN(__builtin_ia32_pminsw, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_pminub, "V8cV8cV8c", "") +BUILTIN(__builtin_ia32_pmovmskb, "iV8c", "") +BUILTIN(__builtin_ia32_pmulhuw, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_psadbw, "V4sV8cV8c", "") +BUILTIN(__builtin_ia32_pshufw, "V4sV4sIc", "") + +// MMX+SSE2 +BUILTIN(__builtin_ia32_cvtpd2pi, "V2iV2d", "") +BUILTIN(__builtin_ia32_cvtpi2pd, "V2dV2i", "") +BUILTIN(__builtin_ia32_cvttpd2pi, "V2iV2d", "") +BUILTIN(__builtin_ia32_paddq, "V1LLiV1LLiV1LLi", "") +BUILTIN(__builtin_ia32_pmuludq, "V1LLiV2iV2i", "") +BUILTIN(__builtin_ia32_psubq, "V1LLiV1LLiV1LLi", "") + +// MMX+SSSE3 +BUILTIN(__builtin_ia32_pabsb, "V8cV8c", "") +BUILTIN(__builtin_ia32_pabsd, "V2iV2i", "") +BUILTIN(__builtin_ia32_pabsw, "V4sV4s", "") +BUILTIN(__builtin_ia32_palignr, "V8cV8cV8cIc", "") +BUILTIN(__builtin_ia32_phaddd, "V2iV2iV2i", "") +BUILTIN(__builtin_ia32_phaddsw, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_phaddw, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_phsubd, "V2iV2iV2i", "") +BUILTIN(__builtin_ia32_phsubsw, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_phsubw, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_pmaddubsw, "V8cV8cV8c", "") +BUILTIN(__builtin_ia32_pmulhrsw, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_pshufb, "V8cV8cV8c", "") +BUILTIN(__builtin_ia32_psignw, "V4sV4sV4s", "") +BUILTIN(__builtin_ia32_psignb, "V8cV8cV8c", "") +BUILTIN(__builtin_ia32_psignd, "V2iV2iV2i", "") + +// SSE intrinsics. +BUILTIN(__builtin_ia32_comieq, "iV4fV4f", "") +BUILTIN(__builtin_ia32_comilt, "iV4fV4f", "") +BUILTIN(__builtin_ia32_comile, "iV4fV4f", "") +BUILTIN(__builtin_ia32_comigt, "iV4fV4f", "") +BUILTIN(__builtin_ia32_comige, "iV4fV4f", "") +BUILTIN(__builtin_ia32_comineq, "iV4fV4f", "") +BUILTIN(__builtin_ia32_ucomieq, "iV4fV4f", "") +BUILTIN(__builtin_ia32_ucomilt, "iV4fV4f", "") +BUILTIN(__builtin_ia32_ucomile, "iV4fV4f", "") +BUILTIN(__builtin_ia32_ucomigt, "iV4fV4f", "") +BUILTIN(__builtin_ia32_ucomige, "iV4fV4f", "") +BUILTIN(__builtin_ia32_ucomineq, "iV4fV4f", "") +BUILTIN(__builtin_ia32_comisdeq, "iV2dV2d", "") +BUILTIN(__builtin_ia32_comisdlt, "iV2dV2d", "") +BUILTIN(__builtin_ia32_comisdle, "iV2dV2d", "") +BUILTIN(__builtin_ia32_comisdgt, "iV2dV2d", "") +BUILTIN(__builtin_ia32_comisdge, "iV2dV2d", "") +BUILTIN(__builtin_ia32_comisdneq, "iV2dV2d", "") +BUILTIN(__builtin_ia32_ucomisdeq, "iV2dV2d", "") +BUILTIN(__builtin_ia32_ucomisdlt, "iV2dV2d", "") +BUILTIN(__builtin_ia32_ucomisdle, "iV2dV2d", "") +BUILTIN(__builtin_ia32_ucomisdgt, "iV2dV2d", "") +BUILTIN(__builtin_ia32_ucomisdge, "iV2dV2d", "") +BUILTIN(__builtin_ia32_ucomisdneq, "iV2dV2d", "") +BUILTIN(__builtin_ia32_cmpps, "V4fV4fV4fIc", "") +BUILTIN(__builtin_ia32_cmpss, "V4fV4fV4fIc", "") +BUILTIN(__builtin_ia32_minps, "V4fV4fV4f", "") +BUILTIN(__builtin_ia32_maxps, "V4fV4fV4f", "") +BUILTIN(__builtin_ia32_minss, "V4fV4fV4f", "") +BUILTIN(__builtin_ia32_maxss, "V4fV4fV4f", "") +BUILTIN(__builtin_ia32_cmppd, "V2dV2dV2dIc", "") +BUILTIN(__builtin_ia32_cmpsd, "V2dV2dV2dIc", "") +BUILTIN(__builtin_ia32_minpd, "V2dV2dV2d", "") +BUILTIN(__builtin_ia32_maxpd, "V2dV2dV2d", "") +BUILTIN(__builtin_ia32_minsd, "V2dV2dV2d", "") +BUILTIN(__builtin_ia32_maxsd, "V2dV2dV2d", "") +BUILTIN(__builtin_ia32_paddsb128, "V16cV16cV16c", "") +BUILTIN(__builtin_ia32_paddsw128, "V8sV8sV8s", "") +BUILTIN(__builtin_ia32_psubsb128, "V16cV16cV16c", "") +BUILTIN(__builtin_ia32_psubsw128, "V8sV8sV8s", "") +BUILTIN(__builtin_ia32_paddusb128, "V16cV16cV16c", "") +BUILTIN(__builtin_ia32_paddusw128, "V8sV8sV8s", "") +BUILTIN(__builtin_ia32_psubusb128, "V16cV16cV16c", "") +BUILTIN(__builtin_ia32_psubusw128, "V8sV8sV8s", "") +BUILTIN(__builtin_ia32_pmulhw128, "V8sV8sV8s", "") +BUILTIN(__builtin_ia32_pavgb128, "V16cV16cV16c", "") +BUILTIN(__builtin_ia32_pavgw128, "V8sV8sV8s", "") +BUILTIN(__builtin_ia32_pmaxub128, "V16cV16cV16c", "") +BUILTIN(__builtin_ia32_pmaxsw128, "V8sV8sV8s", "") +BUILTIN(__builtin_ia32_pminub128, "V16cV16cV16c", "") +BUILTIN(__builtin_ia32_pminsw128, "V8sV8sV8s", "") +BUILTIN(__builtin_ia32_packsswb128, "V16cV8sV8s", "") +BUILTIN(__builtin_ia32_packssdw128, "V8sV4iV4i", "") +BUILTIN(__builtin_ia32_packuswb128, "V16cV8sV8s", "") +BUILTIN(__builtin_ia32_pmulhuw128, "V8sV8sV8s", "") +BUILTIN(__builtin_ia32_addsubps, "V4fV4fV4f", "") +BUILTIN(__builtin_ia32_addsubpd, "V2dV2dV2d", "") +BUILTIN(__builtin_ia32_haddps, "V4fV4fV4f", "") +BUILTIN(__builtin_ia32_haddpd, "V2dV2dV2d", "") +BUILTIN(__builtin_ia32_hsubps, "V4fV4fV4f", "") +BUILTIN(__builtin_ia32_hsubpd, "V2dV2dV2d", "") +BUILTIN(__builtin_ia32_phaddw128, "V8sV8sV8s", "") +BUILTIN(__builtin_ia32_phaddd128, "V4iV4iV4i", "") +BUILTIN(__builtin_ia32_phaddsw128, "V8sV8sV8s", "") +BUILTIN(__builtin_ia32_phsubw128, "V8sV8sV8s", "") +BUILTIN(__builtin_ia32_phsubd128, "V4iV4iV4i", "") +BUILTIN(__builtin_ia32_phsubsw128, "V8sV8sV8s", "") +BUILTIN(__builtin_ia32_pmaddubsw128, "V8sV16cV16c", "") +BUILTIN(__builtin_ia32_pmulhrsw128, "V8sV8sV8s", "") +BUILTIN(__builtin_ia32_pshufb128, "V16cV16cV16c", "") +BUILTIN(__builtin_ia32_psignb128, "V16cV16cV16c", "") +BUILTIN(__builtin_ia32_psignw128, "V8sV8sV8s", "") +BUILTIN(__builtin_ia32_psignd128, "V4iV4iV4i", "") +BUILTIN(__builtin_ia32_pabsb128, "V16cV16c", "") +BUILTIN(__builtin_ia32_pabsw128, "V8sV8s", "") +BUILTIN(__builtin_ia32_pabsd128, "V4iV4i", "") +BUILTIN(__builtin_ia32_ldmxcsr, "vUi", "") +BUILTIN(__builtin_ia32_stmxcsr, "Ui", "") +BUILTIN(__builtin_ia32_cvtss2si, "iV4f", "") +BUILTIN(__builtin_ia32_cvtss2si64, "LLiV4f", "") +BUILTIN(__builtin_ia32_storeups, "vf*V4f", "") +BUILTIN(__builtin_ia32_storehps, "vV2i*V4f", "") +BUILTIN(__builtin_ia32_storelps, "vV2i*V4f", "") +BUILTIN(__builtin_ia32_movmskps, "iV4f", "") +BUILTIN(__builtin_ia32_movntps, "vf*V4f", "") +BUILTIN(__builtin_ia32_sfence, "v", "") +BUILTIN(__builtin_ia32_rcpps, "V4fV4f", "") +BUILTIN(__builtin_ia32_rcpss, "V4fV4f", "") +BUILTIN(__builtin_ia32_rsqrtps, "V4fV4f", "") +BUILTIN(__builtin_ia32_rsqrtss, "V4fV4f", "") +BUILTIN(__builtin_ia32_sqrtps, "V4fV4f", "") +BUILTIN(__builtin_ia32_sqrtss, "V4fV4f", "") +BUILTIN(__builtin_ia32_maskmovdqu, "vV16cV16cc*", "") +BUILTIN(__builtin_ia32_storeupd, "vd*V2d", "") +BUILTIN(__builtin_ia32_movmskpd, "iV2d", "") +BUILTIN(__builtin_ia32_pmovmskb128, "iV16c", "") +BUILTIN(__builtin_ia32_movnti, "vi*i", "") +BUILTIN(__builtin_ia32_movntpd, "vd*V2d", "") +BUILTIN(__builtin_ia32_movntdq, "vV2LLi*V2LLi", "") +BUILTIN(__builtin_ia32_psadbw128, "V2LLiV16cV16c", "") +BUILTIN(__builtin_ia32_sqrtpd, "V2dV2d", "") +BUILTIN(__builtin_ia32_sqrtsd, "V2dV2d", "") +BUILTIN(__builtin_ia32_cvtdq2pd, "V2dV4i", "") +BUILTIN(__builtin_ia32_cvtdq2ps, "V4fV4i", "") +BUILTIN(__builtin_ia32_cvtpd2dq, "V2LLiV2d", "") +BUILTIN(__builtin_ia32_cvtpd2ps, "V4fV2d", "") +BUILTIN(__builtin_ia32_cvttpd2dq, "V4iV2d", "") +BUILTIN(__builtin_ia32_cvtsd2si, "iV2d", "") +BUILTIN(__builtin_ia32_cvtsd2si64, "LLiV2d", "") +BUILTIN(__builtin_ia32_cvtps2dq, "V4iV4f", "") +BUILTIN(__builtin_ia32_cvtps2pd, "V2dV4f", "") +BUILTIN(__builtin_ia32_cvttps2dq, "V4iV4f", "") +BUILTIN(__builtin_ia32_clflush, "vvC*", "") +BUILTIN(__builtin_ia32_lfence, "v", "") +BUILTIN(__builtin_ia32_mfence, "v", "") +BUILTIN(__builtin_ia32_storedqu, "vc*V16c", "") +BUILTIN(__builtin_ia32_pmuludq128, "V2LLiV4iV4i", "") +BUILTIN(__builtin_ia32_psraw128, "V8sV8sV8s", "") +BUILTIN(__builtin_ia32_psrad128, "V4iV4iV4i", "") +BUILTIN(__builtin_ia32_psrlw128, "V8sV8sV8s", "") +BUILTIN(__builtin_ia32_psrld128, "V4iV4iV4i", "") +BUILTIN(__builtin_ia32_pslldqi128, "V2LLiV2LLiIi", "") +BUILTIN(__builtin_ia32_psrldqi128, "V2LLiV2LLiIi", "") +BUILTIN(__builtin_ia32_psrlq128, "V2LLiV2LLiV2LLi", "") +BUILTIN(__builtin_ia32_psllw128, "V8sV8sV8s", "") +BUILTIN(__builtin_ia32_pslld128, "V4iV4iV4i", "") +BUILTIN(__builtin_ia32_psllq128, "V2LLiV2LLiV2LLi", "") +BUILTIN(__builtin_ia32_psllwi128, "V8sV8si", "") +BUILTIN(__builtin_ia32_pslldi128, "V4iV4ii", "") +BUILTIN(__builtin_ia32_psllqi128, "V2LLiV2LLii", "") +BUILTIN(__builtin_ia32_psrlwi128, "V8sV8si", "") +BUILTIN(__builtin_ia32_psrldi128, "V4iV4ii", "") +BUILTIN(__builtin_ia32_psrlqi128, "V2LLiV2LLii", "") +BUILTIN(__builtin_ia32_psrawi128, "V8sV8si", "") +BUILTIN(__builtin_ia32_psradi128, "V4iV4ii", "") +BUILTIN(__builtin_ia32_pmaddwd128, "V4iV8sV8s", "") +BUILTIN(__builtin_ia32_monitor, "vv*UiUi", "") +BUILTIN(__builtin_ia32_mwait, "vUiUi", "") +BUILTIN(__builtin_ia32_lddqu, "V16ccC*", "") +BUILTIN(__builtin_ia32_palignr128, "V16cV16cV16cIc", "") +BUILTIN(__builtin_ia32_insertps128, "V4fV4fV4fi", "") + +BUILTIN(__builtin_ia32_storelv4si, "vV2i*V2LLi", "") + +BUILTIN(__builtin_ia32_pblendvb128, "V16cV16cV16cV16c", "") +BUILTIN(__builtin_ia32_pblendw128, "V8sV8sV8sIi", "") +BUILTIN(__builtin_ia32_blendpd, "V2dV2dV2dIi", "") +BUILTIN(__builtin_ia32_blendps, "V4fV4fV4fIi", "") +BUILTIN(__builtin_ia32_blendvpd, "V2dV2dV2dV2d", "") +BUILTIN(__builtin_ia32_blendvps, "V4fV4fV4fV4f", "") + +BUILTIN(__builtin_ia32_packusdw128, "V8sV4iV4i", "") +BUILTIN(__builtin_ia32_pmaxsb128, "V16cV16cV16c", "") +BUILTIN(__builtin_ia32_pmaxsd128, "V4iV4iV4i", "") +BUILTIN(__builtin_ia32_pmaxud128, "V4iV4iV4i", "") +BUILTIN(__builtin_ia32_pmaxuw128, "V8sV8sV8s", "") +BUILTIN(__builtin_ia32_pminsb128, "V16cV16cV16c", "") +BUILTIN(__builtin_ia32_pminsd128, "V4iV4iV4i", "") +BUILTIN(__builtin_ia32_pminud128, "V4iV4iV4i", "") +BUILTIN(__builtin_ia32_pminuw128, "V8sV8sV8s", "") +BUILTIN(__builtin_ia32_pmovsxbd128, "V4iV16c", "") +BUILTIN(__builtin_ia32_pmovsxbq128, "V2LLiV16c", "") +BUILTIN(__builtin_ia32_pmovsxbw128, "V8sV16c", "") +BUILTIN(__builtin_ia32_pmovsxdq128, "V2LLiV4i", "") +BUILTIN(__builtin_ia32_pmovsxwd128, "V4iV8s", "") +BUILTIN(__builtin_ia32_pmovsxwq128, "V2LLiV8s", "") +BUILTIN(__builtin_ia32_pmovzxbd128, "V4iV16c", "") +BUILTIN(__builtin_ia32_pmovzxbq128, "V2LLiV16c", "") +BUILTIN(__builtin_ia32_pmovzxbw128, "V8sV16c", "") +BUILTIN(__builtin_ia32_pmovzxdq128, "V2LLiV4i", "") +BUILTIN(__builtin_ia32_pmovzxwd128, "V4iV8s", "") +BUILTIN(__builtin_ia32_pmovzxwq128, "V2LLiV8s", "") +BUILTIN(__builtin_ia32_pmuldq128, "V2LLiV4iV4i", "") +BUILTIN(__builtin_ia32_pmulld128, "V4iV4iV4i", "") +BUILTIN(__builtin_ia32_roundps, "V4fV4fi", "") +BUILTIN(__builtin_ia32_roundss, "V4fV4fV4fi", "") +BUILTIN(__builtin_ia32_roundsd, "V2dV2dV2di", "") +BUILTIN(__builtin_ia32_roundpd, "V2dV2di", "") +BUILTIN(__builtin_ia32_dpps, "V4fV4fV4fi", "") +BUILTIN(__builtin_ia32_dppd, "V2dV2dV2di", "") +BUILTIN(__builtin_ia32_movntdqa, "V2LLiV2LLi*", "") +BUILTIN(__builtin_ia32_ptestz128, "iV2LLiV2LLi", "") +BUILTIN(__builtin_ia32_ptestc128, "iV2LLiV2LLi", "") +BUILTIN(__builtin_ia32_ptestnzc128, "iV2LLiV2LLi", "") +BUILTIN(__builtin_ia32_mpsadbw128, "V16cV16cV16ci", "") +BUILTIN(__builtin_ia32_phminposuw128, "V8sV8s", "") + +// SSE 4.2 +BUILTIN(__builtin_ia32_pcmpistrm128, "V16cV16cV16cIc", "") +BUILTIN(__builtin_ia32_pcmpistri128, "iV16cV16cIc", "") +BUILTIN(__builtin_ia32_pcmpestrm128, "V16cV16ciV16ciIc", "") +BUILTIN(__builtin_ia32_pcmpestri128, "iV16ciV16ciIc","") + +// FIXME: These builtins are horribly broken; reenable when PR11305 is fixed. +//BUILTIN(__builtin_ia32_pcmpistria128, "iV16cV16cIc","") +//BUILTIN(__builtin_ia32_pcmpistric128, "iV16cV16cIc","") +//BUILTIN(__builtin_ia32_pcmpistrio128, "iV16cV16cIc","") +//BUILTIN(__builtin_ia32_pcmpistris128, "iV16cV16cIc","") +//BUILTIN(__builtin_ia32_pcmpistriz128, "iV16cV16cIc","") +//BUILTIN(__builtin_ia32_pcmpestria128, "iV16ciV16ciIc","") +//BUILTIN(__builtin_ia32_pcmpestric128, "iV16ciV16ciIc","") +//BUILTIN(__builtin_ia32_pcmpestrio128, "iV16ciV16ciic","") +//BUILTIN(__builtin_ia32_pcmpestris128, "iV16ciV16ciIc","") +//BUILTIN(__builtin_ia32_pcmpestriz128, "iV16ciV16ciIc","") + +BUILTIN(__builtin_ia32_crc32qi, "UiUiUc", "") +BUILTIN(__builtin_ia32_crc32hi, "UiUiUs", "") +BUILTIN(__builtin_ia32_crc32si, "UiUiUi", "") +BUILTIN(__builtin_ia32_crc32di, "ULLiULLiULLi", "") + +// AES +BUILTIN(__builtin_ia32_aesenc128, "V2LLiV2LLiV2LLi", "") +BUILTIN(__builtin_ia32_aesenclast128, "V2LLiV2LLiV2LLi", "") +BUILTIN(__builtin_ia32_aesdec128, "V2LLiV2LLiV2LLi", "") +BUILTIN(__builtin_ia32_aesdeclast128, "V2LLiV2LLiV2LLi", "") +BUILTIN(__builtin_ia32_aesimc128, "V2LLiV2LLi", "") +BUILTIN(__builtin_ia32_aeskeygenassist128, "V2LLiV2LLiIc", "") + +// AVX +BUILTIN(__builtin_ia32_addsubpd256, "V4dV4dV4d", "") +BUILTIN(__builtin_ia32_addsubps256, "V8fV8fV8f", "") +BUILTIN(__builtin_ia32_haddpd256, "V4dV4dV4d", "") +BUILTIN(__builtin_ia32_hsubps256, "V8fV8fV8f", "") +BUILTIN(__builtin_ia32_hsubpd256, "V4dV4dV4d", "") +BUILTIN(__builtin_ia32_haddps256, "V8fV8fV8f", "") +BUILTIN(__builtin_ia32_maxpd256, "V4dV4dV4d", "") +BUILTIN(__builtin_ia32_maxps256, "V8fV8fV8f", "") +BUILTIN(__builtin_ia32_minpd256, "V4dV4dV4d", "") +BUILTIN(__builtin_ia32_minps256, "V8fV8fV8f", "") +BUILTIN(__builtin_ia32_vpermilvarpd, "V2dV2dV2LLi", "") +BUILTIN(__builtin_ia32_vpermilvarps, "V4fV4fV4i", "") +BUILTIN(__builtin_ia32_vpermilvarpd256, "V4dV4dV4LLi", "") +BUILTIN(__builtin_ia32_vpermilvarps256, "V8fV8fV8i", "") +BUILTIN(__builtin_ia32_blendpd256, "V4dV4dV4dIi", "") +BUILTIN(__builtin_ia32_blendps256, "V8fV8fV8fIi", "") +BUILTIN(__builtin_ia32_blendvpd256, "V4dV4dV4dV4d", "") +BUILTIN(__builtin_ia32_blendvps256, "V8fV8fV8fV8f", "") +BUILTIN(__builtin_ia32_dpps256, "V8fV8fV8fIi", "") +BUILTIN(__builtin_ia32_cmppd256, "V4dV4dV4dc", "") +BUILTIN(__builtin_ia32_cmpps256, "V8fV8fV8fc", "") +BUILTIN(__builtin_ia32_vextractf128_pd256, "V2dV4dIc", "") +BUILTIN(__builtin_ia32_vextractf128_ps256, "V4fV8fIc", "") +BUILTIN(__builtin_ia32_vextractf128_si256, "V4iV8iIc", "") +BUILTIN(__builtin_ia32_cvtdq2pd256, "V4dV4i", "") +BUILTIN(__builtin_ia32_cvtdq2ps256, "V8fV8i", "") +BUILTIN(__builtin_ia32_cvtpd2ps256, "V4fV4d", "") +BUILTIN(__builtin_ia32_cvtps2dq256, "V8iV8f", "") +BUILTIN(__builtin_ia32_cvtps2pd256, "V4dV4f", "") +BUILTIN(__builtin_ia32_cvttpd2dq256, "V4iV4d", "") +BUILTIN(__builtin_ia32_cvtpd2dq256, "V4iV4d", "") +BUILTIN(__builtin_ia32_cvttps2dq256, "V8iV8f", "") +BUILTIN(__builtin_ia32_vperm2f128_pd256, "V4dV4dV4dIc", "") +BUILTIN(__builtin_ia32_vperm2f128_ps256, "V8fV8fV8fIc", "") +BUILTIN(__builtin_ia32_vperm2f128_si256, "V8iV8iV8iIc", "") +BUILTIN(__builtin_ia32_vinsertf128_pd256, "V4dV4dV2dIc", "") +BUILTIN(__builtin_ia32_vinsertf128_ps256, "V8fV8fV4fIc", "") +BUILTIN(__builtin_ia32_vinsertf128_si256, "V8iV8iV4iIc", "") +BUILTIN(__builtin_ia32_sqrtpd256, "V4dV4d", "") +BUILTIN(__builtin_ia32_sqrtps256, "V8fV8f", "") +BUILTIN(__builtin_ia32_rsqrtps256, "V8fV8f", "") +BUILTIN(__builtin_ia32_rcpps256, "V8fV8f", "") +BUILTIN(__builtin_ia32_roundpd256, "V4dV4dIi", "") +BUILTIN(__builtin_ia32_roundps256, "V8fV8fIi", "") +BUILTIN(__builtin_ia32_vtestzpd, "iV2dV2d", "") +BUILTIN(__builtin_ia32_vtestcpd, "iV2dV2d", "") +BUILTIN(__builtin_ia32_vtestnzcpd, "iV2dV2d", "") +BUILTIN(__builtin_ia32_vtestzps, "iV4fV4f", "") +BUILTIN(__builtin_ia32_vtestcps, "iV4fV4f", "") +BUILTIN(__builtin_ia32_vtestnzcps, "iV4fV4f", "") +BUILTIN(__builtin_ia32_vtestzpd256, "iV4dV4d", "") +BUILTIN(__builtin_ia32_vtestcpd256, "iV4dV4d", "") +BUILTIN(__builtin_ia32_vtestnzcpd256, "iV4dV4d", "") +BUILTIN(__builtin_ia32_vtestzps256, "iV8fV8f", "") +BUILTIN(__builtin_ia32_vtestcps256, "iV8fV8f", "") +BUILTIN(__builtin_ia32_vtestnzcps256, "iV8fV8f", "") +BUILTIN(__builtin_ia32_ptestz256, "iV4LLiV4LLi", "") +BUILTIN(__builtin_ia32_ptestc256, "iV4LLiV4LLi", "") +BUILTIN(__builtin_ia32_ptestnzc256, "iV4LLiV4LLi", "") +BUILTIN(__builtin_ia32_movmskpd256, "iV4d", "") +BUILTIN(__builtin_ia32_movmskps256, "iV8f", "") +BUILTIN(__builtin_ia32_vzeroall, "v", "") +BUILTIN(__builtin_ia32_vzeroupper, "v", "") +BUILTIN(__builtin_ia32_vbroadcastss, "V4ffC*", "") +BUILTIN(__builtin_ia32_vbroadcastsd256, "V4ddC*", "") +BUILTIN(__builtin_ia32_vbroadcastss256, "V8ffC*", "") +BUILTIN(__builtin_ia32_vbroadcastf128_pd256, "V4dV2dC*", "") +BUILTIN(__builtin_ia32_vbroadcastf128_ps256, "V8fV4fC*", "") +BUILTIN(__builtin_ia32_storeupd256, "vd*V4d", "") +BUILTIN(__builtin_ia32_storeups256, "vf*V8f", "") +BUILTIN(__builtin_ia32_storedqu256, "vc*V32c", "") +BUILTIN(__builtin_ia32_lddqu256, "V32ccC*", "") +BUILTIN(__builtin_ia32_movntdq256, "vV4LLi*V4LLi", "") +BUILTIN(__builtin_ia32_movntpd256, "vd*V4d", "") +BUILTIN(__builtin_ia32_movntps256, "vf*V8f", "") +BUILTIN(__builtin_ia32_maskloadpd, "V2dV2dC*V2d", "") +BUILTIN(__builtin_ia32_maskloadps, "V4fV4fC*V4f", "") +BUILTIN(__builtin_ia32_maskloadpd256, "V4dV4dC*V4d", "") +BUILTIN(__builtin_ia32_maskloadps256, "V8fV8fC*V8f", "") +BUILTIN(__builtin_ia32_maskstorepd, "vV2d*V2dV2d", "") +BUILTIN(__builtin_ia32_maskstoreps, "vV4f*V4fV4f", "") +BUILTIN(__builtin_ia32_maskstorepd256, "vV4d*V4dV4d", "") +BUILTIN(__builtin_ia32_maskstoreps256, "vV8f*V8fV8f", "") + +// AVX2 +BUILTIN(__builtin_ia32_mpsadbw256, "V32cV32cV32ci", "") +BUILTIN(__builtin_ia32_pabsb256, "V32cV32c", "") +BUILTIN(__builtin_ia32_pabsw256, "V16sV16s", "") +BUILTIN(__builtin_ia32_pabsd256, "V8iV8i", "") +BUILTIN(__builtin_ia32_packsswb256, "V32cV16sV16s", "") +BUILTIN(__builtin_ia32_packssdw256, "V16sV8iV8i", "") +BUILTIN(__builtin_ia32_packuswb256, "V32cV16sV16s", "") +BUILTIN(__builtin_ia32_packusdw256, "V16sV8iV8i", "") +BUILTIN(__builtin_ia32_paddsb256, "V32cV32cV32c", "") +BUILTIN(__builtin_ia32_paddsw256, "V16sV16sV16s", "") +BUILTIN(__builtin_ia32_psubsb256, "V32cV32cV32c", "") +BUILTIN(__builtin_ia32_psubsw256, "V16sV16sV16s", "") +BUILTIN(__builtin_ia32_paddusb256, "V32cV32cV32c", "") +BUILTIN(__builtin_ia32_paddusw256, "V16sV16sV16s", "") +BUILTIN(__builtin_ia32_psubusb256, "V32cV32cV32c", "") +BUILTIN(__builtin_ia32_psubusw256, "V16sV16sV16s", "") +BUILTIN(__builtin_ia32_palignr256, "V32cV32cV32cIc", "") +BUILTIN(__builtin_ia32_pavgb256, "V32cV32cV32c", "") +BUILTIN(__builtin_ia32_pavgw256, "V16sV16sV16s", "") +BUILTIN(__builtin_ia32_pblendvb256, "V32cV32cV32cV32c", "") +BUILTIN(__builtin_ia32_pblendw256, "V16sV16sV16sIi", "") +BUILTIN(__builtin_ia32_phaddw256, "V16sV16sV16s", "") +BUILTIN(__builtin_ia32_phaddd256, "V8iV8iV8i", "") +BUILTIN(__builtin_ia32_phaddsw256, "V16sV16sV16s", "") +BUILTIN(__builtin_ia32_phsubw256, "V16sV16sV16s", "") +BUILTIN(__builtin_ia32_phsubd256, "V8iV8iV8i", "") +BUILTIN(__builtin_ia32_phsubsw256, "V16sV16sV16s", "") +BUILTIN(__builtin_ia32_pmaddubsw256, "V16sV32cV32c", "") +BUILTIN(__builtin_ia32_pmaddwd256, "V8iV16sV16s", "") +BUILTIN(__builtin_ia32_pmaxub256, "V32cV32cV32c", "") +BUILTIN(__builtin_ia32_pmaxuw256, "V16sV16sV16s", "") +BUILTIN(__builtin_ia32_pmaxud256, "V8iV8iV8i", "") +BUILTIN(__builtin_ia32_pmaxsb256, "V32cV32cV32c", "") +BUILTIN(__builtin_ia32_pmaxsw256, "V16sV16sV16s", "") +BUILTIN(__builtin_ia32_pmaxsd256, "V8iV8iV8i", "") +BUILTIN(__builtin_ia32_pminub256, "V32cV32cV32c", "") +BUILTIN(__builtin_ia32_pminuw256, "V16sV16sV16s", "") +BUILTIN(__builtin_ia32_pminud256, "V8iV8iV8i", "") +BUILTIN(__builtin_ia32_pminsb256, "V32cV32cV32c", "") +BUILTIN(__builtin_ia32_pminsw256, "V16sV16sV16s", "") +BUILTIN(__builtin_ia32_pminsd256, "V8iV8iV8i", "") +BUILTIN(__builtin_ia32_pmovmskb256, "iV32c", "") +BUILTIN(__builtin_ia32_pmovsxbw256, "V16sV16c", "") +BUILTIN(__builtin_ia32_pmovsxbd256, "V8iV16c", "") +BUILTIN(__builtin_ia32_pmovsxbq256, "V4LLiV16c", "") +BUILTIN(__builtin_ia32_pmovsxwd256, "V8iV8s", "") +BUILTIN(__builtin_ia32_pmovsxwq256, "V4LLiV8s", "") +BUILTIN(__builtin_ia32_pmovsxdq256, "V4LLiV4i", "") +BUILTIN(__builtin_ia32_pmovzxbw256, "V16sV16c", "") +BUILTIN(__builtin_ia32_pmovzxbd256, "V8iV16c", "") +BUILTIN(__builtin_ia32_pmovzxbq256, "V4LLiV16c", "") +BUILTIN(__builtin_ia32_pmovzxwd256, "V8iV8s", "") +BUILTIN(__builtin_ia32_pmovzxwq256, "V4LLiV8s", "") +BUILTIN(__builtin_ia32_pmovzxdq256, "V4LLiV4i", "") +BUILTIN(__builtin_ia32_pmuldq256, "V4LLiV8iV8i", "") +BUILTIN(__builtin_ia32_pmulhrsw256, "V16sV16sV16s", "") +BUILTIN(__builtin_ia32_pmulhuw256, "V16sV16sV16s", "") +BUILTIN(__builtin_ia32_pmulhw256, "V16sV16sV16s", "") +BUILTIN(__builtin_ia32_pmuludq256, "V4LLiV8iV8i", "") +BUILTIN(__builtin_ia32_psadbw256, "V4LLiV32cV32c", "") +BUILTIN(__builtin_ia32_pshufb256, "V32cV32cV32c", "") +BUILTIN(__builtin_ia32_psignb256, "V32cV32cV32c", "") +BUILTIN(__builtin_ia32_psignw256, "V16sV16sV16s", "") +BUILTIN(__builtin_ia32_psignd256, "V8iV8iV8i", "") +BUILTIN(__builtin_ia32_pslldqi256, "V4LLiV4LLiIi", "") +BUILTIN(__builtin_ia32_psllwi256, "V16sV16si", "") +BUILTIN(__builtin_ia32_psllw256, "V16sV16sV8s", "") +BUILTIN(__builtin_ia32_pslldi256, "V8iV8ii", "") +BUILTIN(__builtin_ia32_pslld256, "V8iV8iV4i", "") +BUILTIN(__builtin_ia32_psllqi256, "V4LLiV4LLii", "") +BUILTIN(__builtin_ia32_psllq256, "V4LLiV4LLiV2LLi", "") +BUILTIN(__builtin_ia32_psrawi256, "V16sV16si", "") +BUILTIN(__builtin_ia32_psraw256, "V16sV16sV8s", "") +BUILTIN(__builtin_ia32_psradi256, "V8iV8ii", "") +BUILTIN(__builtin_ia32_psrad256, "V8iV8iV4i", "") +BUILTIN(__builtin_ia32_psrldqi256, "V4LLiV4LLiIi", "") +BUILTIN(__builtin_ia32_psrlwi256, "V16sV16si", "") +BUILTIN(__builtin_ia32_psrlw256, "V16sV16sV8s", "") +BUILTIN(__builtin_ia32_psrldi256, "V8iV8ii", "") +BUILTIN(__builtin_ia32_psrld256, "V8iV8iV4i", "") +BUILTIN(__builtin_ia32_psrlqi256, "V4LLiV4LLii", "") +BUILTIN(__builtin_ia32_psrlq256, "V4LLiV4LLiV2LLi", "") +BUILTIN(__builtin_ia32_movntdqa256, "V4LLiV4LLi*", "") +BUILTIN(__builtin_ia32_vbroadcastss_ps, "V4fV4f", "") +BUILTIN(__builtin_ia32_vbroadcastss_ps256, "V8fV4f", "") +BUILTIN(__builtin_ia32_vbroadcastsd_pd256, "V4dV2d", "") +BUILTIN(__builtin_ia32_vbroadcastsi256, "V4LLiV2LLiC*", "") +BUILTIN(__builtin_ia32_pblendd128, "V4iV4iV4iIi", "") +BUILTIN(__builtin_ia32_pblendd256, "V8iV8iV8iIi", "") +BUILTIN(__builtin_ia32_pbroadcastb256, "V32cV16c", "") +BUILTIN(__builtin_ia32_pbroadcastw256, "V16sV8s", "") +BUILTIN(__builtin_ia32_pbroadcastd256, "V8iV4i", "") +BUILTIN(__builtin_ia32_pbroadcastq256, "V4LLiV2LLi", "") +BUILTIN(__builtin_ia32_pbroadcastb128, "V16cV16c", "") +BUILTIN(__builtin_ia32_pbroadcastw128, "V8sV8s", "") +BUILTIN(__builtin_ia32_pbroadcastd128, "V4iV4i", "") +BUILTIN(__builtin_ia32_pbroadcastq128, "V2LLiV2LLi", "") +BUILTIN(__builtin_ia32_permvarsi256, "V8iV8iV8i", "") +BUILTIN(__builtin_ia32_permvarsf256, "V8fV8fV8f", "") +BUILTIN(__builtin_ia32_permti256, "V4LLiV4LLiV4LLiIc", "") +BUILTIN(__builtin_ia32_extract128i256, "V2LLiV4LLiIc", "") +BUILTIN(__builtin_ia32_insert128i256, "V4LLiV4LLiV2LLiIc", "") +BUILTIN(__builtin_ia32_maskloadd256, "V8iV8iC*V8i", "") +BUILTIN(__builtin_ia32_maskloadq256, "V4LLiV4LLiC*V4LLi", "") +BUILTIN(__builtin_ia32_maskloadd, "V4iV4iC*V4i", "") +BUILTIN(__builtin_ia32_maskloadq, "V2LLiV2LLiC*V2LLi", "") +BUILTIN(__builtin_ia32_maskstored256, "vV8i*V8iV8i", "") +BUILTIN(__builtin_ia32_maskstoreq256, "vV4LLi*V4LLiV4LLi", "") +BUILTIN(__builtin_ia32_maskstored, "vV4i*V4iV4i", "") +BUILTIN(__builtin_ia32_maskstoreq, "vV2LLi*V2LLiV2LLi", "") +BUILTIN(__builtin_ia32_psllv8si, "V8iV8iV8i", "") +BUILTIN(__builtin_ia32_psllv4si, "V4iV4iV4i", "") +BUILTIN(__builtin_ia32_psllv4di, "V4LLiV4LLiV4LLi", "") +BUILTIN(__builtin_ia32_psllv2di, "V2LLiV2LLiV2LLi", "") +BUILTIN(__builtin_ia32_psrav8si, "V8iV8iV8i", "") +BUILTIN(__builtin_ia32_psrav4si, "V4iV4iV4i", "") +BUILTIN(__builtin_ia32_psrlv8si, "V8iV8iV8i", "") +BUILTIN(__builtin_ia32_psrlv4si, "V4iV4iV4i", "") +BUILTIN(__builtin_ia32_psrlv4di, "V4LLiV4LLiV4LLi", "") +BUILTIN(__builtin_ia32_psrlv2di, "V2LLiV2LLiV2LLi", "") + +// BMI +BUILTIN(__builtin_ia32_bextr_u32, "UiUiUi", "") +BUILTIN(__builtin_ia32_bextr_u64, "ULLiULLiULLi", "") + +// BMI2 +BUILTIN(__builtin_ia32_bzhi_si, "UiUiUi", "") +BUILTIN(__builtin_ia32_bzhi_di, "ULLiULLiULLi", "") +BUILTIN(__builtin_ia32_pdep_si, "UiUiUi", "") +BUILTIN(__builtin_ia32_pdep_di, "ULLiULLiULLi", "") +BUILTIN(__builtin_ia32_pext_si, "UiUiUi", "") +BUILTIN(__builtin_ia32_pext_di, "ULLiULLiULLi", "") + +// FMA4 +BUILTIN(__builtin_ia32_vfmaddps, "V4fV4fV4fV4f", "") +BUILTIN(__builtin_ia32_vfmaddpd, "V2dV2dV2dV2d", "") +BUILTIN(__builtin_ia32_vfmaddss, "V4fV4fV4fV4f", "") +BUILTIN(__builtin_ia32_vfmaddsd, "V2dV2dV2dV2d", "") +BUILTIN(__builtin_ia32_vfmsubps, "V4fV4fV4fV4f", "") +BUILTIN(__builtin_ia32_vfmsubpd, "V2dV2dV2dV2d", "") +BUILTIN(__builtin_ia32_vfmsubss, "V4fV4fV4fV4f", "") +BUILTIN(__builtin_ia32_vfmsubsd, "V2dV2dV2dV2d", "") +BUILTIN(__builtin_ia32_vfnmaddps, "V4fV4fV4fV4f", "") +BUILTIN(__builtin_ia32_vfnmaddpd, "V2dV2dV2dV2d", "") +BUILTIN(__builtin_ia32_vfnmaddss, "V4fV4fV4fV4f", "") +BUILTIN(__builtin_ia32_vfnmaddsd, "V2dV2dV2dV2d", "") +BUILTIN(__builtin_ia32_vfnmsubps, "V4fV4fV4fV4f", "") +BUILTIN(__builtin_ia32_vfnmsubpd, "V2dV2dV2dV2d", "") +BUILTIN(__builtin_ia32_vfnmsubss, "V4fV4fV4fV4f", "") +BUILTIN(__builtin_ia32_vfnmsubsd, "V2dV2dV2dV2d", "") +BUILTIN(__builtin_ia32_vfmaddsubps, "V4fV4fV4fV4f", "") +BUILTIN(__builtin_ia32_vfmaddsubpd, "V2dV2dV2dV2d", "") +BUILTIN(__builtin_ia32_vfmsubaddps, "V4fV4fV4fV4f", "") +BUILTIN(__builtin_ia32_vfmsubaddpd, "V2dV2dV2dV2d", "") +BUILTIN(__builtin_ia32_vfmaddps256, "V8fV8fV8fV8f", "") +BUILTIN(__builtin_ia32_vfmaddpd256, "V4dV4dV4dV4d", "") +BUILTIN(__builtin_ia32_vfmsubps256, "V8fV8fV8fV8f", "") +BUILTIN(__builtin_ia32_vfmsubpd256, "V4dV4dV4dV4d", "") +BUILTIN(__builtin_ia32_vfnmaddps256, "V8fV8fV8fV8f", "") +BUILTIN(__builtin_ia32_vfnmaddpd256, "V4dV4dV4dV4d", "") +BUILTIN(__builtin_ia32_vfnmsubps256, "V8fV8fV8fV8f", "") +BUILTIN(__builtin_ia32_vfnmsubpd256, "V4dV4dV4dV4d", "") +BUILTIN(__builtin_ia32_vfmaddsubps256, "V8fV8fV8fV8f", "") +BUILTIN(__builtin_ia32_vfmaddsubpd256, "V4dV4dV4dV4d", "") +BUILTIN(__builtin_ia32_vfmsubaddps256, "V8fV8fV8fV8f", "") +BUILTIN(__builtin_ia32_vfmsubaddpd256, "V4dV4dV4dV4d", "") + +#undef BUILTIN diff --git a/clang/include/clang/Basic/CMakeLists.txt b/clang/include/clang/Basic/CMakeLists.txt new file mode 100644 index 0000000..3df88c7 --- /dev/null +++ b/clang/include/clang/Basic/CMakeLists.txt @@ -0,0 +1,33 @@ +macro(clang_diag_gen component) + clang_tablegen(Diagnostic${component}Kinds.inc + -gen-clang-diags-defs -clang-component=${component} + SOURCE Diagnostic.td + TARGET ClangDiagnostic${component}) +endmacro(clang_diag_gen) + +clang_diag_gen(Analysis) +clang_diag_gen(AST) +clang_diag_gen(Common) +clang_diag_gen(Driver) +clang_diag_gen(Frontend) +clang_diag_gen(Lex) +clang_diag_gen(Parse) +clang_diag_gen(Sema) +clang_diag_gen(Serialization) +clang_tablegen(DiagnosticGroups.inc -gen-clang-diag-groups + SOURCE Diagnostic.td + TARGET ClangDiagnosticGroups) + +clang_tablegen(DiagnosticIndexName.inc -gen-clang-diags-index-name + SOURCE Diagnostic.td + TARGET ClangDiagnosticIndexName) + +clang_tablegen(AttrList.inc -gen-clang-attr-list + -I ${CMAKE_CURRENT_SOURCE_DIR}/../../ + SOURCE Attr.td + TARGET ClangAttrList) + +# ARM NEON +clang_tablegen(arm_neon.inc -gen-arm-neon-sema + SOURCE arm_neon.td + TARGET ClangARMNeon) diff --git a/clang/include/clang/Basic/ConvertUTF.h b/clang/include/clang/Basic/ConvertUTF.h new file mode 100644 index 0000000..7fb5874 --- /dev/null +++ b/clang/include/clang/Basic/ConvertUTF.h @@ -0,0 +1,166 @@ +/*===--- ConvertUTF.h - Universal Character Names conversions ---------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + *==------------------------------------------------------------------------==*/ +/* + * Copyright 2001-2004 Unicode, Inc. + * + * Disclaimer + * + * This source code is provided as is by Unicode, Inc. No claims are + * made as to fitness for any particular purpose. No warranties of any + * kind are expressed or implied. The recipient agrees to determine + * applicability of information provided. If this file has been + * purchased on magnetic or optical media from Unicode, Inc., the + * sole remedy for any claim will be exchange of defective media + * within 90 days of receipt. + * + * Limitations on Rights to Redistribute This Code + * + * Unicode, Inc. hereby grants the right to freely use the information + * supplied in this file in the creation of products supporting the + * Unicode Standard, and to make copies of this file in any form + * for internal or external distribution as long as this notice + * remains attached. + */ + +/* --------------------------------------------------------------------- + + Conversions between UTF32, UTF-16, and UTF-8. Header file. + + Several funtions are included here, forming a complete set of + conversions between the three formats. UTF-7 is not included + here, but is handled in a separate source file. + + Each of these routines takes pointers to input buffers and output + buffers. The input buffers are const. + + Each routine converts the text between *sourceStart and sourceEnd, + putting the result into the buffer between *targetStart and + targetEnd. Note: the end pointers are *after* the last item: e.g. + *(sourceEnd - 1) is the last item. + + The return result indicates whether the conversion was successful, + and if not, whether the problem was in the source or target buffers. + (Only the first encountered problem is indicated.) + + After the conversion, *sourceStart and *targetStart are both + updated to point to the end of last text successfully converted in + the respective buffers. + + Input parameters: + sourceStart - pointer to a pointer to the source buffer. + The contents of this are modified on return so that + it points at the next thing to be converted. + targetStart - similarly, pointer to pointer to the target buffer. + sourceEnd, targetEnd - respectively pointers to the ends of the + two buffers, for overflow checking only. + + These conversion functions take a ConversionFlags argument. When this + flag is set to strict, both irregular sequences and isolated surrogates + will cause an error. When the flag is set to lenient, both irregular + sequences and isolated surrogates are converted. + + Whether the flag is strict or lenient, all illegal sequences will cause + an error return. This includes sequences such as: <F4 90 80 80>, <C0 80>, + or <A0> in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code + must check for illegal sequences. + + When the flag is set to lenient, characters over 0x10FFFF are converted + to the replacement character; otherwise (when the flag is set to strict) + they constitute an error. + + Output parameters: + The value "sourceIllegal" is returned from some routines if the input + sequence is malformed. When "sourceIllegal" is returned, the source + value will point to the illegal value that caused the problem. E.g., + in UTF-8 when a sequence is malformed, it points to the start of the + malformed sequence. + + Author: Mark E. Davis, 1994. + Rev History: Rick McGowan, fixes & updates May 2001. + Fixes & updates, Sept 2001. + +------------------------------------------------------------------------ */ + +#ifndef CLANG_BASIC_CONVERTUTF_H +#define CLANG_BASIC_CONVERTUTF_H + +/* --------------------------------------------------------------------- + The following 4 definitions are compiler-specific. + The C standard does not guarantee that wchar_t has at least + 16 bits, so wchar_t is no less portable than unsigned short! + All should be unsigned values to avoid sign extension during + bit mask & shift operations. +------------------------------------------------------------------------ */ + +typedef unsigned int UTF32; /* at least 32 bits */ +typedef unsigned short UTF16; /* at least 16 bits */ +typedef unsigned char UTF8; /* typically 8 bits */ +typedef unsigned char Boolean; /* 0 or 1 */ + +/* Some fundamental constants */ +#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD +#define UNI_MAX_BMP (UTF32)0x0000FFFF +#define UNI_MAX_UTF16 (UTF32)0x0010FFFF +#define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF +#define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF + +typedef enum { + conversionOK, /* conversion successful */ + sourceExhausted, /* partial character in source, but hit end */ + targetExhausted, /* insuff. room in target for conversion */ + sourceIllegal /* source sequence is illegal/malformed */ +} ConversionResult; + +typedef enum { + strictConversion = 0, + lenientConversion +} ConversionFlags; + +/* This is for C++ and does no harm in C */ +#ifdef __cplusplus +extern "C" { +#endif + +ConversionResult ConvertUTF8toUTF16 ( + const UTF8** sourceStart, const UTF8* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); + +ConversionResult ConvertUTF8toUTF32 ( + const UTF8** sourceStart, const UTF8* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags); + +#ifdef CLANG_NEEDS_THESE_ONE_DAY +ConversionResult ConvertUTF16toUTF8 ( + const UTF16** sourceStart, const UTF16* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags); + +ConversionResult ConvertUTF32toUTF8 ( + const UTF32** sourceStart, const UTF32* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags); + +ConversionResult ConvertUTF16toUTF32 ( + const UTF16** sourceStart, const UTF16* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags); + +ConversionResult ConvertUTF32toUTF16 ( + const UTF32** sourceStart, const UTF32* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); +#endif + +Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd); + +Boolean isLegalUTF8String(const UTF8 *source, const UTF8 *sourceEnd); + +#ifdef __cplusplus +} +#endif + +#endif + +/* --------------------------------------------------------------------- */ diff --git a/clang/include/clang/Basic/DeclNodes.td b/clang/include/clang/Basic/DeclNodes.td new file mode 100644 index 0000000..6f2bb35 --- /dev/null +++ b/clang/include/clang/Basic/DeclNodes.td @@ -0,0 +1,77 @@ +class AttrSubject; + +class Decl<bit abstract = 0> : AttrSubject { + bit Abstract = abstract; +} + +class DDecl<Decl base, bit abstract = 0> : Decl<abstract> { + Decl Base = base; +} + +class DeclContext { } + +def TranslationUnit : Decl, DeclContext; +def Named : Decl<1>; + def Namespace : DDecl<Named>, DeclContext; + def UsingDirective : DDecl<Named>; + def NamespaceAlias : DDecl<Named>; + def Label : DDecl<Named>; + def Type : DDecl<Named, 1>; + def TypedefName : DDecl<Type, 1>; + def Typedef : DDecl<TypedefName>; + def TypeAlias : DDecl<TypedefName>; + def UnresolvedUsingTypename : DDecl<Type>; + def Tag : DDecl<Type, 1>, DeclContext; + def Enum : DDecl<Tag>; + def Record : DDecl<Tag>; + def CXXRecord : DDecl<Record>; + def ClassTemplateSpecialization : DDecl<CXXRecord>; + def ClassTemplatePartialSpecialization + : DDecl<ClassTemplateSpecialization>; + def TemplateTypeParm : DDecl<Type>; + def Value : DDecl<Named, 1>; + def EnumConstant : DDecl<Value>; + def UnresolvedUsingValue : DDecl<Value>; + def IndirectField : DDecl<Value>; + def Declarator : DDecl<Value, 1>; + def Function : DDecl<Declarator>, DeclContext; + def CXXMethod : DDecl<Function>; + def CXXConstructor : DDecl<CXXMethod>; + def CXXDestructor : DDecl<CXXMethod>; + def CXXConversion : DDecl<CXXMethod>; + def Field : DDecl<Declarator>; + def ObjCIvar : DDecl<Field>; + def ObjCAtDefsField : DDecl<Field>; + def Var : DDecl<Declarator>; + def ImplicitParam : DDecl<Var>; + def ParmVar : DDecl<Var>; + def NonTypeTemplateParm : DDecl<Declarator>; + def Template : DDecl<Named, 1>; + def RedeclarableTemplate : DDecl<Template, 1>; + def FunctionTemplate : DDecl<RedeclarableTemplate>; + def ClassTemplate : DDecl<RedeclarableTemplate>; + def TypeAliasTemplate : DDecl<RedeclarableTemplate>; + def TemplateTemplateParm : DDecl<Template>; + def Using : DDecl<Named>; + def UsingShadow : DDecl<Named>; + def ObjCMethod : DDecl<Named>, DeclContext; + def ObjCContainer : DDecl<Named, 1>, DeclContext; + def ObjCCategory : DDecl<ObjCContainer>; + def ObjCProtocol : DDecl<ObjCContainer>; + def ObjCInterface : DDecl<ObjCContainer>; + def ObjCImpl : DDecl<ObjCContainer, 1>; + def ObjCCategoryImpl : DDecl<ObjCImpl>; + def ObjCImplementation : DDecl<ObjCImpl>; + def ObjCProperty : DDecl<Named>; + def ObjCCompatibleAlias : DDecl<Named>; +def LinkageSpec : Decl, DeclContext; +def ObjCPropertyImpl : Decl; +def FileScopeAsm : Decl; +def AccessSpec : Decl; +def Friend : Decl; +def FriendTemplate : Decl; +def StaticAssert : Decl; +def Block : Decl, DeclContext; +def ClassScopeFunctionSpecialization : Decl; +def Import : Decl; + diff --git a/clang/include/clang/Basic/Diagnostic.h b/clang/include/clang/Basic/Diagnostic.h new file mode 100644 index 0000000..e157178 --- /dev/null +++ b/clang/include/clang/Basic/Diagnostic.h @@ -0,0 +1,1207 @@ +//===--- Diagnostic.h - C Language Family Diagnostic Handling ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Diagnostic-related interfaces. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_DIAGNOSTIC_H +#define LLVM_CLANG_DIAGNOSTIC_H + +#include "clang/Basic/DiagnosticIDs.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/Support/type_traits.h" + +#include <vector> +#include <list> + +namespace clang { + class DiagnosticConsumer; + class DiagnosticBuilder; + class IdentifierInfo; + class DeclContext; + class LangOptions; + class Preprocessor; + class DiagnosticErrorTrap; + class StoredDiagnostic; + +/// \brief Annotates a diagnostic with some code that should be +/// inserted, removed, or replaced to fix the problem. +/// +/// This kind of hint should be used when we are certain that the +/// introduction, removal, or modification of a particular (small!) +/// amount of code will correct a compilation error. The compiler +/// should also provide full recovery from such errors, such that +/// suppressing the diagnostic output can still result in successful +/// compilation. +class FixItHint { +public: + /// \brief Code that should be replaced to correct the error. Empty for an + /// insertion hint. + CharSourceRange RemoveRange; + + /// \brief Code in the specific range that should be inserted in the insertion + /// location. + CharSourceRange InsertFromRange; + + /// \brief The actual code to insert at the insertion location, as a + /// string. + std::string CodeToInsert; + + bool BeforePreviousInsertions; + + /// \brief Empty code modification hint, indicating that no code + /// modification is known. + FixItHint() : BeforePreviousInsertions(false) { } + + bool isNull() const { + return !RemoveRange.isValid(); + } + + /// \brief Create a code modification hint that inserts the given + /// code string at a specific location. + static FixItHint CreateInsertion(SourceLocation InsertionLoc, + StringRef Code, + bool BeforePreviousInsertions = false) { + FixItHint Hint; + Hint.RemoveRange = + CharSourceRange(SourceRange(InsertionLoc, InsertionLoc), false); + Hint.CodeToInsert = Code; + Hint.BeforePreviousInsertions = BeforePreviousInsertions; + return Hint; + } + + /// \brief Create a code modification hint that inserts the given + /// code from \arg FromRange at a specific location. + static FixItHint CreateInsertionFromRange(SourceLocation InsertionLoc, + CharSourceRange FromRange, + bool BeforePreviousInsertions = false) { + FixItHint Hint; + Hint.RemoveRange = + CharSourceRange(SourceRange(InsertionLoc, InsertionLoc), false); + Hint.InsertFromRange = FromRange; + Hint.BeforePreviousInsertions = BeforePreviousInsertions; + return Hint; + } + + /// \brief Create a code modification hint that removes the given + /// source range. + static FixItHint CreateRemoval(CharSourceRange RemoveRange) { + FixItHint Hint; + Hint.RemoveRange = RemoveRange; + return Hint; + } + static FixItHint CreateRemoval(SourceRange RemoveRange) { + return CreateRemoval(CharSourceRange::getTokenRange(RemoveRange)); + } + + /// \brief Create a code modification hint that replaces the given + /// source range with the given code string. + static FixItHint CreateReplacement(CharSourceRange RemoveRange, + StringRef Code) { + FixItHint Hint; + Hint.RemoveRange = RemoveRange; + Hint.CodeToInsert = Code; + return Hint; + } + + static FixItHint CreateReplacement(SourceRange RemoveRange, + StringRef Code) { + return CreateReplacement(CharSourceRange::getTokenRange(RemoveRange), Code); + } +}; + +/// DiagnosticsEngine - This concrete class is used by the front-end to report +/// problems and issues. It massages the diagnostics (e.g. handling things like +/// "report warnings as errors" and passes them off to the DiagnosticConsumer +/// for reporting to the user. DiagnosticsEngine is tied to one translation unit +/// and one SourceManager. +class DiagnosticsEngine : public RefCountedBase<DiagnosticsEngine> { +public: + /// Level - The level of the diagnostic, after it has been through mapping. + enum Level { + Ignored = DiagnosticIDs::Ignored, + Note = DiagnosticIDs::Note, + Warning = DiagnosticIDs::Warning, + Error = DiagnosticIDs::Error, + Fatal = DiagnosticIDs::Fatal + }; + + /// ExtensionHandling - How do we handle otherwise-unmapped extension? This + /// is controlled by -pedantic and -pedantic-errors. + enum ExtensionHandling { + Ext_Ignore, Ext_Warn, Ext_Error + }; + + enum ArgumentKind { + ak_std_string, // std::string + ak_c_string, // const char * + ak_sint, // int + ak_uint, // unsigned + ak_identifierinfo, // IdentifierInfo + ak_qualtype, // QualType + ak_declarationname, // DeclarationName + ak_nameddecl, // NamedDecl * + ak_nestednamespec, // NestedNameSpecifier * + ak_declcontext // DeclContext * + }; + + /// Specifies which overload candidates to display when overload resolution + /// fails. + enum OverloadsShown { + Ovl_All, ///< Show all overloads. + Ovl_Best ///< Show just the "best" overload candidates. + }; + + /// ArgumentValue - This typedef represents on argument value, which is a + /// union discriminated by ArgumentKind, with a value. + typedef std::pair<ArgumentKind, intptr_t> ArgumentValue; + +private: + unsigned char AllExtensionsSilenced; // Used by __extension__ + bool IgnoreAllWarnings; // Ignore all warnings: -w + bool WarningsAsErrors; // Treat warnings like errors. + bool EnableAllWarnings; // Enable all warnings. + bool ErrorsAsFatal; // Treat errors like fatal errors. + bool SuppressSystemWarnings; // Suppress warnings in system headers. + bool SuppressAllDiagnostics; // Suppress all diagnostics. + OverloadsShown ShowOverloads; // Which overload candidates to show. + unsigned ErrorLimit; // Cap of # errors emitted, 0 -> no limit. + unsigned TemplateBacktraceLimit; // Cap on depth of template backtrace stack, + // 0 -> no limit. + unsigned ConstexprBacktraceLimit; // Cap on depth of constexpr evaluation + // backtrace stack, 0 -> no limit. + ExtensionHandling ExtBehavior; // Map extensions onto warnings or errors? + IntrusiveRefCntPtr<DiagnosticIDs> Diags; + DiagnosticConsumer *Client; + bool OwnsDiagClient; + SourceManager *SourceMgr; + + /// \brief Mapping information for diagnostics. Mapping info is + /// packed into four bits per diagnostic. The low three bits are the mapping + /// (an instance of diag::Mapping), or zero if unset. The high bit is set + /// when the mapping was established as a user mapping. If the high bit is + /// clear, then the low bits are set to the default value, and should be + /// mapped with -pedantic, -Werror, etc. + /// + /// A new DiagState is created and kept around when diagnostic pragmas modify + /// the state so that we know what is the diagnostic state at any given + /// source location. + class DiagState { + llvm::DenseMap<unsigned, DiagnosticMappingInfo> DiagMap; + + public: + typedef llvm::DenseMap<unsigned, DiagnosticMappingInfo>::iterator + iterator; + typedef llvm::DenseMap<unsigned, DiagnosticMappingInfo>::const_iterator + const_iterator; + + void setMappingInfo(diag::kind Diag, DiagnosticMappingInfo Info) { + DiagMap[Diag] = Info; + } + + DiagnosticMappingInfo &getOrAddMappingInfo(diag::kind Diag); + + const_iterator begin() const { return DiagMap.begin(); } + const_iterator end() const { return DiagMap.end(); } + }; + + /// \brief Keeps and automatically disposes all DiagStates that we create. + std::list<DiagState> DiagStates; + + /// \brief Represents a point in source where the diagnostic state was + /// modified because of a pragma. 'Loc' can be null if the point represents + /// the diagnostic state modifications done through the command-line. + struct DiagStatePoint { + DiagState *State; + FullSourceLoc Loc; + DiagStatePoint(DiagState *State, FullSourceLoc Loc) + : State(State), Loc(Loc) { } + + bool operator<(const DiagStatePoint &RHS) const { + // If Loc is invalid it means it came from <command-line>, in which case + // we regard it as coming before any valid source location. + if (RHS.Loc.isInvalid()) + return false; + if (Loc.isInvalid()) + return true; + return Loc.isBeforeInTranslationUnitThan(RHS.Loc); + } + }; + + /// \brief A vector of all DiagStatePoints representing changes in diagnostic + /// state due to diagnostic pragmas. The vector is always sorted according to + /// the SourceLocation of the DiagStatePoint. + typedef std::vector<DiagStatePoint> DiagStatePointsTy; + mutable DiagStatePointsTy DiagStatePoints; + + /// \brief Keeps the DiagState that was active during each diagnostic 'push' + /// so we can get back at it when we 'pop'. + std::vector<DiagState *> DiagStateOnPushStack; + + DiagState *GetCurDiagState() const { + assert(!DiagStatePoints.empty()); + return DiagStatePoints.back().State; + } + + void PushDiagStatePoint(DiagState *State, SourceLocation L) { + FullSourceLoc Loc(L, *SourceMgr); + // Make sure that DiagStatePoints is always sorted according to Loc. + assert((Loc.isValid() || DiagStatePoints.empty()) && + "Adding invalid loc point after another point"); + assert((Loc.isInvalid() || DiagStatePoints.empty() || + DiagStatePoints.back().Loc.isInvalid() || + DiagStatePoints.back().Loc.isBeforeInTranslationUnitThan(Loc)) && + "Previous point loc comes after or is the same as new one"); + DiagStatePoints.push_back(DiagStatePoint(State, + FullSourceLoc(Loc, *SourceMgr))); + } + + /// \brief Finds the DiagStatePoint that contains the diagnostic state of + /// the given source location. + DiagStatePointsTy::iterator GetDiagStatePointForLoc(SourceLocation Loc) const; + + /// ErrorOccurred / FatalErrorOccurred - This is set to true when an error or + /// fatal error is emitted, and is sticky. + bool ErrorOccurred; + bool FatalErrorOccurred; + + /// \brief Indicates that an unrecoverable error has occurred. + bool UnrecoverableErrorOccurred; + + /// \brief Counts for DiagnosticErrorTrap to check whether an error occurred + /// during a parsing section, e.g. during parsing a function. + unsigned TrapNumErrorsOccurred; + unsigned TrapNumUnrecoverableErrorsOccurred; + + /// LastDiagLevel - This is the level of the last diagnostic emitted. This is + /// used to emit continuation diagnostics with the same level as the + /// diagnostic that they follow. + DiagnosticIDs::Level LastDiagLevel; + + unsigned NumWarnings; // Number of warnings reported + unsigned NumErrors; // Number of errors reported + unsigned NumErrorsSuppressed; // Number of errors suppressed + + /// ArgToStringFn - A function pointer that converts an opaque diagnostic + /// argument to a strings. This takes the modifiers and argument that was + /// present in the diagnostic. + /// + /// The PrevArgs array (whose length is NumPrevArgs) indicates the previous + /// arguments formatted for this diagnostic. Implementations of this function + /// can use this information to avoid redundancy across arguments. + /// + /// This is a hack to avoid a layering violation between libbasic and libsema. + typedef void (*ArgToStringFnTy)( + ArgumentKind Kind, intptr_t Val, + const char *Modifier, unsigned ModifierLen, + const char *Argument, unsigned ArgumentLen, + const ArgumentValue *PrevArgs, + unsigned NumPrevArgs, + SmallVectorImpl<char> &Output, + void *Cookie, + ArrayRef<intptr_t> QualTypeVals); + void *ArgToStringCookie; + ArgToStringFnTy ArgToStringFn; + + /// \brief ID of the "delayed" diagnostic, which is a (typically + /// fatal) diagnostic that had to be delayed because it was found + /// while emitting another diagnostic. + unsigned DelayedDiagID; + + /// \brief First string argument for the delayed diagnostic. + std::string DelayedDiagArg1; + + /// \brief Second string argument for the delayed diagnostic. + std::string DelayedDiagArg2; + +public: + explicit DiagnosticsEngine( + const IntrusiveRefCntPtr<DiagnosticIDs> &Diags, + DiagnosticConsumer *client = 0, + bool ShouldOwnClient = true); + ~DiagnosticsEngine(); + + const IntrusiveRefCntPtr<DiagnosticIDs> &getDiagnosticIDs() const { + return Diags; + } + + DiagnosticConsumer *getClient() { return Client; } + const DiagnosticConsumer *getClient() const { return Client; } + + /// \brief Determine whether this \c DiagnosticsEngine object own its client. + bool ownsClient() const { return OwnsDiagClient; } + + /// \brief Return the current diagnostic client along with ownership of that + /// client. + DiagnosticConsumer *takeClient() { + OwnsDiagClient = false; + return Client; + } + + bool hasSourceManager() const { return SourceMgr != 0; } + SourceManager &getSourceManager() const { + assert(SourceMgr && "SourceManager not set!"); + return *SourceMgr; + } + void setSourceManager(SourceManager *SrcMgr) { SourceMgr = SrcMgr; } + + //===--------------------------------------------------------------------===// + // DiagnosticsEngine characterization methods, used by a client to customize + // how diagnostics are emitted. + // + + /// pushMappings - Copies the current DiagMappings and pushes the new copy + /// onto the top of the stack. + void pushMappings(SourceLocation Loc); + + /// popMappings - Pops the current DiagMappings off the top of the stack + /// causing the new top of the stack to be the active mappings. Returns + /// true if the pop happens, false if there is only one DiagMapping on the + /// stack. + bool popMappings(SourceLocation Loc); + + /// \brief Set the diagnostic client associated with this diagnostic object. + /// + /// \param ShouldOwnClient true if the diagnostic object should take + /// ownership of \c client. + void setClient(DiagnosticConsumer *client, bool ShouldOwnClient = true); + + /// setErrorLimit - Specify a limit for the number of errors we should + /// emit before giving up. Zero disables the limit. + void setErrorLimit(unsigned Limit) { ErrorLimit = Limit; } + + /// \brief Specify the maximum number of template instantiation + /// notes to emit along with a given diagnostic. + void setTemplateBacktraceLimit(unsigned Limit) { + TemplateBacktraceLimit = Limit; + } + + /// \brief Retrieve the maximum number of template instantiation + /// notes to emit along with a given diagnostic. + unsigned getTemplateBacktraceLimit() const { + return TemplateBacktraceLimit; + } + + /// \brief Specify the maximum number of constexpr evaluation + /// notes to emit along with a given diagnostic. + void setConstexprBacktraceLimit(unsigned Limit) { + ConstexprBacktraceLimit = Limit; + } + + /// \brief Retrieve the maximum number of constexpr evaluation + /// notes to emit along with a given diagnostic. + unsigned getConstexprBacktraceLimit() const { + return ConstexprBacktraceLimit; + } + + /// setIgnoreAllWarnings - When set to true, any unmapped warnings are + /// ignored. If this and WarningsAsErrors are both set, then this one wins. + void setIgnoreAllWarnings(bool Val) { IgnoreAllWarnings = Val; } + bool getIgnoreAllWarnings() const { return IgnoreAllWarnings; } + + /// setEnableAllWarnings - When set to true, any unmapped ignored warnings + /// are no longer ignored. If this and IgnoreAllWarnings are both set, + /// then that one wins. + void setEnableAllWarnings(bool Val) { EnableAllWarnings = Val; } + bool getEnableAllWarnngs() const { return EnableAllWarnings; } + + /// setWarningsAsErrors - When set to true, any warnings reported are issued + /// as errors. + void setWarningsAsErrors(bool Val) { WarningsAsErrors = Val; } + bool getWarningsAsErrors() const { return WarningsAsErrors; } + + /// setErrorsAsFatal - When set to true, any error reported is made a + /// fatal error. + void setErrorsAsFatal(bool Val) { ErrorsAsFatal = Val; } + bool getErrorsAsFatal() const { return ErrorsAsFatal; } + + /// setSuppressSystemWarnings - When set to true mask warnings that + /// come from system headers. + void setSuppressSystemWarnings(bool Val) { SuppressSystemWarnings = Val; } + bool getSuppressSystemWarnings() const { return SuppressSystemWarnings; } + + /// \brief Suppress all diagnostics, to silence the front end when we + /// know that we don't want any more diagnostics to be passed along to the + /// client + void setSuppressAllDiagnostics(bool Val = true) { + SuppressAllDiagnostics = Val; + } + bool getSuppressAllDiagnostics() const { return SuppressAllDiagnostics; } + + /// \brief Specify which overload candidates to show when overload resolution + /// fails. By default, we show all candidates. + void setShowOverloads(OverloadsShown Val) { + ShowOverloads = Val; + } + OverloadsShown getShowOverloads() const { return ShowOverloads; } + + /// \brief Pretend that the last diagnostic issued was ignored. This can + /// be used by clients who suppress diagnostics themselves. + void setLastDiagnosticIgnored() { + LastDiagLevel = DiagnosticIDs::Ignored; + } + + /// setExtensionHandlingBehavior - This controls whether otherwise-unmapped + /// extension diagnostics are mapped onto ignore/warning/error. This + /// corresponds to the GCC -pedantic and -pedantic-errors option. + void setExtensionHandlingBehavior(ExtensionHandling H) { + ExtBehavior = H; + } + ExtensionHandling getExtensionHandlingBehavior() const { return ExtBehavior; } + + /// AllExtensionsSilenced - This is a counter bumped when an __extension__ + /// block is encountered. When non-zero, all extension diagnostics are + /// entirely silenced, no matter how they are mapped. + void IncrementAllExtensionsSilenced() { ++AllExtensionsSilenced; } + void DecrementAllExtensionsSilenced() { --AllExtensionsSilenced; } + bool hasAllExtensionsSilenced() { return AllExtensionsSilenced != 0; } + + /// \brief This allows the client to specify that certain + /// warnings are ignored. Notes can never be mapped, errors can only be + /// mapped to fatal, and WARNINGs and EXTENSIONs can be mapped arbitrarily. + /// + /// \param Loc The source location that this change of diagnostic state should + /// take affect. It can be null if we are setting the latest state. + void setDiagnosticMapping(diag::kind Diag, diag::Mapping Map, + SourceLocation Loc); + + /// setDiagnosticGroupMapping - Change an entire diagnostic group (e.g. + /// "unknown-pragmas" to have the specified mapping. This returns true and + /// ignores the request if "Group" was unknown, false otherwise. + /// + /// 'Loc' is the source location that this change of diagnostic state should + /// take affect. It can be null if we are setting the state from command-line. + bool setDiagnosticGroupMapping(StringRef Group, diag::Mapping Map, + SourceLocation Loc = SourceLocation()); + + /// \brief Set the warning-as-error flag for the given diagnostic. This + /// function always only operates on the current diagnostic state. + void setDiagnosticWarningAsError(diag::kind Diag, bool Enabled); + + /// \brief Set the warning-as-error flag for the given diagnostic group. This + /// function always only operates on the current diagnostic state. + /// + /// \returns True if the given group is unknown, false otherwise. + bool setDiagnosticGroupWarningAsError(StringRef Group, bool Enabled); + + /// \brief Set the error-as-fatal flag for the given diagnostic. This function + /// always only operates on the current diagnostic state. + void setDiagnosticErrorAsFatal(diag::kind Diag, bool Enabled); + + /// \brief Set the error-as-fatal flag for the given diagnostic group. This + /// function always only operates on the current diagnostic state. + /// + /// \returns True if the given group is unknown, false otherwise. + bool setDiagnosticGroupErrorAsFatal(StringRef Group, bool Enabled); + + /// \brief Add the specified mapping to all diagnostics. Mainly to be used + /// by -Wno-everything to disable all warnings but allow subsequent -W options + /// to enable specific warnings. + void setMappingToAllDiagnostics(diag::Mapping Map, + SourceLocation Loc = SourceLocation()); + + bool hasErrorOccurred() const { return ErrorOccurred; } + bool hasFatalErrorOccurred() const { return FatalErrorOccurred; } + + /// \brief Determine whether any kind of unrecoverable error has occurred. + bool hasUnrecoverableErrorOccurred() const { + return FatalErrorOccurred || UnrecoverableErrorOccurred; + } + + unsigned getNumWarnings() const { return NumWarnings; } + + void setNumWarnings(unsigned NumWarnings) { + this->NumWarnings = NumWarnings; + } + + /// getCustomDiagID - Return an ID for a diagnostic with the specified message + /// and level. If this is the first request for this diagnosic, it is + /// registered and created, otherwise the existing ID is returned. + unsigned getCustomDiagID(Level L, StringRef Message) { + return Diags->getCustomDiagID((DiagnosticIDs::Level)L, Message); + } + + /// ConvertArgToString - This method converts a diagnostic argument (as an + /// intptr_t) into the string that represents it. + void ConvertArgToString(ArgumentKind Kind, intptr_t Val, + const char *Modifier, unsigned ModLen, + const char *Argument, unsigned ArgLen, + const ArgumentValue *PrevArgs, unsigned NumPrevArgs, + SmallVectorImpl<char> &Output, + SmallVectorImpl<intptr_t> &QualTypeVals) const { + ArgToStringFn(Kind, Val, Modifier, ModLen, Argument, ArgLen, + PrevArgs, NumPrevArgs, Output, ArgToStringCookie, + QualTypeVals); + } + + void SetArgToStringFn(ArgToStringFnTy Fn, void *Cookie) { + ArgToStringFn = Fn; + ArgToStringCookie = Cookie; + } + + /// \brief Reset the state of the diagnostic object to its initial + /// configuration. + void Reset(); + + //===--------------------------------------------------------------------===// + // DiagnosticsEngine classification and reporting interfaces. + // + + /// \brief Based on the way the client configured the DiagnosticsEngine + /// object, classify the specified diagnostic ID into a Level, consumable by + /// the DiagnosticConsumer. + /// + /// \param Loc The source location we are interested in finding out the + /// diagnostic state. Can be null in order to query the latest state. + Level getDiagnosticLevel(unsigned DiagID, SourceLocation Loc) const { + return (Level)Diags->getDiagnosticLevel(DiagID, Loc, *this); + } + + /// Report - Issue the message to the client. @c DiagID is a member of the + /// @c diag::kind enum. This actually returns aninstance of DiagnosticBuilder + /// which emits the diagnostics (through @c ProcessDiag) when it is destroyed. + /// @c Pos represents the source location associated with the diagnostic, + /// which can be an invalid location if no position information is available. + inline DiagnosticBuilder Report(SourceLocation Pos, unsigned DiagID); + inline DiagnosticBuilder Report(unsigned DiagID); + + void Report(const StoredDiagnostic &storedDiag); + + /// \brief Determine whethere there is already a diagnostic in flight. + bool isDiagnosticInFlight() const { return CurDiagID != ~0U; } + + /// \brief Set the "delayed" diagnostic that will be emitted once + /// the current diagnostic completes. + /// + /// If a diagnostic is already in-flight but the front end must + /// report a problem (e.g., with an inconsistent file system + /// state), this routine sets a "delayed" diagnostic that will be + /// emitted after the current diagnostic completes. This should + /// only be used for fatal errors detected at inconvenient + /// times. If emitting a delayed diagnostic causes a second delayed + /// diagnostic to be introduced, that second delayed diagnostic + /// will be ignored. + /// + /// \param DiagID The ID of the diagnostic being delayed. + /// + /// \param Arg1 A string argument that will be provided to the + /// diagnostic. A copy of this string will be stored in the + /// DiagnosticsEngine object itself. + /// + /// \param Arg2 A string argument that will be provided to the + /// diagnostic. A copy of this string will be stored in the + /// DiagnosticsEngine object itself. + void SetDelayedDiagnostic(unsigned DiagID, StringRef Arg1 = "", + StringRef Arg2 = ""); + + /// \brief Clear out the current diagnostic. + void Clear() { CurDiagID = ~0U; } + +private: + /// \brief Report the delayed diagnostic. + void ReportDelayed(); + + // This is private state used by DiagnosticBuilder. We put it here instead of + // in DiagnosticBuilder in order to keep DiagnosticBuilder a small lightweight + // object. This implementation choice means that we can only have one + // diagnostic "in flight" at a time, but this seems to be a reasonable + // tradeoff to keep these objects small. Assertions verify that only one + // diagnostic is in flight at a time. + friend class DiagnosticIDs; + friend class DiagnosticBuilder; + friend class Diagnostic; + friend class PartialDiagnostic; + friend class DiagnosticErrorTrap; + + /// CurDiagLoc - This is the location of the current diagnostic that is in + /// flight. + SourceLocation CurDiagLoc; + + /// CurDiagID - This is the ID of the current diagnostic that is in flight. + /// This is set to ~0U when there is no diagnostic in flight. + unsigned CurDiagID; + + enum { + /// MaxArguments - The maximum number of arguments we can hold. We currently + /// only support up to 10 arguments (%0-%9). A single diagnostic with more + /// than that almost certainly has to be simplified anyway. + MaxArguments = 10, + + /// MaxRanges - The maximum number of ranges we can hold. + MaxRanges = 10, + + /// MaxFixItHints - The maximum number of ranges we can hold. + MaxFixItHints = 10 + }; + + /// NumDiagArgs - This contains the number of entries in Arguments. + signed char NumDiagArgs; + /// NumDiagRanges - This is the number of ranges in the DiagRanges array. + unsigned char NumDiagRanges; + /// NumDiagFixItHints - This is the number of hints in the DiagFixItHints + /// array. + unsigned char NumDiagFixItHints; + + /// DiagArgumentsKind - This is an array of ArgumentKind::ArgumentKind enum + /// values, with one for each argument. This specifies whether the argument + /// is in DiagArgumentsStr or in DiagArguments. + unsigned char DiagArgumentsKind[MaxArguments]; + + /// DiagArgumentsStr - This holds the values of each string argument for the + /// current diagnostic. This value is only used when the corresponding + /// ArgumentKind is ak_std_string. + std::string DiagArgumentsStr[MaxArguments]; + + /// DiagArgumentsVal - The values for the various substitution positions. This + /// is used when the argument is not an std::string. The specific value is + /// mangled into an intptr_t and the interpretation depends on exactly what + /// sort of argument kind it is. + intptr_t DiagArgumentsVal[MaxArguments]; + + /// DiagRanges - The list of ranges added to this diagnostic. + CharSourceRange DiagRanges[MaxRanges]; + + /// FixItHints - If valid, provides a hint with some code to insert, remove, + /// or modify at a particular position. + FixItHint DiagFixItHints[MaxFixItHints]; + + DiagnosticMappingInfo makeMappingInfo(diag::Mapping Map, SourceLocation L) { + bool isPragma = L.isValid(); + DiagnosticMappingInfo MappingInfo = DiagnosticMappingInfo::Make( + Map, /*IsUser=*/true, isPragma); + + // If this is a pragma mapping, then set the diagnostic mapping flags so + // that we override command line options. + if (isPragma) { + MappingInfo.setNoWarningAsError(true); + MappingInfo.setNoErrorAsFatal(true); + } + + return MappingInfo; + } + + /// ProcessDiag - This is the method used to report a diagnostic that is + /// finally fully formed. + /// + /// \returns true if the diagnostic was emitted, false if it was + /// suppressed. + bool ProcessDiag() { + return Diags->ProcessDiag(*this); + } + + /// @name Diagnostic Emission + /// @{ +protected: + // Sema requires access to the following functions because the current design + // of SFINAE requires it to use its own SemaDiagnosticBuilder, which needs to + // access us directly to ensure we minimize the emitted code for the common + // Sema::Diag() patterns. + friend class Sema; + + /// \brief Emit the current diagnostic and clear the diagnostic state. + bool EmitCurrentDiagnostic(); + + unsigned getCurrentDiagID() const { return CurDiagID; } + + SourceLocation getCurrentDiagLoc() const { return CurDiagLoc; } + + /// @} + + friend class ASTReader; + friend class ASTWriter; +}; + +/// \brief RAII class that determines when any errors have occurred +/// between the time the instance was created and the time it was +/// queried. +class DiagnosticErrorTrap { + DiagnosticsEngine &Diag; + unsigned NumErrors; + unsigned NumUnrecoverableErrors; + +public: + explicit DiagnosticErrorTrap(DiagnosticsEngine &Diag) + : Diag(Diag) { reset(); } + + /// \brief Determine whether any errors have occurred since this + /// object instance was created. + bool hasErrorOccurred() const { + return Diag.TrapNumErrorsOccurred > NumErrors; + } + + /// \brief Determine whether any unrecoverable errors have occurred since this + /// object instance was created. + bool hasUnrecoverableErrorOccurred() const { + return Diag.TrapNumUnrecoverableErrorsOccurred > NumUnrecoverableErrors; + } + + // Set to initial state of "no errors occurred". + void reset() { + NumErrors = Diag.TrapNumErrorsOccurred; + NumUnrecoverableErrors = Diag.TrapNumUnrecoverableErrorsOccurred; + } +}; + +//===----------------------------------------------------------------------===// +// DiagnosticBuilder +//===----------------------------------------------------------------------===// + +/// DiagnosticBuilder - This is a little helper class used to produce +/// diagnostics. This is constructed by the DiagnosticsEngine::Report method, +/// and allows insertion of extra information (arguments and source ranges) into +/// the currently "in flight" diagnostic. When the temporary for the builder is +/// destroyed, the diagnostic is issued. +/// +/// Note that many of these will be created as temporary objects (many call +/// sites), so we want them to be small and we never want their address taken. +/// This ensures that compilers with somewhat reasonable optimizers will promote +/// the common fields to registers, eliminating increments of the NumArgs field, +/// for example. +class DiagnosticBuilder { + mutable DiagnosticsEngine *DiagObj; + mutable unsigned NumArgs, NumRanges, NumFixits; + + /// \brief Status variable indicating if this diagnostic is still active. + /// + // NOTE: This field is redundant with DiagObj (IsActive iff (DiagObj == 0)), + // but LLVM is not currently smart enough to eliminate the null check that + // Emit() would end up with if we used that as our status variable. + mutable bool IsActive; + + void operator=(const DiagnosticBuilder&); // DO NOT IMPLEMENT + friend class DiagnosticsEngine; + explicit DiagnosticBuilder(DiagnosticsEngine *diagObj) + : DiagObj(diagObj), NumArgs(0), NumRanges(0), NumFixits(0), IsActive(true) { + assert(diagObj && "DiagnosticBuilder requires a valid DiagnosticsEngine!"); + } + + friend class PartialDiagnostic; + +protected: + void FlushCounts() { + DiagObj->NumDiagArgs = NumArgs; + DiagObj->NumDiagRanges = NumRanges; + DiagObj->NumDiagFixItHints = NumFixits; + } + + /// \brief Clear out the current diagnostic. + void Clear() const { + DiagObj = 0; + IsActive = false; + } + + /// isActive - Determine whether this diagnostic is still active. + bool isActive() const { return IsActive; } + + /// \brief Force the diagnostic builder to emit the diagnostic now. + /// + /// Once this function has been called, the DiagnosticBuilder object + /// should not be used again before it is destroyed. + /// + /// \returns true if a diagnostic was emitted, false if the + /// diagnostic was suppressed. + bool Emit() { + // If this diagnostic is inactive, then its soul was stolen by the copy ctor + // (or by a subclass, as in SemaDiagnosticBuilder). + if (!isActive()) return false; + + // When emitting diagnostics, we set the final argument count into + // the DiagnosticsEngine object. + FlushCounts(); + + // Process the diagnostic. + bool Result = DiagObj->EmitCurrentDiagnostic(); + + // This diagnostic is dead. + Clear(); + + return Result; + } + +public: + /// Copy constructor. When copied, this "takes" the diagnostic info from the + /// input and neuters it. + DiagnosticBuilder(const DiagnosticBuilder &D) { + DiagObj = D.DiagObj; + IsActive = D.IsActive; + D.Clear(); + NumArgs = D.NumArgs; + NumRanges = D.NumRanges; + NumFixits = D.NumFixits; + } + + /// Destructor - The dtor emits the diagnostic. + ~DiagnosticBuilder() { + Emit(); + } + + /// Operator bool: conversion of DiagnosticBuilder to bool always returns + /// true. This allows is to be used in boolean error contexts like: + /// return Diag(...); + operator bool() const { return true; } + + void AddString(StringRef S) const { + assert(isActive() && "Clients must not add to cleared diagnostic!"); + assert(NumArgs < DiagnosticsEngine::MaxArguments && + "Too many arguments to diagnostic!"); + DiagObj->DiagArgumentsKind[NumArgs] = DiagnosticsEngine::ak_std_string; + DiagObj->DiagArgumentsStr[NumArgs++] = S; + } + + void AddTaggedVal(intptr_t V, DiagnosticsEngine::ArgumentKind Kind) const { + assert(isActive() && "Clients must not add to cleared diagnostic!"); + assert(NumArgs < DiagnosticsEngine::MaxArguments && + "Too many arguments to diagnostic!"); + DiagObj->DiagArgumentsKind[NumArgs] = Kind; + DiagObj->DiagArgumentsVal[NumArgs++] = V; + } + + void AddSourceRange(const CharSourceRange &R) const { + assert(isActive() && "Clients must not add to cleared diagnostic!"); + assert(NumRanges < DiagnosticsEngine::MaxRanges && + "Too many arguments to diagnostic!"); + DiagObj->DiagRanges[NumRanges++] = R; + } + + void AddFixItHint(const FixItHint &Hint) const { + assert(isActive() && "Clients must not add to cleared diagnostic!"); + assert(NumFixits < DiagnosticsEngine::MaxFixItHints && + "Too many arguments to diagnostic!"); + DiagObj->DiagFixItHints[NumFixits++] = Hint; + } +}; + +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + StringRef S) { + DB.AddString(S); + return DB; +} + +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + const char *Str) { + DB.AddTaggedVal(reinterpret_cast<intptr_t>(Str), + DiagnosticsEngine::ak_c_string); + return DB; +} + +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, int I) { + DB.AddTaggedVal(I, DiagnosticsEngine::ak_sint); + return DB; +} + +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB,bool I) { + DB.AddTaggedVal(I, DiagnosticsEngine::ak_sint); + return DB; +} + +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + unsigned I) { + DB.AddTaggedVal(I, DiagnosticsEngine::ak_uint); + return DB; +} + +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + const IdentifierInfo *II) { + DB.AddTaggedVal(reinterpret_cast<intptr_t>(II), + DiagnosticsEngine::ak_identifierinfo); + return DB; +} + +// Adds a DeclContext to the diagnostic. The enable_if template magic is here +// so that we only match those arguments that are (statically) DeclContexts; +// other arguments that derive from DeclContext (e.g., RecordDecls) will not +// match. +template<typename T> +inline +typename llvm::enable_if<llvm::is_same<T, DeclContext>, + const DiagnosticBuilder &>::type +operator<<(const DiagnosticBuilder &DB, T *DC) { + DB.AddTaggedVal(reinterpret_cast<intptr_t>(DC), + DiagnosticsEngine::ak_declcontext); + return DB; +} + +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + const SourceRange &R) { + DB.AddSourceRange(CharSourceRange::getTokenRange(R)); + return DB; +} + +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + const CharSourceRange &R) { + DB.AddSourceRange(R); + return DB; +} + +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + const FixItHint &Hint) { + if (!Hint.isNull()) + DB.AddFixItHint(Hint); + return DB; +} + +/// Report - Issue the message to the client. DiagID is a member of the +/// diag::kind enum. This actually returns a new instance of DiagnosticBuilder +/// which emits the diagnostics (through ProcessDiag) when it is destroyed. +inline DiagnosticBuilder DiagnosticsEngine::Report(SourceLocation Loc, + unsigned DiagID){ + assert(CurDiagID == ~0U && "Multiple diagnostics in flight at once!"); + CurDiagLoc = Loc; + CurDiagID = DiagID; + return DiagnosticBuilder(this); +} +inline DiagnosticBuilder DiagnosticsEngine::Report(unsigned DiagID) { + return Report(SourceLocation(), DiagID); +} + +//===----------------------------------------------------------------------===// +// Diagnostic +//===----------------------------------------------------------------------===// + +/// Diagnostic - This is a little helper class (which is basically a smart +/// pointer that forward info from DiagnosticsEngine) that allows clients to +/// enquire about the currently in-flight diagnostic. +class Diagnostic { + const DiagnosticsEngine *DiagObj; + StringRef StoredDiagMessage; +public: + explicit Diagnostic(const DiagnosticsEngine *DO) : DiagObj(DO) {} + Diagnostic(const DiagnosticsEngine *DO, StringRef storedDiagMessage) + : DiagObj(DO), StoredDiagMessage(storedDiagMessage) {} + + const DiagnosticsEngine *getDiags() const { return DiagObj; } + unsigned getID() const { return DiagObj->CurDiagID; } + const SourceLocation &getLocation() const { return DiagObj->CurDiagLoc; } + bool hasSourceManager() const { return DiagObj->hasSourceManager(); } + SourceManager &getSourceManager() const { return DiagObj->getSourceManager();} + + unsigned getNumArgs() const { return DiagObj->NumDiagArgs; } + + /// getArgKind - Return the kind of the specified index. Based on the kind + /// of argument, the accessors below can be used to get the value. + DiagnosticsEngine::ArgumentKind getArgKind(unsigned Idx) const { + assert(Idx < getNumArgs() && "Argument index out of range!"); + return (DiagnosticsEngine::ArgumentKind)DiagObj->DiagArgumentsKind[Idx]; + } + + /// getArgStdStr - Return the provided argument string specified by Idx. + const std::string &getArgStdStr(unsigned Idx) const { + assert(getArgKind(Idx) == DiagnosticsEngine::ak_std_string && + "invalid argument accessor!"); + return DiagObj->DiagArgumentsStr[Idx]; + } + + /// getArgCStr - Return the specified C string argument. + const char *getArgCStr(unsigned Idx) const { + assert(getArgKind(Idx) == DiagnosticsEngine::ak_c_string && + "invalid argument accessor!"); + return reinterpret_cast<const char*>(DiagObj->DiagArgumentsVal[Idx]); + } + + /// getArgSInt - Return the specified signed integer argument. + int getArgSInt(unsigned Idx) const { + assert(getArgKind(Idx) == DiagnosticsEngine::ak_sint && + "invalid argument accessor!"); + return (int)DiagObj->DiagArgumentsVal[Idx]; + } + + /// getArgUInt - Return the specified unsigned integer argument. + unsigned getArgUInt(unsigned Idx) const { + assert(getArgKind(Idx) == DiagnosticsEngine::ak_uint && + "invalid argument accessor!"); + return (unsigned)DiagObj->DiagArgumentsVal[Idx]; + } + + /// getArgIdentifier - Return the specified IdentifierInfo argument. + const IdentifierInfo *getArgIdentifier(unsigned Idx) const { + assert(getArgKind(Idx) == DiagnosticsEngine::ak_identifierinfo && + "invalid argument accessor!"); + return reinterpret_cast<IdentifierInfo*>(DiagObj->DiagArgumentsVal[Idx]); + } + + /// getRawArg - Return the specified non-string argument in an opaque form. + intptr_t getRawArg(unsigned Idx) const { + assert(getArgKind(Idx) != DiagnosticsEngine::ak_std_string && + "invalid argument accessor!"); + return DiagObj->DiagArgumentsVal[Idx]; + } + + + /// getNumRanges - Return the number of source ranges associated with this + /// diagnostic. + unsigned getNumRanges() const { + return DiagObj->NumDiagRanges; + } + + const CharSourceRange &getRange(unsigned Idx) const { + assert(Idx < DiagObj->NumDiagRanges && "Invalid diagnostic range index!"); + return DiagObj->DiagRanges[Idx]; + } + + /// \brief Return an array reference for this diagnostic's ranges. + ArrayRef<CharSourceRange> getRanges() const { + return llvm::makeArrayRef(DiagObj->DiagRanges, DiagObj->NumDiagRanges); + } + + unsigned getNumFixItHints() const { + return DiagObj->NumDiagFixItHints; + } + + const FixItHint &getFixItHint(unsigned Idx) const { + assert(Idx < getNumFixItHints() && "Invalid index!"); + return DiagObj->DiagFixItHints[Idx]; + } + + const FixItHint *getFixItHints() const { + return getNumFixItHints()? DiagObj->DiagFixItHints : 0; + } + + /// FormatDiagnostic - Format this diagnostic into a string, substituting the + /// formal arguments into the %0 slots. The result is appended onto the Str + /// array. + void FormatDiagnostic(SmallVectorImpl<char> &OutStr) const; + + /// FormatDiagnostic - Format the given format-string into the + /// output buffer using the arguments stored in this diagnostic. + void FormatDiagnostic(const char *DiagStr, const char *DiagEnd, + SmallVectorImpl<char> &OutStr) const; +}; + +/** + * \brief Represents a diagnostic in a form that can be retained until its + * corresponding source manager is destroyed. + */ +class StoredDiagnostic { + unsigned ID; + DiagnosticsEngine::Level Level; + FullSourceLoc Loc; + std::string Message; + std::vector<CharSourceRange> Ranges; + std::vector<FixItHint> FixIts; + +public: + StoredDiagnostic(); + StoredDiagnostic(DiagnosticsEngine::Level Level, const Diagnostic &Info); + StoredDiagnostic(DiagnosticsEngine::Level Level, unsigned ID, + StringRef Message); + StoredDiagnostic(DiagnosticsEngine::Level Level, unsigned ID, + StringRef Message, FullSourceLoc Loc, + ArrayRef<CharSourceRange> Ranges, + ArrayRef<FixItHint> Fixits); + ~StoredDiagnostic(); + + /// \brief Evaluates true when this object stores a diagnostic. + operator bool() const { return Message.size() > 0; } + + unsigned getID() const { return ID; } + DiagnosticsEngine::Level getLevel() const { return Level; } + const FullSourceLoc &getLocation() const { return Loc; } + StringRef getMessage() const { return Message; } + + void setLocation(FullSourceLoc Loc) { this->Loc = Loc; } + + typedef std::vector<CharSourceRange>::const_iterator range_iterator; + range_iterator range_begin() const { return Ranges.begin(); } + range_iterator range_end() const { return Ranges.end(); } + unsigned range_size() const { return Ranges.size(); } + + ArrayRef<CharSourceRange> getRanges() const { + return llvm::makeArrayRef(Ranges); + } + + + typedef std::vector<FixItHint>::const_iterator fixit_iterator; + fixit_iterator fixit_begin() const { return FixIts.begin(); } + fixit_iterator fixit_end() const { return FixIts.end(); } + unsigned fixit_size() const { return FixIts.size(); } + + ArrayRef<FixItHint> getFixIts() const { + return llvm::makeArrayRef(FixIts); + } +}; + +/// DiagnosticConsumer - This is an abstract interface implemented by clients of +/// the front-end, which formats and prints fully processed diagnostics. +class DiagnosticConsumer { +protected: + unsigned NumWarnings; // Number of warnings reported + unsigned NumErrors; // Number of errors reported + +public: + DiagnosticConsumer() : NumWarnings(0), NumErrors(0) { } + + unsigned getNumErrors() const { return NumErrors; } + unsigned getNumWarnings() const { return NumWarnings; } + virtual void clear() { NumWarnings = NumErrors = 0; } + + virtual ~DiagnosticConsumer(); + + /// BeginSourceFile - Callback to inform the diagnostic client that processing + /// of a source file is beginning. + /// + /// Note that diagnostics may be emitted outside the processing of a source + /// file, for example during the parsing of command line options. However, + /// diagnostics with source range information are required to only be emitted + /// in between BeginSourceFile() and EndSourceFile(). + /// + /// \arg LO - The language options for the source file being processed. + /// \arg PP - The preprocessor object being used for the source; this optional + /// and may not be present, for example when processing AST source files. + virtual void BeginSourceFile(const LangOptions &LangOpts, + const Preprocessor *PP = 0) {} + + /// EndSourceFile - Callback to inform the diagnostic client that processing + /// of a source file has ended. The diagnostic client should assume that any + /// objects made available via \see BeginSourceFile() are inaccessible. + virtual void EndSourceFile() {} + + /// \brief Callback to inform the diagnostic client that processing of all + /// source files has ended. + virtual void finish() {} + + /// IncludeInDiagnosticCounts - This method (whose default implementation + /// returns true) indicates whether the diagnostics handled by this + /// DiagnosticConsumer should be included in the number of diagnostics + /// reported by DiagnosticsEngine. + virtual bool IncludeInDiagnosticCounts() const; + + /// HandleDiagnostic - Handle this diagnostic, reporting it to the user or + /// capturing it to a log as needed. + /// + /// Default implementation just keeps track of the total number of warnings + /// and errors. + virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, + const Diagnostic &Info); + + /// \brief Clone the diagnostic consumer, producing an equivalent consumer + /// that can be used in a different context. + virtual DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const = 0; +}; + +/// IgnoringDiagConsumer - This is a diagnostic client that just ignores all +/// diags. +class IgnoringDiagConsumer : public DiagnosticConsumer { + virtual void anchor(); + void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, + const Diagnostic &Info) { + // Just ignore it. + } + DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const { + return new IgnoringDiagConsumer(); + } +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Basic/Diagnostic.td b/clang/include/clang/Basic/Diagnostic.td new file mode 100644 index 0000000..109cd08 --- /dev/null +++ b/clang/include/clang/Basic/Diagnostic.td @@ -0,0 +1,98 @@ +//===--- Diagnostic.td - C Language Family Diagnostic Handling ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the TableGen core definitions for the diagnostics +// and diagnostic control. +// +//===----------------------------------------------------------------------===// + +// Define the diagnostic mappings. +class DiagMapping; +def MAP_IGNORE : DiagMapping; +def MAP_WARNING : DiagMapping; +def MAP_ERROR : DiagMapping; +def MAP_FATAL : DiagMapping; + +// Define the diagnostic classes. +class DiagClass; +def CLASS_NOTE : DiagClass; +def CLASS_WARNING : DiagClass; +def CLASS_EXTENSION : DiagClass; +def CLASS_ERROR : DiagClass; + +// Diagnostic Categories. These can be applied to groups or individual +// diagnostics to specify a category. +class DiagCategory<string Name> { + string CategoryName = Name; +} + +// Diagnostic Groups. +class DiagGroup<string Name, list<DiagGroup> subgroups = []> { + string GroupName = Name; + list<DiagGroup> SubGroups = subgroups; + string CategoryName = ""; +} +class InGroup<DiagGroup G> { DiagGroup Group = G; } +//class IsGroup<string Name> { DiagGroup Group = DiagGroup<Name>; } + + +// This defines all of the named diagnostic categories. +include "DiagnosticCategories.td" + +// This defines all of the named diagnostic groups. +include "DiagnosticGroups.td" + + +// All diagnostics emitted by the compiler are an indirect subclass of this. +class Diagnostic<string text, DiagClass DC, DiagMapping defaultmapping> { + /// Component is specified by the file with a big let directive. + string Component = ?; + string Text = text; + DiagClass Class = DC; + bit SFINAE = 1; + bit AccessControl = 0; + bit WarningNoWerror = 0; + bit WarningShowInSystemHeader = 0; + DiagMapping DefaultMapping = defaultmapping; + DiagGroup Group; + string CategoryName = ""; +} + +class Error<string str> : Diagnostic<str, CLASS_ERROR, MAP_ERROR>; +class Warning<string str> : Diagnostic<str, CLASS_WARNING, MAP_WARNING>; +class Extension<string str> : Diagnostic<str, CLASS_EXTENSION, MAP_IGNORE>; +class ExtWarn<string str> : Diagnostic<str, CLASS_EXTENSION, MAP_WARNING>; +class Note<string str> : Diagnostic<str, CLASS_NOTE, MAP_FATAL/*ignored*/>; + + +class DefaultIgnore { DiagMapping DefaultMapping = MAP_IGNORE; } +class DefaultWarn { DiagMapping DefaultMapping = MAP_WARNING; } +class DefaultError { DiagMapping DefaultMapping = MAP_ERROR; } +class DefaultFatal { DiagMapping DefaultMapping = MAP_FATAL; } +class DefaultWarnNoWerror { + bit WarningNoWerror = 1; +} +class DefaultWarnShowInSystemHeader { + bit WarningShowInSystemHeader = 1; +} + +class NoSFINAE { bit SFINAE = 0; } +class AccessControl { bit AccessControl = 1; } + +// Definitions for Diagnostics. +include "DiagnosticASTKinds.td" +include "DiagnosticAnalysisKinds.td" +include "DiagnosticCommonKinds.td" +include "DiagnosticDriverKinds.td" +include "DiagnosticFrontendKinds.td" +include "DiagnosticLexKinds.td" +include "DiagnosticParseKinds.td" +include "DiagnosticSemaKinds.td" +include "DiagnosticSerializationKinds.td" + diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td b/clang/include/clang/Basic/DiagnosticASTKinds.td new file mode 100644 index 0000000..9cfe5ef --- /dev/null +++ b/clang/include/clang/Basic/DiagnosticASTKinds.td @@ -0,0 +1,211 @@ +//==--- DiagnosticASTKinds.td - libast diagnostics ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +let Component = "AST" in { + +// Constant expression diagnostics. These (and their users) belong in Sema. +def note_expr_divide_by_zero : Note<"division by zero">; +def note_constexpr_invalid_cast : Note< + "%select{reinterpret_cast|dynamic_cast|cast which performs the conversions of" + " a reinterpret_cast|cast from %1}0 is not allowed in a constant expression">; +def note_constexpr_invalid_downcast : Note< + "cannot cast object of dynamic type %0 to type %1">; +def note_constexpr_overflow : Note< + "value %0 is outside the range of representable values of type %1">; +def note_constexpr_negative_shift : Note<"negative shift count %0">; +def note_constexpr_large_shift : Note< + "shift count %0 >= width of type %1 (%2 bit%s2)">; +def note_constexpr_lshift_of_negative : Note<"left shift of negative value %0">; +def note_constexpr_lshift_discards : Note<"signed left shift discards bits">; +def note_constexpr_invalid_function : Note< + "%select{non-constexpr|undefined}0 %select{function|constructor}1 %2 cannot " + "be used in a constant expression">; +def note_constexpr_virtual_call : Note< + "cannot evaluate virtual function call in a constant expression">; +def note_constexpr_virtual_base : Note< + "cannot construct object of type %0 with virtual base class " + "in a constant expression">; +def note_constexpr_nonliteral : Note< + "non-literal type %0 cannot be used in a constant expression">; +def note_constexpr_non_global : Note< + "%select{pointer|reference}0 to %select{|subobject of }1" + "%select{temporary|%3}2 is not a constant expression">; +def note_constexpr_array_index : Note<"cannot refer to element %0 of " + "%select{array of %2 elements|non-array object}1 in a constant expression">; +def note_constexpr_float_arithmetic : Note< + "floating point arithmetic produces %select{an infinity|a NaN}0">; +def note_constexpr_pointer_subtraction_not_same_array : Note< + "subtracted pointers are not elements of the same array">; +def note_constexpr_pointer_comparison_base_classes : Note< + "comparison of addresses of subobjects of different base classes " + "has unspecified value">; +def note_constexpr_pointer_comparison_base_field : Note< + "comparison of address of base class subobject %0 of class %1 to field %2 " + "has unspecified value">; +def note_constexpr_pointer_comparison_differing_access : Note< + "comparison of address of fields %0 and %2 of %4 with differing access " + "specifiers (%1 vs %3) has unspecified value">; +def note_constexpr_compare_virtual_mem_ptr : Note< + "comparison of pointer to virtual member function %0 has unspecified value">; +def note_constexpr_past_end : Note< + "dereferenced pointer past the end of %select{|subobject of }0" + "%select{temporary|%2}1 is not a constant expression">; +def note_constexpr_past_end_subobject : Note< + "cannot %select{access base class of|access derived class of|access field of|" + "access array element of|ERROR|call member function on|" + "access real component of|access imaginary component of}0 " + "pointer past the end of object">; +def note_constexpr_null_subobject : Note< + "cannot %select{access base class of|access derived class of|access field of|" + "access array element of|perform pointer arithmetic on|" + "call member function on|access real component of|" + "access imaginary component of}0 null pointer">; +def note_constexpr_var_init_non_constant : Note< + "initializer of %0 is not a constant expression">; +def note_constexpr_typeid_polymorphic : Note< + "typeid applied to expression of polymorphic type %0 is " + "not allowed in a constant expression">; +def note_constexpr_void_comparison : Note< + "comparison between unequal pointers to void has unspecified result">; +def note_constexpr_temporary_here : Note<"temporary created here">; +def note_constexpr_conditional_never_const : Note< + "both arms of conditional operator are unable to produce a " + "constant expression">; +def note_constexpr_depth_limit_exceeded : Note< + "constexpr evaluation exceeded maximum depth of %0 calls">; +def note_constexpr_call_limit_exceeded : Note< + "constexpr evaluation hit maximum call limit">; +def note_constexpr_lifetime_ended : Note< + "read of %select{temporary|variable}0 whose lifetime has ended">; +def note_constexpr_ltor_volatile_type : Note< + "read of volatile-qualified type %0 is not allowed in a constant expression">; +def note_constexpr_ltor_volatile_obj : Note< + "read of volatile %select{temporary|object %1|member %1}0 is not allowed in " + "a constant expression">; +def note_constexpr_ltor_mutable : Note< + "read of mutable member %0 is not allowed in a constant expression">; +def note_constexpr_ltor_non_const_int : Note< + "read of non-const variable %0 is not allowed in a constant expression">; +def note_constexpr_ltor_non_constexpr : Note< + "read of non-constexpr variable %0 is not allowed in a constant expression">; +def note_constexpr_read_past_end : Note< + "read of dereferenced one-past-the-end pointer is not allowed in a " + "constant expression">; +def note_constexpr_read_inactive_union_member : Note< + "read of member %0 of union with %select{active member %2|no active member}1 " + "is not allowed in a constant expression">; +def note_constexpr_read_uninit : Note< + "read of uninitialized object is not allowed in a constant expression">; +def note_constexpr_calls_suppressed : Note< + "(skipping %0 call%s0 in backtrace; use -fconstexpr-backtrace-limit=0 to " + "see all)">; +def note_constexpr_call_here : Note<"in call to '%0'">; + +// inline asm related. +let CategoryName = "Inline Assembly Issue" in { + def err_asm_invalid_escape : Error< + "invalid %% escape in inline assembly string">; + def err_asm_unknown_symbolic_operand_name : Error< + "unknown symbolic operand name in inline assembly string">; + + def err_asm_unterminated_symbolic_operand_name : Error< + "unterminated symbolic operand name in inline assembly string">; + def err_asm_empty_symbolic_operand_name : Error< + "empty symbolic operand name in inline assembly string">; + def err_asm_invalid_operand_number : Error< + "invalid operand number in inline asm string">; +} + + +// Importing ASTs +def err_odr_variable_type_inconsistent : Error< + "external variable %0 declared with incompatible types in different " + "translation units (%1 vs. %2)">; +def err_odr_variable_multiple_def : Error< + "external variable %0 defined in multiple translation units">; +def note_odr_value_here : Note<"declared here with type %0">; +def note_odr_defined_here : Note<"also defined here">; +def err_odr_function_type_inconsistent : Error< + "external function %0 declared with incompatible types in different " + "translation units (%1 vs. %2)">; +def warn_odr_tag_type_inconsistent : Warning< + "type %0 has incompatible definitions in different translation units">; +def note_odr_tag_kind_here: Note< + "%0 is a %select{struct|union|class|enum}1 here">; +def note_odr_field : Note<"field %0 has type %1 here">; +def note_odr_missing_field : Note<"no corresponding field here">; +def note_odr_bit_field : Note<"bit-field %0 with type %1 and length %2 here">; +def note_odr_not_bit_field : Note<"field %0 is not a bit-field">; +def note_odr_base : Note<"class has base type %0">; +def note_odr_virtual_base : Note< + "%select{non-virtual|virtual}0 derivation here">; +def note_odr_missing_base : Note<"no corresponding base class here">; +def note_odr_number_of_bases : Note< + "class has %0 base %plural{1:class|:classes}0">; +def note_odr_enumerator : Note<"enumerator %0 with value %1 here">; +def note_odr_missing_enumerator : Note<"no corresponding enumerator here">; + +def err_odr_field_type_inconsistent : Error< + "field %0 declared with incompatible types in different " + "translation units (%1 vs. %2)">; + +// Importing Objective-C ASTs +def err_odr_ivar_type_inconsistent : Error< + "instance variable %0 declared with incompatible types in different " + "translation units (%1 vs. %2)">; +def err_odr_objc_superclass_inconsistent : Error< + "class %0 has incompatible superclasses">; +def note_odr_objc_superclass : Note<"inherits from superclass %0 here">; +def note_odr_objc_missing_superclass : Note<"no corresponding superclass here">; +def err_odr_objc_method_result_type_inconsistent : Error< + "%select{class|instance}0 method %1 has incompatible result types in " + "different translation units (%2 vs. %3)">; +def err_odr_objc_method_num_params_inconsistent : Error< + "%select{class|instance}0 method %1 has a different number of parameters in " + "different translation units (%2 vs. %3)">; +def err_odr_objc_method_param_type_inconsistent : Error< + "%select{class|instance}0 method %1 has a parameter with a different types " + "in different translation units (%2 vs. %3)">; +def err_odr_objc_method_variadic_inconsistent : Error< + "%select{class|instance}0 method %1 is variadic in one translation unit " + "and not variadic in another">; +def note_odr_objc_method_here : Note< + "%select{class|instance}0 method %1 also declared here">; +def err_odr_objc_property_type_inconsistent : Error< + "property %0 declared with incompatible types in different " + "translation units (%1 vs. %2)">; +def err_odr_objc_property_impl_kind_inconsistent : Error< + "property %0 is implemented with %select{@synthesize|@dynamic}1 in one " + "translation but %select{@dynamic|@synthesize}1 in another translation unit">; +def note_odr_objc_property_impl_kind : Note< + "property %0 is implemented with %select{@synthesize|@dynamic}1 here">; +def err_odr_objc_synthesize_ivar_inconsistent : Error< + "property %0 is synthesized to different ivars in different translation " + "units (%1 vs. %2)">; +def note_odr_objc_synthesize_ivar_here : Note< + "property is synthesized to ivar %0 here">; + +// Importing C++ ASTs +def err_odr_different_num_template_parameters : Error< + "template parameter lists have a different number of parameters (%0 vs %1)">; +def note_odr_template_parameter_list : Note< + "template parameter list also declared here">; +def err_odr_different_template_parameter_kind : Error< + "template parameter has different kinds in different translation units">; +def note_odr_template_parameter_here : Note< + "template parameter declared here">; +def err_odr_parameter_pack_non_pack : Error< + "parameter kind mismatch; parameter is %select{not a|a}0 parameter pack">; +def note_odr_parameter_pack_non_pack : Note< + "%select{parameter|parameter pack}0 declared here">; +def err_odr_non_type_parameter_type_inconsistent : Error< + "non-type template parameter declared with incompatible types in different " + "translation units (%0 vs. %1)">; +def err_unsupported_ast_node: Error<"cannot import unsupported AST node %0">; +} diff --git a/clang/include/clang/Basic/DiagnosticAnalysisKinds.td b/clang/include/clang/Basic/DiagnosticAnalysisKinds.td new file mode 100644 index 0000000..5461212 --- /dev/null +++ b/clang/include/clang/Basic/DiagnosticAnalysisKinds.td @@ -0,0 +1,12 @@ +//==--- DiagnosticAnalysisKinds.td - libanalysis diagnostics --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +let Component = "Analysis" in { + +} diff --git a/clang/include/clang/Basic/DiagnosticCategories.h b/clang/include/clang/Basic/DiagnosticCategories.h new file mode 100644 index 0000000..4dd067b --- /dev/null +++ b/clang/include/clang/Basic/DiagnosticCategories.h @@ -0,0 +1,26 @@ +//===- DiagnosticCategories.h - Diagnostic Categories Enumerators-*- C++ -*===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_DIAGNOSTICCATEGORIES_H +#define LLVM_CLANG_BASIC_DIAGNOSTICCATEGORIES_H + +namespace clang { + namespace diag { + enum { +#define GET_CATEGORY_TABLE +#define CATEGORY(X, ENUM) ENUM, +#include "clang/Basic/DiagnosticGroups.inc" +#undef CATEGORY +#undef GET_CATEGORY_TABLE + DiagCat_NUM_CATEGORIES + }; + } // end namespace diag +} // end namespace clang + +#endif diff --git a/clang/include/clang/Basic/DiagnosticCategories.td b/clang/include/clang/Basic/DiagnosticCategories.td new file mode 100644 index 0000000..a02fbdf --- /dev/null +++ b/clang/include/clang/Basic/DiagnosticCategories.td @@ -0,0 +1,10 @@ +//==--- DiagnosticCategories.td - Diagnostic Category Definitions ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +class CatInlineAsm : DiagCategory<"Inline Assembly Issue">; diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td new file mode 100644 index 0000000..103fc00 --- /dev/null +++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td @@ -0,0 +1,109 @@ +//==--- DiagnosticCommonKinds.td - common diagnostics ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Common Helpers +//===----------------------------------------------------------------------===// + +let Component = "Common" in { + +// Basic. + +def fatal_too_many_errors + : Error<"too many errors emitted, stopping now">, DefaultFatal; + +def note_declared_at : Note<"declared here">; +def note_previous_definition : Note<"previous definition is here">; +def note_previous_declaration : Note<"previous declaration is here">; +def note_previous_implicit_declaration : Note< + "previous implicit declaration is here">; +def note_previous_use : Note<"previous use is here">; +def note_duplicate_case_prev : Note<"previous case defined here">; +def note_forward_declaration : Note<"forward declaration of %0">; +def note_type_being_defined : Note< + "definition of %0 is not complete until the closing '}'">; +/// note_matching - this is used as a continuation of a previous diagnostic, +/// e.g. to specify the '(' when we expected a ')'. +def note_matching : Note<"to match this '%0'">; + +def note_using : Note<"using">; +def note_possibility : Note<"one possibility">; +def note_also_found : Note<"also found">; + +// Parse && Lex +def err_expected_colon : Error<"expected ':'">; +def err_expected_colon_after_setter_name : Error< + "method name referenced in property setter attribute " + "must end with ':'">; +def err_invalid_string_udl : Error< + "string literal with user-defined suffix cannot be used here">; +def err_invalid_character_udl : Error< + "character literal with user-defined suffix cannot be used here">; +def err_invalid_numeric_udl : Error< + "numeric literal with user-defined suffix cannot be used here">; + +// Parse && Sema +def ext_no_declarators : ExtWarn<"declaration does not declare anything">, + InGroup<MissingDeclarations>; +def err_param_redefinition : Error<"redefinition of parameter %0">; +def warn_method_param_redefinition : Warning<"redefinition of method parameter %0">; +def warn_method_param_declaration : Warning<"redeclaration of method parameter %0">, + InGroup<DuplicateArgDecl>, DefaultIgnore; +def err_invalid_storage_class_in_func_decl : Error< + "invalid storage class specifier in function declarator">; +def err_expected_namespace_name : Error<"expected namespace name">; +def ext_variadic_templates : ExtWarn< + "variadic templates are a C++11 extension">, InGroup<CXX11>; +def warn_cxx98_compat_variadic_templates : + Warning<"variadic templates are incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def err_default_special_members : Error< + "only special member functions may be defaulted">; +def err_deleted_non_function : Error< + "only functions can have deleted definitions">; +def err_module_not_found : Error<"module '%0' not found">, DefaultFatal; +def err_module_not_built : Error<"could not build module '%0'">, DefaultFatal; +def err_module_cycle : Error<"cyclic dependency in module '%0': %1">, + DefaultFatal; +def warn_module_build : Warning<"building module '%0' from source">, + InGroup<ModuleBuild>, DefaultIgnore; +def note_pragma_entered_here : Note<"#pragma entered here">; + +// Sema && Lex +def ext_longlong : Extension< + "'long long' is an extension when C99 mode is not enabled">, + InGroup<LongLong>; +def warn_cxx98_compat_longlong : Warning< + "'long long' is incompatible with C++98">, + InGroup<CXX98CompatPedantic>, DefaultIgnore; +def warn_integer_too_large : Warning< + "integer constant is too large for its type">; +def warn_integer_too_large_for_signed : Warning< + "integer constant is so large that it is unsigned">; + +// Sema && AST +def note_invalid_subexpr_in_const_expr : Note< + "subexpression not valid in a constant expression">; + +// Targets + +def err_target_unknown_triple : Error< + "unknown target triple '%0', please use -triple or -arch">; +def err_target_unknown_cpu : Error<"unknown target CPU '%0'">; +def err_target_unknown_abi : Error<"unknown target ABI '%0'">; +def err_target_unknown_cxxabi : Error<"unknown C++ ABI '%0'">; +def err_target_invalid_feature : Error<"invalid target feature '%0'">; + +// Source manager +def err_cannot_open_file : Error<"cannot open file '%0': %1">, DefaultFatal; +def err_file_modified : Error< + "file '%0' modified since it was first processed">, DefaultFatal; +def err_unsupported_bom : Error<"%0 byte order mark detected in '%1', but " + "encoding is not supported">, DefaultFatal; +} diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td new file mode 100644 index 0000000..b443159 --- /dev/null +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -0,0 +1,138 @@ +//==--- DiagnosticDriverKinds.td - libdriver diagnostics ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +let Component = "Driver" in { + +def err_drv_no_such_file : Error<"no such file or directory: '%0'">; +def err_drv_unsupported_opt : Error<"unsupported option '%0'">; +def err_drv_unsupported_option_argument : Error< + "unsupported argument '%1' to option '%0'">; +def err_drv_unknown_stdin_type : Error< + "-E or -x required when input is from standard input">; +def err_drv_unknown_language : Error<"language not recognized: '%0'">; +def err_drv_invalid_arch_name : Error< + "invalid arch name '%0'">; +def err_drv_invalid_rtlib_name : Error< + "invalid runtime library name in argument '%0'">; +def err_drv_unsupported_rtlib_for_platform : Error< + "unsupported runtime library '%0' for platform '%1'">; +def err_drv_invalid_stdlib_name : Error< + "invalid library name in argument '%0'">; +def err_drv_invalid_opt_with_multiple_archs : Error< + "option '%0' cannot be used with multiple -arch options">; +def err_drv_invalid_output_with_multiple_archs : Error< + "cannot use '%0' output with multiple -arch options">; +def err_drv_no_input_files : Error<"no input files">; +def err_drv_use_of_Z_option : Error< + "unsupported use of internal gcc -Z option '%0'">; +def err_drv_output_argument_with_multiple_files : Error< + "cannot specify -o when generating multiple output files">; +def err_drv_unable_to_make_temp : Error< + "unable to make temporary file: %0">; +def err_drv_unable_to_remove_file : Error< + "unable to remove file: %0">; +def err_drv_command_failure : Error< + "unable to execute command: %0">; +def err_drv_invalid_darwin_version : Error< + "invalid Darwin version number: %0">; +def err_drv_missing_argument : Error< + "argument to '%0' is missing (expected %1 value%s1)">; +def err_drv_invalid_Xarch_argument_with_args : Error< + "invalid Xarch argument: '%0', options requiring arguments are unsupported">; +def err_drv_invalid_Xarch_argument_isdriver : Error< + "invalid Xarch argument: '%0', cannot change driver behavior inside Xarch argument">; +def err_drv_argument_only_allowed_with : Error< + "invalid argument '%0' only allowed with '%1'">; +def err_drv_argument_not_allowed_with : Error< + "invalid argument '%0' not allowed with '%1'">; +def err_drv_invalid_version_number : Error< + "invalid version number in '%0'">; +def err_drv_no_linker_llvm_support : Error< + "'%0': unable to pass LLVM bit-code files to linker">; +def err_drv_no_ast_support : Error< + "'%0': unable to use AST files with this tool">; +def err_drv_clang_unsupported : Error< + "the clang compiler does not support '%0'">; +def err_drv_clang_unsupported_per_platform : Error< + "the clang compiler does not support '%0' on this platform">; +def err_drv_clang_unsupported_opt_cxx_darwin_i386 : Error< + "the clang compiler does not support '%0' for C++ on Darwin/i386">; +def err_drv_command_failed : Error< + "%0 command failed with exit code %1 (use -v to see invocation)">; +def err_drv_command_signalled : Error< + "%0 command failed due to signal (use -v to see invocation)">; +def err_drv_invalid_mfloat_abi : Error< + "invalid float ABI '%0'">; +def err_drv_invalid_libcxx_deployment : Error< + "invalid deployment target for -stdlib=libc++ (requires %0 or later)">; +def err_drv_invalid_feature : Error< + "invalid feature '%0' for CPU '%1'">; + +def err_drv_I_dash_not_supported : Error< + "'%0' not supported, please use -iquote instead">; +def err_drv_unknown_argument : Error<"unknown argument: '%0'">; +def err_drv_invalid_value : Error<"invalid value '%1' in '%0'">; +def err_drv_invalid_int_value : Error<"invalid integral value '%1' in '%0'">; +def err_drv_invalid_remap_file : Error< + "invalid option '%0' not of the form <from-file>;<to-file>">; +def err_drv_invalid_gcc_output_type : Error< + "invalid output type '%0' for use with gcc tool">; +def err_drv_cc_print_options_failure : Error< + "unable to open CC_PRINT_OPTIONS file: %0">; +def err_drv_preamble_format : Error< + "incorrect format for -preamble-bytes=N,END">; +def err_drv_conflicting_deployment_targets : Error< + "conflicting deployment targets, both '%0' and '%1' are present in environment">; +def err_drv_invalid_arch_for_deployment_target : Error< + "invalid architecture '%0' for deployment target '%1'">; +def err_drv_objc_gc_arr : Error< + "cannot specify both '-fobjc-arc' and '%0'">; +def err_arc_nonfragile_abi : Error< + "-fobjc-arc is not supported with fragile abi">; +def err_arc_unsupported : Error< + "-fobjc-arc is not supported on current deployment target">; +def err_drv_mg_requires_m_or_mm : Error< + "option '-MG' requires '-M' or '-MM'">; + +def warn_c_kext : Warning< + "ignoring -fapple-kext which is valid for c++ and objective-c++ only">; +def warn_drv_input_file_unused : Warning< + "%0: '%1' input unused when '%2' is present">; +def warn_drv_preprocessed_input_file_unused : Warning< + "%0: previously preprocessed input unused when '%1' is present">; +def warn_drv_unused_argument : Warning< + "argument unused during compilation: '%0'">, + InGroup<DiagGroup<"unused-command-line-argument">>; +def warn_drv_empty_joined_argument : Warning< + "joined argument expects addition arg: '%0'">, + InGroup<DiagGroup<"unused-command-line-argument">>; +def warn_drv_not_using_clang_cpp : Warning< + "not using the clang preprocessor due to user override">; +def warn_drv_not_using_clang_cxx : Warning< + "not using the clang compiler for C++ inputs">; +def warn_drv_not_using_clang_arch : Warning< + "not using the clang compiler for the '%0' architecture">; +def warn_drv_clang_unsupported : Warning< + "the clang compiler does not support '%0'">; +def warn_drv_assuming_mfloat_abi_is : Warning< + "unknown platform, assuming -mfloat-abi=%0">; +def warn_ignoring_ftabstop_value : Warning< + "ignoring invalid -ftabstop value '%0', using default value %1">; +def warn_drv_treating_input_as_cxx : Warning< + "treating '%0' input as '%1' when in C++ mode, this behavior is deprecated">, + InGroup<Deprecated>; +def warn_drv_objc_gc_unsupported : Warning< + "Objective-C garbage collection is not supported on this platform, ignoring '%0'">; +def warn_drv_pch_not_first_include : Warning< + "precompiled header '%0' was ignored because '%1' is not first '-include'">; + +def note_drv_command_failed_diag_msg : Note< + "diagnostic msg: %0">; + +} diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td new file mode 100644 index 0000000..5d6b887 --- /dev/null +++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -0,0 +1,134 @@ +//==--- DiagnosticFrontendKinds.td - frontend diagnostics -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +let Component = "Frontend" in { + +def err_fe_error_opening : Error<"error opening '%0': %1">; +def err_fe_error_reading : Error<"error reading '%0'">; +def err_fe_error_reading_stdin : Error<"error reading stdin">; +def err_fe_error_backend : Error<"error in backend: %0">, DefaultFatal; + +// Error generated by the backend. +def err_fe_inline_asm : Error<"%0">, CatInlineAsm; +def note_fe_inline_asm_here : Note<"instantiated into assembly here">; +def err_fe_cannot_link_module : Error<"cannot link module '%0': %1">, + DefaultFatal; + + + +def err_fe_invalid_code_complete_file : Error< + "cannot locate code-completion file %0">, DefaultFatal; +def err_fe_stdout_binary : Error<"unable to change standard output to binary">, + DefaultFatal; +def err_fe_dependency_file_requires_MT : Error< + "-dependency-file requires at least one -MT or -MQ option">; +def err_fe_invalid_plugin_name : Error< + "unable to find plugin '%0'">; +def err_fe_expected_compiler_job : Error< + "unable to handle compilation, expected exactly one compiler job in '%0'">; +def err_fe_expected_clang_command : Error< + "expected a clang compiler command">; +def err_fe_remap_missing_to_file : Error< + "could not remap file '%0' to the contents of file '%1'">, DefaultFatal; +def err_fe_remap_missing_from_file : Error< + "could not remap from missing file '%0'">, DefaultFatal; +def err_fe_unable_to_load_pch : Error< + "unable to load PCH file">; +def err_fe_unable_to_load_plugin : Error< + "unable to load plugin '%0': '%1'">; +def err_fe_unable_to_create_target : Error< + "unable to create target: '%0'">; +def err_fe_unable_to_interface_with_target : Error< + "unable to interface with target machine">; +def err_fe_unable_to_open_output : Error< + "unable to open output file '%0': '%1'">; +def err_fe_unable_to_rename_temp : Error< + "unable to rename temporary '%0' to output file '%1': '%2'">; +def err_fe_unable_to_open_logfile : Error< + "unable to open logfile file '%0': '%1'">; +def err_fe_pth_file_has_no_source_header : Error< + "PTH file '%0' does not designate an original source header file for -include-pth">; +def warn_fe_macro_contains_embedded_newline : Warning< + "macro '%0' contains embedded newline, text after the newline is ignored.">; +def warn_fe_cc_print_header_failure : Warning< + "unable to open CC_PRINT_HEADERS file: %0 (using stderr)">; +def warn_fe_cc_log_diagnostics_failure : Warning< + "unable to open CC_LOG_DIAGNOSTICS file: %0 (using stderr)">; + +def warn_fe_serialized_diag_failure : Warning< + "unable to open file %0 for serializing diagnostics (%1)">, + InGroup<DiagGroup<"serialized-diagnostics">>; + +def err_verify_missing_start : Error< + "cannot find start ('{{') of expected %0">; +def err_verify_missing_end : Error< + "cannot find end ('}}') of expected %0">; +def err_verify_invalid_content : Error< + "invalid expected %0: %1">; +def err_verify_inconsistent_diags : Error< + "'%0' diagnostics %select{expected|seen}1 but not %select{seen|expected}1: " + "%2">; + +def note_fixit_applied : Note<"FIX-IT applied suggested code changes">; +def note_fixit_in_macro : Note< + "FIX-IT unable to apply suggested code changes in a macro">; +def note_fixit_failed : Note< + "FIX-IT unable to apply suggested code changes">; +def note_fixit_unfixed_error : Note<"FIX-IT detected an error it cannot fix">; +def warn_fixit_no_changes : Note< + "FIX-IT detected errors it could not fix; no output will be generated">; + +// PCH reader +def err_relocatable_without_isysroot : Error< + "must specify system root with -isysroot when building a relocatable " + "PCH file">; + +def warn_unknown_warning_option : Warning< + "unknown warning option '%0'">, + InGroup<DiagGroup<"unknown-warning-option"> >; +def warn_unknown_negative_warning_option : Warning< + "unknown warning option '%0'?">, + InGroup<DiagGroup<"unknown-warning-option"> >, DefaultIgnore; +def warn_unknown_warning_option_suggest : Warning< + "unknown warning option '%0'; did you mean '%1'?">, + InGroup<DiagGroup<"unknown-warning-option"> >; +def warn_unknown_negative_warning_option_suggest : Warning< + "unknown warning option '%0'; did you mean '%1'?">, + InGroup<DiagGroup<"unknown-warning-option"> >, DefaultIgnore; +def warn_unknown_warning_specifier : Warning< + "unknown %0 warning specifier: '%1'">, + InGroup<DiagGroup<"unknown-warning-option"> >; + +def warn_unknown_analyzer_checker : Warning< + "no analyzer checkers are associated with '%0'">; +def warn_incompatible_analyzer_plugin_api : Warning< + "checker plugin '%0' is not compatible with this version of the analyzer">, + InGroup<DiagGroup<"analyzer-incompatible-plugin"> >; +def note_incompatible_analyzer_plugin_api : Note< + "current API version is '%0', but plugin was compiled with version '%1'">; + +def err_module_map_not_found : Error<"module map file '%0' not found">, + DefaultFatal; +def err_missing_module_name : Error< + "no module name provided; specify one with -fmodule-name=">, + DefaultFatal; +def err_missing_module : Error< + "no module named '%0' declared in module map file '%1'">, DefaultFatal; +def err_missing_umbrella_header : Error< + "cannot open umbrella header '%0': %1">, DefaultFatal; +def err_no_submodule : Error<"no submodule named %0 in module '%1'">; +def err_no_submodule_suggest : Error< + "no submodule named %0 in module '%1'; did you mean '%2'?">; +def warn_missing_submodule : Warning<"missing submodule '%0'">, + InGroup<IncompleteUmbrella>; +def err_module_map_temp_file : Error< + "unable to write temporary module map file '%0'">, DefaultFatal; +def err_module_unavailable : Error<"module '%0' requires feature '%1'">; + +} diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td new file mode 100644 index 0000000..c839853 --- /dev/null +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -0,0 +1,415 @@ +//==--- DiagnosticGroups.td - Diagnostic Group Definitions ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +def ImplicitFunctionDeclare : DiagGroup<"implicit-function-declaration">; +def ImplicitInt : DiagGroup<"implicit-int">; + +// Aggregation warning settings. +def Implicit : DiagGroup<"implicit", [ + ImplicitFunctionDeclare, + ImplicitInt +]>; + +// Empty DiagGroups are recognized by clang but ignored. +def : DiagGroup<"abi">; +def : DiagGroup<"address">; +def AddressOfTemporary : DiagGroup<"address-of-temporary">; +def : DiagGroup<"aggregate-return">; +def AmbigMemberTemplate : DiagGroup<"ambiguous-member-template">; +def : DiagGroup<"attributes">; +def : DiagGroup<"bad-function-cast">; +def Availability : DiagGroup<"availability">; +def AutoImport : DiagGroup<"auto-import">; +def ConstantConversion : DiagGroup<"constant-conversion">; +def LiteralConversion : DiagGroup<"literal-conversion">; +def StringConversion : DiagGroup<"string-conversion">; +def SignConversion : DiagGroup<"sign-conversion">; +def BoolConversion : DiagGroup<"bool-conversion">; +def IntConversion : DiagGroup<"int-conversion">; +def NullConversion : DiagGroup<"null-conversion">; +def BuiltinRequiresHeader : DiagGroup<"builtin-requires-header">; +def CXXCompat: DiagGroup<"c++-compat">; +def CastAlign : DiagGroup<"cast-align">; +def : DiagGroup<"cast-qual">; +def : DiagGroup<"char-align">; +def Comment : DiagGroup<"comment">; +def : DiagGroup<"ctor-dtor-privacy">; +def : DiagGroup<"declaration-after-statement">; +def DefaultArgSpecialMember : DiagGroup<"default-arg-special-member">; +def GNUDesignator : DiagGroup<"gnu-designator">; + +def DeleteNonVirtualDtor : DiagGroup<"delete-non-virtual-dtor">; + +def DeprecatedDeclarations : DiagGroup<"deprecated-declarations">; +def DeprecatedWritableStr : DiagGroup<"deprecated-writable-strings">; +def Deprecated : DiagGroup<"deprecated", [ DeprecatedDeclarations] >, + DiagCategory<"Deprecations">; + +def DeprecatedImplementations :DiagGroup<"deprecated-implementations">; + +def : DiagGroup<"disabled-optimization">; +def : DiagGroup<"discard-qual">; +def : DiagGroup<"div-by-zero">; +def EmptyBody : DiagGroup<"empty-body">; +def ExtraTokens : DiagGroup<"extra-tokens">; + +def FormatExtraArgs : DiagGroup<"format-extra-args">; +def FormatZeroLength : DiagGroup<"format-zero-length">; + +def CXX98CompatBindToTemporaryCopy : + DiagGroup<"c++98-compat-bind-to-temporary-copy">; +def CXX98CompatLocalTypeTemplateArgs : + DiagGroup<"c++98-compat-local-type-template-args">; +def CXX98CompatUnnamedTypeTemplateArgs : + DiagGroup<"c++98-compat-unnamed-type-template-args">; + +def CXX98Compat : DiagGroup<"c++98-compat", + [CXX98CompatBindToTemporaryCopy, + CXX98CompatLocalTypeTemplateArgs, + CXX98CompatUnnamedTypeTemplateArgs]>; +// Warnings for C++11 features which are Extensions in C++98 mode. +def CXX98CompatPedantic : DiagGroup<"c++98-compat-pedantic", [CXX98Compat]>; + +def CXX11Narrowing : DiagGroup<"c++11-narrowing">; + +// Original name of this warning in Clang +def : DiagGroup<"c++0x-narrowing", [CXX11Narrowing]>; + +// Name of this warning in GCC +def : DiagGroup<"narrowing", [CXX11Narrowing]>; + +def CXX11CompatReservedUserDefinedLiteral : + DiagGroup<"c++11-compat-reserved-user-defined-literal">; +def ReservedUserDefinedLiteral : + DiagGroup<"reserved-user-defined-literal", + [CXX11CompatReservedUserDefinedLiteral]>; + +def CXX11Compat : DiagGroup<"c++11-compat", + [CXX11Narrowing, + CXX11CompatReservedUserDefinedLiteral]>; +def : DiagGroup<"c++0x-compat", [CXX11Compat]>; + +def : DiagGroup<"effc++">; +def ExitTimeDestructors : DiagGroup<"exit-time-destructors">; +def FlexibleArrayExtensions : DiagGroup<"flexible-array-extensions">; +def FourByteMultiChar : DiagGroup<"four-char-constants">; +def GlobalConstructors : DiagGroup<"global-constructors">; +def : DiagGroup<"idiomatic-parentheses">; +def BitwiseOpParentheses: DiagGroup<"bitwise-op-parentheses">; +def LogicalOpParentheses: DiagGroup<"logical-op-parentheses">; +def DanglingElse: DiagGroup<"dangling-else">; +def IgnoredQualifiers : DiagGroup<"ignored-qualifiers">; +def : DiagGroup<"import">; +def IncompatiblePointerTypes : DiagGroup<"incompatible-pointer-types">; +def IncompleteUmbrella : DiagGroup<"incomplete-umbrella">; +def KNRPromotedParameter : DiagGroup<"knr-promoted-parameter">; +def : DiagGroup<"init-self">; +def : DiagGroup<"inline">; +def : DiagGroup<"int-to-pointer-cast">; +def : DiagGroup<"invalid-pch">; +def LiteralRange : DiagGroup<"literal-range">; +def LocalTypeTemplateArgs : DiagGroup<"local-type-template-args", + [CXX98CompatLocalTypeTemplateArgs]>; +def MalformedWarningCheck : DiagGroup<"malformed-warning-check">; +def Main : DiagGroup<"main">; +def MainReturnType : DiagGroup<"main-return-type">; +def MissingBraces : DiagGroup<"missing-braces">; +def MissingDeclarations: DiagGroup<"missing-declarations">; +def : DiagGroup<"missing-format-attribute">; +def : DiagGroup<"missing-include-dirs">; +def : DiagGroup<"missing-noreturn">; +def MultiChar : DiagGroup<"multichar">; +def : DiagGroup<"nested-externs">; +def : DiagGroup<"newline-eof">; +def LongLong : DiagGroup<"long-long">; +def MismatchedTags : DiagGroup<"mismatched-tags">; +def MissingFieldInitializers : DiagGroup<"missing-field-initializers">; +def ModuleBuild : DiagGroup<"module-build">; +def NullCharacter : DiagGroup<"null-character">; +def NullDereference : DiagGroup<"null-dereference">; +def InitializerOverrides : DiagGroup<"initializer-overrides">; +def NonNull : DiagGroup<"nonnull">; +def : DiagGroup<"nonportable-cfstrings">; +def NonVirtualDtor : DiagGroup<"non-virtual-dtor">; +def OveralignedType : DiagGroup<"over-aligned">; +def : DiagGroup<"old-style-cast">; +def : DiagGroup<"old-style-definition">; +def OutOfLineDeclaration : DiagGroup<"out-of-line-declaration">; +def : DiagGroup<"overflow">; +def OverlengthStrings : DiagGroup<"overlength-strings">; +def OverloadedVirtual : DiagGroup<"overloaded-virtual">; +def ObjCPropertyImpl : DiagGroup<"objc-property-implementation">; +def ObjCMissingSuperCalls : DiagGroup<"objc-missing-super-calls">; +def ObjCRetainBlockProperty : DiagGroup<"objc-noncopy-retain-block-property">; +def ObjCReadonlyPropertyHasSetter : DiagGroup<"objc-readonly-with-setter-property">; +def ObjCRootClass : DiagGroup<"objc-root-class">; +def Packed : DiagGroup<"packed">; +def Padded : DiagGroup<"padded">; +def PointerArith : DiagGroup<"pointer-arith">; +def PoundWarning : DiagGroup<"#warnings">, + DiagCategory<"#warning Directive">; +def PoundPragmaMessage : DiagGroup<"#pragma-messages">, + DiagCategory<"#pragma message Directive">; +def : DiagGroup<"pointer-to-int-cast">; +def : DiagGroup<"redundant-decls">; +def ReturnTypeCLinkage : DiagGroup<"return-type-c-linkage">; +def ReturnType : DiagGroup<"return-type", [ReturnTypeCLinkage]>; +def BindToTemporaryCopy : DiagGroup<"bind-to-temporary-copy", + [CXX98CompatBindToTemporaryCopy]>; +def SelfAssignment : DiagGroup<"self-assign">; +def SemiBeforeMethodBody : DiagGroup<"semicolon-before-method-body">; +def Sentinel : DiagGroup<"sentinel">; +def MissingMethodReturnType : DiagGroup<"missing-method-return-type">; +def : DiagGroup<"sequence-point">; +def Shadow : DiagGroup<"shadow">; +def : DiagGroup<"shorten-64-to-32">; +def : DiagGroup<"sign-promo">; +def SignCompare : DiagGroup<"sign-compare">; +def : DiagGroup<"stack-protector">; +def : DiagGroup<"switch-default">; +def : DiagGroup<"synth">; +def SizeofArrayArgument : DiagGroup<"sizeof-array-argument">; +def StringPlusInt : DiagGroup<"string-plus-int">; +def StrncatSize : DiagGroup<"strncat-size">; +def TautologicalCompare : DiagGroup<"tautological-compare">; +def HeaderHygiene : DiagGroup<"header-hygiene">; + +// Preprocessor warnings. +def : DiagGroup<"builtin-macro-redefined">; + +// Just silence warnings about -Wstrict-aliasing for now. +def : DiagGroup<"strict-aliasing=0">; +def : DiagGroup<"strict-aliasing=1">; +def : DiagGroup<"strict-aliasing=2">; +def : DiagGroup<"strict-aliasing">; + +// Just silence warnings about -Wstrict-overflow for now. +def : DiagGroup<"strict-overflow=0">; +def : DiagGroup<"strict-overflow=1">; +def : DiagGroup<"strict-overflow=2">; +def : DiagGroup<"strict-overflow=3">; +def : DiagGroup<"strict-overflow=4">; +def : DiagGroup<"strict-overflow=5">; +def : DiagGroup<"strict-overflow">; + +def InvalidOffsetof : DiagGroup<"invalid-offsetof">; +def LambdaExtensions : DiagGroup<"lambda-extensions">; +def : DiagGroup<"strict-prototypes">; +def StrictSelector : DiagGroup<"strict-selector-match">; +def MethodDuplicate : DiagGroup<"duplicate-method-match">; +def CoveredSwitchDefault : DiagGroup<"covered-switch-default">; +def SwitchEnum : DiagGroup<"switch-enum">; +def Switch : DiagGroup<"switch">; +def Trigraphs : DiagGroup<"trigraphs">; + +def : DiagGroup<"type-limits">; +def Unicode : DiagGroup<"unicode">; +def Uninitialized : DiagGroup<"uninitialized">; +def UninitializedMaybe : DiagGroup<"conditional-uninitialized">; +def UnknownPragmas : DiagGroup<"unknown-pragmas">; +def NSobjectAttribute : DiagGroup<"NSObject-attribute">; +def UnknownAttributes : DiagGroup<"attributes">; +def IgnoredAttributes : DiagGroup<"ignored-attributes">; +def UnnamedTypeTemplateArgs : DiagGroup<"unnamed-type-template-args", + [CXX98CompatUnnamedTypeTemplateArgs]>; +def UnusedArgument : DiagGroup<"unused-argument">; +def UnusedComparison : DiagGroup<"unused-comparison">; +def UnusedExceptionParameter : DiagGroup<"unused-exception-parameter">; +def UnneededInternalDecl : DiagGroup<"unneeded-internal-declaration">; +def UnneededMemberFunction : DiagGroup<"unneeded-member-function">; +def UnusedFunction : DiagGroup<"unused-function", [UnneededInternalDecl]>; +def UnusedMemberFunction : DiagGroup<"unused-member-function", + [UnneededMemberFunction]>; +def UnusedLabel : DiagGroup<"unused-label">; +def UnusedParameter : DiagGroup<"unused-parameter">; +def UnusedResult : DiagGroup<"unused-result">; +def UnusedValue : DiagGroup<"unused-value", [UnusedComparison, UnusedResult]>; +def UnusedVariable : DiagGroup<"unused-variable">; +def UsedButMarkedUnused : DiagGroup<"used-but-marked-unused">; +def UserDefinedLiterals : DiagGroup<"user-defined-literals">; +def ReadOnlySetterAttrs : DiagGroup<"readonly-setter-attrs">; +def Reorder : DiagGroup<"reorder">; +def UndeclaredSelector : DiagGroup<"undeclared-selector">; +def ImplicitAtomic : DiagGroup<"implicit-atomic-properties">; +def CustomAtomic : DiagGroup<"custom-atomic-properties">; +def AtomicProperties : DiagGroup<"atomic-properties", + [ImplicitAtomic, CustomAtomic]>; +def AutomaticReferenceCountingABI : DiagGroup<"arc-abi">; +def ARCUnsafeRetainedAssign : DiagGroup<"arc-unsafe-retained-assign">; +def ARCRetainCycles : DiagGroup<"arc-retain-cycles">; +def ARCNonPodMemAccess : DiagGroup<"arc-non-pod-memaccess">; +def AutomaticReferenceCounting : DiagGroup<"arc", + [AutomaticReferenceCountingABI, + ARCUnsafeRetainedAssign, + ARCRetainCycles, + ARCNonPodMemAccess]>; +def Selector : DiagGroup<"selector">; +def NonfragileAbi2 : DiagGroup<"nonfragile-abi2">; +def Protocol : DiagGroup<"protocol">; +def SuperSubClassMismatch : DiagGroup<"super-class-method-mismatch">; +def OverridingMethodMismatch : DiagGroup<"overriding-method-mismatch">; +def : DiagGroup<"variadic-macros">; +def VariadicMacros : DiagGroup<"variadic-macros">; +def VectorConversion : DiagGroup<"vector-conversion">; // clang specific +def VexingParse : DiagGroup<"vexing-parse">; +def VLA : DiagGroup<"vla">; +def VolatileRegisterVar : DiagGroup<"volatile-register-var">; +def Visibility : DiagGroup<"visibility">; + +// GCC calls -Wdeprecated-writable-strings -Wwrite-strings. +def GCCWriteStrings : DiagGroup<"write-strings" , [DeprecatedWritableStr]>; + +def CharSubscript : DiagGroup<"char-subscripts">; +def LargeByValueCopy : DiagGroup<"large-by-value-copy">; +def DuplicateArgDecl : DiagGroup<"duplicate-method-arg">; + +// Aggregation warning settings. + +// -Widiomatic-parentheses contains warnings about 'idiomatic' +// missing parentheses; it is off by default. We do not include it +// in -Wparentheses because most users who use -Wparentheses explicitly +// do not want these warnings. +def ParenthesesOnEquality : DiagGroup<"parentheses-equality">; +def Parentheses : DiagGroup<"parentheses", + [LogicalOpParentheses, + BitwiseOpParentheses, + ParenthesesOnEquality, + DanglingElse]>; + +// -Wconversion has its own warnings, but we split a few out for +// legacy reasons: +// - some people want just 64-to-32 warnings +// - conversion warnings with constant sources are on by default +// - conversion warnings for literals are on by default +// - bool-to-pointer conversion warnings are on by default +// - __null-to-integer conversion warnings are on by default +def Conversion : DiagGroup<"conversion", + [DiagGroup<"shorten-64-to-32">, + ConstantConversion, + LiteralConversion, + StringConversion, + SignConversion, + BoolConversion, + NullConversion, + IntConversion]>, + DiagCategory<"Value Conversion Issue">; + +def Unused : DiagGroup<"unused", + [UnusedArgument, UnusedFunction, UnusedLabel, + // UnusedParameter, (matches GCC's behavior) + // UnusedMemberFunction, (clean-up llvm before enabling) + UnusedValue, UnusedVariable]>, + DiagCategory<"Unused Entity Issue">; + +// Format settings. +def FormatInvalidSpecifier : DiagGroup<"format-invalid-specifier">; +def FormatSecurity : DiagGroup<"format-security">; +def FormatNonStandard : DiagGroup<"format-non-iso">; +def FormatY2K : DiagGroup<"format-y2k">; +def Format : DiagGroup<"format", + [FormatExtraArgs, FormatZeroLength, NonNull, + FormatSecurity, FormatY2K, FormatInvalidSpecifier]>, + DiagCategory<"Format String Issue">; +def FormatNonLiteral : DiagGroup<"format-nonliteral", [FormatSecurity]>; +def Format2 : DiagGroup<"format=2", + [FormatNonLiteral, FormatSecurity, FormatY2K]>; + +def Extra : DiagGroup<"extra", [ + MissingFieldInitializers, + IgnoredQualifiers, + InitializerOverrides, + SemiBeforeMethodBody, + MissingMethodReturnType, + SignCompare, + UnusedParameter + ]>; + +def Most : DiagGroup<"most", [ + CharSubscript, + Comment, + DeleteNonVirtualDtor, + Format, + Implicit, + MismatchedTags, + MissingBraces, + MultiChar, + Reorder, + ReturnType, + SelfAssignment, + SizeofArrayArgument, + StringPlusInt, + Trigraphs, + Uninitialized, + UnknownPragmas, + Unused, + VolatileRegisterVar, + ObjCMissingSuperCalls, + OverloadedVirtual + ]>; + +// Thread Safety warnings +def ThreadSafety : DiagGroup<"thread-safety">; + +// Note that putting warnings in -Wall will not disable them by default. If a +// warning should be active _only_ when -Wall is passed in, mark it as +// DefaultIgnore in addition to putting it here. +def : DiagGroup<"all", [Most, Parentheses, Switch]>; + +// Aliases. +def : DiagGroup<"", [Extra]>; // -W = -Wextra +def : DiagGroup<"endif-labels", [ExtraTokens]>; // -Wendif-labels=-Wendif-tokens +def : DiagGroup<"comments", [Comment]>; // -Wcomments = -Wcomment +def : DiagGroup<"conversion-null", + [NullConversion]>; // -Wconversion-null = -Wnull-conversion +def : DiagGroup<"bool-conversions", + [BoolConversion]>; // -Wbool-conversions = -Wbool-conversion +def : DiagGroup<"int-conversions", + [IntConversion]>; // -Wint-conversions = -Wint-conversion +def : DiagGroup<"vector-conversions", + [VectorConversion]>; // -Wvector-conversions = -Wvector-conversion + +// A warning group for warnings that we want to have on by default in clang, +// but which aren't on by default in GCC. +def NonGCC : DiagGroup<"non-gcc", + [SignCompare, Conversion, LiteralRange]>; + +// A warning group for warnings about using C++11 features as extensions in +// earlier C++ versions. +def CXX11 : DiagGroup<"c++11-extensions">; +def : DiagGroup<"c++0x-extensions", [CXX11]>; +def DelegatingCtorCycles : + DiagGroup<"delegating-ctor-cycles">; + +// A warning group for warnings about using C11 features as extensions. +def C11 : DiagGroup<"c11-extensions">; + +// A warning group for warnings about using C99 features as extensions. +def C99 : DiagGroup<"c99-extensions">; + +// A warning group for warnings about GCC extensions. +def GNU : DiagGroup<"gnu", [GNUDesignator, VLA]>; +// A warning group for warnings about code that clang accepts but gcc doesn't. +def GccCompat : DiagGroup<"gcc-compat">; + +// A warning group for warnings about Microsoft extensions. +def Microsoft : DiagGroup<"microsoft">; + +def ObjCNonUnifiedException : DiagGroup<"objc-nonunified-exceptions">; + +def ObjCProtocolMethodImpl : DiagGroup<"objc-protocol-method-implementation">; + +// ObjC API warning groups. +def ObjCRedundantLiteralUse : DiagGroup<"objc-redundant-literal-use">; +def ObjCRedundantAPIUse : DiagGroup<"objc-redundant-api-use", [ + ObjCRedundantLiteralUse + ]>; + +def ObjCCocoaAPI : DiagGroup<"objc-cocoa-api", [ + ObjCRedundantAPIUse + ]>; diff --git a/clang/include/clang/Basic/DiagnosticIDs.h b/clang/include/clang/Basic/DiagnosticIDs.h new file mode 100644 index 0000000..a6c22db --- /dev/null +++ b/clang/include/clang/Basic/DiagnosticIDs.h @@ -0,0 +1,279 @@ +//===--- DiagnosticIDs.h - Diagnostic IDs Handling --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Diagnostic IDs-related interfaces. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_DIAGNOSTICIDS_H +#define LLVM_CLANG_DIAGNOSTICIDS_H + +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/StringRef.h" +#include "clang/Basic/LLVM.h" + +namespace llvm { + template<typename T, unsigned> class SmallVector; +} + +namespace clang { + class DiagnosticsEngine; + class SourceLocation; + struct WarningOption; + + // Import the diagnostic enums themselves. + namespace diag { + // Start position for diagnostics. + enum { + DIAG_START_DRIVER = 300, + DIAG_START_FRONTEND = DIAG_START_DRIVER + 100, + DIAG_START_SERIALIZATION = DIAG_START_FRONTEND + 100, + DIAG_START_LEX = DIAG_START_SERIALIZATION + 120, + DIAG_START_PARSE = DIAG_START_LEX + 300, + DIAG_START_AST = DIAG_START_PARSE + 400, + DIAG_START_SEMA = DIAG_START_AST + 100, + DIAG_START_ANALYSIS = DIAG_START_SEMA + 3000, + DIAG_UPPER_LIMIT = DIAG_START_ANALYSIS + 100 + }; + + class CustomDiagInfo; + + /// diag::kind - All of the diagnostics that can be emitted by the frontend. + typedef unsigned kind; + + // Get typedefs for common diagnostics. + enum { +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\ + SFINAE,ACCESS,CATEGORY,NOWERROR,SHOWINSYSHEADER) ENUM, +#include "clang/Basic/DiagnosticCommonKinds.inc" + NUM_BUILTIN_COMMON_DIAGNOSTICS +#undef DIAG + }; + + /// Enum values that allow the client to map NOTEs, WARNINGs, and EXTENSIONs + /// to either MAP_IGNORE (nothing), MAP_WARNING (emit a warning), MAP_ERROR + /// (emit as an error). It allows clients to map errors to + /// MAP_ERROR/MAP_DEFAULT or MAP_FATAL (stop emitting diagnostics after this + /// one). + enum Mapping { + // NOTE: 0 means "uncomputed". + MAP_IGNORE = 1, //< Map this diagnostic to nothing, ignore it. + MAP_WARNING = 2, //< Map this diagnostic to a warning. + MAP_ERROR = 3, //< Map this diagnostic to an error. + MAP_FATAL = 4 //< Map this diagnostic to a fatal error. + }; + } + +class DiagnosticMappingInfo { + unsigned Mapping : 3; + unsigned IsUser : 1; + unsigned IsPragma : 1; + unsigned HasShowInSystemHeader : 1; + unsigned HasNoWarningAsError : 1; + unsigned HasNoErrorAsFatal : 1; + +public: + static DiagnosticMappingInfo Make(diag::Mapping Mapping, bool IsUser, + bool IsPragma) { + DiagnosticMappingInfo Result; + Result.Mapping = Mapping; + Result.IsUser = IsUser; + Result.IsPragma = IsPragma; + Result.HasShowInSystemHeader = 0; + Result.HasNoWarningAsError = 0; + Result.HasNoErrorAsFatal = 0; + return Result; + } + + diag::Mapping getMapping() const { return diag::Mapping(Mapping); } + void setMapping(diag::Mapping Value) { Mapping = Value; } + + bool isUser() const { return IsUser; } + bool isPragma() const { return IsPragma; } + + bool hasShowInSystemHeader() const { return HasShowInSystemHeader; } + void setShowInSystemHeader(bool Value) { HasShowInSystemHeader = Value; } + + bool hasNoWarningAsError() const { return HasNoWarningAsError; } + void setNoWarningAsError(bool Value) { HasNoWarningAsError = Value; } + + bool hasNoErrorAsFatal() const { return HasNoErrorAsFatal; } + void setNoErrorAsFatal(bool Value) { HasNoErrorAsFatal = Value; } +}; + +/// \brief Used for handling and querying diagnostic IDs. Can be used and shared +/// by multiple Diagnostics for multiple translation units. +class DiagnosticIDs : public RefCountedBase<DiagnosticIDs> { +public: + /// Level - The level of the diagnostic, after it has been through mapping. + enum Level { + Ignored, Note, Warning, Error, Fatal + }; + +private: + /// CustomDiagInfo - Information for uniquing and looking up custom diags. + diag::CustomDiagInfo *CustomDiagInfo; + +public: + DiagnosticIDs(); + ~DiagnosticIDs(); + + /// getCustomDiagID - Return an ID for a diagnostic with the specified message + /// and level. If this is the first request for this diagnosic, it is + /// registered and created, otherwise the existing ID is returned. + unsigned getCustomDiagID(Level L, StringRef Message); + + //===--------------------------------------------------------------------===// + // Diagnostic classification and reporting interfaces. + // + + /// getDescription - Given a diagnostic ID, return a description of the + /// issue. + StringRef getDescription(unsigned DiagID) const; + + /// isBuiltinWarningOrExtension - Return true if the unmapped diagnostic level + /// of the specified diagnostic ID is a Warning or Extension. This only works + /// on builtin diagnostics, not custom ones, and is not legal to call on + /// NOTEs. + static bool isBuiltinWarningOrExtension(unsigned DiagID); + + /// \brief Return true if the specified diagnostic is mapped to errors by + /// default. + static bool isDefaultMappingAsError(unsigned DiagID); + + /// \brief Determine whether the given built-in diagnostic ID is a + /// Note. + static bool isBuiltinNote(unsigned DiagID); + + /// isBuiltinExtensionDiag - Determine whether the given built-in diagnostic + /// ID is for an extension of some sort. + /// + static bool isBuiltinExtensionDiag(unsigned DiagID) { + bool ignored; + return isBuiltinExtensionDiag(DiagID, ignored); + } + + /// isBuiltinExtensionDiag - Determine whether the given built-in diagnostic + /// ID is for an extension of some sort. This also returns EnabledByDefault, + /// which is set to indicate whether the diagnostic is ignored by default (in + /// which case -pedantic enables it) or treated as a warning/error by default. + /// + static bool isBuiltinExtensionDiag(unsigned DiagID, bool &EnabledByDefault); + + + /// getWarningOptionForDiag - Return the lowest-level warning option that + /// enables the specified diagnostic. If there is no -Wfoo flag that controls + /// the diagnostic, this returns null. + static StringRef getWarningOptionForDiag(unsigned DiagID); + + /// getCategoryNumberForDiag - Return the category number that a specified + /// DiagID belongs to, or 0 if no category. + static unsigned getCategoryNumberForDiag(unsigned DiagID); + + /// getNumberOfCategories - Return the number of categories + static unsigned getNumberOfCategories(); + + /// getCategoryNameFromID - Given a category ID, return the name of the + /// category. + static StringRef getCategoryNameFromID(unsigned CategoryID); + + /// isARCDiagnostic - Return true if a given diagnostic falls into an + /// ARC diagnostic category; + static bool isARCDiagnostic(unsigned DiagID); + + /// \brief Enumeration describing how the the emission of a diagnostic should + /// be treated when it occurs during C++ template argument deduction. + enum SFINAEResponse { + /// \brief The diagnostic should not be reported, but it should cause + /// template argument deduction to fail. + /// + /// The vast majority of errors that occur during template argument + /// deduction fall into this category. + SFINAE_SubstitutionFailure, + + /// \brief The diagnostic should be suppressed entirely. + /// + /// Warnings generally fall into this category. + SFINAE_Suppress, + + /// \brief The diagnostic should be reported. + /// + /// The diagnostic should be reported. Various fatal errors (e.g., + /// template instantiation depth exceeded) fall into this category. + SFINAE_Report, + + /// \brief The diagnostic is an access-control diagnostic, which will be + /// substitution failures in some contexts and reported in others. + SFINAE_AccessControl + }; + + /// \brief Determines whether the given built-in diagnostic ID is + /// for an error that is suppressed if it occurs during C++ template + /// argument deduction. + /// + /// When an error is suppressed due to SFINAE, the template argument + /// deduction fails but no diagnostic is emitted. Certain classes of + /// errors, such as those errors that involve C++ access control, + /// are not SFINAE errors. + static SFINAEResponse getDiagnosticSFINAEResponse(unsigned DiagID); + + /// \brief Get the set of all diagnostic IDs in the group with the given name. + /// + /// \param Diags [out] - On return, the diagnostics in the group. + /// \returns True if the given group is unknown, false otherwise. + bool getDiagnosticsInGroup(StringRef Group, + llvm::SmallVectorImpl<diag::kind> &Diags) const; + + /// \brief Get the set of all diagnostic IDs. + void getAllDiagnostics(llvm::SmallVectorImpl<diag::kind> &Diags) const; + + /// \brief Get the warning option with the closest edit distance to the given + /// group name. + static StringRef getNearestWarningOption(StringRef Group); + +private: + /// \brief Get the set of all diagnostic IDs in the given group. + /// + /// \param Diags [out] - On return, the diagnostics in the group. + void getDiagnosticsInGroup(const WarningOption *Group, + llvm::SmallVectorImpl<diag::kind> &Diags) const; + + /// \brief Based on the way the client configured the DiagnosticsEngine + /// object, classify the specified diagnostic ID into a Level, consumable by + /// the DiagnosticClient. + /// + /// \param Loc The source location we are interested in finding out the + /// diagnostic state. Can be null in order to query the latest state. + DiagnosticIDs::Level getDiagnosticLevel(unsigned DiagID, SourceLocation Loc, + const DiagnosticsEngine &Diag) const; + + /// getDiagnosticLevel - This is an internal implementation helper used when + /// DiagClass is already known. + DiagnosticIDs::Level getDiagnosticLevel(unsigned DiagID, + unsigned DiagClass, + SourceLocation Loc, + const DiagnosticsEngine &Diag) const; + + /// ProcessDiag - This is the method used to report a diagnostic that is + /// finally fully formed. + /// + /// \returns true if the diagnostic was emitted, false if it was + /// suppressed. + bool ProcessDiag(DiagnosticsEngine &Diag) const; + + /// \brief Whether the diagnostic may leave the AST in a state where some + /// invariants can break. + bool isUnrecoverable(unsigned DiagID) const; + + friend class DiagnosticsEngine; +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td new file mode 100644 index 0000000..670283e --- /dev/null +++ b/clang/include/clang/Basic/DiagnosticLexKinds.td @@ -0,0 +1,503 @@ +//==--- DiagnosticLexKinds.td - liblex diagnostics ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Lexer Diagnostics +//===----------------------------------------------------------------------===// + +let Component = "Lex", CategoryName = "Lexical or Preprocessor Issue" in { + +def null_in_string : Warning<"null character(s) preserved in string literal">, + InGroup<NullCharacter>; +def null_in_char : Warning<"null character(s) preserved in character literal">, + InGroup<NullCharacter>; +def null_in_file : Warning<"null character ignored">, InGroup<NullCharacter>; +def warn_nested_block_comment : Warning<"'/*' within block comment">, + InGroup<Comment>; +def escaped_newline_block_comment_end : Warning< + "escaped newline between */ characters at block comment end">, + InGroup<Comment>; +def backslash_newline_space : Warning< + "backslash and newline separated by space">, + InGroup<DiagGroup<"backslash-newline-escape">>; + +// Digraphs. +def warn_cxx98_compat_less_colon_colon : Warning< + "'<::' is treated as digraph '<:' (aka '[') followed by ':' in C++98">, + InGroup<CXX98Compat>, DefaultIgnore; + +// Trigraphs. +def trigraph_ignored : Warning<"trigraph ignored">, InGroup<Trigraphs>; +def trigraph_ignored_block_comment : Warning< + "ignored trigraph would end block comment">, InGroup<Trigraphs>; +def trigraph_ends_block_comment : Warning<"trigraph ends block comment">, + InGroup<Trigraphs>; +def trigraph_converted : Warning<"trigraph converted to '%0' character">, + InGroup<Trigraphs>; + +def ext_multi_line_bcpl_comment : Extension<"multi-line // comment">, + InGroup<Comment>; +def ext_bcpl_comment : Extension< + "// comments are not allowed in this language">, + InGroup<Comment>; +def ext_no_newline_eof : Extension<"no newline at end of file">, + InGroup<DiagGroup<"newline-eof">>; + +def warn_cxx98_compat_no_newline_eof : Warning< + "C++98 requires newline at end of file">, + InGroup<CXX98CompatPedantic>, DefaultIgnore; + +def ext_dollar_in_identifier : Extension<"'$' in identifier">, + InGroup<DiagGroup<"dollar-in-identifier-extension">>; +def ext_charize_microsoft : Extension<"@# is a microsoft extension">, + InGroup<Microsoft>; + +def ext_token_used : Extension<"extension used">, + InGroup<DiagGroup<"language-extension-token">>; + +def warn_cxx11_keyword : Warning<"'%0' is a keyword in C++11">, + InGroup<CXX11Compat>, DefaultIgnore; + +def warn_unterminated_string : ExtWarn<"missing terminating '\"' character">; +def warn_unterminated_char : ExtWarn<"missing terminating ' character">; +def err_empty_character : Error<"empty character constant">; +def err_unterminated_block_comment : Error<"unterminated /* comment">; +def err_invalid_character_to_charify : Error< + "invalid argument to convert to character">; +def err_unterminated___pragma : Error<"missing terminating ')' character">; + +def err_conflict_marker : Error<"version control conflict marker in file">; + +def err_raw_delim_too_long : Error< + "raw string delimiter longer than 16 characters" + "; use PREFIX( )PREFIX to delimit raw string">; +def err_invalid_char_raw_delim : Error< + "invalid character '%0' character in raw string delimiter" + "; use PREFIX( )PREFIX to delimit raw string">; +def err_unterminated_raw_string : Error< + "raw string missing terminating delimiter )%0\"">; +def warn_cxx98_compat_raw_string_literal : Warning< + "raw string literals are incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; + +def ext_multichar_character_literal : ExtWarn< + "multi-character character constant">, InGroup<MultiChar>; +def ext_four_char_character_literal : Extension< + "multi-character character constant">, InGroup<FourByteMultiChar>; + + +// Literal +def ext_nonstandard_escape : Extension< + "use of non-standard escape character '\\%0'">; +def ext_unknown_escape : ExtWarn<"unknown escape sequence '\\%0'">; +def err_hex_escape_no_digits : Error<"\\x used with no following hex digits">; +def err_ucn_escape_no_digits : Error<"\\u used with no following hex digits">; +def err_ucn_escape_invalid : Error<"invalid universal character">; +def err_ucn_escape_incomplete : Error<"incomplete universal character name">; +def err_ucn_escape_basic_scs : Error< + "character '%0' cannot be specified by a universal character name">; +def err_ucn_control_character : Error< + "universal character name refers to a control character">; +def warn_cxx98_compat_literal_ucn_escape_basic_scs : Warning< + "specifying character '%0' with a universal character name " + "is incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore; +def warn_cxx98_compat_literal_ucn_control_character : Warning< + "universal character name referring to a control character " + "is incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore; +def err_invalid_decimal_digit : Error<"invalid digit '%0' in decimal constant">; +def err_invalid_binary_digit : Error<"invalid digit '%0' in binary constant">; +def err_invalid_octal_digit : Error<"invalid digit '%0' in octal constant">; +def err_invalid_suffix_integer_constant : Error< + "invalid suffix '%0' on integer constant">; +def err_invalid_suffix_float_constant : Error< + "invalid suffix '%0' on floating constant">; +def warn_extraneous_char_constant : Warning< + "extraneous characters in character constant ignored">; +def warn_char_constant_too_large : Warning< + "character constant too long for its type">; +def err_multichar_utf_character_literal : Error< + "Unicode character literals may not contain multiple characters">; +def err_exponent_has_no_digits : Error<"exponent has no digits">; +def ext_imaginary_constant : Extension<"imaginary constants are an extension">; +def err_hexconstant_requires_exponent : Error< + "hexadecimal floating constants require an exponent">; +def err_hexconstant_requires_digits : Error< + "hexadecimal floating constants require a significand">; +def ext_hexconstant_invalid : Extension< + "hexadecimal floating constants are a C99 feature">; +def ext_binary_literal : Extension< + "binary integer literals are an extension">; +def err_pascal_string_too_long : Error<"Pascal string is too long">; +def warn_octal_escape_too_large : ExtWarn<"octal escape sequence out of range">; +def warn_hex_escape_too_large : ExtWarn<"hex escape sequence out of range">; +def ext_string_too_long : Extension<"string literal of length %0 exceeds " + "maximum length %1 that %select{C90|ISO C99|C++}2 compilers are required to " + "support">, InGroup<OverlengthStrings>; +def err_character_too_large : Error< + "character too large for enclosing character literal type">; +def warn_ucn_not_valid_in_c89 : ExtWarn< + "unicode escape sequences are only valid in C99 or C++">, InGroup<Unicode>; +def warn_cxx98_compat_unicode_literal : Warning< + "unicode literals are incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def warn_cxx11_compat_user_defined_literal : Warning< + "identifier after literal will be treated as a user-defined literal suffix " + "in C++11">, InGroup<CXX11Compat>, DefaultIgnore; +def warn_cxx11_compat_reserved_user_defined_literal : Warning< + "identifier after literal will be treated as a reserved user-defined literal " + "suffix in C++11">, + InGroup<CXX11CompatReservedUserDefinedLiteral>, DefaultIgnore; +def ext_reserved_user_defined_literal : ExtWarn< + "invalid suffix on literal; C++11 requires a space between literal and " + "identifier">, InGroup<ReservedUserDefinedLiteral>, DefaultError; +def ext_ms_reserved_user_defined_literal : ExtWarn< + "invalid suffix on literal; C++11 requires a space between literal and " + "identifier">, InGroup<ReservedUserDefinedLiteral>; +def err_unsupported_string_concat : Error< + "unsupported non-standard concatenation of string literals">; +def err_string_concat_mixed_suffix : Error< + "differing user-defined suffixes ('%0' and '%1') in string literal " + "concatenation">; +def err_pp_invalid_udl : Error< + "%select{character|integer}0 literal with user-defined suffix " + "cannot be used in preprocessor constant expression">; +def err_bad_string_encoding : Error< + "illegal character encoding in string literal">; +def warn_bad_string_encoding : ExtWarn< + "illegal character encoding in string literal">, + InGroup<DiagGroup<"invalid-source-encoding">>; +def err_bad_character_encoding : Error< + "illegal character encoding in character literal">; +def warn_bad_character_encoding : ExtWarn< + "illegal character encoding in character literal">, + InGroup<DiagGroup<"invalid-source-encoding">>; + + +//===----------------------------------------------------------------------===// +// PTH Diagnostics +//===----------------------------------------------------------------------===// +def err_invalid_pth_file : Error< + "invalid or corrupt PTH file '%0'">; + +//===----------------------------------------------------------------------===// +// Preprocessor Diagnostics +//===----------------------------------------------------------------------===// + +let CategoryName = "User Defined Issues" in { +def pp_hash_warning : Warning<"%0">, + InGroup<PoundWarning>, DefaultWarnShowInSystemHeader; +def err_pp_hash_error : Error<"%0">; +} + +def pp_include_next_in_primary : Warning< + "#include_next in primary source file">; +def pp_include_macros_out_of_predefines : Error< + "the #__include_macros directive is only for internal use by -imacros">; +def pp_include_next_absolute_path : Warning<"#include_next with absolute path">; +def ext_c99_whitespace_required_after_macro_name : ExtWarn< + "ISO C99 requires whitespace after the macro name">, InGroup<C99>; +def ext_missing_whitespace_after_macro_name : ExtWarn< + "whitespace required after macro name">; +def warn_missing_whitespace_after_macro_name : Warning< + "whitespace recommended after macro name">; + +def pp_pragma_once_in_main_file : Warning<"#pragma once in main file">; +def pp_pragma_sysheader_in_main_file : Warning< + "#pragma system_header ignored in main file">; +def pp_poisoning_existing_macro : Warning<"poisoning existing macro">; +def pp_out_of_date_dependency : Warning< + "current file is older than dependency %0">; +def pp_undef_builtin_macro : Warning<"undefining builtin macro">; +def pp_redef_builtin_macro : Warning<"redefining builtin macro">, + InGroup<DiagGroup<"builtin-macro-redefined">>; +def pp_disabled_macro_expansion : Warning< + "disabled expansion of recursive macro">, DefaultIgnore, + InGroup<DiagGroup<"disabled-macro-expansion">>; +def pp_macro_not_used : Warning<"macro is not used">, DefaultIgnore, + InGroup<DiagGroup<"unused-macros">>; +def warn_pp_undef_identifier : Warning< + "%0 is not defined, evaluates to 0">, + InGroup<DiagGroup<"undef">>, DefaultIgnore; + +def pp_invalid_string_literal : Warning< + "invalid string literal, ignoring final '\\'">; +def warn_pp_expr_overflow : Warning< + "integer overflow in preprocessor expression">; +def warn_pp_convert_lhs_to_positive : Warning< + "left side of operator converted from negative value to unsigned: %0">; +def warn_pp_convert_rhs_to_positive : Warning< + "right side of operator converted from negative value to unsigned: %0">; + +def ext_pp_import_directive : Extension<"#import is a language extension">, + InGroup<DiagGroup<"import-preprocessor-directive-pedantic">>; +def err_pp_import_directive_ms : Error< + "#import of type library is an unsupported Microsoft feature">; + +def ext_pp_ident_directive : Extension<"#ident is a language extension">; +def ext_pp_include_next_directive : Extension< + "#include_next is a language extension">; +def ext_pp_warning_directive : Extension<"#warning is a language extension">; + +def ext_pp_extra_tokens_at_eol : ExtWarn< + "extra tokens at end of #%0 directive">, InGroup<ExtraTokens>; + +def ext_pp_comma_expr : Extension<"comma operator in operand of #if">; +def ext_pp_bad_vaargs_use : Extension< + "__VA_ARGS__ can only appear in the expansion of a C99 variadic macro">; +def ext_pp_macro_redef : ExtWarn<"%0 macro redefined">; +def ext_variadic_macro : Extension<"variadic macros were introduced in C99">, + InGroup<VariadicMacros>; +def warn_cxx98_compat_variadic_macro : Warning< + "variadic macros are incompatible with C++98">, + InGroup<CXX98CompatPedantic>, DefaultIgnore; +def ext_named_variadic_macro : Extension< + "named variadic macros are a GNU extension">, InGroup<VariadicMacros>; +def err_embedded_include : Error< + "embedding a #%0 directive within macro arguments is not supported">; +def ext_embedded_directive : Extension< + "embedding a directive within macro arguments has undefined behavior">, + InGroup<DiagGroup<"embedded-directive">>; +def ext_missing_varargs_arg : Extension< + "varargs argument missing, but tolerated as an extension">; +def ext_empty_fnmacro_arg : Extension< + "empty macro arguments were standardized in C99">; +def warn_cxx98_compat_empty_fnmacro_arg : Warning< + "empty macro argument list is incompatible with C++98">, + InGroup<CXX98CompatPedantic>, DefaultIgnore; + +def err_pp_invalid_directive : Error<"invalid preprocessing directive">; +def err_pp_file_not_found : Error<"'%0' file not found">, DefaultFatal; +def err_pp_error_opening_file : Error< + "error opening file '%0': %1">, DefaultFatal; +def err_pp_empty_filename : Error<"empty filename">; +def err_pp_include_too_deep : Error<"#include nested too deeply">; +def err_pp_expects_filename : Error<"expected \"FILENAME\" or <FILENAME>">; +def err_pp_macro_not_identifier : Error<"macro names must be identifiers">; +def err_pp_missing_macro_name : Error<"macro name missing">; +def err_pp_missing_rparen_in_macro_def : Error< + "missing ')' in macro parameter list">; +def err_pp_invalid_tok_in_arg_list : Error< + "invalid token in macro parameter list">; +def err_pp_expected_ident_in_arg_list : Error< + "expected identifier in macro parameter list">; +def err_pp_expected_comma_in_arg_list : Error< + "expected comma in macro parameter list">; +def err_pp_duplicate_name_in_arg_list : Error< + "duplicate macro parameter name %0">; +def err_pp_stringize_not_parameter : Error< + "'#' is not followed by a macro parameter">; +def err_pp_malformed_ident : Error<"invalid #ident directive">; +def err_pp_unterminated_conditional : Error< + "unterminated conditional directive">; +def pp_err_else_after_else : Error<"#else after #else">; +def pp_err_elif_after_else : Error<"#elif after #else">; +def pp_err_else_without_if : Error<"#else without #if">; +def pp_err_elif_without_if : Error<"#elif without #if">; +def err_pp_endif_without_if : Error<"#endif without #if">; +def err_pp_expected_value_in_expr : Error<"expected value in expression">; +def err_pp_expected_rparen : Error<"expected ')' in preprocessor expression">; +def err_pp_expected_eol : Error< + "expected end of line in preprocessor expression">; +def err_pp_defined_requires_identifier : Error< + "operator 'defined' requires an identifier">; +def err_pp_missing_lparen : Error<"missing '(' after '%0'">; +def err_pp_missing_rparen : Error<"missing ')' after '%0'">; +def err_pp_colon_without_question : Error<"':' without preceding '?'">; +def err_pp_division_by_zero : Error< + "division by zero in preprocessor expression">; +def err_pp_remainder_by_zero : Error< + "remainder by zero in preprocessor expression">; +def err_pp_expr_bad_token_binop : Error< + "token is not a valid binary operator in a preprocessor subexpression">; +def err_pp_expr_bad_token_start_expr : Error< + "invalid token at start of a preprocessor expression">; +def err_pp_invalid_poison : Error<"can only poison identifier tokens">; +def err_pp_used_poisoned_id : Error<"attempt to use a poisoned identifier">; + +def err_feature_check_malformed : Error< + "builtin feature check macro requires a parenthesized identifier">; + +def err_warning_check_malformed : Error< + "builtin warning check macro requires a parenthesized string">, + InGroup<MalformedWarningCheck>; +def warn_has_warning_invalid_option : + ExtWarn<"__has_warning expected option name (e.g. \"-Wundef\")">, + InGroup<MalformedWarningCheck>; + +def warn_pragma_include_alias_mismatch_angle : + ExtWarn<"angle-bracketed include <%0> cannot be aliased to double-quoted " + "include \"%1\"">, InGroup<UnknownPragmas>; +def warn_pragma_include_alias_mismatch_quote : + ExtWarn<"double-quoted include \"%0\" cannot be aliased to angle-bracketed " + "include <%1>">, InGroup<UnknownPragmas>; +def warn_pragma_include_alias_expected : + ExtWarn<"pragma include_alias expected '%0'">, + InGroup<UnknownPragmas>; +def warn_pragma_include_alias_expected_filename : + ExtWarn<"pragma include_alias expected include filename">, + InGroup<UnknownPragmas>; + +def err__Pragma_malformed : Error< + "_Pragma takes a parenthesized string literal">; +def err_pragma_comment_malformed : Error< + "pragma comment requires parenthesized identifier and optional string">; +def err_pragma_message_malformed : Error< + "pragma message requires parenthesized string">; +def err_pragma_push_pop_macro_malformed : Error< + "pragma %0 requires a parenthesized string">; +def warn_pragma_pop_macro_no_push : Warning< + "pragma pop_macro could not pop '%0', no matching push_macro">; +def warn_pragma_message : Warning<"%0">, + InGroup<PoundPragmaMessage>, DefaultWarnNoWerror; +def warn_pragma_ignored : Warning<"unknown pragma ignored">, + InGroup<UnknownPragmas>, DefaultIgnore; +def ext_stdc_pragma_ignored : ExtWarn<"unknown pragma in STDC namespace">, + InGroup<UnknownPragmas>; +def ext_on_off_switch_syntax : + ExtWarn<"expected 'ON' or 'OFF' or 'DEFAULT' in pragma">, + InGroup<UnknownPragmas>; +def ext_pragma_syntax_eod : + ExtWarn<"expected end of directive in pragma">, + InGroup<UnknownPragmas>; +def warn_stdc_fenv_access_not_supported : + Warning<"pragma STDC FENV_ACCESS ON is not supported, ignoring pragma">, + InGroup<UnknownPragmas>; +def warn_pragma_diagnostic_invalid : + ExtWarn<"pragma diagnostic expected 'error', 'warning', 'ignored', 'fatal'," + " 'push', or 'pop'">, + InGroup<UnknownPragmas>; +def warn_pragma_diagnostic_cannot_pop : + ExtWarn<"pragma diagnostic pop could not pop, no matching push">, + InGroup<UnknownPragmas>; +def warn_pragma_diagnostic_invalid_option : + ExtWarn<"pragma diagnostic expected option name (e.g. \"-Wundef\")">, + InGroup<UnknownPragmas>; +def warn_pragma_diagnostic_invalid_token : + ExtWarn<"unexpected token in pragma diagnostic">, + InGroup<UnknownPragmas>; +def warn_pragma_diagnostic_unknown_warning : + ExtWarn<"unknown warning group '%0', ignored">, + InGroup<UnknownPragmas>; +// - #pragma __debug +def warn_pragma_debug_unexpected_command : Warning< + "unexpected debug command '%0'">; + +def err_pragma_comment_unknown_kind : Error<"unknown kind of pragma comment">; +def err_defined_macro_name : Error<"'defined' cannot be used as a macro name">; +def err_paste_at_start : Error< + "'##' cannot appear at start of macro expansion">; +def err_paste_at_end : Error<"'##' cannot appear at end of macro expansion">; +def ext_paste_comma : Extension< + "Use of comma pasting extension is non-portable">; +def err_unterm_macro_invoc : Error< + "unterminated function-like macro invocation">; +def err_too_many_args_in_macro_invoc : Error< + "too many arguments provided to function-like macro invocation">; +def err_too_few_args_in_macro_invoc : Error< + "too few arguments provided to function-like macro invocation">; +def err_pp_bad_paste : Error< + "pasting formed '%0', an invalid preprocessing token">; +def err_pp_bad_paste_ms : Warning< + "pasting formed '%0', an invalid preprocessing token">, DefaultError, + InGroup<DiagGroup<"invalid-token-paste">>; +def err_pp_operator_used_as_macro_name : Error< + "C++ operator '%0' cannot be used as a macro name">; +def err_pp_illegal_floating_literal : Error< + "floating point literal in preprocessor expression">; +def err_pp_line_requires_integer : Error< + "#line directive requires a positive integer argument">; +def err_pp_line_invalid_filename : Error< + "invalid filename for #line directive">; +def warn_pp_line_decimal : Warning< + "#line directive interprets number as decimal, not octal">; +def err_pp_line_digit_sequence : Error< + "#line directive requires a simple digit sequence">; +def err_pp_linemarker_requires_integer : Error< + "line marker directive requires a positive integer argument">; +def err_pp_linemarker_invalid_filename : Error< + "invalid filename for line marker directive">; +def err_pp_linemarker_invalid_flag : Error< + "invalid flag line marker directive">; +def err_pp_linemarker_invalid_pop : Error< + "invalid line marker flag '2': cannot pop empty include stack">; +def ext_pp_line_too_big : Extension< + "C requires #line number to be less than %0, allowed as extension">; +def warn_cxx98_compat_pp_line_too_big : Warning< + "#line number greater than 32767 is incompatible with C++98">, + InGroup<CXX98CompatPedantic>, DefaultIgnore; + +def err_pp_visibility_non_macro : Error<"no macro named %0">; + +def err_pp_arc_cf_code_audited_syntax : Error<"expected 'begin' or 'end'">; +def err_pp_double_begin_of_arc_cf_code_audited : Error< + "already inside '#pragma clang arc_cf_code_audited'">; +def err_pp_unmatched_end_of_arc_cf_code_audited : Error< + "not currently inside '#pragma clang arc_cf_code_audited'">; +def err_pp_include_in_arc_cf_code_audited : Error< + "cannot #include files inside '#pragma clang arc_cf_code_audited'">; +def err_pp_eof_in_arc_cf_code_audited : Error< + "'#pragma clang arc_cf_code_audited' was not ended within this file">; + +// Module map parsing +def err_mmap_unknown_token : Error<"skipping stray token">; +def err_mmap_expected_module : Error<"expected module declaration">; +def err_mmap_expected_module_name : Error<"expected module name">; +def err_mmap_expected_lbrace : Error<"expected '{' to start module '%0'">; +def err_mmap_expected_rbrace : Error<"expected '}'">; +def note_mmap_lbrace_match : Note<"to match this '{'">; +def err_mmap_expected_rsquare : Error<"expected ']' to close attribute">; +def note_mmap_lsquare_match : Note<"to match this ']'">; +def err_mmap_expected_member : Error< + "expected umbrella, header, submodule, or module export">; +def err_mmap_expected_header : Error<"expected a header name after '%0'">; +def err_mmap_module_redefinition : Error< + "redefinition of module '%0'">; +def note_mmap_prev_definition : Note<"previously defined here">; +def err_mmap_header_conflict : Error< + "header '%0' is already part of module '%1'">; +def err_mmap_header_not_found : Error< + "%select{|umbrella }0header '%1' not found">; +def err_mmap_umbrella_dir_not_found : Error< + "umbrella directory '%0' not found">; +def err_mmap_umbrella_clash : Error< + "umbrella for module '%0' already covers this directory">; +def err_mmap_export_module_id : Error< + "expected an exported module name or '*'">; +def err_mmap_missing_module_unqualified : Error< + "no module named '%0' visible from '%1'">; +def err_mmap_missing_module_qualified : Error< + "no module named '%0' in '%1'">; +def err_mmap_top_level_inferred_submodule : Error< + "only submodules may be inferred with wildcard syntax">; +def err_mmap_inferred_no_umbrella : Error< + "inferred submodules require a module with an umbrella">; +def err_mmap_inferred_redef : Error< + "redefinition of inferred submodule">; +def err_mmap_expected_lbrace_wildcard : Error< + "expected '{' to start inferred submodule">; +def err_mmap_expected_wildcard_member : Error< + "expected module export wildcard">; +def err_mmap_expected_export_wildcard : Error< + "only '*' can be exported from an inferred submodule">; +def err_mmap_explicit_top_level : Error< + "'explicit' is not permitted on top-level modules">; +def err_mmap_nested_submodule_id : Error< + "qualified module name can only be used to define modules at the top level">; +def err_mmap_expected_feature : Error<"expected a feature name">; +def err_mmap_expected_attribute : Error<"expected an attribute name">; +def warn_mmap_unknown_attribute : Warning<"unknown attribute '%0'">, + InGroup<IgnoredAttributes>; + +def warn_auto_module_import : Warning< + "treating #%select{include|import|include_next|__include_macros}0 as an " + "import of module '%1'">, InGroup<AutoImport>, DefaultIgnore; +def warn_uncovered_module_header : Warning< + "umbrella header does not include header '%0'">, InGroup<IncompleteUmbrella>; + +} diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td new file mode 100644 index 0000000..c183da7 --- /dev/null +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -0,0 +1,718 @@ +//==--- DiagnosticParseKinds.td - libparse diagnostics --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Parser Diagnostics +//===----------------------------------------------------------------------===// + +let Component = "Parse" in { + +def w_asm_qualifier_ignored : Warning<"ignored %0 qualifier on asm">, + CatInlineAsm; +def warn_file_asm_volatile : Warning< + "meaningless 'volatile' on asm outside function">, CatInlineAsm; + +let CategoryName = "Parse Issue" in { + +def ext_empty_source_file : Extension<"ISO C forbids an empty source file">; +def ext_top_level_semi : Extension< + "extra ';' outside of a function">; +def warn_cxx98_compat_top_level_semi : Warning< + "extra ';' outside of a function is incompatible with C++98">, + InGroup<CXX98CompatPedantic>, DefaultIgnore; +def ext_extra_struct_semi : Extension< + "extra ';' inside a %0">; +def ext_extra_ivar_semi : Extension< + "extra ';' inside instance variable list">; + +def ext_duplicate_declspec : Extension<"duplicate '%0' declaration specifier">; +def ext_plain_complex : ExtWarn< + "plain '_Complex' requires a type specifier; assuming '_Complex double'">; +def ext_integer_complex : Extension< + "complex integer types are an extension">; +def ext_thread_before : Extension<"'__thread' before 'static'">; + +def ext_empty_struct_union : Extension< + "empty %select{struct|union}0 is a GNU extension">, InGroup<GNU>; +def warn_empty_struct_union_compat : Warning<"empty %select{struct|union}0 " + "has size 0 in C, size 1 in C++">, InGroup<CXXCompat>, DefaultIgnore; +def error_empty_enum : Error<"use of empty enum">; +def err_invalid_sign_spec : Error<"'%0' cannot be signed or unsigned">; +def err_invalid_short_spec : Error<"'short %0' is invalid">; +def err_invalid_long_spec : Error<"'long %0' is invalid">; +def err_invalid_longlong_spec : Error<"'long long %0' is invalid">; +def err_invalid_complex_spec : Error<"'_Complex %0' is invalid">; +def err_friend_storage_spec : Error<"'%0' is invalid in friend declarations">; + +def ext_ident_list_in_param : Extension< + "type-less parameter names in function declaration">; +def ext_c99_variable_decl_in_for_loop : Extension< + "variable declaration in for loop is a C99-specific feature">, InGroup<C99>; +def ext_c99_compound_literal : Extension< + "compound literals are a C99-specific feature">, InGroup<C99>; +def ext_c99_flexible_array_member : Extension< + "Flexible array members are a C99-specific feature">, InGroup<C99>; +def ext_enumerator_list_comma : Extension< + "commas at the end of enumerator lists are a %select{C99|C++11}0-specific " + "feature">; +def warn_cxx98_compat_enumerator_list_comma : Warning< + "commas at the end of enumerator lists are incompatible with C++98">, + InGroup<CXX98CompatPedantic>, DefaultIgnore; +def err_enumerator_list_missing_comma : Error< + "missing ',' between enumerators">; +def err_enumerator_unnamed_no_def : Error< + "unnamed enumeration must be a definition">; +def ext_ms_enum_fixed_underlying_type : Extension< + "enumeration types with a fixed underlying type are a Microsoft extension">, + InGroup<Microsoft>; +def warn_cxx98_compat_enum_fixed_underlying_type : Warning< + "enumeration types with a fixed underlying type are incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def warn_cxx98_compat_alignof : Warning< + "alignof expressions are incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; + +def warn_microsoft_dependent_exists : Warning< + "dependent %select{__if_not_exists|__if_exists}0 declarations are ignored">, + InGroup<DiagGroup<"microsoft-exists">>; + +def ext_c11_generic_selection : Extension< + "generic selections are a C11-specific feature">, InGroup<C11>; +def err_duplicate_default_assoc : Error< + "duplicate default generic association">; +def note_previous_default_assoc : Note< + "previous default generic association is here">; + +def ext_c11_alignas : Extension< + "_Alignas is a C11-specific feature">, InGroup<C11>; + +def ext_gnu_indirect_goto : Extension< + "use of GNU indirect-goto extension">, InGroup<GNU>; +def ext_gnu_address_of_label : Extension< + "use of GNU address-of-label extension">, InGroup<GNU>; +def ext_gnu_local_label : Extension< + "use of GNU locally declared label extension">, InGroup<GNU>; +def ext_gnu_statement_expr : Extension< + "use of GNU statement expression extension">, InGroup<GNU>; +def ext_gnu_conditional_expr : Extension< + "use of GNU ?: expression extension, eliding middle term">, InGroup<GNU>; +def ext_gnu_empty_initializer : Extension< + "use of GNU empty initializer extension">, InGroup<GNU>; +def ext_gnu_array_range : Extension<"use of GNU array range extension">, + InGroup<GNUDesignator>; +def ext_gnu_missing_equal_designator : ExtWarn< + "use of GNU 'missing =' extension in designator">, + InGroup<GNUDesignator>; +def err_expected_equal_designator : Error<"expected '=' or another designator">; +def ext_gnu_old_style_field_designator : ExtWarn< + "use of GNU old-style field designator extension">, + InGroup<GNUDesignator>; +def ext_gnu_case_range : Extension<"use of GNU case range extension">, + InGroup<GNU>; + +// Generic errors. +def err_expected_expression : Error<"expected expression">; +def err_expected_type : Error<"expected a type">; +def err_expected_external_declaration : Error<"expected external declaration">; +def err_extraneous_closing_brace : Error<"extraneous closing brace ('}')">; +def err_expected_ident : Error<"expected identifier">; +def err_expected_ident_lparen : Error<"expected identifier or '('">; +def err_expected_ident_lbrace : Error<"expected identifier or '{'">; +def err_expected_lbrace : Error<"expected '{'">; +def err_expected_lparen : Error<"expected '('">; +def err_expected_lparen_or_lbrace : Error<"expected '('or '{'">; +def err_expected_rparen : Error<"expected ')'">; +def err_expected_lsquare : Error<"expected '['">; +def err_expected_rsquare : Error<"expected ']'">; +def err_expected_rbrace : Error<"expected '}'">; +def err_expected_greater : Error<"expected '>'">; +def err_expected_ggg : Error<"expected '>>>'">; +def err_expected_semi_declaration : Error< + "expected ';' at end of declaration">; +def err_expected_semi_decl_list : Error< + "expected ';' at end of declaration list">; +def ext_expected_semi_decl_list : ExtWarn< + "expected ';' at end of declaration list">; +def err_expected_member_name_or_semi : Error< + "expected member name or ';' after declaration specifiers">; +def err_function_declared_typedef : Error< + "function definition declared 'typedef'">; +def err_iboutletcollection_builtintype : Error< + "type argument of iboutletcollection attribute cannot be a builtin type">; +def err_iboutletcollection_with_protocol : Error< + "invalid argument of iboutletcollection attribute">; +def err_at_defs_cxx : Error<"@defs is not supported in Objective-C++">; +def err_at_in_class : Error<"unexpected '@' in member specification">; + +def err_expected_fn_body : Error< + "expected function body after function declarator">; +def warn_attribute_on_function_definition : Warning< + "GCC does not allow %0 attribute in this position on a function definition">, + InGroup<GccCompat>; +def warn_attribute_no_decl : Warning< + "attribute %0 ignored, because it is not attached to a declaration">, + InGroup<IgnoredAttributes>; +def err_expected_method_body : Error<"expected method body">; +def err_invalid_token_after_toplevel_declarator : Error< + "expected ';' after top level declarator">; +def err_invalid_token_after_declarator_suggest_equal : Error< + "invalid '%0' at end of declaration; did you mean '='?">; +def err_expected_statement : Error<"expected statement">; +def err_expected_lparen_after : Error<"expected '(' after '%0'">; +def err_expected_lparen_after_id : Error<"expected '(' after %0">; +def err_expected_less_after : Error<"expected '<' after '%0'">; +def err_expected_equal_after : Error<"expected '=' after %0">; +def err_expected_comma : Error<"expected ','">; +def err_expected_lbrace_in_compound_literal : Error< + "expected '{' in compound literal">; +def err_expected_while : Error<"expected 'while' in do/while loop">; + +def err_expected_semi_after : Error<"expected ';' after %0">; +def err_expected_semi_after_stmt : Error<"expected ';' after %0 statement">; +def err_expected_semi_after_expr : Error<"expected ';' after expression">; +def err_extraneous_token_before_semi : Error<"extraneous '%0' before ';'">; + +def err_expected_semi_after_method_proto : Error< + "expected ';' after method prototype">; +def err_expected_semi_after_namespace_name : Error< + "expected ';' after namespace name">; +def err_unexpected_namespace_attributes_alias : Error< + "attributes can not be specified on namespace alias">; +def err_inline_namespace_alias : Error<"namespace alias cannot be inline">; +def err_namespace_nonnamespace_scope : Error< + "namespaces can only be defined in global or namespace scope">; +def err_nested_namespaces_with_double_colon : Error< + "nested namespace definition must define each namespace separately">; +def err_expected_semi_after_attribute_list : Error< + "expected ';' after attribute list">; +def err_expected_semi_after_static_assert : Error< + "expected ';' after static_assert">; +def err_expected_semi_for : Error<"expected ';' in 'for' statement specifier">; +def err_expected_colon_after : Error<"expected ':' after %0">; +def err_label_end_of_compound_statement : Error< + "label at end of compound statement: expected statement">; +def err_address_of_label_outside_fn : Error< + "use of address-of-label extension outside of a function body">; +def err_expected_string_literal : Error<"expected string literal">; +def err_asm_operand_wide_string_literal : Error< + "cannot use %select{unicode|wide}0 string literal in 'asm'">; +def err_expected_selector_for_method : Error< + "expected selector for Objective-C method">; +def err_expected_property_name : Error<"expected property name">; + +def err_unexpected_at : Error<"unexpected '@' in program">; + +def err_invalid_reference_qualifier_application : Error< + "'%0' qualifier may not be applied to a reference">; +def err_illegal_decl_reference_to_reference : Error< + "%0 declared as a reference to a reference">; +def ext_rvalue_reference : ExtWarn< + "rvalue references are a C++11 extension">, InGroup<CXX11>; +def warn_cxx98_compat_rvalue_reference : Warning< + "rvalue references are incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def ext_ref_qualifier : ExtWarn< + "reference qualifiers on functions are a C++11 extension">, InGroup<CXX11>; +def warn_cxx98_compat_ref_qualifier : Warning< + "reference qualifiers on functions are incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def ext_inline_namespace : ExtWarn< + "inline namespaces are a C++11 feature">, InGroup<CXX11>; +def warn_cxx98_compat_inline_namespace : Warning< + "inline namespaces are incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def ext_generalized_initializer_lists : ExtWarn< + "generalized initializer lists are a C++11 extension">, + InGroup<CXX11>; +def warn_cxx98_compat_generalized_initializer_lists : Warning< + "generalized initializer lists are incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def err_init_list_bin_op : Error<"initializer list cannot be used on the " + "%select{left|right}0 hand side of operator '%1'">; +def warn_cxx98_compat_trailing_return_type : Warning< + "trailing return types are incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def ext_auto_type_specifier : ExtWarn< + "'auto' type specifier is a C++11 extension">, InGroup<CXX11>; +def warn_auto_storage_class : Warning< + "'auto' storage class specifier is redundant and incompatible with C++11">, + InGroup<CXX11Compat>, DefaultIgnore; +def ext_auto_storage_class : ExtWarn< + "'auto' storage class specifier is not permitted in C++11, and will not " + "be supported in future releases">, InGroup<DiagGroup<"auto-storage-class">>; +def ext_for_range : ExtWarn< + "range-based for loop is a C++11 extension">, InGroup<CXX11>; +def warn_cxx98_compat_for_range : Warning< + "range-based for loop is incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def err_for_range_expected_decl : Error< + "for range declaration must declare a variable">; +def err_argument_required_after_attribute : Error< + "argument required after attribute">; +def err_missing_param : Error<"expected parameter declarator">; +def err_missing_comma_before_ellipsis : Error< + "C requires a comma prior to the ellipsis in a variadic function type">; +def err_unexpected_typedef_ident : Error< + "unexpected type name %0: expected identifier">; +def warn_cxx98_compat_decltype : Warning< + "'decltype' type specifier is incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def err_unexpected_scope_on_base_decltype : Error< + "unexpected namespace scope prior to decltype">; +def err_expected_class_name : Error<"expected class name">; +def err_expected_class_name_not_template : + Error<"'typename' is redundant; base classes are implicitly types">; +def err_unspecified_vla_size_with_static : Error< + "'static' may not be used with an unspecified variable length array size">; + +def err_expected_case_before_expression: Error< + "expected 'case' keyword before expression">; + +// Declarations. +def err_typename_requires_specqual : Error< + "type name requires a specifier or qualifier">; +def err_typename_invalid_storageclass : Error< + "type name does not allow storage class to be specified">; +def err_typename_invalid_functionspec : Error< + "type name does not allow function specifier to be specified">; +def err_typename_invalid_constexpr : Error< + "type name does not allow constexpr specifier to be specified">; +def err_typename_identifiers_only : Error< + "typename is allowed for identifiers only">; + +def err_invalid_decl_spec_combination : Error< + "cannot combine with previous '%0' declaration specifier">; +def err_invalid_vector_decl_spec_combination : Error< + "cannot combine with previous '%0' declaration specifier. " + "'__vector' must be first">; +def err_invalid_pixel_decl_spec_combination : Error< + "'__pixel' must be preceded by '__vector'. " + "'%0' declaration specifier not allowed here">; +def err_invalid_vector_decl_spec : Error< + "cannot use '%0' with '__vector'">; +def err_invalid_vector_bool_decl_spec : Error< + "cannot use '%0' with '__vector bool'">; +def warn_vector_long_decl_spec_combination : Warning< + "Use of 'long' with '__vector' is deprecated">, InGroup<Deprecated>; +def err_friend_invalid_in_context : Error< + "'friend' used outside of class">; +def err_unknown_typename : Error< + "unknown type name %0">; +def err_use_of_tag_name_without_tag : Error< + "must use '%1' tag to refer to type %0%select{| in this scope}2">; +def err_templated_using_directive : Error< + "cannot template a using directive">; +def err_templated_using_declaration : Error< + "cannot template a using declaration">; +def err_unexected_colon_in_nested_name_spec : Error< + "unexpected ':' in nested name specifier">; +def err_bool_redeclaration : Error< + "redeclaration of C++ built-in type 'bool'">; +def ext_c11_static_assert : Extension< + "_Static_assert is a C11-specific feature">, InGroup<C11>; +def warn_cxx98_compat_static_assert : Warning< + "static_assert declarations are incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; + +/// Objective-C parser diagnostics +def err_expected_minus_or_plus : Error< + "method type specifier must start with '-' or '+'">; +def err_objc_no_attributes_on_category : Error< + "attributes may not be specified on a category">; +def err_objc_missing_end : Error<"missing '@end'">; +def note_objc_container_start : Note< + "%select{class|protocol|category|class extension|implementation" + "|category implementation}0 started here">; +def warn_objc_protocol_qualifier_missing_id : Warning< + "protocol qualifiers without 'id' is archaic">; +def err_objc_unknown_at : Error<"expected an Objective-C directive after '@'">; +def err_illegal_super_cast : Error< + "cannot cast 'super' (it isn't an expression)">; +def err_nsnumber_nonliteral_unary : Error< + "@%0 must be followed by a number to form an NSNumber object">; + +let CategoryName = "ARC Parse Issue" in { +def err_arc_bridge_retain : Error< + "unknown cast annotation __bridge_retain; did you mean __bridge_retained?">; +// To be default mapped to an error later. +def warn_arc_bridge_cast_nonarc : Warning< + "'%0' casts have no effect when not using ARC">, + InGroup<DiagGroup<"arc-bridge-casts-disallowed-in-nonarc">>; +} + +def err_objc_illegal_visibility_spec : Error< + "illegal visibility specification">; +def err_objc_illegal_interface_qual : Error<"illegal interface qualifier">; +def err_objc_expected_equal_for_getter : Error< + "expected '=' for Objective-C getter">; +def err_objc_expected_equal_for_setter : Error< + "expected '=' for Objective-C setter">; +def err_objc_expected_selector_for_getter_setter : Error< + "expected selector for Objective-C %select{setter|getter}0">; +def err_objc_property_requires_field_name : Error< + "property requires fields to be named">; +def err_objc_property_bitfield : Error<"property name cannot be a bitfield">; +def err_objc_expected_property_attr : Error<"unknown property attribute %0">; +def err_objc_properties_require_objc2 : Error< + "properties are an Objective-C 2 feature">; +def err_objc_unexpected_attr : Error< + "prefix attribute must be followed by an interface or protocol">; +def err_objc_directive_only_in_protocol : Error< + "directive may only be specified in protocols only">; +def err_missing_catch_finally : Error< + "@try statement without a @catch and @finally clause">; +def err_objc_concat_string : Error<"unexpected token after Objective-C string">; +def err_expected_objc_container : Error< + "'@end' must appear in an Objective-C context">; +def error_property_ivar_decl : Error< + "property synthesize requires specification of an ivar">; +def err_synthesized_property_name : Error< + "expected a property name in @synthesize">; +def warn_semicolon_before_method_body : Warning< + "semicolon before method body is ignored">, + InGroup<DiagGroup<"semicolon-before-method-body">>, DefaultIgnore; + +def err_expected_field_designator : Error< + "expected a field designator, such as '.field = 4'">; + +def err_declaration_does_not_declare_param : Error< + "declaration does not declare a parameter">; +def err_no_matching_param : Error<"parameter named %0 is missing">; + +/// C++ parser diagnostics +def err_expected_unqualified_id : Error< + "expected %select{identifier|unqualified-id}0">; +def err_func_def_no_params : Error< + "function definition does not declare parameters">; +def err_expected_lparen_after_type : Error< + "expected '(' for function-style cast or type construction">; +def err_expected_init_in_condition : Error< + "variable declaration in condition must have an initializer">; +def err_expected_init_in_condition_lparen : Error< + "variable declaration in condition cannot have a parenthesized initializer">; +def warn_parens_disambiguated_as_function_decl : Warning< + "parentheses were disambiguated as a function declarator">, + InGroup<VexingParse>; +def warn_dangling_else : Warning< + "add explicit braces to avoid dangling else">, + InGroup<DanglingElse>; +def err_expected_member_or_base_name : Error< + "expected class member or base class name">; +def err_expected_lbrace_after_base_specifiers : Error< + "expected '{' after base class list">; +def ext_ellipsis_exception_spec : Extension< + "exception specification of '...' is a Microsoft extension">; +def err_dynamic_and_noexcept_specification : Error< + "cannot have both throw() and noexcept() clause on the same function">; +def warn_cxx98_compat_noexcept_decl : Warning< + "noexcept specifications are incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def err_expected_catch : Error<"expected catch">; +def err_expected_lbrace_or_comma : Error<"expected '{' or ','">; +def err_expected_rbrace_or_comma : Error<"expected '}' or ','">; +def err_expected_rsquare_or_comma : Error<"expected ']' or ','">; +def err_using_namespace_in_class : Error< + "'using namespace' is not allowed in classes">; +def err_destructor_tilde_identifier : Error< + "expected a class name after '~' to name a destructor">; +def err_destructor_template_id : Error< + "destructor name %0 does not refer to a template">; +def err_default_arg_unparsed : Error< + "unexpected end of default argument expression">; +def err_parser_impl_limit_overflow : Error< + "parser recursion limit reached, program too complex">, DefaultFatal; +def err_misplaced_ellipsis_in_declaration : Error< + "'...' must %select{immediately precede declared identifier|" + "be innermost component of anonymous pack declaration}0">; + +// C++ derived classes +def err_dup_virtual : Error<"duplicate 'virtual' in base specifier">; + +// C++ operator overloading +def err_literal_operator_string_prefix : Error< + "string literal after 'operator' cannot have an encoding prefix">; +def err_literal_operator_string_not_empty : Error< + "string literal after 'operator' must be '\"\"'">; +def err_literal_operator_missing_space : Error< + "C++11 requires a space between the \"\" and the user-defined suffix in a " + "literal operator">; +def warn_cxx98_compat_literal_operator : Warning< + "literal operators are incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; + +// Classes. +def err_anon_type_definition : Error< + "declaration of anonymous %0 must be a definition">; +def err_default_delete_in_multiple_declaration : Error< + "'= %select{default|delete}0' is a function definition and must occur in a " + "standalone declaration">; + +def warn_cxx98_compat_noexcept_expr : Warning< + "noexcept expressions are incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def warn_cxx98_compat_nullptr : Warning< + "'nullptr' is incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore; + +def warn_cxx98_compat_alignas : Warning<"'alignas' is incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def warn_cxx98_compat_attribute : Warning< + "attributes are incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def err_cxx11_attribute_forbids_arguments : Error< + "attribute '%0' cannot have an argument list">; +def err_cxx11_attribute_forbids_ellipsis : Error< + "attribute '%0' cannot be used as an attribute pack">; +def err_attributes_not_allowed : Error<"an attribute list cannot appear here">; +def err_l_square_l_square_not_attribute : Error< + "C++11 only allows consecutive left square brackets when " + "introducing an attribute">; +def err_alignas_pack_exp_unsupported : Error< + "pack expansions in alignment specifiers are not supported yet">; + +/// C++ Templates +def err_expected_template : Error<"expected template">; +def err_unknown_template_name : Error< + "unknown template name %0">; +def err_expected_comma_greater : Error< + "expected ',' or '>' in template-parameter-list">; +def err_class_on_template_template_param : Error< + "template template parameter requires 'class' after the parameter list">; +def err_template_spec_syntax_non_template : Error< + "identifier followed by '<' indicates a class template specialization but " + "%0 %select{does not refer to a template|refers to a function " + "template|<unused>|refers to a template template parameter}1">; +def err_id_after_template_in_nested_name_spec : Error< + "expected template name after 'template' keyword in nested name specifier">; +def err_two_right_angle_brackets_need_space : Error< + "a space is required between consecutive right angle brackets (use '> >')">; +def warn_cxx0x_right_shift_in_template_arg : Warning< + "use of right-shift operator ('>>') in template argument will require " + "parentheses in C++11">; +def warn_cxx98_compat_two_right_angle_brackets : Warning< + "consecutive right angle brackets are incompatible with C++98 (use '> >')">, + InGroup<CXX98Compat>, DefaultIgnore; +def err_multiple_template_declarators : Error< + "%select{|a template declaration|an explicit template specialization|" + "an explicit template instantiation}0 can " + "only %select{|declare|declare|instantiate}0 a single entity">; +def err_explicit_instantiation_with_definition : Error< + "explicit template instantiation cannot have a definition; if this " + "definition is meant to be an explicit specialization, add '<>' after the " + "'template' keyword">; +def err_enum_template : Error<"enumeration cannot be a template">; +def err_explicit_instantiation_enum : Error< + "enumerations cannot be explicitly instantiated">; +def err_expected_template_parameter : Error<"expected template parameter">; + +def err_missing_dependent_template_keyword : Error< + "use 'template' keyword to treat '%0' as a dependent template name">; +def warn_missing_dependent_template_keyword : ExtWarn< + "use 'template' keyword to treat '%0' as a dependent template name">; + +def ext_extern_template : Extension< + "extern templates are a C++11 extension">, InGroup<CXX11>; +def warn_cxx98_compat_extern_template : Warning< + "extern templates are incompatible with C++98">, + InGroup<CXX98CompatPedantic>, DefaultIgnore; +def warn_static_inline_explicit_inst_ignored : Warning< + "ignoring '%select{static|inline}0' keyword on explicit template " + "instantiation">; + +// Constructor template diagnostics. +def err_out_of_line_constructor_template_id : Error< + "out-of-line constructor for %0 cannot have template arguments">; +def err_out_of_line_template_id_names_constructor : Error< + "qualified reference to %0 is a constructor name rather than a " + "template name wherever a constructor can be declared">; +def err_out_of_line_type_names_constructor : Error< + "qualified reference to %0 is a constructor name rather than a " + "type wherever a constructor can be declared">; + +def err_expected_qualified_after_typename : Error< + "expected a qualified name after 'typename'">; +def warn_expected_qualified_after_typename : ExtWarn< + "expected a qualified name after 'typename'">; +def err_expected_semi_after_tagdecl : Error< + "expected ';' after %0">; + +def err_typename_refers_to_non_type_template : Error< + "typename specifier refers to a non-template">; +def err_expected_type_name_after_typename : Error< + "expected an identifier or template-id after '::'">; +def err_explicit_spec_non_template : Error< + "explicit %select{specialization|instantiation}0 of non-template " + "%select{class|struct|union}1 %2">; + +def err_default_template_template_parameter_not_template : Error< + "default template argument for a template template parameter must be a class " + "template">; + +def err_ctor_init_missing_comma : Error< + "missing ',' between base or member initializers">; + +// C++ declarations +def err_friend_decl_defines_type : Error< + "cannot define a type in a friend declaration">; +def err_missing_whitespace_digraph : Error< + "found '<::' after a " + "%select{template name|const_cast|dynamic_cast|reinterpret_cast|static_cast}0" + " which forms the digraph '<:' (aka '[') and a ':', did you mean '< ::'?">; + +def ext_deleted_function : ExtWarn< + "deleted function definitions are a C++11 extension">, InGroup<CXX11>; +def warn_cxx98_compat_deleted_function : Warning< + "deleted function definitions are incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def ext_defaulted_function : ExtWarn< + "defaulted function definitions are a C++11 extension">, InGroup<CXX11>; +def warn_cxx98_compat_defaulted_function : Warning< + "defaulted function definitions are incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; + +// C++11 in-class member initialization +def ext_nonstatic_member_init : ExtWarn< + "in-class initialization of non-static data member is a C++11 extension">, + InGroup<CXX11>; +def warn_cxx98_compat_nonstatic_member_init : Warning< + "in-class initialization of non-static data members is incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def err_bitfield_member_init: Error< + "bitfield member cannot have an in-class initializer">; +def err_incomplete_array_member_init: Error< + "array bound cannot be deduced from an in-class initializer">; + +// C++11 alias-declaration +def ext_alias_declaration : ExtWarn< + "alias declarations are a C++11 extension">, InGroup<CXX11>; +def warn_cxx98_compat_alias_declaration : Warning< + "alias declarations are incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def err_alias_declaration_not_identifier : Error< + "name defined in alias declaration must be an identifier">; +def err_alias_declaration_specialization : Error< + "%select{partial specialization|explicit specialization|explicit instantiation}0 of alias templates is not permitted">; + +// C++11 override control +def ext_override_control_keyword : ExtWarn< + "'%0' keyword is a C++11 extension">, InGroup<CXX11>; +def warn_cxx98_compat_override_control_keyword : Warning< + "'%0' keyword is incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; + +def err_duplicate_virt_specifier : Error< + "class member already marked '%0'">; + +def err_scoped_enum_missing_identifier : Error< + "scoped enumeration requires a name">; +def warn_cxx98_compat_scoped_enum : Warning< + "scoped enumerations are incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; + +def err_expected_parameter_pack : Error< + "expected the name of a parameter pack">; +def err_paren_sizeof_parameter_pack : Error< + "missing parentheses around the size of parameter pack %0">; +def err_sizeof_parameter_pack : Error< + "expected parenthesized parameter pack name in 'sizeof...' expression">; + +// C++11 lambda expressions +def err_expected_comma_or_rsquare : Error< + "expected ',' or ']' in lambda capture list">; +def err_this_captured_by_reference : Error< + "'this' cannot be captured by reference">; +def err_expected_capture : Error< + "expected variable name or 'this' in lambda capture list">; +def err_expected_lambda_body : Error<"expected body of lambda expression">; +def warn_cxx98_compat_lambda : Warning< + "lambda expressions are incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def err_lambda_missing_parens : Error< + "lambda requires '()' before %select{'mutable'|return type}0">; + +// Availability attribute +def err_expected_version : Error< + "expected a version of the form 'major[.minor[.subminor]]'">; +def err_zero_version : Error< + "version number must have non-zero major, minor, or sub-minor version">; +def err_availability_expected_platform : Error< + "expected a platform name, e.g., 'macosx'">; +def err_availability_expected_change : Error< + "expected 'introduced', 'deprecated', or 'obsoleted'">; +def err_availability_unknown_change : Error< + "%0 is not an availability stage; use 'introduced', 'deprecated', or " + "'obsoleted'">; +def err_availability_redundant : Error< + "redundant %0 availability change; only the last specified change will " "be used">; +def warn_availability_and_unavailable : Warning< + "'unavailable' availability overrides all other availability information">; + +// Language specific pragmas +// - Generic warnings +def warn_pragma_expected_lparen : Warning< + "missing '(' after '#pragma %0' - ignoring">; +def warn_pragma_expected_rparen : Warning< + "missing ')' after '#pragma %0' - ignoring">; +def warn_pragma_expected_identifier : Warning< + "expected identifier in '#pragma %0' - ignored">; +def warn_pragma_ms_struct : Warning< + "incorrect use of '#pragma ms_struct on|off' - ignored">; +def warn_pragma_extra_tokens_at_eol : Warning< + "extra tokens at end of '#pragma %0' - ignored">; +// - #pragma options +def warn_pragma_options_expected_align : Warning< + "expected 'align' following '#pragma options' - ignored">; +def warn_pragma_align_expected_equal : Warning< + "expected '=' following '#pragma %select{align|options align}0' - ignored">; +def warn_pragma_align_invalid_option : Warning< + "invalid alignment option in '#pragma %select{align|options align}0' - ignored">; +// - #pragma pack +def warn_pragma_pack_invalid_action : Warning< + "unknown action for '#pragma pack' - ignored">; +def warn_pragma_pack_malformed : Warning< + "expected integer or identifier in '#pragma pack' - ignored">; +// - #pragma unused +def warn_pragma_unused_expected_var : Warning< + "expected '#pragma unused' argument to be a variable name">; +def warn_pragma_unused_expected_punc : Warning< + "expected ')' or ',' in '#pragma unused'">; + +// OpenCL Section 6.8.g +def err_not_opencl_storage_class_specifier : Error< + "OpenCL does not support the '%0' storage class specifier">; + +// OpenCL EXTENSION pragma (OpenCL 1.1 [9.1]) +def warn_pragma_expected_colon : Warning< + "missing ':' after %0 - ignoring">; +def warn_pragma_expected_enable_disable : Warning< + "expected 'enable' or 'disable' - ignoring">; +def warn_pragma_unknown_extension : Warning< + "unknown OpenCL extension %0 - ignoring">; + +def err_seh_expected_handler : Error< + "expected '__except' or '__finally' block">; + +def err_seh___except_block : Error< + "%0 only allowed in __except block">; + +def err_seh___except_filter : Error< + "%0 only allowed in __except filter expression">; + +def err_seh___finally_block : Error< + "%0 only allowed in __finally block">; + +} // end of Parse Issue category. + +let CategoryName = "Modules Issue" in { +def err_module_expected_ident : Error< + "expected a module name after module import">; +def err_module_expected_semi : Error< + "expected a semicolon name after module name">; +} + +} // end of Parser diagnostics diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td new file mode 100644 index 0000000..0614ade --- /dev/null +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -0,0 +1,5498 @@ +//==--- DiagnosticSemaKinds.td - libsema diagnostics ----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Semantic Analysis +//===----------------------------------------------------------------------===// + +let Component = "Sema" in { +let CategoryName = "Semantic Issue" in { + +// Constant expressions +def err_expr_not_ice : Error< + "expression is not an %select{integer|integral}0 constant expression">; +def ext_expr_not_ice : Extension< + "expression is not an %select{integer|integral}0 constant expression; " + "folding it to a constant is a GNU extension">, InGroup<GNU>; +def err_typecheck_converted_constant_expression : Error< + "value of type %0 is not implicitly convertible to %1">; +def err_typecheck_converted_constant_expression_disallowed : Error< + "conversion from %0 to %1 is not allowed in a converted constant expression">; +def err_expr_not_cce : Error< + "%select{case value|enumerator value|non-type template argument}0 " + "is not a constant expression">; +def err_cce_narrowing : ExtWarn< + "%select{case value|enumerator value|non-type template argument}0 " + "%select{cannot be narrowed from type %2 to %3|" + "evaluates to %2, which cannot be narrowed to type %3}1">, + InGroup<CXX11Narrowing>, DefaultError; +def err_cce_narrowing_sfinae : Error< + "%select{case value|enumerator value|non-type template argument}0 " + "%select{cannot be narrowed from type %2 to %3|" + "evaluates to %2, which cannot be narrowed to type %3}1">; +def err_ice_not_integral : Error< + "integral constant expression must have integral or unscoped enumeration " + "type, not %0">; +def err_ice_incomplete_type : Error< + "integral constant expression has incomplete class type %0">; +def err_ice_explicit_conversion : Error< + "integral constant expression requires explicit conversion from %0 to %1">; +def note_ice_conversion_here : Note< + "conversion to %select{integral|enumeration}0 type %1 declared here">; +def err_ice_ambiguous_conversion : Error< + "ambiguous conversion from type %0 to an integral or unscoped " + "enumeration type">; + +// Semantic analysis of constant literals. +def ext_predef_outside_function : Warning< + "predefined identifier is only valid inside function">, + InGroup<DiagGroup<"predefined-identifier-outside-function">>; +def warn_float_overflow : Warning< + "magnitude of floating-point constant too large for type %0; maximum is %1">, + InGroup<LiteralRange>; +def warn_float_underflow : Warning< + "magnitude of floating-point constant too small for type %0; minimum is %1">, + InGroup<LiteralRange>; +def warn_double_const_requires_fp64 : Warning< + "double precision constant requires cl_khr_fp64, casting to single precision">; + +// C99 variable-length arrays +def ext_vla : Extension<"variable length arrays are a C99 feature">, + InGroup<VLA>; +def err_vla_non_pod : Error<"variable length array of non-POD element type %0">; +def err_vla_in_sfinae : Error< + "variable length array cannot be formed during template argument deduction">; +def err_array_star_in_function_definition : Error< + "variable length array must be bound in function definition">; +def err_vla_decl_in_file_scope : Error< + "variable length array declaration not allowed at file scope">; +def err_vla_decl_has_static_storage : Error< + "variable length array declaration can not have 'static' storage duration">; +def err_vla_decl_has_extern_linkage : Error< + "variable length array declaration can not have 'extern' linkage">; +def ext_vla_folded_to_constant : Extension< + "variable length array folded to constant array as an extension">; + +// C99 variably modified types +def err_variably_modified_template_arg : Error< + "variably modified type %0 cannot be used as a template argument">; +def err_variably_modified_nontype_template_param : Error< + "non-type template parameter of variably modified type %0">; +def err_variably_modified_new_type : Error< + "'new' cannot allocate object of variably modified type %0">; + +// C99 Designated Initializers +def ext_designated_init : Extension< + "designated initializers are a C99 feature">; +def err_array_designator_negative : Error< + "array designator value '%0' is negative">; +def err_array_designator_empty_range : Error< + "array designator range [%0, %1] is empty">; +def err_array_designator_non_array : Error< + "array designator cannot initialize non-array type %0">; +def err_array_designator_too_large : Error< + "array designator index (%0) exceeds array bounds (%1)">; +def err_field_designator_non_aggr : Error< + "field designator cannot initialize a " + "%select{non-struct, non-union|non-class}0 type %1">; +def err_field_designator_unknown : Error< + "field designator %0 does not refer to any field in type %1">; +def err_field_designator_nonfield : Error< + "field designator %0 does not refer to a non-static data member">; +def note_field_designator_found : Note<"field designator refers here">; +def err_designator_for_scalar_init : Error< + "designator in initializer for scalar type %0">; +def warn_subobject_initializer_overrides : Warning< + "subobject initialization overrides initialization of other fields " + "within its enclosing subobject">, InGroup<InitializerOverrides>; +def warn_initializer_overrides : Warning< + "initializer overrides prior initialization of this subobject">, + InGroup<InitializerOverrides>; +def note_previous_initializer : Note< + "previous initialization %select{|with side effects }0is here" + "%select{| (side effects may not occur at run time)}0">; +def err_designator_into_flexible_array_member : Error< + "designator into flexible array member subobject">; +def note_flexible_array_member : Note< + "initialized flexible array member %0 is here">; +def ext_flexible_array_init : Extension< + "flexible array initialization is a GNU extension">, InGroup<GNU>; + +// Declarations. +def err_bad_variable_name : Error< + "%0 cannot be the name of a variable or data member">; +def err_bad_parameter_name : Error< + "'%0' cannot be the name of a parameter">; +def err_parameter_name_omitted : Error<"parameter name omitted">; +def warn_unused_parameter : Warning<"unused parameter %0">, + InGroup<UnusedParameter>, DefaultIgnore; +def warn_unused_variable : Warning<"unused variable %0">, + InGroup<UnusedVariable>, DefaultIgnore; +def warn_unused_exception_param : Warning<"unused exception parameter %0">, + InGroup<UnusedExceptionParameter>, DefaultIgnore; +def warn_decl_in_param_list : Warning< + "declaration of %0 will not be visible outside of this function">, + InGroup<Visibility>; +def warn_redefinition_in_param_list : Warning< + "redefinition of %0 will not be visible outside of this function">, + InGroup<Visibility>; +def warn_empty_parens_are_function_decl : Warning< + "empty parentheses interpreted as a function declaration">, + InGroup<VexingParse>; +def note_empty_parens_function_call : Note< + "change this ',' to a ';' to call %0">; +def note_empty_parens_default_ctor : Note< + "remove parentheses to declare a variable">; +def note_empty_parens_zero_initialize : Note< + "replace parentheses with an initializer to declare a variable">; +def warn_unused_function : Warning<"unused function %0">, + InGroup<UnusedFunction>, DefaultIgnore; +def warn_unused_member_function : Warning<"unused member function %0">, + InGroup<UnusedMemberFunction>, DefaultIgnore; +def warn_used_but_marked_unused: Warning<"%0 was marked unused but was used">, + InGroup<UsedButMarkedUnused>, DefaultIgnore; +def warn_unneeded_internal_decl : Warning< + "%select{function|variable}0 %1 is not needed and will not be emitted">, + InGroup<UnneededInternalDecl>, DefaultIgnore; +def warn_unneeded_member_function : Warning< + "member function %0 is not needed and will not be emitted">, + InGroup<UnneededMemberFunction>, DefaultIgnore; + +def warn_parameter_size: Warning< + "%0 is a large (%1 bytes) pass-by-value argument; " + "pass it by reference instead ?">, InGroup<LargeByValueCopy>; +def warn_return_value_size: Warning< + "return value of %0 is a large (%1 bytes) pass-by-value object; " + "pass it by reference instead ?">, InGroup<LargeByValueCopy>; +def warn_return_value_udt: Warning< + "%0 has C-linkage specified, but returns user-defined type %1 which is " + "incompatible with C">, InGroup<ReturnTypeCLinkage>; +def warn_implicit_function_decl : Warning< + "implicit declaration of function %0">, + InGroup<ImplicitFunctionDeclare>, DefaultIgnore; +def ext_implicit_function_decl : ExtWarn< + "implicit declaration of function %0 is invalid in C99">, + InGroup<ImplicitFunctionDeclare>; +def note_function_suggestion : Note<"did you mean %0?">; + +def err_ellipsis_first_arg : Error< + "ISO C requires a named argument before '...'">; +def err_declarator_need_ident : Error<"declarator requires an identifier">; +def err_bad_language : Error<"unknown linkage language">; +def warn_use_out_of_scope_declaration : Warning< + "use of out-of-scope declaration of %0">; +def err_inline_non_function : Error< + "'inline' can only appear on functions">; +def warn_qual_return_type : Warning< + "'%0' type qualifier%s1 on return type %plural{1:has|:have}1 no effect">, + InGroup<IgnoredQualifiers>, DefaultIgnore; + +def warn_decl_shadow : + Warning<"declaration shadows a %select{" + "local variable|" + "variable in %2|" + "static data member of %2|" + "field of %2}1">, + InGroup<Shadow>, DefaultIgnore; + +// C++ using declarations +def err_using_requires_qualname : Error< + "using declaration requires a qualified name">; +def err_using_typename_non_type : Error< + "'typename' keyword used on a non-type">; +def err_using_dependent_value_is_type : Error< + "dependent using declaration resolved to type without 'typename'">; +def err_using_decl_nested_name_specifier_is_not_class : Error< + "using declaration in class refers into '%0', which is not a class">; +def err_using_decl_nested_name_specifier_is_current_class : Error< + "using declaration refers to its own class">; +def err_using_decl_nested_name_specifier_is_not_base_class : Error< + "using declaration refers into '%0', which is not a base class of %1">; +def err_using_decl_constructor_not_in_direct_base : Error< + "%0 is not a direct base of %1, can not inherit constructors">; +def err_using_decl_constructor_conflict : Error< + "can not inherit constructor, already inherited constructor with " + "the same signature">; +def note_using_decl_constructor_conflict_current_ctor : Note< + "conflicting constructor">; +def note_using_decl_constructor_conflict_previous_ctor : Note< + "previous constructor">; +def note_using_decl_constructor_conflict_previous_using : Note< + "previously inherited here">; +def err_using_decl_can_not_refer_to_class_member : Error< + "using declaration can not refer to class member">; +def err_using_decl_can_not_refer_to_namespace : Error< + "using declaration can not refer to namespace">; +def err_using_decl_constructor : Error< + "using declaration can not refer to a constructor">; +def err_using_decl_constructor_unsupported : Error< + "inheriting constructors are not supported">; +// FIXME: Replace the above error with this warning if support for +// inheriting constructors is implemented. +//def warn_cxx98_compat_using_decl_constructor : Warning< +// "inheriting constructors are incompatible with C++98">, +// InGroup<CXX98Compat>, DefaultIgnore; +def err_using_decl_destructor : Error< + "using declaration can not refer to a destructor">; +def err_using_decl_template_id : Error< + "using declaration can not refer to a template specialization">; +def note_using_decl_target : Note<"target of using declaration">; +def note_using_decl_conflict : Note<"conflicting declaration">; +def err_using_decl_redeclaration : Error<"redeclaration of using decl">; +def err_using_decl_conflict : Error< + "target of using declaration conflicts with declaration already in scope">; +def err_using_decl_conflict_reverse : Error< + "declaration conflicts with target of using declaration already in scope">; +def note_using_decl : Note<"%select{|previous }0using declaration">; + +def warn_access_decl_deprecated : Warning< + "access declarations are deprecated; use using declarations instead">, + InGroup<Deprecated>; + +def warn_global_constructor : Warning< + "declaration requires a global constructor">, + InGroup<GlobalConstructors>, DefaultIgnore; +def warn_global_destructor : Warning< + "declaration requires a global destructor">, + InGroup<GlobalConstructors>, DefaultIgnore; +def warn_exit_time_destructor : Warning< + "declaration requires an exit-time destructor">, + InGroup<ExitTimeDestructors>, DefaultIgnore; + +def err_invalid_thread : Error< + "'__thread' is only allowed on variable declarations">; +def err_thread_non_global : Error< + "'__thread' variables must have global storage">; +def err_thread_unsupported : Error< + "thread-local storage is unsupported for the current target">; + +def warn_maybe_falloff_nonvoid_function : Warning< + "control may reach end of non-void function">, + InGroup<ReturnType>; +def warn_falloff_nonvoid_function : Warning< + "control reaches end of non-void function">, + InGroup<ReturnType>; +def err_maybe_falloff_nonvoid_block : Error< + "control may reach end of non-void block">; +def err_falloff_nonvoid_block : Error< + "control reaches end of non-void block">; +def warn_suggest_noreturn_function : Warning< + "%select{function|method}0 %1 could be declared with attribute 'noreturn'">, + InGroup<DiagGroup<"missing-noreturn">>, DefaultIgnore; +def warn_suggest_noreturn_block : Warning< + "block could be declared with attribute 'noreturn'">, + InGroup<DiagGroup<"missing-noreturn">>, DefaultIgnore; +def warn_unreachable : Warning<"will never be executed">, + InGroup<DiagGroup<"unreachable-code">>, DefaultIgnore; + +/// Built-in functions. +def ext_implicit_lib_function_decl : ExtWarn< + "implicitly declaring library function '%0' with type %1">; +def note_please_include_header : Note< + "please include the header <%0> or explicitly provide a " + "declaration for '%1'">; +def note_previous_builtin_declaration : Note<"%0 is a builtin with type %1">; +def warn_implicit_decl_requires_stdio : Warning< + "declaration of built-in function '%0' requires inclusion of the header " + "<stdio.h>">, + InGroup<BuiltinRequiresHeader>; +def warn_implicit_decl_requires_setjmp : Warning< + "declaration of built-in function '%0' requires inclusion of the header " + "<setjmp.h>">, + InGroup<BuiltinRequiresHeader>; +def warn_implicit_decl_requires_ucontext : Warning< + "declaration of built-in function '%0' requires inclusion of the header " + "<ucontext.h>">, + InGroup<BuiltinRequiresHeader>; +def warn_redecl_library_builtin : Warning< + "incompatible redeclaration of library function %0">; +def err_builtin_definition : Error<"definition of builtin function %0">; +def err_types_compatible_p_in_cplusplus : Error< + "__builtin_types_compatible_p is not valid in C++">; +def warn_builtin_unknown : Warning<"use of unknown builtin %0">, + InGroup<ImplicitFunctionDeclare>, DefaultError; +def warn_dyn_class_memaccess : Warning< + "%select{destination for|source of|first operand of|second operand of}0 this " + "%1 call is a pointer to dynamic class %2; vtable pointer will be " + "%select{overwritten|copied|moved|compared}3">, + InGroup<DiagGroup<"dynamic-class-memaccess">>; +def note_bad_memaccess_silence : Note< + "explicitly cast the pointer to silence this warning">; +def warn_sizeof_pointer_expr_memaccess : Warning< + "argument to 'sizeof' in %0 call is the same expression as the " + "%select{destination|source}1; did you mean to " + "%select{dereference it|remove the addressof|provide an explicit length}2?">, + InGroup<DiagGroup<"sizeof-pointer-memaccess">>; +def warn_sizeof_pointer_type_memaccess : Warning< + "argument to 'sizeof' in %0 call is the same pointer type %1 as the " + "%select{destination|source}2; expected %3 or an explicit length">, + InGroup<DiagGroup<"sizeof-pointer-memaccess">>; +def warn_strlcpycat_wrong_size : Warning< + "size argument in %0 call appears to be size of the source; expected the size of " + "the destination">, + InGroup<DiagGroup<"strlcpy-strlcat-size">>; +def note_strlcpycat_wrong_size : Note< + "change size argument to be the size of the destination">; + +def warn_strncat_large_size : Warning< + "the value of the size argument in 'strncat' is too large, might lead to a " + "buffer overflow">, InGroup<StrncatSize>, DefaultIgnore; +def warn_strncat_src_size : Warning<"size argument in 'strncat' call appears " + "to be size of the source">, InGroup<StrncatSize>, DefaultIgnore; +def note_strncat_wrong_size : Note< + "change the argument to be the free space in the destination buffer minus " + "the terminating null byte">; + +/// main() +// static/inline main() are not errors in C, just in C++. +def warn_static_main : Warning<"'main' should not be declared static">, + InGroup<Main>; +def err_static_main : Error<"'main' is not allowed to be declared static">; +def err_inline_main : Error<"'main' is not allowed to be declared inline">; +def err_constexpr_main : Error< + "'main' is not allowed to be declared constexpr">; +def err_main_template_decl : Error<"'main' cannot be a template">; +def err_main_returns_nonint : Error<"'main' must return 'int'">; +def ext_main_returns_nonint : ExtWarn<"return type of 'main' is not 'int'">, + InGroup<MainReturnType>; +def err_main_surplus_args : Error<"too many parameters (%0) for 'main': " + "must be 0, 2, or 3">; +def warn_main_one_arg : Warning<"only one parameter on 'main' declaration">, + InGroup<Main>; +def err_main_arg_wrong : Error<"%select{first|second|third|fourth}0 " + "parameter of 'main' (%select{argument count|argument array|environment|" + "platform-specific data}0) must be of type %1">; + +/// parser diagnostics +def ext_typedef_without_a_name : ExtWarn<"typedef requires a name">, + InGroup<MissingDeclarations>; +def err_typedef_not_identifier : Error<"typedef name must be an identifier">; +def err_statically_allocated_object : Error< + "interface type cannot be statically allocated">; +def err_object_cannot_be_passed_returned_by_value : Error< + "interface type %1 cannot be %select{returned|passed}0 by value" + "; did you forget * in %1">; +def err_parameters_retval_cannot_have_fp16_type : Error< + "%select{parameters|function return value}0 cannot have __fp16 type; did you forget * ?">; +def warn_enum_value_overflow : Warning<"overflow in enumeration value">; +def warn_pragma_options_align_unsupported_option : Warning< + "unsupported alignment option in '#pragma options align'">; +def warn_pragma_options_align_reset_failed : Warning< + "#pragma options align=reset failed: %0">; +def err_pragma_options_align_mac68k_target_unsupported : Error< + "mac68k alignment pragma is not supported on this target">; +def warn_pragma_pack_invalid_alignment : Warning< + "expected #pragma pack parameter to be '1', '2', '4', '8', or '16'">; +// Follow the MSVC implementation. +def warn_pragma_pack_show : Warning<"value of #pragma pack(show) == %0">; +def warn_pragma_pack_pop_identifer_and_alignment : Warning< + "specifying both a name and alignment to 'pop' is undefined">; +def warn_pragma_pack_pop_failed : Warning<"#pragma pack(pop, ...) failed: %0">; + +def warn_pragma_unused_undeclared_var : Warning< + "undeclared variable %0 used as an argument for '#pragma unused'">; +def warn_pragma_unused_expected_var_arg : Warning< + "only variables can be arguments to '#pragma unused'">; +def err_pragma_push_visibility_mismatch : Error< + "#pragma visibility push with no matching #pragma visibility pop">; +def note_surrounding_namespace_ends_here : Note< + "surrounding namespace with visibility attribute ends here">; +def err_pragma_pop_visibility_mismatch : Error< + "#pragma visibility pop with no matching #pragma visibility push">; +def note_surrounding_namespace_starts_here : Note< + "surrounding namespace with visibility attribute starts here">; + +/// Objective-C parser diagnostics +def err_duplicate_class_def : Error< + "duplicate interface definition for class %0">; +def err_undef_superclass : Error< + "cannot find interface declaration for %0, superclass of %1">; +def err_forward_superclass : Error< + "attempting to use the forward class %0 as superclass of %1">; +def err_no_nsconstant_string_class : Error< + "cannot find interface declaration for %0">; +def err_recursive_superclass : Error< + "trying to recursively use %0 as superclass of %1">; +def warn_previous_alias_decl : Warning<"previously declared alias is ignored">; +def err_conflicting_aliasing_type : Error<"conflicting types for alias %0">; +def warn_undef_interface : Warning<"cannot find interface declaration for %0">; +def warn_duplicate_protocol_def : Warning<"duplicate protocol definition of %0 is ignored">; +def err_protocol_has_circular_dependency : Error< + "protocol has circular dependency">; +def err_undeclared_protocol : Error<"cannot find protocol declaration for %0">; +def warn_undef_protocolref : Warning<"cannot find protocol definition for %0">; +def warn_readonly_property : Warning< + "attribute 'readonly' of property %0 restricts attribute " + "'readwrite' of property inherited from %1">; + +def warn_property_attribute : Warning< + "property %0 '%1' attribute does not match the property inherited from %2">; +def warn_property_types_are_incompatible : Warning< + "property type %0 is incompatible with type %1 inherited from %2">; +def err_undef_interface : Error<"cannot find interface declaration for %0">; +def err_category_forward_interface : Error< + "cannot define %select{category|class extension}0 for undefined class %1">; +def err_class_extension_after_impl : Error< + "cannot declare class extension for %0 after class implementation">; +def note_implementation_declared : Note< + "class implementation is declared here">; +def note_class_declared : Note< + "class is declared here">; +def note_receiver_is_id : Note< + "receiver is treated with 'id' type for purpose of method lookup">; +def note_suppressed_class_declare : Note< + "class with specified objc_requires_property_definitions attribute is declared here">; +def err_objc_root_class_subclass : Error< + "objc_root_class attribute may only be specified on a root class declaration">; +def warn_objc_root_class_missing : Warning< + "class %0 defined without specifying a base class">, + InGroup<ObjCRootClass>, DefaultIgnore; +def note_objc_needs_superclass : Note< + "add a super class to fix this problem">; +def warn_dup_category_def : Warning< + "duplicate definition of category %1 on interface %0">; +def err_conflicting_super_class : Error<"conflicting super class name %0">; +def err_dup_implementation_class : Error<"reimplementation of class %0">; +def err_dup_implementation_category : Error< + "reimplementation of category %1 for class %0">; +def err_conflicting_ivar_type : Error< + "instance variable %0 has conflicting type: %1 vs %2">; +def err_duplicate_ivar_declaration : Error< + "instance variable is already declared">; +def warn_on_superclass_use : Warning< + "class implementation may not have super class">; +def err_conflicting_ivar_bitwidth : Error< + "instance variable %0 has conflicting bit-field width">; +def err_conflicting_ivar_name : Error< + "conflicting instance variable names: %0 vs %1">; +def err_inconsistant_ivar_count : Error< + "inconsistent number of instance variables specified">; +def warn_incomplete_impl : Warning<"incomplete implementation">, + InGroup<DiagGroup<"incomplete-implementation">>; +def note_undef_method_impl : Note<"method definition for %0 not found">; +def note_required_for_protocol_at : + Note<"required for direct or indirect protocol %0">; + +def warn_conflicting_overriding_ret_types : Warning< + "conflicting return type in " + "declaration of %0: %1 vs %2">, + InGroup<OverridingMethodMismatch>, DefaultIgnore; + +def warn_conflicting_ret_types : Warning< + "conflicting return type in " + "implementation of %0: %1 vs %2">; + +def warn_conflicting_overriding_ret_type_modifiers : Warning< + "conflicting distributed object modifiers on return type " + "in declaration of %0">, + InGroup<OverridingMethodMismatch>, DefaultIgnore; + +def warn_conflicting_ret_type_modifiers : Warning< + "conflicting distributed object modifiers on return type " + "in implementation of %0">, + InGroup<DiagGroup<"distributed-object-modifiers">>; + +def warn_non_covariant_overriding_ret_types : Warning< + "conflicting return type in " + "declaration of %0: %1 vs %2">, + InGroup<OverridingMethodMismatch>, DefaultIgnore; + +def warn_non_covariant_ret_types : Warning< + "conflicting return type in " + "implementation of %0: %1 vs %2">, + InGroup<DiagGroup<"method-signatures">>, DefaultIgnore; + +def warn_conflicting_overriding_param_types : Warning< + "conflicting parameter types in " + "declaration of %0: %1 vs %2">, + InGroup<OverridingMethodMismatch>, DefaultIgnore; + +def warn_conflicting_param_types : Warning< + "conflicting parameter types in " + "implementation of %0: %1 vs %2">; +def warn_conflicting_param_modifiers : Warning< + "conflicting distributed object modifiers on parameter type " + "in implementation of %0">, + InGroup<DiagGroup<"distributed-object-modifiers">>; + +def warn_conflicting_overriding_param_modifiers : Warning< + "conflicting distributed object modifiers on parameter type " + "in declaration of %0">, + InGroup<OverridingMethodMismatch>, DefaultIgnore; + +def warn_non_contravariant_overriding_param_types : Warning< + "conflicting parameter types in " + "declaration of %0: %1 vs %2">, + InGroup<OverridingMethodMismatch>, DefaultIgnore; + +def warn_non_contravariant_param_types : Warning< + "conflicting parameter types in " + "implementation of %0: %1 vs %2">, + InGroup<DiagGroup<"method-signatures">>, DefaultIgnore; + +def warn_conflicting_overriding_variadic :Warning< + "conflicting variadic declaration of method and its " + "implementation">, + InGroup<OverridingMethodMismatch>, DefaultIgnore; + +def warn_conflicting_variadic :Warning< + "conflicting variadic declaration of method and its " + "implementation">; + +def warn_category_method_impl_match:Warning< + "category is implementing a method which will also be implemented" + " by its primary class">, InGroup<ObjCProtocolMethodImpl>; + +def warn_implements_nscopying : Warning< +"default assign attribute on property %0 which implements " +"NSCopying protocol is not appropriate with -fobjc-gc[-only]">; + +def warn_multiple_method_decl : Warning<"multiple methods named %0 found">; +def warn_strict_multiple_method_decl : Warning< + "multiple methods named %0 found">, InGroup<StrictSelector>, DefaultIgnore; +def warn_accessor_property_type_mismatch : Warning< + "type of property %0 does not match type of accessor %1">; +def not_conv_function_declared_at : Note<"type conversion function declared here">; +def note_method_declared_at : Note<"method %0 declared here">; +def err_setter_type_void : Error<"type of setter must be void">; +def err_duplicate_method_decl : Error<"duplicate declaration of method %0">; +def warn_duplicate_method_decl : + Warning<"multiple declarations of method %0 found and ignored">, + InGroup<MethodDuplicate>, DefaultIgnore; +def err_objc_var_decl_inclass : + Error<"cannot declare variable inside @interface or @protocol">; +def error_missing_method_context : Error< + "missing context for method declaration">; +def err_objc_property_attr_mutually_exclusive : Error< + "property attributes '%0' and '%1' are mutually exclusive">; +def err_objc_property_requires_object : Error< + "property with '%0' attribute must be of object type">; +def warn_objc_property_no_assignment_attribute : Warning< + "no 'assign', 'retain', or 'copy' attribute is specified - " + "'assign' is assumed">; +def warn_objc_isa_use : Warning< + "direct access to objective-c's isa is deprecated " + "in favor of object_setClass() and object_getClass()">, + InGroup<DiagGroup<"deprecated-objc-isa-usage">>; +def warn_objc_property_default_assign_on_object : Warning< + "default property attribute 'assign' not appropriate for non-gc object">; +def warn_property_attr_mismatch : Warning< + "property attribute in continuation class does not match the primary class">; +def warn_objc_property_copy_missing_on_block : Warning< + "'copy' attribute must be specified for the block property " + "when -fobjc-gc-only is specified">; +def warn_objc_property_retain_of_block : Warning< + "retain'ed block property does not copy the block " + "- use copy attribute instead">, InGroup<ObjCRetainBlockProperty>; +def warn_objc_readonly_property_has_setter : Warning< + "setter cannot be specified for a readonly property">, + InGroup<ObjCReadonlyPropertyHasSetter>; +def warn_atomic_property_rule : Warning< + "writable atomic property %0 cannot pair a synthesized %select{getter|setter}1 " + "with a user defined %select{getter|setter}2">, + InGroup<DiagGroup<"atomic-property-with-user-defined-accessor">>; +def note_atomic_property_fixup_suggest : Note<"setter and getter must both be " + "synthesized, or both be user defined,or the property must be nonatomic">; +def err_atomic_property_nontrivial_assign_op : Error< + "atomic property of reference type %0 cannot have non-trivial assignment" + " operator">; +def warn_owning_getter_rule : Warning< + "property's synthesized getter follows Cocoa naming" + " convention for returning 'owned' objects">, + InGroup<DiagGroup<"objc-property-matches-cocoa-ownership-rule">>; +def warn_auto_synthesizing_protocol_property :Warning< + "auto property synthesis will not synthesize property" + " declared in a protocol">, + InGroup<DiagGroup<"objc-protocol-property-synthesis">>; +def warn_property_getter_owning_mismatch : Warning< + "property declared as returning non-retained objects" + "; getter returning retained objects">; +def err_ownin_getter_rule : Error< + "property's synthesized getter follows Cocoa naming" + " convention for returning 'owned' objects">; +def warn_default_atomic_custom_getter_setter : Warning< + "atomic by default property %0 has a user defined %select{getter|setter}1 " + "(property should be marked 'atomic' if this is intended)">, + InGroup<CustomAtomic>, DefaultIgnore; +def err_use_continuation_class : Error< + "illegal redeclaration of property in continuation class %0" + " (attribute must be 'readwrite', while its primary must be 'readonly')">; +def err_type_mismatch_continuation_class : Error< + "type of property %0 in continuation class does not match " + "property type in primary class">; +def err_use_continuation_class_redeclaration_readwrite : Error< + "illegal redeclaration of 'readwrite' property in continuation class %0" + " (perhaps you intended this to be a 'readwrite' redeclaration of a " + "'readonly' public property?)">; +def err_continuation_class : Error<"continuation class has no primary class">; +def err_property_type : Error<"property cannot have array or function type %0">; +def error_missing_property_context : Error< + "missing context for property implementation declaration">; +def error_bad_property_decl : Error< + "property implementation must have its declaration in interface %0">; +def error_category_property : Error< + "property declared in category %0 cannot be implemented in " + "class implementation">; +def note_property_declare : Note< + "property declared here">; +def error_synthesize_category_decl : Error< + "@synthesize not allowed in a category's implementation">; +def error_reference_property : Error< + "property of reference type is not supported">; +def error_missing_property_interface : Error< + "property implementation in a category with no category declaration">; +def error_bad_category_property_decl : Error< + "property implementation must have its declaration in the category %0">; +def error_bad_property_context : Error< + "property implementation must be in a class or category implementation">; +def error_missing_property_ivar_decl : Error< + "synthesized property %0 must either be named the same as a compatible" + " ivar or must explicitly name an ivar">; +def error_synthesize_weak_non_arc_or_gc : Error< + "@synthesize of 'weak' property is only allowed in ARC or GC mode">; +def err_arc_perform_selector_retains : Error< + "performSelector names a selector which retains the object">; +def warn_arc_perform_selector_leaks : Warning< + "performSelector may cause a leak because its selector is unknown">, + InGroup<DiagGroup<"arc-performSelector-leaks">>; +def err_gc_weak_property_strong_type : Error< + "weak attribute declared on a __strong type property in GC mode">; +def warn_receiver_is_weak : Warning < + "weak receiver may be unpredictably null in ARC mode">, + InGroup<DiagGroup<"receiver-is-weak">>, DefaultIgnore; + +def error_synthesized_ivar_yet_not_supported : Error< + "instance variable synthesis not yet supported" + " (need to declare %0 explicitly)">; + +def error_property_ivar_type : Error< + "type of property %0 (%1) does not match type of ivar %2 (%3)">; +def error_ivar_in_superclass_use : Error< + "property %0 attempting to use ivar %1 declared in super class %2">; +def error_weak_property : Error< + "existing ivar %1 for __weak property %0 must be __weak">; +def error_strong_property : Error< + "existing ivar %1 for strong property %0 may not be __weak">; +def error_dynamic_property_ivar_decl : Error< + "dynamic property can not have ivar specification">; +def error_duplicate_ivar_use : Error< + "synthesized properties %0 and %1 both claim ivar %2">; +def error_property_implemented : Error<"property %0 is already implemented">; +def warn_objc_property_attr_mutually_exclusive : Warning< + "property attributes '%0' and '%1' are mutually exclusive">, + InGroup<ReadOnlySetterAttrs>, DefaultIgnore; +def warn_objc_missing_super_dealloc : Warning< + "method possibly missing a [super dealloc] call">, + InGroup<ObjCMissingSuperCalls>; +def warn_objc_missing_super_finalize : Warning< + "method possibly missing a [super finalize] call">, + InGroup<ObjCMissingSuperCalls>; +def warn_undeclared_selector : Warning< + "undeclared selector %0">, InGroup<UndeclaredSelector>, DefaultIgnore; +def warn_implicit_atomic_property : Warning< + "property is assumed atomic by default">, InGroup<ImplicitAtomic>, DefaultIgnore; +def warn_auto_implicit_atomic_property : Warning< + "property is assumed atomic when auto-synthesizing the property">, + InGroup<ImplicitAtomic>, DefaultIgnore; +def warn_unimplemented_selector: Warning< + "unimplemented selector %0">, InGroup<Selector>, DefaultIgnore; +def warn_unimplemented_protocol_method : Warning< + "method %0 in protocol not implemented">, InGroup<Protocol>; + +// C++ declarations +def err_static_assert_expression_is_not_constant : Error< + "static_assert expression is not an integral constant expression">; +def err_static_assert_failed : Error<"static_assert failed %0">; + +def warn_inline_namespace_reopened_noninline : Warning< + "inline namespace cannot be re-opened as a non-inline namespace">; +def err_inline_namespace_mismatch : Error< + "%select{|non-}0inline namespace " + "cannot be reopened as %select{non-|}0inline">; + +def err_unexpected_friend : Error< + "friends can only be classes or functions">; +def ext_enum_friend : ExtWarn< + "enumeration type %0 cannot be a friend">; +def warn_cxx98_compat_enum_friend : Warning< + "befriending enumeration type %0 is incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def ext_nonclass_type_friend : ExtWarn< + "non-class friend type %0 is a C++11 extension">, InGroup<CXX11>; +def warn_cxx98_compat_nonclass_type_friend : Warning< + "non-class friend type %0 is incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def err_friend_is_member : Error< + "friends cannot be members of the declaring class">; +def warn_cxx98_compat_friend_is_member : Warning< + "friend declaration naming a member of the declaring class is incompatible " + "with C++98">, InGroup<CXX98Compat>, DefaultIgnore; +def ext_unelaborated_friend_type : ExtWarn< + "unelaborated friend declaration is a C++11 extension; specify " + "'%select{struct|union|class|enum}0' to befriend %1">, InGroup<CXX11>; +def warn_cxx98_compat_unelaborated_friend_type : Warning< + "befriending %1 without '%select{struct|union|class|enum}0' keyword is " + "incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore; +def err_qualified_friend_not_found : Error< + "no function named %0 with type %1 was found in the specified scope">; +def err_introducing_special_friend : Error< + "must use a qualified name when declaring a %select{constructor|" + "destructor|conversion operator}0 as a friend">; +def err_tagless_friend_type_template : Error< + "friend type templates must use an elaborated type">; +def err_no_matching_local_friend : Error< + "no matching function found in local scope">; +def err_no_matching_local_friend_suggest : Error< + "no matching function %0 found in local scope; did you mean %2">; +def err_partial_specialization_friend : Error< + "partial specialization cannot be declared as a friend">; +def err_qualified_friend_def : Error< + "friend function definition cannot be qualified with '%0'">; +def err_friend_def_in_local_class : Error< + "friend function cannot be defined in a local class">; + +def err_abstract_type_in_decl : Error< + "%select{return|parameter|variable|field}0 type %1 is an abstract class">; +def err_allocation_of_abstract_type : Error< + "allocating an object of abstract class type %0">; +def err_throw_abstract_type : Error< + "cannot throw an object of abstract type %0">; +def err_array_of_abstract_type : Error<"array of abstract class type %0">; + +def err_multiple_final_overriders : Error< + "virtual function %q0 has more than one final overrider in %1">; +def note_final_overrider : Note<"final overrider of %q0 in %1">; + +def err_type_defined_in_type_specifier : Error< + "%0 can not be defined in a type specifier">; +def err_type_defined_in_result_type : Error< + "%0 can not be defined in the result type of a function">; +def err_type_defined_in_param_type : Error< + "%0 can not be defined in a parameter type">; +def err_type_defined_in_alias_template : Error< + "%0 can not be defined in a type alias template">; + +def note_pure_virtual_function : Note< + "unimplemented pure virtual method %0 in %1">; + +def err_deleted_decl_not_first : Error< + "deleted definition must be first declaration">; + +def warn_weak_vtable : Warning< + "%0 has no out-of-line virtual method definitions; its vtable will be " + "emitted in every translation unit">, + InGroup<DiagGroup<"weak-vtables">>, DefaultIgnore; +def warn_weak_template_vtable : Warning< + "explicit template instantiation %0 will emit a vtable in every " + "translation unit">, + InGroup<DiagGroup<"weak-template-vtables">>, DefaultIgnore; + +def ext_using_undefined_std : ExtWarn< + "using directive refers to implicitly-defined namespace 'std'">; + +// C++ exception specifications +def err_exception_spec_in_typedef : Error< + "exception specifications are not allowed in %select{typedefs|type aliases}0">; +def err_distant_exception_spec : Error< + "exception specifications are not allowed beyond a single level " + "of indirection">; +def err_incomplete_in_exception_spec : Error< + "%select{|pointer to |reference to }0incomplete type %1 is not allowed " + "in exception specification">; +def err_mismatched_exception_spec : Error< + "exception specification in declaration does not match previous declaration">; +def warn_mismatched_exception_spec : ExtWarn< + "exception specification in declaration does not match previous declaration">; +def err_override_exception_spec : Error< + "exception specification of overriding function is more lax than " + "base version">; +def warn_override_exception_spec : ExtWarn< + "exception specification of overriding function is more lax than " + "base version">, InGroup<Microsoft>; +def err_incompatible_exception_specs : Error< + "target exception specification is not superset of source">; +def err_deep_exception_specs_differ : Error< + "exception specifications of %select{return|argument}0 types differ">; +def warn_missing_exception_specification : Warning< + "%0 is missing exception specification '%1'">; +def err_noexcept_needs_constant_expression : Error< + "argument to noexcept specifier must be a constant expression">; +def err_exception_spec_unknown : Error< + "exception specification is not available until end of class definition">; + +// C++ access checking +def err_class_redeclared_with_different_access : Error< + "%0 redeclared with '%1' access">; +def err_access : Error< + "%1 is a %select{private|protected}0 member of %3">, AccessControl; +def ext_ms_using_declaration_inaccessible : ExtWarn< + "using declaration referring to inaccessible member '%0' (which refers " + "to accessible member '%1') is a Microsoft compatibility extension">, + AccessControl, InGroup<Microsoft>; +def err_access_ctor : Error< + "calling a %select{private|protected}0 constructor of class %2">, + AccessControl; +def ext_rvalue_to_reference_access_ctor : ExtWarn< + "C++98 requires an accessible copy constructor for class %2 when binding " + "a reference to a temporary; was %select{private|protected}0">, + AccessControl, InGroup<BindToTemporaryCopy>; +def err_access_base_ctor : Error< + // The ERRORs represent other special members that aren't constructors, in + // hopes that someone will bother noticing and reporting if they appear + "%select{base class|inherited virtual base class}0 %1 has %select{private|" + "protected}3 %select{default |copy |move |*ERROR* |*ERROR* " + "|*ERROR*|}2constructor">, AccessControl; +def err_access_field_ctor : Error< + // The ERRORs represent other special members that aren't constructors, in + // hopes that someone will bother noticing and reporting if they appear + "field of type %0 has %select{private|protected}2 " + "%select{default |copy |move |*ERROR* |*ERROR* |*ERROR* |}1constructor">, + AccessControl; + +def err_access_dtor : Error< + "calling a %select{private|protected}1 destructor of class %0">, + AccessControl; +def err_access_dtor_base : + Error<"base class %0 has %select{private|protected}1 destructor">, + AccessControl; +def err_access_dtor_vbase : + Error<"inherited virtual base class %0 has " + "%select{private|protected}1 destructor">, + AccessControl; +def err_access_dtor_temp : + Error<"temporary of type %0 has %select{private|protected}1 destructor">, + AccessControl; +def err_access_dtor_exception : + Error<"exception object of type %0 has %select{private|protected}1 " + "destructor">, AccessControl; +def err_access_dtor_field : + Error<"field of type %1 has %select{private|protected}2 destructor">, + AccessControl; +def err_access_dtor_var : + Error<"variable of type %1 has %select{private|protected}2 destructor">, + AccessControl; +def err_access_dtor_ivar : + Error<"instance variable of type %0 has %select{private|protected}1 " + "destructor">, + AccessControl; +def note_previous_access_declaration : Note< + "previously declared '%1' here">; +def note_access_natural : Note< + "%select{|implicitly }1declared %select{private|protected}0 here">; +def note_access_constrained_by_path : Note< + "constrained by %select{|implicitly }1%select{private|protected}0" + " inheritance here">; +def note_access_protected_restricted_noobject : Note< + "must name member using the type of the current context %0">; +def note_access_protected_restricted_ctordtor : Note< + "protected %select{constructor|destructor}0 can only be used to " + "%select{construct|destroy}0 a base class subobject">; +def note_access_protected_restricted_object : Note< + "can only access this member on an object of type %0">; +def warn_cxx98_compat_sfinae_access_control : Warning< + "substitution failure due to access control is incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore, NoSFINAE; + +// C++ name lookup +def err_incomplete_nested_name_spec : Error< + "incomplete type %0 named in nested name specifier">; +def err_dependent_nested_name_spec : Error< + "nested name specifier for a declaration cannot depend on a template " + "parameter">; +def err_nested_name_member_ref_lookup_ambiguous : Error< + "lookup of %0 in member access expression is ambiguous">; +def ext_nested_name_member_ref_lookup_ambiguous : ExtWarn< + "lookup of %0 in member access expression is ambiguous; using member of %1">, + InGroup<AmbigMemberTemplate>; +def note_ambig_member_ref_object_type : Note< + "lookup in the object type %0 refers here">; +def note_ambig_member_ref_scope : Note< + "lookup from the current scope refers here">; +def err_qualified_member_nonclass : Error< + "qualified member access refers to a member in %0">; +def err_incomplete_member_access : Error< + "member access into incomplete type %0">; +def err_incomplete_type : Error< + "incomplete type %0 where a complete type is required">; +def warn_cxx98_compat_enum_nested_name_spec : Warning< + "enumeration type in nested name specifier is incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; + +// C++ class members +def err_storageclass_invalid_for_member : Error< + "storage class specified for a member declaration">; +def err_mutable_function : Error<"'mutable' cannot be applied to functions">; +def err_mutable_reference : Error<"'mutable' cannot be applied to references">; +def err_mutable_const : Error<"'mutable' and 'const' cannot be mixed">; +def err_mutable_nonmember : Error< + "'mutable' can only be applied to member variables">; +def err_virtual_non_function : Error< + "'virtual' can only appear on non-static member functions">; +def err_virtual_out_of_class : Error< + "'virtual' can only be specified inside the class definition">; +def err_virtual_member_function_template : Error< + "'virtual' can not be specified on member function templates">; +def err_static_overrides_virtual : Error< + "'static' member function %0 overrides a virtual function in a base class">; +def err_explicit_non_function : Error< + "'explicit' can only appear on non-static member functions">; +def err_explicit_out_of_class : Error< + "'explicit' can only be specified inside the class definition">; +def err_explicit_non_ctor_or_conv_function : Error< + "'explicit' can only be applied to a constructor or conversion function">; +def err_static_not_bitfield : Error<"static member %0 cannot be a bit-field">; +def err_static_out_of_line : Error< + "'static' can only be specified inside the class definition">; +def err_typedef_not_bitfield : Error<"typedef member %0 cannot be a bit-field">; +def err_not_integral_type_bitfield : Error< + "bit-field %0 has non-integral type %1">; +def err_not_integral_type_anon_bitfield : Error< + "anonymous bit-field has non-integral type %0">; +def err_member_function_initialization : Error< + "initializer on function does not look like a pure-specifier">; +def err_non_virtual_pure : Error< + "%0 is not virtual and cannot be declared pure">; +def warn_pure_function_definition : ExtWarn< + "function definition with pure-specifier is a Microsoft extension">, + InGroup<Microsoft>; +def err_implicit_object_parameter_init : Error< + "cannot initialize object parameter of type %0 with an expression " + "of type %1">; +def err_qualified_member_of_unrelated : Error< + "%q0 is not a member of class %1">; + +def warn_call_to_pure_virtual_member_function_from_ctor_dtor : Warning< + "call to pure virtual member function %0; overrides of %0 in subclasses are " + "not available in the %select{constructor|destructor}1 of %2">; + +def note_field_decl : Note<"member is declared here">; +def note_ivar_decl : Note<"ivar is declared here">; +def note_bitfield_decl : Note<"bit-field is declared here">; +def note_previous_decl : Note<"%0 declared here">; +def note_member_synthesized_at : Note< + "implicit default %select{constructor|copy constructor|move constructor|copy " + "assignment operator|move assignment operator|destructor}0 for %1 first " + "required here">; +def err_missing_default_ctor : Error< + "%select{|implicit default }0constructor for %1 must explicitly initialize " + "the %select{base class|member}2 %3 which does not have a default " + "constructor">; +def err_illegal_union_or_anon_struct_member : Error< + "%select{anonymous struct|union}0 member %1 has a non-trivial " + "%select{constructor|copy constructor|move constructor|copy assignment " + "operator|move assignment operator|destructor}2">; +def warn_cxx98_compat_nontrivial_union_or_anon_struct_member : Warning< + "%select{anonymous struct|union}0 member %1 with a non-trivial " + "%select{constructor|copy constructor|move constructor|copy assignment " + "operator|move assignment operator|destructor}2 is incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def note_nontrivial_has_virtual : Note< + "because type %0 has a virtual %select{member function|base class}1">; +def note_nontrivial_has_nontrivial : Note< + "because type %0 has a %select{member|base class}1 with a non-trivial " + "%select{constructor|copy constructor|move constructor|copy assignment " + "operator|move assignment operator|destructor}2">; +def note_nontrivial_user_defined : Note< + "because type %0 has a user-declared %select{constructor|copy constructor|" + "move constructor|copy assignment operator|move assignment operator|" + "destructor}1">; +def err_static_data_member_not_allowed_in_anon_struct : Error< + "static data member %0 not allowed in anonymous struct">; +def ext_static_data_member_in_union : ExtWarn< + "static data member %0 in union is a C++11 extension">, InGroup<CXX11>; +def warn_cxx98_compat_static_data_member_in_union : Warning< + "static data member %0 in union is incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def err_union_member_of_reference_type : Error< + "union member %0 has reference type %1">; +def ext_anonymous_struct_union_qualified : Extension< + "anonymous %select{struct|union}0 cannot be '%select{const|volatile|" + "restrict}1'">; +def err_different_return_type_for_overriding_virtual_function : Error< + "virtual function %0 has a different return type (%1) than the " + "function it overrides (which has return type %2)">; +def note_overridden_virtual_function : Note< + "overridden virtual function is here">; + +def err_covariant_return_inaccessible_base : Error< + "invalid covariant return for virtual function: %1 is a " + "%select{private|protected}2 base class of %0">, AccessControl; +def err_covariant_return_ambiguous_derived_to_base_conv : Error< + "return type of virtual function %3 is not covariant with the return type of " + "the function it overrides (ambiguous conversion from derived class " + "%0 to base class %1:%2)">; +def err_covariant_return_not_derived : Error< + "return type of virtual function %0 is not covariant with the return type of " + "the function it overrides (%1 is not derived from %2)">; +def err_covariant_return_incomplete : Error< + "return type of virtual function %0 is not covariant with the return type of " + "the function it overrides (%1 is incomplete)">; +def err_covariant_return_type_different_qualifications : Error< + "return type of virtual function %0 is not covariant with the return type of " + "the function it overrides (%1 has different qualifiers than %2)">; +def err_covariant_return_type_class_type_more_qualified : Error< + "return type of virtual function %0 is not covariant with the return type of " + "the function it overrides (class type %1 is more qualified than class " + "type %2">; + +// C++ constructors +def err_constructor_cannot_be : Error<"constructor cannot be declared '%0'">; +def err_invalid_qualified_constructor : Error< + "'%0' qualifier is not allowed on a constructor">; +def err_ref_qualifier_constructor : Error< + "ref-qualifier '%select{&&|&}0' is not allowed on a constructor">; + +def err_constructor_return_type : Error< + "constructor cannot have a return type">; +def err_constructor_redeclared : Error<"constructor cannot be redeclared">; +def err_constructor_byvalue_arg : Error< + "copy constructor must pass its first argument by reference">; +def warn_no_constructor_for_refconst : Warning< + "%select{struct|union|class|enum}0 %1 does not declare any constructor to " + "initialize its non-modifiable members">; +def note_refconst_member_not_initialized : Note< + "%select{const|reference}0 member %1 will never be initialized">; +def ext_ms_explicit_constructor_call : ExtWarn< + "explicit constructor calls are a Microsoft extension">, InGroup<Microsoft>; + +// C++ destructors +def err_destructor_not_member : Error< + "destructor must be a non-static member function">; +def err_destructor_cannot_be : Error<"destructor cannot be declared '%0'">; +def err_invalid_qualified_destructor : Error< + "'%0' qualifier is not allowed on a destructor">; +def err_ref_qualifier_destructor : Error< + "ref-qualifier '%select{&&|&}0' is not allowed on a destructor">; +def err_destructor_return_type : Error<"destructor cannot have a return type">; +def err_destructor_redeclared : Error<"destructor cannot be redeclared">; +def err_destructor_with_params : Error<"destructor cannot have any parameters">; +def err_destructor_variadic : Error<"destructor cannot be variadic">; +def err_destructor_typedef_name : Error< + "destructor cannot be declared using a %select{typedef|type alias}1 %0 of the class name">; +def err_destructor_name : Error< + "expected the class name after '~' to name the enclosing class">; +def err_destructor_class_name : Error< + "expected the class name after '~' to name a destructor">; +def err_ident_in_dtor_not_a_type : Error< + "identifier %0 in object destruction expression does not name a type">; +def err_destructor_expr_type_mismatch : Error< + "destructor type %0 in object destruction expression does not match the " + "type %1 of the object being destroyed">; +def note_destructor_type_here : Note< + "type %0 is declared here">; + +def err_destructor_template : Error< + "destructor cannot be declared as a template">; + +// C++ initialization +def err_init_conversion_failed : Error< + "cannot initialize %select{a variable|a parameter|return object|an " + "exception object|a member subobject|an array element|a new value|a value|a " + "base class|a constructor delegation|a vector element}0 of type %1 with an " + "%select{rvalue|lvalue}2 of type %3" + "%select{|: different classes (%5 vs %6)" + "|: different number of parameters (%5 vs %6)" + "|: type mismatch at %ordinal5 parameter (%6 vs %7)" + "|: different return type (%5 vs %6)" + "|: different qualifiers (" + "%select{none|const|restrict|const and restrict|volatile|const and volatile|" + "volatile and restrict|const, volatile, and restrict}5 vs " + "%select{none|const|restrict|const and restrict|volatile|const and volatile|" + "volatile and restrict|const, volatile, and restrict}6)}4">; + +def err_lvalue_to_rvalue_ref : Error<"rvalue reference to type %0 cannot bind " + "to lvalue of type %1">; +def err_lvalue_reference_bind_to_initlist : Error< + "%select{non-const|volatile}0 lvalue reference to type %1 cannot bind to an " + "initializer list temporary">; +def err_lvalue_reference_bind_to_temporary : Error< + "%select{non-const|volatile}0 lvalue reference to type %1 cannot bind to a " + "temporary of type %2">; +def err_lvalue_reference_bind_to_unrelated : Error< + "%select{non-const|volatile}0 lvalue reference to type %1 cannot bind to a " + "value of unrelated type %2">; +def err_reference_bind_drops_quals : Error< + "binding of reference to type %0 to a value of type %1 drops qualifiers">; +def err_reference_bind_failed : Error< + "reference to type %0 could not bind to an %select{rvalue|lvalue}1 of type " + "%2">; +def err_reference_bind_init_list : Error< + "reference to type %0 cannot bind to an initializer list">; +def err_init_list_bad_dest_type : Error< + "%select{|non-aggregate }0type %1 cannot be initialized with an initializer " + "list">; +def err_member_function_call_bad_cvr : Error<"member function %0 not viable: " + "'this' argument has type %1, but function is not marked " + "%select{const|restrict|const or restrict|volatile|const or volatile|" + "volatile or restrict|const, volatile, or restrict}2">; + +def err_reference_bind_to_bitfield : Error< + "%select{non-const|volatile}0 reference cannot bind to bit-field %1">; +def err_reference_bind_to_vector_element : Error< + "%select{non-const|volatile}0 reference cannot bind to vector element">; +def err_reference_var_requires_init : Error< + "declaration of reference variable %0 requires an initializer">; +def err_reference_without_init : Error< + "reference to type %0 requires an initializer">; +def err_reference_has_multiple_inits : Error< + "reference cannot be initialized with multiple values">; +def err_init_non_aggr_init_list : Error< + "initialization of non-aggregate type %0 with an initializer list">; +def err_init_reference_member_uninitialized : Error< + "reference member of type %0 uninitialized">; +def note_uninit_reference_member : Note< + "uninitialized reference member is here">; +def warn_field_is_uninit : Warning<"field is uninitialized when used here">, + InGroup<Uninitialized>; +def warn_uninit_self_reference_in_init : Warning< + "variable %0 is uninitialized when used within its own initialization">, + InGroup<Uninitialized>; +def warn_uninit_var : Warning< + "variable %0 is uninitialized when used here">, + InGroup<Uninitialized>, DefaultIgnore; +def warn_maybe_uninit_var : + Warning<"variable %0 may be uninitialized when used here">, + InGroup<UninitializedMaybe>, DefaultIgnore; +def note_uninit_var_def : Note< + "variable %0 is declared here">; +def warn_uninit_var_captured_by_block : Warning< + "variable %0 is uninitialized when captured by block">, + InGroup<Uninitialized>, DefaultIgnore; +def warn_maybe_uninit_var_captured_by_block : Warning< + "variable %0 may be uninitialized when captured by block">, + InGroup<UninitializedMaybe>, DefaultIgnore; +def warn_uninit_byref_blockvar_captured_by_block : Warning< + "block pointer variable %0 is uninitialized when captured by block">, + InGroup<Uninitialized>, DefaultIgnore; +def note_block_var_fixit_add_initialization : Note< + "maybe you meant to use __block %0">; +def note_var_fixit_add_initialization : Note< + "initialize the variable %0 to silence this warning">; +def err_init_incomplete_type : Error<"initialization of incomplete type %0">; + +def err_temp_copy_no_viable : Error< + "no viable constructor %select{copying variable|copying parameter|" + "returning object|throwing object|copying member subobject|copying array " + "element|allocating object|copying temporary|initializing base subobject|" + "initializing vector element|capturing value}0 of type %1">; +def ext_rvalue_to_reference_temp_copy_no_viable : ExtWarn< + "no viable constructor %select{copying variable|copying parameter|" + "returning object|throwing object|copying member subobject|copying array " + "element|allocating object|copying temporary|initializing base subobject|" + "initializing vector element|capturing value}0 of type %1; C++98 requires a copy " + "constructor when binding a reference to a temporary">, + InGroup<BindToTemporaryCopy>; +def err_temp_copy_ambiguous : Error< + "ambiguous constructor call when %select{copying variable|copying " + "parameter|returning object|throwing object|copying member subobject|copying " + "array element|allocating object|copying temporary|initializing base subobject|" + "initializing vector element|capturing value}0 of type %1">; +def err_temp_copy_deleted : Error< + "%select{copying variable|copying parameter|returning object|throwing " + "object|copying member subobject|copying array element|allocating object|" + "copying temporary|initializing base subobject|initializing vector element|" + "capturing value}0 of type %1 invokes deleted constructor">; +def err_temp_copy_incomplete : Error< + "copying a temporary object of incomplete type %0">; +def warn_cxx98_compat_temp_copy : Warning< + "%select{copying variable|copying parameter|returning object|throwing " + "object|copying member subobject|copying array element|allocating object|" + "copying temporary|initializing base subobject|initializing vector element}1 " + "of type %2 when binding a reference to a temporary would %select{invoke " + "an inaccessible constructor|find no viable constructor|find ambiguous " + "constructors|invoke a deleted constructor}0 in C++98">, + InGroup<CXX98CompatBindToTemporaryCopy>, DefaultIgnore; +def err_selected_explicit_constructor : Error< + "chosen constructor is explicit in copy-initialization">; +def note_constructor_declared_here : Note< + "constructor declared here">; + +// C++11 decltype +def err_decltype_in_declarator : Error< + "'decltype' cannot be used to name a declaration">; + +// C++11 auto +def warn_cxx98_compat_auto_type_specifier : Warning< + "'auto' type specifier is incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def err_auto_variable_cannot_appear_in_own_initializer : Error< + "variable %0 declared with 'auto' type cannot appear in its own initializer">; +def err_illegal_decl_array_of_auto : Error< + "'%0' declared as array of %1">; +def err_new_array_of_auto : Error< + "cannot allocate array of 'auto'">; +def err_auto_not_allowed : Error< + "'auto' not allowed %select{in function prototype|in non-static struct member" + "|in non-static union member|in non-static class member|in exception declaration" + "|in template parameter|in block literal|in template argument" + "|in typedef|in type alias|in function return type|here}0">; +def err_auto_var_requires_init : Error< + "declaration of variable %0 with type %1 requires an initializer">; +def err_auto_new_requires_ctor_arg : Error< + "new expression for type %0 requires a constructor argument">; +def err_auto_new_requires_parens : Error< + "new expression for type %0 cannot use list-initialization">; +def err_auto_var_init_no_expression : Error< + "initializer for variable %0 with type %1 is empty">; +def err_auto_var_init_multiple_expressions : Error< + "initializer for variable %0 with type %1 contains multiple expressions">; +def err_auto_new_ctor_multiple_expressions : Error< + "new expression for type %0 contains multiple constructor arguments">; +def err_auto_missing_trailing_return : Error< + "'auto' return without trailing return type">; +def err_trailing_return_without_auto : Error< + "function with trailing return type must specify return type 'auto', not %0">; +def err_trailing_return_in_parens : Error< + "trailing return type may not be nested within parentheses">; +def err_auto_var_deduction_failure : Error< + "variable %0 with type %1 has incompatible initializer of type %2">; +def err_auto_var_deduction_failure_from_init_list : Error< + "cannot deduce actual type for variable %0 with type %1 from initializer list">; +def err_auto_new_deduction_failure : Error< + "new expression for type %0 has incompatible constructor argument of type %1">; +def err_auto_different_deductions : Error< + "'auto' deduced as %0 in declaration of %1 and deduced as %2 in declaration of %3">; +def err_implied_std_initializer_list_not_found : Error< + "cannot deduce type of initializer list because std::initializer_list was " + "not found; include <initializer_list>">; +def err_malformed_std_initializer_list : Error< + "std::initializer_list must be a class template with a single type parameter">; +def warn_dangling_std_initializer_list : Warning< + "array backing the initializer list will be destroyed at the end of " + "%select{the full-expression|the constructor}0">, + InGroup<DiagGroup<"dangling-initializer-list">>; + +// C++11 override control +def override_keyword_only_allowed_on_virtual_member_functions : Error< + "only virtual member functions can be marked '%0'">; +def err_function_marked_override_not_overriding : Error< + "%0 marked 'override' but does not override any member functions">; +def err_class_marked_final_used_as_base : Error< + "base %0 is marked 'final'">; + +// C++11 attributes +def err_repeat_attribute : Error<"'%0' attribute cannot be repeated">; + +// C++11 final +def err_final_function_overridden : Error< + "declaration of %0 overrides a 'final' function">; + +// C++11 scoped enumerations +def err_enum_invalid_underlying : Error< + "non-integral type %0 is an invalid underlying type">; +def err_enumerator_too_large : Error< + "enumerator value is not representable in the underlying type %0">; +def ext_enumerator_too_large : ExtWarn< + "enumerator value is not representable in the underlying type %0">, + InGroup<Microsoft>; +def err_enumerator_wrapped : Error< + "enumerator value %0 is not representable in the underlying type %1">; +def err_enum_redeclare_type_mismatch : Error< + "enumeration redeclared with different underlying type %0 (was %1)">; +def err_enum_redeclare_fixed_mismatch : Error< + "enumeration previously declared with %select{non|}0fixed underlying type">; +def err_enum_redeclare_scoped_mismatch : Error< + "enumeration previously declared as %select{un|}0scoped">; +def err_enum_class_reference : Error< + "reference to %select{|scoped }0enumeration must use 'enum' " + "not 'enum class'">; +def err_only_enums_have_underlying_types : Error< + "only enumeration types have underlying types">; + +// C++11 delegating constructors +def err_delegating_ctor : Error< + "delegating constructors are permitted only in C++11">; +def warn_cxx98_compat_delegating_ctor : Warning< + "delegating constructors are incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def err_delegating_initializer_alone : Error< + "an initializer for a delegating constructor must appear alone">; +def warn_delegating_ctor_cycle : Warning< + "constructor for %0 creates a delegation cycle">, DefaultError, + InGroup<DelegatingCtorCycles>; +def note_it_delegates_to : Note< + "it delegates to">, InGroup<DelegatingCtorCycles>; +def note_which_delegates_to : Note< + "which delegates to">, InGroup<DelegatingCtorCycles>; + +// C++11 range-based for loop +def err_for_range_decl_must_be_var : Error< + "for range declaration must declare a variable">; +def err_for_range_storage_class : Error< + "loop variable %0 may not be declared %select{'extern'|'static'|" + "'__private_extern__'|'auto'|'register'|'constexpr'}1">; +def err_type_defined_in_for_range : Error< + "types may not be defined in a for range declaration">; +def err_for_range_deduction_failure : Error< + "cannot use type %0 as a range">; +def err_for_range_incomplete_type : Error< + "cannot use incomplete type %0 as a range">; +def err_for_range_iter_deduction_failure : Error< + "cannot use type %0 as an iterator">; +def err_for_range_member_begin_end_mismatch : Error< + "range type %0 has '%select{begin|end}1' member but no '%select{end|begin}1' member">; +def err_for_range_begin_end_types_differ : Error< + "'begin' and 'end' must return the same type (got %0 and %1)">; +def note_for_range_type : Note<"range has type %0">; +def note_for_range_begin_end : Note< + "selected '%select{begin|end}0' %select{function|template }1%2 with iterator type %3">; + +// C++11 constexpr +def warn_cxx98_compat_constexpr : Warning< + "'constexpr' specifier is incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def err_invalid_constexpr : Error< + "%select{function parameter|typedef|non-static data member}0 " + "cannot be constexpr">; +def err_constexpr_tag : Error< + "%select{class|struct|union|enum}0 cannot be marked constexpr">; +def err_constexpr_dtor : Error<"destructor cannot be marked constexpr">; +def err_constexpr_no_declarators : Error< + "constexpr can only be used in variable and function declarations">; +def err_invalid_constexpr_var_decl : Error< + "constexpr variable declaration must be a definition">; +def err_constexpr_static_mem_var_requires_init : Error< + "declaration of constexpr static data member %0 requires an initializer">; +def err_constexpr_var_non_literal : Error< + "constexpr variable cannot have non-literal type %0">; +def err_constexpr_var_requires_const_init : Error< + "constexpr variable %0 must be initialized by a constant expression">; +def err_constexpr_redecl_mismatch : Error< + "%select{non-constexpr declaration of %0 follows constexpr declaration" + "|constexpr declaration of %0 follows non-constexpr declaration}1">; +def err_constexpr_virtual : Error<"virtual function cannot be constexpr">; +def err_constexpr_virtual_base : Error< + "constexpr %select{member function|constructor}0 not allowed in " + "%select{class|struct}1 with virtual base %plural{1:class|:classes}2">; +def note_non_literal_virtual_base : Note<"%select{class|struct}0 with virtual " + "base %plural{1:class|:classes}1 is not a literal type">; +def note_constexpr_virtual_base_here : Note<"virtual base class declared here">; +def err_constexpr_non_literal_return : Error< + "constexpr function's return type %0 is not a literal type">; +def err_constexpr_non_literal_param : Error< + "constexpr %select{function|constructor}1's %ordinal0 parameter type %2 is " + "not a literal type">; +def err_constexpr_body_invalid_stmt : Error< + "statement not allowed in constexpr %select{function|constructor}0">; +def err_constexpr_type_definition : Error< + "types cannot be defined in a constexpr %select{function|constructor}0">; +def err_constexpr_vla : Error< + "variably-modified type %0 cannot be used in a constexpr " + "%select{function|constructor}1">; +def err_constexpr_var_declaration : Error< + "variables cannot be declared in a constexpr %select{function|constructor}0">; +def err_constexpr_function_never_constant_expr : ExtWarn< + "constexpr %select{function|constructor}0 never produces a " + "constant expression">, InGroup<DiagGroup<"invalid-constexpr">>, DefaultError; +def err_constexpr_body_no_return : Error< + "no return statement in constexpr function">; +def err_constexpr_body_multiple_return : Error< + "multiple return statements in constexpr function">; +def note_constexpr_body_previous_return : Note< + "previous return statement is here">; +def err_constexpr_function_try_block : Error< + "function try block not allowed in constexpr %select{function|constructor}0">; +def err_constexpr_union_ctor_no_init : Error< + "constexpr union constructor does not initialize any member">; +def err_constexpr_ctor_missing_init : Error< + "constexpr constructor must initialize all members">; +def note_constexpr_ctor_missing_init : Note< + "member not initialized by constructor">; +def err_constexpr_method_non_literal : Error< + "non-literal type %0 cannot have constexpr members">; +def note_non_literal_no_constexpr_ctors : Note< + "%0 is not literal because it is not an aggregate and has no constexpr " + "constructors other than copy or move constructors">; +def note_non_literal_base_class : Note< + "%0 is not literal because it has base class %1 of non-literal type">; +def note_non_literal_field : Note< + "%0 is not literal because it has data member %1 of " + "%select{non-literal|volatile}3 type %2">; +def note_non_literal_user_provided_dtor : Note< + "%0 is not literal because it has a user-provided destructor">; +def note_non_literal_nontrivial_dtor : Note< + "%0 is not literal because it has a non-trivial destructor">; + +// C++11 char16_t/char32_t +def warn_cxx98_compat_unicode_type : Warning< + "'%0' type specifier is incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; + +// Objective-C++ +def err_objc_decls_may_only_appear_in_global_scope : Error< + "Objective-C declarations may only appear in global scope">; +// Attributes +def err_nsobject_attribute : Error< + "__attribute ((NSObject)) is for pointer types only">; +def err_attribute_can_be_applied_only_to_symbol_declaration : Error< + "%0 attribute can be applied only to symbol declaration">; +def err_attributes_are_not_compatible : Error< + "%0 and %1 attributes are not compatible">; +def err_attribute_wrong_number_arguments : Error< + "attribute %plural{0:takes no arguments|1:takes one argument|" + ":requires exactly %0 arguments}0">; +def err_attribute_too_many_arguments : Error< + "attribute takes no more than %0 argument%s0">; +def err_suppress_autosynthesis : Error< + "objc_requires_property_definitions attribute may only be specified on a class" + "to a class declaration">; +def err_attribute_too_few_arguments : Error< + "attribute takes at least %0 argument%s0">; +def err_attribute_missing_parameter_name : Error< + "attribute requires unquoted parameter">; +def err_attribute_invalid_vector_type : Error<"invalid vector element type %0">; +def err_attribute_bad_neon_vector_size : Error< + "Neon vector size must be 64 or 128 bits">; +def err_attribute_argument_not_int : Error< + "'%0' attribute requires integer constant">; +def err_attribute_argument_not_class : Error< + "%0 attribute requires arguments that are class type or point to class type">; +def err_attribute_first_argument_not_int_or_bool : Error< + "%0 attribute first argument must be of int or bool type">; +def err_attribute_argument_outof_range : Error< + "init_priority attribute requires integer constant between " + "101 and 65535 inclusive">; +def err_init_priority_object_attr : Error< + "can only use 'init_priority' attribute on file-scope definitions " + "of objects of class type">; +def err_attribute_argument_n_not_int : Error< + "'%0' attribute requires parameter %1 to be an integer constant">; +def err_attribute_argument_n_not_string : Error< + "'%0' attribute requires parameter %1 to be a string">; +def err_attribute_argument_out_of_bounds : Error< + "'%0' attribute parameter %1 is out of bounds">; +def err_attribute_requires_objc_interface : Error< + "attribute may only be applied to an Objective-C interface">; +def err_attribute_uuid_malformed_guid : Error< + "uuid attribute contains a malformed GUID">; +def warn_nonnull_pointers_only : Warning< + "nonnull attribute only applies to pointer arguments">; +def err_attribute_invalid_implicit_this_argument : Error< + "'%0' attribute is invalid for the implicit this argument">; +def err_ownership_type : Error< + "%0 attribute only applies to %1 arguments">; +def err_format_strftime_third_parameter : Error< + "strftime format attribute requires 3rd parameter to be 0">; +def err_format_attribute_requires_variadic : Error< + "format attribute requires variadic function">; +def err_format_attribute_not : Error<"format argument not %0">; +def err_format_attribute_result_not : Error<"function does not return %0">; +def err_format_attribute_implicit_this_format_string : Error< + "format attribute cannot specify the implicit this argument as the format " + "string">; +def warn_unknown_method_family : Warning<"unrecognized method family">; +def err_init_method_bad_return_type : Error< + "init methods must return an object pointer type, not %0">; +def err_attribute_invalid_size : Error< + "vector size not an integral multiple of component size">; +def err_attribute_zero_size : Error<"zero vector size">; +def err_typecheck_vector_not_convertable : Error< + "can't convert between vector values of different size (%0 and %1)">; +def err_typecheck_ext_vector_not_typedef : Error< + "ext_vector_type only applies to types, not variables">; +def err_ext_vector_component_exceeds_length : Error< + "vector component access exceeds type %0">; +def err_ext_vector_component_name_illegal : Error< + "illegal vector component name '%0'">; +def err_attribute_address_space_not_int : Error< + "address space attribute requires an integer constant">; +def err_attribute_address_space_negative : Error< + "address space is negative">; +def err_attribute_address_space_too_high : Error< + "address space is larger than the maximum supported (%0)">; +def err_attribute_address_multiple_qualifiers : Error< + "multiple address spaces specified for type">; +def err_attribute_address_function_type : Error< + "function type may not be qualified with an address space">; +def err_as_qualified_auto_decl : Error< + "automatic variable qualified with an address space">; +def err_arg_with_address_space : Error< + "parameter may not be qualified with an address space">; +def err_attr_objc_ownership_redundant : Error< + "the type %0 is already explicitly ownership-qualified">; +def err_attribute_not_string : Error< + "argument to %0 attribute was not a string literal">; +def err_undeclared_nsnumber : Error< + "NSNumber must be available to use Objective-C literals">; +def err_invalid_nsnumber_type : Error< + "%0 is not a valid literal type for NSNumber">; +def err_undeclared_nsarray : Error< + "NSArray must be available to use Objective-C array literals">; +def err_undeclared_nsdictionary : Error< + "NSDictionary must be available to use Objective-C dictionary " + "literals">; +def err_undeclared_arraywithobjects : Error< + "declaration of %0 is missing in NSArray class">; +def err_undeclared_dictwithobjects : Error< + "declaration of %0 is missing in NSDictionary class">; +def err_undeclared_nsnumber_method : Error< + "declaration of %0 is missing in NSNumber class">; +def err_objc_literal_method_sig : Error< + "literal construction method %0 has incompatible signature">; +def note_objc_literal_method_param : Note< + "%select{first|second|third}0 parameter has unexpected type %1 " + "(should be %2)">; +def note_objc_literal_method_return : Note< + "method returns unexpected type %0 (should be an object type)">; +def err_invalid_collection_element : Error< + "collection element of type %0 is not an Objective-C object">; +def err_box_literal_collection : Error< + "%select{string|character|boolean|numeric}0 literal must be prefixed by '@' " + "in a collection">; + +let CategoryName = "Cocoa API Issue" in { +def warn_objc_redundant_literal_use : Warning< + "using %0 with a literal is redundant">, InGroup<ObjCRedundantLiteralUse>; +} + +def err_only_annotate_after_access_spec : Error< + "access specifier can only have annotation attributes">; +def err_attribute_section_invalid_for_target : Error< + "argument to 'section' attribute is not valid for this target: %0">; +def err_attribute_section_local_variable : Error< + "'section' attribute is not valid on local variables">; +def err_attribute_aligned_not_power_of_two : Error< + "requested alignment is not a power of 2">; +def warn_redeclaration_without_attribute_prev_attribute_ignored : Warning< + "'%0' redeclared without %1 attribute: previous %1 ignored">; +def warn_attribute_ignored : Warning<"%0 attribute ignored">; +def warn_unknown_attribute_ignored : Warning< + "unknown attribute %0 ignored">, InGroup<UnknownAttributes>; +def warn_attribute_invalid_on_stmt : Warning< + "attribute %0 cannot be specified on a statement">, + InGroup<IgnoredAttributes>; +def warn_declspec_attribute_ignored : Warning< + "attribute %0 is ignored, place it after \"%select{class|struct|union|enum}1\" to apply attribute to type declaration">, InGroup<IgnoredAttributes>; +def warn_attribute_precede_definition : Warning< + "attribute declaration must precede definition">; +def warn_attribute_void_function_method : Warning< + "attribute %0 cannot be applied to " + "%select{functions|Objective-C method}1 without return value">; +def warn_attribute_weak_on_field : Warning< + "__weak attribute cannot be specified on a field declaration">; +def warn_gc_attribute_weak_on_local : Warning< + "Objective-C GC does not allow weak variables on the stack">; +def warn_nsobject_attribute : Warning< + "__attribute ((NSObject)) may be put on a typedef only, " + "attribute is ignored">, InGroup<NSobjectAttribute>; +def warn_attribute_weak_on_local : Warning< + "__weak attribute cannot be specified on an automatic variable">; +def warn_weak_identifier_undeclared : Warning< + "weak identifier %0 never declared">; +def err_attribute_weak_static : Error< + "weak declaration cannot have internal linkage">; +def warn_attribute_weak_import_invalid_on_definition : Warning< + "'weak_import' attribute cannot be specified on a definition">; +def err_attribute_weakref_not_static : Error< + "weakref declaration must have internal linkage">; +def err_attribute_weakref_not_global_context : Error< + "weakref declaration of '%0' must be in a global context">; +def err_attribute_weakref_without_alias : Error< + "weakref declaration of '%0' must also have an alias attribute">; +def err_alias_not_supported_on_darwin : Error < + "only weak aliases are supported on darwin">; +def warn_attribute_wrong_decl_type : Warning< + "%0 attribute only applies to %select{functions|unions|" + "variables and functions|functions and methods|parameters|" + "functions, methods and blocks|functions, methods, and parameters|" + "classes|variables|methods|variables, functions and labels|" + "fields and global variables|structs}1">; +def err_attribute_wrong_decl_type : Error< + "%0 attribute only applies to %select{functions|unions|" + "variables and functions|functions and methods|parameters|" + "functions, methods and blocks|functions, methods, and parameters|" + "classes|variables|methods|variables, functions and labels|" + "fields and global variables|structs}1">; +def warn_function_attribute_wrong_type : Warning< + "'%0' only applies to function types; type here is %1">; +def warn_pointer_attribute_wrong_type : Warning< + "'%0' only applies to pointer types; type here is %1">; +def warn_objc_object_attribute_wrong_type : Warning< + "'%0' only applies to objective-c object or block pointer types; type here is %1">; +def warn_gnu_inline_attribute_requires_inline : Warning< + "'gnu_inline' attribute requires function to be marked 'inline'," + " attribute ignored">; +def err_attribute_vecreturn_only_vector_member : Error< + "the vecreturn attribute can only be used on a class or structure with one member, which must be a vector">; +def err_attribute_vecreturn_only_pod_record : Error< + "the vecreturn attribute can only be used on a POD (plain old data) class or structure (i.e. no virtual functions)">; +def err_cconv_change : Error< + "function declared '%0' here was previously declared " + "%select{'%2'|without calling convention}1">; +def err_cconv_knr : Error< + "function with no prototype cannot use %0 calling convention">; +def err_cconv_varargs : Error< + "variadic function cannot use %0 calling convention">; +def err_regparm_mismatch : Error<"function declared with with regparm(%0) " + "attribute was previously declared " + "%plural{0:without the regparm|:with the regparm(%1)}1 attribute">; +def err_returns_retained_mismatch : Error< + "function declared with the ns_returns_retained attribute " + "was previously declared without the ns_returns_retained attribute">; +def err_objc_precise_lifetime_bad_type : Error< + "objc_precise_lifetime only applies to retainable types; type here is %0">; +def warn_objc_precise_lifetime_meaningless : Error< + "objc_precise_lifetime is not meaningful for " + "%select{__unsafe_unretained|__autoreleasing}0 objects">; +def err_invalid_pcs : Error<"Invalid PCS type">; +def err_attribute_can_be_applied_only_to_value_decl : Error< + "%0 attribute can only be applied to value declarations">; +def warn_attribute_not_on_decl : Error< + "%0 attribute ignored when parsing type">; + + +// Availability attribute +def warn_availability_unknown_platform : Warning< + "unknown platform %0 in availability macro">; +def warn_availability_version_ordering : Warning< + "feature cannot be %select{introduced|deprecated|obsoleted}0 in %1 version " + "%2 before it was %select{introduced|deprecated|obsoleted}3 in version %4; " + "attribute ignored">; + +// Thread Safety Attributes +// Errors when parsing the attributes +def err_attribute_argument_out_of_range : Error< + "%0 attribute parameter %1 is out of bounds: " + "%plural{0:no parameters to index into|" + "1:can only be 1, since there is one parameter|" + ":must be between 1 and %2}2">; +def warn_attribute_argument_not_lockable : Warning< + "%0 attribute requires arguments whose type is annotated " + "with 'lockable' attribute; type here is '%1'">, + InGroup<ThreadSafety>, DefaultIgnore; +def warn_attribute_decl_not_lockable : Warning< + "%0 attribute can only be applied in a context annotated " + "with 'lockable' attribute">, + InGroup<ThreadSafety>, DefaultIgnore; +def warn_attribute_argument_not_class : Warning< + "%0 attribute requires arguments that are class type or point to" + " class type; type here is '%1'">, + InGroup<ThreadSafety>, DefaultIgnore; +def warn_unlock_but_no_lock : Warning< + "unlocking '%0' that was not locked">, + InGroup<ThreadSafety>, DefaultIgnore; +def warn_double_lock : Warning< + "locking '%0' that is already locked">, + InGroup<ThreadSafety>, DefaultIgnore; +def warn_no_unlock : Warning< + "mutex '%0' is still locked at the end of function">, + InGroup<ThreadSafety>, DefaultIgnore; +// FIXME: improve the error message about locks not in scope +def warn_lock_some_predecessors : Warning< + "mutex '%0' is not locked on every path through here">, + InGroup<ThreadSafety>, DefaultIgnore; +def warn_expecting_lock_held_on_loop : Warning< + "expecting mutex '%0' to be locked at start of each loop">, + InGroup<ThreadSafety>, DefaultIgnore; +def note_locked_here : Note<"mutex acquired here">; +def warn_lock_exclusive_and_shared : Warning< + "mutex '%0' is locked exclusively and shared in the same scope">, + InGroup<ThreadSafety>, DefaultIgnore; +def note_lock_exclusive_and_shared : Note< + "the other lock of mutex '%0' is here">, + InGroup<ThreadSafety>, DefaultIgnore; +def warn_variable_requires_lock : Warning< + "%select{reading|writing}2 variable '%0' requires locking " + "%select{'%1'|'%1' exclusively}2">, + InGroup<ThreadSafety>, DefaultIgnore; +def warn_var_deref_requires_lock : Warning< + "%select{reading|writing}2 the value pointed to by '%0' requires locking " + "%select{'%1'|'%1' exclusively}2">, + InGroup<ThreadSafety>, DefaultIgnore; +def warn_variable_requires_any_lock : Warning< + "%select{reading|writing}1 variable '%0' requires locking " + "%select{any mutex|any mutex exclusively}1">, + InGroup<ThreadSafety>, DefaultIgnore; +def warn_var_deref_requires_any_lock : Warning< + "%select{reading|writing}1 the value pointed to by '%0' requires locking " + "%select{any mutex|any mutex exclusively}1">, + InGroup<ThreadSafety>, DefaultIgnore; +def warn_fun_requires_lock : Warning< + "calling function '%0' requires %select{shared|exclusive}2 lock on '%1'">, + InGroup<ThreadSafety>, DefaultIgnore; +def warn_fun_excludes_mutex : Warning< + "cannot call function '%0' while mutex '%1' is locked">, + InGroup<ThreadSafety>, DefaultIgnore; +def warn_cannot_resolve_lock : Warning< + "cannot resolve lock expression">, + InGroup<ThreadSafety>, DefaultIgnore; + + +def warn_impcast_vector_scalar : Warning< + "implicit conversion turns vector to scalar: %0 to %1">, + InGroup<DiagGroup<"conversion">>, DefaultIgnore; +def warn_impcast_complex_scalar : Warning< + "implicit conversion discards imaginary component: %0 to %1">, + InGroup<DiagGroup<"conversion">>, DefaultIgnore; +def warn_impcast_float_precision : Warning< + "implicit conversion loses floating-point precision: %0 to %1">, + InGroup<DiagGroup<"conversion">>, DefaultIgnore; +def warn_impcast_float_integer : Warning< + "implicit conversion turns floating-point number into integer: %0 to %1">, + InGroup<DiagGroup<"conversion">>, DefaultIgnore; +def warn_impcast_integer_sign : Warning< + "implicit conversion changes signedness: %0 to %1">, + InGroup<SignConversion>, DefaultIgnore; +def warn_impcast_integer_sign_conditional : Warning< + "operand of ? changes signedness: %0 to %1">, + InGroup<SignConversion>, DefaultIgnore; +def warn_impcast_integer_precision : Warning< + "implicit conversion loses integer precision: %0 to %1">, + InGroup<DiagGroup<"conversion">>, DefaultIgnore; +def warn_impcast_integer_64_32 : Warning< + "implicit conversion loses integer precision: %0 to %1">, + InGroup<DiagGroup<"shorten-64-to-32">>, DefaultIgnore; +def warn_impcast_integer_precision_constant : Warning< + "implicit conversion from %2 to %3 changes value from %0 to %1">, + InGroup<ConstantConversion>; +def warn_impcast_bitfield_precision_constant : Warning< + "implicit truncation from %2 to bitfield changes value from %0 to %1">, + InGroup<ConstantConversion>; +def warn_impcast_literal_float_to_integer : Warning< + "implicit conversion turns literal floating-point number into integer: " + "%0 to %1">, + InGroup<LiteralConversion>; +def warn_impcast_string_literal_to_bool : Warning< + "implicit conversion turns string literal into bool: %0 to %1">, + InGroup<StringConversion>, DefaultIgnore; +def warn_impcast_different_enum_types : Warning< + "implicit conversion from enumeration type %0 to different enumeration type " + "%1">, InGroup<DiagGroup<"conversion">>; +def warn_impcast_bool_to_null_pointer : Warning< + "initialization of pointer of type %0 to null from a constant boolean " + "expression">, InGroup<BoolConversion>; +def warn_impcast_null_pointer_to_integer : Warning< + "implicit conversion of NULL constant to %0">, + InGroup<NullConversion>; +def warn_impcast_function_to_bool : Warning< + "address of function %q0 will always evaluate to 'true'">, + InGroup<BoolConversion>; +def note_function_to_bool_silence : Note< + "prefix with the address-of operator to silence this warning">; +def note_function_to_bool_call : Note< + "suffix with parentheses to turn this into a function call">; + +def warn_cast_align : Warning< + "cast from %0 to %1 increases required alignment from %2 to %3">, + InGroup<CastAlign>, DefaultIgnore; + +def warn_attribute_ignored_for_field_of_type : Warning< + "%0 attribute ignored for field of type %1">; +def warn_transparent_union_attribute_field_size_align : Warning< + "%select{alignment|size}0 of field %1 (%2 bits) does not match the " + "%select{alignment|size}0 of the first field in transparent union; " + "transparent_union attribute ignored">; +def note_transparent_union_first_field_size_align : Note< + "%select{alignment|size}0 of first field is %1 bits">; +def warn_transparent_union_attribute_not_definition : Warning< + "transparent_union attribute can only be applied to a union definition; " + "attribute ignored">; +def warn_transparent_union_attribute_floating : Warning< + "first field of a transparent union cannot have %select{floating point|" + "vector}0 type %1; transparent_union attribute ignored">; +def warn_transparent_union_attribute_zero_fields : Warning< + "transparent union definition must contain at least one field; " + "transparent_union attribute ignored">; +def warn_attribute_type_not_supported : Warning< + "'%0' attribute argument not supported: %1">; +def warn_attribute_unknown_visibility : Warning<"unknown visibility '%0'">; +def warn_attribute_protected_visibility : + Warning<"target does not support 'protected' visibility; using 'default'">, + InGroup<DiagGroup<"unsupported-visibility">>; +def err_unknown_machine_mode : Error<"unknown machine mode %0">; +def err_unsupported_machine_mode : Error<"unsupported machine mode %0">; +def err_mode_not_primitive : Error< + "mode attribute only supported for integer and floating-point types">; +def err_mode_wrong_type : Error< + "type of machine mode does not match type of base type">; +def err_attr_wrong_decl : Error< + "'%0' attribute invalid on this declaration, requires typedef or value">; +def warn_attribute_nonnull_no_pointers : Warning< + "'nonnull' attribute applied to function with no pointer arguments">; +def warn_attribute_malloc_pointer_only : Warning< + "'malloc' attribute only applies to functions returning a pointer type">; +def warn_attribute_sentinel_named_arguments : Warning< + "'sentinel' attribute requires named arguments">; +def warn_attribute_sentinel_not_variadic : Warning< + "'sentinel' attribute only supported for variadic %select{functions|blocks}0">; +def err_attribute_sentinel_less_than_zero : Error< + "'sentinel' parameter 1 less than zero">; +def err_attribute_sentinel_not_zero_or_one : Error< + "'sentinel' parameter 2 not 0 or 1">; +def err_attribute_cleanup_arg_not_found : Error< + "'cleanup' argument %0 not found">; +def err_attribute_cleanup_arg_not_function : Error< + "'cleanup' argument %0 is not a function">; +def err_attribute_cleanup_func_must_take_one_arg : Error< + "'cleanup' function %0 must take 1 parameter">; +def err_attribute_cleanup_func_arg_incompatible_type : Error< + "'cleanup' function %0 parameter has type %1 which is incompatible with " + "type %2">; +def err_attribute_regparm_wrong_platform : Error< + "'regparm' is not valid on this platform">; +def err_attribute_regparm_invalid_number : Error< + "'regparm' parameter must be between 0 and %0 inclusive">; + + +// Clang-Specific Attributes +def warn_attribute_iboutlet : Warning< + "%0 attribute can only be applied to instance variables or properties">; +def warn_attribute_ibaction: Warning< + "ibaction attribute can only be applied to Objective-C instance methods">; +def err_iboutletcollection_type : Error< + "invalid type %0 as argument of iboutletcollection attribute">; +def warn_iboutlet_object_type : Warning< + "%select{ivar|property}2 with %0 attribute must " + "be an object type (invalid %1)">, + InGroup<DiagGroup<"invalid-iboutlet">>; +def err_attribute_overloadable_not_function : Error< + "'overloadable' attribute can only be applied to a function">; +def err_attribute_overloadable_missing : Error< + "%select{overloaded function|redeclaration of}0 %1 must have the " + "'overloadable' attribute">; +def note_attribute_overloadable_prev_overload : Note< + "previous overload of function is here">; +def err_attribute_overloadable_no_prototype : Error< + "'overloadable' function %0 must have a prototype">; +def warn_ns_attribute_wrong_return_type : Warning< + "%0 attribute only applies to %select{functions|methods}1 that " + "return %select{an Objective-C object|a pointer|a non-retainable pointer}2">; +def warn_ns_attribute_wrong_parameter_type : Warning< + "%0 attribute only applies to %select{Objective-C object|pointer}1 " + "parameters">; +def err_ns_bridged_not_interface : Error< + "parameter of 'ns_bridged' attribute does not name an Objective-C class">; + +// Function Parameter Semantic Analysis. +def err_param_with_void_type : Error<"argument may not have 'void' type">; +def err_void_only_param : Error< + "'void' must be the first and only parameter if specified">; +def err_void_param_qualified : Error< + "'void' as parameter must not have type qualifiers">; +def err_ident_list_in_fn_declaration : Error< + "a parameter list without types is only allowed in a function definition">; +def ext_param_not_declared : Extension< + "parameter %0 was not declared, defaulting to type 'int'">; +def err_param_typedef_of_void : Error< + "empty parameter list defined with a %select{typedef|type alias}0 of 'void' not allowed%select{ in C++|}0">; +def err_param_default_argument : Error< + "C does not support default arguments">; +def err_param_default_argument_redefinition : Error< + "redefinition of default argument">; +def warn_param_default_argument_redefinition : ExtWarn< + "redefinition of default argument">; +def err_param_default_argument_missing : Error< + "missing default argument on parameter">; +def err_param_default_argument_missing_name : Error< + "missing default argument on parameter %0">; +def err_param_default_argument_references_param : Error< + "default argument references parameter %0">; +def err_param_default_argument_references_local : Error< + "default argument references local variable %0 of enclosing function">; +def err_param_default_argument_references_this : Error< + "default argument references 'this'">; +def err_param_default_argument_nonfunc : Error< + "default arguments can only be specified for parameters in a function " + "declaration">; +def err_param_default_argument_template_redecl : Error< + "default arguments cannot be added to a function template that has already " + "been declared">; +def err_param_default_argument_member_template_redecl : Error< + "default arguments cannot be added to an out-of-line definition of a member " + "of a %select{class template|class template partial specialization|nested " + "class in a template}0">; +def err_uninitialized_member_for_assign : Error< + "cannot define the implicit default assignment operator for %0, because " + "non-static %select{reference|const}1 member %2 can't use default " + "assignment operator">; +def err_uninitialized_member_in_ctor : Error< + "%select{|implicit default }0constructor for %1 must explicitly initialize " + "the %select{reference|const}2 member %3">; +def warn_default_arg_makes_ctor_special : Warning< + "addition of default argument on redeclaration makes this constructor a " + "%select{default|copy|move}0 constructor">, InGroup<DefaultArgSpecialMember>; +def note_previous_declaration_special : Note< + // The ERRORs are in hopes that if they occur, they'll get reported. + "previous declaration was %select{*ERROR*|a copy constructor|a move " + "constructor|*ERROR*|*ERROR*|*ERROR*|not a special member function}0">; + +def err_use_of_default_argument_to_function_declared_later : Error< + "use of default argument to function %0 that is declared later in class %1">; +def note_default_argument_declared_here : Note< + "default argument declared here">; + +def ext_param_promoted_not_compatible_with_prototype : ExtWarn< + "promoted type %0 of K&R function parameter is not compatible with the " + "parameter type %1 declared in a previous prototype">, + InGroup<KNRPromotedParameter>; + + +// C++ Overloading Semantic Analysis. +def err_ovl_diff_return_type : Error< + "functions that differ only in their return type cannot be overloaded">; +def err_ovl_static_nonstatic_member : Error< + "static and non-static member functions with the same parameter types " + "cannot be overloaded">; + +def err_ovl_no_viable_function_in_call : Error< + "no matching function for call to %0">; +def err_ovl_no_viable_member_function_in_call : Error< + "no matching member function for call to %0">; +def err_ovl_ambiguous_call : Error< + "call to %0 is ambiguous">; +def err_ovl_deleted_call : Error< + "call to %select{unavailable|deleted}0 function %1%2">; +def err_ovl_ambiguous_member_call : Error< + "call to member function %0 is ambiguous">; +def err_ovl_deleted_member_call : Error< + "call to %select{unavailable|deleted}0 member function %1%2">; +def note_ovl_too_many_candidates : Note< + "remaining %0 candidate%s0 omitted; " + "pass -fshow-overloads=all to show them">; +def note_ovl_candidate : Note<"candidate " + "%select{function|function|constructor|" + "function |function |constructor |" + "is the implicit default constructor|" + "is the implicit copy constructor|" + "is the implicit move constructor|" + "is the implicit copy assignment operator|" + "is the implicit move assignment operator|" + "is an inherited constructor}0%1" + "%select{| has different class (expected %3 but has %4)" + "| has different number of parameters (expected %3 but has %4)" + "| has type mismatch at %ordinal3 parameter (expected %4 but has %5)" + "| has different return type (%3 expected but has %4)" + "| has different qualifiers (expected " + "%select{none|const|restrict|const and restrict|volatile|const and volatile" + "|volatile and restrict|const, volatile, and restrict}3 but found " + "%select{none|const|restrict|const and restrict|volatile|const and volatile" + "|volatile and restrict|const, volatile, and restrict}4)}2">; + +def note_ovl_candidate_inherited_constructor : Note<"inherited from here">; +def note_ovl_candidate_bad_deduction : Note< + "candidate template ignored: failed template argument deduction">; +def note_ovl_candidate_incomplete_deduction : Note<"candidate template ignored: " + "couldn't infer template argument %0">; +def note_ovl_candidate_inconsistent_deduction : Note< + "candidate template ignored: deduced conflicting %select{types|values|" + "templates}0 for parameter %1 (%2 vs. %3)">; +def note_ovl_candidate_explicit_arg_mismatch_named : Note< + "candidate template ignored: invalid explicitly-specified argument " + "for template parameter %0">; +def note_ovl_candidate_explicit_arg_mismatch_unnamed : Note< + "candidate template ignored: invalid explicitly-specified argument " + "for %ordinal0 template parameter">; +def note_ovl_candidate_instantiation_depth : Note< + "candidate template ignored: substitution exceeded maximum template " + "instantiation depth">; +def note_ovl_candidate_underqualified : Note< + "candidate template ignored: can't deduce a type for %0 which would " + "make %2 equal %1">; +def note_ovl_candidate_substitution_failure : Note< + "candidate template ignored: substitution failure %0">; + +// Note that we don't treat templates differently for this diagnostic. +def note_ovl_candidate_arity : Note<"candidate " + "%select{function|function|constructor|function|function|constructor|" + "constructor (the implicit default constructor)|" + "constructor (the implicit copy constructor)|" + "constructor (the implicit move constructor)|" + "function (the implicit copy assignment operator)|" + "function (the implicit move assignment operator)|" + "constructor (inherited)}0 %select{|template }1" + "not viable: requires%select{ at least| at most|}2 %3 argument%s3, but %4 " + "%plural{1:was|:were}4 provided">; + +def note_ovl_candidate_deleted : Note< + "candidate %select{function|function|constructor|" + "function |function |constructor |" + "constructor (the implicit default constructor)|" + "constructor (the implicit copy constructor)|" + "constructor (the implicit move constructor)|" + "function (the implicit copy assignment operator)|" + "function (the implicit move assignment operator)|" + "constructor (inherited)}0%1 has been " + "%select{explicitly made unavailable|explicitly deleted|" + "implicitly deleted}2">; + +// Giving the index of the bad argument really clutters this message, and +// it's relatively unimportant because 1) it's generally obvious which +// argument(s) are of the given object type and 2) the fix is usually +// to complete the type, which doesn't involve changes to the call line +// anyway. If people complain, we can change it. +def note_ovl_candidate_bad_conv_incomplete : Note<"candidate " + "%select{function|function|constructor|" + "function |function |constructor |" + "constructor (the implicit default constructor)|" + "constructor (the implicit copy constructor)|" + "constructor (the implicit move constructor)|" + "function (the implicit copy assignment operator)|" + "function (the implicit move assignment operator)|" + "constructor (inherited)}0%1 " + "not viable: cannot convert argument of incomplete type %2 to %3">; +def note_ovl_candidate_bad_list_argument : Note<"candidate " + "%select{function|function|constructor|" + "function |function |constructor |" + "constructor (the implicit default constructor)|" + "constructor (the implicit copy constructor)|" + "constructor (the implicit move constructor)|" + "function (the implicit copy assignment operator)|" + "function (the implicit move assignment operator)|" + "constructor (inherited)}0%1 " + "not viable: cannot convert initializer list argument to %3">; +def note_ovl_candidate_bad_overload : Note<"candidate " + "%select{function|function|constructor|" + "function |function |constructor |" + "constructor (the implicit default constructor)|" + "constructor (the implicit copy constructor)|" + "constructor (the implicit move constructor)|" + "function (the implicit copy assignment operator)|" + "function (the implicit move assignment operator)|" + "constructor (inherited)}0%1" + " not viable: no overload of %3 matching %2 for %ordinal4 argument">; +def note_ovl_candidate_bad_conv : Note<"candidate " + "%select{function|function|constructor|" + "function |function |constructor |" + "constructor (the implicit default constructor)|" + "constructor (the implicit copy constructor)|" + "constructor (the implicit move constructor)|" + "function (the implicit copy assignment operator)|" + "function (the implicit move assignment operator)|" + "constructor (inherited)}0%1" + " not viable: no known conversion from %2 to %3 for " + "%select{%ordinal5 argument|object argument}4; " + "%select{|dereference the argument with *|" + "take the address of the argument with &|" + "remove *|" + "remove &}6">; +def note_ovl_candidate_bad_arc_conv : Note<"candidate " + "%select{function|function|constructor|" + "function |function |constructor |" + "constructor (the implicit default constructor)|" + "constructor (the implicit copy constructor)|" + "constructor (the implicit move constructor)|" + "function (the implicit copy assignment operator)|" + "function (the implicit move assignment operator)|" + "constructor (inherited)}0%1" + " not viable: cannot implicitly convert argument of type %2 to %3 for " + "%select{%ordinal5 argument|object argument}4 under ARC">; +def note_ovl_candidate_bad_addrspace : Note<"candidate " + "%select{function|function|constructor|" + "function |function |constructor |" + "constructor (the implicit default constructor)|" + "constructor (the implicit copy constructor)|" + "constructor (the implicit move constructor)|" + "function (the implicit copy assignment operator)|" + "function (the implicit move assignment operator)|" + "constructor (inherited)}0%1 not viable: " + "%select{%ordinal6|'this'}5 argument (%2) is in " + "address space %3, but parameter must be in address space %4">; +def note_ovl_candidate_bad_gc : Note<"candidate " + "%select{function|function|constructor|" + "function |function |constructor |" + "constructor (the implicit default constructor)|" + "constructor (the implicit copy constructor)|" + "constructor (the implicit move constructor)|" + "function (the implicit copy assignment operator)|" + "function (the implicit move assignment operator)|" + "constructor (inherited)}0%1 not viable: " + "%select{%ordinal6|'this'}5 argument (%2) has %select{no|__weak|__strong}3 " + "ownership, but parameter has %select{no|__weak|__strong}4 ownership">; +def note_ovl_candidate_bad_ownership : Note<"candidate " + "%select{function|function|constructor|" + "function |function |constructor |" + "constructor (the implicit default constructor)|" + "constructor (the implicit copy constructor)|" + "constructor (the implicit move constructor)|" + "function (the implicit copy assignment operator)|" + "function (the implicit move assignment operator)|" + "constructor (inherited)}0%1 not viable: " + "%select{%ordinal6|'this'}5 argument (%2) has " + "%select{no|__unsafe_unretained|__strong|__weak|__autoreleasing}3 ownership," + " but parameter has %select{no|__unsafe_unretained|__strong|__weak|" + "__autoreleasing}4 ownership">; +def note_ovl_candidate_bad_cvr_this : Note<"candidate " + "%select{|function|||function|||||" + "function (the implicit copy assignment operator)|" + "function (the implicit move assignment operator)|}0 not viable: " + "'this' argument has type %2, but method is not marked " + "%select{const|restrict|const or restrict|volatile|const or volatile|" + "volatile or restrict|const, volatile, or restrict}3">; +def note_ovl_candidate_bad_cvr : Note<"candidate " + "%select{function|function|constructor|" + "function |function |constructor |" + "constructor (the implicit default constructor)|" + "constructor (the implicit copy constructor)|" + "constructor (the implicit move constructor)|" + "function (the implicit copy assignment operator)|" + "function (the implicit move assignment operator)|" + "constructor (inherited)}0%1 not viable: " + "%ordinal4 argument (%2) would lose " + "%select{const|restrict|const and restrict|volatile|const and volatile|" + "volatile and restrict|const, volatile, and restrict}3 qualifier" + "%select{||s||s|s|s}3">; +def note_ovl_candidate_bad_base_to_derived_conv : Note<"candidate " + "%select{function|function|constructor|" + "function |function |constructor |" + "constructor (the implicit default constructor)|" + "constructor (the implicit copy constructor)|" + "constructor (the implicit move constructor)|" + "function (the implicit copy assignment operator)|" + "function (the implicit move assignment operator)|" + "constructor (inherited)}0%1" + " not viable: cannot %select{convert from|convert from|bind}2 " + "%select{base class pointer|superclass|base class object of type}2 %3 to " + "%select{derived class pointer|subclass|derived class reference}2 %4 for " + "%ordinal5 argument">; +def note_ovl_candidate_bad_target : Note< + "candidate %select{function|function|constructor|" + "function |function |constructor |" + "constructor (the implicit default constructor)|" + "constructor (the implicit copy constructor)|" + "constructor (the implicit move constructor)|" + "function (the implicit copy assignment operator)|" + "function (the implicit move assignment operator)|" + "constructor (inherited)}0 not viable: call to " + "%select{__device__|__global__|__host__|__host__ __device__}1 function from" + " %select{__device__|__global__|__host__|__host__ __device__}2 function">; + +def note_ambiguous_type_conversion: Note< + "because of ambiguity in conversion of %0 to %1">; +def note_ovl_builtin_binary_candidate : Note< + "built-in candidate %0">; +def note_ovl_builtin_unary_candidate : Note< + "built-in candidate %0">; +def err_ovl_no_viable_function_in_init : Error< + "no matching constructor for initialization of %0">; +def err_ovl_no_conversion_in_cast : Error< + "cannot convert %1 to %2 without a conversion operator">; +def err_ovl_no_viable_conversion_in_cast : Error< + "no matching conversion for %select{|static_cast|reinterpret_cast|" + "dynamic_cast|C-style cast|functional-style cast}0 from %1 to %2">; +def err_ovl_ambiguous_conversion_in_cast : Error< + "ambiguous conversion for %select{|static_cast|reinterpret_cast|" + "dynamic_cast|C-style cast|functional-style cast}0 from %1 to %2">; +def err_ovl_deleted_conversion_in_cast : Error< + "%select{|static_cast|reinterpret_cast|dynamic_cast|C-style cast|" + "functional-style cast}0 from %1 to %2 uses deleted function">; +def err_ovl_ambiguous_init : Error<"call to constructor of %0 is ambiguous">; +def err_ref_init_ambiguous : Error< + "reference initialization of type %0 with initializer of type %1 is ambiguous">; +def err_ovl_deleted_init : Error< + "call to %select{unavailable|deleted}0 constructor of %1">; +def err_ovl_deleted_special_init : Error< + "call to implicitly-deleted %select{default constructor|copy constructor|" + "move constructor|copy assignment operator|move assignment operator|" + "destructor|function}0 of %1">; +def err_ovl_ambiguous_oper_unary : Error< + "use of overloaded operator '%0' is ambiguous (operand type %1)">; +def err_ovl_ambiguous_oper_binary : Error< + "use of overloaded operator '%0' is ambiguous (with operand types %1 and %2)">; +def err_ovl_no_viable_oper : Error<"no viable overloaded '%0'">; +def err_ovl_deleted_oper : Error< + "overload resolution selected %select{unavailable|deleted}0 operator '%1'%2">; +def err_ovl_deleted_special_oper : Error< + "overload resolution selected implicitly-deleted %select{default constructor|" + "copy constructor|move constructor|copy assignment operator|move assignment " + "operator|destructor|'%1'}0%2">; +def err_ovl_no_viable_subscript : + Error<"no viable overloaded operator[] for type %0">; +def err_ovl_no_oper : + Error<"type %0 does not provide a %select{subscript|call}1 operator">; +def err_ovl_unresolvable : Error< + "reference to overloaded function could not be resolved; " + "did you mean to call it%select{| with no arguments}0?">; +def err_bound_member_function : Error< + "reference to non-static member function must be called" + "%select{|; did you mean to call it with no arguments?}0">; +def note_possible_target_of_call : Note<"possible target for call">; + +def err_ovl_no_viable_object_call : Error< + "no matching function for call to object of type %0">; +def err_ovl_ambiguous_object_call : Error< + "call to object of type %0 is ambiguous">; +def err_ovl_deleted_object_call : Error< + "call to %select{unavailable|deleted}0 function call operator in type %1%2">; +def note_ovl_surrogate_cand : Note<"conversion candidate of type %0">; +def err_member_call_without_object : Error< + "call to non-static member function without an object argument">; + +// C++ Address of Overloaded Function +def err_addr_ovl_no_viable : Error< + "address of overloaded function %0 does not match required type %1">; +def err_addr_ovl_ambiguous : Error< + "address of overloaded function %0 is ambiguous">; +def err_addr_ovl_not_func_ptrref : Error< + "address of overloaded function %0 cannot be converted to type %1">; +def err_addr_ovl_no_qualifier : Error< + "can't form member pointer of type %0 without '&' and class name">; + +// C++11 Literal Operators +def err_ovl_no_viable_literal_operator : Error< + "no matching literal operator for call to %0" + "%select{| with argument of type %2| with arguments of types %2 and %3}1" + "%select{| or 'const char *', and no matching literal operator template}4">; + +// C++ Template Declarations +def err_template_param_shadow : Error< + "declaration of %0 shadows template parameter">; +def note_template_param_here : Note<"template parameter is declared here">; +def warn_template_export_unsupported : Warning< + "exported templates are unsupported">; +def err_template_outside_namespace_or_class_scope : Error< + "templates can only be declared in namespace or class scope">; +def err_template_linkage : Error<"templates must have C++ linkage">; +def err_template_typedef : Error<"a typedef cannot be a template">; +def err_template_unnamed_class : Error< + "cannot declare a class template with no name">; +def err_template_param_list_different_arity : Error< + "%select{too few|too many}0 template parameters in template " + "%select{|template parameter }1redeclaration">; +def note_template_param_list_different_arity : Note< + "%select{too few|too many}0 template parameters in template template " + "argument">; +def note_template_prev_declaration : Note< + "previous template %select{declaration|template parameter}0 is here">; +def err_template_param_different_kind : Error< + "template parameter has a different kind in template " + "%select{|template parameter }0redeclaration">; +def note_template_param_different_kind : Note< + "template parameter has a different kind in template argument">; + +def err_template_nontype_parm_different_type : Error< + "template non-type parameter has a different type %0 in template " + "%select{|template parameter }1redeclaration">; + +def note_template_nontype_parm_different_type : Note< + "template non-type parameter has a different type %0 in template argument">; +def note_template_nontype_parm_prev_declaration : Note< + "previous non-type template parameter with type %0 is here">; +def err_template_nontype_parm_bad_type : Error< + "a non-type template parameter cannot have type %0">; +def err_template_param_default_arg_redefinition : Error< + "template parameter redefines default argument">; +def note_template_param_prev_default_arg : Note< + "previous default template argument defined here">; +def err_template_param_default_arg_missing : Error< + "template parameter missing a default argument">; +def ext_template_parameter_default_in_function_template : ExtWarn< + "default template arguments for a function template are a C++11 extension">, + InGroup<CXX11>; +def warn_cxx98_compat_template_parameter_default_in_function_template : Warning< + "default template arguments for a function template are incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def err_template_parameter_default_template_member : Error< + "cannot add a default template argument to the definition of a member of a " + "class template">; +def err_template_parameter_default_friend_template : Error< + "default template argument not permitted on a friend template">; +def err_template_template_parm_no_parms : Error< + "template template parameter must have its own template parameters">; + +def err_template_variable : Error<"variable %0 declared as a template">; +def err_template_variable_noparams : Error< + "extraneous 'template<>' in declaration of variable %0">; +def err_template_member : Error<"member %0 declared as a template">; +def err_template_member_noparams : Error< + "extraneous 'template<>' in declaration of member %0">; +def err_template_tag_noparams : Error< + "extraneous 'template<>' in declaration of %0 %1">; +def err_template_decl_ref : Error< + "cannot refer to class template %0 without a template argument list">; + +// C++ Template Argument Lists +def err_template_missing_args : Error< + "use of class template %0 requires template arguments">; +def err_template_arg_list_different_arity : Error< + "%select{too few|too many}0 template arguments for " + "%select{class template|function template|template template parameter" + "|template}1 %2">; +def note_template_decl_here : Note<"template is declared here">; +def note_member_of_template_here : Note<"member is declared here">; +def err_template_arg_must_be_type : Error< + "template argument for template type parameter must be a type">; +def err_template_arg_must_be_expr : Error< + "template argument for non-type template parameter must be an expression">; +def err_template_arg_nontype_ambig : Error< + "template argument for non-type template parameter is treated as type %0">; +def err_template_arg_must_be_template : Error< + "template argument for template template parameter must be a class template%select{| or type alias template}0">; +def ext_template_arg_local_type : ExtWarn< + "template argument uses local type %0">, InGroup<LocalTypeTemplateArgs>; +def ext_template_arg_unnamed_type : ExtWarn< + "template argument uses unnamed type">, InGroup<UnnamedTypeTemplateArgs>; +def warn_cxx98_compat_template_arg_local_type : Warning< + "local type %0 as template argument is incompatible with C++98">, + InGroup<CXX98CompatLocalTypeTemplateArgs>, DefaultIgnore; +def warn_cxx98_compat_template_arg_unnamed_type : Warning< + "unnamed type as template argument is incompatible with C++98">, + InGroup<CXX98CompatUnnamedTypeTemplateArgs>, DefaultIgnore; +def note_template_unnamed_type_here : Note< + "unnamed type used in template argument was declared here">; +def err_template_arg_overload_type : Error< + "template argument is the type of an unresolved overloaded function">; +def err_template_arg_not_class_template : Error< + "template argument does not refer to a class template or template " + "template parameter">; +def note_template_arg_refers_here_func : Note< + "template argument refers to function template %0, here">; +def err_template_arg_template_params_mismatch : Error< + "template template argument has different template parameters than its " + "corresponding template template parameter">; +def err_template_arg_not_integral_or_enumeral : Error< + "non-type template argument of type %0 must have an integral or enumeration" + " type">; +def err_template_arg_not_ice : Error< + "non-type template argument of type %0 is not an integral constant " + "expression">; +def err_template_arg_not_address_constant : Error< + "non-type template argument of type %0 is not a constant expression">; +def err_template_arg_untyped_null_constant : Error< + "null non-type template argument must be cast to template parameter type %0">; +def err_template_arg_wrongtype_null_constant : Error< + "null non-type template argument of type %0 does not match template parameter " + "of type %1">; +def err_deduced_non_type_template_arg_type_mismatch : Error< + "deduced non-type template argument does not have the same type as the " + "its corresponding template parameter (%0 vs %1)">; +def err_template_arg_not_convertible : Error< + "non-type template argument of type %0 cannot be converted to a value " + "of type %1">; +def warn_template_arg_negative : Warning< + "non-type template argument with value '%0' converted to '%1' for unsigned " + "template parameter of type %2">, InGroup<Conversion>, DefaultIgnore; +def warn_template_arg_too_large : Warning< + "non-type template argument value '%0' truncated to '%1' for " + "template parameter of type %2">, InGroup<Conversion>, DefaultIgnore; +def err_template_arg_no_ref_bind : Error< + "non-type template parameter of reference type %0 cannot bind to template " + "argument of type %1">; +def err_template_arg_ref_bind_ignores_quals : Error< + "reference binding of non-type template parameter of type %0 to template " + "argument of type %1 ignores qualifiers">; +def err_template_arg_not_decl_ref : Error< + "non-type template argument does not refer to any declaration">; +def err_template_arg_not_object_or_func_form : Error< + "non-type template argument does not directly refer to an object or " + "function">; +def err_template_arg_not_address_of : Error< + "non-type template argument for template parameter of pointer type %0 must " + "have its address taken">; +def err_template_arg_address_of_non_pointer : Error< + "address taken in non-type template argument for template parameter of " + "reference type %0">; +def err_template_arg_reference_var : Error< + "non-type template argument of reference type %0 is not an object">; +def err_template_arg_field : Error< + "non-type template argument refers to non-static data member %0">; +def err_template_arg_method : Error< + "non-type template argument refers to non-static member function %0">; +def err_template_arg_object_no_linkage : Error< + "non-type template argument refers to %select{function|object}0 %1 that " + "does not have linkage">; +def warn_cxx98_compat_template_arg_object_internal : Warning< + "non-type template argument referring to %select{function|object}0 %1 with " + "internal linkage is incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def ext_template_arg_object_internal : ExtWarn< + "non-type template argument referring to %select{function|object}0 %1 with " + "internal linkage is a C++11 extension">, InGroup<CXX11>; +def err_template_arg_thread_local : Error< + "non-type template argument refers to thread-local object">; +def note_template_arg_internal_object : Note< + "non-type template argument refers to %select{function|object}0 here">; +def note_template_arg_refers_here : Note< + "non-type template argument refers here">; +def err_template_arg_not_object_or_func : Error< + "non-type template argument does not refer to an object or function">; +def err_template_arg_not_pointer_to_member_form : Error< + "non-type template argument is not a pointer to member constant">; +def ext_template_arg_extra_parens : ExtWarn< + "address non-type template argument cannot be surrounded by parentheses">; +def warn_cxx98_compat_template_arg_extra_parens : Warning< + "redundant parentheses surrounding address non-type template argument are " + "incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore; +def err_pointer_to_member_type : Error< + "invalid use of pointer to member type after %select{.*|->*}0">; +def err_pointer_to_member_call_drops_quals : Error< + "call to pointer to member function of type %0 drops '%1' qualifier%s2">; +def err_pointer_to_member_oper_value_classify: Error< + "pointer-to-member function type %0 can only be called on an " + "%select{rvalue|lvalue}1">; + +// C++ template specialization +def err_template_spec_unknown_kind : Error< + "can only provide an explicit specialization for a class template, function " + "template, or a member function, static data member, " + "%select{or member class|member class, or member enumeration}0 of a " + "class template">; +def note_specialized_entity : Note< + "explicitly specialized declaration is here">; +def err_template_spec_decl_function_scope : Error< + "explicit specialization of %0 in function scope">; +def err_template_spec_decl_class_scope : Error< + "explicit specialization of %0 in class scope">; +def err_template_spec_decl_friend : Error< + "cannot declare an explicit specialization in a friend">; +def err_template_spec_decl_out_of_scope_global : Error< + "%select{class template|class template partial|function template|member " + "function|static data member|member class|member enumeration}0 " + "specialization of %1 must originally be declared in the global scope">; +def err_template_spec_decl_out_of_scope : Error< + "%select{class template|class template partial|function template|member " + "function|static data member|member class|member enumeration}0 " + "specialization of %1 must originally be declared in namespace %2">; +def ext_template_spec_decl_out_of_scope : ExtWarn< + "first declaration of %select{class template|class template partial|" + "function template|member function|static data member|member class|" + "member enumeration}0 specialization of %1 outside namespace %2 is a " + "C++11 extension">, InGroup<CXX11>; +def warn_cxx98_compat_template_spec_decl_out_of_scope : Warning< + "%select{class template|class template partial|function template|member " + "function|static data member|member class|member enumeration}0 " + "specialization of %1 outside namespace %2 is incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def err_template_spec_redecl_out_of_scope : Error< + "%select{class template|class template partial|function template|member " + "function|static data member|member class|member enumeration}0 " + "specialization of %1 not in a namespace enclosing %2">; +def err_template_spec_redecl_global_scope : Error< + "%select{class template|class template partial|function template|member " + "function|static data member|member class|member enumeration}0 " + "specialization of %1 must occur at global scope">; +def err_spec_member_not_instantiated : Error< + "specialization of member %q0 does not specialize an instantiated member">; +def note_specialized_decl : Note<"attempt to specialize declaration here">; +def err_specialization_after_instantiation : Error< + "explicit specialization of %0 after instantiation">; +def note_instantiation_required_here : Note< + "%select{implicit|explicit}0 instantiation first required here">; +def err_template_spec_friend : Error< + "template specialization declaration cannot be a friend">; +def err_template_spec_default_arg : Error< + "default argument not permitted on an explicit " + "%select{instantiation|specialization}0 of function %1">; +def err_not_class_template_specialization : Error< + "cannot specialize a %select{dependent template|template template " + "parameter}0">; +def err_function_specialization_in_class : Error< + "cannot specialize a function %0 within class scope">; +def ext_function_specialization_in_class : ExtWarn< + "explicit specialization of %0 within class scope is a Microsoft extension">, + InGroup<Microsoft>; +def ext_explicit_specialization_storage_class : ExtWarn< + "explicit specialization cannot have a storage class">; +def err_explicit_specialization_inconsistent_storage_class : Error< + "explicit specialization has extraneous, inconsistent storage class " + "'%select{none|extern|static|__private_extern__|auto|register}0'">; + +// C++ class template specializations and out-of-line definitions +def err_template_spec_needs_header : Error< + "template specialization requires 'template<>'">; +def err_template_spec_needs_template_parameters : Error< + "template specialization or definition requires a template parameter list " + "corresponding to the nested type %0">; +def err_template_param_list_matches_nontemplate : Error< + "template parameter list matching the non-templated nested type %0 should " + "be empty ('template<>')">; +def err_alias_template_extra_headers : Error< + "extraneous template parameter list in alias template declaration">; +def err_template_spec_extra_headers : Error< + "extraneous template parameter list in template specialization or " + "out-of-line template definition">; +def warn_template_spec_extra_headers : Warning< + "extraneous template parameter list in template specialization">; +def note_explicit_template_spec_does_not_need_header : Note< + "'template<>' header not required for explicitly-specialized class %0 " + "declared here">; +def err_template_qualified_declarator_no_match : Error< + "nested name specifier '%0' for declaration does not refer into a class, " + "class template or class template partial specialization">; +def err_specialize_member_of_template : Error< + "cannot specialize (with 'template<>') a member of an unspecialized " + "template">; + +// C++ Class Template Partial Specialization +def err_default_arg_in_partial_spec : Error< + "default template argument in a class template partial specialization">; +def err_dependent_non_type_arg_in_partial_spec : Error< + "non-type template argument depends on a template parameter of the " + "partial specialization">; +def err_dependent_typed_non_type_arg_in_partial_spec : Error< + "non-type template argument specializes a template parameter with " + "dependent type %0">; +def err_partial_spec_args_match_primary_template : Error< + "class template partial specialization does not specialize any template " + "argument; to %select{declare|define}0 the primary template, remove the " + "template argument list">; +def warn_partial_specs_not_deducible : Warning< + "class template partial specialization contains " + "%select{a template parameter|template parameters}0 that can not be " + "deduced; this partial specialization will never be used">; +def note_partial_spec_unused_parameter : Note< + "non-deducible template parameter %0">; +def err_partial_spec_ordering_ambiguous : Error< + "ambiguous partial specializations of %0">; +def note_partial_spec_match : Note<"partial specialization matches %0">; +def err_partial_spec_redeclared : Error< + "class template partial specialization %0 cannot be redeclared">; +def note_prev_partial_spec_here : Note< + "previous declaration of class template partial specialization %0 is here">; +def err_partial_spec_fully_specialized : Error< + "partial specialization of %0 does not use any of its template parameters">; + +// C++ Function template specializations +def err_function_template_spec_no_match : Error< + "no function template matches function template specialization %0">; +def err_function_template_spec_ambiguous : Error< + "function template specialization %0 ambiguously refers to more than one " + "function template; explicitly specify%select{| additional}1 template " + "arguments to identify a particular function template">; +def note_function_template_spec_matched : Note< + "function template matches specialization %0">; +def err_function_template_partial_spec : Error< + "function template partial specialization is not allowed">; + +// C++ Template Instantiation +def err_template_recursion_depth_exceeded : Error< + "recursive template instantiation exceeded maximum depth of %0">, + DefaultFatal, NoSFINAE; +def note_template_recursion_depth : Note< + "use -ftemplate-depth=N to increase recursive template instantiation depth">; + +def err_template_instantiate_within_definition : Error< + "%select{implicit|explicit}0 instantiation of template %1 within its" + " own definition">; +def err_template_instantiate_undefined : Error< + "%select{implicit|explicit}0 instantiation of undefined template %1">; +def err_implicit_instantiate_member_undefined : Error< + "implicit instantiation of undefined member %0">; +def note_template_class_instantiation_here : Note< + "in instantiation of template class %0 requested here">; +def note_template_member_class_here : Note< + "in instantiation of member class %0 requested here">; +def note_template_member_function_here : Note< + "in instantiation of member function %q0 requested here">; +def note_function_template_spec_here : Note< + "in instantiation of function template specialization %q0 requested here">; +def note_template_static_data_member_def_here : Note< + "in instantiation of static data member %q0 requested here">; +def note_template_enum_def_here : Note< + "in instantiation of enumeration %q0 requested here">; +def note_template_type_alias_instantiation_here : Note< + "in instantiation of template type alias %0 requested here">; +def note_template_exception_spec_instantiation_here : Note< + "in instantiation of exception specification for %0 requested here">; + +def note_default_arg_instantiation_here : Note< + "in instantiation of default argument for '%0' required here">; +def note_default_function_arg_instantiation_here : Note< + "in instantiation of default function argument expression " + "for '%0' required here">; +def note_explicit_template_arg_substitution_here : Note< + "while substituting explicitly-specified template arguments into function " + "template %0 %1">; +def note_function_template_deduction_instantiation_here : Note< + "while substituting deduced template arguments into function template %0 " + "%1">; +def note_partial_spec_deduct_instantiation_here : Note< + "during template argument deduction for class template partial " + "specialization %0 %1">; +def note_prior_template_arg_substitution : Note< + "while substituting prior template arguments into %select{non-type|template}0" + " template parameter%1 %2">; +def note_template_default_arg_checking : Note< + "while checking a default template argument used here">; +def note_instantiation_contexts_suppressed : Note< + "(skipping %0 context%s0 in backtrace; use -ftemplate-backtrace-limit=0 to " + "see all)">; + +def err_field_instantiates_to_function : Error< + "data member instantiated with function type %0">; +def err_variable_instantiates_to_function : Error< + "%select{variable|static data member}0 instantiated with function type %1">; +def err_nested_name_spec_non_tag : Error< + "type %0 cannot be used prior to '::' because it has no members">; + +// C++ Explicit Instantiation +def err_explicit_instantiation_duplicate : Error< + "duplicate explicit instantiation of %0">; +def note_previous_explicit_instantiation : Note< + "previous explicit instantiation is here">; +def ext_explicit_instantiation_after_specialization : Extension< + "explicit instantiation of %0 that occurs after an explicit " + "specialization will be ignored (C++11 extension)">, + InGroup<CXX11>; +def warn_cxx98_compat_explicit_instantiation_after_specialization : Warning< + "explicit instantiation of %0 that occurs after an explicit " + "specialization is incompatible with C++98">, + InGroup<CXX98CompatPedantic>, DefaultIgnore; +def note_previous_template_specialization : Note< + "previous template specialization is here">; +def err_explicit_instantiation_nontemplate_type : Error< + "explicit instantiation of non-templated type %0">; +def note_nontemplate_decl_here : Note< + "non-templated declaration is here">; +def err_explicit_instantiation_in_class : Error< + "explicit instantiation of %0 in class scope">; +def err_explicit_instantiation_out_of_scope : Error< + "explicit instantiation of %0 not in a namespace enclosing %1">; +def err_explicit_instantiation_must_be_global : Error< + "explicit instantiation of %0 must occur at global scope">; +def warn_explicit_instantiation_out_of_scope_0x : Warning< + "explicit instantiation of %0 not in a namespace enclosing %1">, + InGroup<CXX11Compat>, DefaultIgnore; +def warn_explicit_instantiation_must_be_global_0x : Warning< + "explicit instantiation of %0 must occur at global scope">, + InGroup<CXX11Compat>, DefaultIgnore; + +def err_explicit_instantiation_requires_name : Error< + "explicit instantiation declaration requires a name">; +def err_explicit_instantiation_of_typedef : Error< + "explicit instantiation of typedef %0">; +def err_explicit_instantiation_storage_class : Error< + "explicit instantiation cannot have a storage class">; +def err_explicit_instantiation_not_known : Error< + "explicit instantiation of %0 does not refer to a function template, member " + "function, member class, or static data member">; +def note_explicit_instantiation_here : Note< + "explicit instantiation refers here">; +def err_explicit_instantiation_data_member_not_instantiated : Error< + "explicit instantiation refers to static data member %q0 that is not an " + "instantiation">; +def err_explicit_instantiation_member_function_not_instantiated : Error< + "explicit instantiation refers to member function %q0 that is not an " + "instantiation">; +def err_explicit_instantiation_ambiguous : Error< + "partial ordering for explicit instantiation of %0 is ambiguous">; +def note_explicit_instantiation_candidate : Note< + "explicit instantiation candidate function template here %0">; +def err_explicit_instantiation_inline : Error< + "explicit instantiation cannot be 'inline'">; +def warn_explicit_instantiation_inline_0x : Warning< + "explicit instantiation cannot be 'inline'">, InGroup<CXX11Compat>, + DefaultIgnore; +def err_explicit_instantiation_constexpr : Error< + "explicit instantiation cannot be 'constexpr'">; +def ext_explicit_instantiation_without_qualified_id : Extension< + "qualifier in explicit instantiation of %q0 requires a template-id " + "(a typedef is not permitted)">; +def err_explicit_instantiation_unqualified_wrong_namespace : Error< + "explicit instantiation of %q0 must occur in namespace %1">; +def warn_explicit_instantiation_unqualified_wrong_namespace_0x : Warning< + "explicit instantiation of %q0 must occur in namespace %1">, + InGroup<CXX11Compat>, DefaultIgnore; +def err_explicit_instantiation_undefined_member : Error< + "explicit instantiation of undefined %select{member class|member function|" + "static data member}0 %1 of class template %2">; +def err_explicit_instantiation_undefined_func_template : Error< + "explicit instantiation of undefined function template %0">; +def err_explicit_instantiation_declaration_after_definition : Error< + "explicit instantiation declaration (with 'extern') follows explicit " + "instantiation definition (without 'extern')">; +def note_explicit_instantiation_definition_here : Note< + "explicit instantiation definition is here">; + +// C++ typename-specifiers +def err_typename_nested_not_found : Error<"no type named %0 in %1">; +def err_typename_nested_not_type : Error< + "typename specifier refers to non-type member %0 in %1">; +def note_typename_refers_here : Note< + "referenced member %0 is declared here">; +def err_typename_missing : Error< + "missing 'typename' prior to dependent type name '%0%1'">; +def warn_typename_missing : ExtWarn< + "missing 'typename' prior to dependent type name '%0%1'">, + InGroup<DiagGroup<"typename-missing">>; +def ext_typename_outside_of_template : ExtWarn< + "'typename' occurs outside of a template">, InGroup<CXX11>; +def warn_cxx98_compat_typename_outside_of_template : Warning< + "use of 'typename' outside of a template is incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def err_typename_refers_to_using_value_decl : Error< + "typename specifier refers to a dependent using declaration for a value " + "%0 in %1">; +def note_using_value_decl_missing_typename : Note< + "add 'typename' to treat this using declaration as a type">; + +def err_template_kw_refers_to_non_template : Error< + "%0 following the 'template' keyword does not refer to a template">; +def err_template_kw_refers_to_class_template : Error< + "'%0%1' instantiated to a class template, not a function template">; +def note_referenced_class_template : Error< + "class template declared here">; +def err_template_kw_missing : Error< + "missing 'template' keyword prior to dependent template name '%0%1'">; +def ext_template_outside_of_template : ExtWarn< + "'template' keyword outside of a template">, InGroup<CXX11>; +def warn_cxx98_compat_template_outside_of_template : Warning< + "use of 'template' keyword outside of a template is incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; + +def err_non_type_template_in_nested_name_specifier : Error< + "qualified name refers into a specialization of function template '%0'">; +def err_template_id_not_a_type : Error< + "template name refers to non-type template '%0'">; +def note_template_declared_here : Note< + "%select{function template|class template|type alias template|template template parameter}0 " + "%1 declared here">; +def note_parameter_type : Note< + "parameter of type %0 is declared here">; + +// C++11 Variadic Templates +def err_template_param_pack_default_arg : Error< + "template parameter pack cannot have a default argument">; +def err_template_param_pack_must_be_last_template_parameter : Error< + "template parameter pack must be the last template parameter">; + +def err_template_parameter_pack_non_pack : Error< + "%select{template type|non-type template|template template}0 parameter" + "%select{| pack}1 conflicts with previous %select{template type|" + "non-type template|template template}0 parameter%select{ pack|}1">; +def note_template_parameter_pack_non_pack : Note< + "%select{template type|non-type template|template template}0 parameter" + "%select{| pack}1 does not match %select{template type|non-type template" + "|template template}0 parameter%select{ pack|}1 in template argument">; +def note_template_parameter_pack_here : Note< + "previous %select{template type|non-type template|template template}0 " + "parameter%select{| pack}1 declared here">; + +def err_unexpanded_parameter_pack_0 : Error< + "%select{expression|base type|declaration type|data member type|bit-field " + "size|static assertion|fixed underlying type|enumerator value|" + "using declaration|friend declaration|qualifier|initializer|default argument|" + "non-type template parameter type|exception type|partial specialization|" + "__if_exists name|__if_not_exists name}0 " + "contains an unexpanded parameter pack">; +def err_unexpanded_parameter_pack_1 : Error< + "%select{expression|base type|declaration type|data member type|bit-field " + "size|static assertion|fixed underlying type|enumerator value|" + "using declaration|friend declaration|qualifier|initializer|default argument|" + "non-type template parameter type|exception type|partial specialization|" + "__if_exists name|__if_not_exists name}0 " + "contains unexpanded parameter pack %1">; +def err_unexpanded_parameter_pack_2 : Error< + "%select{expression|base type|declaration type|data member type|bit-field " + "size|static assertion|fixed underlying type|enumerator value|" + "using declaration|friend declaration|qualifier|initializer|default argument|" + "non-type template parameter type|exception type|partial specialization|" + "__if_exists name|__if_not_exists name}0 " + "contains unexpanded parameter packs %1 and %2">; +def err_unexpanded_parameter_pack_3_or_more : Error< + "%select{expression|base type|declaration type|data member type|bit-field " + "size|static assertion|fixed underlying type|enumerator value|" + "using declaration|friend declaration|qualifier|initializer|default argument|" + "non-type template parameter type|exception type|partial specialization|" + "__if_exists name|__if_not_exists name}0 " + "contains unexpanded parameter packs %1, %2, ...">; + +def err_pack_expansion_without_parameter_packs : Error< + "pack expansion does not contain any unexpanded parameter packs">; +def err_pack_expansion_length_conflict : Error< + "pack expansion contains parameter packs %0 and %1 that have different " + "lengths (%2 vs. %3)">; +def err_pack_expansion_length_conflict_multilevel : Error< + "pack expansion contains parameter pack %0 that has a different " + "length (%1 vs. %2) from outer parameter packs">; +def err_pack_expansion_member_init : Error< + "pack expansion for initialization of member %0">; + +def err_function_parameter_pack_without_parameter_packs : Error< + "type %0 of function parameter pack does not contain any unexpanded " + "parameter packs">; +def err_ellipsis_in_declarator_not_parameter : Error< + "only function and template parameters can be parameter packs">; + +def err_sizeof_pack_no_pack_name : Error< + "%0 does not refer to the name of a parameter pack">; + +def err_unexpected_typedef : Error< + "unexpected type name %0: expected expression">; +def err_unexpected_namespace : Error< + "unexpected namespace name %0: expected expression">; +def err_undeclared_var_use : Error<"use of undeclared identifier %0">; +def warn_found_via_dependent_bases_lookup : ExtWarn<"use of identifier %0 " + "found via unqualified lookup into dependent bases of class templates is a " + "Microsoft extension">, InGroup<Microsoft>; +def note_dependent_var_use : Note<"must qualify identifier to find this " + "declaration in dependent base class">; +def err_not_found_by_two_phase_lookup : Error<"call to function %0 that is neither " + "visible in the template definition nor found by argument-dependent lookup">; +def note_not_found_by_two_phase_lookup : Note<"%0 should be declared prior to the " + "call site%select{| or in %2| or in an associated namespace of one of its arguments}1">; +def err_undeclared_use : Error<"use of undeclared %0">; +def warn_deprecated : Warning<"%0 is deprecated">, + InGroup<DeprecatedDeclarations>; +def warn_deprecated_message : Warning<"%0 is deprecated: %1">, + InGroup<DeprecatedDeclarations>; +def warn_deprecated_fwdclass_message : Warning< + "%0 maybe deprecated because receiver type is unknown">, + InGroup<DeprecatedDeclarations>; +def warn_deprecated_def : Warning< + "Implementing deprecated %select{method|class|category}0">, + InGroup<DeprecatedImplementations>, DefaultIgnore; +def err_unavailable : Error<"%0 is unavailable">; +def err_unavailable_message : Error<"%0 is unavailable: %1">; +def warn_unavailable_fwdclass_message : Warning< + "%0 maybe unavailable because receiver type is unknown">; +def note_unavailable_here : Note< + "%select{declaration|function}0 has been explicitly marked " + "%select{unavailable|deleted|deprecated}1 here">; +def note_implicitly_deleted : Note< + "explicitly defaulted function was implicitly deleted here">; +def warn_not_enough_argument : Warning< + "not enough variable arguments in %0 declaration to fit a sentinel">, + InGroup<Sentinel>; +def warn_missing_sentinel : Warning < + "missing sentinel in %select{function call|method dispatch|block call}0">, + InGroup<Sentinel>; +def note_sentinel_here : Note< + "%select{function|method|block}0 has been explicitly marked sentinel here">; +def warn_missing_prototype : Warning< + "no previous prototype for function %0">, + InGroup<DiagGroup<"missing-prototypes">>, DefaultIgnore; +def err_redefinition : Error<"redefinition of %0">; +def err_definition_of_implicitly_declared_member : Error< + "definition of implicitly declared %select{default constructor|copy " + "constructor|move constructor|copy assignment operator|move assignment " + "operator|destructor}1">; +def err_definition_of_explicitly_defaulted_member : Error< + "definition of explicitly defaulted %select{default constructor|copy " + "constructor|move constructor|copy assignment operator|move assignment " + "operator|destructor}0">; +def err_redefinition_extern_inline : Error< + "redefinition of a 'extern inline' function %0 is not supported in " + "%select{C99 mode|C++}1">; +def warn_cxx98_compat_friend_redefinition : Warning< + "friend function %0 would be implicitly redefined in C++98">, + InGroup<CXX98Compat>, DefaultIgnore; + +def note_deleted_dtor_no_operator_delete : Note< + "virtual destructor requires an unambiguous, accessible 'operator delete'">; +def note_deleted_special_member_class_subobject : Note< + "%select{default constructor|copy constructor|move constructor|" + "copy assignment operator|move assignment operator|destructor}0 of " + "%select{||||union }4%1 is implicitly deleted because " + "%select{base class %3|field %3}2 has " + "%select{no|a deleted|multiple|an inaccessible|a non-trivial}4 " + "%select{%select{default constructor|copy constructor|move constructor|copy " + "assignment operator|move assignment operator|destructor}0|destructor}5" + "%select{||s||}4">; +def note_deleted_default_ctor_uninit_field : Note< + "default constructor of %0 is implicitly deleted because field %1 of " + "%select{reference|const-qualified}3 type %2 would not be initialized">; +def note_deleted_default_ctor_all_const : Note< + "default constructor of %0 is implicitly deleted because all " + "%select{data members|data members of an anonymous union member}1" + " are const-qualified">; +def note_deleted_copy_ctor_rvalue_reference : Note< + "copy constructor of %0 is implicitly deleted because field %1 is of " + "rvalue reference type %2">; +def note_deleted_copy_user_declared_move : Note< + "copy %select{constructor|assignment operator}0 is implicitly deleted because" + " %1 has a user-declared move %select{constructor|assignment operator}2">; +def note_deleted_assign_field : Note< + "%select{copy|move}0 assignment operator of %0 is implicitly deleted " + "because field %1 is of %select{reference|const-qualified}3 type %2">; + +// This should eventually be an error. +def warn_undefined_internal : Warning< + "%select{function|variable}0 %q1 has internal linkage but is not defined">, + DiagGroup<"undefined-internal">; +def note_used_here : Note<"used here">; + +def warn_redefinition_of_typedef : ExtWarn< + "redefinition of typedef %0 is a C11 feature">, + InGroup<DiagGroup<"typedef-redefinition"> >; +def err_redefinition_variably_modified_typedef : Error< + "redefinition of %select{typedef|type alias}0 for variably-modified type %1">; + +def err_inline_declaration_block_scope : Error< + "inline declaration of %0 not allowed in block scope">; +def err_static_non_static : Error< + "static declaration of %0 follows non-static declaration">; +def warn_weak_import : Warning < + "an already-declared variable is made a weak_import declaration %0">; +def warn_static_non_static : ExtWarn< + "static declaration of %0 follows non-static declaration">; +def err_non_static_static : Error< + "non-static declaration of %0 follows static declaration">; +def err_extern_non_extern : Error< + "extern declaration of %0 follows non-extern declaration">; +def err_non_extern_extern : Error< + "non-extern declaration of %0 follows extern declaration">; +def err_non_thread_thread : Error< + "non-thread-local declaration of %0 follows thread-local declaration">; +def err_thread_non_thread : Error< + "thread-local declaration of %0 follows non-thread-local declaration">; +def err_redefinition_different_type : Error< + "redefinition of %0 with a different type">; +def err_redefinition_different_kind : Error< + "redefinition of %0 as different kind of symbol">; +def warn_forward_class_redefinition : Warning< + "redefinition of forward class %0 of a typedef name of an object type is ignored">, + InGroup<DiagGroup<"objc-forward-class-redefinition">>; +def err_redefinition_different_typedef : Error< + "%select{typedef|type alias|type alias template}0 redefinition with different types (%1 vs %2)">; +def err_tag_reference_non_tag : Error< + "elaborated type refers to %select{a non-tag type|a typedef|a type alias|a template|a type alias template}0">; +def err_tag_reference_conflict : Error< + "implicit declaration introduced by elaborated type conflicts with " + "%select{a declaration|a typedef|a type alias|a template}0 of the same name">; +def err_dependent_tag_decl : Error< + "%select{declaration|definition}0 of %select{struct|union|class|enum}1 " + "in a dependent scope">; +def err_tag_definition_of_typedef : Error< + "definition of type %0 conflicts with %select{typedef|type alias}1 of the same name">; +def err_conflicting_types : Error<"conflicting types for %0">; +def err_nested_redefinition : Error<"nested redefinition of %0">; +def err_use_with_wrong_tag : Error< + "use of %0 with tag type that does not match previous declaration">; +def warn_struct_class_tag_mismatch : Warning< + "%select{struct|class}0%select{| template}1 %2 was previously declared " + "as a %select{class|struct}0%select{| template}1">, + InGroup<MismatchedTags>, DefaultIgnore; +def warn_struct_class_previous_tag_mismatch : Warning< + "%2 defined as a %select{struct|class}0%select{| template}1 here but " + "previously declared as a %select{class|struct}0%select{| template}1">, + InGroup<MismatchedTags>, DefaultIgnore; +def note_struct_class_suggestion : Note< + "did you mean %select{struct|class}0 here?">; +def ext_forward_ref_enum : Extension< + "ISO C forbids forward references to 'enum' types">; +def err_forward_ref_enum : Error< + "ISO C++ forbids forward references to 'enum' types">; +def ext_ms_forward_ref_enum : Extension< + "forward references to 'enum' types are a Microsoft extension">, InGroup<Microsoft>; +def ext_forward_ref_enum_def : Extension< + "redeclaration of already-defined enum %0 is a GNU extension">, InGroup<GNU>; + +def err_redefinition_of_enumerator : Error<"redefinition of enumerator %0">; +def err_duplicate_member : Error<"duplicate member %0">; +def err_misplaced_ivar : Error< + "ivars may not be placed in %select{categories|class extension}0">; +def ext_enum_value_not_int : Extension< + "ISO C restricts enumerator values to range of 'int' (%0 is too " + "%select{small|large}1)">; +def warn_enum_too_large : Warning< + "enumeration values exceed range of largest integer">; +def warn_enumerator_too_large : Warning< + "enumerator value %0 is not representable in the largest integer type">; + +def warn_illegal_constant_array_size : Extension< + "size of static array must be an integer constant expression">; +def err_vm_decl_in_file_scope : Error< + "variably modified type declaration not allowed at file scope">; +def err_vm_decl_has_extern_linkage : Error< + "variably modified type declaration can not have 'extern' linkage">; +def err_typecheck_field_variable_size : Error< + "fields must have a constant size: 'variable length array in structure' " + "extension will never be supported">; +def err_vm_func_decl : Error< + "function declaration cannot have variably modified type">; +def err_array_too_large : Error< + "array is too large (%0 elements)">; +def warn_array_new_too_large : Warning<"array is too large (%0 elements)">, + // FIXME PR11644: ", will throw std::bad_array_new_length at runtime" + InGroup<DiagGroup<"bad-array-new-length">>; + +// -Wpadded, -Wpacked +def warn_padded_struct_field : Warning< + "padding %select{struct|class}0 %1 with %2 %select{byte|bit}3%select{|s}4 " + "to align %5">, InGroup<Padded>, DefaultIgnore; +def warn_padded_struct_anon_field : Warning< + "padding %select{struct|class}0 %1 with %2 %select{byte|bit}3%select{|s}4 " + "to align anonymous bit-field">, InGroup<Padded>, DefaultIgnore; +def warn_padded_struct_size : Warning< + "padding size of %0 with %1 %select{byte|bit}2%select{|s}3 " + "to alignment boundary">, InGroup<Padded>, DefaultIgnore; +def warn_unnecessary_packed : Warning< + "packed attribute is unnecessary for %0">, InGroup<Packed>, DefaultIgnore; + +def err_typecheck_negative_array_size : Error<"array size is negative">; +def warn_typecheck_negative_array_new_size : Warning<"array size is negative">, + // FIXME PR11644: ", will throw std::bad_array_new_length at runtime" + InGroup<DiagGroup<"bad-array-new-length">>; +def warn_typecheck_function_qualifiers : Warning< + "qualifier on function type %0 has unspecified behavior">; +def err_typecheck_invalid_restrict_not_pointer : Error< + "restrict requires a pointer or reference (%0 is invalid)">; +def err_typecheck_invalid_restrict_not_pointer_noarg : Error< + "restrict requires a pointer or reference">; +def err_typecheck_invalid_restrict_invalid_pointee : Error< + "pointer to function type %0 may not be 'restrict' qualified">; +def ext_typecheck_zero_array_size : Extension< + "zero size arrays are an extension">; +def err_typecheck_zero_array_size : Error< + "zero-length arrays are not permitted in C++">; +def warn_typecheck_zero_static_array_size : Warning< + "'static' has no effect on zero-length arrays">, + InGroup<DiagGroup<"array-bounds">>; +def err_array_size_non_int : Error<"size of array has non-integer type %0">; +def err_init_element_not_constant : Error< + "initializer element is not a compile-time constant">; +def err_local_cant_init : Error< + "'__local' variable cannot have an initializer">; +def err_block_extern_cant_init : Error< + "'extern' variable cannot have an initializer">; +def warn_extern_init : Warning<"'extern' variable has an initializer">; +def err_variable_object_no_init : Error< + "variable-sized object may not be initialized">; +def err_excess_initializers : Error< + "excess elements in %select{array|vector|scalar|union|struct}0 initializer">; +def warn_excess_initializers : ExtWarn< + "excess elements in %select{array|vector|scalar|union|struct}0 initializer">; +def err_excess_initializers_in_char_array_initializer : Error< + "excess elements in char array initializer">; +def warn_excess_initializers_in_char_array_initializer : ExtWarn< + "excess elements in char array initializer">; +def err_initializer_string_for_char_array_too_long : Error< + "initializer-string for char array is too long">; +def warn_initializer_string_for_char_array_too_long : ExtWarn< + "initializer-string for char array is too long">; +def warn_missing_field_initializers : Warning< + "missing field '%0' initializer">, + InGroup<MissingFieldInitializers>, DefaultIgnore; +def warn_braces_around_scalar_init : Warning< + "braces around scalar initializer">; +def warn_many_braces_around_scalar_init : ExtWarn< + "too many braces around scalar initializer">; +def ext_complex_component_init : Extension< + "complex initialization specifying real and imaginary components " + "is an extension">, InGroup<DiagGroup<"complex-component-init">>; +def err_empty_scalar_initializer : Error<"scalar initializer cannot be empty">; +def warn_cxx98_compat_empty_scalar_initializer : Warning< + "scalar initialized from empty initializer list is incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def err_illegal_initializer : Error< + "illegal initializer (only variables can be initialized)">; +def err_illegal_initializer_type : Error<"illegal initializer type %0">; +def err_init_list_type_narrowing_sfinae : Error< + "type %0 cannot be narrowed to %1 in initializer list">; +def err_init_list_type_narrowing : ExtWarn< + "type %0 cannot be narrowed to %1 in initializer list">, + InGroup<CXX11Narrowing>, DefaultError; +def err_init_list_variable_narrowing_sfinae : Error< + "non-constant-expression cannot be narrowed from type %0 to %1 in " + "initializer list">; +def err_init_list_variable_narrowing : ExtWarn< + "non-constant-expression cannot be narrowed from type %0 to %1 in " + "initializer list">, InGroup<CXX11Narrowing>, DefaultError; +def err_init_list_constant_narrowing_sfinae : Error< + "constant expression evaluates to %0 which cannot be narrowed to type %1">; +def err_init_list_constant_narrowing : ExtWarn< + "constant expression evaluates to %0 which cannot be narrowed to type %1">, + InGroup<CXX11Narrowing>, DefaultError; +def warn_init_list_type_narrowing : Warning< + "type %0 cannot be narrowed to %1 in initializer list in C++11">, + InGroup<CXX11Narrowing>, DefaultIgnore; +def warn_init_list_variable_narrowing : Warning< + "non-constant-expression cannot be narrowed from type %0 to %1 in " + "initializer list in C++11">, + InGroup<CXX11Narrowing>, DefaultIgnore; +def warn_init_list_constant_narrowing : Warning< + "constant expression evaluates to %0 which cannot be narrowed to type %1 in " + "C++11">, + InGroup<CXX11Narrowing>, DefaultIgnore; +def note_init_list_narrowing_override : Note< + "override this message by inserting an explicit cast">; +def err_init_objc_class : Error< + "cannot initialize Objective-C class type %0">; +def err_implicit_empty_initializer : Error< + "initializer for aggregate with no elements requires explicit braces">; +def err_bitfield_has_negative_width : Error< + "bit-field %0 has negative width (%1)">; +def err_anon_bitfield_has_negative_width : Error< + "anonymous bit-field has negative width (%0)">; +def err_bitfield_has_zero_width : Error<"named bit-field %0 has zero width">; +def err_bitfield_width_exceeds_type_size : Error< + "size of bit-field %0 (%1 bits) exceeds size of its type (%2 bits)">; +def err_anon_bitfield_width_exceeds_type_size : Error< + "size of anonymous bit-field (%0 bits) exceeds size of its type (%1 bits)">; +def err_incorrect_number_of_vector_initializers : Error< + "number of elements must be either one or match the size of the vector">; + +// Used by C++ which allows bit-fields that are wider than the type. +def warn_bitfield_width_exceeds_type_size: Warning< + "size of bit-field %0 (%1 bits) exceeds the size of its type; value will be " + "truncated to %2 bits">; +def warn_anon_bitfield_width_exceeds_type_size : Warning< + "size of anonymous bit-field (%0 bits) exceeds size of its type; value will " + "be truncated to %1 bits">; + +def warn_missing_braces : Warning< + "suggest braces around initialization of subobject">, + InGroup<DiagGroup<"missing-braces">>, DefaultIgnore; +def err_missing_braces : Error< + "cannot omit braces around initialization of subobject when using direct " + "list-initialization">; + +def err_redefinition_of_label : Error<"redefinition of label %0">; +def err_undeclared_label_use : Error<"use of undeclared label %0">; +def warn_unused_label : Warning<"unused label %0">, + InGroup<UnusedLabel>, DefaultIgnore; + +def err_goto_into_protected_scope : Error<"goto into protected scope">; +def warn_goto_into_protected_scope : ExtWarn<"goto into protected scope">, + InGroup<Microsoft>; +def warn_cxx98_compat_goto_into_protected_scope : Warning< + "goto would jump into protected scope in C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def err_switch_into_protected_scope : Error< + "switch case is in protected scope">; +def warn_cxx98_compat_switch_into_protected_scope : Warning< + "switch case would be in a protected scope in C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def err_indirect_goto_without_addrlabel : Error< + "indirect goto in function with no address-of-label expressions">; +def err_indirect_goto_in_protected_scope : Error< + "indirect goto might cross protected scopes">; +def warn_cxx98_compat_indirect_goto_in_protected_scope : Warning< + "indirect goto might cross protected scopes in C++98">, + InGroup<CXX98Compat>, DefaultIgnore; +def note_indirect_goto_target : Note<"possible target of indirect goto">; +def note_protected_by_variable_init : Note< + "jump bypasses variable initialization">; +def note_protected_by_variable_nontriv_destructor : Note< + "jump bypasses variable with a non-trivial destructor">; +def note_protected_by_variable_non_pod : Note< + "jump bypasses initialization of non-POD variable">; +def note_protected_by_cleanup : Note< + "jump bypasses initialization of variable with __attribute__((cleanup))">; +def note_protected_by_vla_typedef : Note< + "jump bypasses initialization of VLA typedef">; +def note_protected_by_vla_type_alias : Note< + "jump bypasses initialization of VLA type alias">; +def note_protected_by_vla : Note< + "jump bypasses initialization of variable length array">; +def note_protected_by_objc_try : Note< + "jump bypasses initialization of @try block">; +def note_protected_by_objc_catch : Note< + "jump bypasses initialization of @catch block">; +def note_protected_by_objc_finally : Note< + "jump bypasses initialization of @finally block">; +def note_protected_by_objc_synchronized : Note< + "jump bypasses initialization of @synchronized block">; +def note_protected_by_objc_autoreleasepool : Note< + "jump bypasses auto release push of @autoreleasepool block">; +def note_protected_by_cxx_try : Note< + "jump bypasses initialization of try block">; +def note_protected_by_cxx_catch : Note< + "jump bypasses initialization of catch block">; +def note_protected_by___block : Note< + "jump bypasses setup of __block variable">; +def note_protected_by_objc_ownership : Note< + "jump bypasses initialization of retaining variable">; +def note_enters_block_captures_cxx_obj : Note< + "jump enters lifetime of block which captures a destructible c++ object">; +def note_enters_block_captures_strong : Note< + "jump enters lifetime of block which strongly captures a variable">; +def note_enters_block_captures_weak : Note< + "jump enters lifetime of block which weakly captures a variable">; + +def note_exits_cleanup : Note< + "jump exits scope of variable with __attribute__((cleanup))">; +def note_exits_dtor : Note< + "jump exits scope of variable with non-trivial destructor">; +def note_exits___block : Note< + "jump exits scope of __block variable">; +def note_exits_objc_try : Note< + "jump exits @try block">; +def note_exits_objc_catch : Note< + "jump exits @catch block">; +def note_exits_objc_finally : Note< + "jump exits @finally block">; +def note_exits_objc_synchronized : Note< + "jump exits @synchronized block">; +def note_exits_cxx_try : Note< + "jump exits try block">; +def note_exits_cxx_catch : Note< + "jump exits catch block">; +def note_exits_objc_autoreleasepool : Note< + "jump exits autoreleasepool block">; +def note_exits_objc_ownership : Note< + "jump exits scope of retaining variable">; +def note_exits_block_captures_cxx_obj : Note< + "jump exits lifetime of block which captures a destructible c++ object">; +def note_exits_block_captures_strong : Note< + "jump exits lifetime of block which strongly captures a variable">; +def note_exits_block_captures_weak : Note< + "jump exits lifetime of block which weakly captures a variable">; + +def err_func_returning_array_function : Error< + "function cannot return %select{array|function}0 type %1">; +def err_field_declared_as_function : Error<"field %0 declared as a function">; +def err_field_incomplete : Error<"field has incomplete type %0">; +def ext_variable_sized_type_in_struct : ExtWarn< + "field %0 with variable sized type %1 not at the end of a struct or class is" + " a GNU extension">, InGroup<GNU>; + +def err_flexible_array_empty_struct : Error< + "flexible array %0 not allowed in otherwise empty struct">; +def err_flexible_array_has_nonpod_type : Error< + "flexible array member %0 of non-POD element type %1">; +def ext_flexible_array_in_struct : Extension< + "%0 may not be nested in a struct due to flexible array member">, + InGroup<FlexibleArrayExtensions>; +def ext_flexible_array_in_array : Extension< + "%0 may not be used as an array element due to flexible array member">, + InGroup<FlexibleArrayExtensions>; +def err_flexible_array_init : Error< + "initialization of flexible array member is not allowed">; +def ext_flexible_array_empty_aggregate_ms : Extension< + "flexible array member %0 in otherwise empty %select{struct|class}1 " + "is a Microsoft extension">, InGroup<Microsoft>; +def ext_flexible_array_union_ms : Extension< + "flexible array member %0 in a union is a Microsoft extension">, + InGroup<Microsoft>; +def ext_flexible_array_empty_aggregate_gnu : Extension< + "flexible array member %0 in otherwise empty %select{struct|class}1 " + "is a GNU extension">, InGroup<GNU>; +def ext_flexible_array_union_gnu : Extension< + "flexible array member %0 in a union is a GNU extension">, InGroup<GNU>; + +let CategoryName = "ARC Semantic Issue" in { + +// ARC-mode diagnostics. + +let CategoryName = "ARC Weak References" in { + +def err_arc_weak_no_runtime : Error< + "the current deployment target does not support automated __weak references">; +def err_arc_unsupported_weak_class : Error< + "class is incompatible with __weak references">; +def err_arc_weak_unavailable_assign : Error< + "assignment of a weak-unavailable object to a __weak object">; +def err_arc_weak_unavailable_property : Error< + "synthesis of a weak-unavailable property is disallowed " + "because it requires synthesis of an ivar of the __weak object">; +def err_arc_convesion_of_weak_unavailable : Error< + "%select{implicit conversion|cast}0 of weak-unavailable object of type %1 to" + " a __weak object of type %2">; + +} // end "ARC Weak References" category + +let CategoryName = "ARC Restrictions" in { + +def err_arc_illegal_explicit_message : Error< + "ARC forbids explicit message send of %0">; +def err_arc_unused_init_message : Error< + "the result of a delegate init call must be immediately returned " + "or assigned to 'self'">; +def err_arc_mismatched_cast : Error< + "%select{implicit conversion|cast}0 of " + "%select{%2|a non-Objective-C pointer type %2|a block pointer|" + "an Objective-C pointer|an indirect pointer to an Objective-C pointer}1" + " to %3 is disallowed with ARC">; +def err_arc_nolifetime_behavior : Error< + "explicit ownership qualifier on cast result has no effect">; +def err_arc_objc_object_in_struct : Error< + "ARC forbids %select{Objective-C objects|blocks}0 in structs or unions">; +def err_arc_objc_property_default_assign_on_object : Error< + "ARC forbids synthesizing a property of an Objective-C object " + "with unspecified ownership or storage attribute">; +def err_arc_illegal_selector : Error< + "ARC forbids use of %0 in a @selector">; +def err_arc_illegal_method_def : Error< + "ARC forbids implementation of %0">; + +} // end "ARC Restrictions" category + +def err_arc_lost_method_convention : Error< + "method was declared as %select{an 'alloc'|a 'copy'|an 'init'|a 'new'}0 " + "method, but its implementation doesn't match because %select{" + "its result type is not an object pointer|" + "its result type is unrelated to its receiver type}1">; +def note_arc_lost_method_convention : Note<"declaration in interface">; +def err_arc_gained_method_convention : Error< + "method implementation does not match its declaration">; +def note_arc_gained_method_convention : Note< + "declaration in interface is not in the '%select{alloc|copy|init|new}0' " + "family because %select{its result type is not an object pointer|" + "its result type is unrelated to its receiver type}1">; +def err_typecheck_arc_assign_self : Error< + "cannot assign to 'self' outside of a method in the init family">; +def err_typecheck_arc_assign_self_class_method : Error< + "cannot assign to 'self' in a class method">; +def err_typecheck_arr_assign_enumeration : Error< + "fast enumeration variables can't be modified in ARC by default; " + "declare the variable __strong to allow this">; +def warn_arc_non_pod_class_with_object_member : Warning< + "%0 cannot be shared between ARC and non-ARC " + "code; add a copy constructor, a copy assignment operator, and a destructor " + "to make it ABI-compatible">, InGroup<AutomaticReferenceCountingABI>, + DefaultIgnore; +def warn_arc_retained_assign : Warning< + "assigning retained object to %select{weak|unsafe_unretained}0 variable" + "; object will be released after assignment">, + InGroup<ARCUnsafeRetainedAssign>; +def warn_arc_retained_property_assign : Warning< + "assigning retained object to unsafe property" + "; object will be released after assignment">, + InGroup<ARCUnsafeRetainedAssign>; +def warn_arc_trivial_member_function_with_object_member : Warning< + "%0 cannot be shared between ARC and non-ARC " + "code; add a non-trivial %select{copy constructor|copy assignment operator|" + "destructor}1 to make it ABI-compatible">, + InGroup<AutomaticReferenceCountingABI>, DefaultIgnore; +def err_arc_new_array_without_ownership : Error< + "'new' cannot allocate an array of %0 with no explicit ownership">; +def warn_err_new_delete_object_array : Warning< + "%select{allocating|destroying}0 an array of %1; this array must not " + "%select{be deleted in|have been allocated from}0 non-ARC code">, + InGroup<AutomaticReferenceCountingABI>, DefaultIgnore; +def err_arc_autoreleasing_var : Error< + "%select{__block variables|global variables|fields|ivars}0 cannot have " + "__autoreleasing ownership">; +def err_arc_autoreleasing_capture : Error< + "cannot capture __autoreleasing variable in a " + "%select{block|lambda by copy}0">; +def err_arc_thread_ownership : Error< + "thread-local variable has non-trivial ownership: type is %0">; +def err_arc_indirect_no_ownership : Error< + "%select{pointer|reference}1 to non-const type %0 with no explicit ownership">, + InGroup<AutomaticReferenceCounting>; +def err_arc_array_param_no_ownership : Error< + "must explicitly describe intended ownership of an object array parameter">; +def err_arc_pseudo_dtor_inconstant_quals : Error< + "pseudo-destructor destroys object of type %0 with inconsistently-qualified " + "type %1">; +def err_arc_init_method_unrelated_result_type : Error< + "init methods must return a type related to the receiver type">; +def err_arc_nonlocal_writeback : Error< + "passing address of %select{non-local|non-scalar}0 object to " + "__autoreleasing parameter for write-back">; +def err_arc_method_not_found : Error< + "no known %select{instance|class}1 method for selector %0">; +def err_arc_receiver_forward_class : Error< + "receiver %0 for class message is a forward declaration">; +def err_arc_may_not_respond : Error< + "no visible @interface for %0 declares the selector %1">; +def err_arc_receiver_forward_instance : Error< + "receiver type %0 for instance message is a forward declaration">; +def warn_receiver_forward_instance : Warning< + "receiver type %0 for instance message is a forward declaration">, + InGroup<DiagGroup<"receiver-forward-class">>, DefaultIgnore; +def err_arc_collection_forward : Error< + "collection expression type %0 is a forward declaration">; +def err_arc_multiple_method_decl : Error< + "multiple methods named %0 found with mismatched result, " + "parameter type or attributes">; + +let CategoryName = "ARC Retain Cycle" in { + +def warn_arc_retain_cycle : Warning< + "capturing %0 strongly in this block is likely to lead to a retain cycle">, + InGroup<ARCRetainCycles>; +def note_arc_retain_cycle_owner : Note< + "block will be retained by %select{the captured object|an object strongly " + "retained by the captured object}0">; + +} // end "ARC Retain Cycle" category + +def note_nontrivial_objc_ownership : Note< + "because type %0 has %select{no|no|__strong|__weak|__autoreleasing}1 " + "ownership">; +def warn_arc_object_memaccess : Warning< + "%select{destination for|source of}0 this %1 call is a pointer to " + "ownership-qualified type %2">, InGroup<ARCNonPodMemAccess>; + +let CategoryName = "ARC and @properties" in { + +def err_arc_strong_property_ownership : Error< + "existing ivar %1 for strong property %0 may not be " + "%select{|__unsafe_unretained||__weak}2">; +def err_arc_assign_property_ownership : Error< + "existing ivar %1 for property %0 with %select{unsafe_unretained| assign}2 " + "attribute must be __unsafe_unretained">; +def err_arc_inconsistent_property_ownership : Error< + "%select{|unsafe_unretained|strong|weak}1 property %0 may not also be " + "declared %select{|__unsafe_unretained|__strong|__weak|__autoreleasing}2">; + +} // end "ARC and @properties" category + +def err_arc_atomic_ownership : Error< + "cannot perform atomic operation on a pointer to type %0: type has " + "non-trivial ownership">; + +let CategoryName = "ARC Casting Rules" in { + +def err_arc_bridge_cast_incompatible : Error< + "incompatible types casting %0 to %1 with a %select{__bridge|" + "__bridge_transfer|__bridge_retained}2 cast">; +def err_arc_bridge_cast_wrong_kind : Error< + "cast of %select{Objective-C|block|C}0 pointer type %1 to " + "%select{Objective-C|block|C}2 pointer type %3 cannot use %select{__bridge|" + "__bridge_transfer|__bridge_retained}4">; +def err_arc_cast_requires_bridge : Error< + "%select{cast|implicit conversion}0 of %select{Objective-C|block|C}1 " + "pointer type %2 to %select{Objective-C|block|C}3 pointer type %4 " + "requires a bridged cast">; +def note_arc_bridge : Note< + "use __bridge to convert directly (no change in ownership)">; +def note_arc_bridge_transfer : Note< + "use %select{__bridge_transfer|CFBridgingRelease call}1 to transfer " + "ownership of a +1 %0 into ARC">; +def note_arc_bridge_retained : Note< + "use %select{__bridge_retained|CFBridgingRetain call}1 to make an " + "ARC object available as a +1 %0">; + +} // ARC Casting category + +} // ARC category name + +def err_flexible_array_init_needs_braces : Error< + "flexible array requires brace-enclosed initializer">; +def err_illegal_decl_array_of_functions : Error< + "'%0' declared as array of functions of type %1">; +def err_illegal_decl_array_incomplete_type : Error< + "array has incomplete element type %0">; +def err_illegal_message_expr_incomplete_type : Error< + "objective-c message has incomplete result type %0">; +def err_illegal_decl_array_of_references : Error< + "'%0' declared as array of references of type %1">; +def err_decl_negative_array_size : Error< + "'%0' declared as an array with a negative size">; +def err_array_star_outside_prototype : Error< + "star modifier used outside of function prototype">; +def err_illegal_decl_pointer_to_reference : Error< + "'%0' declared as a pointer to a reference of type %1">; +def err_illegal_decl_mempointer_to_reference : Error< + "'%0' declared as a member pointer to a reference of type %1">; +def err_illegal_decl_mempointer_to_void : Error< + "'%0' declared as a member pointer to void">; +def err_illegal_decl_mempointer_in_nonclass : Error< + "'%0' does not point into a class">; +def err_mempointer_in_nonclass_type : Error< + "member pointer refers into non-class type %0">; +def err_reference_to_void : Error<"cannot form a reference to 'void'">; +def err_nonfunction_block_type : Error< + "block pointer to non-function type is invalid">; +def err_return_block_has_expr : Error<"void block should not return a value">; +def err_block_return_missing_expr : Error< + "non-void block should return a value">; +def err_func_def_incomplete_result : Error< + "incomplete result type %0 in function definition">; +def err_atomic_specifier_bad_type : Error< + "_Atomic cannot be applied to " + "%select{incomplete |array |function |reference |atomic |qualified |}0type " + "%1 %select{||||||which is not trivially copyable}0">; + +// Expressions. +def ext_sizeof_function_type : Extension< + "invalid application of 'sizeof' to a function type">, InGroup<PointerArith>; +def ext_sizeof_void_type : Extension< + "invalid application of '%select{sizeof|__alignof|vec_step}0' to a void " + "type">, InGroup<PointerArith>; +def err_sizeof_alignof_incomplete_type : Error< + "invalid application of '%select{sizeof|__alignof|vec_step}0' to an " + "incomplete type %1">; +def err_sizeof_alignof_bitfield : Error< + "invalid application of '%select{sizeof|__alignof}0' to bit-field">; +def err_vecstep_non_scalar_vector_type : Error< + "'vec_step' requires built-in scalar or vector type, %0 invalid">; +def err_offsetof_incomplete_type : Error< + "offsetof of incomplete type %0">; +def err_offsetof_record_type : Error< + "offsetof requires struct, union, or class type, %0 invalid">; +def err_offsetof_array_type : Error<"offsetof requires array type, %0 invalid">; +def ext_offsetof_extended_field_designator : Extension< + "using extended field designator is an extension">, + InGroup<DiagGroup<"extended-offsetof">>; +def warn_offsetof_non_pod_type : ExtWarn<"offset of on non-POD type %0">, + InGroup<InvalidOffsetof>; +def err_offsetof_bitfield : Error<"cannot compute offset of bit-field %0">; + +def warn_floatingpoint_eq : Warning< + "comparing floating point with == or != is unsafe">, + InGroup<DiagGroup<"float-equal">>, DefaultIgnore; + +def warn_division_by_zero : Warning<"division by zero is undefined">; +def warn_remainder_by_zero : Warning<"remainder by zero is undefined">; +def warn_shift_negative : Warning<"shift count is negative">, + InGroup<DiagGroup<"shift-count-negative">>; +def warn_shift_gt_typewidth : Warning<"shift count >= width of type">, + InGroup<DiagGroup<"shift-count-overflow">>; +def warn_shift_result_gt_typewidth : Warning< + "signed shift result (%0) requires %1 bits to represent, but %2 only has " + "%3 bits">, InGroup<DiagGroup<"shift-overflow">>; +def warn_shift_result_sets_sign_bit : Warning< + "signed shift result (%0) sets the sign bit of the shift expression's " + "type (%1) and becomes negative">, + InGroup<DiagGroup<"shift-sign-overflow">>, DefaultIgnore; + +def warn_precedence_bitwise_rel : Warning< + "%0 has lower precedence than %1; %1 will be evaluated first">, + InGroup<Parentheses>; +def note_precedence_bitwise_first : Note< + "place parentheses around the %0 expression to evaluate it first">; +def note_precedence_bitwise_silence : Note< + "place parentheses around the %0 expression to silence this warning">; + +def warn_precedence_conditional : Warning< + "operator '?:' has lower precedence than '%0'; '%0' will be evaluated first">, + InGroup<Parentheses>; +def note_precedence_conditional_first : Note< + "place parentheses around the '?:' expression to evaluate it first">; +def note_precedence_conditional_silence : Note< + "place parentheses around the '%0' expression to silence this warning">; + +def warn_logical_instead_of_bitwise : Warning< + "use of logical '%0' with constant operand">, + InGroup<DiagGroup<"constant-logical-operand">>; +def note_logical_instead_of_bitwise_change_operator : Note< + "use '%0' for a bitwise operation">; +def note_logical_instead_of_bitwise_remove_constant : Note< + "remove constant to silence this warning">; + +def warn_bitwise_and_in_bitwise_or : Warning< + "'&' within '|'">, InGroup<BitwiseOpParentheses>; +def note_bitwise_and_in_bitwise_or_silence : Note< + "place parentheses around the '&' expression to silence this warning">; + +def warn_logical_and_in_logical_or : Warning< + "'&&' within '||'">, InGroup<LogicalOpParentheses>; +def note_logical_and_in_logical_or_silence : Note< + "place parentheses around the '&&' expression to silence this warning">; + +def warn_self_assignment : Warning< + "explicitly assigning a variable of type %0 to itself">, + InGroup<SelfAssignment>, DefaultIgnore; + +def warn_string_plus_int : Warning< + "adding %0 to a string does not append to the string">, + InGroup<StringPlusInt>; +def note_string_plus_int_silence : Note< + "use array indexing to silence this warning">; + +def warn_sizeof_array_param : Warning< + "sizeof on array function parameter will return size of %0 instead of %1">, + InGroup<SizeofArrayArgument>; + +def err_sizeof_nonfragile_interface : Error< + "invalid application of '%select{alignof|sizeof}1' to interface %0 in " + "non-fragile ABI">; +def err_atdef_nonfragile_interface : Error< + "invalid application of @defs in non-fragile ABI">; +def err_subscript_nonfragile_interface : Error< + "subscript requires size of interface %0, which is not constant in " + "non-fragile ABI">; + +def err_arithmetic_nonfragile_interface : Error< + "arithmetic on pointer to interface %0, which is not a constant size in " + "non-fragile ABI">; + + +def ext_subscript_non_lvalue : Extension< + "ISO C90 does not allow subscripting non-lvalue array">; +def err_typecheck_subscript_value : Error< + "subscripted value is not an array, pointer, or vector">; +def err_typecheck_subscript_not_integer : Error< + "array subscript is not an integer">; +def err_subscript_function_type : Error< + "subscript of pointer to function type %0">; +def err_subscript_incomplete_type : Error< + "subscript of pointer to incomplete type %0">; +def ext_gnu_subscript_void_type : Extension< + "subscript of a pointer to void is a GNU extension">, InGroup<PointerArith>; +def err_typecheck_member_reference_struct_union : Error< + "member reference base type %0 is not a structure or union">; +def err_typecheck_member_reference_ivar : Error< + "%0 does not have a member named %1">; +def error_arc_weak_ivar_access : Error< + "dereferencing a __weak pointer is not allowed due to possible " + "null value caused by race condition, assign it to strong variable first">; +def err_typecheck_member_reference_arrow : Error< + "member reference type %0 is not a pointer">; +def err_typecheck_member_reference_suggestion : Error< + "member reference type %0 is %select{a|not a}1 pointer; maybe you meant to use '%select{->|.}1'?">; +def err_typecheck_member_reference_type : Error< + "cannot refer to type member %0 in %1 with '%select{.|->}2'">; +def err_typecheck_member_reference_unknown : Error< + "cannot refer to member %0 in %1 with '%select{.|->}2'">; +def err_member_reference_needs_call : Error< + "base of member reference is a function; perhaps you meant to call " + "it%select{| with no arguments}0?">; +def warn_subscript_is_char : Warning<"array subscript is of type 'char'">, + InGroup<CharSubscript>, DefaultIgnore; + +def err_typecheck_incomplete_tag : Error<"incomplete definition of type %0">; +def err_no_member : Error<"no member named %0 in %1">; + +def err_member_not_yet_instantiated : Error< + "no member %0 in %1; it has not yet been instantiated">; +def note_non_instantiated_member_here : Note< + "not-yet-instantiated member is declared here">; + +def err_enumerator_does_not_exist : Error< + "enumerator %0 does not exist in instantiation of %1">; +def note_enum_specialized_here : Note< + "enum %0 was explicitly specialized here">; + +def err_member_redeclared : Error<"class member cannot be redeclared">; +def err_member_name_of_class : Error<"member %0 has the same name as its class">; +def err_member_def_undefined_record : Error< + "out-of-line definition of %0 from class %1 without definition">; +def err_member_def_does_not_match : Error< + "out-of-line definition of %0 does not match any declaration in %1">; +def err_member_def_does_not_match_suggest : Error< + "out-of-line definition of %0 does not match any declaration in %1; " + "did you mean %2?">; +def err_member_def_does_not_match_ret_type : Error< + "out-of-line definition of %q0 differs from the declaration in the return type">; +def err_nonstatic_member_out_of_line : Error< + "non-static data member defined out-of-line">; +def err_qualified_typedef_declarator : Error< + "typedef declarator cannot be qualified">; +def err_qualified_param_declarator : Error< + "parameter declarator cannot be qualified">; +def ext_out_of_line_declaration : ExtWarn< + "out-of-line declaration of a member must be a definition">, + InGroup<OutOfLineDeclaration>, DefaultError; +def warn_member_extra_qualification : Warning< + "extra qualification on member %0">; +def err_member_qualification : Error< + "non-friend class member %0 cannot have a qualified name">; +def note_member_def_close_match : Note<"member declaration nearly matches">; +def note_member_def_close_const_match : Note< + "member declaration does not match because " + "it %select{is|is not}0 const qualified">; +def note_member_def_close_param_match : Note< + "type of %ordinal0 parameter of member declaration does not match " + "definition (%1 vs %2)">; +def err_typecheck_ivar_variable_size : Error< + "instance variables must have a constant size">; +def err_ivar_reference_type : Error< + "instance variables cannot be of reference type">; +def err_typecheck_illegal_increment_decrement : Error< + "cannot %select{decrement|increment}1 value of type %0">; +def err_typecheck_arithmetic_incomplete_type : Error< + "arithmetic on a pointer to an incomplete type %0">; +def err_typecheck_pointer_arith_function_type : Error< + "arithmetic on%select{ a|}0 pointer%select{|s}0 to%select{ the|}2 " + "function type%select{|s}2 %1%select{| and %3}2">; +def err_typecheck_pointer_arith_void_type : Error< + "arithmetic on%select{ a|}0 pointer%select{|s}0 to void">; +def err_typecheck_decl_incomplete_type : Error< + "variable has incomplete type %0">; +def ext_typecheck_decl_incomplete_type : ExtWarn< + "tentative definition of variable with internal linkage has incomplete non-array type %0">, + InGroup<DiagGroup<"tentative-definition-incomplete-type">>; +def err_tentative_def_incomplete_type : Error< + "tentative definition has type %0 that is never completed">; +def err_tentative_def_incomplete_type_arr : Error< + "tentative definition has array of type %0 that is never completed">; +def warn_tentative_incomplete_array : Warning< + "tentative array definition assumed to have one element">; +def err_typecheck_incomplete_array_needs_initializer : Error< + "definition of variable with array type needs an explicit size " + "or an initializer">; +def err_array_init_not_init_list : Error< + "array initializer must be an initializer " + "list%select{| or string literal}0">; +def err_array_init_different_type : Error< + "cannot initialize array of type %0 with array of type %1">; +def err_array_init_non_constant_array : Error< + "cannot initialize array of type %0 with non-constant array of type %1">; +def ext_array_init_copy : Extension< + "initialization of an array of type %0 from a compound literal of type %1 is " + "a GNU extension">, InGroup<GNU>; +// This is intentionally not disabled by -Wno-gnu. +def ext_array_init_parens : ExtWarn< + "parenthesized initialization of a member array is a GNU extension">, + InGroup<DiagGroup<"gnu-array-member-paren-init">>, DefaultError; +def warn_deprecated_string_literal_conversion : Warning< + "conversion from string literal to %0 is deprecated">, InGroup<DeprecatedWritableStr>; +def err_realimag_invalid_type : Error<"invalid type %0 to %1 operator">; +def err_typecheck_sclass_fscope : Error< + "illegal storage class on file-scoped variable">; +def err_unsupported_global_register : Error< + "global register variables are not supported">; +def warn_standalone_specifier : Warning<"'%0' ignored on this declaration">; +def err_typecheck_sclass_func : Error<"illegal storage class on function">; +def err_static_block_func : Error< + "function declared in block scope cannot have 'static' storage class">; +def err_typecheck_address_of : Error<"address of %select{bit-field" + "|vector element|property expression|register variable}0 requested">; +def ext_typecheck_addrof_void : Extension< + "ISO C forbids taking the address of an expression of type 'void'">; +def err_unqualified_pointer_member_function : Error< + "must explicitly qualify name of member function when taking its address">; +def err_invalid_form_pointer_member_function : Error< + "cannot create a non-constant pointer to member function">; +def err_parens_pointer_member_function : Error< + "cannot parenthesize the name of a method when forming a member pointer">; +def err_typecheck_invalid_lvalue_addrof : Error< + "address expression must be an lvalue or a function designator">; +def ext_typecheck_addrof_class_temporary : ExtWarn< + "taking the address of a temporary object of type %0">, + InGroup<DiagGroup<"address-of-temporary">>, DefaultError; +def err_typecheck_addrof_class_temporary : Error< + "taking the address of a temporary object of type %0">; +def err_typecheck_unary_expr : Error< + "invalid argument type %0 to unary expression">; +def err_typecheck_indirection_requires_pointer : Error< + "indirection requires pointer operand (%0 invalid)">; +def warn_indirection_through_null : Warning< + "indirection of non-volatile null pointer will be deleted, not trap">, InGroup<NullDereference>; +def note_indirection_through_null : Note< + "consider using __builtin_trap() or qualifying pointer with 'volatile'">; +def warn_pointer_indirection_from_incompatible_type : Warning< + "dereference of type %1 that was reinterpret_cast from type %0 has undefined " + "behavior.">, + InGroup<DiagGroup<"undefined-reinterpret-cast">>, DefaultIgnore; + +def err_objc_object_assignment : Error< + "cannot assign to class object (%0 invalid)">; +def err_typecheck_invalid_operands : Error< + "invalid operands to binary expression (%0 and %1)">; +def err_typecheck_sub_ptr_compatible : Error< + "%0 and %1 are not pointers to compatible types">; +def ext_typecheck_ordered_comparison_of_pointer_integer : ExtWarn< + "ordered comparison between pointer and integer (%0 and %1)">; +def ext_typecheck_ordered_comparison_of_pointer_and_zero : Extension< + "ordered comparison between pointer and zero (%0 and %1) is an extension">; +def ext_typecheck_ordered_comparison_of_function_pointers : ExtWarn< + "ordered comparison of function pointers (%0 and %1)">; +def ext_typecheck_comparison_of_fptr_to_void : Extension< + "equality comparison between function pointer and void pointer (%0 and %1)">; +def err_typecheck_comparison_of_fptr_to_void : Error< + "equality comparison between function pointer and void pointer (%0 and %1)">; +def ext_typecheck_comparison_of_pointer_integer : ExtWarn< + "comparison between pointer and integer (%0 and %1)">; +def err_typecheck_comparison_of_pointer_integer : Error< + "comparison between pointer and integer (%0 and %1)">; +def ext_typecheck_comparison_of_distinct_pointers : ExtWarn< + "comparison of distinct pointer types (%0 and %1)">; +def ext_typecheck_cond_incompatible_operands : ExtWarn< + "incompatible operand types (%0 and %1)">; +def err_cond_voidptr_arc : Error < + "operands to conditional of types %0 and %1 are incompatible in ARC mode">; +def err_typecheck_comparison_of_distinct_pointers : Error< + "comparison of distinct pointer types (%0 and %1)">; +def ext_typecheck_comparison_of_distinct_pointers_nonstandard : ExtWarn< + "comparison of distinct pointer types (%0 and %1) uses non-standard " + "composite pointer type %2">; +def err_typecheck_assign_const : Error<"read-only variable is not assignable">; +def err_stmtexpr_file_scope : Error< + "statement expression not allowed at file scope">; +def warn_mixed_sign_comparison : Warning< + "comparison of integers of different signs: %0 and %1">, + InGroup<SignCompare>, DefaultIgnore; +def warn_lunsigned_always_true_comparison : Warning< + "comparison of unsigned%select{| enum}2 expression %0 is always %1">, + InGroup<TautologicalCompare>; +def warn_runsigned_always_true_comparison : Warning< + "comparison of %0 unsigned%select{| enum}2 expression is always %1">, + InGroup<TautologicalCompare>; +def warn_comparison_of_mixed_enum_types : Warning< + "comparison of two values with different enumeration types (%0 and %1)">, + InGroup<DiagGroup<"enum-compare">>; +def warn_null_in_arithmetic_operation : Warning< + "use of NULL in arithmetic operation">, + InGroup<DiagGroup<"null-arithmetic">>; +def warn_null_in_comparison_operation : Warning< + "comparison between NULL and non-pointer " + "%select{(%1 and NULL)|(NULL and %1)}0">, + InGroup<DiagGroup<"null-arithmetic">>; + +def err_invalid_this_use : Error< + "invalid use of 'this' outside of a non-static member function">; +def err_this_static_member_func : Error< + "'this' cannot be%select{| implicitly}0 used in a static member function " + "declaration">; +def err_invalid_member_use_in_static_method : Error< + "invalid use of member %0 in static member function">; +def err_invalid_qualified_function_type : Error< + "%select{static |non-}0member function %select{of type %2 |}1" + "cannot have '%3' qualifier">; +def err_compound_qualified_function_type : Error< + "%select{block pointer|pointer|reference}0 to function type %select{%2 |}1" + "cannot have '%3' qualifier">; + +def err_ref_qualifier_overload : Error< + "cannot overload a member function %select{without a ref-qualifier|with " + "ref-qualifier '&'|with ref-qualifier '&&'}0 with a member function %select{" + "without a ref-qualifier|with ref-qualifier '&'|with ref-qualifier '&&'}1">; + +def err_invalid_non_static_member_use : Error< + "invalid use of non-static data member %0">; +def err_nested_non_static_member_use : Error< + "%select{call to non-static member function|use of non-static data member}0 " + "%2 of %1 from nested type %3">; +def warn_cxx98_compat_non_static_member_use : Warning< + "use of non-static data member %0 in an unevaluated context is " + "incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore; +def err_invalid_incomplete_type_use : Error< + "invalid use of incomplete type %0">; +def err_builtin_func_cast_more_than_one_arg : Error< + "function-style cast to a builtin type can only take one argument">; +def err_value_init_for_array_type : Error< + "array types cannot be value-initialized">; +def warn_format_nonliteral_noargs : Warning< + "format string is not a string literal (potentially insecure)">, + InGroup<FormatSecurity>; +def warn_format_nonliteral : Warning< + "format string is not a string literal">, + InGroup<FormatNonLiteral>, DefaultIgnore; + +def err_unexpected_interface : Error< + "unexpected interface name %0: expected expression">; +def err_ref_non_value : Error<"%0 does not refer to a value">; +def err_ref_vm_type : Error< + "cannot refer to declaration with a variably modified type inside block">; +def err_ref_array_type : Error< + "cannot refer to declaration with an array type inside block">; +def err_property_not_found : Error< + "property %0 not found on object of type %1">; +def err_invalid_property_name : Error< + "%0 is not a valid property name (accessing an object of type %1)">; +def err_getter_not_found : Error< + "expected getter method not found on object of type %0">; +def err_objc_subscript_method_not_found : Error< + "expected method to %select{read|write}1 %select{dictionary|array}2 element not " + "found on object of type %0">; +def err_objc_subscript_index_type : Error< + "method index parameter type %0 is not integral type">; +def err_objc_subscript_key_type : Error< + "method key parameter type %0 is not object type">; +def err_objc_subscript_dic_object_type : Error< + "method object parameter type %0 is not object type">; +def err_objc_subscript_object_type : Error< + "cannot assign to this %select{dictionary|array}1 because assigning method's 2nd parameter" + " of type %0 is not an objective-C pointer type">; +def err_objc_subscript_base_type : Error< + "%select{dictionary|array}1 subscript base type %0 is not an Objective-C object">; +def err_objc_multiple_subscript_type_conversion : Error< + "indexing expression is invalid because subscript type %0 has " + "multiple type conversion functions">; +def err_objc_subscript_type_conversion : Error< + "indexing expression is invalid because subscript type %0 is not an integral" + " or objective-C pointer type">; +def err_objc_subscript_pointer : Error< + "indexing expression is invalid because subscript type %0 is not an" + " objective-C pointer">; +def err_objc_indexing_method_result_type : Error< + "method for accessing %select{dictionary|array}1 element must have Objective-C" + " object return type instead of %0">; +def err_objc_index_incomplete_class_type : Error< + "objective-C index expression has incomplete class type %0">; +def err_illegal_container_subscripting_op : Error< + "illegal operation on objective-c container subscripting">; +def err_property_not_found_forward_class : Error< + "property %0 cannot be found in forward class object %1">; +def err_property_not_as_forward_class : Error< + "property %0 refers to an incomplete Objective-C class %1 " + "(with no @interface available)">; +def note_forward_class : Note< + "forward declaration of class here">; +def err_duplicate_property : Error< + "property has a previous declaration">; +def ext_gnu_void_ptr : Extension< + "arithmetic on%select{ a|}0 pointer%select{|s}0 to void is a GNU extension">, + InGroup<PointerArith>; +def ext_gnu_ptr_func_arith : Extension< + "arithmetic on%select{ a|}0 pointer%select{|s}0 to%select{ the|}2 function " + "type%select{|s}2 %1%select{| and %3}2 is a GNU extension">, + InGroup<PointerArith>; +def error_readonly_message_assignment : Error< + "assigning to 'readonly' return result of an objective-c message not allowed">; +def ext_integer_increment_complex : Extension< + "ISO C does not support '++'/'--' on complex integer type %0">; +def ext_integer_complement_complex : Extension< + "ISO C does not support '~' for complex conjugation of %0">; +def err_nosetter_property_assignment : Error< + "%select{assignment to readonly property|" + "no setter method %1 for assignment to property}0">; +def err_nosetter_property_incdec : Error< + "%select{%select{increment|decrement}1 of readonly property|" + "no setter method %2 for %select{increment|decrement}1 of property}0">; +def err_nogetter_property_compound_assignment : Error< + "a getter method is needed to perform a compound assignment on a property">; +def err_nogetter_property_incdec : Error< + "no getter method %1 for %select{increment|decrement}0 of property">; +def error_no_subobject_property_setting : Error< + "expression is not assignable">; +def err_qualified_objc_access : Error< + "%select{property|ivar}0 access cannot be qualified with '%1'">; + +def ext_freestanding_complex : Extension< + "complex numbers are an extension in a freestanding C99 implementation">; + +// FIXME: Remove when we support imaginary. +def err_imaginary_not_supported : Error<"imaginary types are not supported">; + +// Obj-c expressions +def warn_root_inst_method_not_found : Warning< + "instance method %0 is being used on 'Class' which is not in the root class">; +def warn_class_method_not_found : Warning< + "class method %objcclass0 not found (return type defaults to 'id')">; +def warn_instance_method_on_class_found : Warning< + "instance method %0 found instead of class method %1">; +def warn_inst_method_not_found : Warning< + "instance method %objcinstance0 not found (return type defaults to 'id')">; +def error_no_super_class_message : Error< + "no @interface declaration found in class messaging of %0">; +def error_root_class_cannot_use_super : Error< + "%0 cannot use 'super' because it is a root class">; +def err_invalid_receiver_to_message : Error< + "invalid receiver to message expression">; +def err_invalid_receiver_to_message_super : Error< + "'super' is only valid in a method body">; +def err_invalid_receiver_class_message : Error< + "receiver type %0 is not an Objective-C class">; +def err_missing_open_square_message_send : Error< + "missing '[' at start of message send expression">; +def warn_bad_receiver_type : Warning< + "receiver type %0 is not 'id' or interface pointer, consider " + "casting it to 'id'">; +def err_bad_receiver_type : Error<"bad receiver type %0">; +def err_unknown_receiver_suggest : Error< + "unknown receiver %0; did you mean %1?">; +def error_objc_throw_expects_object : Error< + "@throw requires an Objective-C object type (%0 invalid)">; +def error_objc_synchronized_expects_object : Error< + "@synchronized requires an Objective-C object type (%0 invalid)">; +def error_rethrow_used_outside_catch : Error< + "@throw (rethrow) used outside of a @catch block">; +def err_attribute_multiple_objc_gc : Error< + "multiple garbage collection attributes specified for type">; +def err_catch_param_not_objc_type : Error< + "@catch parameter is not a pointer to an interface type">; +def err_illegal_qualifiers_on_catch_parm : Error< + "illegal qualifiers on @catch parameter">; +def err_storage_spec_on_catch_parm : Error< + "@catch parameter cannot have storage specifier %select{|'typedef'|'extern'|" + "'static'|'auto'|'register'|'__private_extern__'|'mutable'}0">; +def warn_register_objc_catch_parm : Warning< + "'register' storage specifier on @catch parameter will be ignored">; +def err_qualified_objc_catch_parm : Error< + "@catch parameter declarator cannot be qualified">; +def warn_objc_pointer_cxx_catch_fragile : Warning< + "can not catch an exception thrown with @throw in C++ in the non-unified " + "exception model">, InGroup<ObjCNonUnifiedException>; +def err_objc_object_catch : Error< + "can't catch an Objective C object by value">; +def err_incomplete_type_objc_at_encode : Error< + "'@encode' of incomplete type %0">; + +def warn_setter_getter_impl_required : Warning< + "property %0 requires method %1 to be defined - " + "use @synthesize, @dynamic or provide a method implementation " + "in this class implementation">, + InGroup<ObjCPropertyImpl>; +def warn_setter_getter_impl_required_in_category : Warning< + "property %0 requires method %1 to be defined - " + "use @dynamic or provide a method implementation in this category">, + InGroup<ObjCPropertyImpl>; +def note_parameter_named_here : Note< + "passing argument to parameter %0 here">; +def note_parameter_here : Note< + "passing argument to parameter here">; + +// C++ casts +// These messages adhere to the TryCast pattern: %0 is an int specifying the +// cast type, %1 is the source type, %2 is the destination type. +def err_bad_reinterpret_cast_overload : Error< + "reinterpret_cast cannot resolve overloaded function %0 to type %1">; + +def err_bad_static_cast_overload : Error< + "address of overloaded function %0 cannot be static_cast to type %1">; + +def err_bad_cstyle_cast_overload : Error< + "address of overloaded function %0 cannot be cast to type %1">; + + +def err_bad_cxx_cast_generic : Error< + "%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|" + "functional-style cast}0 from %1 to %2 is not allowed">; +def err_bad_cxx_cast_rvalue : Error< + "%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|" + "functional-style cast}0 from rvalue to reference type %2">; +def err_bad_cxx_cast_qualifiers_away : Error< + "%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|" + "functional-style cast}0 from %1 to %2 casts away qualifiers">; +def err_bad_const_cast_dest : Error< + "%select{const_cast||||C-style cast|functional-style cast}0 to %2, " + "which is not a reference, pointer-to-object, or pointer-to-data-member">; +def ext_cast_fn_obj : Extension< + "cast between pointer-to-function and pointer-to-object is an extension">; +def warn_cxx98_compat_cast_fn_obj : Warning< + "cast between pointer-to-function and pointer-to-object is incompatible with C++98">, + InGroup<CXX98CompatPedantic>, DefaultIgnore; +def err_bad_reinterpret_cast_small_int : Error< + "cast from pointer to smaller type %2 loses information">; +def err_bad_cxx_cast_vector_to_scalar_different_size : Error< + "%select{||reinterpret_cast||C-style cast|}0 from vector %1 " + "to scalar %2 of different size">; +def err_bad_cxx_cast_scalar_to_vector_different_size : Error< + "%select{||reinterpret_cast||C-style cast|}0 from scalar %1 " + "to vector %2 of different size">; +def err_bad_cxx_cast_vector_to_vector_different_size : Error< + "%select{||reinterpret_cast||C-style cast|}0 from vector %1 " + "to vector %2 of different size">; +def err_bad_lvalue_to_rvalue_cast : Error< + "cannot cast from lvalue of type %1 to rvalue reference type %2; types are " + "not compatible">; +def err_bad_static_cast_pointer_nonpointer : Error< + "cannot cast from type %1 to pointer type %2">; +def err_bad_static_cast_member_pointer_nonmp : Error< + "cannot cast from type %1 to member pointer type %2">; +def err_bad_cxx_cast_member_pointer_size : Error< + "cannot %select{||reinterpret_cast||C-style cast|}0 from member pointer " + "type %1 to member pointer type %2 of different size">; +def err_bad_reinterpret_cast_reference : Error< + "reinterpret_cast of a %0 to %1 needs its address which is not allowed">; +def warn_undefined_reinterpret_cast : Warning< + "reinterpret_cast from %0 to %1 has undefined behavior.">, + InGroup<DiagGroup<"undefined-reinterpret-cast">>, DefaultIgnore; + +// These messages don't adhere to the pattern. +// FIXME: Display the path somehow better. +def err_ambiguous_base_to_derived_cast : Error< + "ambiguous cast from base %0 to derived %1:%2">; +def err_static_downcast_via_virtual : Error< + "cannot cast %0 to %1 via virtual base %2">; +def err_downcast_from_inaccessible_base : Error< + "cannot cast %select{private|protected}2 base class %1 to %0">; +def err_upcast_to_inaccessible_base : Error< + "cannot cast %0 to its %select{private|protected}2 base class %1">; +def err_bad_dynamic_cast_not_ref_or_ptr : Error< + "%0 is not a reference or pointer">; +def err_bad_dynamic_cast_not_class : Error<"%0 is not a class">; +def err_bad_dynamic_cast_incomplete : Error<"%0 is an incomplete type">; +def err_bad_dynamic_cast_not_ptr : Error<"%0 is not a pointer">; +def err_bad_dynamic_cast_not_polymorphic : Error<"%0 is not polymorphic">; + +// Other C++ expressions +def err_need_header_before_typeid : Error< + "you need to include <typeinfo> before using the 'typeid' operator">; +def err_need_header_before_ms_uuidof : Error< + "you need to include <guiddef.h> before using the '__uuidof' operator">; +def err_uuidof_without_guid : Error< + "cannot call operator __uuidof on a type with no GUID">; +def err_incomplete_typeid : Error<"'typeid' of incomplete type %0">; +def err_static_illegal_in_new : Error< + "the 'static' modifier for the array size is not legal in new expressions">; +def err_array_new_needs_size : Error< + "array size must be specified in new expressions">; +def err_bad_new_type : Error< + "cannot allocate %select{function|reference}1 type %0 with new">; +def err_new_incomplete_type : Error< + "allocation of incomplete type %0">; +def err_new_array_nonconst : Error< + "only the first dimension of an allocated array may have dynamic size">; +def err_new_array_init_args : Error< + "array 'new' cannot have initialization arguments">; +def ext_new_paren_array_nonconst : ExtWarn< + "when type is in parentheses, array cannot have dynamic size">; +def err_placement_new_non_placement_delete : Error< + "'new' expression with placement arguments refers to non-placement " + "'operator delete'">; +def err_array_size_not_integral : Error< + "array size expression must have integral or %select{|unscoped }0" + "enumeration type, not %1">; +def err_array_size_incomplete_type : Error< + "array size expression has incomplete class type %0">; +def err_array_size_explicit_conversion : Error< + "array size expression of type %0 requires explicit conversion to type %1">; +def note_array_size_conversion : Note< + "conversion to %select{integral|enumeration}0 type %1 declared here">; +def err_array_size_ambiguous_conversion : Error< + "ambiguous conversion of array size expression of type %0 to an integral or " + "enumeration type">; +def ext_array_size_conversion : Extension< + "implicit conversion from array size expression of type %0 to " + "%select{integral|enumeration}1 type %2 is a C++11 extension">, + InGroup<CXX11>; +def warn_cxx98_compat_array_size_conversion : Warning< + "implicit conversion from array size expression of type %0 to " + "%select{integral|enumeration}1 type %2 is incompatible with C++98">, + InGroup<CXX98CompatPedantic>, DefaultIgnore; +def err_address_space_qualified_new : Error< + "'new' cannot allocate objects of type %0 in address space '%1'">; +def err_address_space_qualified_delete : Error< + "'delete' cannot delete objects of type %0 in address space '%1'">; + +def err_default_init_const : Error< + "default initialization of an object of const type %0" + "%select{| requires a user-provided default constructor}1">; +def err_delete_operand : Error<"cannot delete expression of type %0">; +def ext_delete_void_ptr_operand : ExtWarn< + "cannot delete expression with pointer-to-'void' type %0">; +def err_ambiguous_delete_operand : Error<"ambiguous conversion of delete " + "expression of type %0 to a pointer">; +def warn_delete_incomplete : Warning< + "deleting pointer to incomplete type %0 may cause undefined behaviour">, + InGroup<DiagGroup<"delete-incomplete">>; +def err_delete_incomplete_class_type : Error< + "deleting incomplete class type %0; no conversions to pointer type">; +def warn_delete_array_type : Warning< + "'delete' applied to a pointer-to-array type %0 treated as delete[]">; +def err_no_suitable_delete_member_function_found : Error< + "no suitable member %0 in %1">; +def err_ambiguous_suitable_delete_member_function_found : Error< + "multiple suitable %0 functions in %1">; +def note_member_declared_here : Note< + "member %0 declared here">; +def err_decrement_bool : Error<"cannot decrement expression of type bool">; +def warn_increment_bool : Warning< + "incrementing expression of type bool is deprecated">, InGroup<Deprecated>; +def err_catch_incomplete_ptr : Error< + "cannot catch pointer to incomplete type %0">; +def err_catch_incomplete_ref : Error< + "cannot catch reference to incomplete type %0">; +def err_catch_incomplete : Error<"cannot catch incomplete type %0">; +def err_catch_rvalue_ref : Error<"cannot catch exceptions by rvalue reference">; +def err_qualified_catch_declarator : Error< + "exception declarator cannot be qualified">; +def err_early_catch_all : Error<"catch-all handler must come last">; +def err_bad_memptr_rhs : Error< + "right hand operand to %0 has non pointer-to-member type %1">; +def err_bad_memptr_lhs : Error< + "left hand operand to %0 must be a %select{|pointer to }1class " + "compatible with the right hand operand, but is %2">; +def warn_exception_caught_by_earlier_handler : Warning< + "exception of type %0 will be caught by earlier handler">; +def note_previous_exception_handler : Note<"for type %0">; +def err_exceptions_disabled : Error< + "cannot use '%0' with exceptions disabled">; +def err_objc_exceptions_disabled : Error< + "cannot use '%0' with Objective-C exceptions disabled">; +def warn_non_virtual_dtor : Warning< + "%0 has virtual functions but non-virtual destructor">, + InGroup<NonVirtualDtor>, DefaultIgnore; +def warn_delete_non_virtual_dtor : Warning< + "delete called on %0 that has virtual functions but non-virtual destructor">, + InGroup<DeleteNonVirtualDtor>, DefaultIgnore; +def warn_delete_abstract_non_virtual_dtor : Warning< + "delete called on %0 that is abstract but has non-virtual destructor">, + InGroup<DeleteNonVirtualDtor>; +def warn_overloaded_virtual : Warning< + "%q0 hides overloaded virtual %select{function|functions}1">, + InGroup<OverloadedVirtual>, DefaultIgnore; +def note_hidden_overloaded_virtual_declared_here : Note< + "hidden overloaded virtual function %q0 declared here">; +def warn_using_directive_in_header : Warning< + "using namespace directive in global context in header">, + InGroup<HeaderHygiene>, DefaultIgnore; +def warn_overaligned_type : Warning< + "type %0 requires %1 bytes of alignment and the default allocator only " + "guarantees %2 bytes">, + InGroup<OveralignedType>, DefaultIgnore; + +def err_conditional_void_nonvoid : Error< + "%select{left|right}1 operand to ? is void, but %select{right|left}1 operand " + "is of type %0">; +def err_conditional_ambiguous : Error< + "conditional expression is ambiguous; %0 can be converted to %1 " + "and vice versa">; +def err_conditional_ambiguous_ovl : Error< + "conditional expression is ambiguous; %0 and %1 can be converted to several " + "common types">; + +def err_throw_incomplete : Error< + "cannot throw object of incomplete type %0">; +def err_throw_incomplete_ptr : Error< + "cannot throw pointer to object of incomplete type %0">; +def err_return_in_constructor_handler : Error< + "return in the catch of a function try block of a constructor is illegal">; + +let CategoryName = "Lambda Issue" in { + def err_capture_more_than_once : Error< + "%0 can appear only once in a capture list">; + def err_reference_capture_with_reference_default : Error< + "'&' cannot precede a capture when the capture default is '&'">; + def err_this_capture_with_copy_default : Error< + "'this' cannot be explicitly captured when the capture default is '='">; + def err_copy_capture_with_copy_default : Error< + "'&' must precede a capture when the capture default is '='">; + def err_capture_does_not_name_variable : Error< + "%0 in capture list does not name a variable">; + def err_capture_non_automatic_variable : Error< + "%0 cannot be captured because it does not have automatic storage " + "duration">; + def err_this_capture : Error< + "'this' cannot be %select{implicitly |}0captured in this context">; + def err_lambda_capture_block : Error< + "__block variable %0 cannot be captured in a lambda expression">; + def err_lambda_capture_anonymous_var : Error< + "unnamed variable cannot be implicitly captured in a lambda expression">; + def err_lambda_capture_vm_type : Error< + "variable %0 with variably modified type cannot be captured in " + "a lambda expression">; + def err_lambda_impcap : Error< + "variable %0 cannot be implicitly captured in a lambda with no " + "capture-default specified">; + def note_lambda_decl : Note<"lambda expression begins here">; + def err_lambda_unevaluated_operand : Error< + "lambda expression in an unevaluated operand">; + def ext_lambda_implies_void_return : ExtWarn< + "C++11 requires lambda with omitted result type to consist of a single " + "return statement">, + InGroup<LambdaExtensions>; + def err_lambda_return_init_list : Error< + "cannot deduce lambda return type from initializer list">; + def err_lambda_capture_default_arg : Error< + "lambda expression in default argument cannot capture any entity">; + def err_lambda_unexpanded_pack : Error< + "unexpanded function parameter pack capture is unsupported">; + def err_lambda_incomplete_result : Error< + "incomplete result type %0 in lambda expression">; + def err_lambda_objc_object_result : Error< + "non-pointer Objective-C class type %0 in lambda expression result">; + def ext_lambda_default_arguments : ExtWarn< + "C++11 forbids default arguments for lambda expressions">, + InGroup<LambdaExtensions>; + def err_noreturn_lambda_has_return_expr : Error< + "lambda declared 'noreturn' should not return">; + def warn_maybe_falloff_nonvoid_lambda : Warning< + "control may reach end of non-void lambda">, + InGroup<ReturnType>; + def warn_falloff_nonvoid_lambda : Warning< + "control reaches end of non-void lambda">, + InGroup<ReturnType>; + def err_access_lambda_capture : Error< + // The ERRORs represent other special members that aren't constructors, in + // hopes that someone will bother noticing and reporting if they appear + "capture of variable '%0' as type %1 calls %select{private|protected}3 " + "%select{default |copy |move |*ERROR* |*ERROR* |*ERROR* |}2constructor">, + AccessControl; + def note_lambda_to_block_conv : Note< + "implicit capture of lambda object due to conversion to block pointer " + "here">; +} + +def err_operator_arrow_circular : Error< + "circular pointer delegation detected">; +def err_pseudo_dtor_base_not_scalar : Error< + "object expression of non-scalar type %0 cannot be used in a " + "pseudo-destructor expression">; +def ext_pseudo_dtor_on_void : ExtWarn< + "pseudo-destructors on type void are a Microsoft extension">, + InGroup<Microsoft>; +def err_pseudo_dtor_type_mismatch : Error< + "the type of object expression (%0) does not match the type being destroyed " + "(%1) in pseudo-destructor expression">; +def err_pseudo_dtor_call_with_args : Error< + "call to pseudo-destructor cannot have any arguments">; +def err_dtor_expr_without_call : Error< + "%select{destructor reference|pseudo-destructor expression}0 must be " + "called immediately with '()'">; +def err_pseudo_dtor_destructor_non_type : Error< + "%0 does not refer to a type name in pseudo-destructor expression; expected " + "the name of type %1">; +def err_invalid_use_of_function_type : Error< + "a function type is not allowed here">; +def err_invalid_use_of_array_type : Error<"an array type is not allowed here">; +def err_type_defined_in_condition : Error< + "types may not be defined in conditions">; +def err_typecheck_bool_condition : Error< + "value of type %0 is not contextually convertible to 'bool'">; +def err_typecheck_ambiguous_condition : Error< + "conversion from %0 to %1 is ambiguous">; +def err_typecheck_nonviable_condition : Error< + "no viable conversion from %0 to %1">; +def err_typecheck_deleted_function : Error< + "conversion function from %0 to %1 invokes a deleted function">; + +def err_expected_class_or_namespace : Error<"expected a class or namespace">; +def err_expected_class : Error<"%0 is not a class%select{ or namespace|, " + "namespace, or scoped enumeration}1">; +def err_invalid_declarator_scope : Error<"cannot define or redeclare %0 here " + "because namespace %1 does not enclose namespace %2">; +def err_invalid_declarator_global_scope : Error< + "definition or redeclaration of %0 cannot name the global scope">; +def err_invalid_declarator_in_function : Error< + "definition or redeclaration of %0 not allowed inside a function">; +def err_not_tag_in_scope : Error< + "no %select{struct|union|class|enum}0 named %1 in %2">; + +def err_cannot_form_pointer_to_member_of_reference_type : Error< + "cannot form a pointer-to-member to member %0 of reference type %1">; +def err_incomplete_object_call : Error< + "incomplete type in call to object of type %0">; + +def warn_condition_is_assignment : Warning<"using the result of an " + "assignment as a condition without parentheses">, + InGroup<Parentheses>; +// Completely identical except off by default. +def warn_condition_is_idiomatic_assignment : Warning<"using the result " + "of an assignment as a condition without parentheses">, + InGroup<DiagGroup<"idiomatic-parentheses">>, DefaultIgnore; +def note_condition_assign_to_comparison : Note< + "use '==' to turn this assignment into an equality comparison">; +def note_condition_or_assign_to_comparison : Note< + "use '!=' to turn this compound assignment into an inequality comparison">; +def note_condition_assign_silence : Note< + "place parentheses around the assignment to silence this warning">; + +def warn_equality_with_extra_parens : Warning<"equality comparison with " + "extraneous parentheses">, InGroup<ParenthesesOnEquality>; +def note_equality_comparison_to_assign : Note< + "use '=' to turn this equality comparison into an assignment">; +def note_equality_comparison_silence : Note< + "remove extraneous parentheses around the comparison to silence this warning">; + +// assignment related diagnostics (also for argument passing, returning, etc). +// In most of these diagnostics the %2 is a value from the +// Sema::AssignmentAction enumeration +def err_typecheck_convert_incompatible : Error< + "%select{assigning to|passing|returning|converting|initializing|sending|casting}2" + " %0 " + "%select{from incompatible type|to parameter of incompatible type|" + "from a function with incompatible result type|to incompatible type|" + "with an expression of incompatible type|to parameter of incompatible type|" + "to incompatible type}2 %1" + "%select{|; dereference with *|" + "; take the address with &|" + "; remove *|" + "; remove &}3" + "%select{|: different classes (%5 vs %6)" + "|: different number of parameters (%5 vs %6)" + "|: type mismatch at %ordinal5 parameter (%6 vs %7)" + "|: different return type (%5 vs %6)" + "|: different qualifiers (" + "%select{none|const|restrict|const and restrict|volatile|const and volatile|" + "volatile and restrict|const, volatile, and restrict}5 vs " + "%select{none|const|restrict|const and restrict|volatile|const and volatile|" + "volatile and restrict|const, volatile, and restrict}6)}4">; +def err_typecheck_missing_return_type_incompatible : Error< + "return type %0 must match previous return type %1 when %select{block " + "literal|lambda expression}2 has unspecified explicit return type">; + +def warn_incompatible_qualified_id : Warning< + "%select{assigning to|passing|returning|converting|initializing|sending|casting}2" + " %0 " + "%select{from incompatible type|to parameter of incompatible type|" + "from a function with incompatible result type|to incompatible type|" + "with an expression of incompatible type|to parameter of incompatible type|" + "to incompatible type}2 %1">; +def ext_typecheck_convert_pointer_int : ExtWarn< + "incompatible pointer to integer conversion " + "%select{assigning to|passing|returning|converting|initializing|sending|casting}2" + " %0 " + "%select{from|to parameter of type|from a function with result type|to type|" + "with an expression of type|to parameter of type|to type}2 %1" + "%select{|; dereference with *|" + "; take the address with &|" + "; remove *|" + "; remove &}3">, + InGroup<IntConversion>; +def ext_typecheck_convert_int_pointer : ExtWarn< + "incompatible integer to pointer conversion " + "%select{assigning to|passing|returning|converting|initializing|sending|casting}2" + " %0 " + "%select{from|to parameter of type|from a function with result type|to type|" + "with an expression of type|to parameter of type|to type}2 %1" + "%select{|; dereference with *|" + "; take the address with &|" + "; remove *|" + "; remove &}3">, + InGroup<IntConversion>; +def ext_typecheck_convert_pointer_void_func : Extension< + "%select{assigning to|passing|returning|converting|initializing|sending|casting}2" + " %0 " + "%select{from|to parameter of type|from a function with result type|to type|" + "with an expression of type|to parameter of type|to type}2 %1 " + "converts between void pointer and function pointer">; +def ext_typecheck_convert_incompatible_pointer_sign : ExtWarn< + "%select{assigning to|passing|returning|converting|initializing|sending|casting}2" + " %0 " + "%select{from|to parameter of type|from a function with result type|to type|" + "with an expression of type|to parameter of type|to type}2 %1 " + "converts between pointers to integer types with different sign">, + InGroup<DiagGroup<"pointer-sign">>; +def ext_typecheck_convert_incompatible_pointer : ExtWarn< + "incompatible pointer types " + "%select{assigning to|passing|returning|converting|initializing|sending|casting}2" + " %0 " + "%select{from|to parameter of type|from a function with result type|to type|" + "with an expression of type|to parameter of type|to type}2 %1" + "%select{|; dereference with *|" + "; take the address with &|" + "; remove *|" + "; remove &}3">, + InGroup<IncompatiblePointerTypes>; +def ext_typecheck_convert_discards_qualifiers : ExtWarn< + "%select{assigning to|passing|returning|converting|initializing|sending|casting}2" + " %0 " + "%select{from|to parameter of type|from a function with result type|to type|" + "with an expression of type|to parameter of type|to type}2 %1 discards " + "qualifiers">, + InGroup<IncompatiblePointerTypes>; +def ext_nested_pointer_qualifier_mismatch : ExtWarn< + "%select{assigning to|passing|returning|converting|initializing|sending|casting}2" + " %0 " + "%select{from|to parameter of type|from a function with result type|to type|" + "with an expression of type|to parameter of type|to type}2 %1 discards " + "qualifiers in nested pointer types">, + InGroup<IncompatiblePointerTypes>; +def warn_incompatible_vectors : Warning< + "incompatible vector types " + "%select{assigning to|passing|returning|converting|initializing|sending|casting}2" + " %0 " + "%select{from|to parameter of type|from a function with result type|to type|" + "with an expression of type|to parameter of type|to type}2 %1">, + InGroup<VectorConversion>, DefaultIgnore; +def err_int_to_block_pointer : Error< + "invalid block pointer conversion " + "%select{assigning to|passing|returning|converting|initializing|sending|casting}2" + " %0 " + "%select{from|to parameter of type|from a function with result type|to type|" + "with an expression of type|to parameter of type|to type}2 %1">; +def err_typecheck_convert_incompatible_block_pointer : Error< + "incompatible block pointer types " + "%select{assigning to|passing|returning|converting|initializing|sending|casting}2" + " %0 " + "%select{from|to parameter of type|from a function with result type|to type|" + "with an expression of type|to parameter of type|to type}2 %1">; +def err_typecheck_incompatible_address_space : Error< + "%select{assigning %1 to %0" + "|passing %0 to parameter of type %1" + "|returning %0 from a function with result type %1" + "|converting %0 to type %1" + "|initializing %0 with an expression of type %1" + "|sending %0 to parameter of type %1" + "|casting %0 to type %1}2" + " changes address space of pointer">; +def err_typecheck_incompatible_ownership : Error< + "%select{assigning %1 to %0" + "|passing %0 to parameter of type %1" + "|returning %0 from a function with result type %1" + "|converting %0 to type %1" + "|initializing %0 with an expression of type %1" + "|sending %0 to parameter of type %1" + "|casting %0 to type %1}2" + " changes retain/release properties of pointer">; +def err_typecheck_comparison_of_distinct_blocks : Error< + "comparison of distinct block types (%0 and %1)">; + +def err_typecheck_array_not_modifiable_lvalue : Error< + "array type %0 is not assignable">; +def err_typecheck_non_object_not_modifiable_lvalue : Error< + "non-object type %0 is not assignable">; +def err_typecheck_expression_not_modifiable_lvalue : Error< + "expression is not assignable">; +def err_typecheck_incomplete_type_not_modifiable_lvalue : Error< + "incomplete type %0 is not assignable">; +def err_typecheck_lvalue_casts_not_supported : Error< + "assignment to cast is illegal, lvalue casts are not supported">; + +def err_typecheck_duplicate_vector_components_not_mlvalue : Error< + "vector is not assignable (contains duplicate components)">; +def err_block_decl_ref_not_modifiable_lvalue : Error< + "variable is not assignable (missing __block type specifier)">; +def err_lambda_decl_ref_not_modifiable_lvalue : Error< + "cannot assign to a variable captured by copy in a non-mutable lambda">; +def err_typecheck_call_not_function : Error< + "called object type %0 is not a function or function pointer">; +def err_call_incomplete_return : Error< + "calling function with incomplete return type %0">; +def err_call_function_incomplete_return : Error< + "calling %0 with incomplete return type %1">; +def note_function_with_incomplete_return_type_declared_here : Note< + "%0 declared here">; +def err_call_incomplete_argument : Error< + "argument type %0 is incomplete">; +def err_typecheck_call_too_few_args : Error< + "too few %select{|||execution configuration }0arguments to " + "%select{function|block|method|kernel function}0 call, " + "expected %1, have %2">; +def err_typecheck_call_too_few_args_at_least : Error< + "too few %select{|||execution configuration }0arguments to " + "%select{function|block|method|kernel function}0 call, " + "expected at least %1, have %2">; +def err_typecheck_call_too_many_args : Error< + "too many %select{|||execution configuration }0arguments to " + "%select{function|block|method|kernel function}0 call, " + "expected %1, have %2">; +def err_typecheck_call_too_many_args_at_most : Error< + "too many %select{|||execution configuration }0arguments to " + "%select{function|block|method|kernel function}0 call, " + "expected at most %1, have %2">; +def note_callee_decl : Note< + "%0 declared here">; +def note_defined_here : Note<"%0 defined here">; + +def warn_call_wrong_number_of_arguments : Warning< + "too %select{few|many}0 arguments in call to %1">; +def err_atomic_builtin_must_be_pointer : Error< + "first argument to atomic builtin must be a pointer (%0 invalid)">; +def err_atomic_builtin_must_be_pointer_intptr : Error< + "first argument to atomic builtin must be a pointer to integer or pointer" + " (%0 invalid)">; +def err_atomic_builtin_pointer_size : Error< + "first argument to atomic builtin must be a pointer to 1,2,4,8 or 16 byte " + "type (%0 invalid)">; +def err_atomic_op_needs_atomic : Error< + "first argument to atomic operation must be a pointer to _Atomic " + "type (%0 invalid)">; +def err_atomic_op_needs_trivial_copy : Error< + "first argument to atomic operation must be a pointer to a trivially-copyable" + " type (%0 invalid)">; +def err_atomic_op_needs_atomic_int_or_ptr : Error< + "first argument to atomic operation must be a pointer to %select{|atomic }0" + "integer or pointer (%1 invalid)">; +def err_atomic_op_bitwise_needs_atomic_int : Error< + "first argument to bitwise atomic operation must be a pointer to " + "%select{|atomic }0integer (%1 invalid)">; + +def err_deleted_function_use : Error<"attempt to use a deleted function">; + +def err_kern_type_not_void_return : Error< + "kernel function type %0 must have void return type">; +def err_config_scalar_return : Error< + "CUDA special function 'cudaConfigureCall' must have scalar return type">; +def err_kern_call_not_global_function : Error< + "kernel call to non-global function %0">; +def err_global_call_not_config : Error< + "call to global function %0 not configured">; +def err_ref_bad_target : Error< + "reference to %select{__device__|__global__|__host__|__host__ __device__}0 " + "function %1 in %select{__device__|__global__|__host__|__host__ __device__}2 function">; + + +def err_cannot_pass_objc_interface_to_vararg : Error< + "cannot pass object with interface type %0 by-value through variadic " + "%select{function|block|method}1">; + +def warn_cannot_pass_non_pod_arg_to_vararg : Warning< + "cannot pass object of %select{non-POD|non-trivial}0 type %1 through variadic" + " %select{function|block|method|constructor}2; call will abort at runtime">, + InGroup<DiagGroup<"non-pod-varargs">>, DefaultError; +def warn_cxx98_compat_pass_non_pod_arg_to_vararg : Warning< + "passing object of trivial but non-POD type %0 through variadic" + " %select{function|block|method|constructor}1 is incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; + +def err_typecheck_call_invalid_ordered_compare : Error< + "ordered compare requires two args of floating point type (%0 and %1)">; +def err_typecheck_call_invalid_unary_fp : Error< + "floating point classification requires argument of floating point type " + "(passed in %0)">; +def err_typecheck_cond_expect_scalar : Error< + "used type %0 where arithmetic or pointer type is required">; +def ext_typecheck_cond_one_void : Extension< + "C99 forbids conditional expressions with only one void side">; +def err_typecheck_cond_expect_scalar_or_vector : Error< + "used type %0 where arithmetic, pointer, or vector type is required">; +def err_typecheck_cast_to_incomplete : Error< + "cast to incomplete type %0">; +def ext_typecheck_cast_nonscalar : Extension< + "C99 forbids casting nonscalar type %0 to the same type">; +def ext_typecheck_cast_to_union : Extension<"C99 forbids casts to union type">; +def err_typecheck_cast_to_union_no_type : Error< + "cast to union type from type %0 not present in union">; +def err_cast_pointer_from_non_pointer_int : Error< + "operand of type %0 cannot be cast to a pointer type">; +def err_cast_pointer_to_non_pointer_int : Error< + "pointer cannot be cast to type %0">; +def err_typecheck_expect_scalar_operand : Error< + "operand of type %0 where arithmetic or pointer type is required">; +def err_typecheck_cond_incompatible_operands : Error< + "incompatible operand types (%0 and %1)">; +def ext_typecheck_cond_incompatible_operands_nonstandard : ExtWarn< + "incompatible operand types (%0 and %1) use non-standard composite pointer " + "type %2">; +def err_cast_selector_expr : Error< + "cannot type cast @selector expression">; +def warn_typecheck_cond_incompatible_pointers : ExtWarn< + "pointer type mismatch (%0 and %1)">, + InGroup<DiagGroup<"pointer-type-mismatch">>; +def warn_typecheck_cond_pointer_integer_mismatch : ExtWarn< + "pointer/integer type mismatch in conditional expression (%0 and %1)">, + InGroup<DiagGroup<"conditional-type-mismatch">>; +def err_typecheck_choose_expr_requires_constant : Error< + "'__builtin_choose_expr' requires a constant expression">; +def warn_unused_expr : Warning<"expression result unused">, + InGroup<UnusedValue>; +def warn_unused_voidptr : Warning< + "expression result unused; should this cast be to 'void'?">, + InGroup<UnusedValue>; +def warn_unused_property_expr : Warning< + "property access result unused - getters should not be used for side effects">, + InGroup<UnusedValue>; +def warn_unused_container_subscript_expr : Warning< + "container access result unused - container access should not be used for side effects">, + InGroup<UnusedValue>; +def warn_unused_call : Warning< + "ignoring return value of function declared with %0 attribute">, + InGroup<UnusedValue>; +def warn_unused_result : Warning< + "ignoring return value of function declared with warn_unused_result " + "attribute">, InGroup<DiagGroup<"unused-result">>; +def warn_unused_comparison : Warning< + "%select{equality|inequality}0 comparison result unused">, + InGroup<UnusedComparison>; +def note_inequality_comparison_to_or_assign : Note< + "use '|=' to turn this inequality comparison into an or-assignment">; + +def err_incomplete_type_used_in_type_trait_expr : Error< + "incomplete type %0 used in type trait expression">; +def err_type_trait_arity : Error< + "type trait requires %0%select{| or more}1 argument%select{|s}2; have " + "%3 argument%s3">; + +def err_dimension_expr_not_constant_integer : Error< + "dimension expression does not evaluate to a constant unsigned int">; +def err_expected_ident_or_lparen : Error<"expected identifier or '('">; + +def err_typecheck_cond_incompatible_operands_null : Error< + "non-pointer operand type %0 incompatible with %select{NULL|nullptr}1">; +} // End of general sema category. + +// inline asm. +let CategoryName = "Inline Assembly Issue" in { + def err_asm_wide_character : Error<"wide string is invalid in 'asm'">; + def err_asm_invalid_lvalue_in_output : Error<"invalid lvalue in asm output">; + def err_asm_invalid_output_constraint : Error< + "invalid output constraint '%0' in asm">; + def err_asm_invalid_lvalue_in_input : Error< + "invalid lvalue in asm input for constraint '%0'">; + def err_asm_invalid_input_constraint : Error< + "invalid input constraint '%0' in asm">; + def err_asm_invalid_type_in_input : Error< + "invalid type %0 in asm input for constraint '%1'">; + def err_asm_tying_incompatible_types : Error< + "unsupported inline asm: input with type %0 matching output with type %1">; + def err_asm_unknown_register_name : Error<"unknown register name '%0' in asm">; + def warn_asm_label_on_auto_decl : Warning< + "ignored asm label '%0' on automatic variable">; + def err_invalid_asm_cast_lvalue : Error< + "invalid use of a cast in a inline asm context requiring an l-value: " + "remove the cast or build with -fheinous-gnu-extensions">; + + def warn_invalid_asm_cast_lvalue : Warning< + "invalid use of a cast in a inline asm context requiring an l-value: " + "accepted due to -fheinous-gnu-extensions, but clang may remove support " + "for this in the future">; +} + +let CategoryName = "Semantic Issue" in { + +def err_invalid_conversion_between_vectors : Error< + "invalid conversion between vector type %0 and %1 of different size">; +def err_invalid_conversion_between_vector_and_integer : Error< + "invalid conversion between vector type %0 and integer type %1 " + "of different size">; + +def err_invalid_conversion_between_vector_and_scalar : Error< + "invalid conversion between vector type %0 and scalar type %1">; + +// C++ member initializers. +def err_only_constructors_take_base_inits : Error< + "only constructors take base initializers">; + +def err_multiple_mem_initialization : Error < + "multiple initializations given for non-static member %0">; +def err_multiple_mem_union_initialization : Error < + "initializing multiple members of union">; +def err_multiple_base_initialization : Error < + "multiple initializations given for base %0">; + +def err_mem_init_not_member_or_class : Error< + "member initializer %0 does not name a non-static data member or base " + "class">; + +def warn_initializer_out_of_order : Warning< + "%select{field|base class}0 %1 will be initialized after " + "%select{field|base}2 %3">, + InGroup<Reorder>, DefaultIgnore; + +def err_base_init_does_not_name_class : Error< + "constructor initializer %0 does not name a class">; +def err_base_init_direct_and_virtual : Error< + "base class initializer %0 names both a direct base class and an " + "inherited virtual base class">; +def err_not_direct_base_or_virtual : Error< + "type %0 is not a direct or virtual base of %1">; + +def err_in_class_initializer_non_const : Error< + "non-const static data member must be initialized out of line">; +def err_in_class_initializer_volatile : Error< + "static const volatile data member must be initialized out of line">; +def err_in_class_initializer_bad_type : Error< + "static data member of type %0 must be initialized out of line">; +def ext_in_class_initializer_float_type : ExtWarn< + "in-class initializer for static data member of type %0 is a GNU extension">, + InGroup<GNU>; +def note_in_class_initializer_float_type_constexpr : Note< + "use 'constexpr' specifier to silence this warning">; +def err_in_class_initializer_literal_type : Error< + "in-class initializer for static data member of type %0 requires " + "'constexpr' specifier">; +def err_in_class_initializer_non_constant : Error< + "in-class initializer for static data member is not a constant expression">; + +def ext_in_class_initializer_non_constant : Extension< + "in-class initializer for static data member is not a constant expression; " + "folding it to a constant is a GNU extension">; + +// C++ anonymous unions and GNU anonymous structs/unions +def ext_anonymous_union : Extension< + "anonymous unions are a C11 extension">, InGroup<C11>; +def ext_gnu_anonymous_struct : Extension< + "anonymous structs are a GNU extension">, InGroup<GNU>; +def ext_c11_anonymous_struct : Extension< + "anonymous structs are a C11 extension">, InGroup<C11>; +def err_anonymous_union_not_static : Error< + "anonymous unions at namespace or global scope must be declared 'static'">; +def err_anonymous_union_with_storage_spec : Error< + "anonymous union at class scope must not have a storage specifier">; +def err_anonymous_struct_not_member : Error< + "anonymous %select{structs|structs and classes}0 must be " + "%select{struct or union|class}0 members">; +def err_anonymous_union_member_redecl : Error< + "member of anonymous union redeclares %0">; +def err_anonymous_struct_member_redecl : Error< + "member of anonymous struct redeclares %0">; +def err_anonymous_record_with_type : Error< + "types cannot be declared in an anonymous %select{struct|union}0">; +def ext_anonymous_record_with_type : Extension< + "types declared in an anonymous %select{struct|union}0 are a Microsoft " + "extension">, InGroup<Microsoft>; +def err_anonymous_record_with_function : Error< + "functions cannot be declared in an anonymous %select{struct|union}0">; +def err_anonymous_record_with_static : Error< + "static members cannot be declared in an anonymous %select{struct|union}0">; +def err_anonymous_record_bad_member : Error< + "anonymous %select{struct|union}0 can only contain non-static data members">; +def err_anonymous_record_nonpublic_member : Error< + "anonymous %select{struct|union}0 cannot contain a " + "%select{private|protected}1 data member">; +def ext_ms_anonymous_struct : ExtWarn< + "anonymous structs are a Microsoft extension">, InGroup<Microsoft>; + +// C++ local classes +def err_reference_to_local_var_in_enclosing_function : Error< + "reference to local variable %0 declared in enclosing function %1">; +def err_reference_to_local_var_in_enclosing_block : Error< + "reference to local variable %0 declared in enclosing block literal">; +def err_reference_to_local_var_in_enclosing_lambda : Error< + "reference to local variable %0 declared in enclosing lambda expression">; +def err_reference_to_local_var_in_enclosing_context : Error< + "reference to local variable %0 declared in enclosing context">; + +def note_local_variable_declared_here : Note< + "%0 declared here">; +def err_static_data_member_not_allowed_in_local_class : Error< + "static data member %0 not allowed in local class %1">; + +// C++ derived classes +def err_base_clause_on_union : Error<"unions cannot have base classes">; +def err_base_must_be_class : Error<"base specifier must name a class">; +def err_union_as_base_class : Error<"unions cannot be base classes">; +def err_incomplete_base_class : Error<"base class has incomplete type">; +def err_duplicate_base_class : Error< + "base class %0 specified more than once as a direct base class">; +// FIXME: better way to display derivation? Pass entire thing into diagclient? +def err_ambiguous_derived_to_base_conv : Error< + "ambiguous conversion from derived class %0 to base class %1:%2">; +def err_ambiguous_memptr_conv : Error< + "ambiguous conversion from pointer to member of %select{base|derived}0 " + "class %1 to pointer to member of %select{derived|base}0 class %2:%3">; + +def err_memptr_conv_via_virtual : Error< + "conversion from pointer to member of class %0 to pointer to member " + "of class %1 via virtual base %2 is not allowed">; + +// C++ member name lookup +def err_ambiguous_member_multiple_subobjects : Error< + "non-static member %0 found in multiple base-class subobjects of type %1:%2">; +def err_ambiguous_member_multiple_subobject_types : Error< + "member %0 found in multiple base classes of different types">; +def note_ambiguous_member_found : Note<"member found by ambiguous name lookup">; +def err_ambiguous_reference : Error<"reference to %0 is ambiguous">; +def note_ambiguous_candidate : Note<"candidate found by name lookup is %q0">; +def err_ambiguous_tag_hiding : Error<"a type named %0 is hidden by a " + "declaration in a different namespace">; +def note_hidden_tag : Note<"type declaration hidden">; +def note_hiding_object : Note<"declaration hides type">; + +// C++ operator overloading +def err_operator_overload_needs_class_or_enum : Error< + "overloaded %0 must have at least one parameter of class " + "or enumeration type">; + +def err_operator_overload_variadic : Error<"overloaded %0 cannot be variadic">; +def err_operator_overload_static : Error< + "overloaded %0 cannot be a static member function">; +def err_operator_overload_default_arg : Error< + "parameter of overloaded %0 cannot have a default argument">; +def err_operator_overload_must_be : Error< + "overloaded %0 must be a %select{unary|binary|unary or binary}2 operator " + "(has %1 parameter%s1)">; + +def err_operator_overload_must_be_member : Error< + "overloaded %0 must be a non-static member function">; +def err_operator_overload_post_incdec_must_be_int : Error< + "parameter of overloaded post-%select{increment|decrement}1 operator must " + "have type 'int' (not %0)">; + +// C++ allocation and deallocation functions. +def err_operator_new_delete_declared_in_namespace : Error< + "%0 cannot be declared inside a namespace">; +def err_operator_new_delete_declared_static : Error< + "%0 cannot be declared static in global scope">; +def err_operator_new_delete_invalid_result_type : Error< + "%0 must return type %1">; +def err_operator_new_delete_dependent_result_type : Error< + "%0 cannot have a dependent return type; use %1 instead">; +def err_operator_new_delete_too_few_parameters : Error< + "%0 must have at least one parameter.">; +def err_operator_new_delete_template_too_few_parameters : Error< + "%0 template must have at least two parameters.">; + +def err_operator_new_dependent_param_type : Error< + "%0 cannot take a dependent type as first parameter; " + "use size_t (%1) instead">; +def err_operator_new_param_type : Error< + "%0 takes type size_t (%1) as first parameter">; +def err_operator_new_default_arg: Error< + "parameter of %0 cannot have a default argument">; +def err_operator_delete_dependent_param_type : Error< + "%0 cannot take a dependent type as first parameter; use %1 instead">; +def err_operator_delete_param_type : Error< + "first parameter of %0 must have type %1">; + +// C++ literal operators +def err_literal_operator_outside_namespace : Error< + "literal operator %0 must be in a namespace or global scope">; +def err_literal_operator_default_argument : Error< + "literal operator cannot have a default argument">; +// FIXME: This diagnostic sucks +def err_literal_operator_params : Error< + "parameter declaration for literal operator %0 is not valid">; +def err_literal_operator_extern_c : Error< + "literal operator must have C++ linkage">; +def warn_user_literal_reserved : Warning< + "user-defined literal suffixes not starting with '_' are reserved; " + "no literal will invoke this operator">, + InGroup<UserDefinedLiterals>; + +// C++ conversion functions +def err_conv_function_not_member : Error< + "conversion function must be a non-static member function">; +def err_conv_function_return_type : Error< + "conversion function cannot have a return type">; +def err_conv_function_with_params : Error< + "conversion function cannot have any parameters">; +def err_conv_function_variadic : Error< + "conversion function cannot be variadic">; +def err_conv_function_to_array : Error< + "conversion function cannot convert to an array type">; +def err_conv_function_to_function : Error< + "conversion function cannot convert to a function type">; +def err_conv_function_with_complex_decl : Error< + "must use a typedef to declare a conversion to %0">; +def err_conv_function_redeclared : Error< + "conversion function cannot be redeclared">; +def warn_conv_to_self_not_used : Warning< + "conversion function converting %0 to itself will never be used">; +def warn_conv_to_base_not_used : Warning< + "conversion function converting %0 to its base class %1 will never be used">; +def warn_conv_to_void_not_used : Warning< + "conversion function converting %0 to %1 will never be used">; + +def warn_not_compound_assign : Warning< + "use of unary operator that may be intended as compound assignment (%0=)">; + +// C++11 explicit conversion operators +def ext_explicit_conversion_functions : ExtWarn< + "explicit conversion functions are a C++11 extension">, InGroup<CXX11>; +def warn_cxx98_compat_explicit_conversion_functions : Warning< + "explicit conversion functions are incompatible with C++98">, + InGroup<CXX98Compat>, DefaultIgnore; + +// C++11 defaulted functions +def err_defaulted_default_ctor_params : Error< + "an explicitly-defaulted default constructor must have no parameters">; +def err_defaulted_copy_ctor_params : Error< + "an explicitly-defaulted copy constructor must have exactly one parameter">; +def err_defaulted_copy_ctor_volatile_param : Error< + "the parameter for an explicitly-defaulted copy constructor may not be " + "volatile">; +def err_defaulted_copy_ctor_const_param : Error< + "the parameter for this explicitly-defaulted copy constructor is const, but " + "a member or base requires it to be non-const">; +def err_defaulted_copy_assign_params : Error< + "an explicitly-defaulted copy assignment operator must have exactly one " + "parameter">; +def err_defaulted_copy_assign_return_type : Error< + "an explicitly-defaulted copy assignment operator must return an unqualified " + "lvalue reference to its class type">; +def err_defaulted_copy_assign_not_ref : Error< + "the parameter for an explicitly-defaulted copy assignment operator must be an " + "lvalue reference type">; +def err_defaulted_copy_assign_volatile_param : Error< + "the parameter for an explicitly-defaulted copy assignment operator may not " + "be volatile">; +def err_defaulted_copy_assign_const_param : Error< + "the parameter for this explicitly-defaulted copy assignment operator is " + "const, but a member or base requires it to be non-const">; +def err_defaulted_copy_assign_quals : Error< + "an explicitly-defaulted copy assignment operator may not have 'const', " + "'constexpr' or 'volatile' qualifiers">; +def err_defaulted_move_ctor_params : Error< + "an explicitly-defaulted move constructor must have exactly one parameter">; +def err_defaulted_move_ctor_volatile_param : Error< + "the parameter for an explicitly-defaulted move constructor may not be " + "volatile">; +def err_defaulted_move_ctor_const_param : Error< + "the parameter for an explicitly-defaulted move constructor may not be " + "const">; +def err_defaulted_move_assign_params : Error< + "an explicitly-defaulted move assignment operator must have exactly one " + "parameter">; +def err_defaulted_move_assign_return_type : Error< + "an explicitly-defaulted move assignment operator must return an unqualified " + "lvalue reference to its class type">; +def err_defaulted_move_assign_not_ref : Error< + "the parameter for an explicitly-defaulted move assignment operator must be an " + "rvalue reference type">; +def err_defaulted_move_assign_volatile_param : Error< + "the parameter for an explicitly-defaulted move assignment operator may not " + "be volatile">; +def err_defaulted_move_assign_const_param : Error< + "the parameter for an explicitly-defaulted move assignment operator may not " + "be const">; +def err_defaulted_move_assign_quals : Error< + "an explicitly-defaulted move assignment operator may not have 'const', " + "'constexpr' or 'volatile' qualifiers">; +def err_incorrect_defaulted_exception_spec : Error< + "exception specification of explicitly defaulted %select{default constructor|" + "copy constructor|move constructor|copy assignment operator|move assignment " + "operator|destructor}0 does not match the " + "calculated one">; +def err_incorrect_defaulted_constexpr : Error< + "defaulted definition of %select{default constructor|copy constructor|" + "move constructor}0 is not constexpr">; +def err_out_of_line_default_deletes : Error< + "defaulting this %select{default constructor|copy constructor|move " + "constructor|copy assignment operator|move assignment operator|destructor}0 " + "would delete it after its first declaration">; + +def warn_ptr_arith_precedes_bounds : Warning< + "the pointer decremented by %0 refers before the beginning of the array">, + InGroup<DiagGroup<"array-bounds-pointer-arithmetic">>, DefaultIgnore; +def warn_ptr_arith_exceeds_bounds : Warning< + "the pointer incremented by %0 refers past the end of the array (that " + "contains %1 element%s2)">, + InGroup<DiagGroup<"array-bounds-pointer-arithmetic">>, DefaultIgnore; +def warn_array_index_precedes_bounds : Warning< + "array index %0 is before the beginning of the array">, + InGroup<DiagGroup<"array-bounds">>; +def warn_array_index_exceeds_bounds : Warning< + "array index %0 is past the end of the array (which contains %1 " + "element%s2)">, InGroup<DiagGroup<"array-bounds">>; +def note_array_index_out_of_bounds : Note< + "array %0 declared here">; + +def warn_printf_write_back : Warning< + "use of '%%n' in format string discouraged (potentially insecure)">, + InGroup<FormatSecurity>; +def warn_printf_insufficient_data_args : Warning< + "more '%%' conversions than data arguments">, InGroup<Format>; +def warn_printf_data_arg_not_used : Warning< + "data argument not used by format string">, InGroup<FormatExtraArgs>; +def warn_format_invalid_conversion : Warning< + "invalid conversion specifier '%0'">, InGroup<FormatInvalidSpecifier>; +def warn_printf_incomplete_specifier : Warning< + "incomplete format specifier">, InGroup<Format>; +def warn_missing_format_string : Warning< + "format string missing">, InGroup<Format>; +def warn_scanf_nonzero_width : Warning< + "zero field width in scanf format string is unused">, + InGroup<Format>; +def warn_printf_conversion_argument_type_mismatch : Warning< + "format specifies type %0 but the argument has type %1">, + InGroup<Format>; +def warn_printf_positional_arg_exceeds_data_args : Warning < + "data argument position '%0' exceeds the number of data arguments (%1)">, + InGroup<Format>; +def warn_format_zero_positional_specifier : Warning< + "position arguments in format strings start counting at 1 (not 0)">, + InGroup<Format>; +def warn_format_invalid_positional_specifier : Warning< + "invalid position specified for %select{field width|field precision}0">, + InGroup<Format>; +def warn_format_mix_positional_nonpositional_args : Warning< + "cannot mix positional and non-positional arguments in format string">, + InGroup<Format>; +def warn_static_array_too_small : Warning< + "array argument is too small; contains %0 elements, callee requires at least %1">, + InGroup<DiagGroup<"array-bounds">>; +def note_callee_static_array : Note< + "callee declares array parameter as static here">; +def warn_empty_format_string : Warning< + "format string is empty">, InGroup<FormatZeroLength>; +def warn_format_string_is_wide_literal : Warning< + "format string should not be a wide string">, InGroup<Format>; +def warn_printf_format_string_contains_null_char : Warning< + "format string contains '\\0' within the string body">, InGroup<Format>; +def warn_printf_asterisk_missing_arg : Warning< + "'%select{*|.*}0' specified field %select{width|precision}0 is missing a matching 'int' argument">; +def warn_printf_asterisk_wrong_type : Warning< + "field %select{width|precision}0 should have type %1, but argument has type %2">, + InGroup<Format>; +def warn_printf_nonsensical_optional_amount: Warning< + "%select{field width|precision}0 used with '%1' conversion specifier, resulting in undefined behavior">, + InGroup<Format>; +def warn_printf_nonsensical_flag: Warning< + "flag '%0' results in undefined behavior with '%1' conversion specifier">, + InGroup<Format>; +def warn_format_nonsensical_length: Warning< + "length modifier '%0' results in undefined behavior or no effect with '%1' conversion specifier">, + InGroup<Format>; +def warn_format_non_standard_positional_arg: ExtWarn< + "positional arguments are not supported by ISO C">, InGroup<FormatNonStandard>, DefaultIgnore; +def warn_format_non_standard: ExtWarn< + "'%0' %select{length modifier|conversion specifier}1 is not supported by ISO C">, + InGroup<FormatNonStandard>, DefaultIgnore; +def warn_format_non_standard_conversion_spec: ExtWarn< + "using length modifier '%0' with conversion specifier '%1' is not supported by ISO C">, + InGroup<FormatNonStandard>, DefaultIgnore; +def warn_printf_ignored_flag: Warning< + "flag '%0' is ignored when flag '%1' is present">, + InGroup<Format>; +def warn_scanf_scanlist_incomplete : Warning< + "no closing ']' for '%%[' in scanf format string">, + InGroup<Format>; +def note_format_string_defined : Note<"format string is defined here">; + +def warn_null_arg : Warning< + "null passed to a callee which requires a non-null argument">, + InGroup<NonNull>; + +// CHECK: returning address/reference of stack memory +def warn_ret_stack_addr : Warning< + "address of stack memory associated with local variable %0 returned">, + InGroup<DiagGroup<"return-stack-address">>; +def warn_ret_stack_ref : Warning< + "reference to stack memory associated with local variable %0 returned">, + InGroup<DiagGroup<"return-stack-address">>; +def warn_ret_local_temp_addr : Warning< + "returning address of local temporary object">, + InGroup<DiagGroup<"return-stack-address">>; +def warn_ret_local_temp_ref : Warning< + "returning reference to local temporary object">, + InGroup<DiagGroup<"return-stack-address">>; +def warn_ret_addr_label : Warning< + "returning address of label, which is local">, + InGroup<DiagGroup<"return-stack-address">>; +def err_ret_local_block : Error< + "returning block that lives on the local stack">; +def note_ref_var_local_bind : Note< + "binding reference variable %0 here">; + +// Check for initializing a member variable with the address or a reference to +// a constructor parameter. +def warn_bind_ref_member_to_parameter : Warning< + "binding reference member %0 to stack allocated parameter %1">, + InGroup<DiagGroup<"dangling-field">>; +def warn_init_ptr_member_to_parameter_addr : Warning< + "initializing pointer member %0 with the stack address of parameter %1">, + InGroup<DiagGroup<"dangling-field">>; +def warn_bind_ref_member_to_temporary : Warning< + "binding reference member %0 to a temporary value">, + InGroup<DiagGroup<"dangling-field">>; +def note_ref_or_ptr_member_declared_here : Note< + "%select{reference|pointer}0 member declared here">; + +// For non-floating point, expressions of the form x == x or x != x +// should result in a warning, since these always evaluate to a constant. +// Array comparisons have similar warnings +def warn_comparison_always : Warning< + "%select{self-|array }0comparison always evaluates to %select{false|true|a constant}1">, + InGroup<TautologicalCompare>; + +def warn_stringcompare : Warning< + "result of comparison against %select{a string literal|@encode}0 is " + "unspecified (use strncmp instead)">, + InGroup<DiagGroup<"string-compare">>; + +// Generic selections. +def err_assoc_type_incomplete : Error< + "type %0 in generic association incomplete">; +def err_assoc_type_nonobject : Error< + "type %0 in generic association not an object type">; +def err_assoc_type_variably_modified : Error< + "type %0 in generic association is a variably modified type">; +def err_assoc_compatible_types : Error< + "type %0 in generic association compatible with previously specified type %1">; +def note_compat_assoc : Note< + "compatible type %0 specified here">; +def err_generic_sel_no_match : Error< + "controlling expression type %0 not compatible with any generic association type">; +def err_generic_sel_multi_match : Error< + "controlling expression type %0 compatible with %1 generic association types">; + + +// Blocks +def err_blocks_disable : Error<"blocks support disabled - compile with -fblocks" + " or pick a deployment target that supports them">; +def err_block_returning_array_function : Error< + "block cannot return %select{array|function}0 type %1">; + +// Builtin annotation string. +def err_builtin_annotation_not_string_constant : Error< + "__builtin_annotation requires a non wide string constant">; + +// CFString checking +def err_cfstring_literal_not_string_constant : Error< + "CFString literal is not a string constant">, + InGroup<DiagGroup<"CFString-literal">>; +def warn_cfstring_truncated : Warning< + "input conversion stopped due to an input byte that does not " + "belong to the input codeset UTF-8">, + InGroup<DiagGroup<"CFString-literal">>; + +// Statements. +def err_continue_not_in_loop : Error< + "'continue' statement not in loop statement">; +def err_break_not_in_loop_or_switch : Error< + "'break' statement not in loop or switch statement">; +def err_default_not_in_switch : Error< + "'default' statement not in switch statement">; +def err_case_not_in_switch : Error<"'case' statement not in switch statement">; +def warn_bool_switch_condition : Warning< + "switch condition has boolean value">; +def warn_case_value_overflow : Warning< + "overflow converting case value to switch condition type (%0 to %1)">, + InGroup<DiagGroup<"switch">>; +def err_duplicate_case : Error<"duplicate case value '%0'">; +def warn_case_empty_range : Warning<"empty case range specified">; +def warn_missing_case_for_condition : + Warning<"no case matching constant switch condition '%0'">; + +def warn_def_missing_case1 : Warning< + "enumeration value %0 not explicitly handled in switch">, + InGroup<SwitchEnum>, DefaultIgnore; +def warn_def_missing_case2 : Warning< + "enumeration values %0 and %1 not explicitly handled in switch">, + InGroup<SwitchEnum>, DefaultIgnore; +def warn_def_missing_case3 : Warning< + "enumeration values %0, %1, and %2 not explicitly handled in switch">, + InGroup<SwitchEnum>, DefaultIgnore; +def warn_def_missing_cases : Warning< + "%0 enumeration values not explicitly handled in switch: %1, %2, %3...">, + InGroup<SwitchEnum>, DefaultIgnore; + +def warn_missing_case1 : Warning<"enumeration value %0 not handled in switch">, + InGroup<Switch>; +def warn_missing_case2 : Warning< + "enumeration values %0 and %1 not handled in switch">, + InGroup<Switch>; +def warn_missing_case3 : Warning< + "enumeration values %0, %1, and %2 not handled in switch">, + InGroup<Switch>; +def warn_missing_cases : Warning< + "%0 enumeration values not handled in switch: %1, %2, %3...">, + InGroup<Switch>; + +def warn_unreachable_default : Warning< + "default label in switch which covers all enumeration values">, + InGroup<CoveredSwitchDefault>, DefaultIgnore; +def warn_not_in_enum : Warning<"case value not in enumerated type %0">, + InGroup<Switch>; +def err_typecheck_statement_requires_scalar : Error< + "statement requires expression of scalar type (%0 invalid)">; +def err_typecheck_statement_requires_integer : Error< + "statement requires expression of integer type (%0 invalid)">; +def err_multiple_default_labels_defined : Error< + "multiple default labels in one switch">; +def err_switch_multiple_conversions : Error< + "multiple conversions from switch condition type %0 to an integral or " + "enumeration type">; +def note_switch_conversion : Note< + "conversion to %select{integral|enumeration}0 type %1">; +def err_switch_explicit_conversion : Error< + "switch condition type %0 requires explicit conversion to %1">; +def err_switch_incomplete_class_type : Error< + "switch condition has incomplete class type %0">; + +def warn_empty_if_body : Warning< + "if statement has empty body">, InGroup<EmptyBody>; +def warn_empty_for_body : Warning< + "for loop has empty body">, InGroup<EmptyBody>; +def warn_empty_range_based_for_body : Warning< + "range-based for loop has empty body">, InGroup<EmptyBody>; +def warn_empty_while_body : Warning< + "while loop has empty body">, InGroup<EmptyBody>; +def warn_empty_switch_body : Warning< + "switch statement has empty body">, InGroup<EmptyBody>; +def note_empty_body_on_separate_line : Note< + "put the semicolon on a separate line to silence this warning">, + InGroup<EmptyBody>; + +def err_va_start_used_in_non_variadic_function : Error< + "'va_start' used in function with fixed args">; +def warn_second_parameter_of_va_start_not_last_named_argument : Warning< + "second parameter of 'va_start' not last named argument">; +def err_first_argument_to_va_arg_not_of_type_va_list : Error< + "first argument to 'va_arg' is of type %0 and not 'va_list'">; +def err_second_parameter_to_va_arg_incomplete: Error< + "second argument to 'va_arg' is of incomplete type %0">; +def err_second_parameter_to_va_arg_abstract: Error< + "second argument to 'va_arg' is of abstract type %0">; +def warn_second_parameter_to_va_arg_not_pod : Warning< + "second argument to 'va_arg' is of non-POD type %0">, + InGroup<DiagGroup<"non-pod-varargs">>, DefaultError; +def warn_second_parameter_to_va_arg_ownership_qualified : Warning< + "second argument to 'va_arg' is of ARC ownership-qualified type %0">, + InGroup<DiagGroup<"non-pod-varargs">>, DefaultError; +def warn_second_parameter_to_va_arg_never_compatible : Warning< + "second argument to 'va_arg' is of promotable type %0; this va_arg has " + "undefined behavior because arguments will be promoted to %1">; + +def warn_return_missing_expr : Warning< + "non-void %select{function|method}1 %0 should return a value">, DefaultError, + InGroup<ReturnType>; +def ext_return_missing_expr : ExtWarn< + "non-void %select{function|method}1 %0 should return a value">, DefaultError, + InGroup<ReturnType>; +def ext_return_has_expr : ExtWarn< + "%select{void function|void method|constructor|destructor}1 %0 " + "should not return a value">, + DefaultError, InGroup<ReturnType>; +def ext_return_has_void_expr : Extension< + "void %select{function|method|block}1 %0 should not return void expression">; +def err_return_init_list : Error< + "%select{void function|void method|constructor|destructor}1 %0 " + "must not return a value">; +def warn_noreturn_function_has_return_expr : Warning< + "function %0 declared 'noreturn' should not return">, + InGroup<DiagGroup<"invalid-noreturn">>; +def warn_falloff_noreturn_function : Warning< + "function declared 'noreturn' should not return">, + InGroup<DiagGroup<"invalid-noreturn">>; +def err_noreturn_block_has_return_expr : Error< + "block declared 'noreturn' should not return">; +def err_block_on_nonlocal : Error< + "__block attribute not allowed, only allowed on local variables">; +def err_block_on_vm : Error< + "__block attribute not allowed on declaration with a variably modified type">; + +def err_shufflevector_non_vector : Error< + "first two arguments to __builtin_shufflevector must be vectors">; +def err_shufflevector_incompatible_vector : Error< + "first two arguments to __builtin_shufflevector must have the same type">; +def err_shufflevector_nonconstant_argument : Error< + "index for __builtin_shufflevector must be a constant integer">; +def err_shufflevector_argument_too_large : Error< + "index for __builtin_shufflevector must be less than the total number " + "of vector elements">; + +def err_vector_incorrect_num_initializers : Error< + "%select{too many|too few}0 elements in vector initialization (expected %1 elements, have %2)">; +def err_altivec_empty_initializer : Error<"expected initializer">; + +def err_invalid_neon_type_code : Error< + "incompatible constant for this __builtin_neon function">; +def err_argument_invalid_range : Error< + "argument should be a value from %0 to %1">; + +def err_builtin_longjmp_invalid_val : Error< + "argument to __builtin_longjmp must be a constant 1">; + +def err_constant_integer_arg_type : Error< + "argument to %0 must be a constant integer">; + +def ext_mixed_decls_code : Extension< + "ISO C90 forbids mixing declarations and code">, + InGroup<DiagGroup<"declaration-after-statement">>; + +def err_non_variable_decl_in_for : Error< + "declaration of non-local variable in 'for' loop">; +def err_toomany_element_decls : Error< + "only one element declaration is allowed">; +def err_selector_element_not_lvalue : Error< + "selector element is not a valid lvalue">; +def err_selector_element_type : Error< + "selector element type %0 is not a valid object">; +def err_collection_expr_type : Error< + "collection expression type %0 is not a valid object">; +def warn_collection_expr_type : Warning< + "collection expression type %0 may not respond to %1">; + +def err_invalid_conversion_between_ext_vectors : Error< + "invalid conversion between ext-vector type %0 and %1">; + +// Type +def ext_invalid_sign_spec : Extension<"'%0' cannot be signed or unsigned">; +def warn_receiver_forward_class : Warning< + "receiver %0 is a forward class and corresponding @interface may not exist">; +def note_method_sent_forward_class : Note<"method %0 is used for the forward class">; +def ext_missing_declspec : ExtWarn< + "declaration specifier missing, defaulting to 'int'">; +def ext_missing_type_specifier : ExtWarn< + "type specifier missing, defaults to 'int'">, + InGroup<ImplicitInt>; +def err_decimal_unsupported : Error< + "GNU decimal type extension not supported">; +def err_missing_type_specifier : Error< + "C++ requires a type specifier for all declarations">; +def err_objc_array_of_interfaces : Error< + "array of interface %0 is invalid (probably should be an array of pointers)">; +def ext_c99_array_usage : Extension< + "%select{qualifier in |static |}0array size %select{||'[*] '}0is a C99 " + "feature">, InGroup<C99>; +def err_c99_array_usage_cxx : Error< + "%select{qualifier in |static |}0array size %select{||'[*] '}0is a C99 " + "feature, not permitted in C++">; +def err_double_requires_fp64 : Error< + "use of type 'double' requires cl_khr_fp64 extension to be enabled">; +def err_nsconsumed_attribute_mismatch : Error< + "overriding method has mismatched ns_consumed attribute on its" + " parameter">; +def err_nsreturns_retained_attribute_mismatch : Error< + "overriding method has mismatched ns_returns_%select{not_retained|retained}0" + " attributes">; + +def note_getter_unavailable : Note< + "or because setter is declared here, but no getter method %0 is found">; +def err_invalid_protocol_qualifiers : Error< + "invalid protocol qualifiers on non-ObjC type">; +def warn_ivar_use_hidden : Warning< + "local declaration of %0 hides instance variable">, + InGroup<DiagGroup<"shadow-ivar">>; +def error_ivar_use_in_class_method : Error< + "instance variable %0 accessed in class method">; +def error_implicit_ivar_access : Error< + "instance variable %0 cannot be accessed because 'self' has been redeclared">; +def error_private_ivar_access : Error<"instance variable %0 is private">, + AccessControl; +def error_protected_ivar_access : Error<"instance variable %0 is protected">, + AccessControl; +def warn_maynot_respond : Warning<"%0 may not respond to %1">; +def warn_attribute_method_def : Warning< + "attributes on method implementation and its declaration must match">, + InGroup<DiagGroup<"mismatched-method-attributes">>; +def ext_typecheck_base_super : Warning< + "method parameter type %0 does not match " + "super class method parameter type %1">, InGroup<SuperSubClassMismatch>, DefaultIgnore; +def warn_missing_method_return_type : Warning< + "method has no return type specified; defaults to 'id'">, + InGroup<MissingMethodReturnType>, DefaultIgnore; + +// Spell-checking diagnostics +def err_unknown_typename_suggest : Error< + "unknown type name %0; did you mean %1?">; +def err_unknown_nested_typename_suggest : Error< + "no type named %0 in %1; did you mean %2?">; +def err_no_member_suggest : Error<"no member named %0 in %1; did you mean %2?">; +def err_undeclared_use_suggest : Error< + "use of undeclared %0; did you mean %1?">; +def err_undeclared_var_use_suggest : Error< + "use of undeclared identifier %0; did you mean %1?">; +def err_no_template_suggest : Error<"no template named %0; did you mean %1?">; +def err_no_member_template_suggest : Error< + "no template named %0 in %1; did you mean %2?">; +def err_mem_init_not_member_or_class_suggest : Error< + "initializer %0 does not name a non-static data member or base " + "class; did you mean the %select{base class|member}1 %2?">; +def err_field_designator_unknown_suggest : Error< + "field designator %0 does not refer to any field in type %1; did you mean " + "%2?">; +def err_typecheck_member_reference_ivar_suggest : Error< + "%0 does not have a member named %1; did you mean %2?">; +def err_property_not_found_suggest : Error< + "property %0 not found on object of type %1; did you mean %2?">; +def err_ivar_access_using_property_syntax_suggest : Error< + "property %0 not found on object of type %1; did you mean to access ivar %2?">; +def err_property_found_suggest : Error< + "property %0 found on object of type %1; did you mean to access " + "it with the \".\" operator?">; +def err_undef_interface_suggest : Error< + "cannot find interface declaration for %0; did you mean %1?">; +def warn_undef_interface_suggest : Warning< + "cannot find interface declaration for %0; did you mean %1?">; +def err_undef_superclass_suggest : Error< + "cannot find interface declaration for %0, superclass of %1; did you mean " + "%2?">; +def err_undeclared_protocol_suggest : Error< + "cannot find protocol declaration for %0; did you mean %1?">; +def note_base_class_specified_here : Note< + "base class %0 specified here">; +def err_using_directive_suggest : Error< + "no namespace named %0; did you mean %1?">; +def err_using_directive_member_suggest : Error< + "no namespace named %0 in %1; did you mean %2?">; +def note_namespace_defined_here : Note<"namespace %0 defined here">; +def err_sizeof_pack_no_pack_name_suggest : Error< + "%0 does not refer to the name of a parameter pack; did you mean %1?">; +def note_parameter_pack_here : Note<"parameter pack %0 declared here">; + +def err_uncasted_use_of_unknown_any : Error< + "%0 has unknown type; cast it to its declared type to use it">; +def err_uncasted_call_of_unknown_any : Error< + "%0 has unknown return type; cast the call to its declared return type">; +def err_uncasted_send_to_unknown_any_method : Error< + "no known method %select{%objcinstance1|%objcclass1}0; cast the " + "message send to the method's return type">; +def err_unsupported_unknown_any_decl : Error< + "%0 has unknown type, which is unsupported for this kind of declaration">; +def err_unsupported_unknown_any_expr : Error< + "unsupported expression with unknown type">; +def err_unsupported_unknown_any_call : Error< + "call to unsupported expression with unknown type">; +def err_unknown_any_addrof : Error< + "the address of a declaration with unknown type " + "can only be cast to a pointer type">; +def err_unknown_any_var_function_type : Error< + "variable %0 with unknown type cannot be given a function type">; +def err_unknown_any_function : Error< + "function %0 with unknown type must be given a function type">; + +def err_filter_expression_integral : Error< + "filter expression type should be an integral value not %0">; + +// OpenCL warnings and errors. +def err_invalid_astype_of_different_size : Error< + "invalid reinterpretation: sizes of %0 and %1 must match">; + +} // end of sema category + +let CategoryName = "Related Result Type Issue" in { +// Objective-C related result type compatibility +def warn_related_result_type_compatibility_class : Warning< + "method is expected to return an instance of its class type %0, but " + "is declared to return %1">; +def warn_related_result_type_compatibility_protocol : Warning< + "protocol method is expected to return an instance of the implementing " + "class, but is declared to return %0">; +def note_related_result_type_overridden_family : Note< + "overridden method is part of the '%select{|alloc|copy|init|mutableCopy|" + "new|autorelease|dealloc|finalize|release|retain|retainCount|self}0' method " + "family">; +def note_related_result_type_overridden : Note< + "overridden method returns an instance of its class type">; +def note_related_result_type_inferred : Note< + "%select{class|instance}0 method %1 is assumed to return an instance of " + "its receiver type (%2)">; + +} + +let CategoryName = "Modules Issue" in { +def err_module_private_specialization : Error< + "%select{template|partial|member}0 specialization cannot be " + "declared __module_private__">; +def err_module_private_local : Error< + "%select{local variable|parameter|typedef}0 %1 cannot be declared " + "__module_private__">; +def err_module_private_local_class : Error< + "local %select{struct|union|class|enum}0 cannot be declared " + "__module_private__">; +def err_module_private_definition : Error< + "definition of %0 must be imported before it is required">; +} + +} // end of sema component. + diff --git a/clang/include/clang/Basic/DiagnosticSerializationKinds.td b/clang/include/clang/Basic/DiagnosticSerializationKinds.td new file mode 100644 index 0000000..7f9fe26 --- /dev/null +++ b/clang/include/clang/Basic/DiagnosticSerializationKinds.td @@ -0,0 +1,60 @@ +//==--- DiagnosticSerializationKinds.td - serialization diagnostics -------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +let Component = "Serialization" in { + +def err_fe_unable_to_read_pch_file : Error< + "unable to read PCH file: '%0'">; +def err_fe_not_a_pch_file : Error< + "input is not a PCH file: '%0'">; +def err_fe_pch_malformed : Error< + "malformed or corrupted PCH file: '%0'">, DefaultFatal; +def err_fe_pch_malformed_block : Error< + "malformed block record in PCH file: '%0'">, DefaultFatal; +def err_fe_pch_error_at_end_block : Error< + "error at end of module block in PCH file: '%0'">, DefaultFatal; +def err_fe_pch_file_modified : Error< + "file '%0' has been modified since the precompiled header was built">, + DefaultFatal; + +def warn_pch_target_triple : Error< + "PCH file was compiled for the target '%0' but the current translation " + "unit is being compiled for target '%1'">; +def err_pch_langopt_mismatch : Error<"%0 was %select{disabled|enabled}1 in " + "PCH file but is currently %select{disabled|enabled}2">; +def err_pch_langopt_value_mismatch : Error< + "%0 differs in PCH file vs. current file">; + +def warn_pch_version_too_old : Error< + "PCH file uses an older PCH format that is no longer supported">; +def warn_pch_version_too_new : Error< + "PCH file uses a newer PCH format that cannot be read">; +def warn_pch_different_branch : Error< + "PCH file built from a different branch (%0) than the compiler (%1)">; +def err_pch_with_compiler_errors : Error< + "PCH file contains compiler errors">; +def warn_cmdline_conflicting_macro_def : Error< + "definition of the macro '%0' conflicts with the definition used to " + "build the precompiled header">; +def note_pch_macro_defined_as : Note< + "definition of macro '%0' in the precompiled header">; +def warn_cmdline_missing_macro_defs : Warning< + "macro definitions used to build the precompiled header are missing">; +def note_using_macro_def_from_pch : Note< + "using this macro definition from precompiled header">; +def warn_macro_name_used_in_pch : Error< + "definition of macro %0 conflicts with an identifier used in the " + "precompiled header">; +def warn_pch_compiler_options_mismatch : Error< + "compiler options used when building the precompiled header differ from " + "the options used when using the precompiled header">; + +def err_not_a_pch_file : Error< + "'%0' does not appear to be a precompiled header file">, DefaultFatal; +} diff --git a/clang/include/clang/Basic/ExceptionSpecificationType.h b/clang/include/clang/Basic/ExceptionSpecificationType.h new file mode 100644 index 0000000..e911bde --- /dev/null +++ b/clang/include/clang/Basic/ExceptionSpecificationType.h @@ -0,0 +1,54 @@ +//===--- ExceptionSpecificationType.h ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ExceptionSpecificationType enumeration and various +// utility functions. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_BASIC_EXCEPTIONSPECIFICATIONTYPE_H +#define LLVM_CLANG_BASIC_EXCEPTIONSPECIFICATIONTYPE_H + +namespace clang { + +/// \brief The various types of exception specifications that exist in C++11. +enum ExceptionSpecificationType { + EST_None, ///< no exception specification + EST_DynamicNone, ///< throw() + EST_Dynamic, ///< throw(T1, T2) + EST_MSAny, ///< Microsoft throw(...) extension + EST_BasicNoexcept, ///< noexcept + EST_ComputedNoexcept, ///< noexcept(expression) + EST_Delayed, ///< not known yet + EST_Uninstantiated ///< not instantiated yet +}; + +inline bool isDynamicExceptionSpec(ExceptionSpecificationType ESpecType) { + return ESpecType >= EST_DynamicNone && ESpecType <= EST_MSAny; +} + +inline bool isNoexceptExceptionSpec(ExceptionSpecificationType ESpecType) { + return ESpecType == EST_BasicNoexcept || ESpecType == EST_ComputedNoexcept; +} + +/// \brief Possible results from evaluation of a noexcept expression. +enum CanThrowResult { + CT_Cannot, + CT_Dependent, + CT_Can +}; + +inline CanThrowResult mergeCanThrow(CanThrowResult CT1, CanThrowResult CT2) { + // CanThrowResult constants are ordered so that the maximum is the correct + // merge result. + return CT1 > CT2 ? CT1 : CT2; +} + +} // end namespace clang + +#endif // LLVM_CLANG_BASIC_EXCEPTIONSPECIFICATIONTYPE_H diff --git a/clang/include/clang/Basic/ExpressionTraits.h b/clang/include/clang/Basic/ExpressionTraits.h new file mode 100644 index 0000000..c4e6a1c --- /dev/null +++ b/clang/include/clang/Basic/ExpressionTraits.h @@ -0,0 +1,25 @@ +//===- ExpressionTraits.h - C++ Expression Traits Support Enums -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines enumerations for expression traits intrinsics. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_EXPRESSIONTRAITS_H +#define LLVM_CLANG_EXPRESSIONTRAITS_H + +namespace clang { + + enum ExpressionTrait { + ET_IsLValueExpr, + ET_IsRValueExpr + }; +} + +#endif diff --git a/clang/include/clang/Basic/FileManager.h b/clang/include/clang/Basic/FileManager.h new file mode 100644 index 0000000..5c7d9eb --- /dev/null +++ b/clang/include/clang/Basic/FileManager.h @@ -0,0 +1,234 @@ +//===--- FileManager.h - File System Probing and Caching --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the FileManager interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FILEMANAGER_H +#define LLVM_CLANG_FILEMANAGER_H + +#include "clang/Basic/FileSystemOptions.h" +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/Support/Allocator.h" +// FIXME: Enhance libsystem to support inode and other fields in stat. +#include <sys/types.h> + +#ifdef _MSC_VER +typedef unsigned short mode_t; +#endif + +struct stat; + +namespace llvm { +class MemoryBuffer; +namespace sys { class Path; } +} + +namespace clang { +class FileManager; +class FileSystemStatCache; + +/// DirectoryEntry - Cached information about one directory (either on +/// the disk or in the virtual file system). +/// +class DirectoryEntry { + const char *Name; // Name of the directory. + friend class FileManager; +public: + DirectoryEntry() : Name(0) {} + const char *getName() const { return Name; } +}; + +/// FileEntry - Cached information about one file (either on the disk +/// or in the virtual file system). If the 'FD' member is valid, then +/// this FileEntry has an open file descriptor for the file. +/// +class FileEntry { + const char *Name; // Name of the file. + off_t Size; // File size in bytes. + time_t ModTime; // Modification time of file. + const DirectoryEntry *Dir; // Directory file lives in. + unsigned UID; // A unique (small) ID for the file. + dev_t Device; // ID for the device containing the file. + ino_t Inode; // Inode number for the file. + mode_t FileMode; // The file mode as returned by 'stat'. + + /// FD - The file descriptor for the file entry if it is opened and owned + /// by the FileEntry. If not, this is set to -1. + mutable int FD; + friend class FileManager; + +public: + FileEntry(dev_t device, ino_t inode, mode_t m) + : Name(0), Device(device), Inode(inode), FileMode(m), FD(-1) {} + // Add a default constructor for use with llvm::StringMap + FileEntry() : Name(0), Device(0), Inode(0), FileMode(0), FD(-1) {} + + FileEntry(const FileEntry &FE) { + memcpy(this, &FE, sizeof(FE)); + assert(FD == -1 && "Cannot copy a file-owning FileEntry"); + } + + void operator=(const FileEntry &FE) { + memcpy(this, &FE, sizeof(FE)); + assert(FD == -1 && "Cannot assign a file-owning FileEntry"); + } + + ~FileEntry(); + + const char *getName() const { return Name; } + off_t getSize() const { return Size; } + unsigned getUID() const { return UID; } + ino_t getInode() const { return Inode; } + dev_t getDevice() const { return Device; } + time_t getModificationTime() const { return ModTime; } + mode_t getFileMode() const { return FileMode; } + + /// getDir - Return the directory the file lives in. + /// + const DirectoryEntry *getDir() const { return Dir; } + + bool operator<(const FileEntry &RHS) const { + return Device < RHS.Device || (Device == RHS.Device && Inode < RHS.Inode); + } +}; + +/// FileManager - Implements support for file system lookup, file system +/// caching, and directory search management. This also handles more advanced +/// properties, such as uniquing files based on "inode", so that a file with two +/// names (e.g. symlinked) will be treated as a single file. +/// +class FileManager : public RefCountedBase<FileManager> { + FileSystemOptions FileSystemOpts; + + class UniqueDirContainer; + class UniqueFileContainer; + + /// UniqueRealDirs/UniqueRealFiles - Cache for existing real + /// directories/files. + /// + UniqueDirContainer &UniqueRealDirs; + UniqueFileContainer &UniqueRealFiles; + + /// \brief The virtual directories that we have allocated. For each + /// virtual file (e.g. foo/bar/baz.cpp), we add all of its parent + /// directories (foo/ and foo/bar/) here. + SmallVector<DirectoryEntry*, 4> VirtualDirectoryEntries; + /// \brief The virtual files that we have allocated. + SmallVector<FileEntry*, 4> VirtualFileEntries; + + /// SeenDirEntries/SeenFileEntries - This is a cache that maps paths + /// to directory/file entries (either real or virtual) we have + /// looked up. The actual Entries for real directories/files are + /// owned by UniqueRealDirs/UniqueRealFiles above, while the Entries + /// for virtual directories/files are owned by + /// VirtualDirectoryEntries/VirtualFileEntries above. + /// + llvm::StringMap<DirectoryEntry*, llvm::BumpPtrAllocator> SeenDirEntries; + llvm::StringMap<FileEntry*, llvm::BumpPtrAllocator> SeenFileEntries; + + /// NextFileUID - Each FileEntry we create is assigned a unique ID #. + /// + unsigned NextFileUID; + + // Statistics. + unsigned NumDirLookups, NumFileLookups; + unsigned NumDirCacheMisses, NumFileCacheMisses; + + // Caching. + OwningPtr<FileSystemStatCache> StatCache; + + bool getStatValue(const char *Path, struct stat &StatBuf, + int *FileDescriptor); + + /// Add all ancestors of the given path (pointing to either a file + /// or a directory) as virtual directories. + void addAncestorsAsVirtualDirs(StringRef Path); + +public: + FileManager(const FileSystemOptions &FileSystemOpts); + ~FileManager(); + + /// \brief Installs the provided FileSystemStatCache object within + /// the FileManager. + /// + /// Ownership of this object is transferred to the FileManager. + /// + /// \param statCache the new stat cache to install. Ownership of this + /// object is transferred to the FileManager. + /// + /// \param AtBeginning whether this new stat cache must be installed at the + /// beginning of the chain of stat caches. Otherwise, it will be added to + /// the end of the chain. + void addStatCache(FileSystemStatCache *statCache, bool AtBeginning = false); + + /// \brief Removes the specified FileSystemStatCache object from the manager. + void removeStatCache(FileSystemStatCache *statCache); + + /// getDirectory - Lookup, cache, and verify the specified directory + /// (real or virtual). This returns NULL if the directory doesn't exist. + /// + /// \param CacheFailure If true and the file does not exist, we'll cache + /// the failure to find this file. + const DirectoryEntry *getDirectory(StringRef DirName, + bool CacheFailure = true); + + /// \brief Lookup, cache, and verify the specified file (real or + /// virtual). This returns NULL if the file doesn't exist. + /// + /// \param OpenFile if true and the file exists, it will be opened. + /// + /// \param CacheFailure If true and the file does not exist, we'll cache + /// the failure to find this file. + const FileEntry *getFile(StringRef Filename, bool OpenFile = false, + bool CacheFailure = true); + + /// \brief Returns the current file system options + const FileSystemOptions &getFileSystemOptions() { return FileSystemOpts; } + + /// \brief Retrieve a file entry for a "virtual" file that acts as + /// if there were a file with the given name on disk. The file + /// itself is not accessed. + const FileEntry *getVirtualFile(StringRef Filename, off_t Size, + time_t ModificationTime); + + /// \brief Open the specified file as a MemoryBuffer, returning a new + /// MemoryBuffer if successful, otherwise returning null. + llvm::MemoryBuffer *getBufferForFile(const FileEntry *Entry, + std::string *ErrorStr = 0); + llvm::MemoryBuffer *getBufferForFile(StringRef Filename, + std::string *ErrorStr = 0); + + // getNoncachedStatValue - Will get the 'stat' information for the given path. + // If the path is relative, it will be resolved against the WorkingDir of the + // FileManager's FileSystemOptions. + bool getNoncachedStatValue(StringRef Path, struct stat &StatBuf); + + /// \brief If path is not absolute and FileSystemOptions set the working + /// directory, the path is modified to be relative to the given + /// working directory. + void FixupRelativePath(SmallVectorImpl<char> &path) const; + + /// \brief Produce an array mapping from the unique IDs assigned to each + /// file to the corresponding FileEntry pointer. + void GetUniqueIDMapping( + SmallVectorImpl<const FileEntry *> &UIDToFiles) const; + + void PrintStats() const; +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Basic/FileSystemOptions.h b/clang/include/clang/Basic/FileSystemOptions.h new file mode 100644 index 0000000..81e928d --- /dev/null +++ b/clang/include/clang/Basic/FileSystemOptions.h @@ -0,0 +1,31 @@ +//===--- FileSystemOptions.h - File System Options --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the FileSystemOptions interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_FILESYSTEMOPTIONS_H +#define LLVM_CLANG_BASIC_FILESYSTEMOPTIONS_H + +#include <string> + +namespace clang { + +/// \brief Keeps track of options that affect how file operations are performed. +class FileSystemOptions { +public: + /// \brief If set, paths are resolved as if the working directory was + /// set to the value of WorkingDir. + std::string WorkingDir; +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Basic/FileSystemStatCache.h b/clang/include/clang/Basic/FileSystemStatCache.h new file mode 100644 index 0000000..96a2f90 --- /dev/null +++ b/clang/include/clang/Basic/FileSystemStatCache.h @@ -0,0 +1,103 @@ +//===--- FileSystemStatCache.h - Caching for 'stat' calls -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the FileSystemStatCache interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FILESYSTEMSTATCACHE_H +#define LLVM_CLANG_FILESYSTEMSTATCACHE_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/StringMap.h" +#include <sys/types.h> +#include <sys/stat.h> + +namespace clang { + +/// \brief Abstract interface for introducing a FileManager cache for 'stat' +/// system calls, which is used by precompiled and pretokenized headers to +/// improve performance. +class FileSystemStatCache { + virtual void anchor(); +protected: + OwningPtr<FileSystemStatCache> NextStatCache; + +public: + virtual ~FileSystemStatCache() {} + + enum LookupResult { + CacheExists, //< We know the file exists and its cached stat data. + CacheMissing //< We know that the file doesn't exist. + }; + + /// FileSystemStatCache::get - Get the 'stat' information for the specified + /// path, using the cache to accellerate it if possible. This returns true if + /// the path does not exist or false if it exists. + /// + /// If FileDescriptor is non-null, then this lookup should only return success + /// for files (not directories). If it is null this lookup should only return + /// success for directories (not files). On a successful file lookup, the + /// implementation can optionally fill in FileDescriptor with a valid + /// descriptor and the client guarantees that it will close it. + static bool get(const char *Path, struct stat &StatBuf, int *FileDescriptor, + FileSystemStatCache *Cache); + + + /// \brief Sets the next stat call cache in the chain of stat caches. + /// Takes ownership of the given stat cache. + void setNextStatCache(FileSystemStatCache *Cache) { + NextStatCache.reset(Cache); + } + + /// \brief Retrieve the next stat call cache in the chain. + FileSystemStatCache *getNextStatCache() { return NextStatCache.get(); } + + /// \brief Retrieve the next stat call cache in the chain, transferring + /// ownership of this cache (and, transitively, all of the remaining caches) + /// to the caller. + FileSystemStatCache *takeNextStatCache() { return NextStatCache.take(); } + +protected: + virtual LookupResult getStat(const char *Path, struct stat &StatBuf, + int *FileDescriptor) = 0; + + LookupResult statChained(const char *Path, struct stat &StatBuf, + int *FileDescriptor) { + if (FileSystemStatCache *Next = getNextStatCache()) + return Next->getStat(Path, StatBuf, FileDescriptor); + + // If we hit the end of the list of stat caches to try, just compute and + // return it without a cache. + return get(Path, StatBuf, FileDescriptor, 0) ? CacheMissing : CacheExists; + } +}; + +/// \brief A stat "cache" that can be used by FileManager to keep +/// track of the results of stat() calls that occur throughout the +/// execution of the front end. +class MemorizeStatCalls : public FileSystemStatCache { +public: + /// \brief The set of stat() calls that have been seen. + llvm::StringMap<struct stat, llvm::BumpPtrAllocator> StatCalls; + + typedef llvm::StringMap<struct stat, llvm::BumpPtrAllocator>::const_iterator + iterator; + + iterator begin() const { return StatCalls.begin(); } + iterator end() const { return StatCalls.end(); } + + virtual LookupResult getStat(const char *Path, struct stat &StatBuf, + int *FileDescriptor); +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Basic/IdentifierTable.h b/clang/include/clang/Basic/IdentifierTable.h new file mode 100644 index 0000000..cc0080b --- /dev/null +++ b/clang/include/clang/Basic/IdentifierTable.h @@ -0,0 +1,809 @@ +//===--- IdentifierTable.h - Hash table for identifier lookup ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the IdentifierInfo, IdentifierTable, and Selector +// interfaces. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_IDENTIFIERTABLE_H +#define LLVM_CLANG_BASIC_IDENTIFIERTABLE_H + +#include "clang/Basic/OperatorKinds.h" +#include "clang/Basic/TokenKinds.h" +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/Support/PointerLikeTypeTraits.h" +#include <cassert> +#include <string> + +namespace llvm { + template <typename T> struct DenseMapInfo; +} + +namespace clang { + class LangOptions; + class IdentifierInfo; + class IdentifierTable; + class SourceLocation; + class MultiKeywordSelector; // private class used by Selector + class DeclarationName; // AST class that stores declaration names + + /// IdentifierLocPair - A simple pair of identifier info and location. + typedef std::pair<IdentifierInfo*, SourceLocation> IdentifierLocPair; + + +/// IdentifierInfo - One of these records is kept for each identifier that +/// is lexed. This contains information about whether the token was #define'd, +/// is a language keyword, or if it is a front-end token of some sort (e.g. a +/// variable or function name). The preprocessor keeps this information in a +/// set, and all tok::identifier tokens have a pointer to one of these. +class IdentifierInfo { + unsigned TokenID : 9; // Front-end token ID or tok::identifier. + // Objective-C keyword ('protocol' in '@protocol') or builtin (__builtin_inf). + // First NUM_OBJC_KEYWORDS values are for Objective-C, the remaining values + // are for builtins. + unsigned ObjCOrBuiltinID :11; + bool HasMacro : 1; // True if there is a #define for this. + bool IsExtension : 1; // True if identifier is a lang extension. + bool IsCXX11CompatKeyword : 1; // True if identifier is a keyword in C++11. + bool IsPoisoned : 1; // True if identifier is poisoned. + bool IsCPPOperatorKeyword : 1; // True if ident is a C++ operator keyword. + bool NeedsHandleIdentifier : 1; // See "RecomputeNeedsHandleIdentifier". + bool IsFromAST : 1; // True if identifier was loaded (at least + // partially) from an AST file. + bool ChangedAfterLoad : 1; // True if identifier has changed from the + // definition loaded from an AST file. + bool RevertedTokenID : 1; // True if RevertTokenIDToIdentifier was + // called. + bool OutOfDate : 1; // True if there may be additional + // information about this identifier + // stored externally. + bool IsModulesImport : 1; // True if this is the 'import' contextual + // keyword. + // 1 bit left in 32-bit word. + + void *FETokenInfo; // Managed by the language front-end. + llvm::StringMapEntry<IdentifierInfo*> *Entry; + + IdentifierInfo(const IdentifierInfo&); // NONCOPYABLE. + void operator=(const IdentifierInfo&); // NONASSIGNABLE. + + friend class IdentifierTable; + +public: + IdentifierInfo(); + + + /// isStr - Return true if this is the identifier for the specified string. + /// This is intended to be used for string literals only: II->isStr("foo"). + template <std::size_t StrLen> + bool isStr(const char (&Str)[StrLen]) const { + return getLength() == StrLen-1 && !memcmp(getNameStart(), Str, StrLen-1); + } + + /// getNameStart - Return the beginning of the actual string for this + /// identifier. The returned string is properly null terminated. + /// + const char *getNameStart() const { + if (Entry) return Entry->getKeyData(); + // FIXME: This is gross. It would be best not to embed specific details + // of the PTH file format here. + // The 'this' pointer really points to a + // std::pair<IdentifierInfo, const char*>, where internal pointer + // points to the external string data. + typedef std::pair<IdentifierInfo, const char*> actualtype; + return ((const actualtype*) this)->second; + } + + /// getLength - Efficiently return the length of this identifier info. + /// + unsigned getLength() const { + if (Entry) return Entry->getKeyLength(); + // FIXME: This is gross. It would be best not to embed specific details + // of the PTH file format here. + // The 'this' pointer really points to a + // std::pair<IdentifierInfo, const char*>, where internal pointer + // points to the external string data. + typedef std::pair<IdentifierInfo, const char*> actualtype; + const char* p = ((const actualtype*) this)->second - 2; + return (((unsigned) p[0]) | (((unsigned) p[1]) << 8)) - 1; + } + + /// getName - Return the actual identifier string. + StringRef getName() const { + return StringRef(getNameStart(), getLength()); + } + + /// hasMacroDefinition - Return true if this identifier is #defined to some + /// other value. + bool hasMacroDefinition() const { + return HasMacro; + } + void setHasMacroDefinition(bool Val) { + if (HasMacro == Val) return; + + HasMacro = Val; + if (Val) + NeedsHandleIdentifier = 1; + else + RecomputeNeedsHandleIdentifier(); + } + + /// getTokenID - If this is a source-language token (e.g. 'for'), this API + /// can be used to cause the lexer to map identifiers to source-language + /// tokens. + tok::TokenKind getTokenID() const { return (tok::TokenKind)TokenID; } + + /// \brief True if RevertTokenIDToIdentifier() was called. + bool hasRevertedTokenIDToIdentifier() const { return RevertedTokenID; } + + /// \brief Revert TokenID to tok::identifier; used for GNU libstdc++ 4.2 + /// compatibility. + /// + /// TokenID is normally read-only but there are 2 instances where we revert it + /// to tok::identifier for libstdc++ 4.2. Keep track of when this happens + /// using this method so we can inform serialization about it. + void RevertTokenIDToIdentifier() { + assert(TokenID != tok::identifier && "Already at tok::identifier"); + TokenID = tok::identifier; + RevertedTokenID = true; + } + + /// getPPKeywordID - Return the preprocessor keyword ID for this identifier. + /// For example, "define" will return tok::pp_define. + tok::PPKeywordKind getPPKeywordID() const; + + /// getObjCKeywordID - Return the Objective-C keyword ID for the this + /// identifier. For example, 'class' will return tok::objc_class if ObjC is + /// enabled. + tok::ObjCKeywordKind getObjCKeywordID() const { + if (ObjCOrBuiltinID < tok::NUM_OBJC_KEYWORDS) + return tok::ObjCKeywordKind(ObjCOrBuiltinID); + else + return tok::objc_not_keyword; + } + void setObjCKeywordID(tok::ObjCKeywordKind ID) { ObjCOrBuiltinID = ID; } + + /// getBuiltinID - Return a value indicating whether this is a builtin + /// function. 0 is not-built-in. 1 is builtin-for-some-nonprimary-target. + /// 2+ are specific builtin functions. + unsigned getBuiltinID() const { + if (ObjCOrBuiltinID >= tok::NUM_OBJC_KEYWORDS) + return ObjCOrBuiltinID - tok::NUM_OBJC_KEYWORDS; + else + return 0; + } + void setBuiltinID(unsigned ID) { + ObjCOrBuiltinID = ID + tok::NUM_OBJC_KEYWORDS; + assert(ObjCOrBuiltinID - unsigned(tok::NUM_OBJC_KEYWORDS) == ID + && "ID too large for field!"); + } + + unsigned getObjCOrBuiltinID() const { return ObjCOrBuiltinID; } + void setObjCOrBuiltinID(unsigned ID) { ObjCOrBuiltinID = ID; } + + /// get/setExtension - Initialize information about whether or not this + /// language token is an extension. This controls extension warnings, and is + /// only valid if a custom token ID is set. + bool isExtensionToken() const { return IsExtension; } + void setIsExtensionToken(bool Val) { + IsExtension = Val; + if (Val) + NeedsHandleIdentifier = 1; + else + RecomputeNeedsHandleIdentifier(); + } + + /// is/setIsCXX11CompatKeyword - Initialize information about whether or not + /// this language token is a keyword in C++11. This controls compatibility + /// warnings, and is only true when not parsing C++11. Once a compatibility + /// problem has been diagnosed with this keyword, the flag will be cleared. + bool isCXX11CompatKeyword() const { return IsCXX11CompatKeyword; } + void setIsCXX11CompatKeyword(bool Val) { + IsCXX11CompatKeyword = Val; + if (Val) + NeedsHandleIdentifier = 1; + else + RecomputeNeedsHandleIdentifier(); + } + + /// setIsPoisoned - Mark this identifier as poisoned. After poisoning, the + /// Preprocessor will emit an error every time this token is used. + void setIsPoisoned(bool Value = true) { + IsPoisoned = Value; + if (Value) + NeedsHandleIdentifier = 1; + else + RecomputeNeedsHandleIdentifier(); + } + + /// isPoisoned - Return true if this token has been poisoned. + bool isPoisoned() const { return IsPoisoned; } + + /// isCPlusPlusOperatorKeyword/setIsCPlusPlusOperatorKeyword controls whether + /// this identifier is a C++ alternate representation of an operator. + void setIsCPlusPlusOperatorKeyword(bool Val = true) { + IsCPPOperatorKeyword = Val; + if (Val) + NeedsHandleIdentifier = 1; + else + RecomputeNeedsHandleIdentifier(); + } + bool isCPlusPlusOperatorKeyword() const { return IsCPPOperatorKeyword; } + + /// getFETokenInfo/setFETokenInfo - The language front-end is allowed to + /// associate arbitrary metadata with this token. + template<typename T> + T *getFETokenInfo() const { return static_cast<T*>(FETokenInfo); } + void setFETokenInfo(void *T) { FETokenInfo = T; } + + /// isHandleIdentifierCase - Return true if the Preprocessor::HandleIdentifier + /// must be called on a token of this identifier. If this returns false, we + /// know that HandleIdentifier will not affect the token. + bool isHandleIdentifierCase() const { return NeedsHandleIdentifier; } + + /// isFromAST - Return true if the identifier in its current state was loaded + /// from an AST file. + bool isFromAST() const { return IsFromAST; } + + void setIsFromAST() { IsFromAST = true; } + + /// \brief Determine whether this identifier has changed since it was loaded + /// from an AST file. + bool hasChangedSinceDeserialization() const { + return ChangedAfterLoad; + } + + /// \brief Note that this identifier has changed since it was loaded from + /// an AST file. + void setChangedSinceDeserialization() { + ChangedAfterLoad = true; + } + + /// \brief Determine whether the information for this identifier is out of + /// date with respect to the external source. + bool isOutOfDate() const { return OutOfDate; } + + /// \brief Set whether the information for this identifier is out of + /// date with respect to the external source. + void setOutOfDate(bool OOD) { + OutOfDate = OOD; + if (OOD) + NeedsHandleIdentifier = true; + else + RecomputeNeedsHandleIdentifier(); + } + + /// \brief Determine whether this is the contextual keyword + /// '__experimental_modules_import'. + bool isModulesImport() const { return IsModulesImport; } + + /// \brief Set whether this identifier is the contextual keyword + /// '__experimental_modules_import'. + void setModulesImport(bool I) { + IsModulesImport = I; + if (I) + NeedsHandleIdentifier = true; + else + RecomputeNeedsHandleIdentifier(); + } + +private: + /// RecomputeNeedsHandleIdentifier - The Preprocessor::HandleIdentifier does + /// several special (but rare) things to identifiers of various sorts. For + /// example, it changes the "for" keyword token from tok::identifier to + /// tok::for. + /// + /// This method is very tied to the definition of HandleIdentifier. Any + /// change to it should be reflected here. + void RecomputeNeedsHandleIdentifier() { + NeedsHandleIdentifier = + (isPoisoned() | hasMacroDefinition() | isCPlusPlusOperatorKeyword() | + isExtensionToken() | isCXX11CompatKeyword() || isOutOfDate() || + isModulesImport()); + } +}; + +/// \brief an RAII object for [un]poisoning an identifier +/// within a certain scope. II is allowed to be null, in +/// which case, objects of this type have no effect. +class PoisonIdentifierRAIIObject { + IdentifierInfo *const II; + const bool OldValue; +public: + PoisonIdentifierRAIIObject(IdentifierInfo *II, bool NewValue) + : II(II), OldValue(II ? II->isPoisoned() : false) { + if(II) + II->setIsPoisoned(NewValue); + } + + ~PoisonIdentifierRAIIObject() { + if(II) + II->setIsPoisoned(OldValue); + } +}; + +/// \brief An iterator that walks over all of the known identifiers +/// in the lookup table. +/// +/// Since this iterator uses an abstract interface via virtual +/// functions, it uses an object-oriented interface rather than the +/// more standard C++ STL iterator interface. In this OO-style +/// iteration, the single function \c Next() provides dereference, +/// advance, and end-of-sequence checking in a single +/// operation. Subclasses of this iterator type will provide the +/// actual functionality. +class IdentifierIterator { +private: + IdentifierIterator(const IdentifierIterator&); // Do not implement + IdentifierIterator &operator=(const IdentifierIterator&); // Do not implement + +protected: + IdentifierIterator() { } + +public: + virtual ~IdentifierIterator(); + + /// \brief Retrieve the next string in the identifier table and + /// advances the iterator for the following string. + /// + /// \returns The next string in the identifier table. If there is + /// no such string, returns an empty \c StringRef. + virtual StringRef Next() = 0; +}; + +/// IdentifierInfoLookup - An abstract class used by IdentifierTable that +/// provides an interface for performing lookups from strings +/// (const char *) to IdentiferInfo objects. +class IdentifierInfoLookup { +public: + virtual ~IdentifierInfoLookup(); + + /// get - Return the identifier token info for the specified named identifier. + /// Unlike the version in IdentifierTable, this returns a pointer instead + /// of a reference. If the pointer is NULL then the IdentifierInfo cannot + /// be found. + virtual IdentifierInfo* get(StringRef Name) = 0; + + /// \brief Retrieve an iterator into the set of all identifiers + /// known to this identifier lookup source. + /// + /// This routine provides access to all of the identifiers known to + /// the identifier lookup, allowing access to the contents of the + /// identifiers without introducing the overhead of constructing + /// IdentifierInfo objects for each. + /// + /// \returns A new iterator into the set of known identifiers. The + /// caller is responsible for deleting this iterator. + virtual IdentifierIterator *getIdentifiers() const; +}; + +/// \brief An abstract class used to resolve numerical identifier +/// references (meaningful only to some external source) into +/// IdentifierInfo pointers. +class ExternalIdentifierLookup { +public: + virtual ~ExternalIdentifierLookup(); + + /// \brief Return the identifier associated with the given ID number. + /// + /// The ID 0 is associated with the NULL identifier. + virtual IdentifierInfo *GetIdentifier(unsigned ID) = 0; +}; + +/// IdentifierTable - This table implements an efficient mapping from strings to +/// IdentifierInfo nodes. It has no other purpose, but this is an +/// extremely performance-critical piece of the code, as each occurrence of +/// every identifier goes through here when lexed. +class IdentifierTable { + // Shark shows that using MallocAllocator is *much* slower than using this + // BumpPtrAllocator! + typedef llvm::StringMap<IdentifierInfo*, llvm::BumpPtrAllocator> HashTableTy; + HashTableTy HashTable; + + IdentifierInfoLookup* ExternalLookup; + +public: + /// IdentifierTable ctor - Create the identifier table, populating it with + /// info about the language keywords for the language specified by LangOpts. + IdentifierTable(const LangOptions &LangOpts, + IdentifierInfoLookup* externalLookup = 0); + + /// \brief Set the external identifier lookup mechanism. + void setExternalIdentifierLookup(IdentifierInfoLookup *IILookup) { + ExternalLookup = IILookup; + } + + /// \brief Retrieve the external identifier lookup object, if any. + IdentifierInfoLookup *getExternalIdentifierLookup() const { + return ExternalLookup; + } + + llvm::BumpPtrAllocator& getAllocator() { + return HashTable.getAllocator(); + } + + /// get - Return the identifier token info for the specified named identifier. + /// + IdentifierInfo &get(StringRef Name) { + llvm::StringMapEntry<IdentifierInfo*> &Entry = + HashTable.GetOrCreateValue(Name); + + IdentifierInfo *II = Entry.getValue(); + if (II) return *II; + + // No entry; if we have an external lookup, look there first. + if (ExternalLookup) { + II = ExternalLookup->get(Name); + if (II) { + // Cache in the StringMap for subsequent lookups. + Entry.setValue(II); + return *II; + } + } + + // Lookups failed, make a new IdentifierInfo. + void *Mem = getAllocator().Allocate<IdentifierInfo>(); + II = new (Mem) IdentifierInfo(); + Entry.setValue(II); + + // Make sure getName() knows how to find the IdentifierInfo + // contents. + II->Entry = &Entry; + + return *II; + } + + IdentifierInfo &get(StringRef Name, tok::TokenKind TokenCode) { + IdentifierInfo &II = get(Name); + II.TokenID = TokenCode; + assert(II.TokenID == (unsigned) TokenCode && "TokenCode too large"); + return II; + } + + /// \brief Gets an IdentifierInfo for the given name without consulting + /// external sources. + /// + /// This is a version of get() meant for external sources that want to + /// introduce or modify an identifier. If they called get(), they would + /// likely end up in a recursion. + IdentifierInfo &getOwn(StringRef Name) { + llvm::StringMapEntry<IdentifierInfo*> &Entry = + HashTable.GetOrCreateValue(Name); + + IdentifierInfo *II = Entry.getValue(); + if (!II) { + + // Lookups failed, make a new IdentifierInfo. + void *Mem = getAllocator().Allocate<IdentifierInfo>(); + II = new (Mem) IdentifierInfo(); + Entry.setValue(II); + + // Make sure getName() knows how to find the IdentifierInfo + // contents. + II->Entry = &Entry; + + // If this is the 'import' contextual keyword, mark it as such. + if (Name.equals("import")) + II->setModulesImport(true); + } + + return *II; + } + + typedef HashTableTy::const_iterator iterator; + typedef HashTableTy::const_iterator const_iterator; + + iterator begin() const { return HashTable.begin(); } + iterator end() const { return HashTable.end(); } + unsigned size() const { return HashTable.size(); } + + /// PrintStats - Print some statistics to stderr that indicate how well the + /// hashing is doing. + void PrintStats() const; + + void AddKeywords(const LangOptions &LangOpts); +}; + +/// ObjCMethodFamily - A family of Objective-C methods. These +/// families have no inherent meaning in the language, but are +/// nonetheless central enough in the existing implementations to +/// merit direct AST support. While, in theory, arbitrary methods can +/// be considered to form families, we focus here on the methods +/// involving allocation and retain-count management, as these are the +/// most "core" and the most likely to be useful to diverse clients +/// without extra information. +/// +/// Both selectors and actual method declarations may be classified +/// into families. Method families may impose additional restrictions +/// beyond their selector name; for example, a method called '_init' +/// that returns void is not considered to be in the 'init' family +/// (but would be if it returned 'id'). It is also possible to +/// explicitly change or remove a method's family. Therefore the +/// method's family should be considered the single source of truth. +enum ObjCMethodFamily { + /// \brief No particular method family. + OMF_None, + + // Selectors in these families may have arbitrary arity, may be + // written with arbitrary leading underscores, and may have + // additional CamelCase "words" in their first selector chunk + // following the family name. + OMF_alloc, + OMF_copy, + OMF_init, + OMF_mutableCopy, + OMF_new, + + // These families are singletons consisting only of the nullary + // selector with the given name. + OMF_autorelease, + OMF_dealloc, + OMF_finalize, + OMF_release, + OMF_retain, + OMF_retainCount, + OMF_self, + + // performSelector families + OMF_performSelector +}; + +/// Enough bits to store any enumerator in ObjCMethodFamily or +/// InvalidObjCMethodFamily. +enum { ObjCMethodFamilyBitWidth = 4 }; + +/// An invalid value of ObjCMethodFamily. +enum { InvalidObjCMethodFamily = (1 << ObjCMethodFamilyBitWidth) - 1 }; + +/// Selector - This smart pointer class efficiently represents Objective-C +/// method names. This class will either point to an IdentifierInfo or a +/// MultiKeywordSelector (which is private). This enables us to optimize +/// selectors that take no arguments and selectors that take 1 argument, which +/// accounts for 78% of all selectors in Cocoa.h. +class Selector { + friend class Diagnostic; + + enum IdentifierInfoFlag { + // MultiKeywordSelector = 0. + ZeroArg = 0x1, + OneArg = 0x2, + ArgFlags = ZeroArg|OneArg + }; + uintptr_t InfoPtr; // a pointer to the MultiKeywordSelector or IdentifierInfo. + + Selector(IdentifierInfo *II, unsigned nArgs) { + InfoPtr = reinterpret_cast<uintptr_t>(II); + assert((InfoPtr & ArgFlags) == 0 &&"Insufficiently aligned IdentifierInfo"); + assert(nArgs < 2 && "nArgs not equal to 0/1"); + InfoPtr |= nArgs+1; + } + Selector(MultiKeywordSelector *SI) { + InfoPtr = reinterpret_cast<uintptr_t>(SI); + assert((InfoPtr & ArgFlags) == 0 &&"Insufficiently aligned IdentifierInfo"); + } + + IdentifierInfo *getAsIdentifierInfo() const { + if (getIdentifierInfoFlag()) + return reinterpret_cast<IdentifierInfo *>(InfoPtr & ~ArgFlags); + return 0; + } + unsigned getIdentifierInfoFlag() const { + return InfoPtr & ArgFlags; + } + + static ObjCMethodFamily getMethodFamilyImpl(Selector sel); + +public: + friend class SelectorTable; // only the SelectorTable can create these + friend class DeclarationName; // and the AST's DeclarationName. + + /// The default ctor should only be used when creating data structures that + /// will contain selectors. + Selector() : InfoPtr(0) {} + Selector(uintptr_t V) : InfoPtr(V) {} + + /// operator==/!= - Indicate whether the specified selectors are identical. + bool operator==(Selector RHS) const { + return InfoPtr == RHS.InfoPtr; + } + bool operator!=(Selector RHS) const { + return InfoPtr != RHS.InfoPtr; + } + void *getAsOpaquePtr() const { + return reinterpret_cast<void*>(InfoPtr); + } + + /// \brief Determine whether this is the empty selector. + bool isNull() const { return InfoPtr == 0; } + + // Predicates to identify the selector type. + bool isKeywordSelector() const { + return getIdentifierInfoFlag() != ZeroArg; + } + bool isUnarySelector() const { + return getIdentifierInfoFlag() == ZeroArg; + } + unsigned getNumArgs() const; + + + /// \brief Retrieve the identifier at a given position in the selector. + /// + /// Note that the identifier pointer returned may be NULL. Clients that only + /// care about the text of the identifier string, and not the specific, + /// uniqued identifier pointer, should use \c getNameForSlot(), which returns + /// an empty string when the identifier pointer would be NULL. + /// + /// \param argIndex The index for which we want to retrieve the identifier. + /// This index shall be less than \c getNumArgs() unless this is a keyword + /// selector, in which case 0 is the only permissible value. + /// + /// \returns the uniqued identifier for this slot, or NULL if this slot has + /// no corresponding identifier. + IdentifierInfo *getIdentifierInfoForSlot(unsigned argIndex) const; + + /// \brief Retrieve the name at a given position in the selector. + /// + /// \param argIndex The index for which we want to retrieve the name. + /// This index shall be less than \c getNumArgs() unless this is a keyword + /// selector, in which case 0 is the only permissible value. + /// + /// \returns the name for this slot, which may be the empty string if no + /// name was supplied. + StringRef getNameForSlot(unsigned argIndex) const; + + /// getAsString - Derive the full selector name (e.g. "foo:bar:") and return + /// it as an std::string. + std::string getAsString() const; + + /// getMethodFamily - Derive the conventional family of this method. + ObjCMethodFamily getMethodFamily() const { + return getMethodFamilyImpl(*this); + } + + static Selector getEmptyMarker() { + return Selector(uintptr_t(-1)); + } + static Selector getTombstoneMarker() { + return Selector(uintptr_t(-2)); + } +}; + +/// SelectorTable - This table allows us to fully hide how we implement +/// multi-keyword caching. +class SelectorTable { + void *Impl; // Actually a SelectorTableImpl + SelectorTable(const SelectorTable&); // DISABLED: DO NOT IMPLEMENT + void operator=(const SelectorTable&); // DISABLED: DO NOT IMPLEMENT +public: + SelectorTable(); + ~SelectorTable(); + + /// getSelector - This can create any sort of selector. NumArgs indicates + /// whether this is a no argument selector "foo", a single argument selector + /// "foo:" or multi-argument "foo:bar:". + Selector getSelector(unsigned NumArgs, IdentifierInfo **IIV); + + Selector getUnarySelector(IdentifierInfo *ID) { + return Selector(ID, 1); + } + Selector getNullarySelector(IdentifierInfo *ID) { + return Selector(ID, 0); + } + + /// Return the total amount of memory allocated for managing selectors. + size_t getTotalMemory() const; + + /// constructSetterName - Return the setter name for the given + /// identifier, i.e. "set" + Name where the initial character of Name + /// has been capitalized. + static Selector constructSetterName(IdentifierTable &Idents, + SelectorTable &SelTable, + const IdentifierInfo *Name); +}; + +/// DeclarationNameExtra - Common base of the MultiKeywordSelector, +/// CXXSpecialName, and CXXOperatorIdName classes, all of which are +/// private classes that describe different kinds of names. +class DeclarationNameExtra { +public: + /// ExtraKind - The kind of "extra" information stored in the + /// DeclarationName. See @c ExtraKindOrNumArgs for an explanation of + /// how these enumerator values are used. + enum ExtraKind { + CXXConstructor = 0, + CXXDestructor, + CXXConversionFunction, +#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ + CXXOperator##Name, +#include "clang/Basic/OperatorKinds.def" + CXXLiteralOperator, + CXXUsingDirective, + NUM_EXTRA_KINDS + }; + + /// ExtraKindOrNumArgs - Either the kind of C++ special name or + /// operator-id (if the value is one of the CXX* enumerators of + /// ExtraKind), in which case the DeclarationNameExtra is also a + /// CXXSpecialName, (for CXXConstructor, CXXDestructor, or + /// CXXConversionFunction) CXXOperatorIdName, or CXXLiteralOperatorName, + /// it may be also name common to C++ using-directives (CXXUsingDirective), + /// otherwise it is NUM_EXTRA_KINDS+NumArgs, where NumArgs is the number of + /// arguments in the Objective-C selector, in which case the + /// DeclarationNameExtra is also a MultiKeywordSelector. + unsigned ExtraKindOrNumArgs; +}; + +} // end namespace clang + +namespace llvm { +/// Define DenseMapInfo so that Selectors can be used as keys in DenseMap and +/// DenseSets. +template <> +struct DenseMapInfo<clang::Selector> { + static inline clang::Selector getEmptyKey() { + return clang::Selector::getEmptyMarker(); + } + static inline clang::Selector getTombstoneKey() { + return clang::Selector::getTombstoneMarker(); + } + + static unsigned getHashValue(clang::Selector S); + + static bool isEqual(clang::Selector LHS, clang::Selector RHS) { + return LHS == RHS; + } +}; + +template <> +struct isPodLike<clang::Selector> { static const bool value = true; }; + +template<> +class PointerLikeTypeTraits<clang::Selector> { +public: + static inline const void *getAsVoidPointer(clang::Selector P) { + return P.getAsOpaquePtr(); + } + static inline clang::Selector getFromVoidPointer(const void *P) { + return clang::Selector(reinterpret_cast<uintptr_t>(P)); + } + enum { NumLowBitsAvailable = 0 }; +}; + +// Provide PointerLikeTypeTraits for IdentifierInfo pointers, which +// are not guaranteed to be 8-byte aligned. +template<> +class PointerLikeTypeTraits<clang::IdentifierInfo*> { +public: + static inline void *getAsVoidPointer(clang::IdentifierInfo* P) { + return P; + } + static inline clang::IdentifierInfo *getFromVoidPointer(void *P) { + return static_cast<clang::IdentifierInfo*>(P); + } + enum { NumLowBitsAvailable = 1 }; +}; + +template<> +class PointerLikeTypeTraits<const clang::IdentifierInfo*> { +public: + static inline const void *getAsVoidPointer(const clang::IdentifierInfo* P) { + return P; + } + static inline const clang::IdentifierInfo *getFromVoidPointer(const void *P) { + return static_cast<const clang::IdentifierInfo*>(P); + } + enum { NumLowBitsAvailable = 1 }; +}; + +} // end namespace llvm +#endif diff --git a/clang/include/clang/Basic/LLVM.h b/clang/include/clang/Basic/LLVM.h new file mode 100644 index 0000000..813b49e --- /dev/null +++ b/clang/include/clang/Basic/LLVM.h @@ -0,0 +1,73 @@ +//===--- LLVM.h - Import various common LLVM datatypes ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file forward declares and imports various common LLVM datatypes that +// clang wants to use unqualified. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_BASIC_LLVM_H +#define CLANG_BASIC_LLVM_H + +// This should be the only #include, force #includes of all the others on +// clients. +#include "llvm/Support/Casting.h" + +namespace llvm { + // ADT's. + class StringRef; + class Twine; + template<typename T> class ArrayRef; + template<class T> class OwningPtr; + template<unsigned InternalLen> class SmallString; + template<typename T, unsigned N> class SmallVector; + template<typename T> class SmallVectorImpl; + + template<typename T> + struct SaveAndRestore; + + // Reference counting. + template <typename T> class IntrusiveRefCntPtr; + template <typename T> struct IntrusiveRefCntPtrInfo; + template <class Derived> class RefCountedBase; + class RefCountedBaseVPTR; + + class raw_ostream; + // TODO: DenseMap, ... +} + + +namespace clang { + // Casting operators. + using llvm::isa; + using llvm::cast; + using llvm::dyn_cast; + using llvm::dyn_cast_or_null; + using llvm::cast_or_null; + + // ADT's. + using llvm::StringRef; + using llvm::Twine; + using llvm::ArrayRef; + using llvm::OwningPtr; + using llvm::SmallString; + using llvm::SmallVector; + using llvm::SmallVectorImpl; + using llvm::SaveAndRestore; + + // Reference counting. + using llvm::IntrusiveRefCntPtr; + using llvm::IntrusiveRefCntPtrInfo; + using llvm::RefCountedBase; + using llvm::RefCountedBaseVPTR; + + using llvm::raw_ostream; +} // end namespace clang. + +#endif diff --git a/clang/include/clang/Basic/Lambda.h b/clang/include/clang/Basic/Lambda.h new file mode 100644 index 0000000..df50d94 --- /dev/null +++ b/clang/include/clang/Basic/Lambda.h @@ -0,0 +1,38 @@ +//===--- Lambda.h - Types for C++ Lambdas -----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines several types used to describe C++ lambda +// expressions that are shared between the parser and AST. +//===----------------------------------------------------------------------===// + + +#ifndef LLVM_CLANG_BASIC_LAMBDA_H +#define LLVM_CLANG_BASIC_LAMBDA_H + +namespace clang { + +/// LambdaCaptureDefault - The default, if any, capture method for a +/// lambda expression. +enum LambdaCaptureDefault { + LCD_None, + LCD_ByCopy, + LCD_ByRef +}; + +/// LambdaCaptureKind - The different capture forms in a lambda +/// introducer: 'this' or a copied or referenced variable. +enum LambdaCaptureKind { + LCK_This, + LCK_ByCopy, + LCK_ByRef +}; + +} // end namespace clang + +#endif // LLVM_CLANG_BASIC_LAMBDA_H diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def new file mode 100644 index 0000000..d2ce7c0 --- /dev/null +++ b/clang/include/clang/Basic/LangOptions.def @@ -0,0 +1,170 @@ +//===--- LangOptions.def - Language option database --------------- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the language options. Users of this file must +// define the LANGOPT macro to make use of this information. +// Optionally, the user may also define BENIGN_LANGOPT +// (for options that don't affect the construction of the AST in an +// incompatible way), ENUM_LANGOPT (for options that have enumeration, +// rather than unsigned, type), BENIGN_ENUM_LANGOPT (for benign +// options that have enumeration type), and VALUE_LANGOPT is a language option +// that describes a value rather than a flag. +// +//===----------------------------------------------------------------------===// +#ifndef LANGOPT +# error Define the LANGOPT macro to handle language options +#endif + +#ifndef VALUE_LANGOPT +# define VALUE_LANGOPT(Name, Bits, Default, Description) \ + LANGOPT(Name, Bits, Default, Description) +#endif + +#ifndef BENIGN_LANGOPT +# define BENIGN_LANGOPT(Name, Bits, Default, Description) \ + LANGOPT(Name, Bits, Default, Description) +#endif + +#ifndef ENUM_LANGOPT +# define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ + LANGOPT(Name, Bits, Default, Description) +#endif + +#ifndef BENIGN_ENUM_LANGOPT +# define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ + ENUM_LANGOPT(Name, Type, Bits, Default, Description) +#endif + +LANGOPT(C99 , 1, 0, "C99") +LANGOPT(C11 , 1, 0, "C11") +LANGOPT(MicrosoftExt , 1, 0, "Microsoft extensions") +LANGOPT(MicrosoftMode , 1, 0, "Microsoft compatibility mode") +LANGOPT(Borland , 1, 0, "Borland extensions") +LANGOPT(CPlusPlus , 1, 0, "C++") +LANGOPT(CPlusPlus0x , 1, 0, "C++0x") +LANGOPT(ObjC1 , 1, 0, "Objective-C 1") +LANGOPT(ObjC2 , 1, 0, "Objective-C 2") +LANGOPT(ObjCNonFragileABI , 1, 0, "Objective-C modern abi") +LANGOPT(ObjCNonFragileABI2 , 1, 0, "Objective-C enhanced modern abi") +BENIGN_LANGOPT(ObjCDefaultSynthProperties , 1, 0, + "Objective-C auto-synthesized properties") +BENIGN_LANGOPT(ObjCInferRelatedResultType , 1, 1, + "Objective-C related result type inference") +LANGOPT(Trigraphs , 1, 0,"trigraphs") +LANGOPT(BCPLComment , 1, 0, "BCPL-style '//' comments") +LANGOPT(Bool , 1, 0, "bool, true, and false keywords") +BENIGN_LANGOPT(DollarIdents , 1, 1, "'$' in identifiers") +BENIGN_LANGOPT(AsmPreprocessor, 1, 0, "preprocessor in asm mode") +BENIGN_LANGOPT(GNUMode , 1, 1, "GNU extensions") +LANGOPT(GNUKeywords , 1, 1, "GNU keywords") +BENIGN_LANGOPT(ImplicitInt, 1, !C99 && !CPlusPlus, "C89 implicit 'int'") +LANGOPT(Digraphs , 1, 0, "digraphs") +BENIGN_LANGOPT(HexFloats , 1, C99, "C99 hexadecimal float constants") +LANGOPT(CXXOperatorNames , 1, 0, "C++ operator name keywords") +LANGOPT(AppleKext , 1, 0, "Apple kext support") +BENIGN_LANGOPT(PascalStrings, 1, 0, "Pascal string support") +LANGOPT(WritableStrings , 1, 0, "writable string support") +LANGOPT(ConstStrings , 1, 0, "const-qualified string support") +LANGOPT(LaxVectorConversions , 1, 1, "lax vector conversions") +LANGOPT(AltiVec , 1, 0, "AltiVec-style vector initializers") +LANGOPT(Exceptions , 1, 0, "exception handling") +LANGOPT(ObjCExceptions , 1, 0, "Objective-C exceptions") +LANGOPT(CXXExceptions , 1, 0, "C++ exceptions") +LANGOPT(SjLjExceptions , 1, 0, "setjmp-longjump exception handling") +LANGOPT(TraditionalCPP , 1, 0, "traditional CPP emulation") +LANGOPT(RTTI , 1, 1, "run-time type information") +LANGOPT(MSBitfields , 1, 0, "Microsoft-compatible structure layout") +LANGOPT(NeXTRuntime , 1, 1, "NeXT Objective-C runtime") +LANGOPT(Freestanding, 1, 0, "freestanding implementation") +LANGOPT(NoBuiltin , 1, 0, "disable builtin functions") + +BENIGN_LANGOPT(ThreadsafeStatics , 1, 1, "thread-safe static initializers") +LANGOPT(POSIXThreads , 1, 0, "POSIX thread support") +LANGOPT(Blocks , 1, 0, "blocks extension to C") +BENIGN_LANGOPT(EmitAllDecls , 1, 0, "support for emitting all declarations") +LANGOPT(MathErrno , 1, 1, "errno support for math functions") +BENIGN_LANGOPT(HeinousExtensions , 1, 0, "Extensions that we really don't like and may be ripped out at any time") +LANGOPT(Modules , 1, 0, "modules extension to C") +LANGOPT(Optimize , 1, 0, "__OPTIMIZE__ predefined macro") +LANGOPT(OptimizeSize , 1, 0, "__OPTIMIZE_SIZE__ predefined macro") +LANGOPT(Static , 1, 0, "__STATIC__ predefined macro (as opposed to __DYNAMIC__)") +VALUE_LANGOPT(PackStruct , 32, 0, + "default struct packing maximum alignment") +VALUE_LANGOPT(PICLevel , 2, 0, "__PIC__ level") +VALUE_LANGOPT(PIELevel , 2, 0, "__PIE__ level") +LANGOPT(GNUInline , 1, 0, "GNU inline semantics") +LANGOPT(NoInlineDefine , 1, 0, "__NO_INLINE__ predefined macro") +LANGOPT(Deprecated , 1, 0, "__DEPRECATED predefined macro") +LANGOPT(FastMath , 1, 0, "__FAST_MATH__ predefined macro") + +BENIGN_LANGOPT(ObjCGCBitmapPrint , 1, 0, "printing of GC's bitmap layout for __weak/__strong ivars") + +BENIGN_LANGOPT(AccessControl , 1, 1, "C++ access control") +LANGOPT(CharIsSigned , 1, 1, "signed char") +LANGOPT(ShortWChar , 1, 0, "unsigned short wchar_t") + +LANGOPT(ShortEnums , 1, 0, "short enum types") + +LANGOPT(OpenCL , 1, 0, "OpenCL") +LANGOPT(CUDA , 1, 0, "CUDA") + +LANGOPT(AssumeSaneOperatorNew , 1, 1, "implicit __attribute__((malloc)) for C++'s new operators") +BENIGN_LANGOPT(ElideConstructors , 1, 1, "C++ copy constructor elision") +BENIGN_LANGOPT(CatchUndefined , 1, 0, "catching undefined behavior at run time") +BENIGN_LANGOPT(DumpRecordLayouts , 1, 0, "dumping the layout of IRgen'd records") +BENIGN_LANGOPT(DumpRecordLayoutsSimple , 1, 0, "dumping the layout of IRgen'd records in a simple form") +BENIGN_LANGOPT(DumpVTableLayouts , 1, 0, "dumping the layouts of emitted vtables") +LANGOPT(NoConstantCFStrings , 1, 0, "no constant CoreFoundation strings") +BENIGN_LANGOPT(InlineVisibilityHidden , 1, 0, "hidden default visibility for inline C++ methods") +BENIGN_LANGOPT(ParseUnknownAnytype, 1, 0, "__unknown_anytype") +BENIGN_LANGOPT(DebuggerSupport , 1, 0, "debugger support") +BENIGN_LANGOPT(DebuggerCastResultToId, 1, 0, "for 'po' in the debugger, cast the result to id if it is of unknown type") +BENIGN_LANGOPT(DebuggerObjCLiteral , 1, 0, "debugger objective-C literals and subscripting support") +BENIGN_LANGOPT(AddressSanitizer , 1, 0, "AddressSanitizer enabled") +BENIGN_LANGOPT(ThreadSanitizer , 1, 0, "ThreadSanitizer enabled") + +BENIGN_LANGOPT(SpellChecking , 1, 1, "spell-checking") +LANGOPT(SinglePrecisionConstants , 1, 0, "treating double-precision floating point constants as single precision constants") +LANGOPT(FastRelaxedMath , 1, 0, "OpenCL fast relaxed math") +LANGOPT(DefaultFPContract , 1, 0, "FP_CONTRACT") +LANGOPT(NoBitFieldTypeAlign , 1, 0, "bit-field type alignment") +LANGOPT(HexagonQdsp6Compat , 1, 0, "hexagon-qdsp6 backward compatibility") +LANGOPT(ObjCAutoRefCount , 1, 0, "Objective-C automated reference counting") +LANGOPT(ObjCRuntimeHasWeak , 1, 0, "__weak support in the ARC runtime") +LANGOPT(FakeAddressSpaceMap , 1, 0, "OpenCL fake address space map") + +LANGOPT(MRTD , 1, 0, "-mrtd calling convention") +BENIGN_LANGOPT(DelayedTemplateParsing , 1, 0, "delayed template parsing") +LANGOPT(BlocksRuntimeOptional , 1, 0, "optional blocks runtime") + +ENUM_LANGOPT(GC, GCMode, 2, NonGC, "Objective-C Garbage Collection mode") +ENUM_LANGOPT(VisibilityMode, Visibility, 3, DefaultVisibility, + "symbol visibility") +ENUM_LANGOPT(StackProtector, StackProtectorMode, 2, SSPOff, + "stack protector mode") +ENUM_LANGOPT(SignedOverflowBehavior, SignedOverflowBehaviorTy, 2, SOB_Undefined, + "signed integer overflow handling") + +BENIGN_LANGOPT(InstantiationDepth, 32, 1024, + "maximum template instantiation depth") +BENIGN_LANGOPT(ConstexprCallDepth, 32, 512, + "maximum constexpr call depth") +BENIGN_LANGOPT(NumLargeByValueCopy, 32, 0, + "if non-zero, warn about parameter or return Warn if parameter/return value is larger in bytes than this setting. 0 is no check.") +VALUE_LANGOPT(MSCVersion, 32, 0, + "version of Microsoft Visual C/C++") + +LANGOPT(ApplePragmaPack, 1, 0, "Apple gcc-compatible #pragma pack handling") + +#undef LANGOPT +#undef VALUE_LANGOPT +#undef BENIGN_LANGOPT +#undef ENUM_LANGOPT +#undef BENIGN_ENUM_LANGOPT + diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h new file mode 100644 index 0000000..ce4ff06 --- /dev/null +++ b/clang/include/clang/Basic/LangOptions.h @@ -0,0 +1,122 @@ +//===--- LangOptions.h - C Language Family Language Options -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the LangOptions interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LANGOPTIONS_H +#define LLVM_CLANG_LANGOPTIONS_H + +#include <string> +#include "clang/Basic/LLVM.h" +#include "clang/Basic/Visibility.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" + +namespace clang { + +/// Bitfields of LangOptions, split out from LangOptions in order to ensure that +/// this large collection of bitfields is a trivial class type. +class LangOptionsBase { +public: + // Define simple language options (with no accessors). +#define LANGOPT(Name, Bits, Default, Description) unsigned Name : Bits; +#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) +#include "clang/Basic/LangOptions.def" + +protected: + // Define language options of enumeration type. These are private, and will + // have accessors (below). +#define LANGOPT(Name, Bits, Default, Description) +#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ + unsigned Name : Bits; +#include "clang/Basic/LangOptions.def" +}; + +/// LangOptions - This class keeps track of the various options that can be +/// enabled, which controls the dialect of C that is accepted. +class LangOptions : public RefCountedBase<LangOptions>, public LangOptionsBase { +public: + typedef clang::Visibility Visibility; + + enum GCMode { NonGC, GCOnly, HybridGC }; + enum StackProtectorMode { SSPOff, SSPOn, SSPReq }; + + enum SignedOverflowBehaviorTy { + SOB_Undefined, // Default C standard behavior. + SOB_Defined, // -fwrapv + SOB_Trapping // -ftrapv + }; + +public: + std::string ObjCConstantStringClass; + + /// The name of the handler function to be called when -ftrapv is specified. + /// If none is specified, abort (GCC-compatible behaviour). + std::string OverflowHandler; + + /// \brief The name of the current module. + std::string CurrentModule; + + LangOptions(); + + // Define accessors/mutators for language options of enumeration type. +#define LANGOPT(Name, Bits, Default, Description) +#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ + Type get##Name() const { return static_cast<Type>(Name); } \ + void set##Name(Type Value) { Name = static_cast<unsigned>(Value); } +#include "clang/Basic/LangOptions.def" + + bool isSignedOverflowDefined() const { + return getSignedOverflowBehavior() == SOB_Defined; + } + + /// \brief Reset all of the options that are not considered when building a + /// module. + void resetNonModularOptions(); +}; + +/// Floating point control options +class FPOptions { +public: + unsigned fp_contract : 1; + + FPOptions() : fp_contract(0) {} + + FPOptions(const LangOptions &LangOpts) : + fp_contract(LangOpts.DefaultFPContract) {} +}; + +/// OpenCL volatile options +class OpenCLOptions { +public: +#define OPENCLEXT(nm) unsigned nm : 1; +#include "clang/Basic/OpenCLExtensions.def" + + OpenCLOptions() { +#define OPENCLEXT(nm) nm = 0; +#include "clang/Basic/OpenCLExtensions.def" + } +}; + +/// \brief Describes the kind of translation unit being processed. +enum TranslationUnitKind { + /// \brief The translation unit is a complete translation unit. + TU_Complete, + /// \brief The translation unit is a prefix to a translation unit, and is + /// not complete. + TU_Prefix, + /// \brief The translation unit is a module. + TU_Module +}; + + /// \brief +} // end namespace clang + +#endif diff --git a/clang/include/clang/Basic/Linkage.h b/clang/include/clang/Basic/Linkage.h new file mode 100644 index 0000000..09a5a0b --- /dev/null +++ b/clang/include/clang/Basic/Linkage.h @@ -0,0 +1,68 @@ +//===--- Linkage.h - Linkage enumeration and utilities ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Linkage enumeration and various utility +// functions. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_BASIC_LINKAGE_H +#define LLVM_CLANG_BASIC_LINKAGE_H + +namespace clang { + +/// \brief Describes the different kinds of linkage +/// (C++ [basic.link], C99 6.2.2) that an entity may have. +enum Linkage { + /// \brief No linkage, which means that the entity is unique and + /// can only be referred to from within its scope. + NoLinkage = 0, + + /// \brief Internal linkage, which indicates that the entity can + /// be referred to from within the translation unit (but not other + /// translation units). + InternalLinkage, + + /// \brief External linkage within a unique namespace. From the + /// language perspective, these entities have external + /// linkage. However, since they reside in an anonymous namespace, + /// their names are unique to this translation unit, which is + /// equivalent to having internal linkage from the code-generation + /// point of view. + UniqueExternalLinkage, + + /// \brief External linkage, which indicates that the entity can + /// be referred to from other translation units. + ExternalLinkage +}; + +/// \brief A more specific kind of linkage. This is relevant to CodeGen and +/// AST file reading. +enum GVALinkage { + GVA_Internal, + GVA_C99Inline, + GVA_CXXInline, + GVA_StrongExternal, + GVA_TemplateInstantiation, + GVA_ExplicitTemplateInstantiation +}; + +/// \brief Determine whether the given linkage is semantically +/// external. +inline bool isExternalLinkage(Linkage L) { + return L == UniqueExternalLinkage || L == ExternalLinkage; +} + +/// \brief Compute the minimum linkage given two linages. +static inline Linkage minLinkage(Linkage L1, Linkage L2) { + return L1 < L2? L1 : L2; +} + +} // end namespace clang + +#endif // LLVM_CLANG_BASIC_LINKAGE_H diff --git a/clang/include/clang/Basic/MacroBuilder.h b/clang/include/clang/Basic/MacroBuilder.h new file mode 100644 index 0000000..1d0f1e8 --- /dev/null +++ b/clang/include/clang/Basic/MacroBuilder.h @@ -0,0 +1,46 @@ +//===--- MacroBuilder.h - CPP Macro building utility ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the MacroBuilder utility class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_MACROBUILDER_H +#define LLVM_CLANG_BASIC_MACROBUILDER_H + +#include "llvm/ADT/Twine.h" +#include "llvm/Support/raw_ostream.h" + +namespace clang { + +class MacroBuilder { + raw_ostream &Out; +public: + MacroBuilder(raw_ostream &Output) : Out(Output) {} + + /// Append a #define line for macro of the form "#define Name Value\n". + void defineMacro(const Twine &Name, const Twine &Value = "1") { + Out << "#define " << Name << ' ' << Value << '\n'; + } + + /// Append a #undef line for Name. Name should be of the form XXX + /// and we emit "#undef XXX". + void undefineMacro(const Twine &Name) { + Out << "#undef " << Name << '\n'; + } + + /// Directly append Str and a newline to the underlying buffer. + void append(const Twine &Str) { + Out << Str << '\n'; + } +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Basic/Makefile b/clang/include/clang/Basic/Makefile new file mode 100644 index 0000000..702afac --- /dev/null +++ b/clang/include/clang/Basic/Makefile @@ -0,0 +1,61 @@ +CLANG_LEVEL := ../../.. +BUILT_SOURCES = \ + DiagnosticAnalysisKinds.inc DiagnosticASTKinds.inc \ + DiagnosticCommonKinds.inc DiagnosticDriverKinds.inc \ + DiagnosticFrontendKinds.inc DiagnosticLexKinds.inc \ + DiagnosticParseKinds.inc DiagnosticSemaKinds.inc \ + DiagnosticSerializationKinds.inc \ + DiagnosticIndexName.inc DiagnosticGroups.inc AttrList.inc arm_neon.inc \ + Version.inc + +TABLEGEN_INC_FILES_COMMON = 1 + +include $(CLANG_LEVEL)/Makefile + +INPUT_TDS = $(wildcard $(PROJ_SRC_DIR)/Diagnostic*.td) + +# Compute the Clang version from the LLVM version, unless specified explicitly. +ifndef CLANG_VERSION +CLANG_VERSION := $(subst svn,,$(LLVMVersion)) +CLANG_VERSION := $(subst rc,,$(CLANG_VERSION)) +endif + +CLANG_VERSION_COMPONENTS := $(subst ., ,$(CLANG_VERSION)) +CLANG_VERSION_MAJOR := $(word 1,$(CLANG_VERSION_COMPONENTS)) +CLANG_VERSION_MINOR := $(word 2,$(CLANG_VERSION_COMPONENTS)) +CLANG_VERSION_PATCHLEVEL := $(word 3,$(CLANG_VERSION_COMPONENTS)) +ifeq ($(CLANG_VERSION_PATCHLEVEL),) +CLANG_HAS_VERSION_PATCHLEVEL := 0 +else +CLANG_HAS_VERSION_PATCHLEVEL := 1 +endif + +$(ObjDir)/Diagnostic%Kinds.inc.tmp : Diagnostic.td $(INPUT_TDS) $(CLANG_TBLGEN) $(ObjDir)/.dir + $(Echo) "Building Clang $(patsubst Diagnostic%Kinds.inc.tmp,%,$(@F)) diagnostic tables with tblgen" + $(Verb) $(ClangTableGen) -gen-clang-diags-defs -clang-component=$(patsubst Diagnostic%Kinds.inc.tmp,%,$(@F)) -o $(call SYSPATH, $@) $< + +$(ObjDir)/DiagnosticIndexName.inc.tmp : Diagnostic.td $(INPUT_TDS) $(CLANG_TBLGEN) $(ObjDir)/.dir + $(Echo) "Building Clang diagnostic name index with tblgen" + $(Verb) $(ClangTableGen) -gen-clang-diags-index-name -o $(call SYSPATH, $@) $< + +$(ObjDir)/DiagnosticGroups.inc.tmp : Diagnostic.td DiagnosticGroups.td $(INPUT_TDS) $(CLANG_TBLGEN) $(ObjDir)/.dir + $(Echo) "Building Clang diagnostic groups with tblgen" + $(Verb) $(ClangTableGen) -gen-clang-diag-groups -o $(call SYSPATH, $@) $< + +$(ObjDir)/AttrList.inc.tmp : Attr.td $(CLANG_TBLGEN) $(ObjDir)/.dir + $(Echo) "Building Clang attribute list with tblgen" + $(Verb) $(ClangTableGen) -gen-clang-attr-list -o $(call SYSPATH, $@) \ + -I $(PROJ_SRC_DIR)/../.. $< + +$(ObjDir)/arm_neon.inc.tmp : arm_neon.td $(CLANG_TBLGEN) $(ObjDir)/.dir + $(Echo) "Building Clang arm_neon.inc with tblgen" + $(Verb) $(ClangTableGen) -gen-arm-neon-sema -o $(call SYSPATH, $@) $< + +$(ObjDir)/Version.inc.tmp : Version.inc.in Makefile $(LLVM_OBJ_ROOT)/Makefile.config $(ObjDir)/.dir + $(Echo) "Updating Clang version info." + $(Verb)sed -e "s#@CLANG_VERSION@#$(CLANG_VERSION)#g" \ + -e "s#@CLANG_VERSION_MAJOR@#$(CLANG_VERSION_MAJOR)#g" \ + -e "s#@CLANG_VERSION_MINOR@#$(CLANG_VERSION_MINOR)#g" \ + -e "s#@CLANG_VERSION_PATCHLEVEL@#$(CLANG_VERSION_PATCHLEVEL)#g" \ + -e "s#@CLANG_HAS_VERSION_PATCHLEVEL@#$(CLANG_HAS_VERSION_PATCHLEVEL)#g" \ + $< > $@ diff --git a/clang/include/clang/Basic/Module.h b/clang/include/clang/Basic/Module.h new file mode 100644 index 0000000..82dbd5b --- /dev/null +++ b/clang/include/clang/Basic/Module.h @@ -0,0 +1,284 @@ +//===--- Module.h - Describe a module ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Module class, which describes a module in the source +// code. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_BASIC_MODULE_H +#define LLVM_CLANG_BASIC_MODULE_H + +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include <string> +#include <utility> +#include <vector> + +namespace llvm { + class raw_ostream; +} + +namespace clang { + +class DirectoryEntry; +class FileEntry; +class LangOptions; +class TargetInfo; + +/// \brief Describes the name of a module. +typedef llvm::SmallVector<std::pair<std::string, SourceLocation>, 2> + ModuleId; + +/// \brief Describes a module or submodule. +class Module { +public: + /// \brief The name of this module. + std::string Name; + + /// \brief The location of the module definition. + SourceLocation DefinitionLoc; + + /// \brief The parent of this module. This will be NULL for the top-level + /// module. + Module *Parent; + + /// \brief The umbrella header or directory. + llvm::PointerUnion<const DirectoryEntry *, const FileEntry *> Umbrella; + +private: + /// \brief The submodules of this module, indexed by name. + std::vector<Module *> SubModules; + + /// \brief A mapping from the submodule name to the index into the + /// \c SubModules vector at which that submodule resides. + llvm::StringMap<unsigned> SubModuleIndex; + +public: + /// \brief The headers that are part of this module. + llvm::SmallVector<const FileEntry *, 2> Headers; + + /// \brief The set of language features required to use this module. + /// + /// If any of these features is not present, the \c IsAvailable bit + /// will be false to indicate that this (sub)module is not + /// available. + llvm::SmallVector<std::string, 2> Requires; + + /// \brief Whether this module is available in the current + /// translation unit. + unsigned IsAvailable : 1; + + /// \brief Whether this module was loaded from a module file. + unsigned IsFromModuleFile : 1; + + /// \brief Whether this is a framework module. + unsigned IsFramework : 1; + + /// \brief Whether this is an explicit submodule. + unsigned IsExplicit : 1; + + /// \brief Whether this is a "system" module (which assumes that all + /// headers in it are system headers). + unsigned IsSystem : 1; + + /// \brief Whether we should infer submodules for this module based on + /// the headers. + /// + /// Submodules can only be inferred for modules with an umbrella header. + unsigned InferSubmodules : 1; + + /// \brief Whether, when inferring submodules, the inferred submodules + /// should be explicit. + unsigned InferExplicitSubmodules : 1; + + /// \brief Whether, when inferring submodules, the inferr submodules should + /// export all modules they import (e.g., the equivalent of "export *"). + unsigned InferExportWildcard : 1; + + /// \brief Describes the visibility of the various names within a + /// particular module. + enum NameVisibilityKind { + /// \brief All of the names in this module are hidden. + /// + Hidden, + /// \brief Only the macro names in this module are visible. + MacrosVisible, + /// \brief All of the names in this module are visible. + AllVisible + }; + + ///\ brief The visibility of names within this particular module. + NameVisibilityKind NameVisibility; + + /// \brief The location of the inferred submodule. + SourceLocation InferredSubmoduleLoc; + + /// \brief The set of modules imported by this module, and on which this + /// module depends. + llvm::SmallVector<Module *, 2> Imports; + + /// \brief Describes an exported module. + /// + /// The pointer is the module being re-exported, while the bit will be true + /// to indicate that this is a wildcard export. + typedef llvm::PointerIntPair<Module *, 1, bool> ExportDecl; + + /// \brief The set of export declarations. + llvm::SmallVector<ExportDecl, 2> Exports; + + /// \brief Describes an exported module that has not yet been resolved + /// (perhaps because tASThe module it refers to has not yet been loaded). + struct UnresolvedExportDecl { + /// \brief The location of the 'export' keyword in the module map file. + SourceLocation ExportLoc; + + /// \brief The name of the module. + ModuleId Id; + + /// \brief Whether this export declaration ends in a wildcard, indicating + /// that all of its submodules should be exported (rather than the named + /// module itself). + bool Wildcard; + }; + + /// \brief The set of export declarations that have yet to be resolved. + llvm::SmallVector<UnresolvedExportDecl, 2> UnresolvedExports; + + /// \brief Construct a top-level module. + explicit Module(StringRef Name, SourceLocation DefinitionLoc, + bool IsFramework) + : Name(Name), DefinitionLoc(DefinitionLoc), Parent(0), Umbrella(), + IsAvailable(true), IsFromModuleFile(false), IsFramework(IsFramework), + IsExplicit(false), IsSystem(false), + InferSubmodules(false), InferExplicitSubmodules(false), + InferExportWildcard(false), NameVisibility(Hidden) { } + + /// \brief Construct a new module or submodule. + Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent, + bool IsFramework, bool IsExplicit); + + ~Module(); + + /// \brief Determine whether this module is available for use within the + /// current translation unit. + bool isAvailable() const { return IsAvailable; } + + /// \brief Determine whether this module is available for use within the + /// current translation unit. + /// + /// \param LangOpts The language options used for the current + /// translation unit. + /// + /// \param Target The target options used for the current translation unit. + /// + /// \param Feature If this module is unavailable, this parameter + /// will be set to one of the features that is required for use of + /// this module (but is not available). + bool isAvailable(const LangOptions &LangOpts, + const TargetInfo &Target, + StringRef &Feature) const; + + /// \brief Determine whether this module is a submodule. + bool isSubModule() const { return Parent != 0; } + + /// \brief Determine whether this module is a submodule of the given other + /// module. + bool isSubModuleOf(Module *Other) const; + + /// \brief Determine whether this module is a part of a framework, + /// either because it is a framework module or because it is a submodule + /// of a framework module. + bool isPartOfFramework() const { + for (const Module *Mod = this; Mod; Mod = Mod->Parent) + if (Mod->IsFramework) + return true; + + return false; + } + + /// \brief Retrieve the full name of this module, including the path from + /// its top-level module. + std::string getFullModuleName() const; + + /// \brief Retrieve the top-level module for this (sub)module, which may + /// be this module. + Module *getTopLevelModule() { + return const_cast<Module *>( + const_cast<const Module *>(this)->getTopLevelModule()); + } + + /// \brief Retrieve the top-level module for this (sub)module, which may + /// be this module. + const Module *getTopLevelModule() const; + + /// \brief Retrieve the name of the top-level module. + /// + StringRef getTopLevelModuleName() const { + return getTopLevelModule()->Name; + } + + /// \brief Retrieve the directory for which this module serves as the + /// umbrella. + const DirectoryEntry *getUmbrellaDir() const; + + /// \brief Retrieve the header that serves as the umbrella header for this + /// module. + const FileEntry *getUmbrellaHeader() const { + return Umbrella.dyn_cast<const FileEntry *>(); + } + + /// \brief Determine whether this module has an umbrella directory that is + /// not based on an umbrella header. + bool hasUmbrellaDir() const { + return Umbrella && Umbrella.is<const DirectoryEntry *>(); + } + + /// \briaf Add the given feature requirement to the list of features + /// required by this module. + /// + /// \param Feature The feature that is required by this module (and + /// its submodules). + /// + /// \param LangOpts The set of language options that will be used to + /// evaluate the availability of this feature. + /// + /// \param Target The target options that will be used to evaluate the + /// availability of this feature. + void addRequirement(StringRef Feature, const LangOptions &LangOpts, + const TargetInfo &Target); + + /// \brief Find the submodule with the given name. + /// + /// \returns The submodule if found, or NULL otherwise. + Module *findSubmodule(StringRef Name) const; + + typedef std::vector<Module *>::iterator submodule_iterator; + typedef std::vector<Module *>::const_iterator submodule_const_iterator; + + submodule_iterator submodule_begin() { return SubModules.begin(); } + submodule_const_iterator submodule_begin() const {return SubModules.begin();} + submodule_iterator submodule_end() { return SubModules.end(); } + submodule_const_iterator submodule_end() const { return SubModules.end(); } + + /// \brief Print the module map for this module to the given stream. + /// + void print(llvm::raw_ostream &OS, unsigned Indent = 0) const; + + /// \brief Dump the contents of this module to the given output stream. + void dump() const; +}; + +} // end namespace clang + + +#endif // LLVM_CLANG_BASIC_MODULE_H diff --git a/clang/include/clang/Basic/OnDiskHashTable.h b/clang/include/clang/Basic/OnDiskHashTable.h new file mode 100644 index 0000000..b92f1cf --- /dev/null +++ b/clang/include/clang/Basic/OnDiskHashTable.h @@ -0,0 +1,485 @@ +//===--- OnDiskHashTable.h - On-Disk Hash Table Implementation --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines facilities for reading and writing on-disk hash +// tables. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_BASIC_ON_DISK_HASH_TABLE_H +#define LLVM_CLANG_BASIC_ON_DISK_HASH_TABLE_H + +#include "llvm/Support/Allocator.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Host.h" +#include <cassert> +#include <cstdlib> + +namespace clang { + +namespace io { + +typedef uint32_t Offset; + +inline void Emit8(raw_ostream& Out, uint32_t V) { + Out << (unsigned char)(V); +} + +inline void Emit16(raw_ostream& Out, uint32_t V) { + Out << (unsigned char)(V); + Out << (unsigned char)(V >> 8); + assert((V >> 16) == 0); +} + +inline void Emit24(raw_ostream& Out, uint32_t V) { + Out << (unsigned char)(V); + Out << (unsigned char)(V >> 8); + Out << (unsigned char)(V >> 16); + assert((V >> 24) == 0); +} + +inline void Emit32(raw_ostream& Out, uint32_t V) { + Out << (unsigned char)(V); + Out << (unsigned char)(V >> 8); + Out << (unsigned char)(V >> 16); + Out << (unsigned char)(V >> 24); +} + +inline void Emit64(raw_ostream& Out, uint64_t V) { + Out << (unsigned char)(V); + Out << (unsigned char)(V >> 8); + Out << (unsigned char)(V >> 16); + Out << (unsigned char)(V >> 24); + Out << (unsigned char)(V >> 32); + Out << (unsigned char)(V >> 40); + Out << (unsigned char)(V >> 48); + Out << (unsigned char)(V >> 56); +} + +inline void Pad(raw_ostream& Out, unsigned A) { + Offset off = (Offset) Out.tell(); + uint32_t n = ((uintptr_t)(off+A-1) & ~(uintptr_t)(A-1)) - off; + for (; n ; --n) + Emit8(Out, 0); +} + +inline uint16_t ReadUnalignedLE16(const unsigned char *&Data) { + uint16_t V = ((uint16_t)Data[0]) | + ((uint16_t)Data[1] << 8); + Data += 2; + return V; +} + +inline uint32_t ReadUnalignedLE32(const unsigned char *&Data) { + uint32_t V = ((uint32_t)Data[0]) | + ((uint32_t)Data[1] << 8) | + ((uint32_t)Data[2] << 16) | + ((uint32_t)Data[3] << 24); + Data += 4; + return V; +} + +inline uint64_t ReadUnalignedLE64(const unsigned char *&Data) { + uint64_t V = ((uint64_t)Data[0]) | + ((uint64_t)Data[1] << 8) | + ((uint64_t)Data[2] << 16) | + ((uint64_t)Data[3] << 24) | + ((uint64_t)Data[4] << 32) | + ((uint64_t)Data[5] << 40) | + ((uint64_t)Data[6] << 48) | + ((uint64_t)Data[7] << 56); + Data += 8; + return V; +} + +inline uint32_t ReadLE32(const unsigned char *&Data) { + // Hosts that directly support little-endian 32-bit loads can just + // use them. Big-endian hosts need a bswap. + uint32_t V = *((uint32_t*)Data); + if (llvm::sys::isBigEndianHost()) + V = llvm::ByteSwap_32(V); + Data += 4; + return V; +} + +} // end namespace io + +template<typename Info> +class OnDiskChainedHashTableGenerator { + unsigned NumBuckets; + unsigned NumEntries; + llvm::BumpPtrAllocator BA; + + class Item { + public: + typename Info::key_type key; + typename Info::data_type data; + Item *next; + const uint32_t hash; + + Item(typename Info::key_type_ref k, typename Info::data_type_ref d, + Info &InfoObj) + : key(k), data(d), next(0), hash(InfoObj.ComputeHash(k)) {} + }; + + class Bucket { + public: + io::Offset off; + Item* head; + unsigned length; + + Bucket() {} + }; + + Bucket* Buckets; + +private: + void insert(Bucket* b, size_t size, Item* E) { + unsigned idx = E->hash & (size - 1); + Bucket& B = b[idx]; + E->next = B.head; + ++B.length; + B.head = E; + } + + void resize(size_t newsize) { + Bucket* newBuckets = (Bucket*) std::calloc(newsize, sizeof(Bucket)); + // Populate newBuckets with the old entries. + for (unsigned i = 0; i < NumBuckets; ++i) + for (Item* E = Buckets[i].head; E ; ) { + Item* N = E->next; + E->next = 0; + insert(newBuckets, newsize, E); + E = N; + } + + free(Buckets); + NumBuckets = newsize; + Buckets = newBuckets; + } + +public: + + void insert(typename Info::key_type_ref key, + typename Info::data_type_ref data) { + Info InfoObj; + insert(key, data, InfoObj); + } + + void insert(typename Info::key_type_ref key, + typename Info::data_type_ref data, Info &InfoObj) { + + ++NumEntries; + if (4*NumEntries >= 3*NumBuckets) resize(NumBuckets*2); + insert(Buckets, NumBuckets, new (BA.Allocate<Item>()) Item(key, data, + InfoObj)); + } + + io::Offset Emit(raw_ostream &out) { + Info InfoObj; + return Emit(out, InfoObj); + } + + io::Offset Emit(raw_ostream &out, Info &InfoObj) { + using namespace clang::io; + + // Emit the payload of the table. + for (unsigned i = 0; i < NumBuckets; ++i) { + Bucket& B = Buckets[i]; + if (!B.head) continue; + + // Store the offset for the data of this bucket. + B.off = out.tell(); + assert(B.off && "Cannot write a bucket at offset 0. Please add padding."); + + // Write out the number of items in the bucket. + Emit16(out, B.length); + assert(B.length != 0 && "Bucket has a head but zero length?"); + + // Write out the entries in the bucket. + for (Item *I = B.head; I ; I = I->next) { + Emit32(out, I->hash); + const std::pair<unsigned, unsigned>& Len = + InfoObj.EmitKeyDataLength(out, I->key, I->data); + InfoObj.EmitKey(out, I->key, Len.first); + InfoObj.EmitData(out, I->key, I->data, Len.second); + } + } + + // Emit the hashtable itself. + Pad(out, 4); + io::Offset TableOff = out.tell(); + Emit32(out, NumBuckets); + Emit32(out, NumEntries); + for (unsigned i = 0; i < NumBuckets; ++i) Emit32(out, Buckets[i].off); + + return TableOff; + } + + OnDiskChainedHashTableGenerator() { + NumEntries = 0; + NumBuckets = 64; + // Note that we do not need to run the constructors of the individual + // Bucket objects since 'calloc' returns bytes that are all 0. + Buckets = (Bucket*) std::calloc(NumBuckets, sizeof(Bucket)); + } + + ~OnDiskChainedHashTableGenerator() { + std::free(Buckets); + } +}; + +template<typename Info> +class OnDiskChainedHashTable { + const unsigned NumBuckets; + const unsigned NumEntries; + const unsigned char* const Buckets; + const unsigned char* const Base; + Info InfoObj; + +public: + typedef typename Info::internal_key_type internal_key_type; + typedef typename Info::external_key_type external_key_type; + typedef typename Info::data_type data_type; + + OnDiskChainedHashTable(unsigned numBuckets, unsigned numEntries, + const unsigned char* buckets, + const unsigned char* base, + const Info &InfoObj = Info()) + : NumBuckets(numBuckets), NumEntries(numEntries), + Buckets(buckets), Base(base), InfoObj(InfoObj) { + assert((reinterpret_cast<uintptr_t>(buckets) & 0x3) == 0 && + "'buckets' must have a 4-byte alignment"); + } + + unsigned getNumBuckets() const { return NumBuckets; } + unsigned getNumEntries() const { return NumEntries; } + const unsigned char* getBase() const { return Base; } + const unsigned char* getBuckets() const { return Buckets; } + + bool isEmpty() const { return NumEntries == 0; } + + class iterator { + internal_key_type key; + const unsigned char* const data; + const unsigned len; + Info *InfoObj; + public: + iterator() : data(0), len(0) {} + iterator(const internal_key_type k, const unsigned char* d, unsigned l, + Info *InfoObj) + : key(k), data(d), len(l), InfoObj(InfoObj) {} + + data_type operator*() const { return InfoObj->ReadData(key, data, len); } + bool operator==(const iterator& X) const { return X.data == data; } + bool operator!=(const iterator& X) const { return X.data != data; } + }; + + iterator find(const external_key_type& eKey, Info *InfoPtr = 0) { + if (!InfoPtr) + InfoPtr = &InfoObj; + + using namespace io; + const internal_key_type& iKey = InfoObj.GetInternalKey(eKey); + unsigned key_hash = InfoObj.ComputeHash(iKey); + + // Each bucket is just a 32-bit offset into the hash table file. + unsigned idx = key_hash & (NumBuckets - 1); + const unsigned char* Bucket = Buckets + sizeof(uint32_t)*idx; + + unsigned offset = ReadLE32(Bucket); + if (offset == 0) return iterator(); // Empty bucket. + const unsigned char* Items = Base + offset; + + // 'Items' starts with a 16-bit unsigned integer representing the + // number of items in this bucket. + unsigned len = ReadUnalignedLE16(Items); + + for (unsigned i = 0; i < len; ++i) { + // Read the hash. + uint32_t item_hash = ReadUnalignedLE32(Items); + + // Determine the length of the key and the data. + const std::pair<unsigned, unsigned>& L = Info::ReadKeyDataLength(Items); + unsigned item_len = L.first + L.second; + + // Compare the hashes. If they are not the same, skip the entry entirely. + if (item_hash != key_hash) { + Items += item_len; + continue; + } + + // Read the key. + const internal_key_type& X = + InfoPtr->ReadKey((const unsigned char* const) Items, L.first); + + // If the key doesn't match just skip reading the value. + if (!InfoPtr->EqualKey(X, iKey)) { + Items += item_len; + continue; + } + + // The key matches! + return iterator(X, Items + L.first, L.second, InfoPtr); + } + + return iterator(); + } + + iterator end() const { return iterator(); } + + /// \brief Iterates over all of the keys in the table. + class key_iterator { + const unsigned char* Ptr; + unsigned NumItemsInBucketLeft; + unsigned NumEntriesLeft; + Info *InfoObj; + public: + typedef external_key_type value_type; + + key_iterator(const unsigned char* const Ptr, unsigned NumEntries, + Info *InfoObj) + : Ptr(Ptr), NumItemsInBucketLeft(0), NumEntriesLeft(NumEntries), + InfoObj(InfoObj) { } + key_iterator() + : Ptr(0), NumItemsInBucketLeft(0), NumEntriesLeft(0), InfoObj(0) { } + + friend bool operator==(const key_iterator &X, const key_iterator &Y) { + return X.NumEntriesLeft == Y.NumEntriesLeft; + } + friend bool operator!=(const key_iterator& X, const key_iterator &Y) { + return X.NumEntriesLeft != Y.NumEntriesLeft; + } + + key_iterator& operator++() { // Preincrement + if (!NumItemsInBucketLeft) { + // 'Items' starts with a 16-bit unsigned integer representing the + // number of items in this bucket. + NumItemsInBucketLeft = io::ReadUnalignedLE16(Ptr); + } + Ptr += 4; // Skip the hash. + // Determine the length of the key and the data. + const std::pair<unsigned, unsigned>& L = Info::ReadKeyDataLength(Ptr); + Ptr += L.first + L.second; + assert(NumItemsInBucketLeft); + --NumItemsInBucketLeft; + assert(NumEntriesLeft); + --NumEntriesLeft; + return *this; + } + key_iterator operator++(int) { // Postincrement + key_iterator tmp = *this; ++*this; return tmp; + } + + value_type operator*() const { + const unsigned char* LocalPtr = Ptr; + if (!NumItemsInBucketLeft) + LocalPtr += 2; // number of items in bucket + LocalPtr += 4; // Skip the hash. + + // Determine the length of the key and the data. + const std::pair<unsigned, unsigned>& L + = Info::ReadKeyDataLength(LocalPtr); + + // Read the key. + const internal_key_type& Key = InfoObj->ReadKey(LocalPtr, L.first); + return InfoObj->GetExternalKey(Key); + } + }; + + key_iterator key_begin() { + return key_iterator(Base + 4, getNumEntries(), &InfoObj); + } + key_iterator key_end() { return key_iterator(); } + + /// \brief Iterates over all the entries in the table, returning the data. + class data_iterator { + const unsigned char* Ptr; + unsigned NumItemsInBucketLeft; + unsigned NumEntriesLeft; + Info *InfoObj; + public: + typedef data_type value_type; + + data_iterator(const unsigned char* const Ptr, unsigned NumEntries, + Info *InfoObj) + : Ptr(Ptr), NumItemsInBucketLeft(0), NumEntriesLeft(NumEntries), + InfoObj(InfoObj) { } + data_iterator() + : Ptr(0), NumItemsInBucketLeft(0), NumEntriesLeft(0), InfoObj(0) { } + + bool operator==(const data_iterator& X) const { + return X.NumEntriesLeft == NumEntriesLeft; + } + bool operator!=(const data_iterator& X) const { + return X.NumEntriesLeft != NumEntriesLeft; + } + + data_iterator& operator++() { // Preincrement + if (!NumItemsInBucketLeft) { + // 'Items' starts with a 16-bit unsigned integer representing the + // number of items in this bucket. + NumItemsInBucketLeft = io::ReadUnalignedLE16(Ptr); + } + Ptr += 4; // Skip the hash. + // Determine the length of the key and the data. + const std::pair<unsigned, unsigned>& L = Info::ReadKeyDataLength(Ptr); + Ptr += L.first + L.second; + assert(NumItemsInBucketLeft); + --NumItemsInBucketLeft; + assert(NumEntriesLeft); + --NumEntriesLeft; + return *this; + } + data_iterator operator++(int) { // Postincrement + data_iterator tmp = *this; ++*this; return tmp; + } + + value_type operator*() const { + const unsigned char* LocalPtr = Ptr; + if (!NumItemsInBucketLeft) + LocalPtr += 2; // number of items in bucket + LocalPtr += 4; // Skip the hash. + + // Determine the length of the key and the data. + const std::pair<unsigned, unsigned>& L =Info::ReadKeyDataLength(LocalPtr); + + // Read the key. + const internal_key_type& Key = + InfoObj->ReadKey(LocalPtr, L.first); + return InfoObj->ReadData(Key, LocalPtr + L.first, L.second); + } + }; + + data_iterator data_begin() { + return data_iterator(Base + 4, getNumEntries(), &InfoObj); + } + data_iterator data_end() { return data_iterator(); } + + Info &getInfoObj() { return InfoObj; } + + static OnDiskChainedHashTable* Create(const unsigned char* buckets, + const unsigned char* const base, + const Info &InfoObj = Info()) { + using namespace io; + assert(buckets > base); + assert((reinterpret_cast<uintptr_t>(buckets) & 0x3) == 0 && + "buckets should be 4-byte aligned."); + + unsigned numBuckets = ReadLE32(buckets); + unsigned numEntries = ReadLE32(buckets); + return new OnDiskChainedHashTable<Info>(numBuckets, numEntries, buckets, + base, InfoObj); + } +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Basic/OpenCL.h b/clang/include/clang/Basic/OpenCL.h new file mode 100644 index 0000000..6f9785f --- /dev/null +++ b/clang/include/clang/Basic/OpenCL.h @@ -0,0 +1,28 @@ +//===--- OpenCL.h - OpenCL enums --------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines some OpenCL-specific enums. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_OPENCL_H +#define LLVM_CLANG_BASIC_OPENCL_H + +namespace clang { + +/// Names for the OpenCL image access qualifiers (OpenCL 1.1 6.6). +enum OpenCLImageAccess { + CLIA_read_only = 1, + CLIA_write_only = 2, + CLIA_read_write = 3 +}; + +} + +#endif diff --git a/clang/include/clang/Basic/OpenCLExtensions.def b/clang/include/clang/Basic/OpenCLExtensions.def new file mode 100644 index 0000000..103fa83 --- /dev/null +++ b/clang/include/clang/Basic/OpenCLExtensions.def @@ -0,0 +1,32 @@ +//===--- OpenCLExtensions.def - OpenCL extension list -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the list of supported OpenCL extensions. +// +//===----------------------------------------------------------------------===// + +// OpenCL 1.1. +OPENCLEXT(cl_khr_fp64) +OPENCLEXT(cl_khr_int64_base_atomics) +OPENCLEXT(cl_khr_int64_extended_atomics) +OPENCLEXT(cl_khr_fp16) +OPENCLEXT(cl_khr_gl_sharing) +OPENCLEXT(cl_khr_gl_event) +OPENCLEXT(cl_khr_d3d10_sharing) +OPENCLEXT(cl_khr_global_int32_base_atomics) +OPENCLEXT(cl_khr_global_int32_extended_atomics) +OPENCLEXT(cl_khr_local_int32_base_atomics) +OPENCLEXT(cl_khr_local_int32_extended_atomics) +OPENCLEXT(cl_khr_byte_addressable_store) +OPENCLEXT(cl_khr_3d_image_writes) + +// Clang Extensions. +OPENCLEXT(cl_clang_storage_class_specifiers) + +#undef OPENCLEXT diff --git a/clang/include/clang/Basic/OperatorKinds.def b/clang/include/clang/Basic/OperatorKinds.def new file mode 100644 index 0000000..d011e9d --- /dev/null +++ b/clang/include/clang/Basic/OperatorKinds.def @@ -0,0 +1,106 @@ +//===--- OperatorKinds.def - C++ Overloaded Operator Database ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the OverloadedOperator database, which includes +// all of the overloadable C++ operators. +// +//===----------------------------------------------------------------------===// +// +/// @file OperatorKinds.def +/// +/// In this file, each of the overloadable C++ operators is enumerated +/// with either the OVERLOADED_OPERATOR or OVERLOADED_OPERATOR_MULTI +/// macro, each of which can be specified by the code including this +/// file. OVERLOADED_OPERATOR is used for single-token operators +/// (e.g., "+"), and has six arguments: +/// +/// Name: The name of the token. OO_Name will be the name of the +/// corresponding enumerator in OverloadedOperatorKind in +/// OperatorKinds.h. +/// +/// Spelling: A string that provides a canonical spelling for the +/// operator, e.g., "operator+". +/// +/// Token: The name of the token that specifies the operator, e.g., +/// "plus" for operator+ or "greatergreaterequal" for +/// "operator>>=". With a "kw_" prefix, the token name can be used as +/// an enumerator into the TokenKind enumeration. +/// +/// Unary: True if the operator can be declared as a unary operator. +/// +/// Binary: True if the operator can be declared as a binary +/// operator. Note that some operators (e.g., "operator+" and +/// "operator*") can be both unary and binary. +/// +/// MemberOnly: True if this operator can only be declared as a +/// non-static member function. False if the operator can be both a +/// non-member function and a non-static member function. +/// +/// OVERLOADED_OPERATOR_MULTI is used to enumerate the multi-token +/// overloaded operator names, e.g., "operator delete []". The macro +/// has all of the parameters of OVERLOADED_OPERATOR except Token, +/// which is omitted. + +#ifndef OVERLOADED_OPERATOR +# define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) +#endif + +#ifndef OVERLOADED_OPERATOR_MULTI +# define OVERLOADED_OPERATOR_MULTI(Name,Spelling,Unary,Binary,MemberOnly) \ + OVERLOADED_OPERATOR(Name,Spelling,unknown,Unary,Binary,MemberOnly) +#endif + +OVERLOADED_OPERATOR_MULTI(New , "new" , true , true , false) +OVERLOADED_OPERATOR_MULTI(Delete , "delete" , true , true , false) +OVERLOADED_OPERATOR_MULTI(Array_New , "new[]" , true , true , false) +OVERLOADED_OPERATOR_MULTI(Array_Delete , "delete[]" , true , true , false) +OVERLOADED_OPERATOR(Plus , "+" , plus , true , true , false) +OVERLOADED_OPERATOR(Minus , "-" , minus , true , true , false) +OVERLOADED_OPERATOR(Star , "*" , star , true , true , false) +OVERLOADED_OPERATOR(Slash , "/" , slash , false, true , false) +OVERLOADED_OPERATOR(Percent , "%" , percent , false, true , false) +OVERLOADED_OPERATOR(Caret , "^" , caret , false, true , false) +OVERLOADED_OPERATOR(Amp , "&" , amp , true , true , false) +OVERLOADED_OPERATOR(Pipe , "|" , pipe , false, true , false) +OVERLOADED_OPERATOR(Tilde , "~" , tilde , true , false, false) +OVERLOADED_OPERATOR(Exclaim , "!" , exclaim , true , false, false) +OVERLOADED_OPERATOR(Equal , "=" , equal , false, true , true) +OVERLOADED_OPERATOR(Less , "<" , less , false, true , false) +OVERLOADED_OPERATOR(Greater , ">" , greater , false, true , false) +OVERLOADED_OPERATOR(PlusEqual , "+=" , plusequal , false, true , false) +OVERLOADED_OPERATOR(MinusEqual , "-=" , minusequal , false, true , false) +OVERLOADED_OPERATOR(StarEqual , "*=" , starequal , false, true , false) +OVERLOADED_OPERATOR(SlashEqual , "/=" , slashequal , false, true , false) +OVERLOADED_OPERATOR(PercentEqual , "%=" , percentequal , false, true , false) +OVERLOADED_OPERATOR(CaretEqual , "^=" , caretequal , false, true , false) +OVERLOADED_OPERATOR(AmpEqual , "&=" , ampequal , false, true , false) +OVERLOADED_OPERATOR(PipeEqual , "|=" , pipeequal , false, true , false) +OVERLOADED_OPERATOR(LessLess , "<<" , lessless , false, true , false) +OVERLOADED_OPERATOR(GreaterGreater , ">>" , greatergreater , false, true , false) +OVERLOADED_OPERATOR(LessLessEqual , "<<=" , lesslessequal , false, true , false) +OVERLOADED_OPERATOR(GreaterGreaterEqual , ">>=" , greatergreaterequal, false, true , false) +OVERLOADED_OPERATOR(EqualEqual , "==" , equalequal , false, true , false) +OVERLOADED_OPERATOR(ExclaimEqual , "!=" , exclaimequal , false, true , false) +OVERLOADED_OPERATOR(LessEqual , "<=" , lessequal , false, true , false) +OVERLOADED_OPERATOR(GreaterEqual , ">=" , greaterequal , false, true , false) +OVERLOADED_OPERATOR(AmpAmp , "&&" , ampamp , false, true , false) +OVERLOADED_OPERATOR(PipePipe , "||" , pipepipe , false, true , false) +OVERLOADED_OPERATOR(PlusPlus , "++" , plusplus , true , true , false) +OVERLOADED_OPERATOR(MinusMinus , "--" , minusminus , true , true , false) +OVERLOADED_OPERATOR(Comma , "," , comma , false, true , false) +OVERLOADED_OPERATOR(ArrowStar , "->*" , arrowstar , false, true , false) +OVERLOADED_OPERATOR(Arrow , "->" , arrow , true , false, true) +OVERLOADED_OPERATOR_MULTI(Call , "()" , true , true , true) +OVERLOADED_OPERATOR_MULTI(Subscript , "[]" , false, true , true) +// ?: can *not* be overloaded, but we need the overload +// resolution machinery for it. +OVERLOADED_OPERATOR_MULTI(Conditional , "?" , false, true , false) + +#undef OVERLOADED_OPERATOR_MULTI +#undef OVERLOADED_OPERATOR diff --git a/clang/include/clang/Basic/OperatorKinds.h b/clang/include/clang/Basic/OperatorKinds.h new file mode 100644 index 0000000..c0a9505 --- /dev/null +++ b/clang/include/clang/Basic/OperatorKinds.h @@ -0,0 +1,35 @@ +//===--- OperatorKinds.h - C++ Overloaded Operators -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines C++ overloaded operators. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_OPERATOR_KINDS_H +#define LLVM_CLANG_BASIC_OPERATOR_KINDS_H + +namespace clang { + +/// OverloadedOperatorKind - Enumeration specifying the different kinds of +/// C++ overloaded operators. +enum OverloadedOperatorKind { + OO_None, //< Not an overloaded operator +#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ + OO_##Name, +#include "clang/Basic/OperatorKinds.def" + NUM_OVERLOADED_OPERATORS +}; + +/// \brief Retrieve the spelling of the given overloaded operator, without +/// the preceding "operator" keyword. +const char *getOperatorSpelling(OverloadedOperatorKind Operator); + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Basic/PartialDiagnostic.h b/clang/include/clang/Basic/PartialDiagnostic.h new file mode 100644 index 0000000..007e6a4 --- /dev/null +++ b/clang/include/clang/Basic/PartialDiagnostic.h @@ -0,0 +1,352 @@ +//===--- PartialDiagnostic.h - Diagnostic "closures" ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements a partial diagnostic that can be emitted anwyhere +// in a DiagnosticBuilder stream. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_PARTIALDIAGNOSTIC_H +#define LLVM_CLANG_PARTIALDIAGNOSTIC_H + +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/DataTypes.h" +#include <cassert> + +namespace clang { + +class PartialDiagnostic { +public: + enum { + // The MaxArguments and MaxFixItHints member enum values from + // DiagnosticsEngine are private but DiagnosticsEngine declares + // PartialDiagnostic a friend. These enum values are redeclared + // here so that the nested Storage class below can access them. + MaxArguments = DiagnosticsEngine::MaxArguments + }; + + struct Storage { + Storage() : NumDiagArgs(0), NumDiagRanges(0) { } + + enum { + /// MaxArguments - The maximum number of arguments we can hold. We + /// currently only support up to 10 arguments (%0-%9). + /// A single diagnostic with more than that almost certainly has to + /// be simplified anyway. + MaxArguments = PartialDiagnostic::MaxArguments + }; + + /// NumDiagArgs - This contains the number of entries in Arguments. + unsigned char NumDiagArgs; + + /// NumDiagRanges - This is the number of ranges in the DiagRanges array. + unsigned char NumDiagRanges; + + /// DiagArgumentsKind - This is an array of ArgumentKind::ArgumentKind enum + /// values, with one for each argument. This specifies whether the argument + /// is in DiagArgumentsStr or in DiagArguments. + unsigned char DiagArgumentsKind[MaxArguments]; + + /// DiagArgumentsVal - The values for the various substitution positions. + /// This is used when the argument is not an std::string. The specific value + /// is mangled into an intptr_t and the interpretation depends on exactly + /// what sort of argument kind it is. + intptr_t DiagArgumentsVal[MaxArguments]; + + /// \brief The values for the various substitution positions that have + /// string arguments. + std::string DiagArgumentsStr[MaxArguments]; + + /// DiagRanges - The list of ranges added to this diagnostic. It currently + /// only support 10 ranges, could easily be extended if needed. + CharSourceRange DiagRanges[10]; + + /// FixItHints - If valid, provides a hint with some code + /// to insert, remove, or modify at a particular position. + SmallVector<FixItHint, 6> FixItHints; + }; + + /// \brief An allocator for Storage objects, which uses a small cache to + /// objects, used to reduce malloc()/free() traffic for partial diagnostics. + class StorageAllocator { + static const unsigned NumCached = 16; + Storage Cached[NumCached]; + Storage *FreeList[NumCached]; + unsigned NumFreeListEntries; + + public: + StorageAllocator(); + ~StorageAllocator(); + + /// \brief Allocate new storage. + Storage *Allocate() { + if (NumFreeListEntries == 0) + return new Storage; + + Storage *Result = FreeList[--NumFreeListEntries]; + Result->NumDiagArgs = 0; + Result->NumDiagRanges = 0; + Result->FixItHints.clear(); + return Result; + } + + /// \brief Free the given storage object. + void Deallocate(Storage *S) { + if (S >= Cached && S <= Cached + NumCached) { + FreeList[NumFreeListEntries++] = S; + return; + } + + delete S; + } + }; + +private: + // NOTE: Sema assumes that PartialDiagnostic is location-invariant + // in the sense that its bits can be safely memcpy'ed and destructed + // in the new location. + + /// DiagID - The diagnostic ID. + mutable unsigned DiagID; + + /// DiagStorage - Storage for args and ranges. + mutable Storage *DiagStorage; + + /// \brief Allocator used to allocate storage for this diagnostic. + StorageAllocator *Allocator; + + /// \brief Retrieve storage for this particular diagnostic. + Storage *getStorage() const { + if (DiagStorage) + return DiagStorage; + + if (Allocator) + DiagStorage = Allocator->Allocate(); + else { + assert(Allocator != reinterpret_cast<StorageAllocator *>(~uintptr_t(0))); + DiagStorage = new Storage; + } + return DiagStorage; + } + + void freeStorage() { + if (!DiagStorage) + return; + + // The hot path for PartialDiagnostic is when we just used it to wrap an ID + // (typically so we have the flexibility of passing a more complex + // diagnostic into the callee, but that does not commonly occur). + // + // Split this out into a slow function for silly compilers (*cough*) which + // can't do decent partial inlining. + freeStorageSlow(); + } + + void freeStorageSlow() { + if (Allocator) + Allocator->Deallocate(DiagStorage); + else if (Allocator != reinterpret_cast<StorageAllocator *>(~uintptr_t(0))) + delete DiagStorage; + DiagStorage = 0; + } + + void AddSourceRange(const CharSourceRange &R) const { + if (!DiagStorage) + DiagStorage = getStorage(); + + assert(DiagStorage->NumDiagRanges < + llvm::array_lengthof(DiagStorage->DiagRanges) && + "Too many arguments to diagnostic!"); + DiagStorage->DiagRanges[DiagStorage->NumDiagRanges++] = R; + } + + void AddFixItHint(const FixItHint &Hint) const { + if (Hint.isNull()) + return; + + if (!DiagStorage) + DiagStorage = getStorage(); + + DiagStorage->FixItHints.push_back(Hint); + } + +public: + PartialDiagnostic(unsigned DiagID, StorageAllocator &Allocator) + : DiagID(DiagID), DiagStorage(0), Allocator(&Allocator) { } + + PartialDiagnostic(const PartialDiagnostic &Other) + : DiagID(Other.DiagID), DiagStorage(0), Allocator(Other.Allocator) + { + if (Other.DiagStorage) { + DiagStorage = getStorage(); + *DiagStorage = *Other.DiagStorage; + } + } + + PartialDiagnostic(const PartialDiagnostic &Other, Storage *DiagStorage) + : DiagID(Other.DiagID), DiagStorage(DiagStorage), + Allocator(reinterpret_cast<StorageAllocator *>(~uintptr_t(0))) + { + if (Other.DiagStorage) + *this->DiagStorage = *Other.DiagStorage; + } + + PartialDiagnostic(const Diagnostic &Other, StorageAllocator &Allocator) + : DiagID(Other.getID()), DiagStorage(0), Allocator(&Allocator) + { + // Copy arguments. + for (unsigned I = 0, N = Other.getNumArgs(); I != N; ++I) { + if (Other.getArgKind(I) == DiagnosticsEngine::ak_std_string) + AddString(Other.getArgStdStr(I)); + else + AddTaggedVal(Other.getRawArg(I), Other.getArgKind(I)); + } + + // Copy source ranges. + for (unsigned I = 0, N = Other.getNumRanges(); I != N; ++I) + AddSourceRange(Other.getRange(I)); + + // Copy fix-its. + for (unsigned I = 0, N = Other.getNumFixItHints(); I != N; ++I) + AddFixItHint(Other.getFixItHint(I)); + } + + PartialDiagnostic &operator=(const PartialDiagnostic &Other) { + DiagID = Other.DiagID; + if (Other.DiagStorage) { + if (!DiagStorage) + DiagStorage = getStorage(); + + *DiagStorage = *Other.DiagStorage; + } else { + freeStorage(); + } + + return *this; + } + + ~PartialDiagnostic() { + freeStorage(); + } + + unsigned getDiagID() const { return DiagID; } + + void AddTaggedVal(intptr_t V, DiagnosticsEngine::ArgumentKind Kind) const { + if (!DiagStorage) + DiagStorage = getStorage(); + + assert(DiagStorage->NumDiagArgs < Storage::MaxArguments && + "Too many arguments to diagnostic!"); + DiagStorage->DiagArgumentsKind[DiagStorage->NumDiagArgs] = Kind; + DiagStorage->DiagArgumentsVal[DiagStorage->NumDiagArgs++] = V; + } + + void AddString(StringRef V) const { + if (!DiagStorage) + DiagStorage = getStorage(); + + assert(DiagStorage->NumDiagArgs < Storage::MaxArguments && + "Too many arguments to diagnostic!"); + DiagStorage->DiagArgumentsKind[DiagStorage->NumDiagArgs] + = DiagnosticsEngine::ak_std_string; + DiagStorage->DiagArgumentsStr[DiagStorage->NumDiagArgs++] = V; + } + + void Emit(const DiagnosticBuilder &DB) const { + if (!DiagStorage) + return; + + // Add all arguments. + for (unsigned i = 0, e = DiagStorage->NumDiagArgs; i != e; ++i) { + if ((DiagnosticsEngine::ArgumentKind)DiagStorage->DiagArgumentsKind[i] + == DiagnosticsEngine::ak_std_string) + DB.AddString(DiagStorage->DiagArgumentsStr[i]); + else + DB.AddTaggedVal(DiagStorage->DiagArgumentsVal[i], + (DiagnosticsEngine::ArgumentKind)DiagStorage->DiagArgumentsKind[i]); + } + + // Add all ranges. + for (unsigned i = 0, e = DiagStorage->NumDiagRanges; i != e; ++i) + DB.AddSourceRange(DiagStorage->DiagRanges[i]); + + // Add all fix-its. + for (unsigned i = 0, e = DiagStorage->FixItHints.size(); i != e; ++i) + DB.AddFixItHint(DiagStorage->FixItHints[i]); + } + + /// \brief Clear out this partial diagnostic, giving it a new diagnostic ID + /// and removing all of its arguments, ranges, and fix-it hints. + void Reset(unsigned DiagID = 0) { + this->DiagID = DiagID; + freeStorage(); + } + + bool hasStorage() const { return DiagStorage != 0; } + + friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, + unsigned I) { + PD.AddTaggedVal(I, DiagnosticsEngine::ak_uint); + return PD; + } + + friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, + int I) { + PD.AddTaggedVal(I, DiagnosticsEngine::ak_sint); + return PD; + } + + friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, + const char *S) { + PD.AddTaggedVal(reinterpret_cast<intptr_t>(S), + DiagnosticsEngine::ak_c_string); + return PD; + } + + friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, + StringRef S) { + + PD.AddString(S); + return PD; + } + + friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, + const SourceRange &R) { + PD.AddSourceRange(CharSourceRange::getTokenRange(R)); + return PD; + } + + friend inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, + const CharSourceRange &R) { + PD.AddSourceRange(R); + return PD; + } + + friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD, + const FixItHint &Hint) { + PD.AddFixItHint(Hint); + return PD; + } + +}; + +inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + const PartialDiagnostic &PD) { + PD.Emit(DB); + return DB; +} + +/// \brief A partial diagnostic along with the source location where this +/// diagnostic occurs. +typedef std::pair<SourceLocation, PartialDiagnostic> PartialDiagnosticAt; + +} // end namespace clang +#endif diff --git a/clang/include/clang/Basic/PrettyStackTrace.h b/clang/include/clang/Basic/PrettyStackTrace.h new file mode 100644 index 0000000..06a1264 --- /dev/null +++ b/clang/include/clang/Basic/PrettyStackTrace.h @@ -0,0 +1,37 @@ +//===- clang/Basic/PrettyStackTrace.h - Pretty Crash Handling --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the PrettyStackTraceEntry class, which is used to make +// crashes give more contextual information about what the program was doing +// when it crashed. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_BASIC_PRETTYSTACKTRACE_H +#define CLANG_BASIC_PRETTYSTACKTRACE_H + +#include "clang/Basic/SourceLocation.h" +#include "llvm/Support/PrettyStackTrace.h" + +namespace clang { + + /// PrettyStackTraceLoc - If a crash happens while one of these objects are + /// live, the message is printed out along with the specified source location. + class PrettyStackTraceLoc : public llvm::PrettyStackTraceEntry { + SourceManager &SM; + SourceLocation Loc; + const char *Message; + public: + PrettyStackTraceLoc(SourceManager &sm, SourceLocation L, const char *Msg) + : SM(sm), Loc(L), Message(Msg) {} + virtual void print(raw_ostream &OS) const; + }; +} + +#endif diff --git a/clang/include/clang/Basic/SourceLocation.h b/clang/include/clang/Basic/SourceLocation.h new file mode 100644 index 0000000..d5fa7e7 --- /dev/null +++ b/clang/include/clang/Basic/SourceLocation.h @@ -0,0 +1,426 @@ +//===--- SourceLocation.h - Compact identifier for Source Files -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the SourceLocation class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SOURCELOCATION_H +#define LLVM_CLANG_SOURCELOCATION_H + +#include "clang/Basic/LLVM.h" +#include "llvm/Support/PointerLikeTypeTraits.h" +#include "llvm/Support/Compiler.h" +#include <utility> +#include <functional> +#include <cassert> + +namespace llvm { + class MemoryBuffer; + template <typename T> struct DenseMapInfo; + template <typename T> struct isPodLike; +} + +namespace clang { + +class SourceManager; + +/// FileID - This is an opaque identifier used by SourceManager which refers to +/// a source file (MemoryBuffer) along with its #include path and #line data. +/// +class FileID { + /// ID - Opaque identifier, 0 is "invalid". >0 is this module, <-1 is + /// something loaded from another module. + int ID; +public: + FileID() : ID(0) {} + + bool isInvalid() const { return ID == 0; } + + bool operator==(const FileID &RHS) const { return ID == RHS.ID; } + bool operator<(const FileID &RHS) const { return ID < RHS.ID; } + bool operator<=(const FileID &RHS) const { return ID <= RHS.ID; } + bool operator!=(const FileID &RHS) const { return !(*this == RHS); } + bool operator>(const FileID &RHS) const { return RHS < *this; } + bool operator>=(const FileID &RHS) const { return RHS <= *this; } + + static FileID getSentinel() { return get(-1); } + unsigned getHashValue() const { return static_cast<unsigned>(ID); } + +private: + friend class SourceManager; + friend class ASTWriter; + friend class ASTReader; + + static FileID get(int V) { + FileID F; + F.ID = V; + return F; + } + int getOpaqueValue() const { return ID; } +}; + + +/// \brief Encodes a location in the source. The SourceManager can decode this +/// to get at the full include stack, line and column information. +/// +/// Technically, a source location is simply an offset into the manager's view +/// of the input source, which is all input buffers (including macro +/// expansions) concatenated in an effectively arbitrary order. The manager +/// actually maintains two blocks of input buffers. One, starting at offset +/// 0 and growing upwards, contains all buffers from this module. The other, +/// starting at the highest possible offset and growing downwards, contains +/// buffers of loaded modules. +/// +/// In addition, one bit of SourceLocation is used for quick access to the +/// information whether the location is in a file or a macro expansion. +/// +/// It is important that this type remains small. It is currently 32 bits wide. +class SourceLocation { + unsigned ID; + friend class SourceManager; + friend class ASTReader; + friend class ASTWriter; + enum { + MacroIDBit = 1U << 31 + }; +public: + + SourceLocation() : ID(0) {} + + bool isFileID() const { return (ID & MacroIDBit) == 0; } + bool isMacroID() const { return (ID & MacroIDBit) != 0; } + + /// \brief Return true if this is a valid SourceLocation object. + /// + /// Invalid SourceLocations are often used when events have no corresponding + /// location in the source (e.g. a diagnostic is required for a command line + /// option). + bool isValid() const { return ID != 0; } + bool isInvalid() const { return ID == 0; } + +private: + /// \brief Return the offset into the manager's global input view. + unsigned getOffset() const { + return ID & ~MacroIDBit; + } + + static SourceLocation getFileLoc(unsigned ID) { + assert((ID & MacroIDBit) == 0 && "Ran out of source locations!"); + SourceLocation L; + L.ID = ID; + return L; + } + + static SourceLocation getMacroLoc(unsigned ID) { + assert((ID & MacroIDBit) == 0 && "Ran out of source locations!"); + SourceLocation L; + L.ID = MacroIDBit | ID; + return L; + } +public: + + /// \brief Return a source location with the specified offset from this + /// SourceLocation. + SourceLocation getLocWithOffset(int Offset) const { + assert(((getOffset()+Offset) & MacroIDBit) == 0 && "offset overflow"); + SourceLocation L; + L.ID = ID+Offset; + return L; + } + + /// getRawEncoding - When a SourceLocation itself cannot be used, this returns + /// an (opaque) 32-bit integer encoding for it. This should only be passed + /// to SourceLocation::getFromRawEncoding, it should not be inspected + /// directly. + unsigned getRawEncoding() const { return ID; } + + /// getFromRawEncoding - Turn a raw encoding of a SourceLocation object into + /// a real SourceLocation. + static SourceLocation getFromRawEncoding(unsigned Encoding) { + SourceLocation X; + X.ID = Encoding; + return X; + } + + /// getPtrEncoding - When a SourceLocation itself cannot be used, this returns + /// an (opaque) pointer encoding for it. This should only be passed + /// to SourceLocation::getFromPtrEncoding, it should not be inspected + /// directly. + void* getPtrEncoding() const { + // Double cast to avoid a warning "cast to pointer from integer of different + // size". + return (void*)(uintptr_t)getRawEncoding(); + } + + /// getFromPtrEncoding - Turn a pointer encoding of a SourceLocation object + /// into a real SourceLocation. + static SourceLocation getFromPtrEncoding(void *Encoding) { + return getFromRawEncoding((unsigned)(uintptr_t)Encoding); + } + + void print(raw_ostream &OS, const SourceManager &SM) const; + void dump(const SourceManager &SM) const; +}; + +inline bool operator==(const SourceLocation &LHS, const SourceLocation &RHS) { + return LHS.getRawEncoding() == RHS.getRawEncoding(); +} + +inline bool operator!=(const SourceLocation &LHS, const SourceLocation &RHS) { + return !(LHS == RHS); +} + +inline bool operator<(const SourceLocation &LHS, const SourceLocation &RHS) { + return LHS.getRawEncoding() < RHS.getRawEncoding(); +} + +/// SourceRange - a trival tuple used to represent a source range. +class SourceRange { + SourceLocation B; + SourceLocation E; +public: + SourceRange(): B(SourceLocation()), E(SourceLocation()) {} + SourceRange(SourceLocation loc) : B(loc), E(loc) {} + SourceRange(SourceLocation begin, SourceLocation end) : B(begin), E(end) {} + + SourceLocation getBegin() const { return B; } + SourceLocation getEnd() const { return E; } + + void setBegin(SourceLocation b) { B = b; } + void setEnd(SourceLocation e) { E = e; } + + bool isValid() const { return B.isValid() && E.isValid(); } + bool isInvalid() const { return !isValid(); } + + bool operator==(const SourceRange &X) const { + return B == X.B && E == X.E; + } + + bool operator!=(const SourceRange &X) const { + return B != X.B || E != X.E; + } +}; + +/// CharSourceRange - This class represents a character granular source range. +/// The underlying SourceRange can either specify the starting/ending character +/// of the range, or it can specify the start or the range and the start of the +/// last token of the range (a "token range"). In the token range case, the +/// size of the last token must be measured to determine the actual end of the +/// range. +class CharSourceRange { + SourceRange Range; + bool IsTokenRange; +public: + CharSourceRange() : IsTokenRange(false) {} + CharSourceRange(SourceRange R, bool ITR) : Range(R),IsTokenRange(ITR){} + + static CharSourceRange getTokenRange(SourceRange R) { + CharSourceRange Result; + Result.Range = R; + Result.IsTokenRange = true; + return Result; + } + + static CharSourceRange getCharRange(SourceRange R) { + CharSourceRange Result; + Result.Range = R; + Result.IsTokenRange = false; + return Result; + } + + static CharSourceRange getTokenRange(SourceLocation B, SourceLocation E) { + return getTokenRange(SourceRange(B, E)); + } + static CharSourceRange getCharRange(SourceLocation B, SourceLocation E) { + return getCharRange(SourceRange(B, E)); + } + + /// isTokenRange - Return true if the end of this range specifies the start of + /// the last token. Return false if the end of this range specifies the last + /// character in the range. + bool isTokenRange() const { return IsTokenRange; } + bool isCharRange() const { return !IsTokenRange; } + + SourceLocation getBegin() const { return Range.getBegin(); } + SourceLocation getEnd() const { return Range.getEnd(); } + const SourceRange &getAsRange() const { return Range; } + + void setBegin(SourceLocation b) { Range.setBegin(b); } + void setEnd(SourceLocation e) { Range.setEnd(e); } + + bool isValid() const { return Range.isValid(); } + bool isInvalid() const { return !isValid(); } +}; + +/// FullSourceLoc - A SourceLocation and its associated SourceManager. Useful +/// for argument passing to functions that expect both objects. +class FullSourceLoc : public SourceLocation { + const SourceManager *SrcMgr; +public: + /// Creates a FullSourceLoc where isValid() returns false. + explicit FullSourceLoc() : SrcMgr(0) {} + + explicit FullSourceLoc(SourceLocation Loc, const SourceManager &SM) + : SourceLocation(Loc), SrcMgr(&SM) {} + + const SourceManager &getManager() const { + assert(SrcMgr && "SourceManager is NULL."); + return *SrcMgr; + } + + FileID getFileID() const; + + FullSourceLoc getExpansionLoc() const; + FullSourceLoc getSpellingLoc() const; + + unsigned getExpansionLineNumber(bool *Invalid = 0) const; + unsigned getExpansionColumnNumber(bool *Invalid = 0) const; + + unsigned getSpellingLineNumber(bool *Invalid = 0) const; + unsigned getSpellingColumnNumber(bool *Invalid = 0) const; + + const char *getCharacterData(bool *Invalid = 0) const; + + const llvm::MemoryBuffer* getBuffer(bool *Invalid = 0) const; + + /// getBufferData - Return a StringRef to the source buffer data for the + /// specified FileID. + StringRef getBufferData(bool *Invalid = 0) const; + + /// getDecomposedLoc - Decompose the specified location into a raw FileID + + /// Offset pair. The first element is the FileID, the second is the + /// offset from the start of the buffer of the location. + std::pair<FileID, unsigned> getDecomposedLoc() const; + + bool isInSystemHeader() const; + + /// \brief Determines the order of 2 source locations in the translation unit. + /// + /// \returns true if this source location comes before 'Loc', false otherwise. + bool isBeforeInTranslationUnitThan(SourceLocation Loc) const; + + /// \brief Determines the order of 2 source locations in the translation unit. + /// + /// \returns true if this source location comes before 'Loc', false otherwise. + bool isBeforeInTranslationUnitThan(FullSourceLoc Loc) const { + assert(Loc.isValid()); + assert(SrcMgr == Loc.SrcMgr && "Loc comes from another SourceManager!"); + return isBeforeInTranslationUnitThan((SourceLocation)Loc); + } + + /// \brief Comparison function class, useful for sorting FullSourceLocs. + struct BeforeThanCompare : public std::binary_function<FullSourceLoc, + FullSourceLoc, bool> { + bool operator()(const FullSourceLoc& lhs, const FullSourceLoc& rhs) const { + return lhs.isBeforeInTranslationUnitThan(rhs); + } + }; + + /// Prints information about this FullSourceLoc to stderr. Useful for + /// debugging. + LLVM_ATTRIBUTE_USED void dump() const; + + friend inline bool + operator==(const FullSourceLoc &LHS, const FullSourceLoc &RHS) { + return LHS.getRawEncoding() == RHS.getRawEncoding() && + LHS.SrcMgr == RHS.SrcMgr; + } + + friend inline bool + operator!=(const FullSourceLoc &LHS, const FullSourceLoc &RHS) { + return !(LHS == RHS); + } + +}; + +/// PresumedLoc - This class represents an unpacked "presumed" location which +/// can be presented to the user. A 'presumed' location can be modified by +/// #line and GNU line marker directives and is always the expansion point of +/// a normal location. +/// +/// You can get a PresumedLoc from a SourceLocation with SourceManager. +class PresumedLoc { + const char *Filename; + unsigned Line, Col; + SourceLocation IncludeLoc; +public: + PresumedLoc() : Filename(0) {} + PresumedLoc(const char *FN, unsigned Ln, unsigned Co, SourceLocation IL) + : Filename(FN), Line(Ln), Col(Co), IncludeLoc(IL) { + } + + /// isInvalid - Return true if this object is invalid or uninitialized. This + /// occurs when created with invalid source locations or when walking off + /// the top of a #include stack. + bool isInvalid() const { return Filename == 0; } + bool isValid() const { return Filename != 0; } + + /// getFilename - Return the presumed filename of this location. This can be + /// affected by #line etc. + const char *getFilename() const { return Filename; } + + /// getLine - Return the presumed line number of this location. This can be + /// affected by #line etc. + unsigned getLine() const { return Line; } + + /// getColumn - Return the presumed column number of this location. This can + /// not be affected by #line, but is packaged here for convenience. + unsigned getColumn() const { return Col; } + + /// getIncludeLoc - Return the presumed include location of this location. + /// This can be affected by GNU linemarker directives. + SourceLocation getIncludeLoc() const { return IncludeLoc; } +}; + + +} // end namespace clang + +namespace llvm { + /// Define DenseMapInfo so that FileID's can be used as keys in DenseMap and + /// DenseSets. + template <> + struct DenseMapInfo<clang::FileID> { + static inline clang::FileID getEmptyKey() { + return clang::FileID(); + } + static inline clang::FileID getTombstoneKey() { + return clang::FileID::getSentinel(); + } + + static unsigned getHashValue(clang::FileID S) { + return S.getHashValue(); + } + + static bool isEqual(clang::FileID LHS, clang::FileID RHS) { + return LHS == RHS; + } + }; + + template <> + struct isPodLike<clang::SourceLocation> { static const bool value = true; }; + template <> + struct isPodLike<clang::FileID> { static const bool value = true; }; + + // Teach SmallPtrSet how to handle SourceLocation. + template<> + class PointerLikeTypeTraits<clang::SourceLocation> { + public: + static inline void *getAsVoidPointer(clang::SourceLocation L) { + return L.getPtrEncoding(); + } + static inline clang::SourceLocation getFromVoidPointer(void *P) { + return clang::SourceLocation::getFromRawEncoding((unsigned)(uintptr_t)P); + } + enum { NumLowBitsAvailable = 0 }; + }; + +} // end namespace llvm + +#endif diff --git a/clang/include/clang/Basic/SourceManager.h b/clang/include/clang/Basic/SourceManager.h new file mode 100644 index 0000000..bcb2d56 --- /dev/null +++ b/clang/include/clang/Basic/SourceManager.h @@ -0,0 +1,1402 @@ +//===--- SourceManager.h - Track and cache source files ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the SourceManager interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SOURCEMANAGER_H +#define LLVM_CLANG_SOURCEMANAGER_H + +#include "clang/Basic/LLVM.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/Support/MemoryBuffer.h" +#include <map> +#include <vector> +#include <cassert> + +namespace clang { + +class DiagnosticsEngine; +class SourceManager; +class FileManager; +class FileEntry; +class LineTableInfo; +class LangOptions; +class ASTWriter; +class ASTReader; + +/// There are three different types of locations in a file: a spelling +/// location, an expansion location, and a presumed location. +/// +/// Given an example of: +/// #define min(x, y) x < y ? x : y +/// +/// and then later on a use of min: +/// #line 17 +/// return min(a, b); +/// +/// The expansion location is the line in the source code where the macro +/// was expanded (the return statement), the spelling location is the +/// location in the source where the macro was originally defined, +/// and the presumed location is where the line directive states that +/// the line is 17, or any other line. + +/// SrcMgr - Public enums and private classes that are part of the +/// SourceManager implementation. +/// +namespace SrcMgr { + /// CharacteristicKind - This is used to represent whether a file or directory + /// holds normal user code, system code, or system code which is implicitly + /// 'extern "C"' in C++ mode. Entire directories can be tagged with this + /// (this is maintained by DirectoryLookup and friends) as can specific + /// FileInfos when a #pragma system_header is seen or various other cases. + /// + enum CharacteristicKind { + C_User, C_System, C_ExternCSystem + }; + + /// ContentCache - One instance of this struct is kept for every file + /// loaded or used. This object owns the MemoryBuffer object. + class ContentCache { + enum CCFlags { + /// \brief Whether the buffer is invalid. + InvalidFlag = 0x01, + /// \brief Whether the buffer should not be freed on destruction. + DoNotFreeFlag = 0x02 + }; + + /// Buffer - The actual buffer containing the characters from the input + /// file. This is owned by the ContentCache object. + /// The bits indicate indicates whether the buffer is invalid. + mutable llvm::PointerIntPair<const llvm::MemoryBuffer *, 2> Buffer; + + public: + /// Reference to the file entry representing this ContentCache. + /// This reference does not own the FileEntry object. + /// It is possible for this to be NULL if + /// the ContentCache encapsulates an imaginary text buffer. + const FileEntry *OrigEntry; + + /// \brief References the file which the contents were actually loaded from. + /// Can be different from 'Entry' if we overridden the contents of one file + /// with the contents of another file. + const FileEntry *ContentsEntry; + + /// SourceLineCache - A bump pointer allocated array of offsets for each + /// source line. This is lazily computed. This is owned by the + /// SourceManager BumpPointerAllocator object. + unsigned *SourceLineCache; + + /// NumLines - The number of lines in this ContentCache. This is only valid + /// if SourceLineCache is non-null. + unsigned NumLines : 31; + + /// \brief Indicates whether the buffer itself was provided to override + /// the actual file contents. + /// + /// When true, the original entry may be a virtual file that does not + /// exist. + unsigned BufferOverridden : 1; + + ContentCache(const FileEntry *Ent = 0) + : Buffer(0, false), OrigEntry(Ent), ContentsEntry(Ent), + SourceLineCache(0), NumLines(0), BufferOverridden(false) {} + + ContentCache(const FileEntry *Ent, const FileEntry *contentEnt) + : Buffer(0, false), OrigEntry(Ent), ContentsEntry(contentEnt), + SourceLineCache(0), NumLines(0), BufferOverridden(false) {} + + ~ContentCache(); + + /// The copy ctor does not allow copies where source object has either + /// a non-NULL Buffer or SourceLineCache. Ownership of allocated memory + /// is not transferred, so this is a logical error. + ContentCache(const ContentCache &RHS) + : Buffer(0, false), SourceLineCache(0), BufferOverridden(false) + { + OrigEntry = RHS.OrigEntry; + ContentsEntry = RHS.ContentsEntry; + + assert (RHS.Buffer.getPointer() == 0 && RHS.SourceLineCache == 0 && + "Passed ContentCache object cannot own a buffer."); + + NumLines = RHS.NumLines; + } + + /// getBuffer - Returns the memory buffer for the associated content. + /// + /// \param Diag Object through which diagnostics will be emitted if the + /// buffer cannot be retrieved. + /// + /// \param Loc If specified, is the location that invalid file diagnostics + /// will be emitted at. + /// + /// \param Invalid If non-NULL, will be set \c true if an error occurred. + const llvm::MemoryBuffer *getBuffer(DiagnosticsEngine &Diag, + const SourceManager &SM, + SourceLocation Loc = SourceLocation(), + bool *Invalid = 0) const; + + /// getSize - Returns the size of the content encapsulated by this + /// ContentCache. This can be the size of the source file or the size of an + /// arbitrary scratch buffer. If the ContentCache encapsulates a source + /// file this size is retrieved from the file's FileEntry. + unsigned getSize() const; + + /// getSizeBytesMapped - Returns the number of bytes actually mapped for + /// this ContentCache. This can be 0 if the MemBuffer was not actually + /// expanded. + unsigned getSizeBytesMapped() const; + + /// Returns the kind of memory used to back the memory buffer for + /// this content cache. This is used for performance analysis. + llvm::MemoryBuffer::BufferKind getMemoryBufferKind() const; + + void setBuffer(const llvm::MemoryBuffer *B) { + assert(!Buffer.getPointer() && "MemoryBuffer already set."); + Buffer.setPointer(B); + Buffer.setInt(false); + } + + /// \brief Get the underlying buffer, returning NULL if the buffer is not + /// yet available. + const llvm::MemoryBuffer *getRawBuffer() const { + return Buffer.getPointer(); + } + + /// \brief Replace the existing buffer (which will be deleted) + /// with the given buffer. + void replaceBuffer(const llvm::MemoryBuffer *B, bool DoNotFree = false); + + /// \brief Determine whether the buffer itself is invalid. + bool isBufferInvalid() const { + return Buffer.getInt() & InvalidFlag; + } + + /// \brief Determine whether the buffer should be freed. + bool shouldFreeBuffer() const { + return (Buffer.getInt() & DoNotFreeFlag) == 0; + } + + private: + // Disable assignments. + ContentCache &operator=(const ContentCache& RHS); + }; + + /// FileInfo - Information about a FileID, basically just the logical file + /// that it represents and include stack information. + /// + /// Each FileInfo has include stack information, indicating where it came + /// from. This information encodes the #include chain that a token was + /// expanded from. The main include file has an invalid IncludeLoc. + /// + /// FileInfos contain a "ContentCache *", with the contents of the file. + /// + class FileInfo { + /// IncludeLoc - The location of the #include that brought in this file. + /// This is an invalid SLOC for the main file (top of the #include chain). + unsigned IncludeLoc; // Really a SourceLocation + + /// \brief Number of FileIDs (files and macros) that were created during + /// preprocessing of this #include, including this SLocEntry. + /// Zero means the preprocessor didn't provide such info for this SLocEntry. + unsigned NumCreatedFIDs; + + /// Data - This contains the ContentCache* and the bits indicating the + /// characteristic of the file and whether it has #line info, all bitmangled + /// together. + uintptr_t Data; + + friend class clang::SourceManager; + friend class clang::ASTWriter; + friend class clang::ASTReader; + public: + /// get - Return a FileInfo object. + static FileInfo get(SourceLocation IL, const ContentCache *Con, + CharacteristicKind FileCharacter) { + FileInfo X; + X.IncludeLoc = IL.getRawEncoding(); + X.NumCreatedFIDs = 0; + X.Data = (uintptr_t)Con; + assert((X.Data & 7) == 0 &&"ContentCache pointer insufficiently aligned"); + assert((unsigned)FileCharacter < 4 && "invalid file character"); + X.Data |= (unsigned)FileCharacter; + return X; + } + + SourceLocation getIncludeLoc() const { + return SourceLocation::getFromRawEncoding(IncludeLoc); + } + const ContentCache* getContentCache() const { + return reinterpret_cast<const ContentCache*>(Data & ~7UL); + } + + /// getCharacteristic - Return whether this is a system header or not. + CharacteristicKind getFileCharacteristic() const { + return (CharacteristicKind)(Data & 3); + } + + /// hasLineDirectives - Return true if this FileID has #line directives in + /// it. + bool hasLineDirectives() const { return (Data & 4) != 0; } + + /// setHasLineDirectives - Set the flag that indicates that this FileID has + /// line table entries associated with it. + void setHasLineDirectives() { + Data |= 4; + } + }; + + /// ExpansionInfo - Each ExpansionInfo encodes the expansion location - where + /// the token was ultimately expanded, and the SpellingLoc - where the actual + /// character data for the token came from. + class ExpansionInfo { + // Really these are all SourceLocations. + + /// SpellingLoc - Where the spelling for the token can be found. + unsigned SpellingLoc; + + /// ExpansionLocStart/ExpansionLocEnd - In a macro expansion, these + /// indicate the start and end of the expansion. In object-like macros, + /// these will be the same. In a function-like macro expansion, the start + /// will be the identifier and the end will be the ')'. Finally, in + /// macro-argument instantitions, the end will be 'SourceLocation()', an + /// invalid location. + unsigned ExpansionLocStart, ExpansionLocEnd; + + public: + SourceLocation getSpellingLoc() const { + return SourceLocation::getFromRawEncoding(SpellingLoc); + } + SourceLocation getExpansionLocStart() const { + return SourceLocation::getFromRawEncoding(ExpansionLocStart); + } + SourceLocation getExpansionLocEnd() const { + SourceLocation EndLoc = + SourceLocation::getFromRawEncoding(ExpansionLocEnd); + return EndLoc.isInvalid() ? getExpansionLocStart() : EndLoc; + } + + std::pair<SourceLocation,SourceLocation> getExpansionLocRange() const { + return std::make_pair(getExpansionLocStart(), getExpansionLocEnd()); + } + + bool isMacroArgExpansion() const { + // Note that this needs to return false for default constructed objects. + return getExpansionLocStart().isValid() && + SourceLocation::getFromRawEncoding(ExpansionLocEnd).isInvalid(); + } + + bool isFunctionMacroExpansion() const { + return getExpansionLocStart().isValid() && + getExpansionLocStart() != getExpansionLocEnd(); + } + + /// create - Return a ExpansionInfo for an expansion. Start and End specify + /// the expansion range (where the macro is expanded), and SpellingLoc + /// specifies the spelling location (where the characters from the token + /// come from). All three can refer to normal File SLocs or expansion + /// locations. + static ExpansionInfo create(SourceLocation SpellingLoc, + SourceLocation Start, SourceLocation End) { + ExpansionInfo X; + X.SpellingLoc = SpellingLoc.getRawEncoding(); + X.ExpansionLocStart = Start.getRawEncoding(); + X.ExpansionLocEnd = End.getRawEncoding(); + return X; + } + + /// createForMacroArg - Return a special ExpansionInfo for the expansion of + /// a macro argument into a function-like macro's body. ExpansionLoc + /// specifies the expansion location (where the macro is expanded). This + /// doesn't need to be a range because a macro is always expanded at + /// a macro parameter reference, and macro parameters are always exactly + /// one token. SpellingLoc specifies the spelling location (where the + /// characters from the token come from). ExpansionLoc and SpellingLoc can + /// both refer to normal File SLocs or expansion locations. + /// + /// Given the code: + /// \code + /// #define F(x) f(x) + /// F(42); + /// \endcode + /// + /// When expanding '\c F(42)', the '\c x' would call this with an + /// SpellingLoc pointing at '\c 42' anad an ExpansionLoc pointing at its + /// location in the definition of '\c F'. + static ExpansionInfo createForMacroArg(SourceLocation SpellingLoc, + SourceLocation ExpansionLoc) { + // We store an intentionally invalid source location for the end of the + // expansion range to mark that this is a macro argument ion rather than + // a normal one. + return create(SpellingLoc, ExpansionLoc, SourceLocation()); + } + }; + + /// SLocEntry - This is a discriminated union of FileInfo and + /// ExpansionInfo. SourceManager keeps an array of these objects, and + /// they are uniquely identified by the FileID datatype. + class SLocEntry { + unsigned Offset; // low bit is set for expansion info. + union { + FileInfo File; + ExpansionInfo Expansion; + }; + public: + unsigned getOffset() const { return Offset >> 1; } + + bool isExpansion() const { return Offset & 1; } + bool isFile() const { return !isExpansion(); } + + const FileInfo &getFile() const { + assert(isFile() && "Not a file SLocEntry!"); + return File; + } + + const ExpansionInfo &getExpansion() const { + assert(isExpansion() && "Not a macro expansion SLocEntry!"); + return Expansion; + } + + static SLocEntry get(unsigned Offset, const FileInfo &FI) { + SLocEntry E; + E.Offset = Offset << 1; + E.File = FI; + return E; + } + + static SLocEntry get(unsigned Offset, const ExpansionInfo &Expansion) { + SLocEntry E; + E.Offset = (Offset << 1) | 1; + E.Expansion = Expansion; + return E; + } + }; +} // end SrcMgr namespace. + +/// \brief External source of source location entries. +class ExternalSLocEntrySource { +public: + virtual ~ExternalSLocEntrySource(); + + /// \brief Read the source location entry with index ID, which will always be + /// less than -1. + /// + /// \returns true if an error occurred that prevented the source-location + /// entry from being loaded. + virtual bool ReadSLocEntry(int ID) = 0; +}; + + +/// IsBeforeInTranslationUnitCache - This class holds the cache used by +/// isBeforeInTranslationUnit. The cache structure is complex enough to be +/// worth breaking out of SourceManager. +class IsBeforeInTranslationUnitCache { + /// L/R QueryFID - These are the FID's of the cached query. If these match up + /// with a subsequent query, the result can be reused. + FileID LQueryFID, RQueryFID; + + /// \brief True if LQueryFID was created before RQueryFID. This is used + /// to compare macro expansion locations. + bool IsLQFIDBeforeRQFID; + + /// CommonFID - This is the file found in common between the two #include + /// traces. It is the nearest common ancestor of the #include tree. + FileID CommonFID; + + /// L/R CommonOffset - This is the offset of the previous query in CommonFID. + /// Usually, this represents the location of the #include for QueryFID, but if + /// LQueryFID is a parent of RQueryFID (or vise versa) then these can be a + /// random token in the parent. + unsigned LCommonOffset, RCommonOffset; +public: + + /// isCacheValid - Return true if the currently cached values match up with + /// the specified LHS/RHS query. If not, we can't use the cache. + bool isCacheValid(FileID LHS, FileID RHS) const { + return LQueryFID == LHS && RQueryFID == RHS; + } + + /// getCachedResult - If the cache is valid, compute the result given the + /// specified offsets in the LHS/RHS FID's. + bool getCachedResult(unsigned LOffset, unsigned ROffset) const { + // If one of the query files is the common file, use the offset. Otherwise, + // use the #include loc in the common file. + if (LQueryFID != CommonFID) LOffset = LCommonOffset; + if (RQueryFID != CommonFID) ROffset = RCommonOffset; + + // It is common for multiple macro expansions to be "included" from the same + // location (expansion location), in which case use the order of the FileIDs + // to determine which came first. This will also take care the case where + // one of the locations points at the inclusion/expansion point of the other + // in which case its FileID will come before the other. + if (LOffset == ROffset) + return IsLQFIDBeforeRQFID; + + return LOffset < ROffset; + } + + // Set up a new query. + void setQueryFIDs(FileID LHS, FileID RHS, bool isLFIDBeforeRFID) { + assert(LHS != RHS); + LQueryFID = LHS; + RQueryFID = RHS; + IsLQFIDBeforeRQFID = isLFIDBeforeRFID; + } + + void clear() { + LQueryFID = RQueryFID = FileID(); + IsLQFIDBeforeRQFID = false; + } + + void setCommonLoc(FileID commonFID, unsigned lCommonOffset, + unsigned rCommonOffset) { + CommonFID = commonFID; + LCommonOffset = lCommonOffset; + RCommonOffset = rCommonOffset; + } + +}; + +/// \brief This class handles loading and caching of source files into memory. +/// +/// This object owns the MemoryBuffer objects for all of the loaded +/// files and assigns unique FileID's for each unique #include chain. +/// +/// The SourceManager can be queried for information about SourceLocation +/// objects, turning them into either spelling or expansion locations. Spelling +/// locations represent where the bytes corresponding to a token came from and +/// expansion locations represent where the location is in the user's view. In +/// the case of a macro expansion, for example, the spelling location indicates +/// where the expanded token came from and the expansion location specifies +/// where it was expanded. +class SourceManager : public RefCountedBase<SourceManager> { + /// \brief DiagnosticsEngine object. + DiagnosticsEngine &Diag; + + FileManager &FileMgr; + + mutable llvm::BumpPtrAllocator ContentCacheAlloc; + + /// FileInfos - Memoized information about all of the files tracked by this + /// SourceManager. This set allows us to merge ContentCache entries based + /// on their FileEntry*. All ContentCache objects will thus have unique, + /// non-null, FileEntry pointers. + llvm::DenseMap<const FileEntry*, SrcMgr::ContentCache*> FileInfos; + + /// \brief True if the ContentCache for files that are overriden by other + /// files, should report the original file name. Defaults to true. + bool OverridenFilesKeepOriginalName; + + /// \brief Files that have been overriden with the contents from another file. + llvm::DenseMap<const FileEntry *, const FileEntry *> OverriddenFiles; + + /// MemBufferInfos - Information about various memory buffers that we have + /// read in. All FileEntry* within the stored ContentCache objects are NULL, + /// as they do not refer to a file. + std::vector<SrcMgr::ContentCache*> MemBufferInfos; + + /// \brief The table of SLocEntries that are local to this module. + /// + /// Positive FileIDs are indexes into this table. Entry 0 indicates an invalid + /// expansion. + std::vector<SrcMgr::SLocEntry> LocalSLocEntryTable; + + /// \brief The table of SLocEntries that are loaded from other modules. + /// + /// Negative FileIDs are indexes into this table. To get from ID to an index, + /// use (-ID - 2). + mutable std::vector<SrcMgr::SLocEntry> LoadedSLocEntryTable; + + /// \brief The starting offset of the next local SLocEntry. + /// + /// This is LocalSLocEntryTable.back().Offset + the size of that entry. + unsigned NextLocalOffset; + + /// \brief The starting offset of the latest batch of loaded SLocEntries. + /// + /// This is LoadedSLocEntryTable.back().Offset, except that that entry might + /// not have been loaded, so that value would be unknown. + unsigned CurrentLoadedOffset; + + /// \brief The highest possible offset is 2^31-1, so CurrentLoadedOffset + /// starts at 2^31. + static const unsigned MaxLoadedOffset = 1U << 31U; + + /// \brief A bitmap that indicates whether the entries of LoadedSLocEntryTable + /// have already been loaded from the external source. + /// + /// Same indexing as LoadedSLocEntryTable. + std::vector<bool> SLocEntryLoaded; + + /// \brief An external source for source location entries. + ExternalSLocEntrySource *ExternalSLocEntries; + + /// LastFileIDLookup - This is a one-entry cache to speed up getFileID. + /// LastFileIDLookup records the last FileID looked up or created, because it + /// is very common to look up many tokens from the same file. + mutable FileID LastFileIDLookup; + + /// LineTable - This holds information for #line directives. It is referenced + /// by indices from SLocEntryTable. + LineTableInfo *LineTable; + + /// LastLineNo - These ivars serve as a cache used in the getLineNumber + /// method which is used to speedup getLineNumber calls to nearby locations. + mutable FileID LastLineNoFileIDQuery; + mutable SrcMgr::ContentCache *LastLineNoContentCache; + mutable unsigned LastLineNoFilePos; + mutable unsigned LastLineNoResult; + + /// MainFileID - The file ID for the main source file of the translation unit. + FileID MainFileID; + + /// \brief The file ID for the precompiled preamble there is one. + FileID PreambleFileID; + + // Statistics for -print-stats. + mutable unsigned NumLinearScans, NumBinaryProbes; + + // Cache results for the isBeforeInTranslationUnit method. + mutable IsBeforeInTranslationUnitCache IsBeforeInTUCache; + + // Cache for the "fake" buffer used for error-recovery purposes. + mutable llvm::MemoryBuffer *FakeBufferForRecovery; + + mutable SrcMgr::ContentCache *FakeContentCacheForRecovery; + + /// \brief Lazily computed map of macro argument chunks to their expanded + /// source location. + typedef std::map<unsigned, SourceLocation> MacroArgsMap; + + mutable llvm::DenseMap<FileID, MacroArgsMap *> MacroArgsCacheMap; + + // SourceManager doesn't support copy construction. + explicit SourceManager(const SourceManager&); + void operator=(const SourceManager&); +public: + SourceManager(DiagnosticsEngine &Diag, FileManager &FileMgr); + ~SourceManager(); + + void clearIDTables(); + + DiagnosticsEngine &getDiagnostics() const { return Diag; } + + FileManager &getFileManager() const { return FileMgr; } + + /// \brief Set true if the SourceManager should report the original file name + /// for contents of files that were overriden by other files.Defaults to true. + void setOverridenFilesKeepOriginalName(bool value) { + OverridenFilesKeepOriginalName = value; + } + + /// createMainFileIDForMembuffer - Create the FileID for a memory buffer + /// that will represent the FileID for the main source. One example + /// of when this would be used is when the main source is read from STDIN. + FileID createMainFileIDForMemBuffer(const llvm::MemoryBuffer *Buffer) { + assert(MainFileID.isInvalid() && "MainFileID already set!"); + MainFileID = createFileIDForMemBuffer(Buffer); + return MainFileID; + } + + //===--------------------------------------------------------------------===// + // MainFileID creation and querying methods. + //===--------------------------------------------------------------------===// + + /// getMainFileID - Returns the FileID of the main source file. + FileID getMainFileID() const { return MainFileID; } + + /// createMainFileID - Create the FileID for the main source file. + FileID createMainFileID(const FileEntry *SourceFile, + SrcMgr::CharacteristicKind Kind = SrcMgr::C_User) { + assert(MainFileID.isInvalid() && "MainFileID already set!"); + MainFileID = createFileID(SourceFile, SourceLocation(), Kind); + return MainFileID; + } + + /// \brief Set the file ID for the main source file. + void setMainFileID(FileID FID) { + assert(MainFileID.isInvalid() && "MainFileID already set!"); + MainFileID = FID; + } + + /// \brief Set the file ID for the precompiled preamble. + void setPreambleFileID(FileID Preamble) { + assert(PreambleFileID.isInvalid() && "PreambleFileID already set!"); + PreambleFileID = Preamble; + } + + /// \brief Get the file ID for the precompiled preamble if there is one. + FileID getPreambleFileID() const { return PreambleFileID; } + + //===--------------------------------------------------------------------===// + // Methods to create new FileID's and macro expansions. + //===--------------------------------------------------------------------===// + + /// createFileID - Create a new FileID that represents the specified file + /// being #included from the specified IncludePosition. This translates NULL + /// into standard input. + FileID createFileID(const FileEntry *SourceFile, SourceLocation IncludePos, + SrcMgr::CharacteristicKind FileCharacter, + int LoadedID = 0, unsigned LoadedOffset = 0) { + const SrcMgr::ContentCache *IR = getOrCreateContentCache(SourceFile); + assert(IR && "getOrCreateContentCache() cannot return NULL"); + return createFileID(IR, IncludePos, FileCharacter, LoadedID, LoadedOffset); + } + + /// createFileIDForMemBuffer - Create a new FileID that represents the + /// specified memory buffer. This does no caching of the buffer and takes + /// ownership of the MemoryBuffer, so only pass a MemoryBuffer to this once. + FileID createFileIDForMemBuffer(const llvm::MemoryBuffer *Buffer, + int LoadedID = 0, unsigned LoadedOffset = 0, + SourceLocation IncludeLoc = SourceLocation()) { + return createFileID(createMemBufferContentCache(Buffer), IncludeLoc, + SrcMgr::C_User, LoadedID, LoadedOffset); + } + + /// createMacroArgExpansionLoc - Return a new SourceLocation that encodes the + /// fact that a token from SpellingLoc should actually be referenced from + /// ExpansionLoc, and that it represents the expansion of a macro argument + /// into the function-like macro body. + SourceLocation createMacroArgExpansionLoc(SourceLocation Loc, + SourceLocation ExpansionLoc, + unsigned TokLength); + + /// createExpansionLoc - Return a new SourceLocation that encodes the fact + /// that a token from SpellingLoc should actually be referenced from + /// ExpansionLoc. + SourceLocation createExpansionLoc(SourceLocation Loc, + SourceLocation ExpansionLocStart, + SourceLocation ExpansionLocEnd, + unsigned TokLength, + int LoadedID = 0, + unsigned LoadedOffset = 0); + + /// \brief Retrieve the memory buffer associated with the given file. + /// + /// \param Invalid If non-NULL, will be set \c true if an error + /// occurs while retrieving the memory buffer. + const llvm::MemoryBuffer *getMemoryBufferForFile(const FileEntry *File, + bool *Invalid = 0); + + /// \brief Override the contents of the given source file by providing an + /// already-allocated buffer. + /// + /// \param SourceFile the source file whose contents will be overriden. + /// + /// \param Buffer the memory buffer whose contents will be used as the + /// data in the given source file. + /// + /// \param DoNotFree If true, then the buffer will not be freed when the + /// source manager is destroyed. + void overrideFileContents(const FileEntry *SourceFile, + const llvm::MemoryBuffer *Buffer, + bool DoNotFree = false); + + /// \brief Override the the given source file with another one. + /// + /// \param SourceFile the source file which will be overriden. + /// + /// \param NewFile the file whose contents will be used as the + /// data instead of the contents of the given source file. + void overrideFileContents(const FileEntry *SourceFile, + const FileEntry *NewFile); + + //===--------------------------------------------------------------------===// + // FileID manipulation methods. + //===--------------------------------------------------------------------===// + + /// getBuffer - Return the buffer for the specified FileID. If there is an + /// error opening this buffer the first time, this manufactures a temporary + /// buffer and returns a non-empty error string. + const llvm::MemoryBuffer *getBuffer(FileID FID, SourceLocation Loc, + bool *Invalid = 0) const { + bool MyInvalid = false; + const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &MyInvalid); + if (MyInvalid || !Entry.isFile()) { + if (Invalid) + *Invalid = true; + + return getFakeBufferForRecovery(); + } + + return Entry.getFile().getContentCache()->getBuffer(Diag, *this, Loc, + Invalid); + } + + const llvm::MemoryBuffer *getBuffer(FileID FID, bool *Invalid = 0) const { + bool MyInvalid = false; + const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &MyInvalid); + if (MyInvalid || !Entry.isFile()) { + if (Invalid) + *Invalid = true; + + return getFakeBufferForRecovery(); + } + + return Entry.getFile().getContentCache()->getBuffer(Diag, *this, + SourceLocation(), + Invalid); + } + + /// getFileEntryForID - Returns the FileEntry record for the provided FileID. + const FileEntry *getFileEntryForID(FileID FID) const { + bool MyInvalid = false; + const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &MyInvalid); + if (MyInvalid || !Entry.isFile()) + return 0; + + const SrcMgr::ContentCache *Content = Entry.getFile().getContentCache(); + if (!Content) + return 0; + return Content->OrigEntry; + } + + /// Returns the FileEntry record for the provided SLocEntry. + const FileEntry *getFileEntryForSLocEntry(const SrcMgr::SLocEntry &sloc) const + { + const SrcMgr::ContentCache *Content = sloc.getFile().getContentCache(); + if (!Content) + return 0; + return Content->OrigEntry; + } + + /// getBufferData - Return a StringRef to the source buffer data for the + /// specified FileID. + /// + /// \param FID The file ID whose contents will be returned. + /// \param Invalid If non-NULL, will be set true if an error occurred. + StringRef getBufferData(FileID FID, bool *Invalid = 0) const; + + /// \brief Get the number of FileIDs (files and macros) that were created + /// during preprocessing of \p FID, including it. + unsigned getNumCreatedFIDsForFileID(FileID FID) const { + bool Invalid = false; + const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &Invalid); + if (Invalid || !Entry.isFile()) + return 0; + + return Entry.getFile().NumCreatedFIDs; + } + + /// \brief Set the number of FileIDs (files and macros) that were created + /// during preprocessing of \p FID, including it. + void setNumCreatedFIDsForFileID(FileID FID, unsigned NumFIDs) const { + bool Invalid = false; + const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &Invalid); + if (Invalid || !Entry.isFile()) + return; + + assert(Entry.getFile().NumCreatedFIDs == 0 && "Already set!"); + const_cast<SrcMgr::FileInfo &>(Entry.getFile()).NumCreatedFIDs = NumFIDs; + } + + //===--------------------------------------------------------------------===// + // SourceLocation manipulation methods. + //===--------------------------------------------------------------------===// + + /// getFileID - Return the FileID for a SourceLocation. This is a very + /// hot method that is used for all SourceManager queries that start with a + /// SourceLocation object. It is responsible for finding the entry in + /// SLocEntryTable which contains the specified location. + /// + FileID getFileID(SourceLocation SpellingLoc) const { + unsigned SLocOffset = SpellingLoc.getOffset(); + + // If our one-entry cache covers this offset, just return it. + if (isOffsetInFileID(LastFileIDLookup, SLocOffset)) + return LastFileIDLookup; + + return getFileIDSlow(SLocOffset); + } + + /// getLocForStartOfFile - Return the source location corresponding to the + /// first byte of the specified file. + SourceLocation getLocForStartOfFile(FileID FID) const { + bool Invalid = false; + const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &Invalid); + if (Invalid || !Entry.isFile()) + return SourceLocation(); + + unsigned FileOffset = Entry.getOffset(); + return SourceLocation::getFileLoc(FileOffset); + } + + /// \brief Return the source location corresponding to the last byte of the + /// specified file. + SourceLocation getLocForEndOfFile(FileID FID) const { + bool Invalid = false; + const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &Invalid); + if (Invalid || !Entry.isFile()) + return SourceLocation(); + + unsigned FileOffset = Entry.getOffset(); + return SourceLocation::getFileLoc(FileOffset + getFileIDSize(FID) - 1); + } + + /// \brief Returns the include location if \p FID is a #include'd file + /// otherwise it returns an invalid location. + SourceLocation getIncludeLoc(FileID FID) const { + bool Invalid = false; + const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &Invalid); + if (Invalid || !Entry.isFile()) + return SourceLocation(); + + return Entry.getFile().getIncludeLoc(); + } + + /// getExpansionLoc - Given a SourceLocation object, return the expansion + /// location referenced by the ID. + SourceLocation getExpansionLoc(SourceLocation Loc) const { + // Handle the non-mapped case inline, defer to out of line code to handle + // expansions. + if (Loc.isFileID()) return Loc; + return getExpansionLocSlowCase(Loc); + } + + /// \brief Given \p Loc, if it is a macro location return the expansion + /// location or the spelling location, depending on if it comes from a + /// macro argument or not. + SourceLocation getFileLoc(SourceLocation Loc) const { + if (Loc.isFileID()) return Loc; + return getFileLocSlowCase(Loc); + } + + /// getImmediateExpansionRange - Loc is required to be an expansion location. + /// Return the start/end of the expansion information. + std::pair<SourceLocation,SourceLocation> + getImmediateExpansionRange(SourceLocation Loc) const; + + /// getExpansionRange - Given a SourceLocation object, return the range of + /// tokens covered by the expansion the ultimate file. + std::pair<SourceLocation,SourceLocation> + getExpansionRange(SourceLocation Loc) const; + + + /// getSpellingLoc - Given a SourceLocation object, return the spelling + /// location referenced by the ID. This is the place where the characters + /// that make up the lexed token can be found. + SourceLocation getSpellingLoc(SourceLocation Loc) const { + // Handle the non-mapped case inline, defer to out of line code to handle + // expansions. + if (Loc.isFileID()) return Loc; + return getSpellingLocSlowCase(Loc); + } + + /// getImmediateSpellingLoc - Given a SourceLocation object, return the + /// spelling location referenced by the ID. This is the first level down + /// towards the place where the characters that make up the lexed token can be + /// found. This should not generally be used by clients. + SourceLocation getImmediateSpellingLoc(SourceLocation Loc) const; + + /// getDecomposedLoc - Decompose the specified location into a raw FileID + + /// Offset pair. The first element is the FileID, the second is the + /// offset from the start of the buffer of the location. + std::pair<FileID, unsigned> getDecomposedLoc(SourceLocation Loc) const { + FileID FID = getFileID(Loc); + bool Invalid = false; + const SrcMgr::SLocEntry &E = getSLocEntry(FID, &Invalid); + if (Invalid) + return std::make_pair(FileID(), 0); + return std::make_pair(FID, Loc.getOffset()-E.getOffset()); + } + + /// getDecomposedExpansionLoc - Decompose the specified location into a raw + /// FileID + Offset pair. If the location is an expansion record, walk + /// through it until we find the final location expanded. + std::pair<FileID, unsigned> + getDecomposedExpansionLoc(SourceLocation Loc) const { + FileID FID = getFileID(Loc); + bool Invalid = false; + const SrcMgr::SLocEntry *E = &getSLocEntry(FID, &Invalid); + if (Invalid) + return std::make_pair(FileID(), 0); + + unsigned Offset = Loc.getOffset()-E->getOffset(); + if (Loc.isFileID()) + return std::make_pair(FID, Offset); + + return getDecomposedExpansionLocSlowCase(E); + } + + /// getDecomposedSpellingLoc - Decompose the specified location into a raw + /// FileID + Offset pair. If the location is an expansion record, walk + /// through it until we find its spelling record. + std::pair<FileID, unsigned> + getDecomposedSpellingLoc(SourceLocation Loc) const { + FileID FID = getFileID(Loc); + bool Invalid = false; + const SrcMgr::SLocEntry *E = &getSLocEntry(FID, &Invalid); + if (Invalid) + return std::make_pair(FileID(), 0); + + unsigned Offset = Loc.getOffset()-E->getOffset(); + if (Loc.isFileID()) + return std::make_pair(FID, Offset); + return getDecomposedSpellingLocSlowCase(E, Offset); + } + + /// getFileOffset - This method returns the offset from the start + /// of the file that the specified SourceLocation represents. This is not very + /// meaningful for a macro ID. + unsigned getFileOffset(SourceLocation SpellingLoc) const { + return getDecomposedLoc(SpellingLoc).second; + } + + /// isMacroArgExpansion - This method tests whether the given source location + /// represents a macro argument's expansion into the function-like macro + /// definition. Such source locations only appear inside of the expansion + /// locations representing where a particular function-like macro was + /// expanded. + bool isMacroArgExpansion(SourceLocation Loc) const; + + /// \brief Returns true if \p Loc is inside the [\p Start, +\p Length) + /// chunk of the source location address space. + /// If it's true and \p RelativeOffset is non-null, it will be set to the + /// relative offset of \p Loc inside the chunk. + bool isInSLocAddrSpace(SourceLocation Loc, + SourceLocation Start, unsigned Length, + unsigned *RelativeOffset = 0) const { + assert(((Start.getOffset() < NextLocalOffset && + Start.getOffset()+Length <= NextLocalOffset) || + (Start.getOffset() >= CurrentLoadedOffset && + Start.getOffset()+Length < MaxLoadedOffset)) && + "Chunk is not valid SLoc address space"); + unsigned LocOffs = Loc.getOffset(); + unsigned BeginOffs = Start.getOffset(); + unsigned EndOffs = BeginOffs + Length; + if (LocOffs >= BeginOffs && LocOffs < EndOffs) { + if (RelativeOffset) + *RelativeOffset = LocOffs - BeginOffs; + return true; + } + + return false; + } + + /// \brief Return true if both \p LHS and \p RHS are in the local source + /// location address space or the loaded one. If it's true and \p + /// RelativeOffset is non-null, it will be set to the offset of \p RHS + /// relative to \p LHS. + bool isInSameSLocAddrSpace(SourceLocation LHS, SourceLocation RHS, + int *RelativeOffset) const { + unsigned LHSOffs = LHS.getOffset(), RHSOffs = RHS.getOffset(); + bool LHSLoaded = LHSOffs >= CurrentLoadedOffset; + bool RHSLoaded = RHSOffs >= CurrentLoadedOffset; + + if (LHSLoaded == RHSLoaded) { + if (RelativeOffset) + *RelativeOffset = RHSOffs - LHSOffs; + return true; + } + + return false; + } + + //===--------------------------------------------------------------------===// + // Queries about the code at a SourceLocation. + //===--------------------------------------------------------------------===// + + /// getCharacterData - Return a pointer to the start of the specified location + /// in the appropriate spelling MemoryBuffer. + /// + /// \param Invalid If non-NULL, will be set \c true if an error occurs. + const char *getCharacterData(SourceLocation SL, bool *Invalid = 0) const; + + /// getColumnNumber - Return the column # for the specified file position. + /// This is significantly cheaper to compute than the line number. This + /// returns zero if the column number isn't known. This may only be called + /// on a file sloc, so you must choose a spelling or expansion location + /// before calling this method. + unsigned getColumnNumber(FileID FID, unsigned FilePos, + bool *Invalid = 0) const; + unsigned getSpellingColumnNumber(SourceLocation Loc, bool *Invalid = 0) const; + unsigned getExpansionColumnNumber(SourceLocation Loc, + bool *Invalid = 0) const; + unsigned getPresumedColumnNumber(SourceLocation Loc, bool *Invalid = 0) const; + + + /// getLineNumber - Given a SourceLocation, return the spelling line number + /// for the position indicated. This requires building and caching a table of + /// line offsets for the MemoryBuffer, so this is not cheap: use only when + /// about to emit a diagnostic. + unsigned getLineNumber(FileID FID, unsigned FilePos, bool *Invalid = 0) const; + unsigned getSpellingLineNumber(SourceLocation Loc, bool *Invalid = 0) const; + unsigned getExpansionLineNumber(SourceLocation Loc, bool *Invalid = 0) const; + unsigned getPresumedLineNumber(SourceLocation Loc, bool *Invalid = 0) const; + + /// Return the filename or buffer identifier of the buffer the location is in. + /// Note that this name does not respect #line directives. Use getPresumedLoc + /// for normal clients. + const char *getBufferName(SourceLocation Loc, bool *Invalid = 0) const; + + /// getFileCharacteristic - return the file characteristic of the specified + /// source location, indicating whether this is a normal file, a system + /// header, or an "implicit extern C" system header. + /// + /// This state can be modified with flags on GNU linemarker directives like: + /// # 4 "foo.h" 3 + /// which changes all source locations in the current file after that to be + /// considered to be from a system header. + SrcMgr::CharacteristicKind getFileCharacteristic(SourceLocation Loc) const; + + /// getPresumedLoc - This method returns the "presumed" location of a + /// SourceLocation specifies. A "presumed location" can be modified by #line + /// or GNU line marker directives. This provides a view on the data that a + /// user should see in diagnostics, for example. + /// + /// Note that a presumed location is always given as the expansion point of + /// an expansion location, not at the spelling location. + /// + /// \returns The presumed location of the specified SourceLocation. If the + /// presumed location cannot be calculate (e.g., because \p Loc is invalid + /// or the file containing \p Loc has changed on disk), returns an invalid + /// presumed location. + PresumedLoc getPresumedLoc(SourceLocation Loc) const; + + /// isFromSameFile - Returns true if both SourceLocations correspond to + /// the same file. + bool isFromSameFile(SourceLocation Loc1, SourceLocation Loc2) const { + return getFileID(Loc1) == getFileID(Loc2); + } + + /// isFromMainFile - Returns true if the file of provided SourceLocation is + /// the main file. + bool isFromMainFile(SourceLocation Loc) const { + return getFileID(Loc) == getMainFileID(); + } + + /// isInSystemHeader - Returns if a SourceLocation is in a system header. + bool isInSystemHeader(SourceLocation Loc) const { + return getFileCharacteristic(Loc) != SrcMgr::C_User; + } + + /// isInExternCSystemHeader - Returns if a SourceLocation is in an "extern C" + /// system header. + bool isInExternCSystemHeader(SourceLocation Loc) const { + return getFileCharacteristic(Loc) == SrcMgr::C_ExternCSystem; + } + + /// \brief Returns whether \p Loc is expanded from a macro in a system header. + bool isInSystemMacro(SourceLocation loc) { + return loc.isMacroID() && isInSystemHeader(getSpellingLoc(loc)); + } + + /// \brief The size of the SLocEnty that \p FID represents. + unsigned getFileIDSize(FileID FID) const; + + /// \brief Given a specific FileID, returns true if \p Loc is inside that + /// FileID chunk and sets relative offset (offset of \p Loc from beginning + /// of FileID) to \p relativeOffset. + bool isInFileID(SourceLocation Loc, FileID FID, + unsigned *RelativeOffset = 0) const { + unsigned Offs = Loc.getOffset(); + if (isOffsetInFileID(FID, Offs)) { + if (RelativeOffset) + *RelativeOffset = Offs - getSLocEntry(FID).getOffset(); + return true; + } + + return false; + } + + //===--------------------------------------------------------------------===// + // Line Table Manipulation Routines + //===--------------------------------------------------------------------===// + + /// getLineTableFilenameID - Return the uniqued ID for the specified filename. + /// + unsigned getLineTableFilenameID(StringRef Str); + + /// AddLineNote - Add a line note to the line table for the FileID and offset + /// specified by Loc. If FilenameID is -1, it is considered to be + /// unspecified. + void AddLineNote(SourceLocation Loc, unsigned LineNo, int FilenameID); + void AddLineNote(SourceLocation Loc, unsigned LineNo, int FilenameID, + bool IsFileEntry, bool IsFileExit, + bool IsSystemHeader, bool IsExternCHeader); + + /// \brief Determine if the source manager has a line table. + bool hasLineTable() const { return LineTable != 0; } + + /// \brief Retrieve the stored line table. + LineTableInfo &getLineTable(); + + //===--------------------------------------------------------------------===// + // Queries for performance analysis. + //===--------------------------------------------------------------------===// + + /// Return the total amount of physical memory allocated by the + /// ContentCache allocator. + size_t getContentCacheSize() const { + return ContentCacheAlloc.getTotalMemory(); + } + + struct MemoryBufferSizes { + const size_t malloc_bytes; + const size_t mmap_bytes; + + MemoryBufferSizes(size_t malloc_bytes, size_t mmap_bytes) + : malloc_bytes(malloc_bytes), mmap_bytes(mmap_bytes) {} + }; + + /// Return the amount of memory used by memory buffers, breaking down + /// by heap-backed versus mmap'ed memory. + MemoryBufferSizes getMemoryBufferSizes() const; + + // Return the amount of memory used for various side tables and + // data structures in the SourceManager. + size_t getDataStructureSizes() const; + + //===--------------------------------------------------------------------===// + // Other miscellaneous methods. + //===--------------------------------------------------------------------===// + + /// \brief Get the source location for the given file:line:col triplet. + /// + /// If the source file is included multiple times, the source location will + /// be based upon the first inclusion. + SourceLocation translateFileLineCol(const FileEntry *SourceFile, + unsigned Line, unsigned Col) const; + + /// \brief Get the FileID for the given file. + /// + /// If the source file is included multiple times, the FileID will be the + /// first inclusion. + FileID translateFile(const FileEntry *SourceFile) const; + + /// \brief Get the source location in \p FID for the given line:col. + /// Returns null location if \p FID is not a file SLocEntry. + SourceLocation translateLineCol(FileID FID, + unsigned Line, unsigned Col) const; + + /// \brief If \p Loc points inside a function macro argument, the returned + /// location will be the macro location in which the argument was expanded. + /// If a macro argument is used multiple times, the expanded location will + /// be at the first expansion of the argument. + /// e.g. + /// MY_MACRO(foo); + /// ^ + /// Passing a file location pointing at 'foo', will yield a macro location + /// where 'foo' was expanded into. + SourceLocation getMacroArgExpandedLocation(SourceLocation Loc) const; + + /// \brief Determines the order of 2 source locations in the translation unit. + /// + /// \returns true if LHS source location comes before RHS, false otherwise. + bool isBeforeInTranslationUnit(SourceLocation LHS, SourceLocation RHS) const; + + /// \brief Comparison function class. + class LocBeforeThanCompare : public std::binary_function<SourceLocation, + SourceLocation, bool> { + SourceManager &SM; + + public: + explicit LocBeforeThanCompare(SourceManager &SM) : SM(SM) { } + + bool operator()(SourceLocation LHS, SourceLocation RHS) const { + return SM.isBeforeInTranslationUnit(LHS, RHS); + } + }; + + /// \brief Determines the order of 2 source locations in the "source location + /// address space". + bool isBeforeInSLocAddrSpace(SourceLocation LHS, SourceLocation RHS) const { + return isBeforeInSLocAddrSpace(LHS, RHS.getOffset()); + } + + /// \brief Determines the order of a source location and a source location + /// offset in the "source location address space". + /// + /// Note that we always consider source locations loaded from + bool isBeforeInSLocAddrSpace(SourceLocation LHS, unsigned RHS) const { + unsigned LHSOffset = LHS.getOffset(); + bool LHSLoaded = LHSOffset >= CurrentLoadedOffset; + bool RHSLoaded = RHS >= CurrentLoadedOffset; + if (LHSLoaded == RHSLoaded) + return LHSOffset < RHS; + + return LHSLoaded; + } + + // Iterators over FileInfos. + typedef llvm::DenseMap<const FileEntry*, SrcMgr::ContentCache*> + ::const_iterator fileinfo_iterator; + fileinfo_iterator fileinfo_begin() const { return FileInfos.begin(); } + fileinfo_iterator fileinfo_end() const { return FileInfos.end(); } + bool hasFileInfo(const FileEntry *File) const { + return FileInfos.find(File) != FileInfos.end(); + } + + /// PrintStats - Print statistics to stderr. + /// + void PrintStats() const; + + /// \brief Get the number of local SLocEntries we have. + unsigned local_sloc_entry_size() const { return LocalSLocEntryTable.size(); } + + /// \brief Get a local SLocEntry. This is exposed for indexing. + const SrcMgr::SLocEntry &getLocalSLocEntry(unsigned Index, + bool *Invalid = 0) const { + assert(Index < LocalSLocEntryTable.size() && "Invalid index"); + return LocalSLocEntryTable[Index]; + } + + /// \brief Get the number of loaded SLocEntries we have. + unsigned loaded_sloc_entry_size() const { return LoadedSLocEntryTable.size();} + + /// \brief Get a loaded SLocEntry. This is exposed for indexing. + const SrcMgr::SLocEntry &getLoadedSLocEntry(unsigned Index, + bool *Invalid = 0) const { + assert(Index < LoadedSLocEntryTable.size() && "Invalid index"); + if (SLocEntryLoaded[Index]) + return LoadedSLocEntryTable[Index]; + return loadSLocEntry(Index, Invalid); + } + + const SrcMgr::SLocEntry &getSLocEntry(FileID FID, bool *Invalid = 0) const { + if (FID.ID == 0 || FID.ID == -1) { + if (Invalid) *Invalid = true; + return LocalSLocEntryTable[0]; + } + return getSLocEntryByID(FID.ID); + } + + unsigned getNextLocalOffset() const { return NextLocalOffset; } + + void setExternalSLocEntrySource(ExternalSLocEntrySource *Source) { + assert(LoadedSLocEntryTable.empty() && + "Invalidating existing loaded entries"); + ExternalSLocEntries = Source; + } + + /// \brief Allocate a number of loaded SLocEntries, which will be actually + /// loaded on demand from the external source. + /// + /// NumSLocEntries will be allocated, which occupy a total of TotalSize space + /// in the global source view. The lowest ID and the base offset of the + /// entries will be returned. + std::pair<int, unsigned> + AllocateLoadedSLocEntries(unsigned NumSLocEntries, unsigned TotalSize); + + /// \brief Returns true if \p Loc came from a PCH/Module. + bool isLoadedSourceLocation(SourceLocation Loc) const { + return Loc.getOffset() >= CurrentLoadedOffset; + } + + /// \brief Returns true if \p Loc did not come from a PCH/Module. + bool isLocalSourceLocation(SourceLocation Loc) const { + return Loc.getOffset() < NextLocalOffset; + } + + /// \brief Returns true if \p FID came from a PCH/Module. + bool isLoadedFileID(FileID FID) const { + assert(FID.ID != -1 && "Using FileID sentinel value"); + return FID.ID < 0; + } + + /// \brief Returns true if \p FID did not come from a PCH/Module. + bool isLocalFileID(FileID FID) const { + return !isLoadedFileID(FID); + } + +private: + const llvm::MemoryBuffer *getFakeBufferForRecovery() const; + const SrcMgr::ContentCache *getFakeContentCacheForRecovery() const; + + const SrcMgr::SLocEntry &loadSLocEntry(unsigned Index, bool *Invalid) const; + + /// \brief Get the entry with the given unwrapped FileID. + const SrcMgr::SLocEntry &getSLocEntryByID(int ID) const { + assert(ID != -1 && "Using FileID sentinel value"); + if (ID < 0) + return getLoadedSLocEntryByID(ID); + return getLocalSLocEntry(static_cast<unsigned>(ID)); + } + + const SrcMgr::SLocEntry &getLoadedSLocEntryByID(int ID, + bool *Invalid = 0) const { + return getLoadedSLocEntry(static_cast<unsigned>(-ID - 2), Invalid); + } + + /// createExpansionLoc - Implements the common elements of storing an + /// expansion info struct into the SLocEntry table and producing a source + /// location that refers to it. + SourceLocation createExpansionLocImpl(const SrcMgr::ExpansionInfo &Expansion, + unsigned TokLength, + int LoadedID = 0, + unsigned LoadedOffset = 0); + + /// isOffsetInFileID - Return true if the specified FileID contains the + /// specified SourceLocation offset. This is a very hot method. + inline bool isOffsetInFileID(FileID FID, unsigned SLocOffset) const { + const SrcMgr::SLocEntry &Entry = getSLocEntry(FID); + // If the entry is after the offset, it can't contain it. + if (SLocOffset < Entry.getOffset()) return false; + + // If this is the very last entry then it does. + if (FID.ID == -2) + return true; + + // If it is the last local entry, then it does if the location is local. + if (static_cast<unsigned>(FID.ID+1) == LocalSLocEntryTable.size()) { + return SLocOffset < NextLocalOffset; + } + + // Otherwise, the entry after it has to not include it. This works for both + // local and loaded entries. + return SLocOffset < getSLocEntry(FileID::get(FID.ID+1)).getOffset(); + } + + /// createFileID - Create a new fileID for the specified ContentCache and + /// include position. This works regardless of whether the ContentCache + /// corresponds to a file or some other input source. + FileID createFileID(const SrcMgr::ContentCache* File, + SourceLocation IncludePos, + SrcMgr::CharacteristicKind DirCharacter, + int LoadedID, unsigned LoadedOffset); + + const SrcMgr::ContentCache * + getOrCreateContentCache(const FileEntry *SourceFile); + + /// createMemBufferContentCache - Create a new ContentCache for the specified + /// memory buffer. + const SrcMgr::ContentCache* + createMemBufferContentCache(const llvm::MemoryBuffer *Buf); + + FileID getFileIDSlow(unsigned SLocOffset) const; + FileID getFileIDLocal(unsigned SLocOffset) const; + FileID getFileIDLoaded(unsigned SLocOffset) const; + + SourceLocation getExpansionLocSlowCase(SourceLocation Loc) const; + SourceLocation getSpellingLocSlowCase(SourceLocation Loc) const; + SourceLocation getFileLocSlowCase(SourceLocation Loc) const; + + std::pair<FileID, unsigned> + getDecomposedExpansionLocSlowCase(const SrcMgr::SLocEntry *E) const; + std::pair<FileID, unsigned> + getDecomposedSpellingLocSlowCase(const SrcMgr::SLocEntry *E, + unsigned Offset) const; + void computeMacroArgsCache(MacroArgsMap *&MacroArgsCache, FileID FID) const; + + friend class ASTReader; + friend class ASTWriter; +}; + + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Basic/SourceManagerInternals.h b/clang/include/clang/Basic/SourceManagerInternals.h new file mode 100644 index 0000000..1cb16b4 --- /dev/null +++ b/clang/include/clang/Basic/SourceManagerInternals.h @@ -0,0 +1,130 @@ +//===--- SourceManagerInternals.h - SourceManager Internals -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the implementation details of the SourceManager +// class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SOURCEMANAGER_INTERNALS_H +#define LLVM_CLANG_SOURCEMANAGER_INTERNALS_H + +#include "clang/Basic/SourceManager.h" +#include "llvm/ADT/StringMap.h" +#include <map> + +namespace clang { + +//===----------------------------------------------------------------------===// +// Line Table Implementation +//===----------------------------------------------------------------------===// + +struct LineEntry { + /// FileOffset - The offset in this file that the line entry occurs at. + unsigned FileOffset; + + /// LineNo - The presumed line number of this line entry: #line 4. + unsigned LineNo; + + /// FilenameID - The ID of the filename identified by this line entry: + /// #line 4 "foo.c". This is -1 if not specified. + int FilenameID; + + /// Flags - Set the 0 if no flags, 1 if a system header, + SrcMgr::CharacteristicKind FileKind; + + /// IncludeOffset - This is the offset of the virtual include stack location, + /// which is manipulated by GNU linemarker directives. If this is 0 then + /// there is no virtual #includer. + unsigned IncludeOffset; + + static LineEntry get(unsigned Offs, unsigned Line, int Filename, + SrcMgr::CharacteristicKind FileKind, + unsigned IncludeOffset) { + LineEntry E; + E.FileOffset = Offs; + E.LineNo = Line; + E.FilenameID = Filename; + E.FileKind = FileKind; + E.IncludeOffset = IncludeOffset; + return E; + } +}; + +// needed for FindNearestLineEntry (upper_bound of LineEntry) +inline bool operator<(const LineEntry &lhs, const LineEntry &rhs) { + // FIXME: should check the other field? + return lhs.FileOffset < rhs.FileOffset; +} + +inline bool operator<(const LineEntry &E, unsigned Offset) { + return E.FileOffset < Offset; +} + +inline bool operator<(unsigned Offset, const LineEntry &E) { + return Offset < E.FileOffset; +} + +/// LineTableInfo - This class is used to hold and unique data used to +/// represent #line information. +class LineTableInfo { + /// FilenameIDs - This map is used to assign unique IDs to filenames in + /// #line directives. This allows us to unique the filenames that + /// frequently reoccur and reference them with indices. FilenameIDs holds + /// the mapping from string -> ID, and FilenamesByID holds the mapping of ID + /// to string. + llvm::StringMap<unsigned, llvm::BumpPtrAllocator> FilenameIDs; + std::vector<llvm::StringMapEntry<unsigned>*> FilenamesByID; + + /// LineEntries - This is a map from FileIDs to a list of line entries (sorted + /// by the offset they occur in the file. + std::map<int, std::vector<LineEntry> > LineEntries; +public: + LineTableInfo() { + } + + void clear() { + FilenameIDs.clear(); + FilenamesByID.clear(); + LineEntries.clear(); + } + + ~LineTableInfo() {} + + unsigned getLineTableFilenameID(StringRef Str); + const char *getFilename(unsigned ID) const { + assert(ID < FilenamesByID.size() && "Invalid FilenameID"); + return FilenamesByID[ID]->getKeyData(); + } + unsigned getNumFilenames() const { return FilenamesByID.size(); } + + void AddLineNote(int FID, unsigned Offset, + unsigned LineNo, int FilenameID); + void AddLineNote(int FID, unsigned Offset, + unsigned LineNo, int FilenameID, + unsigned EntryExit, SrcMgr::CharacteristicKind FileKind); + + + /// FindNearestLineEntry - Find the line entry nearest to FID that is before + /// it. If there is no line entry before Offset in FID, return null. + const LineEntry *FindNearestLineEntry(int FID, unsigned Offset); + + // Low-level access + typedef std::map<int, std::vector<LineEntry> >::iterator iterator; + iterator begin() { return LineEntries.begin(); } + iterator end() { return LineEntries.end(); } + + /// \brief Add a new line entry that has already been encoded into + /// the internal representation of the line table. + void AddEntry(int FID, const std::vector<LineEntry> &Entries); +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Basic/Specifiers.h b/clang/include/clang/Basic/Specifiers.h new file mode 100644 index 0000000..9e71827 --- /dev/null +++ b/clang/include/clang/Basic/Specifiers.h @@ -0,0 +1,173 @@ +//===--- Specifiers.h - Declaration and Type Specifiers ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines various enumerations that describe declaration and +// type specifiers. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_SPECIFIERS_H +#define LLVM_CLANG_BASIC_SPECIFIERS_H + +namespace clang { + /// \brief Specifies the width of a type, e.g., short, long, or long long. + enum TypeSpecifierWidth { + TSW_unspecified, + TSW_short, + TSW_long, + TSW_longlong + }; + + /// \brief Specifies the signedness of a type, e.g., signed or unsigned. + enum TypeSpecifierSign { + TSS_unspecified, + TSS_signed, + TSS_unsigned + }; + + /// \brief Specifies the kind of type. + enum TypeSpecifierType { + TST_unspecified, + TST_void, + TST_char, + TST_wchar, // C++ wchar_t + TST_char16, // C++0x char16_t + TST_char32, // C++0x char32_t + TST_int, + TST_int128, + TST_half, // OpenCL half, ARM NEON __fp16 + TST_float, + TST_double, + TST_bool, // _Bool + TST_decimal32, // _Decimal32 + TST_decimal64, // _Decimal64 + TST_decimal128, // _Decimal128 + TST_enum, + TST_union, + TST_struct, + TST_class, // C++ class type + TST_typename, // Typedef, C++ class-name or enum name, etc. + TST_typeofType, + TST_typeofExpr, + TST_decltype, // C++0x decltype + TST_underlyingType, // __underlying_type for C++0x + TST_auto, // C++0x auto + TST_unknown_anytype, // __unknown_anytype extension + TST_atomic, // C11 _Atomic + TST_error // erroneous type + }; + + /// WrittenBuiltinSpecs - Structure that packs information about the + /// type specifiers that were written in a particular type specifier + /// sequence. + struct WrittenBuiltinSpecs { + /*DeclSpec::TST*/ unsigned Type : 5; + /*DeclSpec::TSS*/ unsigned Sign : 2; + /*DeclSpec::TSW*/ unsigned Width : 2; + bool ModeAttr : 1; + }; + + /// AccessSpecifier - A C++ access specifier (public, private, + /// protected), plus the special value "none" which means + /// different things in different contexts. + enum AccessSpecifier { + AS_public, + AS_protected, + AS_private, + AS_none + }; + + /// ExprValueKind - The categorization of expression values, + /// currently following the C++0x scheme. + enum ExprValueKind { + /// An r-value expression (a pr-value in the C++0x taxonomy) + /// produces a temporary value. + VK_RValue, + + /// An l-value expression is a reference to an object with + /// independent storage. + VK_LValue, + + /// An x-value expression is a reference to an object with + /// independent storage but which can be "moved", i.e. + /// efficiently cannibalized for its resources. + VK_XValue + }; + + /// A further classification of the kind of object referenced by an + /// l-value or x-value. + enum ExprObjectKind { + /// An ordinary object is located at an address in memory. + OK_Ordinary, + + /// A bitfield object is a bitfield on a C or C++ record. + OK_BitField, + + /// A vector component is an element or range of elements on a vector. + OK_VectorComponent, + + /// An Objective C property is a logical field of an Objective-C + /// object which is read and written via Objective C method calls. + OK_ObjCProperty, + + /// An Objective C array/dictionary subscripting which reads an object + /// or writes at the subscripted array/dictionary element via + /// Objective C method calls. + OK_ObjCSubscript + }; + + // \brief Describes the kind of template specialization that a + // particular template specialization declaration represents. + enum TemplateSpecializationKind { + /// This template specialization was formed from a template-id but + /// has not yet been declared, defined, or instantiated. + TSK_Undeclared = 0, + /// This template specialization was implicitly instantiated from a + /// template. (C++ [temp.inst]). + TSK_ImplicitInstantiation, + /// This template specialization was declared or defined by an + /// explicit specialization (C++ [temp.expl.spec]) or partial + /// specialization (C++ [temp.class.spec]). + TSK_ExplicitSpecialization, + /// This template specialization was instantiated from a template + /// due to an explicit instantiation declaration request + /// (C++0x [temp.explicit]). + TSK_ExplicitInstantiationDeclaration, + /// This template specialization was instantiated from a template + /// due to an explicit instantiation definition request + /// (C++ [temp.explicit]). + TSK_ExplicitInstantiationDefinition + }; + + /// \brief Storage classes. + enum StorageClass { + // These are legal on both functions and variables. + SC_None, + SC_Extern, + SC_Static, + SC_PrivateExtern, + + // These are only legal on variables. + SC_OpenCLWorkGroupLocal, + SC_Auto, + SC_Register + }; + + /// Checks whether the given storage class is legal for functions. + inline bool isLegalForFunction(StorageClass SC) { + return SC <= SC_PrivateExtern; + } + + /// Checks whether the given storage class is legal for variables. + inline bool isLegalForVariable(StorageClass SC) { + return true; + } +} // end namespace clang + +#endif // LLVM_CLANG_BASIC_SPECIFIERS_H diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td new file mode 100644 index 0000000..e7718cd --- /dev/null +++ b/clang/include/clang/Basic/StmtNodes.td @@ -0,0 +1,170 @@ +class AttrSubject; + +class Stmt<bit abstract = 0> : AttrSubject { + bit Abstract = abstract; +} + +class DStmt<Stmt base, bit abstract = 0> : Stmt<abstract> { + Stmt Base = base; +} + +// Statements +def NullStmt : Stmt; +def CompoundStmt : Stmt; +def LabelStmt : Stmt; +def AttributedStmt : Stmt; +def IfStmt : Stmt; +def SwitchStmt : Stmt; +def WhileStmt : Stmt; +def DoStmt : Stmt; +def ForStmt : Stmt; +def GotoStmt : Stmt; +def IndirectGotoStmt : Stmt; +def ContinueStmt : Stmt; +def BreakStmt : Stmt; +def ReturnStmt : Stmt; +def DeclStmt : Stmt; +def SwitchCase : Stmt<1>; +def CaseStmt : DStmt<SwitchCase>; +def DefaultStmt : DStmt<SwitchCase>; + +// GNU Extensions +def AsmStmt : Stmt; + +// Obj-C statements +def ObjCAtTryStmt : Stmt; +def ObjCAtCatchStmt : Stmt; +def ObjCAtFinallyStmt : Stmt; +def ObjCAtThrowStmt : Stmt; +def ObjCAtSynchronizedStmt : Stmt; +def ObjCForCollectionStmt : Stmt; +def ObjCAutoreleasePoolStmt : Stmt; + +// C++ statments +def CXXCatchStmt : Stmt; +def CXXTryStmt : Stmt; +def CXXForRangeStmt : Stmt; + +// Expressions +def Expr : Stmt<1>; +def PredefinedExpr : DStmt<Expr>; +def DeclRefExpr : DStmt<Expr>; +def IntegerLiteral : DStmt<Expr>; +def FloatingLiteral : DStmt<Expr>; +def ImaginaryLiteral : DStmt<Expr>; +def StringLiteral : DStmt<Expr>; +def CharacterLiteral : DStmt<Expr>; +def ParenExpr : DStmt<Expr>; +def UnaryOperator : DStmt<Expr>; +def OffsetOfExpr : DStmt<Expr>; +def UnaryExprOrTypeTraitExpr : DStmt<Expr>; +def ArraySubscriptExpr : DStmt<Expr>; +def CallExpr : DStmt<Expr>; +def MemberExpr : DStmt<Expr>; +def CastExpr : DStmt<Expr, 1>; +def BinaryOperator : DStmt<Expr>; +def CompoundAssignOperator : DStmt<BinaryOperator>; +def AbstractConditionalOperator : DStmt<Expr, 1>; +def ConditionalOperator : DStmt<AbstractConditionalOperator>; +def BinaryConditionalOperator : DStmt<AbstractConditionalOperator>; +def ImplicitCastExpr : DStmt<CastExpr>; +def ExplicitCastExpr : DStmt<CastExpr, 1>; +def CStyleCastExpr : DStmt<ExplicitCastExpr>; +def CompoundLiteralExpr : DStmt<Expr>; +def ExtVectorElementExpr : DStmt<Expr>; +def InitListExpr : DStmt<Expr>; +def DesignatedInitExpr : DStmt<Expr>; +def ImplicitValueInitExpr : DStmt<Expr>; +def ParenListExpr : DStmt<Expr>; +def VAArgExpr : DStmt<Expr>; +def GenericSelectionExpr : DStmt<Expr>; +def PseudoObjectExpr : DStmt<Expr>; + +// Atomic expressions +def AtomicExpr : DStmt<Expr>; + +// GNU Extensions. +def AddrLabelExpr : DStmt<Expr>; +def StmtExpr : DStmt<Expr>; +def ChooseExpr : DStmt<Expr>; +def GNUNullExpr : DStmt<Expr>; + +// C++ Expressions. +def CXXOperatorCallExpr : DStmt<CallExpr>; +def CXXMemberCallExpr : DStmt<CallExpr>; +def CXXNamedCastExpr : DStmt<ExplicitCastExpr, 1>; +def CXXStaticCastExpr : DStmt<CXXNamedCastExpr>; +def CXXDynamicCastExpr : DStmt<CXXNamedCastExpr>; +def CXXReinterpretCastExpr : DStmt<CXXNamedCastExpr>; +def CXXConstCastExpr : DStmt<CXXNamedCastExpr>; +def CXXFunctionalCastExpr : DStmt<ExplicitCastExpr>; +def CXXTypeidExpr : DStmt<Expr>; +def UserDefinedLiteral : DStmt<CallExpr>; +def CXXBoolLiteralExpr : DStmt<Expr>; +def CXXNullPtrLiteralExpr : DStmt<Expr>; +def CXXThisExpr : DStmt<Expr>; +def CXXThrowExpr : DStmt<Expr>; +def CXXDefaultArgExpr : DStmt<Expr>; +def CXXScalarValueInitExpr : DStmt<Expr>; +def CXXNewExpr : DStmt<Expr>; +def CXXDeleteExpr : DStmt<Expr>; +def CXXPseudoDestructorExpr : DStmt<Expr>; +def TypeTraitExpr : DStmt<Expr>; +def UnaryTypeTraitExpr : DStmt<Expr>; +def BinaryTypeTraitExpr : DStmt<Expr>; +def ArrayTypeTraitExpr : DStmt<Expr>; +def ExpressionTraitExpr : DStmt<Expr>; +def DependentScopeDeclRefExpr : DStmt<Expr>; +def CXXConstructExpr : DStmt<Expr>; +def CXXBindTemporaryExpr : DStmt<Expr>; +def ExprWithCleanups : DStmt<Expr>; +def CXXTemporaryObjectExpr : DStmt<CXXConstructExpr>; +def CXXUnresolvedConstructExpr : DStmt<Expr>; +def CXXDependentScopeMemberExpr : DStmt<Expr>; +def OverloadExpr : DStmt<Expr, 1>; +def UnresolvedLookupExpr : DStmt<OverloadExpr>; +def UnresolvedMemberExpr : DStmt<OverloadExpr>; +def CXXNoexceptExpr : DStmt<Expr>; +def PackExpansionExpr : DStmt<Expr>; +def SizeOfPackExpr : DStmt<Expr>; +def SubstNonTypeTemplateParmExpr : DStmt<Expr>; +def SubstNonTypeTemplateParmPackExpr : DStmt<Expr>; +def MaterializeTemporaryExpr : DStmt<Expr>; +def LambdaExpr : DStmt<Expr>; + +// Obj-C Expressions. +def ObjCStringLiteral : DStmt<Expr>; +def ObjCNumericLiteral : DStmt<Expr>; +def ObjCArrayLiteral : DStmt<Expr>; +def ObjCDictionaryLiteral : DStmt<Expr>; +def ObjCEncodeExpr : DStmt<Expr>; +def ObjCMessageExpr : DStmt<Expr>; +def ObjCSelectorExpr : DStmt<Expr>; +def ObjCProtocolExpr : DStmt<Expr>; +def ObjCIvarRefExpr : DStmt<Expr>; +def ObjCPropertyRefExpr : DStmt<Expr>; +def ObjCIsaExpr : DStmt<Expr>; +def ObjCIndirectCopyRestoreExpr : DStmt<Expr>; +def ObjCBoolLiteralExpr : DStmt<Expr>; +def ObjCSubscriptRefExpr : DStmt<Expr>; + +// Obj-C ARC Expressions. +def ObjCBridgedCastExpr : DStmt<ExplicitCastExpr>; + +// CUDA Expressions. +def CUDAKernelCallExpr : DStmt<CallExpr>; + +// Clang Extensions. +def ShuffleVectorExpr : DStmt<Expr>; +def BlockExpr : DStmt<Expr>; +def OpaqueValueExpr : DStmt<Expr>; + +// Microsoft Extensions. +def CXXUuidofExpr : DStmt<Expr>; +def SEHTryStmt : Stmt; +def SEHExceptStmt : Stmt; +def SEHFinallyStmt : Stmt; +def MSDependentExistsStmt : Stmt; + +// OpenCL Extensions. +def AsTypeExpr : DStmt<Expr>; diff --git a/clang/include/clang/Basic/TargetBuiltins.h b/clang/include/clang/Basic/TargetBuiltins.h new file mode 100644 index 0000000..7c04bf7 --- /dev/null +++ b/clang/include/clang/Basic/TargetBuiltins.h @@ -0,0 +1,110 @@ +//===--- TargetBuiltins.h - Target specific builtin IDs -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_TARGET_BUILTINS_H +#define LLVM_CLANG_BASIC_TARGET_BUILTINS_H + +#include "clang/Basic/Builtins.h" +#undef PPC + +namespace clang { + + /// ARM builtins + namespace ARM { + enum { + LastTIBuiltin = clang::Builtin::FirstTSBuiltin-1, +#define BUILTIN(ID, TYPE, ATTRS) BI##ID, +#include "clang/Basic/BuiltinsARM.def" + LastTSBuiltin + }; + } + + /// PPC builtins + namespace PPC { + enum { + LastTIBuiltin = clang::Builtin::FirstTSBuiltin-1, +#define BUILTIN(ID, TYPE, ATTRS) BI##ID, +#include "clang/Basic/BuiltinsPPC.def" + LastTSBuiltin + }; + } + + /// PTX builtins + namespace PTX { + enum { + LastTIBuiltin = clang::Builtin::FirstTSBuiltin-1, +#define BUILTIN(ID, TYPE, ATTRS) BI##ID, +#include "clang/Basic/BuiltinsPTX.def" + LastTSBuiltin + }; + } + + + /// X86 builtins + namespace X86 { + enum { + LastTIBuiltin = clang::Builtin::FirstTSBuiltin-1, +#define BUILTIN(ID, TYPE, ATTRS) BI##ID, +#include "clang/Basic/BuiltinsX86.def" + LastTSBuiltin + }; + } + + /// NeonTypeFlags - Flags to identify the types for overloaded Neon + /// builtins. These must be kept in sync with the flags in + /// utils/TableGen/NeonEmitter.h. + class NeonTypeFlags { + enum { + EltTypeMask = 0xf, + UnsignedFlag = 0x10, + QuadFlag = 0x20 + }; + uint32_t Flags; + + public: + enum EltType { + Int8, + Int16, + Int32, + Int64, + Poly8, + Poly16, + Float16, + Float32 + }; + + NeonTypeFlags(unsigned F) : Flags(F) {} + NeonTypeFlags(EltType ET, bool IsUnsigned, bool IsQuad) : Flags(ET) { + if (IsUnsigned) + Flags |= UnsignedFlag; + if (IsQuad) + Flags |= QuadFlag; + } + + EltType getEltType() const { return (EltType)(Flags & EltTypeMask); } + bool isPoly() const { + EltType ET = getEltType(); + return ET == Poly8 || ET == Poly16; + } + bool isUnsigned() const { return (Flags & UnsignedFlag) != 0; } + bool isQuad() const { return (Flags & QuadFlag) != 0; } + }; + + /// Hexagon builtins + namespace Hexagon { + enum { + LastTIBuiltin = clang::Builtin::FirstTSBuiltin-1, +#define BUILTIN(ID, TYPE, ATTRS) BI##ID, +#include "clang/Basic/BuiltinsHexagon.def" + LastTSBuiltin + }; + } +} // end namespace clang. + +#endif diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h new file mode 100644 index 0000000..a03cf83 --- /dev/null +++ b/clang/include/clang/Basic/TargetInfo.h @@ -0,0 +1,695 @@ +//===--- TargetInfo.h - Expose information about the target -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the TargetInfo interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_TARGETINFO_H +#define LLVM_CLANG_BASIC_TARGETINFO_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/DataTypes.h" +#include "clang/Basic/AddressSpaces.h" +#include "clang/Basic/VersionTuple.h" +#include <cassert> +#include <vector> +#include <string> + +namespace llvm { +struct fltSemantics; +} + +namespace clang { +class DiagnosticsEngine; +class LangOptions; +class MacroBuilder; +class SourceLocation; +class SourceManager; +class TargetOptions; + +namespace Builtin { struct Info; } + +/// TargetCXXABI - The types of C++ ABIs for which we can generate code. +enum TargetCXXABI { + /// The generic ("Itanium") C++ ABI, documented at: + /// http://www.codesourcery.com/public/cxx-abi/ + CXXABI_Itanium, + + /// The ARM C++ ABI, based largely on the Itanium ABI but with + /// significant differences. + /// http://infocenter.arm.com + /// /help/topic/com.arm.doc.ihi0041c/IHI0041C_cppabi.pdf + CXXABI_ARM, + + /// The Visual Studio ABI. Only scattered official documentation exists. + CXXABI_Microsoft +}; + +/// TargetInfo - This class exposes information about the current target. +/// +class TargetInfo : public RefCountedBase<TargetInfo> { + llvm::Triple Triple; +protected: + // Target values set by the ctor of the actual target implementation. Default + // values are specified by the TargetInfo constructor. + bool BigEndian; + bool TLSSupported; + bool NoAsmVariants; // True if {|} are normal characters. + unsigned char PointerWidth, PointerAlign; + unsigned char BoolWidth, BoolAlign; + unsigned char IntWidth, IntAlign; + unsigned char HalfWidth, HalfAlign; + unsigned char FloatWidth, FloatAlign; + unsigned char DoubleWidth, DoubleAlign; + unsigned char LongDoubleWidth, LongDoubleAlign; + unsigned char LargeArrayMinWidth, LargeArrayAlign; + unsigned char LongWidth, LongAlign; + unsigned char LongLongWidth, LongLongAlign; + unsigned char SuitableAlign; + unsigned char MaxAtomicPromoteWidth, MaxAtomicInlineWidth; + const char *DescriptionString; + const char *UserLabelPrefix; + const char *MCountName; + const llvm::fltSemantics *HalfFormat, *FloatFormat, *DoubleFormat, + *LongDoubleFormat; + unsigned char RegParmMax, SSERegParmMax; + TargetCXXABI CXXABI; + const LangAS::Map *AddrSpaceMap; + + mutable StringRef PlatformName; + mutable VersionTuple PlatformMinVersion; + + unsigned HasAlignMac68kSupport : 1; + unsigned RealTypeUsesObjCFPRet : 3; + unsigned ComplexLongDoubleUsesFP2Ret : 1; + + // TargetInfo Constructor. Default initializes all fields. + TargetInfo(const std::string &T); + +public: + /// CreateTargetInfo - Construct a target for the given options. + /// + /// \param Opts - The options to use to initialize the target. The target may + /// modify the options to canonicalize the target feature information to match + /// what the backend expects. + static TargetInfo* CreateTargetInfo(DiagnosticsEngine &Diags, + TargetOptions &Opts); + + virtual ~TargetInfo(); + + ///===---- Target Data Type Query Methods -------------------------------===// + enum IntType { + NoInt = 0, + SignedShort, + UnsignedShort, + SignedInt, + UnsignedInt, + SignedLong, + UnsignedLong, + SignedLongLong, + UnsignedLongLong + }; + + enum RealType { + Float = 0, + Double, + LongDouble + }; + +protected: + IntType SizeType, IntMaxType, UIntMaxType, PtrDiffType, IntPtrType, WCharType, + WIntType, Char16Type, Char32Type, Int64Type, SigAtomicType; + + /// Flag whether the Objective-C built-in boolean type should be signed char. + /// Otherwise, when this flag is not set, the normal built-in boolean type is + /// used. + unsigned UseSignedCharForObjCBool : 1; + + /// Control whether the alignment of bit-field types is respected when laying + /// out structures. If true, then the alignment of the bit-field type will be + /// used to (a) impact the alignment of the containing structure, and (b) + /// ensure that the individual bit-field will not straddle an alignment + /// boundary. + unsigned UseBitFieldTypeAlignment : 1; + + /// Control whether zero length bitfields (e.g., int : 0;) force alignment of + /// the next bitfield. If the alignment of the zero length bitfield is + /// greater than the member that follows it, `bar', `bar' will be aligned as + /// the type of the zero-length bitfield. + unsigned UseZeroLengthBitfieldAlignment : 1; + + /// If non-zero, specifies a fixed alignment value for bitfields that follow + /// zero length bitfield, regardless of the zero length bitfield type. + unsigned ZeroLengthBitfieldBoundary; + +public: + IntType getSizeType() const { return SizeType; } + IntType getIntMaxType() const { return IntMaxType; } + IntType getUIntMaxType() const { return UIntMaxType; } + IntType getPtrDiffType(unsigned AddrSpace) const { + return AddrSpace == 0 ? PtrDiffType : getPtrDiffTypeV(AddrSpace); + } + IntType getIntPtrType() const { return IntPtrType; } + IntType getWCharType() const { return WCharType; } + IntType getWIntType() const { return WIntType; } + IntType getChar16Type() const { return Char16Type; } + IntType getChar32Type() const { return Char32Type; } + IntType getInt64Type() const { return Int64Type; } + IntType getSigAtomicType() const { return SigAtomicType; } + + + /// getTypeWidth - Return the width (in bits) of the specified integer type + /// enum. For example, SignedInt -> getIntWidth(). + unsigned getTypeWidth(IntType T) const; + + /// getTypeAlign - Return the alignment (in bits) of the specified integer + /// type enum. For example, SignedInt -> getIntAlign(). + unsigned getTypeAlign(IntType T) const; + + /// isTypeSigned - Return whether an integer types is signed. Returns true if + /// the type is signed; false otherwise. + static bool isTypeSigned(IntType T); + + /// getPointerWidth - Return the width of pointers on this target, for the + /// specified address space. + uint64_t getPointerWidth(unsigned AddrSpace) const { + return AddrSpace == 0 ? PointerWidth : getPointerWidthV(AddrSpace); + } + uint64_t getPointerAlign(unsigned AddrSpace) const { + return AddrSpace == 0 ? PointerAlign : getPointerAlignV(AddrSpace); + } + + /// getBoolWidth/Align - Return the size of '_Bool' and C++ 'bool' for this + /// target, in bits. + unsigned getBoolWidth() const { return BoolWidth; } + unsigned getBoolAlign() const { return BoolAlign; } + + unsigned getCharWidth() const { return 8; } // FIXME + unsigned getCharAlign() const { return 8; } // FIXME + + /// getShortWidth/Align - Return the size of 'signed short' and + /// 'unsigned short' for this target, in bits. + unsigned getShortWidth() const { return 16; } // FIXME + unsigned getShortAlign() const { return 16; } // FIXME + + /// getIntWidth/Align - Return the size of 'signed int' and 'unsigned int' for + /// this target, in bits. + unsigned getIntWidth() const { return IntWidth; } + unsigned getIntAlign() const { return IntAlign; } + + /// getLongWidth/Align - Return the size of 'signed long' and 'unsigned long' + /// for this target, in bits. + unsigned getLongWidth() const { return LongWidth; } + unsigned getLongAlign() const { return LongAlign; } + + /// getLongLongWidth/Align - Return the size of 'signed long long' and + /// 'unsigned long long' for this target, in bits. + unsigned getLongLongWidth() const { return LongLongWidth; } + unsigned getLongLongAlign() const { return LongLongAlign; } + + /// getSuitableAlign - Return the alignment that is suitable for storing any + /// object with a fundamental alignment requirement. + unsigned getSuitableAlign() const { return SuitableAlign; } + + /// getWCharWidth/Align - Return the size of 'wchar_t' for this target, in + /// bits. + unsigned getWCharWidth() const { return getTypeWidth(WCharType); } + unsigned getWCharAlign() const { return getTypeAlign(WCharType); } + + /// getChar16Width/Align - Return the size of 'char16_t' for this target, in + /// bits. + unsigned getChar16Width() const { return getTypeWidth(Char16Type); } + unsigned getChar16Align() const { return getTypeAlign(Char16Type); } + + /// getChar32Width/Align - Return the size of 'char32_t' for this target, in + /// bits. + unsigned getChar32Width() const { return getTypeWidth(Char32Type); } + unsigned getChar32Align() const { return getTypeAlign(Char32Type); } + + /// getHalfWidth/Align/Format - Return the size/align/format of 'half'. + unsigned getHalfWidth() const { return HalfWidth; } + unsigned getHalfAlign() const { return HalfAlign; } + const llvm::fltSemantics &getHalfFormat() const { return *HalfFormat; } + + /// getFloatWidth/Align/Format - Return the size/align/format of 'float'. + unsigned getFloatWidth() const { return FloatWidth; } + unsigned getFloatAlign() const { return FloatAlign; } + const llvm::fltSemantics &getFloatFormat() const { return *FloatFormat; } + + /// getDoubleWidth/Align/Format - Return the size/align/format of 'double'. + unsigned getDoubleWidth() const { return DoubleWidth; } + unsigned getDoubleAlign() const { return DoubleAlign; } + const llvm::fltSemantics &getDoubleFormat() const { return *DoubleFormat; } + + /// getLongDoubleWidth/Align/Format - Return the size/align/format of 'long + /// double'. + unsigned getLongDoubleWidth() const { return LongDoubleWidth; } + unsigned getLongDoubleAlign() const { return LongDoubleAlign; } + const llvm::fltSemantics &getLongDoubleFormat() const { + return *LongDoubleFormat; + } + + /// getFloatEvalMethod - Return the value for the C99 FLT_EVAL_METHOD macro. + virtual unsigned getFloatEvalMethod() const { return 0; } + + // getLargeArrayMinWidth/Align - Return the minimum array size that is + // 'large' and its alignment. + unsigned getLargeArrayMinWidth() const { return LargeArrayMinWidth; } + unsigned getLargeArrayAlign() const { return LargeArrayAlign; } + + /// getMaxAtomicPromoteWidth - Return the maximum width lock-free atomic + /// operation which will ever be supported for the given target + unsigned getMaxAtomicPromoteWidth() const { return MaxAtomicPromoteWidth; } + /// getMaxAtomicInlineWidth - Return the maximum width lock-free atomic + /// operation which can be inlined given the supported features of the + /// given target. + unsigned getMaxAtomicInlineWidth() const { return MaxAtomicInlineWidth; } + + /// getIntMaxTWidth - Return the size of intmax_t and uintmax_t for this + /// target, in bits. + unsigned getIntMaxTWidth() const { + return getTypeWidth(IntMaxType); + } + + /// getRegisterWidth - Return the "preferred" register width on this target. + uint64_t getRegisterWidth() const { + // Currently we assume the register width on the target matches the pointer + // width, we can introduce a new variable for this if/when some target wants + // it. + return LongWidth; + } + + /// getUserLabelPrefix - This returns the default value of the + /// __USER_LABEL_PREFIX__ macro, which is the prefix given to user symbols by + /// default. On most platforms this is "_", but it is "" on some, and "." on + /// others. + const char *getUserLabelPrefix() const { + return UserLabelPrefix; + } + + /// MCountName - This returns name of the mcount instrumentation function. + const char *getMCountName() const { + return MCountName; + } + + /// useSignedCharForObjCBool - Check if the Objective-C built-in boolean + /// type should be signed char. Otherwise, if this returns false, the + /// normal built-in boolean type should also be used for Objective-C. + bool useSignedCharForObjCBool() const { + return UseSignedCharForObjCBool; + } + void noSignedCharForObjCBool() { + UseSignedCharForObjCBool = false; + } + + /// useBitFieldTypeAlignment() - Check whether the alignment of bit-field + /// types is respected when laying out structures. + bool useBitFieldTypeAlignment() const { + return UseBitFieldTypeAlignment; + } + + /// useZeroLengthBitfieldAlignment() - Check whether zero length bitfields + /// should force alignment of the next member. + bool useZeroLengthBitfieldAlignment() const { + return UseZeroLengthBitfieldAlignment; + } + + /// getZeroLengthBitfieldBoundary() - Get the fixed alignment value in bits + /// for a member that follows a zero length bitfield. + unsigned getZeroLengthBitfieldBoundary() const { + return ZeroLengthBitfieldBoundary; + } + + /// hasAlignMac68kSupport - Check whether this target support '#pragma options + /// align=mac68k'. + bool hasAlignMac68kSupport() const { + return HasAlignMac68kSupport; + } + + /// getTypeName - Return the user string for the specified integer type enum. + /// For example, SignedShort -> "short". + static const char *getTypeName(IntType T); + + /// getTypeConstantSuffix - Return the constant suffix for the specified + /// integer type enum. For example, SignedLong -> "L". + static const char *getTypeConstantSuffix(IntType T); + + /// \brief Check whether the given real type should use the "fpret" flavor of + /// Obj-C message passing on this target. + bool useObjCFPRetForRealType(RealType T) const { + return RealTypeUsesObjCFPRet & (1 << T); + } + + /// \brief Check whether _Complex long double should use the "fp2ret" flavor + /// of Obj-C message passing on this target. + bool useObjCFP2RetForComplexLongDouble() const { + return ComplexLongDoubleUsesFP2Ret; + } + + ///===---- Other target property query methods --------------------------===// + + /// getTargetDefines - Appends the target-specific #define values for this + /// target set to the specified buffer. + virtual void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const = 0; + + + /// getTargetBuiltins - Return information about target-specific builtins for + /// the current primary target, and info about which builtins are non-portable + /// across the current set of primary and secondary targets. + virtual void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const = 0; + + /// isCLZForZeroUndef - The __builtin_clz* and __builtin_ctz* built-in + /// functions are specified to have undefined results for zero inputs, but + /// on targets that support these operations in a way that provides + /// well-defined results for zero without loss of performance, it is a good + /// idea to avoid optimizing based on that undef behavior. + virtual bool isCLZForZeroUndef() const { return true; } + + /// getVAListDeclaration - Return the declaration to use for + /// __builtin_va_list, which is target-specific. + virtual const char *getVAListDeclaration() const = 0; + + /// isValidClobber - Returns whether the passed in string is + /// a valid clobber in an inline asm statement. This is used by + /// Sema. + bool isValidClobber(StringRef Name) const; + + /// isValidGCCRegisterName - Returns whether the passed in string + /// is a valid register name according to GCC. This is used by Sema for + /// inline asm statements. + bool isValidGCCRegisterName(StringRef Name) const; + + // getNormalizedGCCRegisterName - Returns the "normalized" GCC register name. + // For example, on x86 it will return "ax" when "eax" is passed in. + StringRef getNormalizedGCCRegisterName(StringRef Name) const; + + struct ConstraintInfo { + enum { + CI_None = 0x00, + CI_AllowsMemory = 0x01, + CI_AllowsRegister = 0x02, + CI_ReadWrite = 0x04, // "+r" output constraint (read and write). + CI_HasMatchingInput = 0x08 // This output operand has a matching input. + }; + unsigned Flags; + int TiedOperand; + + std::string ConstraintStr; // constraint: "=rm" + std::string Name; // Operand name: [foo] with no []'s. + public: + ConstraintInfo(StringRef ConstraintStr, StringRef Name) + : Flags(0), TiedOperand(-1), ConstraintStr(ConstraintStr.str()), + Name(Name.str()) {} + + const std::string &getConstraintStr() const { return ConstraintStr; } + const std::string &getName() const { return Name; } + bool isReadWrite() const { return (Flags & CI_ReadWrite) != 0; } + bool allowsRegister() const { return (Flags & CI_AllowsRegister) != 0; } + bool allowsMemory() const { return (Flags & CI_AllowsMemory) != 0; } + + /// hasMatchingInput - Return true if this output operand has a matching + /// (tied) input operand. + bool hasMatchingInput() const { return (Flags & CI_HasMatchingInput) != 0; } + + /// hasTiedOperand() - Return true if this input operand is a matching + /// constraint that ties it to an output operand. If this returns true, + /// then getTiedOperand will indicate which output operand this is tied to. + bool hasTiedOperand() const { return TiedOperand != -1; } + unsigned getTiedOperand() const { + assert(hasTiedOperand() && "Has no tied operand!"); + return (unsigned)TiedOperand; + } + + void setIsReadWrite() { Flags |= CI_ReadWrite; } + void setAllowsMemory() { Flags |= CI_AllowsMemory; } + void setAllowsRegister() { Flags |= CI_AllowsRegister; } + void setHasMatchingInput() { Flags |= CI_HasMatchingInput; } + + /// setTiedOperand - Indicate that this is an input operand that is tied to + /// the specified output operand. Copy over the various constraint + /// information from the output. + void setTiedOperand(unsigned N, ConstraintInfo &Output) { + Output.setHasMatchingInput(); + Flags = Output.Flags; + TiedOperand = N; + // Don't copy Name or constraint string. + } + }; + + // validateOutputConstraint, validateInputConstraint - Checks that + // a constraint is valid and provides information about it. + // FIXME: These should return a real error instead of just true/false. + bool validateOutputConstraint(ConstraintInfo &Info) const; + bool validateInputConstraint(ConstraintInfo *OutputConstraints, + unsigned NumOutputs, + ConstraintInfo &info) const; + bool resolveSymbolicName(const char *&Name, + ConstraintInfo *OutputConstraints, + unsigned NumOutputs, unsigned &Index) const; + + // Constraint parm will be left pointing at the last character of + // the constraint. In practice, it won't be changed unless the + // constraint is longer than one character. + virtual std::string convertConstraint(const char *&Constraint) const { + // 'p' defaults to 'r', but can be overridden by targets. + if (*Constraint == 'p') + return std::string("r"); + return std::string(1, *Constraint); + } + + // Returns a string of target-specific clobbers, in LLVM format. + virtual const char *getClobbers() const = 0; + + + /// getTriple - Return the target triple of the primary target. + const llvm::Triple &getTriple() const { + return Triple; + } + + const char *getTargetDescription() const { + return DescriptionString; + } + + struct GCCRegAlias { + const char * const Aliases[5]; + const char * const Register; + }; + + struct AddlRegName { + const char * const Names[5]; + const unsigned RegNum; + }; + + /// hasProtectedVisibility - Does this target support "protected" + /// visibility? + /// + /// Any target which dynamic libraries will naturally support + /// something like "default" (meaning that the symbol is visible + /// outside this shared object) and "hidden" (meaning that it isn't) + /// visibilities, but "protected" is really an ELF-specific concept + /// with wierd semantics designed around the convenience of dynamic + /// linker implementations. Which is not to suggest that there's + /// consistent target-independent semantics for "default" visibility + /// either; the entire thing is pretty badly mangled. + virtual bool hasProtectedVisibility() const { return true; } + + virtual bool useGlobalsForAutomaticVariables() const { return false; } + + /// getCFStringSection - Return the section to use for CFString + /// literals, or 0 if no special section is used. + virtual const char *getCFStringSection() const { + return "__DATA,__cfstring"; + } + + /// getNSStringSection - Return the section to use for NSString + /// literals, or 0 if no special section is used. + virtual const char *getNSStringSection() const { + return "__OBJC,__cstring_object,regular,no_dead_strip"; + } + + /// getNSStringNonFragileABISection - Return the section to use for + /// NSString literals, or 0 if no special section is used (NonFragile ABI). + virtual const char *getNSStringNonFragileABISection() const { + return "__DATA, __objc_stringobj, regular, no_dead_strip"; + } + + /// isValidSectionSpecifier - This is an optional hook that targets can + /// implement to perform semantic checking on attribute((section("foo"))) + /// specifiers. In this case, "foo" is passed in to be checked. If the + /// section specifier is invalid, the backend should return a non-empty string + /// that indicates the problem. + /// + /// This hook is a simple quality of implementation feature to catch errors + /// and give good diagnostics in cases when the assembler or code generator + /// would otherwise reject the section specifier. + /// + virtual std::string isValidSectionSpecifier(StringRef SR) const { + return ""; + } + + /// setForcedLangOptions - Set forced language options. + /// Apply changes to the target information with respect to certain + /// language options which change the target configuration. + virtual void setForcedLangOptions(LangOptions &Opts); + + /// getDefaultFeatures - Get the default set of target features for the CPU; + /// this should include all legal feature strings on the target. + virtual void getDefaultFeatures(llvm::StringMap<bool> &Features) const { + } + + /// getABI - Get the ABI in use. + virtual const char *getABI() const { + return ""; + } + + /// getCXXABI - Get the C++ ABI in use. + virtual TargetCXXABI getCXXABI() const { + return CXXABI; + } + + /// setCPU - Target the specific CPU. + /// + /// \return - False on error (invalid CPU name). + virtual bool setCPU(const std::string &Name) { + return false; + } + + /// setABI - Use the specific ABI. + /// + /// \return - False on error (invalid ABI name). + virtual bool setABI(const std::string &Name) { + return false; + } + + /// setCXXABI - Use this specific C++ ABI. + /// + /// \return - False on error (invalid C++ ABI name). + bool setCXXABI(const std::string &Name) { + static const TargetCXXABI Unknown = static_cast<TargetCXXABI>(-1); + TargetCXXABI ABI = llvm::StringSwitch<TargetCXXABI>(Name) + .Case("arm", CXXABI_ARM) + .Case("itanium", CXXABI_Itanium) + .Case("microsoft", CXXABI_Microsoft) + .Default(Unknown); + if (ABI == Unknown) return false; + return setCXXABI(ABI); + } + + /// setCXXABI - Set the C++ ABI to be used by this implementation. + /// + /// \return - False on error (ABI not valid on this target) + virtual bool setCXXABI(TargetCXXABI ABI) { + CXXABI = ABI; + return true; + } + + /// setFeatureEnabled - Enable or disable a specific target feature, + /// the feature name must be valid. + /// + /// \return - False on error (invalid feature name). + virtual bool setFeatureEnabled(llvm::StringMap<bool> &Features, + StringRef Name, + bool Enabled) const { + return false; + } + + /// HandleTargetOptions - Perform initialization based on the user configured + /// set of features (e.g., +sse4). The list is guaranteed to have at most one + /// entry per feature. + /// + /// The target may modify the features list, to change which options are + /// passed onwards to the backend. + virtual void HandleTargetFeatures(std::vector<std::string> &Features) { + } + + /// \brief Determine whether the given target has the given feature. + virtual bool hasFeature(StringRef Feature) const { + return false; + } + + // getRegParmMax - Returns maximal number of args passed in registers. + unsigned getRegParmMax() const { + assert(RegParmMax < 7 && "RegParmMax value is larger than AST can handle"); + return RegParmMax; + } + + /// isTLSSupported - Whether the target supports thread-local storage. + bool isTLSSupported() const { + return TLSSupported; + } + + /// hasNoAsmVariants - Return true if {|} are normal characters in the + /// asm string. If this returns false (the default), then {abc|xyz} is syntax + /// that says that when compiling for asm variant #0, "abc" should be + /// generated, but when compiling for asm variant #1, "xyz" should be + /// generated. + bool hasNoAsmVariants() const { + return NoAsmVariants; + } + + /// getEHDataRegisterNumber - Return the register number that + /// __builtin_eh_return_regno would return with the specified argument. + virtual int getEHDataRegisterNumber(unsigned RegNo) const { + return -1; + } + + /// getStaticInitSectionSpecifier - Return the section to use for C++ static + /// initialization functions. + virtual const char *getStaticInitSectionSpecifier() const { + return 0; + } + + const LangAS::Map &getAddressSpaceMap() const { + return *AddrSpaceMap; + } + + /// \brief Retrieve the name of the platform as it is used in the + /// availability attribute. + StringRef getPlatformName() const { return PlatformName; } + + /// \brief Retrieve the minimum desired version of the platform, to + /// which the program should be compiled. + VersionTuple getPlatformMinVersion() const { return PlatformMinVersion; } + + bool isBigEndian() const { return BigEndian; } + +protected: + virtual uint64_t getPointerWidthV(unsigned AddrSpace) const { + return PointerWidth; + } + virtual uint64_t getPointerAlignV(unsigned AddrSpace) const { + return PointerAlign; + } + virtual enum IntType getPtrDiffTypeV(unsigned AddrSpace) const { + return PtrDiffType; + } + virtual void getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const = 0; + virtual void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const = 0; + virtual void getGCCAddlRegNames(const AddlRegName *&Addl, + unsigned &NumAddl) const { + Addl = 0; + NumAddl = 0; + } + virtual bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &info) const= 0; +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Basic/TargetOptions.h b/clang/include/clang/Basic/TargetOptions.h new file mode 100644 index 0000000..f3c206f --- /dev/null +++ b/clang/include/clang/Basic/TargetOptions.h @@ -0,0 +1,45 @@ +//===--- TargetOptions.h ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_TARGETOPTIONS_H +#define LLVM_CLANG_FRONTEND_TARGETOPTIONS_H + +#include <string> +#include <vector> + +namespace clang { + +/// TargetOptions - Options for controlling the target. +class TargetOptions { +public: + /// If given, the name of the target triple to compile for. If not given the + /// target will be selected to match the host. + std::string Triple; + + /// If given, the name of the target CPU to generate code for. + std::string CPU; + + /// If given, the name of the target ABI to use. + std::string ABI; + + /// If given, the name of the target C++ ABI to use. If not given, defaults + /// to "itanium". + std::string CXXABI; + + /// If given, the version string of the linker in use. + std::string LinkerVersion; + + /// The list of target specific features to enable or disable -- this should + /// be a list of strings starting with by '+' or '-'. + std::vector<std::string> Features; +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Basic/TemplateKinds.h b/clang/include/clang/Basic/TemplateKinds.h new file mode 100644 index 0000000..c6ea05b --- /dev/null +++ b/clang/include/clang/Basic/TemplateKinds.h @@ -0,0 +1,39 @@ +//===--- TemplateKinds.h - Enum values for C++ Template Kinds ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the TemplateNameKind enum. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_TEMPLATEKINDS_H +#define LLVM_CLANG_TEMPLATEKINDS_H + +namespace clang { + +/// \brief Specifies the kind of template name that an identifier refers to. +enum TemplateNameKind { + /// The name does not refer to a template. + TNK_Non_template = 0, + /// The name refers to a function template or a set of overloaded + /// functions that includes at least one function template. + TNK_Function_template, + /// The name refers to a template whose specialization produces a + /// type. The template itself could be a class template, template + /// template parameter, or C++0x template alias. + TNK_Type_template, + /// The name refers to a dependent template name. Whether the + /// template name is assumed to refer to a type template or a + /// function template depends on the context in which the template + /// name occurs. + TNK_Dependent_template_name +}; + +} +#endif + + diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def new file mode 100644 index 0000000..2e4d34d --- /dev/null +++ b/clang/include/clang/Basic/TokenKinds.def @@ -0,0 +1,596 @@ +//===--- TokenKinds.def - C Family Token Kind Database ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the TokenKind database. This includes normal tokens like +// tok::ampamp (corresponding to the && token) as well as keywords for various +// languages. Users of this file must optionally #define the TOK, KEYWORD, +// ALIAS, or PPKEYWORD macros to make use of this file. +// +//===----------------------------------------------------------------------===// + +#ifndef TOK +#define TOK(X) +#endif +#ifndef PUNCTUATOR +#define PUNCTUATOR(X,Y) TOK(X) +#endif +#ifndef KEYWORD +#define KEYWORD(X,Y) TOK(kw_ ## X) +#endif +#ifndef ALIAS +#define ALIAS(X,Y,Z) +#endif +#ifndef PPKEYWORD +#define PPKEYWORD(X) +#endif +#ifndef CXX_KEYWORD_OPERATOR +#define CXX_KEYWORD_OPERATOR(X,Y) +#endif +#ifndef OBJC1_AT_KEYWORD +#define OBJC1_AT_KEYWORD(X) +#endif +#ifndef OBJC2_AT_KEYWORD +#define OBJC2_AT_KEYWORD(X) +#endif +#ifndef TESTING_KEYWORD +#define TESTING_KEYWORD(X, L) KEYWORD(X, L) +#endif +#ifndef ANNOTATION +#define ANNOTATION(X) TOK(annot_ ## X) +#endif + +//===----------------------------------------------------------------------===// +// Preprocessor keywords. +//===----------------------------------------------------------------------===// + +// These have meaning after a '#' at the start of a line. These define enums in +// the tok::pp_* namespace. Note that IdentifierInfo::getPPKeywordID must be +// manually updated if something is added here. +PPKEYWORD(not_keyword) + +// C99 6.10.1 - Conditional Inclusion. +PPKEYWORD(if) +PPKEYWORD(ifdef) +PPKEYWORD(ifndef) +PPKEYWORD(elif) +PPKEYWORD(else) +PPKEYWORD(endif) +PPKEYWORD(defined) + +// C99 6.10.2 - Source File Inclusion. +PPKEYWORD(include) +PPKEYWORD(__include_macros) + +// C99 6.10.3 - Macro Replacement. +PPKEYWORD(define) +PPKEYWORD(undef) + +// C99 6.10.4 - Line Control. +PPKEYWORD(line) + +// C99 6.10.5 - Error Directive. +PPKEYWORD(error) + +// C99 6.10.6 - Pragma Directive. +PPKEYWORD(pragma) + +// GNU Extensions. +PPKEYWORD(import) +PPKEYWORD(include_next) +PPKEYWORD(warning) +PPKEYWORD(ident) +PPKEYWORD(sccs) +PPKEYWORD(assert) +PPKEYWORD(unassert) + +// Clang extensions +PPKEYWORD(__public_macro) +PPKEYWORD(__private_macro) + +//===----------------------------------------------------------------------===// +// Language keywords. +//===----------------------------------------------------------------------===// + +// These define members of the tok::* namespace. + +TOK(unknown) // Not a token. +TOK(eof) // End of file. +TOK(eod) // End of preprocessing directive (end of line inside a + // directive). +TOK(code_completion) // Code completion marker +TOK(cxx_defaultarg_end) // C++ default argument end marker + +// C99 6.4.9: Comments. +TOK(comment) // Comment (only in -E -C[C] mode) + +// C99 6.4.2: Identifiers. +TOK(identifier) // abcde123 +TOK(raw_identifier) // Used only in raw lexing mode. + +// C99 6.4.4.1: Integer Constants +// C99 6.4.4.2: Floating Constants +TOK(numeric_constant) // 0x123 + +// C99 6.4.4: Character Constants +TOK(char_constant) // 'a' +TOK(wide_char_constant) // L'b' + +// C++0x Character Constants +TOK(utf16_char_constant) // u'a' +TOK(utf32_char_constant) // U'a' + +// C99 6.4.5: String Literals. +TOK(string_literal) // "foo" +TOK(wide_string_literal) // L"foo" +TOK(angle_string_literal)// <foo> + +// C++0x String Literals. +TOK(utf8_string_literal) // u8"foo" +TOK(utf16_string_literal)// u"foo" +TOK(utf32_string_literal)// U"foo" + +// C99 6.4.6: Punctuators. +PUNCTUATOR(l_square, "[") +PUNCTUATOR(r_square, "]") +PUNCTUATOR(l_paren, "(") +PUNCTUATOR(r_paren, ")") +PUNCTUATOR(l_brace, "{") +PUNCTUATOR(r_brace, "}") +PUNCTUATOR(period, ".") +PUNCTUATOR(ellipsis, "...") +PUNCTUATOR(amp, "&") +PUNCTUATOR(ampamp, "&&") +PUNCTUATOR(ampequal, "&=") +PUNCTUATOR(star, "*") +PUNCTUATOR(starequal, "*=") +PUNCTUATOR(plus, "+") +PUNCTUATOR(plusplus, "++") +PUNCTUATOR(plusequal, "+=") +PUNCTUATOR(minus, "-") +PUNCTUATOR(arrow, "->") +PUNCTUATOR(minusminus, "--") +PUNCTUATOR(minusequal, "-=") +PUNCTUATOR(tilde, "~") +PUNCTUATOR(exclaim, "!") +PUNCTUATOR(exclaimequal, "!=") +PUNCTUATOR(slash, "/") +PUNCTUATOR(slashequal, "/=") +PUNCTUATOR(percent, "%") +PUNCTUATOR(percentequal, "%=") +PUNCTUATOR(less, "<") +PUNCTUATOR(lessless, "<<") +PUNCTUATOR(lessequal, "<=") +PUNCTUATOR(lesslessequal, "<<=") +PUNCTUATOR(greater, ">") +PUNCTUATOR(greatergreater, ">>") +PUNCTUATOR(greaterequal, ">=") +PUNCTUATOR(greatergreaterequal, ">>=") +PUNCTUATOR(caret, "^") +PUNCTUATOR(caretequal, "^=") +PUNCTUATOR(pipe, "|") +PUNCTUATOR(pipepipe, "||") +PUNCTUATOR(pipeequal, "|=") +PUNCTUATOR(question, "?") +PUNCTUATOR(colon, ":") +PUNCTUATOR(semi, ";") +PUNCTUATOR(equal, "=") +PUNCTUATOR(equalequal, "==") +PUNCTUATOR(comma, ",") +PUNCTUATOR(hash, "#") +PUNCTUATOR(hashhash, "##") +PUNCTUATOR(hashat, "#@") + +// C++ Support +PUNCTUATOR(periodstar, ".*") +PUNCTUATOR(arrowstar, "->*") +PUNCTUATOR(coloncolon, "::") + +// Objective C support. +PUNCTUATOR(at, "@") + +// CUDA support. +PUNCTUATOR(lesslessless, "<<<") +PUNCTUATOR(greatergreatergreater, ">>>") + +// C99 6.4.1: Keywords. These turn into kw_* tokens. +// Flags allowed: +// KEYALL - This is a keyword in all variants of C and C++, or it +// is a keyword in the implementation namespace that should +// always be treated as a keyword +// KEYC99 - This is a keyword introduced to C in C99 +// KEYC11 - This is a keyword introduced to C in C11 +// KEYCXX - This is a C++ keyword, or a C++-specific keyword in the +// implementation namespace +// KEYNOCXX - This is a keyword in every non-C++ dialect. +// KEYCXX0X - This is a C++ keyword introduced to C++ in C++0x +// KEYGNU - This is a keyword if GNU extensions are enabled +// KEYMS - This is a keyword if Microsoft extensions are enabled +// KEYOPENCL - This is a keyword in OpenCL +// KEYALTIVEC - This is a keyword in AltiVec +// KEYBORLAND - This is a keyword if Borland extensions are enabled +// BOOLSUPPORT - This is a keyword if 'bool' is a built-in type +// +KEYWORD(auto , KEYALL) +KEYWORD(break , KEYALL) +KEYWORD(case , KEYALL) +KEYWORD(char , KEYALL) +KEYWORD(const , KEYALL) +KEYWORD(continue , KEYALL) +KEYWORD(default , KEYALL) +KEYWORD(do , KEYALL) +KEYWORD(double , KEYALL) +KEYWORD(else , KEYALL) +KEYWORD(enum , KEYALL) +KEYWORD(extern , KEYALL) +KEYWORD(float , KEYALL) +KEYWORD(for , KEYALL) +KEYWORD(goto , KEYALL) +KEYWORD(if , KEYALL) +KEYWORD(inline , KEYC99|KEYCXX|KEYGNU) +KEYWORD(int , KEYALL) +KEYWORD(long , KEYALL) +KEYWORD(register , KEYALL) +KEYWORD(restrict , KEYC99) +KEYWORD(return , KEYALL) +KEYWORD(short , KEYALL) +KEYWORD(signed , KEYALL) +KEYWORD(sizeof , KEYALL) +KEYWORD(static , KEYALL) +KEYWORD(struct , KEYALL) +KEYWORD(switch , KEYALL) +KEYWORD(typedef , KEYALL) +KEYWORD(union , KEYALL) +KEYWORD(unsigned , KEYALL) +KEYWORD(void , KEYALL) +KEYWORD(volatile , KEYALL) +KEYWORD(while , KEYALL) +KEYWORD(_Alignas , KEYALL) +KEYWORD(_Atomic , KEYALL) +KEYWORD(_Bool , KEYNOCXX) +KEYWORD(_Complex , KEYALL) +KEYWORD(_Generic , KEYALL) +KEYWORD(_Imaginary , KEYALL) +KEYWORD(_Static_assert , KEYALL) +KEYWORD(__func__ , KEYALL) +KEYWORD(__objc_yes , KEYALL) +KEYWORD(__objc_no , KEYALL) + + +// C++ 2.11p1: Keywords. +KEYWORD(asm , KEYCXX|KEYGNU) +KEYWORD(bool , BOOLSUPPORT|KEYALTIVEC) +KEYWORD(catch , KEYCXX) +KEYWORD(class , KEYCXX) +KEYWORD(const_cast , KEYCXX) +KEYWORD(delete , KEYCXX) +KEYWORD(dynamic_cast , KEYCXX) +KEYWORD(explicit , KEYCXX) +KEYWORD(export , KEYCXX) +KEYWORD(false , BOOLSUPPORT|KEYALTIVEC) +KEYWORD(friend , KEYCXX) +KEYWORD(mutable , KEYCXX) +KEYWORD(namespace , KEYCXX) +KEYWORD(new , KEYCXX) +KEYWORD(operator , KEYCXX) +KEYWORD(private , KEYCXX|KEYOPENCL) +KEYWORD(protected , KEYCXX) +KEYWORD(public , KEYCXX) +KEYWORD(reinterpret_cast , KEYCXX) +KEYWORD(static_cast , KEYCXX) +KEYWORD(template , KEYCXX) +KEYWORD(this , KEYCXX) +KEYWORD(throw , KEYCXX) +KEYWORD(true , BOOLSUPPORT|KEYALTIVEC) +KEYWORD(try , KEYCXX) +KEYWORD(typename , KEYCXX) +KEYWORD(typeid , KEYCXX) +KEYWORD(using , KEYCXX) +KEYWORD(virtual , KEYCXX) +KEYWORD(wchar_t , KEYCXX) + +// C++ 2.5p2: Alternative Representations. +CXX_KEYWORD_OPERATOR(and , ampamp) +CXX_KEYWORD_OPERATOR(and_eq , ampequal) +CXX_KEYWORD_OPERATOR(bitand , amp) +CXX_KEYWORD_OPERATOR(bitor , pipe) +CXX_KEYWORD_OPERATOR(compl , tilde) +CXX_KEYWORD_OPERATOR(not , exclaim) +CXX_KEYWORD_OPERATOR(not_eq , exclaimequal) +CXX_KEYWORD_OPERATOR(or , pipepipe) +CXX_KEYWORD_OPERATOR(or_eq , pipeequal) +CXX_KEYWORD_OPERATOR(xor , caret) +CXX_KEYWORD_OPERATOR(xor_eq , caretequal) + +// C++0x keywords +KEYWORD(alignas , KEYCXX0X) +KEYWORD(alignof , KEYCXX0X) +KEYWORD(char16_t , KEYCXX0X) +KEYWORD(char32_t , KEYCXX0X) +KEYWORD(constexpr , KEYCXX0X) +KEYWORD(decltype , KEYCXX0X) +KEYWORD(noexcept , KEYCXX0X) +KEYWORD(nullptr , KEYCXX0X) +KEYWORD(static_assert , KEYCXX0X) +KEYWORD(thread_local , KEYCXX0X) + +// GNU Extensions (in impl-reserved namespace) +KEYWORD(_Decimal32 , KEYALL) +KEYWORD(_Decimal64 , KEYALL) +KEYWORD(_Decimal128 , KEYALL) +KEYWORD(__null , KEYCXX) +KEYWORD(__alignof , KEYALL) +KEYWORD(__attribute , KEYALL) +KEYWORD(__builtin_choose_expr , KEYALL) +KEYWORD(__builtin_offsetof , KEYALL) +KEYWORD(__builtin_types_compatible_p, KEYALL) +KEYWORD(__builtin_va_arg , KEYALL) +KEYWORD(__extension__ , KEYALL) +KEYWORD(__imag , KEYALL) +KEYWORD(__int128 , KEYALL) +KEYWORD(__label__ , KEYALL) +KEYWORD(__real , KEYALL) +KEYWORD(__thread , KEYALL) +KEYWORD(__FUNCTION__ , KEYALL) +KEYWORD(__PRETTY_FUNCTION__ , KEYALL) + +// GNU Extensions (outside impl-reserved namespace) +KEYWORD(typeof , KEYGNU) + +// GNU and MS Type Traits +KEYWORD(__has_nothrow_assign , KEYCXX) +KEYWORD(__has_nothrow_copy , KEYCXX) +KEYWORD(__has_nothrow_constructor , KEYCXX) +KEYWORD(__has_trivial_assign , KEYCXX) +KEYWORD(__has_trivial_copy , KEYCXX) +KEYWORD(__has_trivial_constructor , KEYCXX) +KEYWORD(__has_trivial_destructor , KEYCXX) +KEYWORD(__has_virtual_destructor , KEYCXX) +KEYWORD(__is_abstract , KEYCXX) +KEYWORD(__is_base_of , KEYCXX) +KEYWORD(__is_class , KEYCXX) +KEYWORD(__is_convertible_to , KEYCXX) +KEYWORD(__is_empty , KEYCXX) +KEYWORD(__is_enum , KEYCXX) +KEYWORD(__is_final , KEYCXX) +// Tentative name - there's no implementation of std::is_literal_type yet. +KEYWORD(__is_literal , KEYCXX) +// Name for GCC 4.6 compatibility - people have already written libraries using +// this name unfortunately. +KEYWORD(__is_literal_type , KEYCXX) +KEYWORD(__is_pod , KEYCXX) +KEYWORD(__is_polymorphic , KEYCXX) +KEYWORD(__is_trivial , KEYCXX) +KEYWORD(__is_union , KEYCXX) + +// Clang-only C++ Type Traits +KEYWORD(__is_trivially_constructible, KEYCXX) +KEYWORD(__is_trivially_copyable , KEYCXX) +KEYWORD(__is_trivially_assignable , KEYCXX) +KEYWORD(__underlying_type , KEYCXX) + +// Embarcadero Expression Traits +KEYWORD(__is_lvalue_expr , KEYCXX) +KEYWORD(__is_rvalue_expr , KEYCXX) + +// Embarcadero Unary Type Traits +KEYWORD(__is_arithmetic , KEYCXX) +KEYWORD(__is_floating_point , KEYCXX) +KEYWORD(__is_integral , KEYCXX) +KEYWORD(__is_complete_type , KEYCXX) +KEYWORD(__is_void , KEYCXX) +KEYWORD(__is_array , KEYCXX) +KEYWORD(__is_function , KEYCXX) +KEYWORD(__is_reference , KEYCXX) +KEYWORD(__is_lvalue_reference , KEYCXX) +KEYWORD(__is_rvalue_reference , KEYCXX) +KEYWORD(__is_fundamental , KEYCXX) +KEYWORD(__is_object , KEYCXX) +KEYWORD(__is_scalar , KEYCXX) +KEYWORD(__is_compound , KEYCXX) +KEYWORD(__is_pointer , KEYCXX) +KEYWORD(__is_member_object_pointer , KEYCXX) +KEYWORD(__is_member_function_pointer, KEYCXX) +KEYWORD(__is_member_pointer , KEYCXX) +KEYWORD(__is_const , KEYCXX) +KEYWORD(__is_volatile , KEYCXX) +KEYWORD(__is_standard_layout , KEYCXX) +KEYWORD(__is_signed , KEYCXX) +KEYWORD(__is_unsigned , KEYCXX) + +// Embarcadero Binary Type Traits +KEYWORD(__is_same , KEYCXX) +KEYWORD(__is_convertible , KEYCXX) +KEYWORD(__array_rank , KEYCXX) +KEYWORD(__array_extent , KEYCXX) + +// Apple Extension. +KEYWORD(__private_extern__ , KEYALL) +KEYWORD(__module_private__ , KEYALL) + +// Microsoft Extension. +KEYWORD(__declspec , KEYALL) +KEYWORD(__cdecl , KEYALL) +KEYWORD(__stdcall , KEYALL) +KEYWORD(__fastcall , KEYALL) +KEYWORD(__thiscall , KEYALL) +KEYWORD(__forceinline , KEYALL) +KEYWORD(__unaligned , KEYMS) + +// OpenCL-specific keywords +KEYWORD(__kernel , KEYOPENCL) +ALIAS("kernel", __kernel , KEYOPENCL) +KEYWORD(vec_step , KEYOPENCL|KEYALTIVEC) +KEYWORD(__private , KEYOPENCL) +KEYWORD(__global , KEYOPENCL) +KEYWORD(__local , KEYOPENCL) +KEYWORD(__constant , KEYOPENCL) +ALIAS("global", __global , KEYOPENCL) +ALIAS("local", __local , KEYOPENCL) +ALIAS("constant", __constant , KEYOPENCL) +KEYWORD(__read_only , KEYOPENCL) +KEYWORD(__write_only , KEYOPENCL) +KEYWORD(__read_write , KEYOPENCL) +ALIAS("read_only", __read_only , KEYOPENCL) +ALIAS("write_only", __write_only , KEYOPENCL) +ALIAS("read_write", __read_write , KEYOPENCL) +KEYWORD(__builtin_astype , KEYOPENCL) + +// Borland Extensions. +KEYWORD(__pascal , KEYALL) + +// Altivec Extension. +KEYWORD(__vector , KEYALTIVEC) +KEYWORD(__pixel , KEYALTIVEC) + +// ARM NEON extensions. +ALIAS("__fp16", half , KEYALL) + +// OpenCL Extension. +KEYWORD(half , KEYOPENCL) + +// Objective-C ARC keywords. +KEYWORD(__bridge , KEYARC) +KEYWORD(__bridge_transfer , KEYARC) +KEYWORD(__bridge_retained , KEYARC) +KEYWORD(__bridge_retain , KEYARC) + +// Alternate spelling for various tokens. There are GCC extensions in all +// languages, but should not be disabled in strict conformance mode. +ALIAS("__alignof__" , __alignof , KEYALL) +ALIAS("__asm" , asm , KEYALL) +ALIAS("__asm__" , asm , KEYALL) +ALIAS("__attribute__", __attribute, KEYALL) +ALIAS("__complex" , _Complex , KEYALL) +ALIAS("__complex__" , _Complex , KEYALL) +ALIAS("__const" , const , KEYALL) +ALIAS("__const__" , const , KEYALL) +ALIAS("__decltype" , decltype , KEYCXX) +ALIAS("__imag__" , __imag , KEYALL) +ALIAS("__inline" , inline , KEYALL) +ALIAS("__inline__" , inline , KEYALL) +ALIAS("__nullptr" , nullptr , KEYCXX) +ALIAS("__real__" , __real , KEYALL) +ALIAS("__restrict" , restrict , KEYALL) +ALIAS("__restrict__" , restrict , KEYALL) +ALIAS("__signed" , signed , KEYALL) +ALIAS("__signed__" , signed , KEYALL) +ALIAS("__typeof" , typeof , KEYALL) +ALIAS("__typeof__" , typeof , KEYALL) +ALIAS("__volatile" , volatile , KEYALL) +ALIAS("__volatile__" , volatile , KEYALL) + +// Microsoft extensions which should be disabled in strict conformance mode +KEYWORD(__ptr64 , KEYMS) +KEYWORD(__ptr32 , KEYMS) +KEYWORD(__w64 , KEYMS) +KEYWORD(__uuidof , KEYMS | KEYBORLAND) +KEYWORD(__try , KEYMS | KEYBORLAND) +KEYWORD(__finally , KEYMS | KEYBORLAND) +KEYWORD(__leave , KEYMS | KEYBORLAND) +KEYWORD(__int64 , KEYMS) +KEYWORD(__if_exists , KEYMS) +KEYWORD(__if_not_exists , KEYMS) +ALIAS("__int8" , char , KEYMS) +ALIAS("__int16" , short , KEYMS) +ALIAS("__int32" , int , KEYMS) +ALIAS("_asm" , asm , KEYMS) +ALIAS("_cdecl" , __cdecl , KEYMS | KEYBORLAND) +ALIAS("_fastcall" , __fastcall , KEYMS | KEYBORLAND) +ALIAS("_stdcall" , __stdcall , KEYMS | KEYBORLAND) +ALIAS("_thiscall" , __thiscall , KEYMS) +ALIAS("_uuidof" , __uuidof , KEYMS | KEYBORLAND) +ALIAS("_inline" , inline , KEYMS) +ALIAS("_declspec" , __declspec , KEYMS) +ALIAS("__interface" , struct , KEYMS) + +// Borland Extensions which should be disabled in strict conformance mode. +ALIAS("_pascal" , __pascal , KEYBORLAND) + +// Clang Extensions. +ALIAS("__char16_t" , char16_t , KEYCXX) +ALIAS("__char32_t" , char32_t , KEYCXX) + +// Clang-specific keywords enabled only in testing. +TESTING_KEYWORD(__unknown_anytype , KEYALL) + + +//===----------------------------------------------------------------------===// +// Objective-C @-preceded keywords. +//===----------------------------------------------------------------------===// + +// These have meaning after an '@' in Objective-C mode. These define enums in +// the tok::objc_* namespace. + +OBJC1_AT_KEYWORD(not_keyword) +OBJC1_AT_KEYWORD(class) +OBJC1_AT_KEYWORD(compatibility_alias) +OBJC1_AT_KEYWORD(defs) +OBJC1_AT_KEYWORD(encode) +OBJC1_AT_KEYWORD(end) +OBJC1_AT_KEYWORD(implementation) +OBJC1_AT_KEYWORD(interface) +OBJC1_AT_KEYWORD(private) +OBJC1_AT_KEYWORD(protected) +OBJC1_AT_KEYWORD(protocol) +OBJC1_AT_KEYWORD(public) +OBJC1_AT_KEYWORD(selector) +OBJC1_AT_KEYWORD(throw) +OBJC1_AT_KEYWORD(try) +OBJC1_AT_KEYWORD(catch) +OBJC1_AT_KEYWORD(finally) +OBJC1_AT_KEYWORD(synchronized) +OBJC1_AT_KEYWORD(autoreleasepool) + +OBJC2_AT_KEYWORD(property) +OBJC2_AT_KEYWORD(package) +OBJC2_AT_KEYWORD(required) +OBJC2_AT_KEYWORD(optional) +OBJC2_AT_KEYWORD(synthesize) +OBJC2_AT_KEYWORD(dynamic) +OBJC2_AT_KEYWORD(__experimental_modules_import) + +// TODO: What to do about context-sensitive keywords like: +// bycopy/byref/in/inout/oneway/out? + +ANNOTATION(cxxscope) // annotation for a C++ scope spec, e.g. "::foo::bar::" +ANNOTATION(typename) // annotation for a C typedef name, a C++ (possibly + // qualified) typename, e.g. "foo::MyClass", or + // template-id that names a type ("std::vector<int>") +ANNOTATION(template_id) // annotation for a C++ template-id that names a + // function template specialization (not a type), + // e.g., "std::swap<int>" +ANNOTATION(primary_expr) // annotation for a primary expression +ANNOTATION(decltype) // annotation for a decltype expression, + // e.g., "decltype(foo.bar())" + +// Annotation for #pragma unused(...) +// For each argument inside the parentheses the pragma handler will produce +// one 'pragma_unused' annotation token followed by the argument token. +ANNOTATION(pragma_unused) + +// Annotation for #pragma GCC visibility... +// The lexer produces these so that they only take effect when the parser +// handles them. +ANNOTATION(pragma_vis) + +// Annotation for #pragma pack... +// The lexer produces these so that they only take effect when the parser +// handles them. +ANNOTATION(pragma_pack) + +#undef ANNOTATION +#undef TESTING_KEYWORD +#undef OBJC2_AT_KEYWORD +#undef OBJC1_AT_KEYWORD +#undef CXX_KEYWORD_OPERATOR +#undef PPKEYWORD +#undef ALIAS +#undef KEYWORD +#undef PUNCTUATOR +#undef TOK diff --git a/clang/include/clang/Basic/TokenKinds.h b/clang/include/clang/Basic/TokenKinds.h new file mode 100644 index 0000000..515390a --- /dev/null +++ b/clang/include/clang/Basic/TokenKinds.h @@ -0,0 +1,70 @@ +//===--- TokenKinds.h - Enum values for C Token Kinds -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the TokenKind enum and support functions. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOKENKINDS_H +#define LLVM_CLANG_TOKENKINDS_H + +namespace clang { + +namespace tok { + +/// TokenKind - This provides a simple uniform namespace for tokens from all C +/// languages. +enum TokenKind { +#define TOK(X) X, +#include "clang/Basic/TokenKinds.def" + NUM_TOKENS +}; + +/// PPKeywordKind - This provides a namespace for preprocessor keywords which +/// start with a '#' at the beginning of the line. +enum PPKeywordKind { +#define PPKEYWORD(X) pp_##X, +#include "clang/Basic/TokenKinds.def" + NUM_PP_KEYWORDS +}; + +/// ObjCKeywordKind - This provides a namespace for Objective-C keywords which +/// start with an '@'. +enum ObjCKeywordKind { +#define OBJC1_AT_KEYWORD(X) objc_##X, +#define OBJC2_AT_KEYWORD(X) objc_##X, +#include "clang/Basic/TokenKinds.def" + NUM_OBJC_KEYWORDS +}; + +/// OnOffSwitch - This defines the possible values of an on-off-switch +/// (C99 6.10.6p2). +enum OnOffSwitch { + OOS_ON, OOS_OFF, OOS_DEFAULT +}; + +/// \brief Determines the name of a token as used within the front end. +/// +/// The name of a token will be an internal name (such as "l_square") +/// and should not be used as part of diagnostic messages. +const char *getTokenName(enum TokenKind Kind); + +/// \brief Determines the spelling of simple punctuation tokens like +/// '!' or '%', and returns NULL for literal and annotation tokens. +/// +/// This routine only retrieves the "simple" spelling of the token, +/// and will not produce any alternative spellings (e.g., a +/// digraph). For the actual spelling of a given Token, use +/// Preprocessor::getSpelling(). +const char *getTokenSimpleSpelling(enum TokenKind Kind); + +} // end namespace tok +} // end namespace clang + +#endif diff --git a/clang/include/clang/Basic/TypeTraits.h b/clang/include/clang/Basic/TypeTraits.h new file mode 100644 index 0000000..721f44f --- /dev/null +++ b/clang/include/clang/Basic/TypeTraits.h @@ -0,0 +1,95 @@ +//===--- TypeTraits.h - C++ Type Traits Support Enumerations ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines enumerations for the type traits support. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TYPETRAITS_H +#define LLVM_CLANG_TYPETRAITS_H + +namespace clang { + + /// UnaryTypeTrait - Names for the unary type traits. + enum UnaryTypeTrait { + UTT_HasNothrowAssign, + UTT_HasNothrowCopy, + UTT_HasNothrowConstructor, + UTT_HasTrivialAssign, + UTT_HasTrivialCopy, + UTT_HasTrivialDefaultConstructor, + UTT_HasTrivialDestructor, + UTT_HasVirtualDestructor, + UTT_IsAbstract, + UTT_IsArithmetic, + UTT_IsArray, + UTT_IsClass, + UTT_IsCompleteType, + UTT_IsCompound, + UTT_IsConst, + UTT_IsEmpty, + UTT_IsEnum, + UTT_IsFinal, + UTT_IsFloatingPoint, + UTT_IsFunction, + UTT_IsFundamental, + UTT_IsIntegral, + UTT_IsLiteral, + UTT_IsLvalueReference, + UTT_IsMemberFunctionPointer, + UTT_IsMemberObjectPointer, + UTT_IsMemberPointer, + UTT_IsObject, + UTT_IsPOD, + UTT_IsPointer, + UTT_IsPolymorphic, + UTT_IsReference, + UTT_IsRvalueReference, + UTT_IsScalar, + UTT_IsSigned, + UTT_IsStandardLayout, + UTT_IsTrivial, + UTT_IsTriviallyCopyable, + UTT_IsUnion, + UTT_IsUnsigned, + UTT_IsVoid, + UTT_IsVolatile + }; + + /// BinaryTypeTrait - Names for the binary type traits. + enum BinaryTypeTrait { + BTT_IsBaseOf, + BTT_IsConvertible, + BTT_IsConvertibleTo, + BTT_IsSame, + BTT_TypeCompatible, + BTT_IsTriviallyAssignable + }; + + /// ArrayTypeTrait - Names for the array type traits. + enum ArrayTypeTrait { + ATT_ArrayRank, + ATT_ArrayExtent + }; + + /// UnaryExprOrTypeTrait - Names for the "expression or type" traits. + enum UnaryExprOrTypeTrait { + UETT_SizeOf, + UETT_AlignOf, + UETT_VecStep + }; + + /// \brief Names for type traits that operate specifically on types. + enum TypeTrait { + TT_IsTriviallyConstructible + }; + +} + +#endif diff --git a/clang/include/clang/Basic/Version.h b/clang/include/clang/Basic/Version.h new file mode 100644 index 0000000..f3f5b5a --- /dev/null +++ b/clang/include/clang/Basic/Version.h @@ -0,0 +1,78 @@ +//===- Version.h - Clang Version Number -------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header defines version macros and version-related utility functions +// for Clang. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_VERSION_H +#define LLVM_CLANG_BASIC_VERSION_H + +#include "llvm/ADT/StringRef.h" + +#include "clang/Basic/Version.inc" + +/// \brief Helper macro for CLANG_VERSION_STRING. +#define CLANG_MAKE_VERSION_STRING2(X) #X + +#ifdef CLANG_VERSION_PATCHLEVEL +/// \brief Helper macro for CLANG_VERSION_STRING. +#define CLANG_MAKE_VERSION_STRING(X,Y,Z) CLANG_MAKE_VERSION_STRING2(X.Y.Z) + +/// \brief A string that describes the Clang version number, e.g., +/// "1.0". +#define CLANG_VERSION_STRING \ + CLANG_MAKE_VERSION_STRING(CLANG_VERSION_MAJOR,CLANG_VERSION_MINOR, \ + CLANG_VERSION_PATCHLEVEL) +#else +/// \brief Helper macro for CLANG_VERSION_STRING. +#define CLANG_MAKE_VERSION_STRING(X,Y) CLANG_MAKE_VERSION_STRING2(X.Y) + +/// \brief A string that describes the Clang version number, e.g., +/// "1.0". +#define CLANG_VERSION_STRING \ + CLANG_MAKE_VERSION_STRING(CLANG_VERSION_MAJOR,CLANG_VERSION_MINOR) +#endif + +namespace clang { + /// \brief Retrieves the repository path (e.g., Subversion path) that + /// identifies the particular Clang branch, tag, or trunk from which this + /// Clang was built. + std::string getClangRepositoryPath(); + + /// \brief Retrieves the repository path from which LLVM was built. Supports + /// LLVM residing in a separate repository from clang. + std::string getLLVMRepositoryPath(); + + /// \brief Retrieves the repository revision number (or identifer) from which + /// this Clang was built. + std::string getClangRevision(); + + /// \brief Retrieves the repository revision number (or identifer) from which + /// LLVM was built. If Clang and LLVM are in the same repository, this returns + /// the same string as getClangRevision. + std::string getLLVMRevision(); + + /// \brief Retrieves the full repository version that is an amalgamation of + /// the information in getClangRepositoryPath() and getClangRevision(). + std::string getClangFullRepositoryVersion(); + + /// \brief Retrieves a string representing the complete clang version, + /// which includes the clang version number, the repository version, + /// and the vendor tag. + std::string getClangFullVersion(); + + /// \brief Retrieves a string representing the complete clang version suitable + /// for use in the CPP __VERSION__ macro, which includes the clang version + /// number, the repository version, and the vendor tag. + std::string getClangFullCPPVersion(); +} + +#endif // LLVM_CLANG_BASIC_VERSION_H diff --git a/clang/include/clang/Basic/Version.inc.in b/clang/include/clang/Basic/Version.inc.in new file mode 100644 index 0000000..ccf8430 --- /dev/null +++ b/clang/include/clang/Basic/Version.inc.in @@ -0,0 +1,6 @@ +#define CLANG_VERSION @CLANG_VERSION@ +#define CLANG_VERSION_MAJOR @CLANG_VERSION_MAJOR@ +#define CLANG_VERSION_MINOR @CLANG_VERSION_MINOR@ +#if @CLANG_HAS_VERSION_PATCHLEVEL@ +#define CLANG_VERSION_PATCHLEVEL @CLANG_VERSION_PATCHLEVEL@ +#endif diff --git a/clang/include/clang/Basic/VersionTuple.h b/clang/include/clang/Basic/VersionTuple.h new file mode 100644 index 0000000..30ef664 --- /dev/null +++ b/clang/include/clang/Basic/VersionTuple.h @@ -0,0 +1,123 @@ +//===- VersionTuple.h - Version Number Handling -----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header defines the VersionTuple class, which represents a version in +// the form major[.minor[.subminor]]. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_BASIC_VERSIONTUPLE_H +#define LLVM_CLANG_BASIC_VERSIONTUPLE_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/Optional.h" +#include <string> + +namespace clang { + +/// \brief Represents a version number in the form major[.minor[.subminor]]. +class VersionTuple { + unsigned Major; + unsigned Minor : 31; + unsigned Subminor : 31; + unsigned HasMinor : 1; + unsigned HasSubminor : 1; + +public: + VersionTuple() + : Major(0), Minor(0), Subminor(0), HasMinor(false), HasSubminor(false) { } + + explicit VersionTuple(unsigned Major) + : Major(Major), Minor(0), Subminor(0), HasMinor(false), HasSubminor(false) + { } + + explicit VersionTuple(unsigned Major, unsigned Minor) + : Major(Major), Minor(Minor), Subminor(0), HasMinor(true), + HasSubminor(false) + { } + + explicit VersionTuple(unsigned Major, unsigned Minor, unsigned Subminor) + : Major(Major), Minor(Minor), Subminor(Subminor), HasMinor(true), + HasSubminor(true) + { } + + /// \brief Determine whether this version information is empty + /// (e.g., all version components are zero). + bool empty() const { return Major == 0 && Minor == 0 && Subminor == 0; } + + /// \brief Retrieve the major version number. + unsigned getMajor() const { return Major; } + + /// \brief Retrieve the minor version number, if provided. + llvm::Optional<unsigned> getMinor() const { + if (!HasMinor) + return llvm::Optional<unsigned>(); + return Minor; + } + + /// \brief Retrieve the subminor version number, if provided. + llvm::Optional<unsigned> getSubminor() const { + if (!HasSubminor) + return llvm::Optional<unsigned>(); + return Subminor; + } + + /// \brief Determine if two version numbers are equivalent. If not + /// provided, minor and subminor version numbers are considered to be zero. + friend bool operator==(const VersionTuple& X, const VersionTuple &Y) { + return X.Major == Y.Major && X.Minor == Y.Minor && X.Subminor == Y.Subminor; + } + + /// \brief Determine if two version numbers are not equivalent. If + /// not provided, minor and subminor version numbers are considered to be + /// zero. + friend bool operator!=(const VersionTuple &X, const VersionTuple &Y) { + return !(X == Y); + } + + /// \brief Determine whether one version number precedes another. If not + /// provided, minor and subminor version numbers are considered to be zero. + friend bool operator<(const VersionTuple &X, const VersionTuple &Y) { + if (X.Major != Y.Major) + return X.Major < Y.Major; + + if (X.Minor != Y.Minor) + return X.Minor < Y.Minor; + + return X.Subminor < Y.Subminor; + } + + /// \brief Determine whether one version number follows another. If not + /// provided, minor and subminor version numbers are considered to be zero. + friend bool operator>(const VersionTuple &X, const VersionTuple &Y) { + return Y < X; + } + + /// \brief Determine whether one version number precedes or is + /// equivalent to another. If not provided, minor and subminor + /// version numbers are considered to be zero. + friend bool operator<=(const VersionTuple &X, const VersionTuple &Y) { + return !(Y < X); + } + + /// \brief Determine whether one version number follows or is + /// equivalent to another. If not provided, minor and subminor + /// version numbers are considered to be zero. + friend bool operator>=(const VersionTuple &X, const VersionTuple &Y) { + return !(X < Y); + } + + /// \brief Retrieve a string representation of the version number/ + std::string getAsString() const; +}; + +/// \brief Print a version number. +raw_ostream& operator<<(raw_ostream &Out, const VersionTuple &V); + +} // end namespace clang +#endif // LLVM_CLANG_BASIC_VERSIONTUPLE_H diff --git a/clang/include/clang/Basic/Visibility.h b/clang/include/clang/Basic/Visibility.h new file mode 100644 index 0000000..90e288a --- /dev/null +++ b/clang/include/clang/Basic/Visibility.h @@ -0,0 +1,48 @@ +//===--- Visibility.h - Visibility enumeration and utilities ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Visibility enumeration and various utility +// functions. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_BASIC_VISIBILITY_H +#define LLVM_CLANG_BASIC_VISIBILITY_H + +namespace clang { + +/// \link Describes the different kinds of visibility that a +/// declaration may have. Visibility determines how a declaration +/// interacts with the dynamic linker. It may also affect whether the +/// symbol can be found by runtime symbol lookup APIs. +/// +/// Visibility is not described in any language standard and +/// (nonetheless) sometimes has odd behavior. Not all platforms +/// support all visibility kinds. +enum Visibility { + /// Objects with "hidden" visibility are not seen by the dynamic + /// linker. + HiddenVisibility, + + /// Objects with "protected" visibility are seen by the dynamic + /// linker but always dynamically resolve to an object within this + /// shared object. + ProtectedVisibility, + + /// Objects with "default" visibility are seen by the dynamic linker + /// and act like normal objects. + DefaultVisibility +}; + +inline Visibility minVisibility(Visibility L, Visibility R) { + return L < R ? L : R; +} + +} + +#endif // LLVM_CLANG_BASIC_VISIBILITY_H diff --git a/clang/include/clang/Basic/arm_neon.td b/clang/include/clang/Basic/arm_neon.td new file mode 100644 index 0000000..71a0aa2 --- /dev/null +++ b/clang/include/clang/Basic/arm_neon.td @@ -0,0 +1,395 @@ +//===--- arm_neon.td - ARM NEON compiler interface ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the TableGen definitions from which the ARM NEON header +// file will be generated. See ARM document DUI0348B. +// +//===----------------------------------------------------------------------===// + +class Op; + +def OP_NONE : Op; +def OP_ADD : Op; +def OP_ADDL : Op; +def OP_ADDW : Op; +def OP_SUB : Op; +def OP_SUBL : Op; +def OP_SUBW : Op; +def OP_MUL : Op; +def OP_MLA : Op; +def OP_MLAL : Op; +def OP_MLS : Op; +def OP_MLSL : Op; +def OP_MUL_N : Op; +def OP_MLA_N : Op; +def OP_MLS_N : Op; +def OP_MLAL_N : Op; +def OP_MLSL_N : Op; +def OP_MUL_LN: Op; +def OP_MULL_LN : Op; +def OP_MLA_LN: Op; +def OP_MLS_LN: Op; +def OP_MLAL_LN : Op; +def OP_MLSL_LN : Op; +def OP_QDMULL_LN : Op; +def OP_QDMLAL_LN : Op; +def OP_QDMLSL_LN : Op; +def OP_QDMULH_LN : Op; +def OP_QRDMULH_LN : Op; +def OP_EQ : Op; +def OP_GE : Op; +def OP_LE : Op; +def OP_GT : Op; +def OP_LT : Op; +def OP_NEG : Op; +def OP_NOT : Op; +def OP_AND : Op; +def OP_OR : Op; +def OP_XOR : Op; +def OP_ANDN : Op; +def OP_ORN : Op; +def OP_CAST : Op; +def OP_HI : Op; +def OP_LO : Op; +def OP_CONC : Op; +def OP_DUP : Op; +def OP_DUP_LN: Op; +def OP_SEL : Op; +def OP_REV64 : Op; +def OP_REV32 : Op; +def OP_REV16 : Op; +def OP_REINT : Op; +def OP_ABDL : Op; +def OP_ABA : Op; +def OP_ABAL : Op; + +class Inst <string n, string p, string t, Op o> { + string Name = n; + string Prototype = p; + string Types = t; + Op Operand = o; + bit isShift = 0; + bit isVCVT_N = 0; +} + +// Used to generate Builtins.def: +// SInst: Instruction with signed/unsigned suffix (e.g., "s8", "u8", "p8") +// IInst: Instruction with generic integer suffix (e.g., "i8") +// WInst: Instruction with only bit size suffix (e.g., "8") +class SInst<string n, string p, string t> : Inst<n, p, t, OP_NONE> {} +class IInst<string n, string p, string t> : Inst<n, p, t, OP_NONE> {} +class WInst<string n, string p, string t> : Inst<n, p, t, OP_NONE> {} + +// prototype: return (arg, arg, ...) +// v: void +// t: best-fit integer (int/poly args) +// x: signed integer (int/float args) +// u: unsigned integer (int/float args) +// f: float (int args) +// d: default +// g: default, ignore 'Q' size modifier. +// w: double width elements, same num elts +// n: double width elements, half num elts +// h: half width elements, double num elts +// e: half width elements, double num elts, unsigned +// i: constant int +// l: constant uint64 +// s: scalar of element type +// a: scalar of element type (splat to vector type) +// k: default elt width, double num elts +// #: array of default vectors +// p: pointer type +// c: const pointer type + +// sizes: +// c: char +// s: short +// i: int +// l: long +// f: float +// h: half-float + +// size modifiers: +// U: unsigned +// Q: 128b +// P: polynomial + +//////////////////////////////////////////////////////////////////////////////// +// E.3.1 Addition +def VADD : Inst<"vadd", "ddd", "csilfUcUsUiUlQcQsQiQlQfQUcQUsQUiQUl", OP_ADD>; +def VADDL : Inst<"vaddl", "wdd", "csiUcUsUi", OP_ADDL>; +def VADDW : Inst<"vaddw", "wwd", "csiUcUsUi", OP_ADDW>; +def VHADD : SInst<"vhadd", "ddd", "csiUcUsUiQcQsQiQUcQUsQUi">; +def VRHADD : SInst<"vrhadd", "ddd", "csiUcUsUiQcQsQiQUcQUsQUi">; +def VQADD : SInst<"vqadd", "ddd", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; +def VADDHN : IInst<"vaddhn", "hkk", "silUsUiUl">; +def VRADDHN : IInst<"vraddhn", "hkk", "silUsUiUl">; + +//////////////////////////////////////////////////////////////////////////////// +// E.3.2 Multiplication +def VMUL : Inst<"vmul", "ddd", "csifUcUsUiQcQsQiQfQUcQUsQUi", OP_MUL>; +def VMULP : SInst<"vmul", "ddd", "PcQPc">; +def VMLA : Inst<"vmla", "dddd", "csifUcUsUiQcQsQiQfQUcQUsQUi", OP_MLA>; +def VMLAL : Inst<"vmlal", "wwdd", "csiUcUsUi", OP_MLAL>; +def VMLS : Inst<"vmls", "dddd", "csifUcUsUiQcQsQiQfQUcQUsQUi", OP_MLS>; +def VMLSL : Inst<"vmlsl", "wwdd", "csiUcUsUi", OP_MLSL>; +def VQDMULH : SInst<"vqdmulh", "ddd", "siQsQi">; +def VQRDMULH : SInst<"vqrdmulh", "ddd", "siQsQi">; +def VQDMLAL : SInst<"vqdmlal", "wwdd", "si">; +def VQDMLSL : SInst<"vqdmlsl", "wwdd", "si">; +def VMULL : SInst<"vmull", "wdd", "csiUcUsUiPc">; +def VQDMULL : SInst<"vqdmull", "wdd", "si">; + +//////////////////////////////////////////////////////////////////////////////// +// E.3.3 Subtraction +def VSUB : Inst<"vsub", "ddd", "csilfUcUsUiUlQcQsQiQlQfQUcQUsQUiQUl", OP_SUB>; +def VSUBL : Inst<"vsubl", "wdd", "csiUcUsUi", OP_SUBL>; +def VSUBW : Inst<"vsubw", "wwd", "csiUcUsUi", OP_SUBW>; +def VQSUB : SInst<"vqsub", "ddd", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; +def VHSUB : SInst<"vhsub", "ddd", "csiUcUsUiQcQsQiQUcQUsQUi">; +def VSUBHN : IInst<"vsubhn", "hkk", "silUsUiUl">; +def VRSUBHN : IInst<"vrsubhn", "hkk", "silUsUiUl">; + +//////////////////////////////////////////////////////////////////////////////// +// E.3.4 Comparison +def VCEQ : Inst<"vceq", "udd", "csifUcUsUiPcQcQsQiQfQUcQUsQUiQPc", OP_EQ>; +def VCGE : Inst<"vcge", "udd", "csifUcUsUiQcQsQiQfQUcQUsQUi", OP_GE>; +def VCLE : Inst<"vcle", "udd", "csifUcUsUiQcQsQiQfQUcQUsQUi", OP_LE>; +def VCGT : Inst<"vcgt", "udd", "csifUcUsUiQcQsQiQfQUcQUsQUi", OP_GT>; +def VCLT : Inst<"vclt", "udd", "csifUcUsUiQcQsQiQfQUcQUsQUi", OP_LT>; +def VCAGE : IInst<"vcage", "udd", "fQf">; +def VCALE : IInst<"vcale", "udd", "fQf">; +def VCAGT : IInst<"vcagt", "udd", "fQf">; +def VCALT : IInst<"vcalt", "udd", "fQf">; +def VTST : WInst<"vtst", "udd", "csiUcUsUiPcQcQsQiQUcQUsQUiQPc">; + +//////////////////////////////////////////////////////////////////////////////// +// E.3.5 Absolute Difference +def VABD : SInst<"vabd", "ddd", "csiUcUsUifQcQsQiQUcQUsQUiQf">; +def VABDL : Inst<"vabdl", "wdd", "csiUcUsUi", OP_ABDL>; +def VABA : Inst<"vaba", "dddd", "csiUcUsUiQcQsQiQUcQUsQUi", OP_ABA>; +def VABAL : Inst<"vabal", "wwdd", "csiUcUsUi", OP_ABAL>; + +//////////////////////////////////////////////////////////////////////////////// +// E.3.6 Max/Min +def VMAX : SInst<"vmax", "ddd", "csiUcUsUifQcQsQiQUcQUsQUiQf">; +def VMIN : SInst<"vmin", "ddd", "csiUcUsUifQcQsQiQUcQUsQUiQf">; + +//////////////////////////////////////////////////////////////////////////////// +// E.3.7 Pairwise Addition +def VPADD : IInst<"vpadd", "ddd", "csiUcUsUif">; +def VPADDL : SInst<"vpaddl", "nd", "csiUcUsUiQcQsQiQUcQUsQUi">; +def VPADAL : SInst<"vpadal", "nnd", "csiUcUsUiQcQsQiQUcQUsQUi">; + +//////////////////////////////////////////////////////////////////////////////// +// E.3.8-9 Folding Max/Min +def VPMAX : SInst<"vpmax", "ddd", "csiUcUsUif">; +def VPMIN : SInst<"vpmin", "ddd", "csiUcUsUif">; + +//////////////////////////////////////////////////////////////////////////////// +// E.3.10 Reciprocal/Sqrt +def VRECPS : IInst<"vrecps", "ddd", "fQf">; +def VRSQRTS : IInst<"vrsqrts", "ddd", "fQf">; + +//////////////////////////////////////////////////////////////////////////////// +// E.3.11 Shifts by signed variable +def VSHL : SInst<"vshl", "ddx", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; +def VQSHL : SInst<"vqshl", "ddx", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; +def VRSHL : SInst<"vrshl", "ddx", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; +def VQRSHL : SInst<"vqrshl", "ddx", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; + +//////////////////////////////////////////////////////////////////////////////// +// E.3.12 Shifts by constant +let isShift = 1 in { +def VSHR_N : SInst<"vshr_n", "ddi", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; +def VSHL_N : IInst<"vshl_n", "ddi", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; +def VRSHR_N : SInst<"vrshr_n", "ddi", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; +def VSRA_N : SInst<"vsra_n", "dddi", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; +def VRSRA_N : SInst<"vrsra_n", "dddi", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; +def VQSHL_N : SInst<"vqshl_n", "ddi", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl">; +def VQSHLU_N : SInst<"vqshlu_n", "udi", "csilQcQsQiQl">; +def VSHRN_N : IInst<"vshrn_n", "hki", "silUsUiUl">; +def VQSHRUN_N : SInst<"vqshrun_n", "eki", "sil">; +def VQRSHRUN_N : SInst<"vqrshrun_n", "eki", "sil">; +def VQSHRN_N : SInst<"vqshrn_n", "hki", "silUsUiUl">; +def VRSHRN_N : IInst<"vrshrn_n", "hki", "silUsUiUl">; +def VQRSHRN_N : SInst<"vqrshrn_n", "hki", "silUsUiUl">; +def VSHLL_N : SInst<"vshll_n", "wdi", "csiUcUsUi">; + +//////////////////////////////////////////////////////////////////////////////// +// E.3.13 Shifts with insert +def VSRI_N : WInst<"vsri_n", "dddi", + "csilUcUsUiUlPcPsQcQsQiQlQUcQUsQUiQUlQPcQPs">; +def VSLI_N : WInst<"vsli_n", "dddi", + "csilUcUsUiUlPcPsQcQsQiQlQUcQUsQUiQUlQPcQPs">; +} + +//////////////////////////////////////////////////////////////////////////////// +// E.3.14 Loads and stores of a single vector +def VLD1 : WInst<"vld1", "dc", + "QUcQUsQUiQUlQcQsQiQlQhQfQPcQPsUcUsUiUlcsilhfPcPs">; +def VLD1_LANE : WInst<"vld1_lane", "dcdi", + "QUcQUsQUiQUlQcQsQiQlQhQfQPcQPsUcUsUiUlcsilhfPcPs">; +def VLD1_DUP : WInst<"vld1_dup", "dc", + "QUcQUsQUiQUlQcQsQiQlQhQfQPcQPsUcUsUiUlcsilhfPcPs">; +def VST1 : WInst<"vst1", "vpd", + "QUcQUsQUiQUlQcQsQiQlQhQfQPcQPsUcUsUiUlcsilhfPcPs">; +def VST1_LANE : WInst<"vst1_lane", "vpdi", + "QUcQUsQUiQUlQcQsQiQlQhQfQPcQPsUcUsUiUlcsilhfPcPs">; + +//////////////////////////////////////////////////////////////////////////////// +// E.3.15 Loads and stores of an N-element structure +def VLD2 : WInst<"vld2", "2c", "QUcQUsQUiQcQsQiQhQfQPcQPsUcUsUiUlcsilhfPcPs">; +def VLD3 : WInst<"vld3", "3c", "QUcQUsQUiQcQsQiQhQfQPcQPsUcUsUiUlcsilhfPcPs">; +def VLD4 : WInst<"vld4", "4c", "QUcQUsQUiQcQsQiQhQfQPcQPsUcUsUiUlcsilhfPcPs">; +def VLD2_DUP : WInst<"vld2_dup", "2c", "UcUsUiUlcsilhfPcPs">; +def VLD3_DUP : WInst<"vld3_dup", "3c", "UcUsUiUlcsilhfPcPs">; +def VLD4_DUP : WInst<"vld4_dup", "4c", "UcUsUiUlcsilhfPcPs">; +def VLD2_LANE : WInst<"vld2_lane", "2c2i", "QUsQUiQsQiQhQfQPsUcUsUicsihfPcPs">; +def VLD3_LANE : WInst<"vld3_lane", "3c3i", "QUsQUiQsQiQhQfQPsUcUsUicsihfPcPs">; +def VLD4_LANE : WInst<"vld4_lane", "4c4i", "QUsQUiQsQiQhQfQPsUcUsUicsihfPcPs">; +def VST2 : WInst<"vst2", "vp2", "QUcQUsQUiQcQsQiQhQfQPcQPsUcUsUiUlcsilhfPcPs">; +def VST3 : WInst<"vst3", "vp3", "QUcQUsQUiQcQsQiQhQfQPcQPsUcUsUiUlcsilhfPcPs">; +def VST4 : WInst<"vst4", "vp4", "QUcQUsQUiQcQsQiQhQfQPcQPsUcUsUiUlcsilhfPcPs">; +def VST2_LANE : WInst<"vst2_lane", "vp2i", "QUsQUiQsQiQhQfQPsUcUsUicsihfPcPs">; +def VST3_LANE : WInst<"vst3_lane", "vp3i", "QUsQUiQsQiQhQfQPsUcUsUicsihfPcPs">; +def VST4_LANE : WInst<"vst4_lane", "vp4i", "QUsQUiQsQiQhQfQPsUcUsUicsihfPcPs">; + +//////////////////////////////////////////////////////////////////////////////// +// E.3.16 Extract lanes from a vector +def VGET_LANE : IInst<"vget_lane", "sdi", + "UcUsUicsiPcPsfQUcQUsQUiQcQsQiQPcQPsQflUlQlQUl">; + +//////////////////////////////////////////////////////////////////////////////// +// E.3.17 Set lanes within a vector +def VSET_LANE : IInst<"vset_lane", "dsdi", + "UcUsUicsiPcPsfQUcQUsQUiQcQsQiQPcQPsQflUlQlQUl">; + +//////////////////////////////////////////////////////////////////////////////// +// E.3.18 Initialize a vector from bit pattern +def VCREATE: Inst<"vcreate", "dl", "csihfUcUsUiUlPcPsl", OP_CAST>; + +//////////////////////////////////////////////////////////////////////////////// +// E.3.19 Set all lanes to same value +def VDUP_N : Inst<"vdup_n", "ds", + "UcUsUicsiPcPsfQUcQUsQUiQcQsQiQPcQPsQflUlQlQUl", OP_DUP>; +def VMOV_N : Inst<"vmov_n", "ds", + "UcUsUicsiPcPsfQUcQUsQUiQcQsQiQPcQPsQflUlQlQUl", OP_DUP>; +def VDUP_LANE : Inst<"vdup_lane", "dgi", + "UcUsUicsiPcPsfQUcQUsQUiQcQsQiQPcQPsQflUlQlQUl",OP_DUP_LN>; + +//////////////////////////////////////////////////////////////////////////////// +// E.3.20 Combining vectors +def VCOMBINE : Inst<"vcombine", "kdd", "csilhfUcUsUiUlPcPs", OP_CONC>; + +//////////////////////////////////////////////////////////////////////////////// +// E.3.21 Splitting vectors +def VGET_HIGH : Inst<"vget_high", "dk", "csilhfUcUsUiUlPcPs", OP_HI>; +def VGET_LOW : Inst<"vget_low", "dk", "csilhfUcUsUiUlPcPs", OP_LO>; + +//////////////////////////////////////////////////////////////////////////////// +// E.3.22 Converting vectors +def VCVT_S32 : SInst<"vcvt_s32", "xd", "fQf">; +def VCVT_U32 : SInst<"vcvt_u32", "ud", "fQf">; +def VCVT_F16 : SInst<"vcvt_f16", "hk", "f">; +def VCVT_F32 : SInst<"vcvt_f32", "fd", "iUiQiQUi">; +def VCVT_F32_F16 : SInst<"vcvt_f32_f16", "fd", "h">; +let isVCVT_N = 1 in { +def VCVT_N_S32 : SInst<"vcvt_n_s32", "xdi", "fQf">; +def VCVT_N_U32 : SInst<"vcvt_n_u32", "udi", "fQf">; +def VCVT_N_F32 : SInst<"vcvt_n_f32", "fdi", "iUiQiQUi">; +} +def VMOVN : IInst<"vmovn", "hk", "silUsUiUl">; +def VMOVL : SInst<"vmovl", "wd", "csiUcUsUi">; +def VQMOVN : SInst<"vqmovn", "hk", "silUsUiUl">; +def VQMOVUN : SInst<"vqmovun", "ek", "sil">; + +//////////////////////////////////////////////////////////////////////////////// +// E.3.23-24 Table lookup, Extended table lookup +def VTBL1 : WInst<"vtbl1", "ddt", "UccPc">; +def VTBL2 : WInst<"vtbl2", "d2t", "UccPc">; +def VTBL3 : WInst<"vtbl3", "d3t", "UccPc">; +def VTBL4 : WInst<"vtbl4", "d4t", "UccPc">; +def VTBX1 : WInst<"vtbx1", "dddt", "UccPc">; +def VTBX2 : WInst<"vtbx2", "dd2t", "UccPc">; +def VTBX3 : WInst<"vtbx3", "dd3t", "UccPc">; +def VTBX4 : WInst<"vtbx4", "dd4t", "UccPc">; + +//////////////////////////////////////////////////////////////////////////////// +// E.3.25 Operations with a scalar value +def VMLA_LANE : Inst<"vmla_lane", "dddgi", "siUsUifQsQiQUsQUiQf", OP_MLA_LN>; +def VMLAL_LANE : Inst<"vmlal_lane", "wwddi", "siUsUi", OP_MLAL_LN>; +def VQDMLAL_LANE : Inst<"vqdmlal_lane", "wwddi", "si", OP_QDMLAL_LN>; +def VMLS_LANE : Inst<"vmls_lane", "dddgi", "siUsUifQsQiQUsQUiQf", OP_MLS_LN>; +def VMLSL_LANE : Inst<"vmlsl_lane", "wwddi", "siUsUi", OP_MLSL_LN>; +def VQDMLSL_LANE : Inst<"vqdmlsl_lane", "wwddi", "si", OP_QDMLSL_LN>; +def VMUL_N : Inst<"vmul_n", "dds", "sifUsUiQsQiQfQUsQUi", OP_MUL_N>; +def VMUL_LANE : Inst<"vmul_lane", "ddgi", "sifUsUiQsQiQfQUsQUi", OP_MUL_LN>; +def VMULL_N : SInst<"vmull_n", "wda", "siUsUi">; +def VMULL_LANE : Inst<"vmull_lane", "wddi", "siUsUi", OP_MULL_LN>; +def VQDMULL_N : SInst<"vqdmull_n", "wda", "si">; +def VQDMULL_LANE : Inst<"vqdmull_lane", "wddi", "si", OP_QDMULL_LN>; +def VQDMULH_N : SInst<"vqdmulh_n", "dda", "siQsQi">; +def VQDMULH_LANE : Inst<"vqdmulh_lane", "ddgi", "siQsQi", OP_QDMULH_LN>; +def VQRDMULH_N : SInst<"vqrdmulh_n", "dda", "siQsQi">; +def VQRDMULH_LANE : Inst<"vqrdmulh_lane", "ddgi", "siQsQi", OP_QRDMULH_LN>; +def VMLA_N : Inst<"vmla_n", "ddda", "siUsUifQsQiQUsQUiQf", OP_MLA_N>; +def VMLAL_N : Inst<"vmlal_n", "wwda", "siUsUi", OP_MLAL_N>; +def VQDMLAL_N : SInst<"vqdmlal_n", "wwda", "si">; +def VMLS_N : Inst<"vmls_n", "ddds", "siUsUifQsQiQUsQUiQf", OP_MLS_N>; +def VMLSL_N : Inst<"vmlsl_n", "wwda", "siUsUi", OP_MLSL_N>; +def VQDMLSL_N : SInst<"vqdmlsl_n", "wwda", "si">; + +//////////////////////////////////////////////////////////////////////////////// +// E.3.26 Vector Extract +def VEXT : WInst<"vext", "dddi", + "cUcPcsUsPsiUilUlfQcQUcQPcQsQUsQPsQiQUiQlQUlQf">; + +//////////////////////////////////////////////////////////////////////////////// +// E.3.27 Reverse vector elements +def VREV64 : Inst<"vrev64", "dd", "csiUcUsUiPcPsfQcQsQiQUcQUsQUiQPcQPsQf", + OP_REV64>; +def VREV32 : Inst<"vrev32", "dd", "csUcUsPcPsQcQsQUcQUsQPcQPs", OP_REV32>; +def VREV16 : Inst<"vrev16", "dd", "cUcPcQcQUcQPc", OP_REV16>; + +//////////////////////////////////////////////////////////////////////////////// +// E.3.28 Other single operand arithmetic +def VABS : SInst<"vabs", "dd", "csifQcQsQiQf">; +def VQABS : SInst<"vqabs", "dd", "csiQcQsQi">; +def VNEG : Inst<"vneg", "dd", "csifQcQsQiQf", OP_NEG>; +def VQNEG : SInst<"vqneg", "dd", "csiQcQsQi">; +def VCLS : SInst<"vcls", "dd", "csiQcQsQi">; +def VCLZ : IInst<"vclz", "dd", "csiUcUsUiQcQsQiQUcQUsQUi">; +def VCNT : WInst<"vcnt", "dd", "UccPcQUcQcQPc">; +def VRECPE : SInst<"vrecpe", "dd", "fUiQfQUi">; +def VRSQRTE : SInst<"vrsqrte", "dd", "fUiQfQUi">; + +//////////////////////////////////////////////////////////////////////////////// +// E.3.29 Logical operations +def VMVN : Inst<"vmvn", "dd", "csiUcUsUiPcQcQsQiQUcQUsQUiQPc", OP_NOT>; +def VAND : Inst<"vand", "ddd", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl", OP_AND>; +def VORR : Inst<"vorr", "ddd", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl", OP_OR>; +def VEOR : Inst<"veor", "ddd", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl", OP_XOR>; +def VBIC : Inst<"vbic", "ddd", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl", OP_ANDN>; +def VORN : Inst<"vorn", "ddd", "csilUcUsUiUlQcQsQiQlQUcQUsQUiQUl", OP_ORN>; +def VBSL : Inst<"vbsl", "dudd", + "csilUcUsUiUlfPcPsQcQsQiQlQUcQUsQUiQUlQfQPcQPs", OP_SEL>; + +//////////////////////////////////////////////////////////////////////////////// +// E.3.30 Transposition operations +def VTRN : WInst<"vtrn", "2dd", "csiUcUsUifPcPsQcQsQiQUcQUsQUiQfQPcQPs">; +def VZIP : WInst<"vzip", "2dd", "csiUcUsUifPcPsQcQsQiQUcQUsQUiQfQPcQPs">; +def VUZP : WInst<"vuzp", "2dd", "csiUcUsUifPcPsQcQsQiQUcQUsQUiQfQPcQPs">; + +//////////////////////////////////////////////////////////////////////////////// +// E.3.31 Vector reinterpret cast operations +def VREINTERPRET + : Inst<"vreinterpret", "dd", + "csilUcUsUiUlhfPcPsQcQsQiQlQUcQUsQUiQUlQhQfQPcQPs", OP_REINT>; + diff --git a/clang/include/clang/CMakeLists.txt b/clang/include/clang/CMakeLists.txt new file mode 100644 index 0000000..71c37fd --- /dev/null +++ b/clang/include/clang/CMakeLists.txt @@ -0,0 +1,7 @@ +add_subdirectory(AST) +add_subdirectory(Basic) +add_subdirectory(Driver) +add_subdirectory(Lex) +add_subdirectory(Parse) +add_subdirectory(Sema) +add_subdirectory(Serialization) diff --git a/clang/include/clang/CodeGen/BackendUtil.h b/clang/include/clang/CodeGen/BackendUtil.h new file mode 100644 index 0000000..135b6a9 --- /dev/null +++ b/clang/include/clang/CodeGen/BackendUtil.h @@ -0,0 +1,40 @@ +//===--- BackendUtil.h - LLVM Backend Utilities -----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_CODEGEN_BACKEND_UTIL_H +#define LLVM_CLANG_CODEGEN_BACKEND_UTIL_H + +#include "clang/Basic/LLVM.h" + +namespace llvm { + class Module; +} + +namespace clang { + class DiagnosticsEngine; + class CodeGenOptions; + class TargetOptions; + class LangOptions; + + enum BackendAction { + Backend_EmitAssembly, ///< Emit native assembly files + Backend_EmitBC, ///< Emit LLVM bitcode files + Backend_EmitLL, ///< Emit human-readable LLVM assembly + Backend_EmitNothing, ///< Don't emit anything (benchmarking mode) + Backend_EmitMCNull, ///< Run CodeGen, but don't emit anything + Backend_EmitObj ///< Emit native object files + }; + + void EmitBackendOutput(DiagnosticsEngine &Diags, const CodeGenOptions &CGOpts, + const TargetOptions &TOpts, const LangOptions &LOpts, + llvm::Module *M, + BackendAction Action, raw_ostream *OS); +} + +#endif diff --git a/clang/include/clang/CodeGen/CodeGenAction.h b/clang/include/clang/CodeGen/CodeGenAction.h new file mode 100644 index 0000000..7fa589f --- /dev/null +++ b/clang/include/clang/CodeGen/CodeGenAction.h @@ -0,0 +1,103 @@ +//===--- CodeGenAction.h - LLVM Code Generation Frontend Action -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_CODEGEN_CODE_GEN_ACTION_H +#define LLVM_CLANG_CODEGEN_CODE_GEN_ACTION_H + +#include "clang/Frontend/FrontendAction.h" +#include "llvm/ADT/OwningPtr.h" + +namespace llvm { + class LLVMContext; + class Module; +} + +namespace clang { +class BackendConsumer; + +class CodeGenAction : public ASTFrontendAction { +private: + unsigned Act; + OwningPtr<llvm::Module> TheModule; + llvm::Module *LinkModule; + llvm::LLVMContext *VMContext; + bool OwnsVMContext; + +protected: + /// Create a new code generation action. If the optional \arg _VMContext + /// parameter is supplied, the action uses it without taking ownership, + /// otherwise it creates a fresh LLVM context and takes ownership. + CodeGenAction(unsigned _Act, llvm::LLVMContext *_VMContext = 0); + + virtual bool hasIRSupport() const; + + virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, + StringRef InFile); + + virtual void ExecuteAction(); + + virtual void EndSourceFileAction(); + +public: + ~CodeGenAction(); + + /// setLinkModule - Set the link module to be used by this action. If a link + /// module is not provided, and CodeGenOptions::LinkBitcodeFile is non-empty, + /// the action will load it from the specified file. + void setLinkModule(llvm::Module *Mod) { LinkModule = Mod; } + + /// takeModule - Take the generated LLVM module, for use after the action has + /// been run. The result may be null on failure. + llvm::Module *takeModule(); + + /// Take the LLVM context used by this action. + llvm::LLVMContext *takeLLVMContext(); + + BackendConsumer *BEConsumer; +}; + +class EmitAssemblyAction : public CodeGenAction { + virtual void anchor(); +public: + EmitAssemblyAction(llvm::LLVMContext *_VMContext = 0); +}; + +class EmitBCAction : public CodeGenAction { + virtual void anchor(); +public: + EmitBCAction(llvm::LLVMContext *_VMContext = 0); +}; + +class EmitLLVMAction : public CodeGenAction { + virtual void anchor(); +public: + EmitLLVMAction(llvm::LLVMContext *_VMContext = 0); +}; + +class EmitLLVMOnlyAction : public CodeGenAction { + virtual void anchor(); +public: + EmitLLVMOnlyAction(llvm::LLVMContext *_VMContext = 0); +}; + +class EmitCodeGenOnlyAction : public CodeGenAction { + virtual void anchor(); +public: + EmitCodeGenOnlyAction(llvm::LLVMContext *_VMContext = 0); +}; + +class EmitObjAction : public CodeGenAction { + virtual void anchor(); +public: + EmitObjAction(llvm::LLVMContext *_VMContext = 0); +}; + +} + +#endif diff --git a/clang/include/clang/CodeGen/ModuleBuilder.h b/clang/include/clang/CodeGen/ModuleBuilder.h new file mode 100644 index 0000000..ba9d1f9 --- /dev/null +++ b/clang/include/clang/CodeGen/ModuleBuilder.h @@ -0,0 +1,46 @@ +//===--- CodeGen/ModuleBuilder.h - Build LLVM from ASTs ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ModuleBuilder interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_CODEGEN_MODULEBUILDER_H +#define LLVM_CLANG_CODEGEN_MODULEBUILDER_H + +#include "clang/AST/ASTConsumer.h" +#include <string> + +namespace llvm { + class LLVMContext; + class Module; +} + +namespace clang { + class DiagnosticsEngine; + class LangOptions; + class CodeGenOptions; + + class CodeGenerator : public ASTConsumer { + virtual void anchor(); + public: + virtual llvm::Module* GetModule() = 0; + virtual llvm::Module* ReleaseModule() = 0; + }; + + /// CreateLLVMCodeGen - Create a CodeGenerator instance. + /// It is the responsibility of the caller to call delete on + /// the allocated CodeGenerator instance. + CodeGenerator *CreateLLVMCodeGen(DiagnosticsEngine &Diags, + const std::string &ModuleName, + const CodeGenOptions &CGO, + llvm::LLVMContext& C); +} + +#endif diff --git a/clang/include/clang/Config/config.h.cmake b/clang/include/clang/Config/config.h.cmake new file mode 100644 index 0000000..c18c4cc --- /dev/null +++ b/clang/include/clang/Config/config.h.cmake @@ -0,0 +1,14 @@ +/* Bug report URL. */ +#define BUG_REPORT_URL "${BUG_REPORT_URL}" + +/* Relative directory for resource files */ +#define CLANG_RESOURCE_DIR "${CLANG_RESOURCE_DIR}" + +/* Directories clang will search for headers */ +#define C_INCLUDE_DIRS "${C_INCLUDE_DIRS}" + +/* Default <path> to all compiler invocations for --sysroot=<path>. */ +#define DEFAULT_SYSROOT "${DEFAULT_SYSROOT}" + +/* Directory where gcc is installed. */ +#define GCC_INSTALL_PREFIX "${GCC_INSTALL_PREFIX}" diff --git a/clang/include/clang/Config/config.h.in b/clang/include/clang/Config/config.h.in new file mode 100644 index 0000000..8ff9417 --- /dev/null +++ b/clang/include/clang/Config/config.h.in @@ -0,0 +1,24 @@ +/* include/clang/Config/config.h.in. */ + +#ifndef CONFIG_H +#define CONFIG_H + +/* Bug report URL. */ +#undef BUG_REPORT_URL + +/* Relative directory for resource files */ +#undef CLANG_RESOURCE_DIR + +/* Directories clang will search for headers */ +#undef C_INCLUDE_DIRS + +/* Linker version detected at compile time. */ +#undef HOST_LINK_VERSION + +/* Default <path> to all compiler invocations for --sysroot=<path>. */ +#undef DEFAULT_SYSROOT + +/* Directory where gcc is installed. */ +#undef GCC_INSTALL_PREFIX + +#endif diff --git a/clang/include/clang/Driver/Action.h b/clang/include/clang/Driver/Action.h new file mode 100644 index 0000000..6e317a0 --- /dev/null +++ b/clang/include/clang/Driver/Action.h @@ -0,0 +1,254 @@ +//===--- Action.h - Abstract compilation steps ------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_DRIVER_ACTION_H_ +#define CLANG_DRIVER_ACTION_H_ + +#include "clang/Driver/Types.h" +#include "clang/Driver/Util.h" +#include "llvm/ADT/SmallVector.h" + +namespace clang { +namespace driver { + class Arg; + +/// Action - Represent an abstract compilation step to perform. +/// +/// An action represents an edge in the compilation graph; typically +/// it is a job to transform an input using some tool. +/// +/// The current driver is hard wired to expect actions which produce a +/// single primary output, at least in terms of controlling the +/// compilation. Actions can produce auxiliary files, but can only +/// produce a single output to feed into subsequent actions. +class Action { +public: + typedef ActionList::size_type size_type; + typedef ActionList::iterator iterator; + typedef ActionList::const_iterator const_iterator; + + enum ActionClass { + InputClass = 0, + BindArchClass, + PreprocessJobClass, + PrecompileJobClass, + AnalyzeJobClass, + MigrateJobClass, + CompileJobClass, + AssembleJobClass, + LinkJobClass, + LipoJobClass, + DsymutilJobClass, + VerifyJobClass, + + JobClassFirst=PreprocessJobClass, + JobClassLast=VerifyJobClass + }; + + static const char *getClassName(ActionClass AC); + +private: + ActionClass Kind; + + /// The output type of this action. + types::ID Type; + + ActionList Inputs; + + unsigned OwnsInputs : 1; + +protected: + Action(ActionClass _Kind, types::ID _Type) + : Kind(_Kind), Type(_Type), OwnsInputs(true) {} + Action(ActionClass _Kind, Action *Input, types::ID _Type) + : Kind(_Kind), Type(_Type), Inputs(&Input, &Input + 1), OwnsInputs(true) {} + Action(ActionClass _Kind, const ActionList &_Inputs, types::ID _Type) + : Kind(_Kind), Type(_Type), Inputs(_Inputs), OwnsInputs(true) {} +public: + virtual ~Action(); + + const char *getClassName() const { return Action::getClassName(getKind()); } + + bool getOwnsInputs() { return OwnsInputs; } + void setOwnsInputs(bool Value) { OwnsInputs = Value; } + + ActionClass getKind() const { return Kind; } + types::ID getType() const { return Type; } + + ActionList &getInputs() { return Inputs; } + const ActionList &getInputs() const { return Inputs; } + + size_type size() const { return Inputs.size(); } + + iterator begin() { return Inputs.begin(); } + iterator end() { return Inputs.end(); } + const_iterator begin() const { return Inputs.begin(); } + const_iterator end() const { return Inputs.end(); } + + static bool classof(const Action *) { return true; } +}; + +class InputAction : public Action { + virtual void anchor(); + const Arg &Input; +public: + InputAction(const Arg &_Input, types::ID _Type); + + const Arg &getInputArg() const { return Input; } + + static bool classof(const Action *A) { + return A->getKind() == InputClass; + } + static bool classof(const InputAction *) { return true; } +}; + +class BindArchAction : public Action { + virtual void anchor(); + /// The architecture to bind, or 0 if the default architecture + /// should be bound. + const char *ArchName; + +public: + BindArchAction(Action *Input, const char *_ArchName); + + const char *getArchName() const { return ArchName; } + + static bool classof(const Action *A) { + return A->getKind() == BindArchClass; + } + static bool classof(const BindArchAction *) { return true; } +}; + +class JobAction : public Action { + virtual void anchor(); +protected: + JobAction(ActionClass Kind, Action *Input, types::ID Type); + JobAction(ActionClass Kind, const ActionList &Inputs, types::ID Type); + +public: + static bool classof(const Action *A) { + return (A->getKind() >= JobClassFirst && + A->getKind() <= JobClassLast); + } + static bool classof(const JobAction *) { return true; } +}; + +class PreprocessJobAction : public JobAction { + virtual void anchor(); +public: + PreprocessJobAction(Action *Input, types::ID OutputType); + + static bool classof(const Action *A) { + return A->getKind() == PreprocessJobClass; + } + static bool classof(const PreprocessJobAction *) { return true; } +}; + +class PrecompileJobAction : public JobAction { + virtual void anchor(); +public: + PrecompileJobAction(Action *Input, types::ID OutputType); + + static bool classof(const Action *A) { + return A->getKind() == PrecompileJobClass; + } + static bool classof(const PrecompileJobAction *) { return true; } +}; + +class AnalyzeJobAction : public JobAction { + virtual void anchor(); +public: + AnalyzeJobAction(Action *Input, types::ID OutputType); + + static bool classof(const Action *A) { + return A->getKind() == AnalyzeJobClass; + } + static bool classof(const AnalyzeJobAction *) { return true; } +}; + +class MigrateJobAction : public JobAction { + virtual void anchor(); +public: + MigrateJobAction(Action *Input, types::ID OutputType); + + static bool classof(const Action *A) { + return A->getKind() == MigrateJobClass; + } + static bool classof(const MigrateJobAction *) { return true; } +}; + +class CompileJobAction : public JobAction { + virtual void anchor(); +public: + CompileJobAction(Action *Input, types::ID OutputType); + + static bool classof(const Action *A) { + return A->getKind() == CompileJobClass; + } + static bool classof(const CompileJobAction *) { return true; } +}; + +class AssembleJobAction : public JobAction { + virtual void anchor(); +public: + AssembleJobAction(Action *Input, types::ID OutputType); + + static bool classof(const Action *A) { + return A->getKind() == AssembleJobClass; + } + static bool classof(const AssembleJobAction *) { return true; } +}; + +class LinkJobAction : public JobAction { + virtual void anchor(); +public: + LinkJobAction(ActionList &Inputs, types::ID Type); + + static bool classof(const Action *A) { + return A->getKind() == LinkJobClass; + } + static bool classof(const LinkJobAction *) { return true; } +}; + +class LipoJobAction : public JobAction { + virtual void anchor(); +public: + LipoJobAction(ActionList &Inputs, types::ID Type); + + static bool classof(const Action *A) { + return A->getKind() == LipoJobClass; + } + static bool classof(const LipoJobAction *) { return true; } +}; + +class DsymutilJobAction : public JobAction { + virtual void anchor(); +public: + DsymutilJobAction(ActionList &Inputs, types::ID Type); + + static bool classof(const Action *A) { + return A->getKind() == DsymutilJobClass; + } + static bool classof(const DsymutilJobAction *) { return true; } +}; + +class VerifyJobAction : public JobAction { + virtual void anchor(); +public: + VerifyJobAction(ActionList &Inputs, types::ID Type); + static bool classof(const Action *A) { + return A->getKind() == VerifyJobClass; + } + static bool classof(const VerifyJobAction *) { return true; } +}; + +} // end namespace driver +} // end namespace clang + +#endif diff --git a/clang/include/clang/Driver/Arg.h b/clang/include/clang/Driver/Arg.h new file mode 100644 index 0000000..e8625bb --- /dev/null +++ b/clang/include/clang/Driver/Arg.h @@ -0,0 +1,122 @@ +//===--- Arg.h - Parsed Argument Classes ------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_DRIVER_ARG_H_ +#define CLANG_DRIVER_ARG_H_ + +#include "Util.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include <string> + +namespace clang { +namespace driver { + class ArgList; + class Option; + + /// Arg - A concrete instance of a particular driver option. + /// + /// The Arg class encodes just enough information to be able to + /// derive the argument values efficiently. In addition, Arg + /// instances have an intrusive double linked list which is used by + /// ArgList to provide efficient iteration over all instances of a + /// particular option. + class Arg { + Arg(const Arg &); // DO NOT IMPLEMENT + void operator=(const Arg &); // DO NOT IMPLEMENT + + private: + /// The option this argument is an instance of. + const Option *Opt; + + /// The argument this argument was derived from (during tool chain + /// argument translation), if any. + const Arg *BaseArg; + + /// The index at which this argument appears in the containing + /// ArgList. + unsigned Index; + + /// Was this argument used to effect compilation; used for generating + /// "argument unused" diagnostics. + mutable unsigned Claimed : 1; + + /// Does this argument own its values. + mutable unsigned OwnsValues : 1; + + /// The argument values, as C strings. + SmallVector<const char *, 2> Values; + + public: + Arg(const Option *Opt, unsigned Index, const Arg *BaseArg = 0); + Arg(const Option *Opt, unsigned Index, + const char *Value0, const Arg *BaseArg = 0); + Arg(const Option *Opt, unsigned Index, + const char *Value0, const char *Value1, const Arg *BaseArg = 0); + ~Arg(); + + const Option &getOption() const { return *Opt; } + unsigned getIndex() const { return Index; } + + /// getBaseArg - Return the base argument which generated this + /// arg; this is either the argument itself or the argument it was + /// derived from during tool chain specific argument translation. + const Arg &getBaseArg() const { + return BaseArg ? *BaseArg : *this; + } + void setBaseArg(const Arg *_BaseArg) { + BaseArg = _BaseArg; + } + + bool getOwnsValues() const { return OwnsValues; } + void setOwnsValues(bool Value) const { OwnsValues = Value; } + + bool isClaimed() const { return getBaseArg().Claimed; } + + /// claim - Set the Arg claimed bit. + void claim() const { getBaseArg().Claimed = true; } + + unsigned getNumValues() const { return Values.size(); } + const char *getValue(const ArgList &Args, unsigned N=0) const { + return Values[N]; + } + + SmallVectorImpl<const char*> &getValues() { + return Values; + } + + bool containsValue(StringRef Value) const { + for (unsigned i = 0, e = getNumValues(); i != e; ++i) + if (Values[i] == Value) + return true; + return false; + } + + /// render - Append the argument onto the given array as strings. + void render(const ArgList &Args, ArgStringList &Output) const; + + /// renderAsInput - Append the argument, render as an input, onto + /// the given array as strings. The distinction is that some + /// options only render their values when rendered as a input + /// (e.g., Xlinker). + void renderAsInput(const ArgList &Args, ArgStringList &Output) const; + + static bool classof(const Arg *) { return true; } + + void dump() const; + + /// getAsString - Return a formatted version of the argument and + /// its values, for debugging and diagnostics. + std::string getAsString(const ArgList &Args) const; + }; + +} // end namespace driver +} // end namespace clang + +#endif diff --git a/clang/include/clang/Driver/ArgList.h b/clang/include/clang/Driver/ArgList.h new file mode 100644 index 0000000..3affb00 --- /dev/null +++ b/clang/include/clang/Driver/ArgList.h @@ -0,0 +1,426 @@ +//===--- ArgList.h - Argument List Management ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_DRIVER_ARGLIST_H_ +#define CLANG_DRIVER_ARGLIST_H_ + +#include "clang/Basic/LLVM.h" +#include "clang/Driver/OptSpecifier.h" +#include "clang/Driver/Util.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" + +#include <list> +#include <string> +#include <vector> + +namespace clang { + class DiagnosticsEngine; + +namespace driver { + class Arg; + class ArgList; + class Option; + + /// arg_iterator - Iterates through arguments stored inside an ArgList. + class arg_iterator { + /// The current argument. + SmallVectorImpl<Arg*>::const_iterator Current; + + /// The argument list we are iterating over. + const ArgList &Args; + + /// Optional filters on the arguments which will be match. Most clients + /// should never want to iterate over arguments without filters, so we won't + /// bother to factor this into two separate iterator implementations. + // + // FIXME: Make efficient; the idea is to provide efficient iteration over + // all arguments which match a particular id and then just provide an + // iterator combinator which takes multiple iterators which can be + // efficiently compared and returns them in order. + OptSpecifier Id0, Id1, Id2; + + void SkipToNextArg(); + + public: + typedef Arg * const * value_type; + typedef Arg * const & reference; + typedef Arg * const * pointer; + typedef std::forward_iterator_tag iterator_category; + typedef std::ptrdiff_t difference_type; + + arg_iterator(SmallVectorImpl<Arg*>::const_iterator it, + const ArgList &_Args, OptSpecifier _Id0 = 0U, + OptSpecifier _Id1 = 0U, OptSpecifier _Id2 = 0U) + : Current(it), Args(_Args), Id0(_Id0), Id1(_Id1), Id2(_Id2) { + SkipToNextArg(); + } + + operator const Arg*() { return *Current; } + reference operator*() const { return *Current; } + pointer operator->() const { return Current; } + + arg_iterator &operator++() { + ++Current; + SkipToNextArg(); + return *this; + } + + arg_iterator operator++(int) { + arg_iterator tmp(*this); + ++(*this); + return tmp; + } + + friend bool operator==(arg_iterator LHS, arg_iterator RHS) { + return LHS.Current == RHS.Current; + } + friend bool operator!=(arg_iterator LHS, arg_iterator RHS) { + return !(LHS == RHS); + } + }; + + /// ArgList - Ordered collection of driver arguments. + /// + /// The ArgList class manages a list of Arg instances as well as + /// auxiliary data and convenience methods to allow Tools to quickly + /// check for the presence of Arg instances for a particular Option + /// and to iterate over groups of arguments. + class ArgList { + private: + ArgList(const ArgList &); // DO NOT IMPLEMENT + void operator=(const ArgList &); // DO NOT IMPLEMENT + + public: + typedef SmallVector<Arg*, 16> arglist_type; + typedef arglist_type::iterator iterator; + typedef arglist_type::const_iterator const_iterator; + typedef arglist_type::reverse_iterator reverse_iterator; + typedef arglist_type::const_reverse_iterator const_reverse_iterator; + + private: + /// The internal list of arguments. + arglist_type Args; + + protected: + ArgList(); + + public: + virtual ~ArgList(); + + /// @name Arg Access + /// @{ + + /// append - Append \arg A to the arg list. + void append(Arg *A); + + arglist_type &getArgs() { return Args; } + const arglist_type &getArgs() const { return Args; } + + unsigned size() const { return Args.size(); } + + /// @} + /// @name Arg Iteration + /// @{ + + iterator begin() { return Args.begin(); } + iterator end() { return Args.end(); } + + reverse_iterator rbegin() { return Args.rbegin(); } + reverse_iterator rend() { return Args.rend(); } + + const_iterator begin() const { return Args.begin(); } + const_iterator end() const { return Args.end(); } + + const_reverse_iterator rbegin() const { return Args.rbegin(); } + const_reverse_iterator rend() const { return Args.rend(); } + + arg_iterator filtered_begin(OptSpecifier Id0 = 0U, OptSpecifier Id1 = 0U, + OptSpecifier Id2 = 0U) const { + return arg_iterator(Args.begin(), *this, Id0, Id1, Id2); + } + arg_iterator filtered_end() const { + return arg_iterator(Args.end(), *this); + } + + /// @} + /// @name Arg Removal + /// @{ + + /// eraseArg - Remove any option matching \arg Id. + void eraseArg(OptSpecifier Id); + + /// @} + /// @name Arg Access + /// @{ + + /// hasArg - Does the arg list contain any option matching \arg Id. + /// + /// \arg Claim Whether the argument should be claimed, if it exists. + bool hasArgNoClaim(OptSpecifier Id) const { + return getLastArgNoClaim(Id) != 0; + } + bool hasArg(OptSpecifier Id) const { + return getLastArg(Id) != 0; + } + bool hasArg(OptSpecifier Id0, OptSpecifier Id1) const { + return getLastArg(Id0, Id1) != 0; + } + bool hasArg(OptSpecifier Id0, OptSpecifier Id1, OptSpecifier Id2) const { + return getLastArg(Id0, Id1, Id2) != 0; + } + + /// getLastArg - Return the last argument matching \arg Id, or null. + /// + /// \arg Claim Whether the argument should be claimed, if it exists. + Arg *getLastArgNoClaim(OptSpecifier Id) const; + Arg *getLastArg(OptSpecifier Id) const; + Arg *getLastArg(OptSpecifier Id0, OptSpecifier Id1) const; + Arg *getLastArg(OptSpecifier Id0, OptSpecifier Id1, OptSpecifier Id2) const; + Arg *getLastArg(OptSpecifier Id0, OptSpecifier Id1, OptSpecifier Id2, + OptSpecifier Id3) const; + Arg *getLastArg(OptSpecifier Id0, OptSpecifier Id1, OptSpecifier Id2, + OptSpecifier Id3, OptSpecifier Id4) const; + + /// getArgString - Return the input argument string at \arg Index. + virtual const char *getArgString(unsigned Index) const = 0; + + /// getNumInputArgStrings - Return the number of original argument strings, + /// which are guaranteed to be the first strings in the argument string + /// list. + virtual unsigned getNumInputArgStrings() const = 0; + + /// @} + /// @name Argument Lookup Utilities + /// @{ + + /// getLastArgValue - Return the value of the last argument, or a default. + StringRef getLastArgValue(OptSpecifier Id, + StringRef Default = "") const; + + /// getLastArgValue - Return the value of the last argument as an integer, + /// or a default. If Diags is non-null, emits an error if the argument + /// is given, but non-integral. + int getLastArgIntValue(OptSpecifier Id, int Default, + DiagnosticsEngine *Diags = 0) const; + + /// getLastArgValue - Return the value of the last argument as an integer, + /// or a default. Emits an error if the argument is given, but non-integral. + int getLastArgIntValue(OptSpecifier Id, int Default, + DiagnosticsEngine &Diags) const { + return getLastArgIntValue(Id, Default, &Diags); + } + + /// getAllArgValues - Get the values of all instances of the given argument + /// as strings. + std::vector<std::string> getAllArgValues(OptSpecifier Id) const; + + /// @} + /// @name Translation Utilities + /// @{ + + /// hasFlag - Given an option \arg Pos and its negative form \arg + /// Neg, return true if the option is present, false if the + /// negation is present, and \arg Default if neither option is + /// given. If both the option and its negation are present, the + /// last one wins. + bool hasFlag(OptSpecifier Pos, OptSpecifier Neg, bool Default=true) const; + + /// AddLastArg - Render only the last argument match \arg Id0, if + /// present. + void AddLastArg(ArgStringList &Output, OptSpecifier Id0) const; + + /// AddAllArgs - Render all arguments matching the given ids. + void AddAllArgs(ArgStringList &Output, OptSpecifier Id0, + OptSpecifier Id1 = 0U, OptSpecifier Id2 = 0U) const; + + /// AddAllArgValues - Render the argument values of all arguments + /// matching the given ids. + void AddAllArgValues(ArgStringList &Output, OptSpecifier Id0, + OptSpecifier Id1 = 0U, OptSpecifier Id2 = 0U) const; + + /// AddAllArgsTranslated - Render all the arguments matching the + /// given ids, but forced to separate args and using the provided + /// name instead of the first option value. + /// + /// \param Joined - If true, render the argument as joined with + /// the option specifier. + void AddAllArgsTranslated(ArgStringList &Output, OptSpecifier Id0, + const char *Translation, + bool Joined = false) const; + + /// ClaimAllArgs - Claim all arguments which match the given + /// option id. + void ClaimAllArgs(OptSpecifier Id0) const; + + /// ClaimAllArgs - Claim all arguments. + /// + void ClaimAllArgs() const; + + /// @} + /// @name Arg Synthesis + /// @{ + + /// MakeArgString - Construct a constant string pointer whose + /// lifetime will match that of the ArgList. + virtual const char *MakeArgString(StringRef Str) const = 0; + const char *MakeArgString(const char *Str) const { + return MakeArgString(StringRef(Str)); + } + const char *MakeArgString(std::string Str) const { + return MakeArgString(StringRef(Str)); + } + const char *MakeArgString(const Twine &Str) const; + + /// \brief Create an arg string for (\arg LHS + \arg RHS), reusing the + /// string at \arg Index if possible. + const char *GetOrMakeJoinedArgString(unsigned Index, StringRef LHS, + StringRef RHS) const; + + /// @} + }; + + class InputArgList : public ArgList { + private: + /// List of argument strings used by the contained Args. + /// + /// This is mutable since we treat the ArgList as being the list + /// of Args, and allow routines to add new strings (to have a + /// convenient place to store the memory) via MakeIndex. + mutable ArgStringList ArgStrings; + + /// Strings for synthesized arguments. + /// + /// This is mutable since we treat the ArgList as being the list + /// of Args, and allow routines to add new strings (to have a + /// convenient place to store the memory) via MakeIndex. + mutable std::list<std::string> SynthesizedStrings; + + /// The number of original input argument strings. + unsigned NumInputArgStrings; + + public: + InputArgList(const char* const *ArgBegin, const char* const *ArgEnd); + ~InputArgList(); + + virtual const char *getArgString(unsigned Index) const { + return ArgStrings[Index]; + } + + virtual unsigned getNumInputArgStrings() const { + return NumInputArgStrings; + } + + /// @name Arg Synthesis + /// @{ + + public: + /// MakeIndex - Get an index for the given string(s). + unsigned MakeIndex(StringRef String0) const; + unsigned MakeIndex(StringRef String0, StringRef String1) const; + + virtual const char *MakeArgString(StringRef Str) const; + + /// @} + }; + + /// DerivedArgList - An ordered collection of driver arguments, + /// whose storage may be in another argument list. + class DerivedArgList : public ArgList { + const InputArgList &BaseArgs; + + /// The list of arguments we synthesized. + mutable arglist_type SynthesizedArgs; + + public: + /// Construct a new derived arg list from \arg BaseArgs. + DerivedArgList(const InputArgList &BaseArgs); + ~DerivedArgList(); + + virtual const char *getArgString(unsigned Index) const { + return BaseArgs.getArgString(Index); + } + + virtual unsigned getNumInputArgStrings() const { + return BaseArgs.getNumInputArgStrings(); + } + + const InputArgList &getBaseArgs() const { + return BaseArgs; + } + + /// @name Arg Synthesis + /// @{ + + /// AddSynthesizedArg - Add a argument to the list of synthesized arguments + /// (to be freed). + void AddSynthesizedArg(Arg *A) { + SynthesizedArgs.push_back(A); + } + + virtual const char *MakeArgString(StringRef Str) const; + + /// AddFlagArg - Construct a new FlagArg for the given option \arg Id and + /// append it to the argument list. + void AddFlagArg(const Arg *BaseArg, const Option *Opt) { + append(MakeFlagArg(BaseArg, Opt)); + } + + /// AddPositionalArg - Construct a new Positional arg for the given option + /// \arg Id, with the provided \arg Value and append it to the argument + /// list. + void AddPositionalArg(const Arg *BaseArg, const Option *Opt, + StringRef Value) { + append(MakePositionalArg(BaseArg, Opt, Value)); + } + + + /// AddSeparateArg - Construct a new Positional arg for the given option + /// \arg Id, with the provided \arg Value and append it to the argument + /// list. + void AddSeparateArg(const Arg *BaseArg, const Option *Opt, + StringRef Value) { + append(MakeSeparateArg(BaseArg, Opt, Value)); + } + + + /// AddJoinedArg - Construct a new Positional arg for the given option \arg + /// Id, with the provided \arg Value and append it to the argument list. + void AddJoinedArg(const Arg *BaseArg, const Option *Opt, + StringRef Value) { + append(MakeJoinedArg(BaseArg, Opt, Value)); + } + + + /// MakeFlagArg - Construct a new FlagArg for the given option + /// \arg Id. + Arg *MakeFlagArg(const Arg *BaseArg, const Option *Opt) const; + + /// MakePositionalArg - Construct a new Positional arg for the + /// given option \arg Id, with the provided \arg Value. + Arg *MakePositionalArg(const Arg *BaseArg, const Option *Opt, + StringRef Value) const; + + /// MakeSeparateArg - Construct a new Positional arg for the + /// given option \arg Id, with the provided \arg Value. + Arg *MakeSeparateArg(const Arg *BaseArg, const Option *Opt, + StringRef Value) const; + + /// MakeJoinedArg - Construct a new Positional arg for the + /// given option \arg Id, with the provided \arg Value. + Arg *MakeJoinedArg(const Arg *BaseArg, const Option *Opt, + StringRef Value) const; + + /// @} + }; + +} // end namespace driver +} // end namespace clang + +#endif diff --git a/clang/include/clang/Driver/CC1AsOptions.h b/clang/include/clang/Driver/CC1AsOptions.h new file mode 100644 index 0000000..0508213 --- /dev/null +++ b/clang/include/clang/Driver/CC1AsOptions.h @@ -0,0 +1,32 @@ +//===--- CC1AsOptions.h - Clang Assembler Options Table ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_DRIVER_CC1ASOPTIONS_H +#define CLANG_DRIVER_CC1ASOPTIONS_H + +namespace clang { +namespace driver { + class OptTable; + +namespace cc1asoptions { + enum ID { + OPT_INVALID = 0, // This is not an option ID. +#define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \ + HELPTEXT, METAVAR) OPT_##ID, +#include "clang/Driver/CC1AsOptions.inc" + LastOption +#undef OPTION + }; +} + + OptTable *createCC1AsOptTable(); +} +} + +#endif diff --git a/clang/include/clang/Driver/CC1AsOptions.td b/clang/include/clang/Driver/CC1AsOptions.td new file mode 100644 index 0000000..37ba602 --- /dev/null +++ b/clang/include/clang/Driver/CC1AsOptions.td @@ -0,0 +1,91 @@ +//===--- CC1AsOptions.td - Options for clang -cc1as -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the options accepted by clang -cc1as. +// +//===----------------------------------------------------------------------===// + +// Include the common option parsing interfaces. +include "OptParser.td" + +//===----------------------------------------------------------------------===// +// Target Options +//===----------------------------------------------------------------------===// + +def triple : Separate<"-triple">, + HelpText<"Specify target triple (e.g. x86_64-pc-linux-gnu)">; +def target_cpu : Separate<"-target-cpu">, + HelpText<"Target a specific cpu type">; +def target_feature : Separate<"-target-feature">, + HelpText<"Target specific attributes">; + +//===----------------------------------------------------------------------===// +// Language Options +//===----------------------------------------------------------------------===// + +def I : JoinedOrSeparate<"-I">, MetaVarName<"<directory>">, + HelpText<"Add directory to include search path">; +def n : Flag<"-n">, + HelpText<"Don't automatically start assembly file with a text section">; +def L : Flag<"-L">, + HelpText<"Save temporary labels in the symbol table. " + "Note this may change .s semantics, it should almost never be used " + "on compiler generated code!">; + +//===----------------------------------------------------------------------===// +// Frontend Options +//===----------------------------------------------------------------------===// + +def o : Separate<"-o">, MetaVarName<"<path>">, HelpText<"Specify output file">; + +def filetype : Separate<"-filetype">, + HelpText<"Specify the output file type ('asm', 'null', or 'obj')">; + +def help : Flag<"-help">, + HelpText<"Print this help text">; +def _help : Flag<"--help">, Alias<help>; + +def version : Flag<"-version">, + HelpText<"Print the assembler version">; +def _version : Flag<"--version">, Alias<version>; +def v : Flag<"-v">, Alias<version>; + +// Generic forwarding to LLVM options. This should only be used for debugging +// and experimental features. +def mllvm : Separate<"-mllvm">, + HelpText<"Additional arguments to forward to LLVM's option processing">; + +//===----------------------------------------------------------------------===// +// Transliterate Options +//===----------------------------------------------------------------------===// + +def output_asm_variant : Separate<"-output-asm-variant">, + HelpText<"Select the asm variant index to use for output">; +def show_encoding : Flag<"-show-encoding">, + HelpText<"Show instruction encoding information in transliterate mode">; +def show_inst : Flag<"-show-inst">, + HelpText<"Show internal instruction representation in transliterate mode">; + +//===----------------------------------------------------------------------===// +// Assemble Options +//===----------------------------------------------------------------------===// + +def relax_all : Flag<"-relax-all">, + HelpText<"Relax all fixups (for performance testing)">; + +def no_exec_stack : Flag<"--noexecstack">, + HelpText<"Mark the file as not needing an executable stack">; + +def fatal_warnings : Flag<"--fatal-warnings">, + HelpText<"Consider warnings as errors">; + +def g : Flag<"-g">, HelpText<"Generate source level debug information">; + +def dwarf_debug_flags : Separate<"-dwarf-debug-flags">, + HelpText<"The string to embed in the Dwarf debug flags record.">; diff --git a/clang/include/clang/Driver/CC1Options.h b/clang/include/clang/Driver/CC1Options.h new file mode 100644 index 0000000..4a8bbe5 --- /dev/null +++ b/clang/include/clang/Driver/CC1Options.h @@ -0,0 +1,32 @@ +//===--- CC1Options.h - Clang CC1 Options Table -----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_DRIVER_CC1OPTIONS_H +#define CLANG_DRIVER_CC1OPTIONS_H + +namespace clang { +namespace driver { + class OptTable; + +namespace cc1options { + enum ID { + OPT_INVALID = 0, // This is not an option ID. +#define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \ + HELPTEXT, METAVAR) OPT_##ID, +#include "clang/Driver/CC1Options.inc" + LastOption +#undef OPTION + }; +} + + OptTable *createCC1OptTable(); +} +} + +#endif diff --git a/clang/include/clang/Driver/CC1Options.td b/clang/include/clang/Driver/CC1Options.td new file mode 100644 index 0000000..83c988a --- /dev/null +++ b/clang/include/clang/Driver/CC1Options.td @@ -0,0 +1,842 @@ +//===--- CC1Options.td - Options for clang -cc1 ---------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the options accepted by clang -cc1. +// +//===----------------------------------------------------------------------===// + +// Include the common option parsing interfaces. +include "OptParser.td" + +//===----------------------------------------------------------------------===// +// Target Options +//===----------------------------------------------------------------------===// + +def cxx_abi : Separate<"-cxx-abi">, + HelpText<"Target a particular C++ ABI type">; +def target_abi : Separate<"-target-abi">, + HelpText<"Target a particular ABI type">; +def target_cpu : Separate<"-target-cpu">, + HelpText<"Target a specific cpu type">; +def target_feature : Separate<"-target-feature">, + HelpText<"Target specific attributes">; +def target_linker_version : Separate<"-target-linker-version">, + HelpText<"Target linker version">; +def triple : Separate<"-triple">, + HelpText<"Specify target triple (e.g. i686-apple-darwin9)">; +def triple_EQ : Joined<"-triple=">, Alias<triple>; + +//===----------------------------------------------------------------------===// +// Analyzer Options +//===----------------------------------------------------------------------===// + +def analysis_UnoptimizedCFG : Flag<"-unoptimized-cfg">, + HelpText<"Generate unoptimized CFGs for all analyses">; +def analysis_CFGAddImplicitDtors : Flag<"-cfg-add-implicit-dtors">, + HelpText<"Add C++ implicit destructors to CFGs for all analyses">; +def analysis_CFGAddInitializers : Flag<"-cfg-add-initializers">, + HelpText<"Add C++ initializers to CFGs for all analyses">; + +def analyzer_store : Separate<"-analyzer-store">, + HelpText<"Source Code Analysis - Abstract Memory Store Models">; +def analyzer_store_EQ : Joined<"-analyzer-store=">, Alias<analyzer_store>; + +def analyzer_constraints : Separate<"-analyzer-constraints">, + HelpText<"Source Code Analysis - Symbolic Constraint Engines">; +def analyzer_constraints_EQ : Joined<"-analyzer-constraints=">, + Alias<analyzer_constraints>; + +def analyzer_output : Separate<"-analyzer-output">, + HelpText<"Source Code Analysis - Output Options">; +def analyzer_output_EQ : Joined<"-analyzer-output=">, + Alias<analyzer_output>; + +def analyzer_purge : Separate<"-analyzer-purge">, + HelpText<"Source Code Analysis - Dead Symbol Removal Frequency">; +def analyzer_purge_EQ : Joined<"-analyzer-purge=">, Alias<analyzer_purge>; + +def analyzer_opt_analyze_headers : Flag<"-analyzer-opt-analyze-headers">, + HelpText<"Force the static analyzer to analyze functions defined in header files">; +def analyzer_opt_analyze_nested_blocks : Flag<"-analyzer-opt-analyze-nested-blocks">, + HelpText<"Analyze the definitions of blocks in addition to functions">; +def analyzer_display_progress : Flag<"-analyzer-display-progress">, + HelpText<"Emit verbose output about the analyzer's progress">; +def analyze_function : Separate<"-analyze-function">, + HelpText<"Run analysis on specific function">; +def analyze_function_EQ : Joined<"-analyze-function=">, Alias<analyze_function>; +def analyzer_eagerly_assume : Flag<"-analyzer-eagerly-assume">, + HelpText<"Eagerly assume the truth/falseness of some symbolic constraints">; +def analyzer_no_eagerly_trim_egraph : Flag<"-analyzer-no-eagerly-trim-egraph">, + HelpText<"Don't eagerly remove uninteresting ExplodedNodes from the ExplodedGraph">; +def trim_egraph : Flag<"-trim-egraph">, + HelpText<"Only show error-related paths in the analysis graph">; +def analyzer_viz_egraph_graphviz : Flag<"-analyzer-viz-egraph-graphviz">, + HelpText<"Display exploded graph using GraphViz">; +def analyzer_viz_egraph_ubigraph : Flag<"-analyzer-viz-egraph-ubigraph">, + HelpText<"Display exploded graph using Ubigraph">; + +def analyzer_inline_max_stack_depth : Separate<"-analyzer-inline-max-stack-depth">, + HelpText<"Bound on stack depth while inlining (4 by default)">; +def analyzer_inline_max_stack_depth_EQ : Joined<"-analyzer-inline-max-stack-depth=">, + Alias<analyzer_inline_max_stack_depth>; + +def analyzer_inline_max_function_size : Separate<"-analyzer-inline-max-function-size">, + HelpText<"Bound on the number of basic blocks in an inlined function (200 by default)">; +def analyzer_inline_max_function_size_EQ : Joined<"-analyzer-inline-max-function-size=">, + Alias<analyzer_inline_max_function_size>; + +def analyzer_ipa : Separate<"-analyzer-ipa">, + HelpText<"Specify the inter-procedural analysis mode">; +def analyzer_ipa_EQ : Joined<"-analyzer-ipa=">, Alias<analyzer_ipa>; + +def analyzer_inlining_mode : Separate<"-analyzer-inlining-mode">, + HelpText<"Specify the function selection heuristic used during inlining">; +def analyzer_inlining_mode_EQ : Joined<"-analyzer-inlining-mode=">, Alias<analyzer_inlining_mode>; + +def analyzer_disable_retry_exhausted : Flag<"-analyzer-disable-retry-exhausted">, + HelpText<"Do not re-analyze paths leading to exhausted nodes with a different strategy (may decrease code coverage)">; + +def analyzer_max_nodes : Separate<"-analyzer-max-nodes">, + HelpText<"The maximum number of nodes the analyzer can generate (150000 default, 0 = no limit)">; +def analyzer_max_loop : Separate<"-analyzer-max-loop">, + HelpText<"The maximum number of times the analyzer will go through a loop">; +def analyzer_stats : Flag<"-analyzer-stats">, + HelpText<"Print internal analyzer statistics.">; + +def analyzer_checker : Separate<"-analyzer-checker">, + HelpText<"Choose analyzer checkers to enable">; +def analyzer_checker_EQ : Joined<"-analyzer-checker=">, + Alias<analyzer_checker>; + +def analyzer_disable_checker : Separate<"-analyzer-disable-checker">, + HelpText<"Choose analyzer checkers to disable">; +def analyzer_disable_checker_EQ : Joined<"-analyzer-disable-checker=">, + Alias<analyzer_disable_checker>; + +def analyzer_checker_help : Flag<"-analyzer-checker-help">, + HelpText<"Display the list of analyzer checkers that are available">; + +//===----------------------------------------------------------------------===// +// Migrator Options +//===----------------------------------------------------------------------===// +def migrator_no_nsalloc_error : Flag<"-no-ns-alloc-error">, + HelpText<"Do not error on use of NSAllocateCollectable/NSReallocateCollectable">; + +def migrator_no_finalize_removal : Flag<"-no-finalize-removal">, + HelpText<"Do not remove finalize method in gc mode">; + +//===----------------------------------------------------------------------===// +// CodeGen Options +//===----------------------------------------------------------------------===// + +def disable_llvm_optzns : Flag<"-disable-llvm-optzns">, + HelpText<"Don't run LLVM optimization passes">; +def disable_llvm_verifier : Flag<"-disable-llvm-verifier">, + HelpText<"Don't run the LLVM IR verifier pass">; +def disable_red_zone : Flag<"-disable-red-zone">, + HelpText<"Do not emit code that uses the red zone.">; +def fdebug_compilation_dir : Separate<"-fdebug-compilation-dir">, + HelpText<"The compilation directory to embed in the debug info.">; +def dwarf_debug_flags : Separate<"-dwarf-debug-flags">, + HelpText<"The string to embed in the Dwarf debug flags record.">; +def faddress_sanitizer: Flag<"-faddress-sanitizer">, + HelpText<"Enable AddressSanitizer instrumentation (memory error detection)">; +def fthread_sanitizer: Flag<"-fthread-sanitizer">, + HelpText<"Enable ThreadSanitizer instrumentation (race detection)">; +def fforbid_guard_variables : Flag<"-fforbid-guard-variables">, + HelpText<"Emit an error if a C++ static local initializer would need a guard variable">; +def g : Flag<"-g">, HelpText<"Generate source level debug information">; +def fno_dwarf2_cfi_asm : Flag<"-fno-dwarf2-cfi-asm">, + HelpText<"Don't use the cfi directives">; +def fno_dwarf_directory_asm : Flag<"-fno-dwarf-directory-asm">, + HelpText<"Don't separate directory and filename in .file directives">; +def fcatch_undefined_behavior : Flag<"-fcatch-undefined-behavior">, + HelpText<"Generate runtime checks for undefined behavior.">; +def flimit_debug_info : Flag<"-flimit-debug-info">, + HelpText<"Limit debug information produced to reduce size of debug binary">; +def fno_common : Flag<"-fno-common">, + HelpText<"Compile common globals like normal definitions">; +def no_implicit_float : Flag<"-no-implicit-float">, + HelpText<"Don't generate implicit floating point instructions (x86-only)">; +def finstrument_functions : Flag<"-finstrument-functions">, + HelpText<"Generate calls to instrument function entry and exit">; +def fno_limit_debug_info : Flag<"-fno-limit-debug-info">, + HelpText<"Do not limit debug information produced to reduce size of debug binary">; +def fno_merge_all_constants : Flag<"-fno-merge-all-constants">, + HelpText<"Disallow merging of constants.">; +def fno_threadsafe_statics : Flag<"-fno-threadsafe-statics">, + HelpText<"Do not emit code to make initialization of local statics thread safe">; +def fdump_vtable_layouts : Flag<"-fdump-vtable-layouts">, + HelpText<"Dump the layouts of all vtables that will be emitted in a translation unit">; +def ffunction_sections : Flag<"-ffunction-sections">, + HelpText<"Place each function in its own section (ELF Only)">; +def fdata_sections : Flag<"-fdata-sections">, + HelpText<"Place each data in its own section (ELF Only)">; +def fstrict_enums : Flag<"-fstrict-enums">, + HelpText<"Enable optimizations based on the strict definition of an enum's " + "value range.">; +def ftrap_function_EQ : Joined<"-ftrap-function=">, + HelpText<"Issue call to specified function rather than a trap instruction">; +def funroll_loops : Flag<"-funroll-loops">, + HelpText<"Turn on loop unroller">; +def femit_coverage_notes : Flag<"-femit-coverage-notes">, + HelpText<"Emit a gcov coverage notes file when compiling.">; +def femit_coverage_data: Flag<"-femit-coverage-data">, + HelpText<"Instrument the program to emit gcov coverage data when run.">; +def coverage_file : Separate<"-coverage-file">, + HelpText<"Emit coverage data to this filename. The extension will be replaced.">; +def coverage_file_EQ : Joined<"-coverage-file=">, Alias<coverage_file>; +def fuse_register_sized_bitfield_access: Flag<"-fuse-register-sized-bitfield-access">, + HelpText<"Use register sized accesses to bit-fields, when possible.">; +def relaxed_aliasing : Flag<"-relaxed-aliasing">, + HelpText<"Turn off Type Based Alias Analysis">; +def masm_verbose : Flag<"-masm-verbose">, + HelpText<"Generate verbose assembly output">; +def mcode_model : Separate<"-mcode-model">, + HelpText<"The code model to use">; +def mdebug_pass : Separate<"-mdebug-pass">, + HelpText<"Enable additional debug output">; +def mdisable_fp_elim : Flag<"-mdisable-fp-elim">, + HelpText<"Disable frame pointer elimination optimization">; +def mdisable_tail_calls : Flag<"-mdisable-tail-calls">, + HelpText<"Disable tail call optimization, keeping the call stack accurate">; +def menable_no_infinities : Flag<"-menable-no-infs">, + HelpText<"Allow optimization to assume there are no infinities.">; +def menable_no_nans : Flag<"-menable-no-nans">, + HelpText<"Allow optimization to assume there are no NaNs.">; +def menable_unsafe_fp_math : Flag<"-menable-unsafe-fp-math">, + HelpText<"Allow unsafe floating-point math optimizations which may decrease " + "precision">; +def mfloat_abi : Separate<"-mfloat-abi">, + HelpText<"The float ABI to use">; +def mno_global_merge : Flag<"-mno-global-merge">, + HelpText<"Disable merging of globals">; +def mlimit_float_precision : Separate<"-mlimit-float-precision">, + HelpText<"Limit float precision to the given value">; +def mno_exec_stack : Flag<"-mnoexecstack">, + HelpText<"Mark the file as not needing an executable stack">; +def mno_zero_initialized_in_bss : Flag<"-mno-zero-initialized-in-bss">, + HelpText<"Do not put zero initialized data in the BSS">; +def momit_leaf_frame_pointer : Flag<"-momit-leaf-frame-pointer">, + HelpText<"Omit frame pointer setup for leaf functions.">; +def msoft_float : Flag<"-msoft-float">, + HelpText<"Use software floating point">; +def backend_option : Separate<"-backend-option">, + HelpText<"Additional arguments to forward to LLVM backend (during code gen)">; +def mregparm : Separate<"-mregparm">, + HelpText<"Limit the number of registers available for integer arguments">; +def mrelax_all : Flag<"-mrelax-all">, + HelpText<"(integrated-as) Relax all machine instructions">; +def msave_temp_labels : Flag<"-msave-temp-labels">, + HelpText<"(integrated-as) Save temporary labels">; +def mrtd: Flag<"-mrtd">, + HelpText<"Make StdCall calling convention the default">; +def mrelocation_model : Separate<"-mrelocation-model">, + HelpText<"The relocation model to use">; +def munwind_tables : Flag<"-munwind-tables">, + HelpText<"Generate unwinding tables for all functions">; +def mconstructor_aliases : Flag<"-mconstructor-aliases">, + HelpText<"Emit complete constructors and destructors as aliases when possible">; +def mms_bitfields : Flag<"-mms-bitfields">, + HelpText<"Set the default structure layout to be compatible with the Microsoft compiler standard.">; +def mstackrealign : Flag<"-mstackrealign">, + HelpText<"Force realign the stack at entry to every function.">; +def mstack_alignment : Joined<"-mstack-alignment=">, + HelpText<"Set the stack alignment">; +def mlink_bitcode_file : Separate<"-mlink-bitcode-file">, + HelpText<"Link the given bitcode file before performing optimizations.">; +def O : Joined<"-O">, HelpText<"Optimization level">; +def Os : Flag<"-Os">, HelpText<"Optimize for size">; +def Oz : Flag<"-Oz">, HelpText<"Optimize for size, regardless of performance">; +def pg : Flag<"-pg">, HelpText<"Enable mcount instrumentation">; + +//===----------------------------------------------------------------------===// +// Dependency Output Options +//===----------------------------------------------------------------------===// + +def dependency_file : Separate<"-dependency-file">, + HelpText<"Filename (or -) to write dependency output to">; +def dependency_dot : Separate<"-dependency-dot">, + HelpText<"Filename to write DOT-formatted header dependencies to">; +def sys_header_deps : Flag<"-sys-header-deps">, + HelpText<"Include system headers in dependency output">; +def header_include_file : Separate<"-header-include-file">, + HelpText<"Filename (or -) to write header include output to">; +def H : Flag<"-H">, + HelpText<"Show header includes and nesting depth">; +def MQ : Separate<"-MQ">, HelpText<"Specify target to quote for dependency">; +def MT : Separate<"-MT">, HelpText<"Specify target for dependency">; +def MP : Flag<"-MP">, + HelpText<"Create phony target for each dependency (other than main file)">; +def MG : Flag<"-MG">, HelpText<"Add missing headers to dependency list">; + +//===----------------------------------------------------------------------===// +// Diagnostic Options +//===----------------------------------------------------------------------===// + +def dump_build_information : Separate<"-dump-build-information">, + MetaVarName<"<filename>">, + HelpText<"output a dump of some build information to a file">; +def diagnostic_log_file : Separate<"-diagnostic-log-file">, + HelpText<"Filename (or -) to log diagnostics to">; +def diagnostic_serialized_file : Separate<"-serialize-diagnostic-file">, + MetaVarName<"<filename>">, + HelpText<"File for serializing diagnostics in a binary format">; +def fno_show_column : Flag<"-fno-show-column">, + HelpText<"Do not include column number on diagnostics">; +def fshow_column : Flag<"-fshow-column">, + HelpText<"Include column number on diagnostics">; +def fno_show_source_location : Flag<"-fno-show-source-location">, + HelpText<"Do not include source location information with diagnostics">; +def fshow_overloads_EQ : Joined<"-fshow-overloads=">, + HelpText<"Which overload candidates to show when overload resolution fails: " + "best|all; defaults to all">; +def fno_caret_diagnostics : Flag<"-fno-caret-diagnostics">, + HelpText<"Do not include source line and caret with diagnostics">; +def fno_diagnostics_fixit_info : Flag<"-fno-diagnostics-fixit-info">, + HelpText<"Do not include fixit information in diagnostics">; +def fno_diagnostics_show_note_include_stack : + Flag<"-fno-diagnostics-show-note-include-stack">, + HelpText<"Display include stacks for diagnostic notes">; +def w : Flag<"-w">, HelpText<"Suppress all warnings">; +def pedantic : Flag<"-pedantic">; +def pedantic_errors : Flag<"-pedantic-errors">; + +// This gets all -W options, including -Werror, -W[no-]system-headers, etc. The +// driver has stripped off -Wa,foo etc. The driver has also translated -W to +// -Wextra, so we don't need to worry about it. +def W : Joined<"-W">; + +def fdiagnostics_print_source_range_info : Flag<"-fdiagnostics-print-source-range-info">, + HelpText<"Print source range spans in numeric form">; +def fdiagnostics_parseable_fixits : Flag<"-fdiagnostics-parseable-fixits">, + HelpText<"Print fix-its in machine parseable form">; +def fdiagnostics_show_option : Flag<"-fdiagnostics-show-option">, + HelpText<"Print option name with mappable diagnostics">; +def fdiagnostics_format : Separate<"-fdiagnostics-format">, + HelpText<"Change diagnostic formatting to match IDE and command line tools">; +def fdiagnostics_show_category : Separate<"-fdiagnostics-show-category">, + HelpText<"Print diagnostic category">; +def fdiagnostics_show_note_include_stack : + Flag<"-fdiagnostics-show-note-include-stack">, + HelpText<"Display include stacks for diagnostic notes">; +def ftabstop : Separate<"-ftabstop">, MetaVarName<"<N>">, + HelpText<"Set the tab stop distance.">; +def ferror_limit : Separate<"-ferror-limit">, MetaVarName<"<N>">, + HelpText<"Set the maximum number of errors to emit before stopping (0 = no limit).">; +def fmacro_backtrace_limit : Separate<"-fmacro-backtrace-limit">, MetaVarName<"<N>">, + HelpText<"Set the maximum number of entries to print in a macro expansion backtrace (0 = no limit).">; +def ftemplate_backtrace_limit : Separate<"-ftemplate-backtrace-limit">, MetaVarName<"<N>">, + HelpText<"Set the maximum number of entries to print in a template instantiation backtrace (0 = no limit).">; +def fconstexpr_backtrace_limit : Separate<"-fconstexpr-backtrace-limit">, MetaVarName<"<N>">, + HelpText<"Set the maximum number of entries to print in a constexpr evaluation backtrace (0 = no limit).">; +def fmessage_length : Separate<"-fmessage-length">, MetaVarName<"<N>">, + HelpText<"Format message diagnostics so that they fit within N columns or fewer, when possible.">; +def fcolor_diagnostics : Flag<"-fcolor-diagnostics">, + HelpText<"Use colors in diagnostics">; +def Wno_rewrite_macros : Flag<"-Wno-rewrite-macros">, + HelpText<"Silence ObjC rewriting warnings">; +def verify : Flag<"-verify">, + HelpText<"Verify emitted diagnostics and warnings">; + +//===----------------------------------------------------------------------===// +// Frontend Options +//===----------------------------------------------------------------------===// + +// This isn't normally used, it is just here so we can parse a +// CompilerInvocation out of a driver-derived argument vector. +def cc1 : Flag<"-cc1">; + +def ast_merge : Separate<"-ast-merge">, + MetaVarName<"<ast file>">, + HelpText<"Merge the given AST file into the translation unit being compiled.">; +def code_completion_at : Separate<"-code-completion-at">, + MetaVarName<"<file>:<line>:<column>">, + HelpText<"Dump code-completion information at a location">; +def remap_file : Separate<"-remap-file">, + MetaVarName<"<from>;<to>">, + HelpText<"Replace the contents of the <from> file with the contents of the <to> file">; +def code_completion_at_EQ : Joined<"-code-completion-at=">, + Alias<code_completion_at>; +def code_completion_macros : Flag<"-code-completion-macros">, + HelpText<"Include macros in code-completion results">; +def code_completion_patterns : Flag<"-code-completion-patterns">, + HelpText<"Include code patterns in code-completion results">; +def no_code_completion_globals : Flag<"-no-code-completion-globals">, + HelpText<"Do not include global declarations in code-completion results.">; +def disable_free : Flag<"-disable-free">, + HelpText<"Disable freeing of memory on exit">; +def help : Flag<"-help">, + HelpText<"Print this help text">; +def _help : Flag<"--help">, Alias<help>; +def x : Separate<"-x">, HelpText<"Input language type">; +def o : Separate<"-o">, MetaVarName<"<path>">, HelpText<"Specify output file">; +def load : Separate<"-load">, MetaVarName<"<dsopath>">, + HelpText<"Load the named plugin (dynamic shared object)">; +def plugin : Separate<"-plugin">, MetaVarName<"<name>">, + HelpText<"Use the named plugin action instead of the default action (use \"help\" to list available options)">; +def plugin_arg : JoinedAndSeparate<"-plugin-arg-">, + MetaVarName<"<name> <arg>">, + HelpText<"Pass <arg> to plugin <name>">; +def add_plugin : Separate<"-add-plugin">, MetaVarName<"<name>">, + HelpText<"Use the named plugin action in addition to the default action">; +def resource_dir : Separate<"-resource-dir">, + HelpText<"The directory which holds the compiler resource files">; +def version : Flag<"-version">, + HelpText<"Print the compiler version">; +def _version : Flag<"--version">, Alias<version>; + +def Action_Group : OptionGroup<"<action group>">; +let Group = Action_Group in { + +def Eonly : Flag<"-Eonly">, + HelpText<"Just run preprocessor, no output (for timings)">; +def E : Flag<"-E">, + HelpText<"Run preprocessor, emit preprocessed file">; +def dump_raw_tokens : Flag<"-dump-raw-tokens">, + HelpText<"Lex file in raw mode and dump raw tokens">; +def analyze : Flag<"-analyze">, + HelpText<"Run static analysis engine">; +def dump_tokens : Flag<"-dump-tokens">, + HelpText<"Run preprocessor, dump internal rep of tokens">; +def init_only : Flag<"-init-only">, + HelpText<"Only execute frontend initialization">; +def fsyntax_only : Flag<"-fsyntax-only">, + HelpText<"Run parser and perform semantic analysis">; +def fixit : Flag<"-fixit">, + HelpText<"Apply fix-it advice to the input source">; +def fixit_EQ : Joined<"-fixit=">, + HelpText<"Apply fix-it advice creating a file with the given suffix">; +def print_preamble : Flag<"-print-preamble">, + HelpText<"Print the \"preamble\" of a file, which is a candidate for implicit" + " precompiled headers.">; +def emit_html : Flag<"-emit-html">, + HelpText<"Output input source as HTML">; +def ast_print : Flag<"-ast-print">, + HelpText<"Build ASTs and then pretty-print them">; +def ast_dump : Flag<"-ast-dump">, + HelpText<"Build ASTs and then debug dump them">; +def ast_dump_xml : Flag<"-ast-dump-xml">, + HelpText<"Build ASTs and then debug dump them in a verbose XML format">; +def ast_view : Flag<"-ast-view">, + HelpText<"Build ASTs and view them with GraphViz">; +def print_decl_contexts : Flag<"-print-decl-contexts">, + HelpText<"Print DeclContexts and their Decls">; +def emit_module : Flag<"-emit-module">, + HelpText<"Generate pre-compiled module file from a module map">; +def emit_pth : Flag<"-emit-pth">, + HelpText<"Generate pre-tokenized header file">; +def emit_pch : Flag<"-emit-pch">, + HelpText<"Generate pre-compiled header file">; +def S : Flag<"-S">, + HelpText<"Emit native assembly code">; +def emit_llvm : Flag<"-emit-llvm">, + HelpText<"Build ASTs then convert to LLVM, emit .ll file">; +def emit_llvm_bc : Flag<"-emit-llvm-bc">, + HelpText<"Build ASTs then convert to LLVM, emit .bc file">; +def emit_llvm_only : Flag<"-emit-llvm-only">, + HelpText<"Build ASTs and convert to LLVM, discarding output">; +def emit_codegen_only : Flag<"-emit-codegen-only">, + HelpText<"Generate machine code, but discard output">; +def emit_obj : Flag<"-emit-obj">, + HelpText<"Emit native object files">; +def rewrite_test : Flag<"-rewrite-test">, + HelpText<"Rewriter playground">; +def rewrite_objc : Flag<"-rewrite-objc">, + HelpText<"Rewrite ObjC into C (code rewriter example)">; +def rewrite_macros : Flag<"-rewrite-macros">, + HelpText<"Expand macros without full preprocessing">; +def migrate : Flag<"-migrate">, + HelpText<"Migrate source code">; +} + +def mt_migrate_directory : Separate<"-mt-migrate-directory">, + HelpText<"Directory for temporary files produced during ARC or ObjC migration">; +def arcmt_check : Flag<"-arcmt-check">, + HelpText<"Check for ARC migration issues that need manual handling">; +def arcmt_modify : Flag<"-arcmt-modify">, + HelpText<"Apply modifications to files to conform to ARC">; +def arcmt_migrate : Flag<"-arcmt-migrate">, + HelpText<"Apply modifications and produces temporary files that conform to ARC">; +def arcmt_migrate_report_output : Separate<"-arcmt-migrate-report-output">, + HelpText<"Output path for the plist report">; +def arcmt_migrate_emit_arc_errors : Flag<"-arcmt-migrate-emit-errors">, + HelpText<"Emit ARC errors even if the migrator can fix them">; + +def objcmt_migrate_literals : Flag<"-objcmt-migrate-literals">, + HelpText<"Enable migration to modern ObjC literals">; +def objcmt_migrate_subscripting : Flag<"-objcmt-migrate-subscripting">, + HelpText<"Enable migration to modern ObjC subscripting">; + +def working_directory : JoinedOrSeparate<"-working-directory">, + HelpText<"Resolve file paths relative to the specified directory">; +def working_directory_EQ : Joined<"-working-directory=">, + Alias<working_directory>; + +def relocatable_pch : Flag<"-relocatable-pch">, + HelpText<"Whether to build a relocatable precompiled header">; +def print_stats : Flag<"-print-stats">, + HelpText<"Print performance metrics and statistics">; +def ftime_report : Flag<"-ftime-report">, + HelpText<"Print the amount of time each phase of compilation takes">; +def fdump_record_layouts : Flag<"-fdump-record-layouts">, + HelpText<"Dump record layout information">; +def fdump_record_layouts_simple : Flag<"-fdump-record-layouts-simple">, + HelpText<"Dump record layout information in a simple form used for testing">; +def fix_what_you_can : Flag<"-fix-what-you-can">, + HelpText<"Apply fix-it advice even in the presence of unfixable errors">; +def fix_only_warnings : Flag<"-fix-only-warnings">, + HelpText<"Apply fix-it advice only for warnings, not errors">; +def fixit_recompile : Flag<"-fixit-recompile">, + HelpText<"Apply fix-it changes and recompile">; +def fixit_to_temp : Flag<"-fixit-to-temporary">, + HelpText<"Apply fix-it changes to temporary files">; + +// Generic forwarding to LLVM options. This should only be used for debugging +// and experimental features. +def mllvm : Separate<"-mllvm">, + HelpText<"Additional arguments to forward to LLVM's option processing">; + +def foverride_record_layout_EQ : Joined<"-foverride-record-layout=">, + HelpText<"Override record layouts with those in the given file">; + +//===----------------------------------------------------------------------===// +// Language Options +//===----------------------------------------------------------------------===// + +def fno_builtin : Flag<"-fno-builtin">, + HelpText<"Disable implicit builtin knowledge of functions">; +def faltivec : Flag<"-faltivec">, + HelpText<"Enable AltiVec vector initializer syntax">; +def fno_access_control : Flag<"-fno-access-control">, + HelpText<"Disable C++ access control">; +def fno_assume_sane_operator_new : Flag<"-fno-assume-sane-operator-new">, + HelpText<"Don't assume that C++'s global operator new can't alias any pointer">; +def fgnu_keywords : Flag<"-fgnu-keywords">, + HelpText<"Allow GNU-extension keywords regardless of language standard">; +def fgnu89_inline : Flag<"-fgnu89-inline">, + HelpText<"Use the gnu89 inline semantics">; +def fno_inline : Flag<"-fno-inline">, + HelpText<"Disable use of the inline keyword">; +def fno_inline_functions : Flag<"-fno-inline-functions">, + HelpText<"Disable automatic function inlining">; +def fno_gnu_keywords : Flag<"-fno-gnu-keywords">, + HelpText<"Disallow GNU-extension keywords regardless of language standard">; +def fdollars_in_identifiers : Flag<"-fdollars-in-identifiers">, + HelpText<"Allow '$' in identifiers">; +def fno_dollars_in_identifiers : Flag<"-fno-dollars-in-identifiers">, + HelpText<"Disallow '$' in identifiers">; +def femit_all_decls : Flag<"-femit-all-decls">, + HelpText<"Emit all declarations, even if unused">; +def fblocks : Flag<"-fblocks">, + HelpText<"Enable the 'blocks' language feature">; +def fblocks_runtime_optional : Flag<"-fblocks-runtime-optional">, + HelpText<"Weakly link in the blocks runtime">; +def fheinous_gnu_extensions : Flag<"-fheinous-gnu-extensions">; +def fexceptions : Flag<"-fexceptions">, + HelpText<"Enable support for exception handling">; +def fobjc_exceptions : Flag<"-fobjc-exceptions">, + HelpText<"Enable Objective-C exceptions">; +def fcxx_exceptions : Flag<"-fcxx-exceptions">, + HelpText<"Enable C++ exceptions">; +def fsjlj_exceptions : Flag<"-fsjlj-exceptions">, + HelpText<"Use SjLj style exceptions">; +def ffast_math : Flag<"-ffast-math">, + HelpText<"Enable the *frontend*'s 'fast-math' mode. This has no effect on " + "optimizations, but provides a preprocessor macro __FAST_MATH__ the " + "same as GCC's -ffast-math flag.">; +def ffreestanding : Flag<"-ffreestanding">, + HelpText<"Assert that the compilation takes place in a freestanding environment">; +def fgnu_runtime : Flag<"-fgnu-runtime">, + HelpText<"Generate output compatible with the standard GNU Objective-C runtime">; +def fhidden_weak_vtables : Flag<"-fhidden-weak-vtables">, + HelpText<"Generate weak vtables and RTTI with hidden visibility">; +def std_EQ : Joined<"-std=">, + HelpText<"Language standard to compile for">; +def stdlib_EQ : Joined<"-stdlib=">, + HelpText<"C++ standard library to use">; +def fmath_errno : Flag<"-fmath-errno">, + HelpText<"Require math functions to indicate errors by setting errno">; +def fms_extensions : Flag<"-fms-extensions">, + HelpText<"Accept some non-standard constructs supported by the Microsoft compiler">; +def fms_compatibility : Flag<"-fms-compatibility">, + HelpText<"Enable Microsoft compatibility mode">; +def fmsc_version : Joined<"-fmsc-version=">, + HelpText<"Version of the Microsoft C/C++ compiler to report in _MSC_VER (0 = don't define it (default))">; +def fborland_extensions : Flag<"-fborland-extensions">, + HelpText<"Accept non-standard constructs supported by the Borland compiler">; +def main_file_name : Separate<"-main-file-name">, + HelpText<"Main file name to use for debug info">; +def fno_elide_constructors : Flag<"-fno-elide-constructors">, + HelpText<"Disable C++ copy constructor elision">; +def fno_lax_vector_conversions : Flag<"-fno-lax-vector-conversions">, + HelpText<"Disallow implicit conversions between vectors with a different number of elements or different element types">; +def fno_operator_names : Flag<"-fno-operator-names">, + HelpText<"Do not treat C++ operator name keywords as synonyms for operators">; +def fno_signed_char : Flag<"-fno-signed-char">, + HelpText<"Char is unsigned">; +def fno_spell_checking : Flag<"-fno-spell-checking">, + HelpText<"Disable spell-checking">; +def fno_use_cxa_atexit : Flag<"-fno-use-cxa-atexit">, + HelpText<"Don't use __cxa_atexit for calling destructors">; +def fconstant_string_class : Separate<"-fconstant-string-class">, + MetaVarName<"<class name>">, + HelpText<"Specify the class to use for constant Objective-C string objects.">; +def fno_constant_cfstrings : Flag<"-fno-constant-cfstrings">, + HelpText<"Enable creation of CodeFoundation-type constant strings">; +def fobjc_arc : Flag<"-fobjc-arc">, + HelpText<"Synthesize retain and release calls for Objective-C pointers">; +def fobjc_arc_cxxlib_EQ : Joined<"-fobjc-arc-cxxlib=">, + HelpText<"Objective-C++ Automatic Reference Counting standard library kind">; +def fobjc_arc_exceptions : Flag<"-fobjc-arc-exceptions">, + HelpText<"Use EH-safe code when synthesizing retains and releases in -fobjc-arc">; +def fobjc_runtime_has_arc : Flag<"-fobjc-runtime-has-arc">, + HelpText<"The target Objective-C runtime provides ARC entrypoints">; +def fobjc_runtime_has_weak : Flag<"-fobjc-runtime-has-weak">, + HelpText<"The target Objective-C runtime supports ARC weak operations">; +def fobjc_runtime_has_terminate : Flag<"-fobjc-runtime-has-terminate">, + HelpText<"The target Objective-C runtime provides an objc_terminate entrypoint">; +def fobjc_gc : Flag<"-fobjc-gc">, + HelpText<"Enable Objective-C garbage collection">; +def fobjc_gc_only : Flag<"-fobjc-gc-only">, + HelpText<"Use GC exclusively for Objective-C related memory management">; +def fapple_kext : Flag<"-fapple-kext">, + HelpText<"Use Apple's kernel extensions ABI">; +def fobjc_dispatch_method_EQ : Joined<"-fobjc-dispatch-method=">, + HelpText<"Objective-C dispatch method to use">; +def fobjc_default_synthesize_properties : Flag<"-fobjc-default-synthesize-properties">, + HelpText<"enable the default synthesis of Objective-C properties">; +def print_ivar_layout : Flag<"-print-ivar-layout">, + HelpText<"Enable Objective-C Ivar layout bitmap print trace">; +def fobjc_fragile_abi : Flag<"-fobjc-fragile-abi">, + HelpText<"Use Objective-C's fragile ABI">; +def fno_objc_infer_related_result_type : Flag< + "-fno-objc-infer-related-result-type">, + HelpText< + "do not infer Objective-C related result type based on method family">; +def ftrapv : Flag<"-ftrapv">, + HelpText<"Trap on integer overflow">; +def ftrapv_handler : Separate<"-ftrapv-handler">, + MetaVarName<"<function name>">, + HelpText<"Specify the function to be called on overflow.">; +def fwrapv : Flag<"-fwrapv">, + HelpText<"Treat signed integer overflow as two's complement">; +def pic_level : Separate<"-pic-level">, + HelpText<"Value for __PIC__">; +def pie_level : Separate<"-pie-level">, + HelpText<"Value for __PIE__">; +def pthread : Flag<"-pthread">, + HelpText<"Support POSIX threads in generated code">; +def fpack_struct : Separate<"-fpack-struct">, + HelpText<"Specify the default maximum struct packing alignment">; +def fpascal_strings : Flag<"-fpascal-strings">, + HelpText<"Recognize and construct Pascal-style string literals">; +def fno_rtti : Flag<"-fno-rtti">, + HelpText<"Disable generation of rtti information">; +def fno_validate_pch : Flag<"-fno-validate-pch">, + HelpText<"Disable validation of precompiled headers">; +def dump_deserialized_pch_decls : Flag<"-dump-deserialized-decls">, + HelpText<"Dump declarations that are deserialized from PCH, for testing">; +def error_on_deserialized_pch_decl : Separate<"-error-on-deserialized-decl">, + HelpText<"Emit error if a specific declaration is deserialized from PCH, for testing">; +def error_on_deserialized_pch_decl_EQ : Joined<"-error-on-deserialized-decl=">, + Alias<error_on_deserialized_pch_decl>; +def fshort_wchar : Flag<"-fshort-wchar">, + HelpText<"Force wchar_t to be a short unsigned int">; +def fshort_enums : Flag<"-fshort-enums">, + HelpText<"Allocate to an enum type only as many bytes as it needs for the declared range of possible values">; +def static_define : Flag<"-static-define">, + HelpText<"Should __STATIC__ be defined">; +def stack_protector : Separate<"-stack-protector">, + HelpText<"Enable stack protectors">; +def fvisibility : Separate<"-fvisibility">, + HelpText<"Default symbol visibility">; +def fvisibility_inlines_hidden : Flag<"-fvisibility-inlines-hidden">, + HelpText<"Give inline C++ member functions default visibility by default">; +def ftemplate_depth : Separate<"-ftemplate-depth">, + HelpText<"Maximum depth of recursive template instantiation">; +def fconstexpr_depth : Separate<"-fconstexpr-depth">, + HelpText<"Maximum depth of recursive constexpr function calls">; +def Wlarge_by_value_copy : Separate<"-Wlarge-by-value-copy">, + HelpText<"Warn if a function definition returns or accepts an object larger " + "in bytes that a given value">; +def Wlarge_by_value_copy_EQ : Joined<"-Wlarge-by-value-copy=">, + Alias<Wlarge_by_value_copy>; +def trigraphs : Flag<"-trigraphs">, + HelpText<"Process trigraph sequences">; +def fwritable_strings : Flag<"-fwritable-strings">, + HelpText<"Store string literals as writable data">; +def fconst_strings : Flag<"-fconst-strings">, + HelpText<"Use a const qualified type for string literals in C and ObjC">; +def fno_const_strings : Flag<"-fno-const-strings">, + HelpText<"Don't use a const qualified type for string literals in C and ObjC">; +def fno_bitfield_type_align : Flag<"-fno-bitfield-type-align">, + HelpText<"Ignore bit-field types when aligning structures">; +def traditional_cpp : Flag<"-traditional-cpp">, + HelpText<"Enable some traditional CPP emulation">; +def ffake_address_space_map : Flag<"-ffake-address-space-map">, + HelpText<"Use a fake address space map; OpenCL testing purposes only">; +def fdelayed_template_parsing : Flag<"-fdelayed-template-parsing">, + HelpText<"Parse templated function definitions at the end of the " + "translation unit ">; +def funknown_anytype : Flag<"-funknown-anytype">, + HelpText<"Enable parser support for the __unknown_anytype type; for testing purposes only">; +def fdebugger_support : Flag<"-fdebugger-support">, + HelpText<"Enable special debugger support behavior">; +def fdebugger_cast_result_to_id : Flag<"-fdebugger-cast-result-to-id">, + HelpText<"Enable casting unknown expression results to id">; +def fdebugger_objc_literal : Flag<"-fdebugger-objc-literal">, + HelpText<"Enable special debugger support for objective-C subscripting and literals">; +def fdeprecated_macro : Flag<"-fdeprecated-macro">, + HelpText<"Defines the __DEPRECATED macro">; +def fno_deprecated_macro : Flag<"-fno-deprecated-macro">, + HelpText<"Undefines the __DEPRECATED macro">; +def fapple_pragma_pack : Flag<"-fapple-pragma-pack">, + HelpText<"Enable Apple gcc-compatible #pragma pack handling">; + +//===----------------------------------------------------------------------===// +// Header Search Options +//===----------------------------------------------------------------------===// + +def nostdsysteminc : Flag<"-nostdsysteminc">, + HelpText<"Disable standard system #include directories">; +def nostdincxx : Flag<"-nostdinc++">, + HelpText<"Disable standard #include directories for the C++ standard library">; +def nobuiltininc : Flag<"-nobuiltininc">, + HelpText<"Disable builtin #include directories">; +def fmodule_cache_path : Separate<"-fmodule-cache-path">, + MetaVarName<"<directory>">, + HelpText<"Specify the module cache path">; +def fmodule_name : Joined<"-fmodule-name=">, + MetaVarName<"<name>">, + HelpText<"Specify the name of the module to build">; +def fdisable_module_hash : Flag<"-fdisable-module-hash">, + HelpText<"Disable the module hash">; +def fmodules : Flag<"-fmodules">, + HelpText<"Enable the 'modules' language feature">; + +def F : JoinedOrSeparate<"-F">, MetaVarName<"<directory>">, + HelpText<"Add directory to framework include search path">; +def I : JoinedOrSeparate<"-I">, MetaVarName<"<directory>">, + HelpText<"Add directory to include search path">; +def idirafter : JoinedOrSeparate<"-idirafter">, MetaVarName<"<directory>">, + HelpText<"Add directory to AFTER include search path">; +def index_header_map : Flag<"-index-header-map">, + HelpText<"Make the next included directory (-I or -F) an indexer header map">; +def iquote : JoinedOrSeparate<"-iquote">, MetaVarName<"<directory>">, + HelpText<"Add directory to QUOTE include search path">; +def c_isystem : JoinedOrSeparate<"-c-isystem">, MetaVarName<"<directory>">, + HelpText<"Add directory to the C SYSTEM include search path">; +def cxx_isystem : JoinedOrSeparate<"-cxx-isystem">, MetaVarName<"<directory>">, + HelpText<"Add directory to the C++ SYSTEM include search path">; +def objc_isystem : JoinedOrSeparate<"-objc-isystem">, + MetaVarName<"<directory>">, + HelpText<"Add directory to the ObjC SYSTEM include search path">; +def objcxx_isystem : JoinedOrSeparate<"-objcxx-isystem">, + MetaVarName<"<directory>">, + HelpText<"Add directory to the ObjC++ SYSTEM include search path">; +def iframework : JoinedOrSeparate<"-iframework">, MetaVarName<"<directory>">, + HelpText<"Add directory to SYSTEM framework search path">; +def isystem : JoinedOrSeparate<"-isystem">, MetaVarName<"<directory>">, + HelpText<"Add directory to SYSTEM include search path">; +def iwithsysroot : JoinedOrSeparate<"-iwithsysroot">,MetaVarName<"<directory>">, + HelpText<"Add directory to SYSTEM include search path, " + "absolute paths are relative to -isysroot">; +def internal_isystem : JoinedOrSeparate<"-internal-isystem">, + MetaVarName<"<directory>">, + HelpText<"Add directory to the internal system include search path; these " + "are assumed to not be user-provided and are used to model system " + "and standard headers' paths.">; +def internal_externc_isystem : JoinedOrSeparate<"-internal-externc-isystem">, + MetaVarName<"<directory>">, + HelpText<"Add directory to the internal system include search path with " + "implicit extern \"C\" semantics; these are assumed to not be " + "user-provided and are used to model system and standard headers' " + "paths.">; +def iprefix : JoinedOrSeparate<"-iprefix">, MetaVarName<"<prefix>">, + HelpText<"Set the -iwithprefix/-iwithprefixbefore prefix">; +def iwithprefix : JoinedOrSeparate<"-iwithprefix">, MetaVarName<"<dir>">, + HelpText<"Set directory to SYSTEM include search path with prefix">; +def iwithprefixbefore : JoinedOrSeparate<"-iwithprefixbefore">, + MetaVarName<"<dir>">, + HelpText<"Set directory to include search path with prefix">; +def isysroot : JoinedOrSeparate<"-isysroot">, MetaVarName<"<dir>">, + HelpText<"Set the system root directory (usually /)">; +def v : Flag<"-v">, HelpText<"Enable verbose output">; + +//===----------------------------------------------------------------------===// +// Preprocessor Options +//===----------------------------------------------------------------------===// + +def D : JoinedOrSeparate<"-D">, MetaVarName<"<macro>">, + HelpText<"Predefine the specified macro">; +def include_ : JoinedOrSeparate<"-include">, MetaVarName<"<file>">, EnumName<"include">, + HelpText<"Include file before parsing">; +def imacros : JoinedOrSeparate<"-imacros">, MetaVarName<"<file>">, + HelpText<"Include macros from file before parsing">; +def include_pch : Separate<"-include-pch">, MetaVarName<"<file>">, + HelpText<"Include precompiled header file">; +def include_pth : Separate<"-include-pth">, MetaVarName<"<file>">, + HelpText<"Include file before parsing">; +def chain_include : Separate<"-chain-include">, MetaVarName<"<file>">, + HelpText<"Include and chain a header file after turning it into PCH">; +def preamble_bytes_EQ : Joined<"-preamble-bytes=">, + HelpText<"Assume that the precompiled header is a precompiled preamble " + "covering the first N bytes of the main file">; +def token_cache : Separate<"-token-cache">, MetaVarName<"<path>">, + HelpText<"Use specified token cache file">; +def U : JoinedOrSeparate<"-U">, MetaVarName<"<macro>">, + HelpText<"Undefine the specified macro">; +def undef : Flag<"-undef">, MetaVarName<"<macro>">, + HelpText<"undef all system defines">; +def detailed_preprocessing_record : Flag<"-detailed-preprocessing-record">, + HelpText<"include a detailed record of preprocessing actions">; +def mqdsp6_compat : Flag<"-mqdsp6-compat">, + HelpText<"Enable hexagon-qdsp6 backward compatibility">; + +//===----------------------------------------------------------------------===// +// Preprocessed Output Options +//===----------------------------------------------------------------------===// + +def P : Flag<"-P">, + HelpText<"Disable linemarker output in -E mode">; +def C : Flag<"-C">, + HelpText<"Enable comment output in -E mode">; +def CC : Flag<"-CC">, + HelpText<"Enable comment output in -E mode, even from macro expansions">; +def dM : Flag<"-dM">, + HelpText<"Print macro definitions in -E mode instead of normal output">; +def dD : Flag<"-dD">, + HelpText<"Print macro definitions in -E mode in addition to normal output">; + +//===----------------------------------------------------------------------===// +// OpenCL Options +//===----------------------------------------------------------------------===// + +def cl_opt_disable : Flag<"-cl-opt-disable">, + HelpText<"OpenCL only. This option disables all optimizations. The default is optimizations are enabled.">; +def cl_single_precision_constant : Flag<"-cl-single-precision-constant">, + HelpText<"OpenCL only. Treat double precision floating-point constant as single precision constant.">; +def cl_finite_math_only : Flag<"-cl-finite-math-only">, + HelpText<"OpenCL only. Allow floating-point optimizations that assume arguments and results are not NaNs or +-Inf.">; +def cl_unsafe_math_optimizations : Flag<"-cl-unsafe-math-optimizations">, + HelpText<"OpenCL only. Allow unsafe floating-point optimizations. Also implies -cl-no-signed-zeros and -cl-mad-enable">; +def cl_fast_relaxed_math : Flag<"-cl-fast-relaxed-math">, + HelpText<"OpenCL only. Sets -cl-finite-math-only and -cl-unsafe-math-optimizations, and defines __FAST_RELAXED_MATH__">; +def cl_mad_enable : Flag<"-cl-mad-enable">, + HelpText<"OpenCL only. Enable less precise MAD instructions to be generated.">; +def cl_std_EQ : Joined<"-cl-std=">, + HelpText<"OpenCL language standard to compile for">; + +//===----------------------------------------------------------------------===// +// CUDA Options +//===----------------------------------------------------------------------===// + +def fcuda_is_device : Flag<"-fcuda-is-device">, + HelpText<"Generate code for CUDA device">; diff --git a/clang/include/clang/Driver/CMakeLists.txt b/clang/include/clang/Driver/CMakeLists.txt new file mode 100644 index 0000000..abd4cfe --- /dev/null +++ b/clang/include/clang/Driver/CMakeLists.txt @@ -0,0 +1,11 @@ +clang_tablegen(Options.inc -gen-opt-parser-defs + SOURCE Options.td + TARGET ClangDriverOptions) + +clang_tablegen(CC1Options.inc -gen-opt-parser-defs + SOURCE CC1Options.td + TARGET ClangCC1Options) + +clang_tablegen(CC1AsOptions.inc -gen-opt-parser-defs + SOURCE CC1AsOptions.td + TARGET ClangCC1AsOptions) diff --git a/clang/include/clang/Driver/Compilation.h b/clang/include/clang/Driver/Compilation.h new file mode 100644 index 0000000..6f1a221 --- /dev/null +++ b/clang/include/clang/Driver/Compilation.h @@ -0,0 +1,166 @@ +//===--- Compilation.h - Compilation Task Data Structure --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_DRIVER_COMPILATION_H_ +#define CLANG_DRIVER_COMPILATION_H_ + +#include "clang/Driver/Job.h" +#include "clang/Driver/Util.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/Support/Path.h" + +namespace clang { +namespace driver { + class DerivedArgList; + class Driver; + class InputArgList; + class JobList; + class ToolChain; + +/// Compilation - A set of tasks to perform for a single driver +/// invocation. +class Compilation { + /// The driver we were created by. + const Driver &TheDriver; + + /// The default tool chain. + const ToolChain &DefaultToolChain; + + /// The original (untranslated) input argument list. + InputArgList *Args; + + /// The driver translated arguments. Note that toolchains may perform their + /// own argument translation. + DerivedArgList *TranslatedArgs; + + /// The list of actions. + ActionList Actions; + + /// The root list of jobs. + JobList Jobs; + + /// Cache of translated arguments for a particular tool chain and bound + /// architecture. + llvm::DenseMap<std::pair<const ToolChain*, const char*>, + DerivedArgList*> TCArgs; + + /// Temporary files which should be removed on exit. + ArgStringList TempFiles; + + /// Result files which should be removed on failure. + ArgStringList ResultFiles; + + /// Result files which are generated correctly on failure, and which should + /// only be removed if we crash. + ArgStringList FailureResultFiles; + + /// Redirection for stdout, stderr, etc. + const llvm::sys::Path **Redirects; + +public: + Compilation(const Driver &D, const ToolChain &DefaultToolChain, + InputArgList *Args, DerivedArgList *TranslatedArgs); + ~Compilation(); + + const Driver &getDriver() const { return TheDriver; } + + const ToolChain &getDefaultToolChain() const { return DefaultToolChain; } + + const InputArgList &getInputArgs() const { return *Args; } + + const DerivedArgList &getArgs() const { return *TranslatedArgs; } + + ActionList &getActions() { return Actions; } + const ActionList &getActions() const { return Actions; } + + JobList &getJobs() { return Jobs; } + const JobList &getJobs() const { return Jobs; } + + void addCommand(Command *C) { Jobs.addJob(C); } + + const ArgStringList &getTempFiles() const { return TempFiles; } + + const ArgStringList &getResultFiles() const { return ResultFiles; } + + const ArgStringList &getFailureResultFiles() const { + return FailureResultFiles; + } + + /// Returns the sysroot path. + StringRef getSysRoot() const; + + /// getArgsForToolChain - Return the derived argument list for the + /// tool chain \arg TC (or the default tool chain, if TC is not + /// specified). + /// + /// \param BoundArch - The bound architecture name, or 0. + const DerivedArgList &getArgsForToolChain(const ToolChain *TC, + const char *BoundArch); + + /// addTempFile - Add a file to remove on exit, and returns its + /// argument. + const char *addTempFile(const char *Name) { + TempFiles.push_back(Name); + return Name; + } + + /// addResultFile - Add a file to remove on failure, and returns its + /// argument. + const char *addResultFile(const char *Name) { + ResultFiles.push_back(Name); + return Name; + } + + /// addFailureResultFile - Add a file to remove if we crash, and returns its + /// argument. + const char *addFailureResultFile(const char *Name) { + FailureResultFiles.push_back(Name); + return Name; + } + + /// CleanupFileList - Remove the files in the given list. + /// + /// \param IssueErrors - Report failures as errors. + /// \return Whether all files were removed successfully. + bool CleanupFileList(const ArgStringList &Files, + bool IssueErrors=false) const; + + /// PrintJob - Print one job in -### format. + /// + /// \param OS - The stream to print on. + /// \param J - The job to print. + /// \param Terminator - A string to print at the end of the line. + /// \param Quote - Should separate arguments be quoted. + void PrintJob(raw_ostream &OS, const Job &J, + const char *Terminator, bool Quote) const; + + /// ExecuteCommand - Execute an actual command. + /// + /// \param FailingCommand - For non-zero results, this will be set to the + /// Command which failed, if any. + /// \return The result code of the subprocess. + int ExecuteCommand(const Command &C, const Command *&FailingCommand) const; + + /// ExecuteJob - Execute a single job. + /// + /// \param FailingCommand - For non-zero results, this will be set to the + /// Command which failed. + /// \return The accumulated result code of the job. + int ExecuteJob(const Job &J, const Command *&FailingCommand) const; + + /// initCompilationForDiagnostics - Remove stale state and suppress output + /// so compilation can be reexecuted to generate additional diagnostic + /// information (e.g., preprocessed source(s)). + void initCompilationForDiagnostics(); +}; + +} // end namespace driver +} // end namespace clang + +#endif diff --git a/clang/include/clang/Driver/Driver.h b/clang/include/clang/Driver/Driver.h new file mode 100644 index 0000000..0538334 --- /dev/null +++ b/clang/include/clang/Driver/Driver.h @@ -0,0 +1,418 @@ +//===--- Driver.h - Clang GCC Compatible Driver -----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_DRIVER_DRIVER_H_ +#define CLANG_DRIVER_DRIVER_H_ + +#include "clang/Basic/Diagnostic.h" + +#include "clang/Driver/Phases.h" +#include "clang/Driver/Types.h" +#include "clang/Driver/Util.h" + +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Path.h" // FIXME: Kill when CompilationInfo + // lands. +#include <list> +#include <set> +#include <string> + +namespace llvm { + template<typename T> class ArrayRef; +} +namespace clang { +namespace driver { + class Action; + class Arg; + class ArgList; + class Command; + class Compilation; + class DerivedArgList; + class InputArgList; + class InputInfo; + class JobAction; + class OptTable; + class ToolChain; + +/// Driver - Encapsulate logic for constructing compilation processes +/// from a set of gcc-driver-like command line arguments. +class Driver { + OptTable *Opts; + + DiagnosticsEngine &Diags; + +public: + // Diag - Forwarding function for diagnostics. + DiagnosticBuilder Diag(unsigned DiagID) const { + return Diags.Report(DiagID); + } + + // FIXME: Privatize once interface is stable. +public: + /// The name the driver was invoked as. + std::string Name; + + /// The path the driver executable was in, as invoked from the + /// command line. + std::string Dir; + + /// The original path to the clang executable. + std::string ClangExecutable; + + /// The path to the installed clang directory, if any. + std::string InstalledDir; + + /// The path to the compiler resource directory. + std::string ResourceDir; + + /// A prefix directory used to emulated a limited subset of GCC's '-Bprefix' + /// functionality. + /// FIXME: This type of customization should be removed in favor of the + /// universal driver when it is ready. + typedef SmallVector<std::string, 4> prefix_list; + prefix_list PrefixDirs; + + /// sysroot, if present + std::string SysRoot; + + /// If the standard library is used + bool UseStdLib; + + /// Default target triple. + std::string DefaultTargetTriple; + + /// Default name for linked images (e.g., "a.out"). + std::string DefaultImageName; + + /// Driver title to use with help. + std::string DriverTitle; + + /// Information about the host which can be overridden by the user. + std::string HostBits, HostMachine, HostSystem, HostRelease; + + /// The file to log CC_PRINT_OPTIONS output to, if enabled. + const char *CCPrintOptionsFilename; + + /// The file to log CC_PRINT_HEADERS output to, if enabled. + const char *CCPrintHeadersFilename; + + /// The file to log CC_LOG_DIAGNOSTICS output to, if enabled. + const char *CCLogDiagnosticsFilename; + + /// A list of inputs and their types for the given arguments. + typedef SmallVector<std::pair<types::ID, const Arg*>, 16> InputList; + + /// Whether the driver should follow g++ like behavior. + unsigned CCCIsCXX : 1; + + /// Whether the driver is just the preprocessor. + unsigned CCCIsCPP : 1; + + /// Echo commands while executing (in -v style). + unsigned CCCEcho : 1; + + /// Only print tool bindings, don't build any jobs. + unsigned CCCPrintBindings : 1; + + /// Set CC_PRINT_OPTIONS mode, which is like -v but logs the commands to + /// CCPrintOptionsFilename or to stderr. + unsigned CCPrintOptions : 1; + + /// Set CC_PRINT_HEADERS mode, which causes the frontend to log header include + /// information to CCPrintHeadersFilename or to stderr. + unsigned CCPrintHeaders : 1; + + /// Set CC_LOG_DIAGNOSTICS mode, which causes the frontend to log diagnostics + /// to CCLogDiagnosticsFilename or to stderr, in a stable machine readable + /// format. + unsigned CCLogDiagnostics : 1; + + /// Whether the driver is generating diagnostics for debugging purposes. + unsigned CCGenDiagnostics : 1; + +private: + /// Name to use when invoking gcc/g++. + std::string CCCGenericGCCName; + + /// Whether to check that input files exist when constructing compilation + /// jobs. + unsigned CheckInputsExist : 1; + + /// Use the clang compiler where possible. + unsigned CCCUseClang : 1; + + /// Use clang for handling C++ and Objective-C++ inputs. + unsigned CCCUseClangCXX : 1; + + /// Use clang as a preprocessor (clang's preprocessor will still be + /// used where an integrated CPP would). + unsigned CCCUseClangCPP : 1; + +public: + /// Use lazy precompiled headers for PCH support. + unsigned CCCUsePCH : 1; + +private: + /// Only use clang for the given architectures (only used when + /// non-empty). + std::set<llvm::Triple::ArchType> CCCClangArchs; + + /// Certain options suppress the 'no input files' warning. + bool SuppressMissingInputWarning : 1; + + std::list<std::string> TempFiles; + std::list<std::string> ResultFiles; + + /// \brief Cache of all the ToolChains in use by the driver. + /// + /// This maps from the string representation of a triple to a ToolChain + /// created targetting that triple. The driver owns all the ToolChain objects + /// stored in it, and will clean them up when torn down. + mutable llvm::StringMap<ToolChain *> ToolChains; + +private: + /// TranslateInputArgs - Create a new derived argument list from the input + /// arguments, after applying the standard argument translations. + DerivedArgList *TranslateInputArgs(const InputArgList &Args) const; + + // getFinalPhase - Determine which compilation mode we are in and record + // which option we used to determine the final phase. + phases::ID getFinalPhase(const DerivedArgList &DAL, Arg **FinalPhaseArg = 0) + const; + +public: + Driver(StringRef _ClangExecutable, + StringRef _DefaultTargetTriple, + StringRef _DefaultImageName, + bool IsProduction, + DiagnosticsEngine &_Diags); + ~Driver(); + + /// @name Accessors + /// @{ + + /// Name to use when invoking gcc/g++. + const std::string &getCCCGenericGCCName() const { return CCCGenericGCCName; } + + + const OptTable &getOpts() const { return *Opts; } + + const DiagnosticsEngine &getDiags() const { return Diags; } + + bool getCheckInputsExist() const { return CheckInputsExist; } + + void setCheckInputsExist(bool Value) { CheckInputsExist = Value; } + + const std::string &getTitle() { return DriverTitle; } + void setTitle(std::string Value) { DriverTitle = Value; } + + /// \brief Get the path to the main clang executable. + const char *getClangProgramPath() const { + return ClangExecutable.c_str(); + } + + /// \brief Get the path to where the clang executable was installed. + const char *getInstalledDir() const { + if (!InstalledDir.empty()) + return InstalledDir.c_str(); + return Dir.c_str(); + } + void setInstalledDir(StringRef Value) { + InstalledDir = Value; + } + + /// @} + /// @name Primary Functionality + /// @{ + + /// BuildCompilation - Construct a compilation object for a command + /// line argument vector. + /// + /// \return A compilation, or 0 if none was built for the given + /// argument vector. A null return value does not necessarily + /// indicate an error condition, the diagnostics should be queried + /// to determine if an error occurred. + Compilation *BuildCompilation(ArrayRef<const char *> Args); + + /// @name Driver Steps + /// @{ + + /// ParseArgStrings - Parse the given list of strings into an + /// ArgList. + InputArgList *ParseArgStrings(ArrayRef<const char *> Args); + + /// BuildInputs - Construct the list of inputs and their types from + /// the given arguments. + /// + /// \param TC - The default host tool chain. + /// \param Args - The input arguments. + /// \param Inputs - The list to store the resulting compilation + /// inputs onto. + void BuildInputs(const ToolChain &TC, const DerivedArgList &Args, + InputList &Inputs) const; + + /// BuildActions - Construct the list of actions to perform for the + /// given arguments, which are only done for a single architecture. + /// + /// \param TC - The default host tool chain. + /// \param Args - The input arguments. + /// \param Actions - The list to store the resulting actions onto. + void BuildActions(const ToolChain &TC, const DerivedArgList &Args, + const InputList &Inputs, ActionList &Actions) const; + + /// BuildUniversalActions - Construct the list of actions to perform + /// for the given arguments, which may require a universal build. + /// + /// \param TC - The default host tool chain. + /// \param Args - The input arguments. + /// \param Actions - The list to store the resulting actions onto. + void BuildUniversalActions(const ToolChain &TC, const DerivedArgList &Args, + const InputList &BAInputs, + ActionList &Actions) const; + + /// BuildJobs - Bind actions to concrete tools and translate + /// arguments to form the list of jobs to run. + /// + /// \arg C - The compilation that is being built. + void BuildJobs(Compilation &C) const; + + /// ExecuteCompilation - Execute the compilation according to the command line + /// arguments and return an appropriate exit code. + /// + /// This routine handles additional processing that must be done in addition + /// to just running the subprocesses, for example reporting errors, removing + /// temporary files, etc. + int ExecuteCompilation(const Compilation &C, + const Command *&FailingCommand) const; + + /// generateCompilationDiagnostics - Generate diagnostics information + /// including preprocessed source file(s). + /// + void generateCompilationDiagnostics(Compilation &C, + const Command *FailingCommand); + + /// @} + /// @name Helper Methods + /// @{ + + /// PrintActions - Print the list of actions. + void PrintActions(const Compilation &C) const; + + /// PrintHelp - Print the help text. + /// + /// \param ShowHidden - Show hidden options. + void PrintHelp(bool ShowHidden) const; + + /// PrintOptions - Print the list of arguments. + void PrintOptions(const ArgList &Args) const; + + /// PrintVersion - Print the driver version. + void PrintVersion(const Compilation &C, raw_ostream &OS) const; + + /// GetFilePath - Lookup \arg Name in the list of file search paths. + /// + /// \arg TC - The tool chain for additional information on + /// directories to search. + // + // FIXME: This should be in CompilationInfo. + std::string GetFilePath(const char *Name, const ToolChain &TC) const; + + /// GetProgramPath - Lookup \arg Name in the list of program search + /// paths. + /// + /// \arg TC - The provided tool chain for additional information on + /// directories to search. + /// + /// \arg WantFile - False when searching for an executable file, otherwise + /// true. Defaults to false. + // + // FIXME: This should be in CompilationInfo. + std::string GetProgramPath(const char *Name, const ToolChain &TC, + bool WantFile = false) const; + + /// HandleImmediateArgs - Handle any arguments which should be + /// treated before building actions or binding tools. + /// + /// \return Whether any compilation should be built for this + /// invocation. + bool HandleImmediateArgs(const Compilation &C); + + /// ConstructAction - Construct the appropriate action to do for + /// \arg Phase on the \arg Input, taking in to account arguments + /// like -fsyntax-only or --analyze. + Action *ConstructPhaseAction(const ArgList &Args, phases::ID Phase, + Action *Input) const; + + + /// BuildJobsForAction - Construct the jobs to perform for the + /// action \arg A. + void BuildJobsForAction(Compilation &C, + const Action *A, + const ToolChain *TC, + const char *BoundArch, + bool AtTopLevel, + const char *LinkingOutput, + InputInfo &Result) const; + + /// GetNamedOutputPath - Return the name to use for the output of + /// the action \arg JA. The result is appended to the compilation's + /// list of temporary or result files, as appropriate. + /// + /// \param C - The compilation. + /// \param JA - The action of interest. + /// \param BaseInput - The original input file that this action was + /// triggered by. + /// \param AtTopLevel - Whether this is a "top-level" action. + const char *GetNamedOutputPath(Compilation &C, + const JobAction &JA, + const char *BaseInput, + bool AtTopLevel) const; + + /// GetTemporaryPath - Return the pathname of a temporary file to use + /// as part of compilation; the file will have the given prefix and suffix. + /// + /// GCC goes to extra lengths here to be a bit more robust. + std::string GetTemporaryPath(StringRef Prefix, const char *Suffix) const; + + /// ShouldUseClangCompilar - Should the clang compiler be used to + /// handle this action. + bool ShouldUseClangCompiler(const Compilation &C, const JobAction &JA, + const llvm::Triple &ArchName) const; + + bool IsUsingLTO(const ArgList &Args) const; + +private: + /// \brief Retrieves a ToolChain for a particular target triple. + /// + /// Will cache ToolChains for the life of the driver object, and create them + /// on-demand. + const ToolChain &getToolChain(const ArgList &Args, + StringRef DarwinArchName = "") const; + + /// @} + +public: + /// GetReleaseVersion - Parse (([0-9]+)(.([0-9]+)(.([0-9]+)?))?)? and + /// return the grouped values as integers. Numbers which are not + /// provided are set to 0. + /// + /// \return True if the entire string was parsed (9.2), or all + /// groups were parsed (10.3.5extrastuff). HadExtra is true if all + /// groups were parsed but extra characters remain at the end. + static bool GetReleaseVersion(const char *Str, unsigned &Major, + unsigned &Minor, unsigned &Micro, + bool &HadExtra); +}; + +} // end namespace driver +} // end namespace clang + +#endif diff --git a/clang/include/clang/Driver/DriverDiagnostic.h b/clang/include/clang/Driver/DriverDiagnostic.h new file mode 100644 index 0000000..ea7b52f --- /dev/null +++ b/clang/include/clang/Driver/DriverDiagnostic.h @@ -0,0 +1,28 @@ +//===--- DiagnosticDriver.h - Diagnostics for libdriver ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_DRIVERDIAGNOSTIC_H +#define LLVM_CLANG_DRIVERDIAGNOSTIC_H + +#include "clang/Basic/Diagnostic.h" + +namespace clang { + namespace diag { + enum { +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\ + SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM, +#define DRIVERSTART +#include "clang/Basic/DiagnosticDriverKinds.inc" +#undef DIAG + NUM_BUILTIN_DRIVER_DIAGNOSTICS + }; + } // end namespace diag +} // end namespace clang + +#endif diff --git a/clang/include/clang/Driver/Job.h b/clang/include/clang/Driver/Job.h new file mode 100644 index 0000000..c94886d --- /dev/null +++ b/clang/include/clang/Driver/Job.h @@ -0,0 +1,122 @@ +//===--- Job.h - Commands to Execute ----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_DRIVER_JOB_H_ +#define CLANG_DRIVER_JOB_H_ + +#include "clang/Driver/Util.h" +#include "llvm/ADT/SmallVector.h" +#include "clang/Basic/LLVM.h" + +namespace clang { +namespace driver { +class Command; +class Tool; + +class Job { +public: + enum JobClass { + CommandClass, + JobListClass + }; + +private: + JobClass Kind; + +protected: + Job(JobClass _Kind) : Kind(_Kind) {} +public: + virtual ~Job(); + + JobClass getKind() const { return Kind; } + + /// addCommand - Append a command to the current job, which must be + /// either a piped job or a job list. + void addCommand(Command *C); + + static bool classof(const Job *) { return true; } +}; + + /// Command - An executable path/name and argument vector to + /// execute. +class Command : public Job { + virtual void anchor(); + + /// Source - The action which caused the creation of this job. + const Action &Source; + + /// Tool - The tool which caused the creation of this job. + const Tool &Creator; + + /// The executable to run. + const char *Executable; + + /// The list of program arguments (not including the implicit first + /// argument, which will be the executable). + ArgStringList Arguments; + +public: + Command(const Action &_Source, const Tool &_Creator, const char *_Executable, + const ArgStringList &_Arguments); + + /// getSource - Return the Action which caused the creation of this job. + const Action &getSource() const { return Source; } + + /// getCreator - Return the Tool which caused the creation of this job. + const Tool &getCreator() const { return Creator; } + + const char *getExecutable() const { return Executable; } + + const ArgStringList &getArguments() const { return Arguments; } + + static bool classof(const Job *J) { + return J->getKind() == CommandClass; + } + static bool classof(const Command *) { return true; } +}; + + /// JobList - A sequence of jobs to perform. +class JobList : public Job { +public: + typedef SmallVector<Job*, 4> list_type; + typedef list_type::size_type size_type; + typedef list_type::iterator iterator; + typedef list_type::const_iterator const_iterator; + +private: + list_type Jobs; + +public: + JobList(); + virtual ~JobList(); + + /// Add a job to the list (taking ownership). + void addJob(Job *J) { Jobs.push_back(J); } + + /// Clear the job list. + void clear(); + + const list_type &getJobs() const { return Jobs; } + + size_type size() const { return Jobs.size(); } + iterator begin() { return Jobs.begin(); } + const_iterator begin() const { return Jobs.begin(); } + iterator end() { return Jobs.end(); } + const_iterator end() const { return Jobs.end(); } + + static bool classof(const Job *J) { + return J->getKind() == JobListClass; + } + static bool classof(const JobList *) { return true; } +}; + +} // end namespace driver +} // end namespace clang + +#endif diff --git a/clang/include/clang/Driver/Makefile b/clang/include/clang/Driver/Makefile new file mode 100644 index 0000000..45bc40f --- /dev/null +++ b/clang/include/clang/Driver/Makefile @@ -0,0 +1,18 @@ +CLANG_LEVEL := ../../.. +BUILT_SOURCES = Options.inc CC1Options.inc CC1AsOptions.inc + +TABLEGEN_INC_FILES_COMMON = 1 + +include $(CLANG_LEVEL)/Makefile + +$(ObjDir)/Options.inc.tmp : Options.td OptParser.td $(CLANG_TBLGEN) $(ObjDir)/.dir + $(Echo) "Building Clang Driver Option tables with tblgen" + $(Verb) $(ClangTableGen) -gen-opt-parser-defs -o $(call SYSPATH, $@) $< + +$(ObjDir)/CC1Options.inc.tmp : CC1Options.td OptParser.td $(CLANG_TBLGEN) $(ObjDir)/.dir + $(Echo) "Building Clang CC1 Option tables with tblgen" + $(Verb) $(ClangTableGen) -gen-opt-parser-defs -o $(call SYSPATH, $@) $< + +$(ObjDir)/CC1AsOptions.inc.tmp : CC1AsOptions.td OptParser.td $(CLANG_TBLGEN) $(ObjDir)/.dir + $(Echo) "Building Clang CC1 Assembler Option tables with tblgen" + $(Verb) $(ClangTableGen) -gen-opt-parser-defs -o $(call SYSPATH, $@) $< diff --git a/clang/include/clang/Driver/ObjCRuntime.h b/clang/include/clang/Driver/ObjCRuntime.h new file mode 100644 index 0000000..094873a --- /dev/null +++ b/clang/include/clang/Driver/ObjCRuntime.h @@ -0,0 +1,49 @@ +//===--- ObjCRuntime.h - Objective C runtime features -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_DRIVER_OBJCRUNTIME_H_ +#define CLANG_DRIVER_OBJCRUNTIME_H_ + +namespace clang { +namespace driver { + +class ObjCRuntime { +public: + enum Kind { GNU, NeXT }; +private: + unsigned RuntimeKind : 1; +public: + void setKind(Kind k) { RuntimeKind = k; } + Kind getKind() const { return static_cast<Kind>(RuntimeKind); } + + /// True if the runtime provides native ARC entrypoints. ARC may + /// still be usable without this if the tool-chain provides a + /// statically-linked runtime support library. + unsigned HasARC : 1; + + /// True if the runtime supports ARC zeroing __weak. + unsigned HasWeak : 1; + + /// \brief True if the runtime supports subscripting methods. + unsigned HasSubscripting : 1; + + /// True if the runtime provides the following entrypoint: + /// void objc_terminate(void); + /// If available, this will be called instead of abort() when an + /// exception is thrown out of an EH cleanup. + unsigned HasTerminate : 1; + + ObjCRuntime() : RuntimeKind(NeXT), HasARC(false), HasWeak(false), + HasSubscripting(false), HasTerminate(false) {} +}; + +} +} + +#endif diff --git a/clang/include/clang/Driver/OptParser.td b/clang/include/clang/Driver/OptParser.td new file mode 100644 index 0000000..25ecbc3 --- /dev/null +++ b/clang/include/clang/Driver/OptParser.td @@ -0,0 +1,138 @@ +//===--- OptParser.td - Common Option Parsing Interfaces ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the common interfaces used by the option parsing TableGen +// backend. +// +//===----------------------------------------------------------------------===// + +// Define the kinds of options. + +class OptionKind<string name, int predecence = 0, bit sentinel = 0> { + string Name = name; + // The kind precedence, kinds with lower precedence are matched first. + int Precedence = predecence; + // Indicate a sentinel option. + bit Sentinel = sentinel; +} + +// An option group. +def KIND_GROUP : OptionKind<"Group">; +// The input option kind. +def KIND_INPUT : OptionKind<"Input", 1, 1>; +// The unknown option kind. +def KIND_UNKNOWN : OptionKind<"Unknown", 2, 1>; +// A flag with no values. +def KIND_FLAG : OptionKind<"Flag">; +// An option which prefixes its (single) value. +def KIND_JOINED : OptionKind<"Joined", 1>; +// An option which is followed by its value. +def KIND_SEPARATE : OptionKind<"Separate">; +// An option followed by its values, which are separated by commas. +def KIND_COMMAJOINED : OptionKind<"CommaJoined">; +// An option which is which takes multiple (separate) arguments. +def KIND_MULTIARG : OptionKind<"MultiArg">; +// An option which is either joined to its (non-empty) value, or followed by its +// value. +def KIND_JOINED_OR_SEPARATE : OptionKind<"JoinedOrSeparate">; +// An option which is both joined to its (first) value, and followed by its +// (second) value. +def KIND_JOINED_AND_SEPARATE : OptionKind<"JoinedAndSeparate">; + +// Define the option flags. + +class OptionFlag {} + +// DriverOption - The option is a "driver" option, and should not be forwarded +// to gcc. +def DriverOption : OptionFlag; + +// LinkerInput - The option is a linker input. +def LinkerInput : OptionFlag; + +// NoArgumentUnused - Don't report argument unused warnings for this option; this +// is useful for options like -static or -dynamic which a user may always end up +// passing, even if the platform defaults to (or only supports) that option. +def NoArgumentUnused : OptionFlag; + +// RenderAsInput - The option should not render the name when rendered as an +// input (i.e., the option is rendered as values). +def RenderAsInput : OptionFlag; + +// RenderJoined - The option should be rendered joined, even if separate (only +// sensible on single value separate options). +def RenderJoined : OptionFlag; + +// RenderSeparate - The option should be rendered separately, even if joined +// (only sensible on joined options). +def RenderSeparate : OptionFlag; + +// Unsupported - The option is unsupported, and the driver will reject command +// lines that use it. +def Unsupported : OptionFlag; + +// HelpHidden - The option should not be displayed in --help, even if it has +// help text. Clients *can* use this in conjunction with the OptTable::PrintHelp +// arguments to implement hidden help groups. +def HelpHidden : OptionFlag; + +// NoForward - The option should not be implicitly forwarded to other tools. +def NoForward : OptionFlag; + +// Define the option group class. + +class OptionGroup<string name> { + string EnumName = ?; // Uses the def name if undefined. + string Name = name; + string HelpText = ?; + OptionGroup Group = ?; +} + +// Define the option class. + +class Option<string name, OptionKind kind> { + string EnumName = ?; // Uses the def name if undefined. + string Name = name; + OptionKind Kind = kind; + // Used by MultiArg option kind. + int NumArgs = 0; + string HelpText = ?; + string MetaVarName = ?; + list<OptionFlag> Flags = []; + OptionGroup Group = ?; + Option Alias = ?; +} + +// Helpers for defining options. + +class Flag<string name> : Option<name, KIND_FLAG>; +class Joined<string name> : Option<name, KIND_JOINED>; +class Separate<string name> : Option<name, KIND_SEPARATE>; +class CommaJoined<string name> : Option<name, KIND_COMMAJOINED>; +class MultiArg<string name, int numargs> : Option<name, KIND_MULTIARG> { + int NumArgs = numargs; +} +class JoinedOrSeparate<string name> : Option<name, KIND_JOINED_OR_SEPARATE>; +class JoinedAndSeparate<string name> : Option<name, KIND_JOINED_AND_SEPARATE>; + +// Mix-ins for adding optional attributes. + +class Alias<Option alias> { Option Alias = alias; } +class EnumName<string name> { string EnumName = name; } +class Flags<list<OptionFlag> flags> { list<OptionFlag> Flags = flags; } +class Group<OptionGroup group> { OptionGroup Group = group; } +class HelpText<string text> { string HelpText = text; } +class MetaVarName<string name> { string MetaVarName = name; } + +// Predefined options. + +// FIXME: Have generator validate that these appear in correct position (and +// aren't duplicated). +def INPUT : Option<"<input>", KIND_INPUT>, Flags<[DriverOption]>; +def UNKNOWN : Option<"<unknown>", KIND_UNKNOWN>; diff --git a/clang/include/clang/Driver/OptSpecifier.h b/clang/include/clang/Driver/OptSpecifier.h new file mode 100644 index 0000000..bb1cd17 --- /dev/null +++ b/clang/include/clang/Driver/OptSpecifier.h @@ -0,0 +1,39 @@ +//===--- OptSpecifier.h - Option Specifiers ---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_DRIVER_OPTSPECIFIER_H +#define CLANG_DRIVER_OPTSPECIFIER_H + +namespace clang { +namespace driver { + class Option; + + /// OptSpecifier - Wrapper class for abstracting references to option IDs. + class OptSpecifier { + unsigned ID; + + private: + explicit OptSpecifier(bool); // DO NOT IMPLEMENT + + public: + OptSpecifier() : ID(0) {} + /*implicit*/ OptSpecifier(unsigned _ID) : ID(_ID) {} + /*implicit*/ OptSpecifier(const Option *Opt); + + bool isValid() const { return ID != 0; } + + unsigned getID() const { return ID; } + + bool operator==(OptSpecifier Opt) const { return ID == Opt.getID(); } + bool operator!=(OptSpecifier Opt) const { return !(*this == Opt); } + }; +} +} + +#endif diff --git a/clang/include/clang/Driver/OptTable.h b/clang/include/clang/Driver/OptTable.h new file mode 100644 index 0000000..3af6f8f --- /dev/null +++ b/clang/include/clang/Driver/OptTable.h @@ -0,0 +1,186 @@ +//===--- OptTable.h - Option Table ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_DRIVER_OPTTABLE_H +#define CLANG_DRIVER_OPTTABLE_H + +#include "clang/Basic/LLVM.h" +#include "clang/Driver/OptSpecifier.h" + +namespace clang { +namespace driver { +namespace options { + enum DriverFlag { + DriverOption = (1 << 0), + HelpHidden = (1 << 1), + LinkerInput = (1 << 2), + NoArgumentUnused = (1 << 3), + NoForward = (1 << 4), + RenderAsInput = (1 << 5), + RenderJoined = (1 << 6), + RenderSeparate = (1 << 7), + Unsupported = (1 << 8) + }; +} + + class Arg; + class ArgList; + class InputArgList; + class Option; + + /// OptTable - Provide access to the Option info table. + /// + /// The OptTable class provides a layer of indirection which allows Option + /// instance to be created lazily. In the common case, only a few options will + /// be needed at runtime; the OptTable class maintains enough information to + /// parse command lines without instantiating Options, while letting other + /// parts of the driver still use Option instances where convenient. + class OptTable { + public: + /// Info - Entry for a single option instance in the option data table. + struct Info { + const char *Name; + const char *HelpText; + const char *MetaVar; + unsigned char Kind; + unsigned char Param; + unsigned short Flags; + unsigned short GroupID; + unsigned short AliasID; + }; + + private: + /// The static option information table. + const Info *OptionInfos; + unsigned NumOptionInfos; + + /// The lazily constructed options table, indexed by option::ID - 1. + mutable Option **Options; + + /// Prebound input option instance. + const Option *TheInputOption; + + /// Prebound unknown option instance. + const Option *TheUnknownOption; + + /// The index of the first option which can be parsed (i.e., is not a + /// special option like 'input' or 'unknown', and is not an option group). + unsigned FirstSearchableIndex; + + private: + const Info &getInfo(OptSpecifier Opt) const { + unsigned id = Opt.getID(); + assert(id > 0 && id - 1 < getNumOptions() && "Invalid Option ID."); + return OptionInfos[id - 1]; + } + + Option *CreateOption(unsigned id) const; + + protected: + OptTable(const Info *_OptionInfos, unsigned _NumOptionInfos); + public: + ~OptTable(); + + /// getNumOptions - Return the total number of option classes. + unsigned getNumOptions() const { return NumOptionInfos; } + + /// getOption - Get the given \arg id's Option instance, lazily creating it + /// if necessary. + /// + /// \return The option, or null for the INVALID option id. + const Option *getOption(OptSpecifier Opt) const { + unsigned id = Opt.getID(); + if (id == 0) + return 0; + + assert((unsigned) (id - 1) < getNumOptions() && "Invalid ID."); + Option *&Entry = Options[id - 1]; + if (!Entry) + Entry = CreateOption(id); + return Entry; + } + + /// getOptionName - Lookup the name of the given option. + const char *getOptionName(OptSpecifier id) const { + return getInfo(id).Name; + } + + /// getOptionKind - Get the kind of the given option. + unsigned getOptionKind(OptSpecifier id) const { + return getInfo(id).Kind; + } + + /// getOptionGroupID - Get the group id for the given option. + unsigned getOptionGroupID(OptSpecifier id) const { + return getInfo(id).GroupID; + } + + /// isOptionHelpHidden - Should the help for the given option be hidden by + /// default. + bool isOptionHelpHidden(OptSpecifier id) const { + return getInfo(id).Flags & options::HelpHidden; + } + + /// getOptionHelpText - Get the help text to use to describe this option. + const char *getOptionHelpText(OptSpecifier id) const { + return getInfo(id).HelpText; + } + + /// getOptionMetaVar - Get the meta-variable name to use when describing + /// this options values in the help text. + const char *getOptionMetaVar(OptSpecifier id) const { + return getInfo(id).MetaVar; + } + + /// ParseOneArg - Parse a single argument; returning the new argument and + /// updating Index. + /// + /// \param [in] [out] Index - The current parsing position in the argument + /// string list; on return this will be the index of the next argument + /// string to parse. + /// + /// \return - The parsed argument, or 0 if the argument is missing values + /// (in which case Index still points at the conceptual next argument string + /// to parse). + Arg *ParseOneArg(const ArgList &Args, unsigned &Index) const; + + /// ParseArgs - Parse an list of arguments into an InputArgList. + /// + /// The resulting InputArgList will reference the strings in [ArgBegin, + /// ArgEnd), and their lifetime should extend past that of the returned + /// InputArgList. + /// + /// The only error that can occur in this routine is if an argument is + /// missing values; in this case \arg MissingArgCount will be non-zero. + /// + /// \param ArgBegin - The beginning of the argument vector. + /// \param ArgEnd - The end of the argument vector. + /// \param MissingArgIndex - On error, the index of the option which could + /// not be parsed. + /// \param MissingArgCount - On error, the number of missing options. + /// \return - An InputArgList; on error this will contain all the options + /// which could be parsed. + InputArgList *ParseArgs(const char* const *ArgBegin, + const char* const *ArgEnd, + unsigned &MissingArgIndex, + unsigned &MissingArgCount) const; + + /// PrintHelp - Render the help text for an option table. + /// + /// \param OS - The stream to write the help text to. + /// \param Name - The name to use in the usage line. + /// \param Title - The title to use in the usage line. + /// \param ShowHidden - Whether help-hidden arguments should be shown. + void PrintHelp(raw_ostream &OS, const char *Name, + const char *Title, bool ShowHidden = false) const; + }; +} +} + +#endif diff --git a/clang/include/clang/Driver/Option.h b/clang/include/clang/Driver/Option.h new file mode 100644 index 0000000..8243f6d --- /dev/null +++ b/clang/include/clang/Driver/Option.h @@ -0,0 +1,318 @@ +//===--- Option.h - Abstract Driver Options ---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_DRIVER_OPTION_H_ +#define CLANG_DRIVER_OPTION_H_ + +#include "clang/Driver/OptSpecifier.h" +#include "llvm/ADT/StringRef.h" +#include "clang/Basic/LLVM.h" + +namespace clang { +namespace driver { + class Arg; + class ArgList; + class OptionGroup; + + /// Option - Abstract representation for a single form of driver + /// argument. + /// + /// An Option class represents a form of option that the driver + /// takes, for example how many arguments the option has and how + /// they can be provided. Individual option instances store + /// additional information about what group the option is a member + /// of (if any), if the option is an alias, and a number of + /// flags. At runtime the driver parses the command line into + /// concrete Arg instances, each of which corresponds to a + /// particular Option instance. + class Option { + public: + enum OptionClass { + GroupClass = 0, + InputClass, + UnknownClass, + FlagClass, + JoinedClass, + SeparateClass, + CommaJoinedClass, + MultiArgClass, + JoinedOrSeparateClass, + JoinedAndSeparateClass + }; + + enum RenderStyleKind { + RenderCommaJoinedStyle, + RenderJoinedStyle, + RenderSeparateStyle, + RenderValuesStyle + }; + + private: + OptionClass Kind; + + /// The option ID. + OptSpecifier ID; + + /// The option name. + StringRef Name; + + /// Group this option is a member of, if any. + const OptionGroup *Group; + + /// Option that this is an alias for, if any. + const Option *Alias; + + /// Unsupported options will be rejected. + bool Unsupported : 1; + + /// Treat this option like a linker input? + bool LinkerInput : 1; + + /// When rendering as an input, don't render the option. + + // FIXME: We should ditch the render/renderAsInput distinction. + bool NoOptAsInput : 1; + + /// The style to using when rendering arguments parsed by this option. + unsigned RenderStyle : 2; + + /// This option is only consumed by the driver. + bool DriverOption : 1; + + /// This option should not report argument unused errors. + bool NoArgumentUnused : 1; + + /// This option should not be implicitly forwarded. + bool NoForward : 1; + + protected: + Option(OptionClass Kind, OptSpecifier ID, const char *Name, + const OptionGroup *Group, const Option *Alias); + public: + virtual ~Option(); + + unsigned getID() const { return ID.getID(); } + OptionClass getKind() const { return Kind; } + StringRef getName() const { return Name; } + const OptionGroup *getGroup() const { return Group; } + const Option *getAlias() const { return Alias; } + + bool isUnsupported() const { return Unsupported; } + void setUnsupported(bool Value) { Unsupported = Value; } + + bool isLinkerInput() const { return LinkerInput; } + void setLinkerInput(bool Value) { LinkerInput = Value; } + + bool hasNoOptAsInput() const { return NoOptAsInput; } + void setNoOptAsInput(bool Value) { NoOptAsInput = Value; } + + RenderStyleKind getRenderStyle() const { + return RenderStyleKind(RenderStyle); + } + void setRenderStyle(RenderStyleKind Value) { RenderStyle = Value; } + + bool isDriverOption() const { return DriverOption; } + void setDriverOption(bool Value) { DriverOption = Value; } + + bool hasNoArgumentUnused() const { return NoArgumentUnused; } + void setNoArgumentUnused(bool Value) { NoArgumentUnused = Value; } + + bool hasNoForward() const { return NoForward; } + void setNoForward(bool Value) { NoForward = Value; } + + bool hasForwardToGCC() const { + return !NoForward && !DriverOption && !LinkerInput; + } + + /// getUnaliasedOption - Return the final option this option + /// aliases (itself, if the option has no alias). + const Option *getUnaliasedOption() const { + if (Alias) return Alias->getUnaliasedOption(); + return this; + } + + /// getRenderName - Return the name to use when rendering this + /// option. + StringRef getRenderName() const { + return getUnaliasedOption()->getName(); + } + + /// matches - Predicate for whether this option is part of the + /// given option (which may be a group). + /// + /// Note that matches against options which are an alias should never be + /// done -- aliases do not participate in matching and so such a query will + /// always be false. + bool matches(OptSpecifier ID) const; + + /// accept - Potentially accept the current argument, returning a + /// new Arg instance, or 0 if the option does not accept this + /// argument (or the argument is missing values). + /// + /// If the option accepts the current argument, accept() sets + /// Index to the position where argument parsing should resume + /// (even if the argument is missing values). + virtual Arg *accept(const ArgList &Args, unsigned &Index) const = 0; + + void dump() const; + + static bool classof(const Option *) { return true; } + }; + + /// OptionGroup - A set of options which are can be handled uniformly + /// by the driver. + class OptionGroup : public Option { + public: + OptionGroup(OptSpecifier ID, const char *Name, const OptionGroup *Group); + + virtual Arg *accept(const ArgList &Args, unsigned &Index) const; + + static bool classof(const Option *O) { + return O->getKind() == Option::GroupClass; + } + static bool classof(const OptionGroup *) { return true; } + }; + + // Dummy option classes. + + /// InputOption - Dummy option class for representing driver inputs. + class InputOption : public Option { + public: + InputOption(OptSpecifier ID); + + virtual Arg *accept(const ArgList &Args, unsigned &Index) const; + + static bool classof(const Option *O) { + return O->getKind() == Option::InputClass; + } + static bool classof(const InputOption *) { return true; } + }; + + /// UnknownOption - Dummy option class for represent unknown arguments. + class UnknownOption : public Option { + public: + UnknownOption(OptSpecifier ID); + + virtual Arg *accept(const ArgList &Args, unsigned &Index) const; + + static bool classof(const Option *O) { + return O->getKind() == Option::UnknownClass; + } + static bool classof(const UnknownOption *) { return true; } + }; + + // Normal options. + + class FlagOption : public Option { + public: + FlagOption(OptSpecifier ID, const char *Name, const OptionGroup *Group, + const Option *Alias); + + virtual Arg *accept(const ArgList &Args, unsigned &Index) const; + + static bool classof(const Option *O) { + return O->getKind() == Option::FlagClass; + } + static bool classof(const FlagOption *) { return true; } + }; + + class JoinedOption : public Option { + public: + JoinedOption(OptSpecifier ID, const char *Name, const OptionGroup *Group, + const Option *Alias); + + virtual Arg *accept(const ArgList &Args, unsigned &Index) const; + + static bool classof(const Option *O) { + return O->getKind() == Option::JoinedClass; + } + static bool classof(const JoinedOption *) { return true; } + }; + + class SeparateOption : public Option { + public: + SeparateOption(OptSpecifier ID, const char *Name, + const OptionGroup *Group, const Option *Alias); + + virtual Arg *accept(const ArgList &Args, unsigned &Index) const; + + static bool classof(const Option *O) { + return O->getKind() == Option::SeparateClass; + } + static bool classof(const SeparateOption *) { return true; } + }; + + class CommaJoinedOption : public Option { + public: + CommaJoinedOption(OptSpecifier ID, const char *Name, + const OptionGroup *Group, const Option *Alias); + + virtual Arg *accept(const ArgList &Args, unsigned &Index) const; + + static bool classof(const Option *O) { + return O->getKind() == Option::CommaJoinedClass; + } + static bool classof(const CommaJoinedOption *) { return true; } + }; + + // FIXME: Fold MultiArgOption into SeparateOption? + + /// MultiArgOption - An option which takes multiple arguments (these + /// are always separate arguments). + class MultiArgOption : public Option { + unsigned NumArgs; + + public: + MultiArgOption(OptSpecifier ID, const char *Name, const OptionGroup *Group, + const Option *Alias, unsigned NumArgs); + + unsigned getNumArgs() const { return NumArgs; } + + virtual Arg *accept(const ArgList &Args, unsigned &Index) const; + + static bool classof(const Option *O) { + return O->getKind() == Option::MultiArgClass; + } + static bool classof(const MultiArgOption *) { return true; } + }; + + /// JoinedOrSeparateOption - An option which either literally + /// prefixes its (non-empty) value, or is follwed by a value. + class JoinedOrSeparateOption : public Option { + public: + JoinedOrSeparateOption(OptSpecifier ID, const char *Name, + const OptionGroup *Group, const Option *Alias); + + virtual Arg *accept(const ArgList &Args, unsigned &Index) const; + + static bool classof(const Option *O) { + return O->getKind() == Option::JoinedOrSeparateClass; + } + static bool classof(const JoinedOrSeparateOption *) { return true; } + }; + + /// JoinedAndSeparateOption - An option which literally prefixes its + /// value and is followed by another value. + class JoinedAndSeparateOption : public Option { + public: + JoinedAndSeparateOption(OptSpecifier ID, const char *Name, + const OptionGroup *Group, const Option *Alias); + + virtual Arg *accept(const ArgList &Args, unsigned &Index) const; + + static bool classof(const Option *O) { + return O->getKind() == Option::JoinedAndSeparateClass; + } + static bool classof(const JoinedAndSeparateOption *) { return true; } + }; + +} // end namespace driver +} // end namespace clang + +#endif diff --git a/clang/include/clang/Driver/Options.h b/clang/include/clang/Driver/Options.h new file mode 100644 index 0000000..ac312cd --- /dev/null +++ b/clang/include/clang/Driver/Options.h @@ -0,0 +1,32 @@ +//===--- Options.h - Option info & table ------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_DRIVER_OPTIONS_H +#define CLANG_DRIVER_OPTIONS_H + +namespace clang { +namespace driver { + class OptTable; + +namespace options { + enum ID { + OPT_INVALID = 0, // This is not an option ID. +#define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \ + HELPTEXT, METAVAR) OPT_##ID, +#include "clang/Driver/Options.inc" + LastOption +#undef OPTION + }; +} + + OptTable *createDriverOptTable(); +} +} + +#endif diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td new file mode 100644 index 0000000..b796771 --- /dev/null +++ b/clang/include/clang/Driver/Options.td @@ -0,0 +1,967 @@ +//===--- DriverOptions.td - Options for clang -----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the options accepted by clang. +// +//===----------------------------------------------------------------------===// + +// Include the common option parsing interfaces. +include "OptParser.td" + +///////// +// Groups + +// Meta-group which defines +def CompileOnly_Group : OptionGroup<"<CompileOnly group>">; + +def I_Group : OptionGroup<"<I group>">, Group<CompileOnly_Group>; +def L_Group : OptionGroup<"<L group>">, Group<CompileOnly_Group>; +def M_Group : OptionGroup<"<M group>">, Group<CompileOnly_Group>; +def T_Group : OptionGroup<"<T group>">; +def O_Group : OptionGroup<"<O group>">, Group<CompileOnly_Group>; +def W_Group : OptionGroup<"<W group>">, Group<CompileOnly_Group>; +def X_Group : OptionGroup<"<X group>">; +def a_Group : OptionGroup<"<a group>">; +def d_Group : OptionGroup<"<d group>">; +def f_Group : OptionGroup<"<f group>">, Group<CompileOnly_Group>; +def f_clang_Group : OptionGroup<"<f (clang-only) group>">, Group<CompileOnly_Group>; +def g_Group : OptionGroup<"<g group>">; +def i_Group : OptionGroup<"<i group>">, Group<CompileOnly_Group>; +def clang_i_Group : OptionGroup<"<clang i group>">, Group<i_Group>; +def m_Group : OptionGroup<"<m group>">, Group<CompileOnly_Group>; +def m_x86_Features_Group : OptionGroup<"<m x86 features group>">, Group<m_Group>; +def u_Group : OptionGroup<"<u group>">; + +def pedantic_Group : OptionGroup<"<pedantic group>">, + Group<CompileOnly_Group>; +def reserved_lib_Group : OptionGroup<"<reserved libs group>">; + +// Temporary groups for clang options which we know we don't support, +// but don't want to verbosely warn the user about. +def clang_ignored_f_Group : OptionGroup<"<clang ignored f group>">, + Group<f_Group>; +def clang_ignored_m_Group : OptionGroup<"<clang ignored m group>">, + Group<m_Group>; + +///////// +// Options + +// The internal option ID must be a valid C++ identifier and results in a +// clang::driver::options::OPT_XX enum constant for XX. +// +// We want to unambiguously be able to refer to options from the driver source +// code, for this reason the option name is mangled into an ID. This mangling +// isn't guaranteed to have an inverse, but for practical purposes it does. +// +// The mangling scheme is to ignore the leading '-', and perform the following +// substitutions: +// _ => __ +// - => _ +// # => _HASH +// , => _COMMA +// = => _EQ +// C++ => CXX +// . => _ + +// Developer Driver Options + +def ccc_Group : OptionGroup<"<clang internal options>">; +def ccc_driver_Group : OptionGroup<"<clang driver internal options>">, + Group<ccc_Group>, HelpText<"DRIVER OPTIONS">; +def ccc_debug_Group : OptionGroup<"<clang debug/development internal options>">, + Group<ccc_Group>, HelpText<"DEBUG/DEVELOPMENT OPTIONS">; + +class CCCDriverOpt : Group<ccc_driver_Group>, Flags<[DriverOption, HelpHidden]>; +def ccc_cxx : Flag<"-ccc-cxx">, CCCDriverOpt, + HelpText<"Act as a C++ driver">; +def ccc_echo : Flag<"-ccc-echo">, CCCDriverOpt, + HelpText<"Echo commands before running them">; +def ccc_gcc_name : Separate<"-ccc-gcc-name">, CCCDriverOpt, + HelpText<"Name for native GCC compiler">, + MetaVarName<"<gcc-path>">; +def ccc_clang_cxx : Flag<"-ccc-clang-cxx">, CCCDriverOpt, + HelpText<"Enable the clang compiler for C++">; +def ccc_no_clang_cxx : Flag<"-ccc-no-clang-cxx">, CCCDriverOpt, + HelpText<"Disable the clang compiler for C++">; +def ccc_no_clang : Flag<"-ccc-no-clang">, CCCDriverOpt, + HelpText<"Disable the clang compiler">; +def ccc_no_clang_cpp : Flag<"-ccc-no-clang-cpp">, CCCDriverOpt, + HelpText<"Disable the clang preprocessor">; +def ccc_clang_archs : Separate<"-ccc-clang-archs">, CCCDriverOpt, + HelpText<"Comma separate list of architectures to use the clang compiler for">, + MetaVarName<"<arch-list>">; +def ccc_pch_is_pch : Flag<"-ccc-pch-is-pch">, CCCDriverOpt, + HelpText<"Use lazy PCH for precompiled headers">; +def ccc_pch_is_pth : Flag<"-ccc-pch-is-pth">, CCCDriverOpt, + HelpText<"Use pretokenized headers for precompiled headers">; + +class CCCDebugOpt : Group<ccc_debug_Group>, Flags<[DriverOption, HelpHidden]>; +def ccc_install_dir : Separate<"-ccc-install-dir">, CCCDebugOpt, + HelpText<"Simulate installation in the given directory">; +def ccc_print_options : Flag<"-ccc-print-options">, CCCDebugOpt, + HelpText<"Dump parsed command line arguments">; +def ccc_print_phases : Flag<"-ccc-print-phases">, CCCDebugOpt, + HelpText<"Dump list of actions to perform">; +def ccc_print_bindings : Flag<"-ccc-print-bindings">, CCCDebugOpt, + HelpText<"Show bindings of tools to actions">; + +def ccc_arcmt_check : Flag<"-ccc-arcmt-check">, CCCDriverOpt, + HelpText<"Check for ARC migration issues that need manual handling">; +def ccc_arcmt_modify : Flag<"-ccc-arcmt-modify">, CCCDriverOpt, + HelpText<"Apply modifications to files to conform to ARC">; +def ccc_arrmt_check : Flag<"-ccc-arrmt-check">, Alias<ccc_arcmt_check>; +def ccc_arrmt_modify : Flag<"-ccc-arrmt-modify">, Alias<ccc_arcmt_modify>; +def ccc_arcmt_migrate : Separate<"-ccc-arcmt-migrate">, CCCDriverOpt, + HelpText<"Apply modifications and produces temporary files that conform to ARC">; +def arcmt_migrate_report_output : Separate<"-arcmt-migrate-report-output">, + HelpText<"Output path for the plist report">; +def arcmt_migrate_emit_arc_errors : Flag<"-arcmt-migrate-emit-errors">, + HelpText<"Emit ARC errors even if the migrator can fix them">; + +def _migrate : Flag<"--migrate">, Flags<[DriverOption]>, + HelpText<"Run the migrator">; +def ccc_objcmt_migrate : Separate<"-ccc-objcmt-migrate">, CCCDriverOpt, + HelpText<"Apply modifications and produces temporary files to migrate to " + "modern ObjC syntax">; +def objcmt_migrate_literals : Flag<"-objcmt-migrate-literals">, + HelpText<"Enable migration to modern ObjC literals">; +def objcmt_migrate_subscripting : Flag<"-objcmt-migrate-subscripting">, + HelpText<"Enable migration to modern ObjC subscripting">; + +// Make sure all other -ccc- options are rejected. +def ccc_ : Joined<"-ccc-">, Group<ccc_Group>, Flags<[Unsupported]>; + +// Standard Options + +def _HASH_HASH_HASH : Flag<"-###">, Flags<[DriverOption]>, + HelpText<"Print the commands to run for this compilation">; +// The '--' option is here for the sake of compatibility with gcc, but is +// being ignored by the driver. +def _DASH_DASH : Flag<"--">, Flags<[DriverOption]>; +def A : JoinedOrSeparate<"-A">; +def B : JoinedOrSeparate<"-B">; +def CC : Flag<"-CC">; +def C : Flag<"-C">; +def D : JoinedOrSeparate<"-D">, Group<CompileOnly_Group>; +def E : Flag<"-E">, Flags<[DriverOption]>, + HelpText<"Only run the preprocessor">; +def F : JoinedOrSeparate<"-F">, Flags<[RenderJoined]>; +def G : Separate<"-G">, Flags<[DriverOption]>; +def H : Flag<"-H">; +def I_ : Flag<"-I-">, Group<I_Group>; +def I : JoinedOrSeparate<"-I">, Group<I_Group>; +def L : JoinedOrSeparate<"-L">, Flags<[RenderJoined]>; +def MD : Flag<"-MD">, Group<M_Group>; +def MF : JoinedOrSeparate<"-MF">, Group<M_Group>; +def MG : Flag<"-MG">, Group<M_Group>; +def MMD : Flag<"-MMD">, Group<M_Group>; +def MM : Flag<"-MM">, Group<M_Group>; +def MP : Flag<"-MP">, Group<M_Group>; +def MQ : JoinedOrSeparate<"-MQ">, Group<M_Group>; +def MT : JoinedOrSeparate<"-MT">, Group<M_Group>; +def Mach : Flag<"-Mach">; +def M : Flag<"-M">, Group<M_Group>; +def O0 : Joined<"-O0">, Group<O_Group>; +def O4 : Joined<"-O4">, Group<O_Group>; +def ObjCXX : Flag<"-ObjC++">, Flags<[DriverOption]>, + HelpText<"Treat source input files as Objective-C++ inputs">; +def ObjC : Flag<"-ObjC">, Flags<[DriverOption]>, + HelpText<"Treat source input files as Objective-C inputs">; +def O : Joined<"-O">, Group<O_Group>; +def P : Flag<"-P">; +def Qn : Flag<"-Qn">; +def Qunused_arguments : Flag<"-Qunused-arguments">, Flags<[DriverOption]>, + HelpText<"Don't emit warning for unused driver arguments">; +def Q : Flag<"-Q">; +def R : Flag<"-R">; +def S : Flag<"-S">, Flags<[DriverOption]>, + HelpText<"Only run preprocess and compilation steps">; +def Tbss : JoinedOrSeparate<"-Tbss">, Group<T_Group>; +def Tdata : JoinedOrSeparate<"-Tdata">, Group<T_Group>; +def Ttext : JoinedOrSeparate<"-Ttext">, Group<T_Group>; +def T : JoinedOrSeparate<"-T">, Group<T_Group>; +def U : JoinedOrSeparate<"-U">, Group<CompileOnly_Group>; +def V : JoinedOrSeparate<"-V">, Flags<[DriverOption, Unsupported]>; +def Wa_COMMA : CommaJoined<"-Wa,">, + HelpText<"Pass the comma separated arguments in <arg> to the assembler">, + MetaVarName<"<arg>">; +def Wall : Flag<"-Wall">, Group<W_Group>; +def Wdeprecated : Flag<"-Wdeprecated">, Group<W_Group>; +def Wno_deprecated : Flag<"-Wno-deprecated">, Group<W_Group>; +def Wextra : Flag<"-Wextra">, Group<W_Group>; +def Wl_COMMA : CommaJoined<"-Wl,">, Flags<[LinkerInput, RenderAsInput]>, + HelpText<"Pass the comma separated arguments in <arg> to the linker">, + MetaVarName<"<arg>">; +def Wno_nonportable_cfstrings : Joined<"-Wno-nonportable-cfstrings">, Group<W_Group>; +def Wnonportable_cfstrings : Joined<"-Wnonportable-cfstrings">, Group<W_Group>; +def Wp_COMMA : CommaJoined<"-Wp,">, + HelpText<"Pass the comma separated arguments in <arg> to the preprocessor">, + MetaVarName<"<arg>">; +def Wwrite_strings : Flag<"-Wwrite-strings">, Group<W_Group>; +def Wno_write_strings : Flag<"-Wno-write-strings">, Group<W_Group>; +def W_Joined : Joined<"-W">, Group<W_Group>; +def Xanalyzer : Separate<"-Xanalyzer">, + HelpText<"Pass <arg> to the static analyzer">, MetaVarName<"<arg>">; +def Xarch__ : JoinedAndSeparate<"-Xarch_">, Flags<[DriverOption]>; +def Xassembler : Separate<"-Xassembler">, + HelpText<"Pass <arg> to the assembler">, MetaVarName<"<arg>">; +def Xclang : Separate<"-Xclang">, + HelpText<"Pass <arg> to the clang compiler">, MetaVarName<"<arg>">, + Flags<[NoForward]>; +def Xlinker : Separate<"-Xlinker">, Flags<[LinkerInput, RenderAsInput]>, + HelpText<"Pass <arg> to the linker">, MetaVarName<"<arg>">; +def Xpreprocessor : Separate<"-Xpreprocessor">, + HelpText<"Pass <arg> to the preprocessor">, MetaVarName<"<arg>">; +def X_Flag : Flag<"-X">; +def X_Joined : Joined<"-X">; +def Z_Flag : Flag<"-Z">; +def Z_Joined : Joined<"-Z">; +def all__load : Flag<"-all_load">; +def allowable__client : Separate<"-allowable_client">; +def ansi : Flag<"-ansi">, Group<a_Group>; +def arch__errors__fatal : Flag<"-arch_errors_fatal">; +def arch : Separate<"-arch">, Flags<[DriverOption]>; +def arch__only : Separate<"-arch_only">; +def a : Joined<"-a">, Group<a_Group>; +def bind__at__load : Flag<"-bind_at_load">; +def bundle__loader : Separate<"-bundle_loader">; +def bundle : Flag<"-bundle">; +def b : JoinedOrSeparate<"-b">, Flags<[Unsupported]>; +def client__name : JoinedOrSeparate<"-client_name">; +def combine : Flag<"-combine">, Flags<[DriverOption, Unsupported]>; +def compatibility__version : JoinedOrSeparate<"-compatibility_version">; +def coverage : Flag<"-coverage">; +def cpp_precomp : Flag<"-cpp-precomp">, Group<clang_ignored_f_Group>; +def current__version : JoinedOrSeparate<"-current_version">; +def cxx_isystem : JoinedOrSeparate<"-cxx-isystem">, Group<clang_i_Group>; +def c : Flag<"-c">, Flags<[DriverOption]>, + HelpText<"Only run preprocess, compile, and assemble steps">; +def dA : Flag<"-dA">, Group<d_Group>; +def dD : Flag<"-dD">, Group<d_Group>; +def dM : Flag<"-dM">, Group<d_Group>; +def dead__strip : Flag<"-dead_strip">; +def dependency_file : Separate<"-dependency-file">; +def dumpmachine : Flag<"-dumpmachine">; +def dumpspecs : Flag<"-dumpspecs">, Flags<[Unsupported]>; +def dumpversion : Flag<"-dumpversion">; +def dylib__file : Separate<"-dylib_file">; +def dylinker__install__name : JoinedOrSeparate<"-dylinker_install_name">; +def dylinker : Flag<"-dylinker">; +def dynamiclib : Flag<"-dynamiclib">; +def dynamic : Flag<"-dynamic">, Flags<[NoArgumentUnused]>; +def d_Flag : Flag<"-d">, Group<d_Group>; +def d_Joined : Joined<"-d">, Group<d_Group>; +def emit_ast : Flag<"-emit-ast">, + HelpText<"Emit Clang AST files for source inputs">; +def emit_llvm : Flag<"-emit-llvm">, + HelpText<"Use the LLVM representation for assembler and object files">; +def exported__symbols__list : Separate<"-exported_symbols_list">; +def e : JoinedOrSeparate<"-e">; +def fPIC : Flag<"-fPIC">, Group<f_Group>; +def fno_PIC : Flag<"-fno-PIC">, Group<f_Group>; +def fPIE : Flag<"-fPIE">, Group<f_Group>; +def fno_PIE : Flag<"-fno-PIE">, Group<f_Group>; +def faccess_control : Flag<"-faccess-control">, Group<f_Group>; +def fallow_unsupported : Flag<"-fallow-unsupported">, Group<f_Group>; +def faltivec : Flag<"-faltivec">, Group<f_Group>; +def fapple_kext : Flag<"-fapple-kext">, Group<f_Group>; +def fapple_pragma_pack : Flag<"-fapple-pragma-pack">, Group<f_Group>; +def faddress_sanitizer : Flag<"-faddress-sanitizer">, Group<f_Group>; +def fno_address_sanitizer : Flag<"-fno-address-sanitizer">, Group<f_Group>; +def fthread_sanitizer : Flag<"-fthread-sanitizer">, Group<f_Group>; +def fno_thread_sanitizer : Flag<"-fno-thread-sanitizer">, Group<f_Group>; +def fasm : Flag<"-fasm">, Group<f_Group>; + +def fasm_blocks : Flag<"-fasm-blocks">, Group<f_Group>; +def fno_asm_blocks : Flag<"-fno-asm-blocks">, Group<f_Group>; + +def fassume_sane_operator_new : Flag<"-fassume-sane-operator-new">, Group<f_Group>; +def fastcp : Flag<"-fastcp">, Group<f_Group>; +def fastf : Flag<"-fastf">, Group<f_Group>; +def fast : Flag<"-fast">, Group<f_Group>; +def fasynchronous_unwind_tables : Flag<"-fasynchronous-unwind-tables">, Group<f_Group>; +def fblocks : Flag<"-fblocks">, Group<f_Group>; +def fbootclasspath_EQ : Joined<"-fbootclasspath=">, Group<f_Group>; +def fborland_extensions : Flag<"-fborland-extensions">, Group<f_Group>; +def fbuiltin_strcat : Flag<"-fbuiltin-strcat">, Group<f_Group>; +def fbuiltin_strcpy : Flag<"-fbuiltin-strcpy">, Group<f_Group>; +def fbuiltin : Flag<"-fbuiltin">, Group<f_Group>; +def fcaret_diagnostics : Flag<"-fcaret-diagnostics">, Group<f_Group>; +def fcatch_undefined_behavior : Flag<"-fcatch-undefined-behavior">, + Group<f_Group>, HelpText<"Generate runtime checks for undefined behavior.">; +def fclasspath_EQ : Joined<"-fclasspath=">, Group<f_Group>; +def fcolor_diagnostics : Flag<"-fcolor-diagnostics">, Group<f_Group>; +def fcommon : Flag<"-fcommon">, Group<f_Group>; +def fcompile_resource_EQ : Joined<"-fcompile-resource=">, Group<f_Group>; +def fconstant_cfstrings : Flag<"-fconstant-cfstrings">, Group<f_Group>; +def fconstant_string_class_EQ : Joined<"-fconstant-string-class=">, Group<f_Group>; +def fconstexpr_depth_EQ : Joined<"-fconstexpr-depth=">, Group<f_Group>; +def fconstexpr_backtrace_limit_EQ : Joined<"-fconstexpr-backtrace-limit=">, + Group<f_Group>; +def fno_crash_diagnostics : Flag<"-fno-crash-diagnostics">, Group<f_clang_Group>, Flags<[NoArgumentUnused]>; +def fcreate_profile : Flag<"-fcreate-profile">, Group<f_Group>; +def fcxx_exceptions: Flag<"-fcxx-exceptions">, Group<f_Group>; +def fcxx_modules : Flag <"-fcxx-modules">, Group<f_Group>, Flags<[NoForward]>; +def fdebug_pass_arguments : Flag<"-fdebug-pass-arguments">, Group<f_Group>; +def fdebug_pass_structure : Flag<"-fdebug-pass-structure">, Group<f_Group>; +def fdiagnostics_fixit_info : Flag<"-fdiagnostics-fixit-info">, Group<f_clang_Group>; +def fdiagnostics_print_source_range_info : Flag<"-fdiagnostics-print-source-range-info">, Group<f_clang_Group>; +def fdiagnostics_parseable_fixits : Flag<"-fdiagnostics-parseable-fixits">, Group<f_clang_Group>; +def fdiagnostics_show_option : Flag<"-fdiagnostics-show-option">, Group<f_Group>; +def fdiagnostics_show_note_include_stack : Flag<"-fdiagnostics-show-note-include-stack">, Group<f_Group>; +def fdiagnostics_format_EQ : Joined<"-fdiagnostics-format=">, Group<f_clang_Group>; +def fdiagnostics_show_category_EQ : Joined<"-fdiagnostics-show-category=">, Group<f_clang_Group>; +def fdollars_in_identifiers : Flag<"-fdollars-in-identifiers">, Group<f_Group>; +def fdwarf2_cfi_asm : Flag<"-fdwarf2-cfi-asm">, Group<f_Group>; +def fno_dwarf2_cfi_asm : Flag<"-fno-dwarf2-cfi-asm">, Group<f_Group>; +def fdwarf_directory_asm : Flag<"-fdwarf-directory-asm">, Group<f_Group>; +def fno_dwarf_directory_asm : Flag<"-fno-dwarf-directory-asm">, Group<f_Group>; +def felide_constructors : Flag<"-felide-constructors">, Group<f_Group>; +def feliminate_unused_debug_symbols : Flag<"-feliminate-unused-debug-symbols">, Group<f_Group>; +def femit_all_decls : Flag<"-femit-all-decls">, Group<f_Group>; +def fencoding_EQ : Joined<"-fencoding=">, Group<f_Group>; +def ferror_limit_EQ : Joined<"-ferror-limit=">, Group<f_Group>; +def fexceptions : Flag<"-fexceptions">, Group<f_Group>; +def fextdirs_EQ : Joined<"-fextdirs=">, Group<f_Group>; +def fhosted : Flag<"-fhosted">, Group<f_Group>; +def ffast_math : Flag<"-ffast-math">, Group<f_Group>; +def fmath_errno : Flag<"-fmath-errno">, Group<f_Group>; +def fno_math_errno : Flag<"-fno-math-errno">, Group<f_Group>; +def fsignaling_math : Flag<"-fsignaling-math">, Group<f_Group>; +def fno_signaling_math : Flag<"-fno-signaling-math">, Group<f_Group>; +def funsafe_math_optimizations : Flag<"-funsafe-math-optimizations">, + Group<f_Group>; +def fno_unsafe_math_optimizations : Flag<"-fno-unsafe-math-optimizations">, + Group<f_Group>; +def fassociative_math : Flag<"-fassociative-math">, Group<f_Group>; +def fno_associative_math : Flag<"-fno-associative-math">, Group<f_Group>; +def freciprocal_math : Flag<"-freciprocal-math">, Group<f_Group>; +def fno_reciprocal_math : Flag<"-fno-reciprocal-math">, Group<f_Group>; +def ffinite_math_only : Flag<"-ffinite-math-only">, Group<f_Group>; +def fno_finite_math_only : Flag<"-fno-finite-math-only">, Group<f_Group>; +def fsigned_zeros : Flag<"-fsigned-zeros">, Group<f_Group>; +def fno_signed_zeros : Flag<"-fno-signed-zeros">, Group<f_Group>; +def fhonor_nans : Flag<"-fhonor-nans">, Group<f_Group>; +def fno_honor_nans : Flag<"-fno-honor-nans">, Group<f_Group>; +def fhonor_infinities : Flag<"-fhonor-infinities">, Group<f_Group>; +def fno_honor_infinities : Flag<"-fno-honor-infinities">, Group<f_Group>; +// Sic. This option was misspelled originally. +def fhonor_infinites : Flag<"-fhonor-infinites">, Group<f_Group>, + Alias<fhonor_infinities>; +def fno_honor_infinites : Flag<"-fno-honor-infinites">, Group<f_Group>, + Alias<fno_honor_infinities>; +def ftrapping_math : Flag<"-ftrapping-math">, Group<f_Group>; +def fno_trapping_math : Flag<"-fno-trapping-math">, Group<f_Group>; + +def ffor_scope : Flag<"-ffor-scope">, Group<f_Group>; +def fno_for_scope : Flag<"-fno-for-scope">, Group<f_Group>; + +def ffreestanding : Flag<"-ffreestanding">, Group<f_Group>; +def fgnu_keywords : Flag<"-fgnu-keywords">, Group<f_Group>; +def fgnu89_inline : Flag<"-fgnu89-inline">, Group<f_Group>; +def fno_gnu89_inline : Flag<"-fno-gnu89-inline">, Group<f_Group>; +def fgnu_runtime : Flag<"-fgnu-runtime">, Group<f_Group>; +def fheinous_gnu_extensions : Flag<"-fheinous-gnu-extensions">; +def filelist : Separate<"-filelist">, Flags<[LinkerInput]>; +def findirect_virtual_calls : Flag<"-findirect-virtual-calls">, Alias<fapple_kext>; +def finline_functions : Flag<"-finline-functions">, Group<clang_ignored_f_Group>; +def finline : Flag<"-finline">, Group<clang_ignored_f_Group>; +def finstrument_functions : Flag<"-finstrument-functions">, Group<f_Group>; +def fkeep_inline_functions : Flag<"-fkeep-inline-functions">, Group<clang_ignored_f_Group>; +def flat__namespace : Flag<"-flat_namespace">; +def flax_vector_conversions : Flag<"-flax-vector-conversions">, Group<f_Group>; +def flimit_debug_info : Flag<"-flimit-debug-info">, Group<f_Group>, + HelpText<"Limit debug information produced to reduce size of debug binary">; +def flimited_precision_EQ : Joined<"-flimited-precision=">, Group<f_Group>; +def flto : Flag<"-flto">, Group<f_Group>; +def fno_lto : Flag<"-fno-lto">, Group<f_Group>; +def fmacro_backtrace_limit_EQ : Joined<"-fmacro-backtrace-limit=">, + Group<f_Group>; +def fmerge_all_constants : Flag<"-fmerge-all-constants">, Group<f_Group>; +def fmessage_length_EQ : Joined<"-fmessage-length=">, Group<f_Group>; +def fms_extensions : Flag<"-fms-extensions">, Group<f_Group>; +def fms_compatibility : Flag<"-fms-compatibility">, Group<f_Group>; +def fmsc_version : Joined<"-fmsc-version=">, Group<f_Group>; +def fdelayed_template_parsing : Flag<"-fdelayed-template-parsing">, Group<f_Group>; +def fmodule_cache_path : Separate<"-fmodule-cache-path">, Group<i_Group>, + Flags<[NoForward]>; +def fmodules : Flag <"-fmodules">, Group<f_Group>, Flags<[NoForward]>; + +def fmudflapth : Flag<"-fmudflapth">, Group<f_Group>; +def fmudflap : Flag<"-fmudflap">, Group<f_Group>; +def fnested_functions : Flag<"-fnested-functions">, Group<f_Group>; +def fnext_runtime : Flag<"-fnext-runtime">, Group<f_Group>; +def fno_access_control : Flag<"-fno-access-control">, Group<f_Group>; +def fno_apple_pragma_pack : Flag<"-fno-apple-pragma-pack">, Group<f_Group>; +def fno_asm : Flag<"-fno-asm">, Group<f_Group>; +def fno_asynchronous_unwind_tables : Flag<"-fno-asynchronous-unwind-tables">, Group<f_Group>; +def fno_assume_sane_operator_new : Flag<"-fno-assume-sane-operator-new">, Group<f_Group>; +def fno_blocks : Flag<"-fno-blocks">, Group<f_Group>; +def fno_borland_extensions : Flag<"-fno-borland-extensions">, Group<f_Group>; +def fno_builtin_strcat : Flag<"-fno-builtin-strcat">, Group<f_Group>; +def fno_builtin_strcpy : Flag<"-fno-builtin-strcpy">, Group<f_Group>; +def fno_builtin : Flag<"-fno-builtin">, Group<f_Group>; +def fno_caret_diagnostics : Flag<"-fno-caret-diagnostics">, Group<f_Group>; +def fno_color_diagnostics : Flag<"-fno-color-diagnostics">, Group<f_Group>; +def fno_common : Flag<"-fno-common">, Group<f_Group>; +def fno_constant_cfstrings : Flag<"-fno-constant-cfstrings">, Group<f_Group>; +def fno_cxx_exceptions: Flag<"-fno-cxx-exceptions">, Group<f_Group>; +def fno_cxx_modules : Flag <"-fno-cxx-modules">, Group<f_Group>, Flags<[NoForward]>; +def fno_diagnostics_fixit_info : Flag<"-fno-diagnostics-fixit-info">, Group<f_Group>; +def fno_diagnostics_show_option : Flag<"-fno-diagnostics-show-option">, Group<f_Group>; +def fno_diagnostics_show_note_include_stack : Flag<"-fno-diagnostics-show-note-include-stack">, Group<f_Group>; +def fno_dollars_in_identifiers : Flag<"-fno-dollars-in-identifiers">, Group<f_Group>; +def fno_elide_constructors : Flag<"-fno-elide-constructors">, Group<f_Group>; +def fno_eliminate_unused_debug_symbols : Flag<"-fno-eliminate-unused-debug-symbols">, Group<f_Group>; +def fno_exceptions : Flag<"-fno-exceptions">, Group<f_Group>; +def fno_gnu_keywords : Flag<"-fno-gnu-keywords">, Group<f_Group>; +def fno_inline_functions : Flag<"-fno-inline-functions">, Group<f_Group>; +def fno_inline : Flag<"-fno-inline">, Group<f_Group>; +def fno_keep_inline_functions : Flag<"-fno-keep-inline-functions">, Group<clang_ignored_f_Group>; +def fno_lax_vector_conversions : Flag<"-fno-lax-vector-conversions">, Group<f_Group>; +def fno_limit_debug_info : Flag<"-fno-limit-debug-info">, Group<f_Group>, + HelpText<"Do not limit debug information produced to reduce size of debug binary">; +def fno_merge_all_constants : Flag<"-fno-merge-all-constants">, Group<f_Group>; +def fno_modules : Flag <"-fno-modules">, Group<f_Group>, Flags<[NoForward]>; +def fno_ms_extensions : Flag<"-fno-ms-extensions">, Group<f_Group>; +def fno_ms_compatibility : Flag<"-fno-ms-compatibility">, Group<f_Group>; +def fno_delayed_template_parsing : Flag<"-fno-delayed-template-parsing">, Group<f_Group>; +def fno_objc_exceptions: Flag<"-fno-objc-exceptions">, Group<f_Group>; +def fno_objc_legacy_dispatch : Flag<"-fno-objc-legacy-dispatch">, Group<f_Group>; +def fno_omit_frame_pointer : Flag<"-fno-omit-frame-pointer">, Group<f_Group>; +def fno_operator_names : Flag<"-fno-operator-names">, Group<f_Group>; +def fno_pascal_strings : Flag<"-fno-pascal-strings">, Group<f_Group>; +def fno_rtti : Flag<"-fno-rtti">, Group<f_Group>; +def fno_short_enums : Flag<"-fno-short-enums">, Group<f_Group>; +def fno_show_column : Flag<"-fno-show-column">, Group<f_Group>; +def fno_show_source_location : Flag<"-fno-show-source-location">, Group<f_Group>; +def fno_spell_checking : Flag<"-fno-spell-checking">, Group<f_Group>; +def fno_stack_protector : Flag<"-fno-stack-protector">, Group<f_Group>; +def fno_strict_aliasing : Flag<"-fno-strict-aliasing">, Group<f_Group>; +def fno_strict_enums : Flag<"-fno-strict-enums">, Group<f_Group>; +def fno_strict_overflow : Flag<"-fno-strict-overflow">, Group<f_Group>; +def fno_threadsafe_statics : Flag<"-fno-threadsafe-statics">, Group<f_Group>; +def fno_use_cxa_atexit : Flag<"-fno-use-cxa-atexit">, Group<f_Group>; +def fno_unit_at_a_time : Flag<"-fno-unit-at-a-time">, Group<f_Group>; +def fno_unwind_tables : Flag<"-fno-unwind-tables">, Group<f_Group>; +def fno_verbose_asm : Flag<"-fno-verbose-asm">, Group<f_Group>; +def fno_working_directory : Flag<"-fno-working-directory">, Group<f_Group>; +def fno_wrapv : Flag<"-fno-wrapv">, Group<f_Group>; +def fno_zero_initialized_in_bss : Flag<"-fno-zero-initialized-in-bss">, Group<f_Group>; +def fobjc_arc : Flag<"-fobjc-arc">, Group<f_Group>; +def fno_objc_arc : Flag<"-fno-objc-arc">, Group<f_Group>; +def fobjc_arc_exceptions : Flag<"-fobjc-arc-exceptions">, Group<f_Group>; +def fno_objc_arc_exceptions : Flag<"-fno-objc-arc-exceptions">, Group<f_Group>; +def fobjc_atdefs : Flag<"-fobjc-atdefs">, Group<clang_ignored_f_Group>; +def fobjc_call_cxx_cdtors : Flag<"-fobjc-call-cxx-cdtors">, Group<clang_ignored_f_Group>; +def fobjc_exceptions: Flag<"-fobjc-exceptions">, Group<f_Group>; + +def fobjc_gc_only : Flag<"-fobjc-gc-only">, Group<f_Group>; +def fobjc_gc : Flag<"-fobjc-gc">, Group<f_Group>; +def fobjc_legacy_dispatch : Flag<"-fobjc-legacy-dispatch">, Group<f_Group>; +def fobjc_new_property : Flag<"-fobjc-new-property">, Group<clang_ignored_f_Group>; +def fobjc_infer_related_result_type : Flag<"-fobjc-infer-related-result-type">, + Group<f_Group>; +def fno_objc_infer_related_result_type : Flag< + "-fno-objc-infer-related-result-type">, Group<f_Group>; +def fobjc_link_runtime: Flag<"-fobjc-link-runtime">, Group<f_Group>; + +// Objective-C ABI options. +def fobjc_abi_version_EQ : Joined<"-fobjc-abi-version=">, Group<f_Group>; +def fobjc_nonfragile_abi_version_EQ : Joined<"-fobjc-nonfragile-abi-version=">, Group<f_Group>; +def fobjc_nonfragile_abi : Flag<"-fobjc-nonfragile-abi">, Group<f_Group>; +def fno_objc_nonfragile_abi : Flag<"-fno-objc-nonfragile-abi">, Group<f_Group>; + +def fobjc_sender_dependent_dispatch : Flag<"-fobjc-sender-dependent-dispatch">, Group<f_Group>; +def fobjc : Flag<"-fobjc">, Group<f_Group>; +def fomit_frame_pointer : Flag<"-fomit-frame-pointer">, Group<f_Group>; +def fopenmp : Flag<"-fopenmp">, Group<f_Group>; +def fno_optimize_sibling_calls : Flag<"-fno-optimize-sibling-calls">, Group<f_Group>; +def foptimize_sibling_calls : Flag<"-foptimize-sibling-calls">, Group<f_Group>; +def force__cpusubtype__ALL : Flag<"-force_cpusubtype_ALL">; +def force__flat__namespace : Flag<"-force_flat_namespace">; +def force__load : Separate<"-force_load">; +def foutput_class_dir_EQ : Joined<"-foutput-class-dir=">, Group<f_Group>; +def fpack_struct : Flag<"-fpack-struct">, Group<f_Group>; +def fno_pack_struct : Flag<"-fno-pack-struct">, Group<f_Group>; +def fpack_struct_EQ : Joined<"-fpack-struct=">, Group<f_Group>; +def fpascal_strings : Flag<"-fpascal-strings">, Group<f_Group>; +def fpch_preprocess : Flag<"-fpch-preprocess">, Group<f_Group>; +def fpic : Flag<"-fpic">, Group<f_Group>; +def fno_pic : Flag<"-fno-pic">, Group<f_Group>; +def fpie : Flag<"-fpie">, Group<f_Group>; +def fno_pie : Flag<"-fno-pie">, Group<f_Group>; +def fprofile_arcs : Flag<"-fprofile-arcs">, Group<f_Group>; +def fprofile_generate : Flag<"-fprofile-generate">, Group<f_Group>; +def framework : Separate<"-framework">, Flags<[LinkerInput]>; +def frandom_seed_EQ : Joined<"-frandom-seed=">, Group<clang_ignored_f_Group>; +def frtti : Flag<"-frtti">, Group<f_Group>; +def fsched_interblock : Flag<"-fsched-interblock">, Group<clang_ignored_f_Group>; +def fshort_enums : Flag<"-fshort-enums">, Group<f_Group>; +def freorder_blocks : Flag<"-freorder-blocks">, Group<clang_ignored_f_Group>; +def fshort_wchar : Flag<"-fshort-wchar">, Group<f_Group>; +def fshow_overloads_EQ : Joined<"-fshow-overloads=">, Group<f_Group>; +def fshow_column : Flag<"-fshow-column">, Group<f_Group>; +def fshow_source_location : Flag<"-fshow-source-location">, Group<f_Group>; +def fspell_checking : Flag<"-fspell-checking">, Group<f_Group>; +def fsigned_bitfields : Flag<"-fsigned-bitfields">, Group<f_Group>; +def fsigned_char : Flag<"-fsigned-char">, Group<f_Group>; +def fstack_protector_all : Flag<"-fstack-protector-all">, Group<f_Group>; +def fstack_protector : Flag<"-fstack-protector">, Group<f_Group>; +def fstrict_aliasing : Flag<"-fstrict-aliasing">, Group<f_Group>; +def fstrict_enums : Flag<"-fstrict-enums">, Group<f_Group>; +def fstrict_overflow : Flag<"-fstrict-overflow">, Group<f_Group>; +def fsyntax_only : Flag<"-fsyntax-only">, Flags<[DriverOption]>; +def ftabstop_EQ : Joined<"-ftabstop=">, Group<f_Group>; +def ftemplate_depth_EQ : Joined<"-ftemplate-depth=">, Group<f_Group>; +def ftemplate_depth_ : Joined<"-ftemplate-depth-">, Group<f_Group>; +def ftemplate_backtrace_limit_EQ : Joined<"-ftemplate-backtrace-limit=">, + Group<f_Group>; +def ftest_coverage : Flag<"-ftest-coverage">, Group<f_Group>; +def Wlarge_by_value_copy_def : Flag<"-Wlarge-by-value-copy">; +def Wlarge_by_value_copy_EQ : Joined<"-Wlarge-by-value-copy=">; + +// Just silence warnings about -Wlarger-than, -Wframe-larger-than for now. +def Wlarger_than : Separate<"-Wlarger-than">, Group<clang_ignored_f_Group>; +def Wlarger_than_EQ : Joined<"-Wlarger-than=">, Alias<Wlarger_than>; +def Wlarger_than_ : Joined<"-Wlarger-than-">, Alias<Wlarger_than>; +def Wframe_larger_than : Separate<"-Wframe-larger-than">, Group<clang_ignored_f_Group>; +def Wframe_larger_than_EQ : Joined<"-Wframe-larger-than=">, Alias<Wframe_larger_than>; + +def fterminated_vtables : Flag<"-fterminated-vtables">, Alias<fapple_kext>; +def fthreadsafe_statics : Flag<"-fthreadsafe-statics">, Group<f_Group>; +def ftime_report : Flag<"-ftime-report">, Group<f_Group>; +def ftrapv : Flag<"-ftrapv">, Group<f_Group>; +def ftrapv_handler_EQ : Joined<"-ftrapv-handler=">, Group<f_Group>; +def ftrap_function_EQ : Joined<"-ftrap-function=">, Group<f_Group>, + HelpText<"Issue call to specified function rather than a trap instruction">; +def funit_at_a_time : Flag<"-funit-at-a-time">, Group<f_Group>; +def funroll_loops : Flag<"-funroll-loops">, Group<f_Group>; +def funsigned_bitfields : Flag<"-funsigned-bitfields">, Group<f_Group>; +def funsigned_char : Flag<"-funsigned-char">, Group<f_Group>; +def funwind_tables : Flag<"-funwind-tables">, Group<f_Group>; +def fuse_cxa_atexit : Flag<"-fuse-cxa-atexit">, Group<f_Group>; +def fverbose_asm : Flag<"-fverbose-asm">, Group<f_Group>; +def fvisibility_EQ : Joined<"-fvisibility=">, Group<f_Group>; +def fvisibility_inlines_hidden : Flag<"-fvisibility-inlines-hidden">, Group<f_Group>; +def fwrapv : Flag<"-fwrapv">, Group<f_Group>; +def fwritable_strings : Flag<"-fwritable-strings">, Group<f_Group>; +def fzero_initialized_in_bss : Flag<"-fzero-initialized-in-bss">, Group<f_Group>; +def ffunction_sections: Flag <"-ffunction-sections">, Group<f_Group>; +def fdata_sections : Flag <"-fdata-sections">, Group<f_Group>; +def f : Joined<"-f">, Group<f_Group>; +def g0 : Flag<"-g0">, Group<g_Group>; +def g2 : Flag<"-g2">, Group<g_Group>; +def g3 : Flag<"-g3">, Group<g_Group>; +def gdwarf2 : Flag<"-gdwarf-2">, Group<g_Group>; +def gfull : Flag<"-gfull">, Group<g_Group>; +def ggdb : Flag<"-ggdb">, Group<g_Group>; +def gstabs : Flag<"-gstabs">, Group<g_Group>; +def gstabsplus : Flag<"-gstabs+">, Group<g_Group>; +def gstabs1 : Flag<"-gstabs1">, Group<g_Group>; +def gstabs2 : Flag<"-gstabs2">, Group<g_Group>; +def gused : Flag<"-gused">, Group<g_Group>; +def g_Flag : Flag<"-g">, Group<g_Group>; +def headerpad__max__install__names : Joined<"-headerpad_max_install_names">; +def index_header_map : Flag<"-index-header-map">; +def idirafter : JoinedOrSeparate<"-idirafter">, Group<clang_i_Group>; +def iframework : Joined<"-iframework">, Group<clang_i_Group>; +def imacros : JoinedOrSeparate<"-imacros">, Group<clang_i_Group>; +def image__base : Separate<"-image_base">; +def include_ : JoinedOrSeparate<"-include">, Group<clang_i_Group>, EnumName<"include">; +def include_pch : Separate<"-include-pch">, Group<clang_i_Group>; +def init : Separate<"-init">; +def install__name : Separate<"-install_name">; +def integrated_as : Flag<"-integrated-as">, Flags<[DriverOption]>; +def iprefix : JoinedOrSeparate<"-iprefix">, Group<clang_i_Group>; +def iquote : JoinedOrSeparate<"-iquote">, Group<clang_i_Group>; +def isysroot : JoinedOrSeparate<"-isysroot">, Group<clang_i_Group>; +def isystem : JoinedOrSeparate<"-isystem">, Group<clang_i_Group>; +def iwithprefixbefore : JoinedOrSeparate<"-iwithprefixbefore">, Group<clang_i_Group>; +def iwithprefix : JoinedOrSeparate<"-iwithprefix">, Group<clang_i_Group>; +def iwithsysroot : JoinedOrSeparate<"-iwithsysroot">, Group<clang_i_Group>; +def i : Joined<"-i">, Group<i_Group>; +def keep__private__externs : Flag<"-keep_private_externs">; +def l : JoinedOrSeparate<"-l">, Flags<[LinkerInput, RenderJoined]>; +def lazy__framework : Separate<"-lazy_framework">, Flags<[LinkerInput]>; +def lazy__library : Separate<"-lazy_library">, Flags<[LinkerInput]>; +def m32 : Flag<"-m32">, Group<m_Group>, Flags<[DriverOption]>; +def mqdsp6_compat : Flag<"-mqdsp6-compat">, Group<m_Group>, Flags<[DriverOption]>; +def m3dnowa : Flag<"-m3dnowa">, Group<m_x86_Features_Group>; +def m3dnow : Flag<"-m3dnow">, Group<m_x86_Features_Group>; +def m64 : Flag<"-m64">, Group<m_Group>, Flags<[DriverOption]>; +def mabi_EQ : Joined<"-mabi=">, Group<m_Group>; +def march_EQ : Joined<"-march=">, Group<m_Group>; +def mcmodel_EQ : Joined<"-mcmodel=">, Group<m_Group>; +def mconstant_cfstrings : Flag<"-mconstant-cfstrings">, Group<clang_ignored_m_Group>; +def mcpu_EQ : Joined<"-mcpu=">, Group<m_Group>; +def mdynamic_no_pic : Joined<"-mdynamic-no-pic">, Group<m_Group>; +def mfix_and_continue : Flag<"-mfix-and-continue">, Group<clang_ignored_m_Group>; +def mfloat_abi_EQ : Joined<"-mfloat-abi=">, Group<m_Group>; +def mfpmath_EQ : Joined<"-mfpmath=">, Group<m_Group>; +def mfpu_EQ : Joined<"-mfpu=">, Group<m_Group>; +def mglobal_merge : Flag<"-mglobal-merge">, Group<m_Group>; +def mhard_float : Flag<"-mhard-float">, Group<m_Group>; +def miphoneos_version_min_EQ : Joined<"-miphoneos-version-min=">, Group<m_Group>; +def mios_version_min_EQ : Joined<"-mios-version-min=">, Alias<miphoneos_version_min_EQ>; +def mios_simulator_version_min_EQ : Joined<"-mios-simulator-version-min=">, Group<m_Group>; +def mkernel : Flag<"-mkernel">, Group<m_Group>; +def mlinker_version_EQ : Joined<"-mlinker-version=">, Flags<[NoForward]>; +def mllvm : Separate<"-mllvm">; +def mmacosx_version_min_EQ : Joined<"-mmacosx-version-min=">, Group<m_Group>; +def mms_bitfields : Flag<"-mms-bitfields">, Group<m_Group>; +def mstackrealign : Flag<"-mstackrealign">, Group<m_Group>; +def mstack_alignment : Joined<"-mstack-alignment=">, Group<m_Group>; +def mmmx : Flag<"-mmmx">, Group<m_x86_Features_Group>; +def mno_3dnowa : Flag<"-mno-3dnowa">, Group<m_x86_Features_Group>; +def mno_3dnow : Flag<"-mno-3dnow">, Group<m_x86_Features_Group>; +def mno_constant_cfstrings : Flag<"-mno-constant-cfstrings">, Group<m_Group>; +def mno_global_merge : Flag<"-mno-global-merge">, Group<m_Group>; +def mno_mmx : Flag<"-mno-mmx">, Group<m_x86_Features_Group>; +def mno_pascal_strings : Flag<"-mno-pascal-strings">, Group<m_Group>; +def mno_red_zone : Flag<"-mno-red-zone">, Group<m_Group>; +def mno_relax_all : Flag<"-mno-relax-all">, Group<m_Group>; +def mno_rtd: Flag<"-mno-rtd">, Group<m_Group>; +def mno_soft_float : Flag<"-mno-soft-float">, Group<m_Group>; +def mno_stackrealign : Flag<"-mno-stackrealign">, Group<m_Group>; +def mno_sse2 : Flag<"-mno-sse2">, Group<m_x86_Features_Group>; +def mno_sse3 : Flag<"-mno-sse3">, Group<m_x86_Features_Group>; +def mno_sse4a : Flag<"-mno-sse4a">, Group<m_x86_Features_Group>; +def mno_sse4 : Flag<"-mno-sse4">, Group<m_x86_Features_Group>; +def mno_sse4_1 : Flag<"-mno-sse4.1">, Group<m_x86_Features_Group>; +def mno_sse4_2 : Flag<"-mno-sse4.2">, Group<m_x86_Features_Group>; +def mno_sse : Flag<"-mno-sse">, Group<m_x86_Features_Group>; +def mno_ssse3 : Flag<"-mno-ssse3">, Group<m_x86_Features_Group>; +def mno_aes : Flag<"-mno-aes">, Group<m_x86_Features_Group>; +def mno_avx : Flag<"-mno-avx">, Group<m_x86_Features_Group>; +def mno_avx2 : Flag<"-mno-avx2">, Group<m_x86_Features_Group>; +def mno_lzcnt : Flag<"-mno-lzcnt">, Group<m_x86_Features_Group>; +def mno_bmi : Flag<"-mno-bmi">, Group<m_x86_Features_Group>; +def mno_bmi2 : Flag<"-mno-bmi2">, Group<m_x86_Features_Group>; +def mno_popcnt : Flag<"-mno-popcnt">, Group<m_x86_Features_Group>; +def mno_fma4 : Flag<"-mno-fma4">, Group<m_x86_Features_Group>; + +def mno_thumb : Flag<"-mno-thumb">, Group<m_Group>; +def marm : Flag<"-marm">, Alias<mno_thumb>; + +def mno_warn_nonportable_cfstrings : Flag<"-mno-warn-nonportable-cfstrings">, Group<m_Group>; +def mno_omit_leaf_frame_pointer : Flag<"-mno-omit-leaf-frame-pointer">, Group<f_Group>; +def momit_leaf_frame_pointer : Flag<"-momit-leaf-frame-pointer">, Group<f_Group>; +def mpascal_strings : Flag<"-mpascal-strings">, Group<m_Group>; +def mred_zone : Flag<"-mred-zone">, Group<m_Group>; +def mregparm_EQ : Joined<"-mregparm=">, Group<m_Group>; +def mrelax_all : Flag<"-mrelax-all">, Group<m_Group>; +def mrtd: Flag<"-mrtd">, Group<m_Group>; +def msmall_data_threshold_EQ : Joined <"-msmall-data-threshold=">, Group<m_Group>; +def msoft_float : Flag<"-msoft-float">, Group<m_Group>; +def msse2 : Flag<"-msse2">, Group<m_x86_Features_Group>; +def msse3 : Flag<"-msse3">, Group<m_x86_Features_Group>; +def msse4a : Flag<"-msse4a">, Group<m_x86_Features_Group>; +def msse4 : Flag<"-msse4">, Group<m_x86_Features_Group>; +def msse4_1 : Flag<"-msse4.1">, Group<m_x86_Features_Group>; +def msse4_2 : Flag<"-msse4.2">, Group<m_x86_Features_Group>; +def msse : Flag<"-msse">, Group<m_x86_Features_Group>; +def mssse3 : Flag<"-mssse3">, Group<m_x86_Features_Group>; +def maes : Flag<"-maes">, Group<m_x86_Features_Group>; +def mavx : Flag<"-mavx">, Group<m_x86_Features_Group>; +def mavx2 : Flag<"-mavx2">, Group<m_x86_Features_Group>; +def mlzcnt : Flag<"-mlzcnt">, Group<m_x86_Features_Group>; +def mbmi : Flag<"-mbmi">, Group<m_x86_Features_Group>; +def mbmi2 : Flag<"-mbmi2">, Group<m_x86_Features_Group>; +def mpopcnt : Flag<"-mpopcnt">, Group<m_x86_Features_Group>; +def mfma4 : Flag<"-mfma4">, Group<m_x86_Features_Group>; +def mthumb : Flag<"-mthumb">, Group<m_Group>; +def mtune_EQ : Joined<"-mtune=">, Group<m_Group>; +def multi__module : Flag<"-multi_module">; +def multiply__defined__unused : Separate<"-multiply_defined_unused">; +def multiply__defined : Separate<"-multiply_defined">; +def mwarn_nonportable_cfstrings : Flag<"-mwarn-nonportable-cfstrings">, Group<m_Group>; +def m_Separate : Separate<"-m">, Group<m_Group>; +def m_Joined : Joined<"-m">, Group<m_Group>; +def no_canonical_prefixes : Flag<"-no-canonical-prefixes">, Flags<[HelpHidden]>, + HelpText<"Use relative instead of canonical paths">; +def no_cpp_precomp : Flag<"-no-cpp-precomp">, Group<clang_ignored_f_Group>; +def no_integrated_as : Flag<"-no-integrated-as">, Flags<[DriverOption]>; +def no_integrated_cpp : Flag<"-no-integrated-cpp">, Flags<[DriverOption]>; +def no__dead__strip__inits__and__terms : Flag<"-no_dead_strip_inits_and_terms">; +def nobuiltininc : Flag<"-nobuiltininc">; +def nodefaultlibs : Flag<"-nodefaultlibs">; +def nofixprebinding : Flag<"-nofixprebinding">; +def nolibc : Flag<"-nolibc">; +def nomultidefs : Flag<"-nomultidefs">; +def noprebind : Flag<"-noprebind">; +def noseglinkedit : Flag<"-noseglinkedit">; +def nostartfiles : Flag<"-nostartfiles">; +def nostdinc : Flag<"-nostdinc">; +def nostdlibinc : Flag<"-nostdlibinc">; +def nostdincxx : Flag<"-nostdinc++">; +def nostdlib : Flag<"-nostdlib">; +def object : Flag<"-object">; +def o : JoinedOrSeparate<"-o">, Flags<[DriverOption, RenderAsInput]>, + HelpText<"Write output to <file>">, MetaVarName<"<file>">; +def pagezero__size : JoinedOrSeparate<"-pagezero_size">; +def pass_exit_codes : Flag<"-pass-exit-codes">, Flags<[Unsupported]>; +def pedantic_errors : Flag<"-pedantic-errors">, Group<pedantic_Group>; +def pedantic : Flag<"-pedantic">, Group<pedantic_Group>; +def pg : Flag<"-pg">; +def pipe : Flag<"-pipe">, + HelpText<"Use pipes between commands, when possible">; +def prebind__all__twolevel__modules : Flag<"-prebind_all_twolevel_modules">; +def prebind : Flag<"-prebind">; +def preload : Flag<"-preload">; +def print_file_name_EQ : Joined<"-print-file-name=">, + HelpText<"Print the full library path of <file>">, MetaVarName<"<file>">; +def print_ivar_layout : Flag<"-print-ivar-layout">; +def print_libgcc_file_name : Flag<"-print-libgcc-file-name">, + HelpText<"Print the library path for \"libgcc.a\"">; +def print_multi_directory : Flag<"-print-multi-directory">; +def print_multi_lib : Flag<"-print-multi-lib">; +def print_multi_os_directory : Flag<"-print-multi-os-directory">; +def print_prog_name_EQ : Joined<"-print-prog-name=">, + HelpText<"Print the full program path of <name>">, MetaVarName<"<name>">; +def print_search_dirs : Flag<"-print-search-dirs">, + HelpText<"Print the paths used for finding libraries and programs">; +def private__bundle : Flag<"-private_bundle">; +def pthreads : Flag<"-pthreads">; +def pthread : Flag<"-pthread">; +def p : Flag<"-p">; +def pie : Flag<"-pie">; +def read__only__relocs : Separate<"-read_only_relocs">; +def remap : Flag<"-remap">; +def rewrite_objc : Flag<"-rewrite-objc">, Flags<[DriverOption]>, + HelpText<"Rewrite Objective-C source to C++">; +def rewrite_legacy_objc : Flag<"-rewrite-legacy-objc">, Flags<[DriverOption]>, + HelpText<"Rewrite Legacy Objective-C source to C++">; +def rdynamic : Flag<"-rdynamic">; +def rpath : Separate<"-rpath">, Flags<[LinkerInput]>; +def rtlib_EQ : Joined<"-rtlib=">; +def r : Flag<"-r">; +def save_temps : Flag<"-save-temps">, Flags<[DriverOption]>, + HelpText<"Save intermediate compilation results">; +def sectalign : MultiArg<"-sectalign", 3>; +def sectcreate : MultiArg<"-sectcreate", 3>; +def sectobjectsymbols : MultiArg<"-sectobjectsymbols", 2>; +def sectorder : MultiArg<"-sectorder", 3>; +def seg1addr : JoinedOrSeparate<"-seg1addr">; +def seg__addr__table__filename : Separate<"-seg_addr_table_filename">; +def seg__addr__table : Separate<"-seg_addr_table">; +def segaddr : MultiArg<"-segaddr", 2>; +def segcreate : MultiArg<"-segcreate", 3>; +def seglinkedit : Flag<"-seglinkedit">; +def segprot : MultiArg<"-segprot", 3>; +def segs__read__only__addr : Separate<"-segs_read_only_addr">; +def segs__read__write__addr : Separate<"-segs_read_write_addr">; +def segs__read__ : Joined<"-segs_read_">; +def shared_libgcc : Flag<"-shared-libgcc">; +def shared : Flag<"-shared">; +def single__module : Flag<"-single_module">; +def specs_EQ : Joined<"-specs=">; +def specs : Separate<"-specs">, Flags<[Unsupported]>; +def static_libgcc : Flag<"-static-libgcc">; +def static_libstdcxx : Flag<"-static-libstdc++">; +def static : Flag<"-static">, Flags<[NoArgumentUnused]>; +def std_default_EQ : Joined<"-std-default=">; +def std_EQ : Joined<"-std=">, Group<L_Group>; +def stdlib_EQ : Joined<"-stdlib=">; +def sub__library : JoinedOrSeparate<"-sub_library">; +def sub__umbrella : JoinedOrSeparate<"-sub_umbrella">; +def s : Flag<"-s">; +def target : Separate<"-target">, Flags<[DriverOption]>, + HelpText<"Generate code for the given target">; +def gcc_toolchain : Separate<"-gcc-toolchain">, Flags<[DriverOption]>, + HelpText<"Use the gcc toolchain at the given directory">; +// We should deprecate the use of -ccc-host-triple, and then remove. +def ccc_host_triple : Separate<"-ccc-host-triple">, Alias<target>; +def time : Flag<"-time">, + HelpText<"Time individual commands">; +def traditional_cpp : Flag<"-traditional-cpp">; +def traditional : Flag<"-traditional">; +def trigraphs : Flag<"-trigraphs">; +def twolevel__namespace__hints : Flag<"-twolevel_namespace_hints">; +def twolevel__namespace : Flag<"-twolevel_namespace">; +def t : Flag<"-t">; +def umbrella : Separate<"-umbrella">; +def undefined : JoinedOrSeparate<"-undefined">, Group<u_Group>; +def undef : Flag<"-undef">, Group<u_Group>; +def unexported__symbols__list : Separate<"-unexported_symbols_list">; +def u : JoinedOrSeparate<"-u">, Group<u_Group>; +def use_gold_plugin : Flag<"-use-gold-plugin">; +def v : Flag<"-v">, + HelpText<"Show commands to run and use verbose output">; +def verify : Flag<"-verify">, Flags<[DriverOption]>, + HelpText<"Verify output using a verifier.">; +def weak_l : Joined<"-weak-l">, Flags<[LinkerInput]>; +def weak__framework : Separate<"-weak_framework">, Flags<[LinkerInput]>; +def weak__library : Separate<"-weak_library">, Flags<[LinkerInput]>; +def weak__reference__mismatches : Separate<"-weak_reference_mismatches">; +def whatsloaded : Flag<"-whatsloaded">; +def whyload : Flag<"-whyload">; +def w : Flag<"-w">; +def x : JoinedOrSeparate<"-x">, Flags<[DriverOption]>, + HelpText<"Treat subsequent input files as having type <language>">, + MetaVarName<"<language>">; +def y : Joined<"-y">; + +def working_directory : Separate<"-working-directory">, + HelpText<"Resolve file paths relative to the specified directory">; +def working_directory_EQ : Joined<"-working-directory=">, + Alias<working_directory>; + +// Double dash options, which are usually an alias for one of the previous +// options. + +def _CLASSPATH_EQ : Joined<"--CLASSPATH=">, Alias<fclasspath_EQ>; +def _CLASSPATH : Separate<"--CLASSPATH">, Alias<fclasspath_EQ>; +def _all_warnings : Flag<"--all-warnings">, Alias<Wall>; +def _analyze_auto : Flag<"--analyze-auto">, Flags<[DriverOption]>; +def _analyzer_no_default_checks : Flag<"--analyzer-no-default-checks">, Flags<[DriverOption]>; +def _analyzer_output : JoinedOrSeparate<"--analyzer-output">, Flags<[DriverOption]>; +def _analyze : Flag<"--analyze">, Flags<[DriverOption]>, + HelpText<"Run the static analyzer">; +def _ansi : Flag<"--ansi">, Alias<ansi>; +def _assemble : Flag<"--assemble">, Alias<S>; +def _assert_EQ : Joined<"--assert=">, Alias<A>; +def _assert : Separate<"--assert">, Alias<A>; +def _bootclasspath_EQ : Joined<"--bootclasspath=">, Alias<fbootclasspath_EQ>; +def _bootclasspath : Separate<"--bootclasspath">, Alias<fbootclasspath_EQ>; +def _classpath_EQ : Joined<"--classpath=">, Alias<fclasspath_EQ>; +def _classpath : Separate<"--classpath">, Alias<fclasspath_EQ>; +def _combine : Flag<"--combine">, Alias<combine>; +def _comments_in_macros : Flag<"--comments-in-macros">, Alias<CC>; +def _comments : Flag<"--comments">, Alias<C>; +def _compile : Flag<"--compile">, Alias<c>; +def _constant_cfstrings : Flag<"--constant-cfstrings">; +def _coverage : Flag<"--coverage">, Alias<coverage>; +def _debug_EQ : Joined<"--debug=">, Alias<g_Flag>; +def _debug : Flag<"--debug">, Alias<g_Flag>; +def _define_macro_EQ : Joined<"--define-macro=">, Alias<D>; +def _define_macro : Separate<"--define-macro">, Alias<D>; +def _dependencies : Flag<"--dependencies">, Alias<M>; +def _encoding_EQ : Joined<"--encoding=">, Alias<fencoding_EQ>; +def _encoding : Separate<"--encoding">, Alias<fencoding_EQ>; +def _entry : Flag<"--entry">, Alias<e>; +def _extdirs_EQ : Joined<"--extdirs=">, Alias<fextdirs_EQ>; +def _extdirs : Separate<"--extdirs">, Alias<fextdirs_EQ>; +def _extra_warnings : Flag<"--extra-warnings">, Alias<W_Joined>; +def _for_linker_EQ : Joined<"--for-linker=">, Alias<Xlinker>; +def _for_linker : Separate<"--for-linker">, Alias<Xlinker>; +def _force_link_EQ : Joined<"--force-link=">, Alias<u>; +def _force_link : Separate<"--force-link">, Alias<u>; +def _help_hidden : Flag<"--help-hidden">; +def _help : Flag<"--help">, + HelpText<"Display available options">; +def _imacros_EQ : Joined<"--imacros=">, Alias<imacros>; +def _imacros : Separate<"--imacros">, Alias<imacros>; +def _include_barrier : Flag<"--include-barrier">, Alias<I_>; +def _include_directory_after_EQ : Joined<"--include-directory-after=">, Alias<idirafter>; +def _include_directory_after : Separate<"--include-directory-after">, Alias<idirafter>; +def _include_directory_EQ : Joined<"--include-directory=">, Alias<I>; +def _include_directory : Separate<"--include-directory">, Alias<I>; +def _include_prefix_EQ : Joined<"--include-prefix=">, Alias<iprefix>; +def _include_prefix : Separate<"--include-prefix">, Alias<iprefix>; +def _include_with_prefix_after_EQ : Joined<"--include-with-prefix-after=">, Alias<iwithprefix>; +def _include_with_prefix_after : Separate<"--include-with-prefix-after">, Alias<iwithprefix>; +def _include_with_prefix_before_EQ : Joined<"--include-with-prefix-before=">, Alias<iwithprefixbefore>; +def _include_with_prefix_before : Separate<"--include-with-prefix-before">, Alias<iwithprefixbefore>; +def _include_with_prefix_EQ : Joined<"--include-with-prefix=">, Alias<iwithprefix>; +def _include_with_prefix : Separate<"--include-with-prefix">, Alias<iwithprefix>; +def _include_EQ : Joined<"--include=">, Alias<include_>; +def _include : Separate<"--include">, Alias<include_>; +def _language_EQ : Joined<"--language=">, Alias<x>; +def _language : Separate<"--language">, Alias<x>; +def _library_directory_EQ : Joined<"--library-directory=">, Alias<L>; +def _library_directory : Separate<"--library-directory">, Alias<L>; +def _machine__EQ : Joined<"--machine-=">, Alias<m_Joined>; +def _machine_ : Joined<"--machine-">, Alias<m_Joined>; +def _machine_EQ : Joined<"--machine=">, Alias<m_Joined>; +def _machine : Separate<"--machine">, Alias<m_Joined>; +def _no_integrated_cpp : Flag<"--no-integrated-cpp">, Alias<no_integrated_cpp>; +def _no_line_commands : Flag<"--no-line-commands">, Alias<P>; +def _no_standard_includes : Flag<"--no-standard-includes">, Alias<nostdinc>; +def _no_standard_libraries : Flag<"--no-standard-libraries">, Alias<nostdlib>; +def _no_undefined : Flag<"--no-undefined">, Flags<[LinkerInput]>; +def _no_warnings : Flag<"--no-warnings">, Alias<w>; +def _optimize_EQ : Joined<"--optimize=">, Alias<O>; +def _optimize : Flag<"--optimize">, Alias<O>; +def _output_class_directory_EQ : Joined<"--output-class-directory=">, Alias<foutput_class_dir_EQ>; +def _output_class_directory : Separate<"--output-class-directory">, Alias<foutput_class_dir_EQ>; +def _output_EQ : Joined<"--output=">, Alias<o>; +def _output : Separate<"--output">, Alias<o>; +def _param : Separate<"--param">; +def _param_EQ : Joined<"--param=">, Alias<_param>; +def _pass_exit_codes : Flag<"--pass-exit-codes">, Alias<pass_exit_codes>; +def _pedantic_errors : Flag<"--pedantic-errors">, Alias<pedantic_errors>; +def _pedantic : Flag<"--pedantic">, Alias<pedantic>; +def _pipe : Flag<"--pipe">, Alias<pipe>; +def _prefix_EQ : Joined<"--prefix=">, Alias<B>; +def _prefix : Separate<"--prefix">, Alias<B>; +def _preprocess : Flag<"--preprocess">, Alias<E>; +def _print_diagnostic_categories : Flag<"--print-diagnostic-categories">; +def _print_file_name_EQ : Joined<"--print-file-name=">, Alias<print_file_name_EQ>; +def _print_file_name : Separate<"--print-file-name">, Alias<print_file_name_EQ>; +def _print_libgcc_file_name : Flag<"--print-libgcc-file-name">, Alias<print_libgcc_file_name>; +def _print_missing_file_dependencies : Flag<"--print-missing-file-dependencies">, Alias<MG>; +def _print_multi_directory : Flag<"--print-multi-directory">, Alias<print_multi_directory>; +def _print_multi_lib : Flag<"--print-multi-lib">, Alias<print_multi_lib>; +def _print_multi_os_directory : Flag<"--print-multi-os-directory">, Alias<print_multi_os_directory>; +def _print_prog_name_EQ : Joined<"--print-prog-name=">, Alias<print_prog_name_EQ>; +def _print_prog_name : Separate<"--print-prog-name">, Alias<print_prog_name_EQ>; +def _print_search_dirs : Flag<"--print-search-dirs">, Alias<print_search_dirs>; +def _profile_blocks : Flag<"--profile-blocks">, Alias<a>; +def _profile : Flag<"--profile">, Alias<p>; +def _relocatable_pch : Flag<"--relocatable-pch">, + HelpText<"Build a relocatable precompiled header">; +def _resource_EQ : Joined<"--resource=">, Alias<fcompile_resource_EQ>; +def _resource : Separate<"--resource">, Alias<fcompile_resource_EQ>; +def _rtlib_EQ : Joined<"--rtlib=">, Alias<rtlib_EQ>; +def _rtlib : Separate<"--rtlib">, Alias<rtlib_EQ>; +def _save_temps : Flag<"--save-temps">, Alias<save_temps>; +def _serialize_diags : Separate<"--serialize-diagnostics">, Flags<[DriverOption]>, + HelpText<"Serialize compiler diagnostics to a file">; +def _shared : Flag<"--shared">, Alias<shared>; +def _signed_char : Flag<"--signed-char">, Alias<fsigned_char>; +def _specs_EQ : Joined<"--specs=">, Alias<specs_EQ>; +def _specs : Separate<"--specs">, Alias<specs_EQ>; +def _static : Flag<"--static">, Alias<static>; +def _std_EQ : Joined<"--std=">, Alias<std_EQ>; +def _std : Separate<"--std">, Alias<std_EQ>; +def _stdlib_EQ : Joined<"--stdlib=">, Alias<stdlib_EQ>; +def _stdlib : Separate<"--stdlib">, Alias<stdlib_EQ>; +def _sysroot_EQ : Joined<"--sysroot=">; +def _sysroot : Separate<"--sysroot">, Alias<_sysroot_EQ>; +def _target_help : Flag<"--target-help">; +def _trace_includes : Flag<"--trace-includes">, Alias<H>; +def _traditional_cpp : Flag<"--traditional-cpp">, Alias<traditional_cpp>; +def _traditional : Flag<"--traditional">, Alias<traditional>; +def _trigraphs : Flag<"--trigraphs">, Alias<trigraphs>; +def _undefine_macro_EQ : Joined<"--undefine-macro=">, Alias<U>; +def _undefine_macro : Separate<"--undefine-macro">, Alias<U>; +def _unsigned_char : Flag<"--unsigned-char">, Alias<funsigned_char>; +def _user_dependencies : Flag<"--user-dependencies">, Alias<MM>; +def _verbose : Flag<"--verbose">, Alias<v>; +def _version : Flag<"--version">; +def _warn__EQ : Joined<"--warn-=">, Alias<W_Joined>; +def _warn_ : Joined<"--warn-">, Alias<W_Joined>; +def _write_dependencies : Flag<"--write-dependencies">, Alias<MD>; +def _write_user_dependencies : Flag<"--write-user-dependencies">, Alias<MMD>; +def _ : Joined<"--">, Flags<[Unsupported]>; + +// Special internal option to handle -Xlinker --no-demangle. +def Z_Xlinker__no_demangle : Flag<"-Z-Xlinker-no-demangle">, + Flags<[Unsupported, NoArgumentUnused]>; + +// Special internal option to allow forwarding arbitrary arguments to linker. +def Zlinker_input : Separate<"-Zlinker-input">, + Flags<[Unsupported, NoArgumentUnused]>; + +// Reserved library options. +def Z_reserved_lib_stdcxx : Flag<"-Z-reserved-lib-stdc++">, + Flags<[LinkerInput, NoArgumentUnused, Unsupported]>, Group<reserved_lib_Group>; +def Z_reserved_lib_cckext : Flag<"-Z-reserved-lib-cckext">, + Flags<[LinkerInput, NoArgumentUnused, Unsupported]>, Group<reserved_lib_Group>; diff --git a/clang/include/clang/Driver/Phases.h b/clang/include/clang/Driver/Phases.h new file mode 100644 index 0000000..a0c42ea --- /dev/null +++ b/clang/include/clang/Driver/Phases.h @@ -0,0 +1,32 @@ +//===--- Phases.h - Transformations on Driver Types -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_DRIVER_PHASES_H_ +#define CLANG_DRIVER_PHASES_H_ + +namespace clang { +namespace driver { +namespace phases { + /// ID - Ordered values for successive stages in the + /// compilation process which interact with user options. + enum ID { + Preprocess, + Precompile, + Compile, + Assemble, + Link + }; + + const char *getPhaseName(ID Id); + +} // end namespace phases +} // end namespace driver +} // end namespace clang + +#endif diff --git a/clang/include/clang/Driver/Tool.h b/clang/include/clang/Driver/Tool.h new file mode 100644 index 0000000..8822d7b --- /dev/null +++ b/clang/include/clang/Driver/Tool.h @@ -0,0 +1,75 @@ +//===--- Tool.h - Compilation Tools -----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_DRIVER_TOOL_H_ +#define CLANG_DRIVER_TOOL_H_ + +#include "clang/Basic/LLVM.h" + +namespace clang { +namespace driver { + class ArgList; + class Compilation; + class InputInfo; + class Job; + class JobAction; + class ToolChain; + + typedef SmallVector<InputInfo, 4> InputInfoList; + +/// Tool - Information on a specific compilation tool. +class Tool { + /// The tool name (for debugging). + const char *Name; + + /// The human readable name for the tool, for use in diagnostics. + const char *ShortName; + + /// The tool chain this tool is a part of. + const ToolChain &TheToolChain; + +public: + Tool(const char *Name, const char *ShortName, + const ToolChain &TC); + +public: + virtual ~Tool(); + + const char *getName() const { return Name; } + + const char *getShortName() const { return ShortName; } + + const ToolChain &getToolChain() const { return TheToolChain; } + + virtual bool hasIntegratedAssembler() const { return false; } + virtual bool hasIntegratedCPP() const = 0; + virtual bool isLinkJob() const { return false; } + + /// \brief Does this tool have "good" standardized diagnostics, or should the + /// driver add an additional "command failed" diagnostic on failures. + virtual bool hasGoodDiagnostics() const { return false; } + + /// ConstructJob - Construct jobs to perform the action \arg JA, + /// writing to \arg Output and with \arg Inputs. + /// + /// \param TCArgs - The argument list for this toolchain, with any + /// tool chain specific translations applied. + /// \param LinkingOutput - If this output will eventually feed the + /// linker, then this is the final output name of the linked image. + virtual void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &TCArgs, + const char *LinkingOutput) const = 0; +}; + +} // end namespace driver +} // end namespace clang + +#endif diff --git a/clang/include/clang/Driver/ToolChain.h b/clang/include/clang/Driver/ToolChain.h new file mode 100644 index 0000000..c35cf67 --- /dev/null +++ b/clang/include/clang/Driver/ToolChain.h @@ -0,0 +1,257 @@ +//===--- ToolChain.h - Collections of tools for one platform ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_DRIVER_TOOLCHAIN_H_ +#define CLANG_DRIVER_TOOLCHAIN_H_ + +#include "clang/Driver/Util.h" +#include "clang/Driver/Types.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Path.h" +#include <string> + +namespace clang { +namespace driver { + class ArgList; + class Compilation; + class DerivedArgList; + class Driver; + class InputArgList; + class JobAction; + class ObjCRuntime; + class Tool; + +/// ToolChain - Access to tools for a single platform. +class ToolChain { +public: + typedef SmallVector<std::string, 4> path_list; + + enum CXXStdlibType { + CST_Libcxx, + CST_Libstdcxx + }; + + enum RuntimeLibType { + RLT_CompilerRT, + RLT_Libgcc + }; + +private: + const Driver &D; + const llvm::Triple Triple; + + /// The list of toolchain specific path prefixes to search for + /// files. + path_list FilePaths; + + /// The list of toolchain specific path prefixes to search for + /// programs. + path_list ProgramPaths; + +protected: + ToolChain(const Driver &D, const llvm::Triple &T); + + /// \name Utilities for implementing subclasses. + ///@{ + static void addSystemInclude(const ArgList &DriverArgs, + ArgStringList &CC1Args, + const Twine &Path); + static void addExternCSystemInclude(const ArgList &DriverArgs, + ArgStringList &CC1Args, + const Twine &Path); + static void addSystemIncludes(const ArgList &DriverArgs, + ArgStringList &CC1Args, + ArrayRef<StringRef> Paths); + ///@} + +public: + virtual ~ToolChain(); + + // Accessors + + const Driver &getDriver() const; + const llvm::Triple &getTriple() const { return Triple; } + + llvm::Triple::ArchType getArch() const { return Triple.getArch(); } + StringRef getArchName() const { return Triple.getArchName(); } + StringRef getPlatform() const { return Triple.getVendorName(); } + StringRef getOS() const { return Triple.getOSName(); } + + std::string getTripleString() const { + return Triple.getTriple(); + } + + path_list &getFilePaths() { return FilePaths; } + const path_list &getFilePaths() const { return FilePaths; } + + path_list &getProgramPaths() { return ProgramPaths; } + const path_list &getProgramPaths() const { return ProgramPaths; } + + // Tool access. + + /// TranslateArgs - Create a new derived argument list for any argument + /// translations this ToolChain may wish to perform, or 0 if no tool chain + /// specific translations are needed. + /// + /// \param BoundArch - The bound architecture name, or 0. + virtual DerivedArgList *TranslateArgs(const DerivedArgList &Args, + const char *BoundArch) const { + return 0; + } + + /// SelectTool - Choose a tool to use to handle the action \arg JA with the + /// given \arg Inputs. + virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, + const ActionList &Inputs) const = 0; + + // Helper methods + + std::string GetFilePath(const char *Name) const; + std::string GetProgramPath(const char *Name, bool WantFile = false) const; + + // Platform defaults information + + /// HasNativeLTOLinker - Check whether the linker and related tools have + /// native LLVM support. + virtual bool HasNativeLLVMSupport() const; + + /// LookupTypeForExtension - Return the default language type to use for the + /// given extension. + virtual types::ID LookupTypeForExtension(const char *Ext) const; + + /// IsBlocksDefault - Does this tool chain enable -fblocks by default. + virtual bool IsBlocksDefault() const { return false; } + + /// IsIntegratedAssemblerDefault - Does this tool chain enable -integrated-as + /// by default. + virtual bool IsIntegratedAssemblerDefault() const { return false; } + + /// IsStrictAliasingDefault - Does this tool chain use -fstrict-aliasing by + /// default. + virtual bool IsStrictAliasingDefault() const { return true; } + + /// IsObjCDefaultSynthPropertiesDefault - Does this tool chain enable + /// -fobjc-default-synthesize-properties by default. + virtual bool IsObjCDefaultSynthPropertiesDefault() const { return false; } + + /// IsObjCNonFragileABIDefault - Does this tool chain set + /// -fobjc-nonfragile-abi by default. + virtual bool IsObjCNonFragileABIDefault() const { return false; } + + /// IsObjCLegacyDispatchDefault - Does this tool chain set + /// -fobjc-legacy-dispatch by default (this is only used with the non-fragile + /// ABI). + virtual bool IsObjCLegacyDispatchDefault() const { return true; } + + /// UseObjCMixedDispatchDefault - When using non-legacy dispatch, should the + /// mixed dispatch method be used? + virtual bool UseObjCMixedDispatch() const { return false; } + + /// GetDefaultStackProtectorLevel - Get the default stack protector level for + /// this tool chain (0=off, 1=on, 2=all). + virtual unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const { + return 0; + } + + /// GetDefaultRuntimeLibType - Get the default runtime library variant to use. + virtual RuntimeLibType GetDefaultRuntimeLibType() const { + return ToolChain::RLT_Libgcc; + } + + /// IsUnwindTablesDefault - Does this tool chain use -funwind-tables + /// by default. + virtual bool IsUnwindTablesDefault() const = 0; + + /// GetDefaultRelocationModel - Return the LLVM name of the default + /// relocation model for this tool chain. + virtual const char *GetDefaultRelocationModel() const = 0; + + /// GetForcedPicModel - Return the LLVM name of the forced PIC model + /// for this tool chain, or 0 if this tool chain does not force a + /// particular PIC mode. + virtual const char *GetForcedPicModel() const = 0; + + /// SupportsProfiling - Does this tool chain support -pg. + virtual bool SupportsProfiling() const { return true; } + + /// Does this tool chain support Objective-C garbage collection. + virtual bool SupportsObjCGC() const { return true; } + + /// Does this tool chain support Objective-C ARC. + virtual bool SupportsObjCARC() const { return true; } + + /// UseDwarfDebugFlags - Embed the compile options to clang into the Dwarf + /// compile unit information. + virtual bool UseDwarfDebugFlags() const { return false; } + + /// UseSjLjExceptions - Does this tool chain use SjLj exceptions. + virtual bool UseSjLjExceptions() const { return false; } + + /// ComputeLLVMTriple - Return the LLVM target triple to use, after taking + /// command line arguments into account. + virtual std::string ComputeLLVMTriple(const ArgList &Args, + types::ID InputType = types::TY_INVALID) const; + + /// ComputeEffectiveClangTriple - Return the Clang triple to use for this + /// target, which may take into account the command line arguments. For + /// example, on Darwin the -mmacosx-version-min= command line argument (which + /// sets the deployment target) determines the version in the triple passed to + /// Clang. + virtual std::string ComputeEffectiveClangTriple(const ArgList &Args, + types::ID InputType = types::TY_INVALID) const; + + /// configureObjCRuntime - Configure the known properties of the + /// Objective-C runtime for this platform. + /// + /// FIXME: this really belongs on some sort of DeploymentTarget abstraction + virtual void configureObjCRuntime(ObjCRuntime &runtime) const; + + /// hasBlocksRuntime - Given that the user is compiling with + /// -fblocks, does this tool chain guarantee the existence of a + /// blocks runtime? + /// + /// FIXME: this really belongs on some sort of DeploymentTarget abstraction + virtual bool hasBlocksRuntime() const { return true; } + + /// \brief Add the clang cc1 arguments for system include paths. + /// + /// This routine is responsible for adding the necessary cc1 arguments to + /// include headers from standard system header directories. + virtual void AddClangSystemIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const; + + // GetRuntimeLibType - Determine the runtime library type to use with the + // given compilation arguments. + virtual RuntimeLibType GetRuntimeLibType(const ArgList &Args) const; + + // GetCXXStdlibType - Determine the C++ standard library type to use with the + // given compilation arguments. + virtual CXXStdlibType GetCXXStdlibType(const ArgList &Args) const; + + /// AddClangCXXStdlibIncludeArgs - Add the clang -cc1 level arguments to set + /// the include paths to use for the given C++ standard library type. + virtual void AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const; + + /// AddCXXStdlibLibArgs - Add the system specific linker arguments to use + /// for the given C++ standard library type. + virtual void AddCXXStdlibLibArgs(const ArgList &Args, + ArgStringList &CmdArgs) const; + + /// AddCCKextLibArgs - Add the system specific linker arguments to use + /// for kernel extensions (Darwin-specific). + virtual void AddCCKextLibArgs(const ArgList &Args, + ArgStringList &CmdArgs) const; +}; + +} // end namespace driver +} // end namespace clang + +#endif diff --git a/clang/include/clang/Driver/Types.def b/clang/include/clang/Driver/Types.def new file mode 100644 index 0000000..b107dfb --- /dev/null +++ b/clang/include/clang/Driver/Types.def @@ -0,0 +1,93 @@ +//===--- Types.def - Driver Type info ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the driver type information. Users of this file +// must define the TYPE macro to make use of this information. +// +//===----------------------------------------------------------------------===// + +#ifndef TYPE +#error "Define TYPE prior to including this file!" +#endif + +// TYPE(NAME, ID, PP_TYPE, TEMP_SUFFIX, FLAGS) + +// The first value is the type name as a string; for types which can +// be user specified this should be the equivalent -x option. + +// The second value is the type id, which will result in a +// clang::driver::types::TY_XX enum constant. + +// The third value is that id of the type for preprocessed inputs of +// this type, or INVALID if this type is not preprocessed. + +// The fourth value is the suffix to use when creating temporary files +// of this type, or null if unspecified. + +// The fifth value is a string containt option flags. Valid values: +// a - The type should only be assembled. +// p - The type should only be precompiled. +// u - The type can be user specified (with -x). +// A - The type's temporary suffix should be appended when generating +// outputs of this type. + + +// C family source language (with and without preprocessing). +TYPE("cpp-output", PP_C, INVALID, "i", "u") +TYPE("c", C, PP_C, 0, "u") +TYPE("cl", CL, PP_C, 0, "u") +TYPE("cuda", CUDA, PP_CXX, 0, "u") +TYPE("objective-c-cpp-output", PP_ObjC, INVALID, "mi", "u") +TYPE("objc-cpp-output", PP_ObjC_Alias, INVALID, "mi", "u") +TYPE("objective-c", ObjC, PP_ObjC, 0, "u") +TYPE("c++-cpp-output", PP_CXX, INVALID, "ii", "u") +TYPE("c++", CXX, PP_CXX, 0, "u") +TYPE("objective-c++-cpp-output", PP_ObjCXX, INVALID, "mii", "u") +TYPE("objc++-cpp-output", PP_ObjCXX_Alias, INVALID, "mii", "u") +TYPE("objective-c++", ObjCXX, PP_ObjCXX, 0, "u") + +// C family input files to precompile. +TYPE("c-header-cpp-output", PP_CHeader, INVALID, "i", "p") +TYPE("c-header", CHeader, PP_CHeader, 0, "pu") +TYPE("cl-header", CLHeader, PP_CHeader, 0, "pu") +TYPE("objective-c-header-cpp-output", PP_ObjCHeader, INVALID, "mi", "p") +TYPE("objective-c-header", ObjCHeader, PP_ObjCHeader, 0, "pu") +TYPE("c++-header-cpp-output", PP_CXXHeader, INVALID, "ii", "p") +TYPE("c++-header", CXXHeader, PP_CXXHeader, 0, "pu") +TYPE("objective-c++-header-cpp-output", PP_ObjCXXHeader, INVALID, "mii", "p") +TYPE("objective-c++-header", ObjCXXHeader, PP_ObjCXXHeader, 0, "pu") + +// Other languages. +TYPE("ada", Ada, INVALID, 0, "u") +TYPE("assembler", PP_Asm, INVALID, "s", "au") +TYPE("assembler-with-cpp", Asm, PP_Asm, 0, "au") +TYPE("f95", PP_Fortran, INVALID, 0, "u") +TYPE("f95-cpp-input", Fortran, PP_Fortran, 0, "u") +TYPE("java", Java, INVALID, 0, "u") + +// LLVM IR/LTO types. We define separate types for IR and LTO because LTO +// outputs should use the standard suffixes. +TYPE("ir", LLVM_IR, INVALID, "ll", "u") +TYPE("ir", LLVM_BC, INVALID, "bc", "u") +TYPE("lto-ir", LTO_IR, INVALID, "s", "") +TYPE("lto-bc", LTO_BC, INVALID, "o", "") + +// Misc. +TYPE("ast", AST, INVALID, "ast", "u") +TYPE("plist", Plist, INVALID, "plist", "") +TYPE("rewritten-objc", RewrittenObjC,INVALID, "cpp", "") +TYPE("rewritten-legacy-objc", RewrittenLegacyObjC,INVALID, "cpp", "") +TYPE("remap", Remap, INVALID, "remap", "") +TYPE("precompiled-header", PCH, INVALID, "gch", "A") +TYPE("object", Object, INVALID, "o", "") +TYPE("treelang", Treelang, INVALID, 0, "u") +TYPE("image", Image, INVALID, "out", "") +TYPE("dSYM", dSYM, INVALID, "dSYM", "A") +TYPE("dependencies", Dependencies, INVALID, "d", "") +TYPE("none", Nothing, INVALID, 0, "u") diff --git a/clang/include/clang/Driver/Types.h b/clang/include/clang/Driver/Types.h new file mode 100644 index 0000000..9187529 --- /dev/null +++ b/clang/include/clang/Driver/Types.h @@ -0,0 +1,96 @@ +//===--- Types.h - Input & Temporary Driver Types ---------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_DRIVER_TYPES_H_ +#define CLANG_DRIVER_TYPES_H_ + +#include "clang/Driver/Phases.h" + +namespace clang { +namespace driver { +namespace types { + enum ID { + TY_INVALID, +#define TYPE(NAME, ID, PP_TYPE, TEMP_SUFFIX, FLAGS) TY_##ID, +#include "clang/Driver/Types.def" +#undef TYPE + TY_LAST + }; + + /// getTypeName - Return the name of the type for \arg Id. + const char *getTypeName(ID Id); + + /// getPreprocessedType - Get the ID of the type for this input when + /// it has been preprocessed, or INVALID if this input is not + /// preprocessed. + ID getPreprocessedType(ID Id); + + /// getTypeTempSuffix - Return the suffix to use when creating a + /// temp file of this type, or null if unspecified. + const char *getTypeTempSuffix(ID Id); + + /// onlyAssembleType - Should this type only be assembled. + bool onlyAssembleType(ID Id); + + /// onlyPrecompileType - Should this type only be precompiled. + bool onlyPrecompileType(ID Id); + + /// canTypeBeUserSpecified - Can this type be specified on the + /// command line (by the type name); this is used when forwarding + /// commands to gcc. + bool canTypeBeUserSpecified(ID Id); + + /// appendSuffixForType - When generating outputs of this type, + /// should the suffix be appended (instead of replacing the existing + /// suffix). + bool appendSuffixForType(ID Id); + + /// canLipoType - Is this type acceptable as the output of a + /// universal build (currently, just the Nothing, Image, and Object + /// types). + bool canLipoType(ID Id); + + /// isAcceptedByClang - Can clang handle this input type. + bool isAcceptedByClang(ID Id); + + /// isOnlyAcceptedByClang - Is clang the only compiler that can handle this + /// input type. + bool isOnlyAcceptedByClang(ID Id); + + /// isCXX - Is this a "C++" input (C++ and Obj-C++ sources and headers). + bool isCXX(ID Id); + + /// isObjC - Is this an "ObjC" input (Obj-C and Obj-C++ sources and headers). + bool isObjC(ID Id); + + /// lookupTypeForExtension - Lookup the type to use for the file + /// extension \arg Ext. + ID lookupTypeForExtension(const char *Ext); + + /// lookupTypeForTypSpecifier - Lookup the type to use for a user + /// specified type name. + ID lookupTypeForTypeSpecifier(const char *Name); + + /// getNumCompilationPhases - Return the complete number of phases + /// to be done for this type. + unsigned getNumCompilationPhases(ID Id); + + /// getCompilationPhase - Return the \args N th compilation phase to + /// be done for this type. + phases::ID getCompilationPhase(ID Id, unsigned N); + + /// lookupCXXTypeForCType - Lookup CXX input type that corresponds to given + /// C type (used for clang++ emulation of g++ behaviour) + ID lookupCXXTypeForCType(ID Id); + +} // end namespace types +} // end namespace driver +} // end namespace clang + +#endif diff --git a/clang/include/clang/Driver/Util.h b/clang/include/clang/Driver/Util.h new file mode 100644 index 0000000..65aef4b --- /dev/null +++ b/clang/include/clang/Driver/Util.h @@ -0,0 +1,28 @@ +//===--- Util.h - Common Driver Utilities -----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_DRIVER_UTIL_H_ +#define CLANG_DRIVER_UTIL_H_ + +#include "clang/Basic/LLVM.h" + +namespace clang { +namespace driver { + class Action; + + /// ArgStringList - Type used for constructing argv lists for subprocesses. + typedef SmallVector<const char*, 16> ArgStringList; + + /// ActionList - Type used for lists of actions. + typedef SmallVector<Action*, 3> ActionList; + +} // end namespace driver +} // end namespace clang + +#endif diff --git a/clang/include/clang/Edit/Commit.h b/clang/include/clang/Edit/Commit.h new file mode 100644 index 0000000..aaf6b18 --- /dev/null +++ b/clang/include/clang/Edit/Commit.h @@ -0,0 +1,140 @@ +//===----- Commit.h - A unit of edits ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_EDIT_COMMIT_H +#define LLVM_CLANG_EDIT_COMMIT_H + +#include "clang/Edit/FileOffset.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/SmallVector.h" + +namespace clang { + class LangOptions; + class PreprocessingRecord; + +namespace edit { + class EditedSource; + +class Commit { +public: + enum EditKind { + Act_Insert, + Act_InsertFromRange, + Act_Remove + }; + + struct Edit { + EditKind Kind; + StringRef Text; + SourceLocation OrigLoc; + FileOffset Offset; + FileOffset InsertFromRangeOffs; + unsigned Length; + bool BeforePrev; + + SourceLocation getFileLocation(SourceManager &SM) const; + CharSourceRange getFileRange(SourceManager &SM) const; + CharSourceRange getInsertFromRange(SourceManager &SM) const; + }; + +private: + const SourceManager &SourceMgr; + const LangOptions &LangOpts; + const PreprocessingRecord *PPRec; + EditedSource *Editor; + + bool IsCommitable; + SmallVector<Edit, 8> CachedEdits; + +public: + explicit Commit(EditedSource &Editor); + Commit(const SourceManager &SM, const LangOptions &LangOpts, + const PreprocessingRecord *PPRec = 0) + : SourceMgr(SM), LangOpts(LangOpts), PPRec(PPRec), Editor(0), + IsCommitable(true) { } + + bool isCommitable() const { return IsCommitable; } + + bool insert(SourceLocation loc, StringRef text, bool afterToken = false, + bool beforePreviousInsertions = false); + bool insertAfterToken(SourceLocation loc, StringRef text, + bool beforePreviousInsertions = false) { + return insert(loc, text, /*afterToken=*/true, beforePreviousInsertions); + } + bool insertBefore(SourceLocation loc, StringRef text) { + return insert(loc, text, /*afterToken=*/false, + /*beforePreviousInsertions=*/true); + } + bool insertFromRange(SourceLocation loc, CharSourceRange range, + bool afterToken = false, + bool beforePreviousInsertions = false); + bool insertWrap(StringRef before, CharSourceRange range, StringRef after); + + bool remove(CharSourceRange range); + + bool replace(CharSourceRange range, StringRef text); + bool replaceWithInner(CharSourceRange range, CharSourceRange innerRange); + bool replaceText(SourceLocation loc, StringRef text, + StringRef replacementText); + + bool insertFromRange(SourceLocation loc, SourceRange TokenRange, + bool afterToken = false, + bool beforePreviousInsertions = false) { + return insertFromRange(loc, CharSourceRange::getTokenRange(TokenRange), + afterToken, beforePreviousInsertions); + } + bool insertWrap(StringRef before, SourceRange TokenRange, StringRef after) { + return insertWrap(before, CharSourceRange::getTokenRange(TokenRange), after); + } + bool remove(SourceRange TokenRange) { + return remove(CharSourceRange::getTokenRange(TokenRange)); + } + bool replace(SourceRange TokenRange, StringRef text) { + return replace(CharSourceRange::getTokenRange(TokenRange), text); + } + bool replaceWithInner(SourceRange TokenRange, SourceRange TokenInnerRange) { + return replaceWithInner(CharSourceRange::getTokenRange(TokenRange), + CharSourceRange::getTokenRange(TokenInnerRange)); + } + + typedef SmallVector<Edit, 8>::const_iterator edit_iterator; + edit_iterator edit_begin() const { return CachedEdits.begin(); } + edit_iterator edit_end() const { return CachedEdits.end(); } + +private: + void addInsert(SourceLocation OrigLoc, + FileOffset Offs, StringRef text, bool beforePreviousInsertions); + void addInsertFromRange(SourceLocation OrigLoc, FileOffset Offs, + FileOffset RangeOffs, unsigned RangeLen, + bool beforePreviousInsertions); + void addRemove(SourceLocation OrigLoc, FileOffset Offs, unsigned Len); + + bool canInsert(SourceLocation loc, FileOffset &Offset); + bool canInsertAfterToken(SourceLocation loc, FileOffset &Offset, + SourceLocation &AfterLoc); + bool canInsertInOffset(SourceLocation OrigLoc, FileOffset Offs); + bool canRemoveRange(CharSourceRange range, FileOffset &Offs, unsigned &Len); + bool canReplaceText(SourceLocation loc, StringRef text, + FileOffset &Offs, unsigned &Len); + + void commitInsert(FileOffset offset, StringRef text, + bool beforePreviousInsertions); + void commitRemove(FileOffset offset, unsigned length); + + bool isAtStartOfMacroExpansion(SourceLocation loc, + SourceLocation *MacroBegin = 0) const; + bool isAtEndOfMacroExpansion(SourceLocation loc, + SourceLocation *MacroEnd = 0) const; +}; + +} + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Edit/EditedSource.h b/clang/include/clang/Edit/EditedSource.h new file mode 100644 index 0000000..c685753 --- /dev/null +++ b/clang/include/clang/Edit/EditedSource.h @@ -0,0 +1,87 @@ +//===----- EditedSource.h - Collection of source edits ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_EDIT_EDITEDSOURCE_H +#define LLVM_CLANG_EDIT_EDITEDSOURCE_H + +#include "clang/Edit/FileOffset.h" +#include "llvm/Support/Allocator.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringRef.h" +#include <map> + +namespace clang { + class LangOptions; + class PreprocessingRecord; + +namespace edit { + class Commit; + class EditsReceiver; + +class EditedSource { + const SourceManager &SourceMgr; + const LangOptions &LangOpts; + const PreprocessingRecord *PPRec; + + struct FileEdit { + StringRef Text; + unsigned RemoveLen; + + FileEdit() : RemoveLen(0) {} + }; + + typedef std::map<FileOffset, FileEdit> FileEditsTy; + FileEditsTy FileEdits; + + llvm::DenseMap<unsigned, SourceLocation> ExpansionToArgMap; + + llvm::BumpPtrAllocator StrAlloc; + +public: + EditedSource(const SourceManager &SM, const LangOptions &LangOpts, + const PreprocessingRecord *PPRec = 0) + : SourceMgr(SM), LangOpts(LangOpts), PPRec(PPRec), + StrAlloc(/*size=*/512) { } + + const SourceManager &getSourceManager() const { return SourceMgr; } + const LangOptions &getLangOpts() const { return LangOpts; } + const PreprocessingRecord *getPreprocessingRecord() const { return PPRec; } + + bool canInsertInOffset(SourceLocation OrigLoc, FileOffset Offs); + + bool commit(const Commit &commit); + + void applyRewrites(EditsReceiver &receiver); + void clearRewrites(); + + StringRef copyString(StringRef str) { + char *buf = StrAlloc.Allocate<char>(str.size()); + std::memcpy(buf, str.data(), str.size()); + return StringRef(buf, str.size()); + } + StringRef copyString(const Twine &twine); + +private: + bool commitInsert(SourceLocation OrigLoc, FileOffset Offs, StringRef text, + bool beforePreviousInsertions); + bool commitInsertFromRange(SourceLocation OrigLoc, FileOffset Offs, + FileOffset InsertFromRangeOffs, unsigned Len, + bool beforePreviousInsertions); + void commitRemove(SourceLocation OrigLoc, FileOffset BeginOffs, unsigned Len); + + StringRef getSourceText(FileOffset BeginOffs, FileOffset EndOffs, + bool &Invalid); + FileEditsTy::iterator getActionForOffset(FileOffset Offs); +}; + +} + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Edit/EditsReceiver.h b/clang/include/clang/Edit/EditsReceiver.h new file mode 100644 index 0000000..600ac28 --- /dev/null +++ b/clang/include/clang/Edit/EditsReceiver.h @@ -0,0 +1,35 @@ +//===----- EditedSource.h - Collection of source edits ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_EDIT_EDITSRECEIVER_H +#define LLVM_CLANG_EDIT_EDITSRECEIVER_H + +#include "clang/Basic/LLVM.h" + +namespace clang { + class SourceLocation; + class CharSourceRange; + +namespace edit { + +class EditsReceiver { +public: + virtual ~EditsReceiver() { } + + virtual void insert(SourceLocation loc, StringRef text) = 0; + virtual void replace(CharSourceRange range, StringRef text) = 0; + /// \brief By default it calls replace with an empty string. + virtual void remove(CharSourceRange range); +}; + +} + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Edit/FileOffset.h b/clang/include/clang/Edit/FileOffset.h new file mode 100644 index 0000000..675ad18 --- /dev/null +++ b/clang/include/clang/Edit/FileOffset.h @@ -0,0 +1,65 @@ +//===----- FileOffset.h - Offset in a file ----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_EDIT_FILEOFFSET_H +#define LLVM_CLANG_EDIT_FILEOFFSET_H + +#include "clang/Basic/SourceLocation.h" + +namespace clang { + +namespace edit { + +class FileOffset { + FileID FID; + unsigned Offs; +public: + FileOffset() : Offs(0) { } + FileOffset(FileID fid, unsigned offs) : FID(fid), Offs(offs) { } + + bool isInvalid() const { return FID.isInvalid(); } + + FileID getFID() const { return FID; } + unsigned getOffset() const { return Offs; } + + FileOffset getWithOffset(unsigned offset) const { + FileOffset NewOffs = *this; + NewOffs.Offs += offset; + return NewOffs; + } + + friend bool operator==(FileOffset LHS, FileOffset RHS) { + return LHS.FID == RHS.FID && LHS.Offs == RHS.Offs; + } + friend bool operator!=(FileOffset LHS, FileOffset RHS) { + return !(LHS == RHS); + } + friend bool operator<(FileOffset LHS, FileOffset RHS) { + if (LHS.FID != RHS.FID) + return LHS.FID < RHS.FID; + return LHS.Offs < RHS.Offs; + } + friend bool operator>(FileOffset LHS, FileOffset RHS) { + if (LHS.FID != RHS.FID) + return LHS.FID > RHS.FID; + return LHS.Offs > RHS.Offs; + } + friend bool operator>=(FileOffset LHS, FileOffset RHS) { + return LHS > RHS || LHS == RHS; + } + friend bool operator<=(FileOffset LHS, FileOffset RHS) { + return LHS < RHS || LHS == RHS; + } +}; + +} + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Edit/Rewriters.h b/clang/include/clang/Edit/Rewriters.h new file mode 100644 index 0000000..aa7a5b2 --- /dev/null +++ b/clang/include/clang/Edit/Rewriters.h @@ -0,0 +1,33 @@ +//===--- Rewriters.h - Rewritings ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_EDIT_REWRITERS_H +#define LLVM_CLANG_EDIT_REWRITERS_H + +namespace clang { + class ObjCMessageExpr; + class NSAPI; + +namespace edit { + class Commit; + +bool rewriteObjCRedundantCallWithLiteral(const ObjCMessageExpr *Msg, + const NSAPI &NS, Commit &commit); + +bool rewriteToObjCLiteralSyntax(const ObjCMessageExpr *Msg, + const NSAPI &NS, Commit &commit); + +bool rewriteToObjCSubscriptSyntax(const ObjCMessageExpr *Msg, + const NSAPI &NS, Commit &commit); + +} + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Frontend/ASTConsumers.h b/clang/include/clang/Frontend/ASTConsumers.h new file mode 100644 index 0000000..cef9509 --- /dev/null +++ b/clang/include/clang/Frontend/ASTConsumers.h @@ -0,0 +1,57 @@ +//===--- ASTConsumers.h - ASTConsumer implementations -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// AST Consumers. +// +//===----------------------------------------------------------------------===// + +#ifndef DRIVER_ASTCONSUMERS_H +#define DRIVER_ASTCONSUMERS_H + +#include "clang/Basic/LLVM.h" + +namespace llvm { + namespace sys { class Path; } +} +namespace clang { + +class ASTConsumer; +class CodeGenOptions; +class DiagnosticsEngine; +class FileManager; +class LangOptions; +class Preprocessor; +class TargetOptions; + +// AST pretty-printer: prints out the AST in a format that is close to the +// original C code. The output is intended to be in a format such that +// clang could re-parse the output back into the same AST, but the +// implementation is still incomplete. +ASTConsumer *CreateASTPrinter(raw_ostream *OS); + +// AST dumper: dumps the raw AST in human-readable form to stderr; this is +// intended for debugging. +ASTConsumer *CreateASTDumper(); + +// AST XML-dumper: dumps out the AST to stderr in a very detailed XML +// format; this is intended for particularly intense debugging. +ASTConsumer *CreateASTDumperXML(raw_ostream &OS); + +// Graphical AST viewer: for each function definition, creates a graph of +// the AST and displays it with the graph viewer "dotty". Also outputs +// function declarations to stderr. +ASTConsumer *CreateASTViewer(); + +// DeclContext printer: prints out the DeclContext tree in human-readable form +// to stderr; this is intended for debugging. +ASTConsumer *CreateDeclContextPrinter(); + +} // end clang namespace + +#endif diff --git a/clang/include/clang/Frontend/ASTUnit.h b/clang/include/clang/Frontend/ASTUnit.h new file mode 100644 index 0000000..041eabb --- /dev/null +++ b/clang/include/clang/Frontend/ASTUnit.h @@ -0,0 +1,791 @@ +//===--- ASTUnit.h - ASTUnit utility ----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// ASTUnit utility class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_ASTUNIT_H +#define LLVM_CLANG_FRONTEND_ASTUNIT_H + +#include "clang/Serialization/ASTBitCodes.h" +#include "clang/Sema/Sema.h" +#include "clang/Sema/CodeCompleteConsumer.h" +#include "clang/Lex/ModuleLoader.h" +#include "clang/Lex/PreprocessingRecord.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/FileSystemOptions.h" +#include "clang-c/Index.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/Support/Path.h" +#include <map> +#include <string> +#include <vector> +#include <cassert> +#include <utility> +#include <sys/types.h> + +namespace llvm { + class MemoryBuffer; +} + +namespace clang { +class ASTContext; +class ASTReader; +class CodeCompleteConsumer; +class CompilerInvocation; +class CompilerInstance; +class Decl; +class DiagnosticsEngine; +class FileEntry; +class FileManager; +class HeaderSearch; +class Preprocessor; +class SourceManager; +class TargetInfo; +class ASTFrontendAction; + +/// \brief Utility class for loading a ASTContext from an AST file. +/// +class ASTUnit : public ModuleLoader { +private: + IntrusiveRefCntPtr<LangOptions> LangOpts; + IntrusiveRefCntPtr<DiagnosticsEngine> Diagnostics; + IntrusiveRefCntPtr<FileManager> FileMgr; + IntrusiveRefCntPtr<SourceManager> SourceMgr; + OwningPtr<HeaderSearch> HeaderInfo; + IntrusiveRefCntPtr<TargetInfo> Target; + IntrusiveRefCntPtr<Preprocessor> PP; + IntrusiveRefCntPtr<ASTContext> Ctx; + ASTReader *Reader; + + FileSystemOptions FileSystemOpts; + + /// \brief The AST consumer that received information about the translation + /// unit as it was parsed or loaded. + OwningPtr<ASTConsumer> Consumer; + + /// \brief The semantic analysis object used to type-check the translation + /// unit. + OwningPtr<Sema> TheSema; + + /// Optional owned invocation, just used to make the invocation used in + /// LoadFromCommandLine available. + IntrusiveRefCntPtr<CompilerInvocation> Invocation; + + /// \brief The set of target features. + /// + /// FIXME: each time we reparse, we need to restore the set of target + /// features from this vector, because TargetInfo::CreateTargetInfo() + /// mangles the target options in place. Yuck! + std::vector<std::string> TargetFeatures; + + // OnlyLocalDecls - when true, walking this AST should only visit declarations + // that come from the AST itself, not from included precompiled headers. + // FIXME: This is temporary; eventually, CIndex will always do this. + bool OnlyLocalDecls; + + /// \brief Whether to capture any diagnostics produced. + bool CaptureDiagnostics; + + /// \brief Track whether the main file was loaded from an AST or not. + bool MainFileIsAST; + + /// \brief What kind of translation unit this AST represents. + TranslationUnitKind TUKind; + + /// \brief Whether we should time each operation. + bool WantTiming; + + /// \brief Whether the ASTUnit should delete the remapped buffers. + bool OwnsRemappedFileBuffers; + + /// Track the top-level decls which appeared in an ASTUnit which was loaded + /// from a source file. + // + // FIXME: This is just an optimization hack to avoid deserializing large parts + // of a PCH file when using the Index library on an ASTUnit loaded from + // source. In the long term we should make the Index library use efficient and + // more scalable search mechanisms. + std::vector<Decl*> TopLevelDecls; + + /// \brief Sorted (by file offset) vector of pairs of file offset/Decl. + typedef SmallVector<std::pair<unsigned, Decl *>, 64> LocDeclsTy; + typedef llvm::DenseMap<FileID, LocDeclsTy *> FileDeclsTy; + + /// \brief Map from FileID to the file-level declarations that it contains. + /// The files and decls are only local (and non-preamble) ones. + FileDeclsTy FileDecls; + + /// The name of the original source file used to generate this ASTUnit. + std::string OriginalSourceFile; + + /// \brief The set of diagnostics produced when creating the preamble. + SmallVector<StoredDiagnostic, 4> PreambleDiagnostics; + + /// \brief The set of diagnostics produced when creating this + /// translation unit. + SmallVector<StoredDiagnostic, 4> StoredDiagnostics; + + /// \brief The set of diagnostics produced when failing to parse, e.g. due + /// to failure to load the PCH. + SmallVector<StoredDiagnostic, 4> FailedParseDiagnostics; + + /// \brief The number of stored diagnostics that come from the driver + /// itself. + /// + /// Diagnostics that come from the driver are retained from one parse to + /// the next. + unsigned NumStoredDiagnosticsFromDriver; + + /// \brief Counter that determines when we want to try building a + /// precompiled preamble. + /// + /// If zero, we will never build a precompiled preamble. Otherwise, + /// it's treated as a counter that decrements each time we reparse + /// without the benefit of a precompiled preamble. When it hits 1, + /// we'll attempt to rebuild the precompiled header. This way, if + /// building the precompiled preamble fails, we won't try again for + /// some number of calls. + unsigned PreambleRebuildCounter; + +public: + class PreambleData { + const FileEntry *File; + std::vector<char> Buffer; + mutable unsigned NumLines; + + public: + PreambleData() : File(0), NumLines(0) { } + + void assign(const FileEntry *F, const char *begin, const char *end) { + File = F; + Buffer.assign(begin, end); + NumLines = 0; + } + + void clear() { Buffer.clear(); File = 0; NumLines = 0; } + + size_t size() const { return Buffer.size(); } + bool empty() const { return Buffer.empty(); } + + const char *getBufferStart() const { return &Buffer[0]; } + + unsigned getNumLines() const { + if (NumLines) + return NumLines; + countLines(); + return NumLines; + } + + SourceRange getSourceRange(const SourceManager &SM) const { + SourceLocation FileLoc = SM.getLocForStartOfFile(SM.getPreambleFileID()); + return SourceRange(FileLoc, FileLoc.getLocWithOffset(size()-1)); + } + + private: + void countLines() const; + }; + + const PreambleData &getPreambleData() const { + return Preamble; + } + +private: + + /// \brief The contents of the preamble that has been precompiled to + /// \c PreambleFile. + PreambleData Preamble; + + /// \brief Whether the preamble ends at the start of a new line. + /// + /// Used to inform the lexer as to whether it's starting at the beginning of + /// a line after skipping the preamble. + bool PreambleEndsAtStartOfLine; + + /// \brief The size of the source buffer that we've reserved for the main + /// file within the precompiled preamble. + unsigned PreambleReservedSize; + + /// \brief Keeps track of the files that were used when computing the + /// preamble, with both their buffer size and their modification time. + /// + /// If any of the files have changed from one compile to the next, + /// the preamble must be thrown away. + llvm::StringMap<std::pair<off_t, time_t> > FilesInPreamble; + + /// \brief When non-NULL, this is the buffer used to store the contents of + /// the main file when it has been padded for use with the precompiled + /// preamble. + llvm::MemoryBuffer *SavedMainFileBuffer; + + /// \brief When non-NULL, this is the buffer used to store the + /// contents of the preamble when it has been padded to build the + /// precompiled preamble. + llvm::MemoryBuffer *PreambleBuffer; + + /// \brief The number of warnings that occurred while parsing the preamble. + /// + /// This value will be used to restore the state of the \c DiagnosticsEngine + /// object when re-using the precompiled preamble. Note that only the + /// number of warnings matters, since we will not save the preamble + /// when any errors are present. + unsigned NumWarningsInPreamble; + + /// \brief A list of the serialization ID numbers for each of the top-level + /// declarations parsed within the precompiled preamble. + std::vector<serialization::DeclID> TopLevelDeclsInPreamble; + + /// \brief Whether we should be caching code-completion results. + bool ShouldCacheCodeCompletionResults; + + /// \brief The language options used when we load an AST file. + LangOptions ASTFileLangOpts; + + static void ConfigureDiags(IntrusiveRefCntPtr<DiagnosticsEngine> &Diags, + const char **ArgBegin, const char **ArgEnd, + ASTUnit &AST, bool CaptureDiagnostics); + + void TranslateStoredDiagnostics(ASTReader *MMan, StringRef ModName, + SourceManager &SrcMan, + const SmallVectorImpl<StoredDiagnostic> &Diags, + SmallVectorImpl<StoredDiagnostic> &Out); + + void clearFileLevelDecls(); + +public: + /// \brief A cached code-completion result, which may be introduced in one of + /// many different contexts. + struct CachedCodeCompletionResult { + /// \brief The code-completion string corresponding to this completion + /// result. + CodeCompletionString *Completion; + + /// \brief A bitmask that indicates which code-completion contexts should + /// contain this completion result. + /// + /// The bits in the bitmask correspond to the values of + /// CodeCompleteContext::Kind. To map from a completion context kind to a + /// bit, subtract one from the completion context kind and shift 1 by that + /// number of bits. Many completions can occur in several different + /// contexts. + unsigned ShowInContexts; + + /// \brief The priority given to this code-completion result. + unsigned Priority; + + /// \brief The libclang cursor kind corresponding to this code-completion + /// result. + CXCursorKind Kind; + + /// \brief The availability of this code-completion result. + CXAvailabilityKind Availability; + + /// \brief The simplified type class for a non-macro completion result. + SimplifiedTypeClass TypeClass; + + /// \brief The type of a non-macro completion result, stored as a unique + /// integer used by the string map of cached completion types. + /// + /// This value will be zero if the type is not known, or a unique value + /// determined by the formatted type string. Se \c CachedCompletionTypes + /// for more information. + unsigned Type; + }; + + /// \brief Retrieve the mapping from formatted type names to unique type + /// identifiers. + llvm::StringMap<unsigned> &getCachedCompletionTypes() { + return CachedCompletionTypes; + } + + /// \brief Retrieve the allocator used to cache global code completions. + IntrusiveRefCntPtr<GlobalCodeCompletionAllocator> + getCachedCompletionAllocator() { + return CachedCompletionAllocator; + } + + CodeCompletionTUInfo &getCodeCompletionTUInfo() { + if (!CCTUInfo) + CCTUInfo.reset(new CodeCompletionTUInfo( + new GlobalCodeCompletionAllocator)); + return *CCTUInfo; + } + +private: + /// \brief Allocator used to store cached code completions. + IntrusiveRefCntPtr<GlobalCodeCompletionAllocator> + CachedCompletionAllocator; + + OwningPtr<CodeCompletionTUInfo> CCTUInfo; + + /// \brief The set of cached code-completion results. + std::vector<CachedCodeCompletionResult> CachedCompletionResults; + + /// \brief A mapping from the formatted type name to a unique number for that + /// type, which is used for type equality comparisons. + llvm::StringMap<unsigned> CachedCompletionTypes; + + /// \brief A string hash of the top-level declaration and macro definition + /// names processed the last time that we reparsed the file. + /// + /// This hash value is used to determine when we need to refresh the + /// global code-completion cache. + unsigned CompletionCacheTopLevelHashValue; + + /// \brief A string hash of the top-level declaration and macro definition + /// names processed the last time that we reparsed the precompiled preamble. + /// + /// This hash value is used to determine when we need to refresh the + /// global code-completion cache after a rebuild of the precompiled preamble. + unsigned PreambleTopLevelHashValue; + + /// \brief The current hash value for the top-level declaration and macro + /// definition names + unsigned CurrentTopLevelHashValue; + + /// \brief Bit used by CIndex to mark when a translation unit may be in an + /// inconsistent state, and is not safe to free. + unsigned UnsafeToFree : 1; + + /// \brief Cache any "global" code-completion results, so that we can avoid + /// recomputing them with each completion. + void CacheCodeCompletionResults(); + + /// \brief Clear out and deallocate + void ClearCachedCompletionResults(); + + ASTUnit(const ASTUnit&); // DO NOT IMPLEMENT + ASTUnit &operator=(const ASTUnit &); // DO NOT IMPLEMENT + + explicit ASTUnit(bool MainFileIsAST); + + void CleanTemporaryFiles(); + bool Parse(llvm::MemoryBuffer *OverrideMainBuffer); + + std::pair<llvm::MemoryBuffer *, std::pair<unsigned, bool> > + ComputePreamble(CompilerInvocation &Invocation, + unsigned MaxLines, bool &CreatedBuffer); + + llvm::MemoryBuffer *getMainBufferWithPrecompiledPreamble( + const CompilerInvocation &PreambleInvocationIn, + bool AllowRebuild = true, + unsigned MaxLines = 0); + void RealizeTopLevelDeclsFromPreamble(); + + /// \brief Transfers ownership of the objects (like SourceManager) from + /// \param CI to this ASTUnit. + void transferASTDataFromCompilerInstance(CompilerInstance &CI); + + /// \brief Allows us to assert that ASTUnit is not being used concurrently, + /// which is not supported. + /// + /// Clients should create instances of the ConcurrencyCheck class whenever + /// using the ASTUnit in a way that isn't intended to be concurrent, which is + /// just about any usage. + /// Becomes a noop in release mode; only useful for debug mode checking. + class ConcurrencyState { + void *Mutex; // a llvm::sys::MutexImpl in debug; + + public: + ConcurrencyState(); + ~ConcurrencyState(); + + void start(); + void finish(); + }; + ConcurrencyState ConcurrencyCheckValue; + +public: + class ConcurrencyCheck { + ASTUnit &Self; + + public: + explicit ConcurrencyCheck(ASTUnit &Self) + : Self(Self) + { + Self.ConcurrencyCheckValue.start(); + } + ~ConcurrencyCheck() { + Self.ConcurrencyCheckValue.finish(); + } + }; + friend class ConcurrencyCheck; + + ~ASTUnit(); + + bool isMainFileAST() const { return MainFileIsAST; } + + bool isUnsafeToFree() const { return UnsafeToFree; } + void setUnsafeToFree(bool Value) { UnsafeToFree = Value; } + + const DiagnosticsEngine &getDiagnostics() const { return *Diagnostics; } + DiagnosticsEngine &getDiagnostics() { return *Diagnostics; } + + const SourceManager &getSourceManager() const { return *SourceMgr; } + SourceManager &getSourceManager() { return *SourceMgr; } + + const Preprocessor &getPreprocessor() const { return *PP; } + Preprocessor &getPreprocessor() { return *PP; } + + const ASTContext &getASTContext() const { return *Ctx; } + ASTContext &getASTContext() { return *Ctx; } + + void setASTContext(ASTContext *ctx) { Ctx = ctx; } + void setPreprocessor(Preprocessor *pp); + + bool hasSema() const { return TheSema; } + Sema &getSema() const { + assert(TheSema && "ASTUnit does not have a Sema object!"); + return *TheSema; + } + + const FileManager &getFileManager() const { return *FileMgr; } + FileManager &getFileManager() { return *FileMgr; } + + const FileSystemOptions &getFileSystemOpts() const { return FileSystemOpts; } + + const std::string &getOriginalSourceFileName(); + + /// \brief Add a temporary file that the ASTUnit depends on. + /// + /// This file will be erased when the ASTUnit is destroyed. + void addTemporaryFile(const llvm::sys::Path &TempFile); + + bool getOnlyLocalDecls() const { return OnlyLocalDecls; } + + bool getOwnsRemappedFileBuffers() const { return OwnsRemappedFileBuffers; } + void setOwnsRemappedFileBuffers(bool val) { OwnsRemappedFileBuffers = val; } + + StringRef getMainFileName() const; + + typedef std::vector<Decl *>::iterator top_level_iterator; + + top_level_iterator top_level_begin() { + assert(!isMainFileAST() && "Invalid call for AST based ASTUnit!"); + if (!TopLevelDeclsInPreamble.empty()) + RealizeTopLevelDeclsFromPreamble(); + return TopLevelDecls.begin(); + } + + top_level_iterator top_level_end() { + assert(!isMainFileAST() && "Invalid call for AST based ASTUnit!"); + if (!TopLevelDeclsInPreamble.empty()) + RealizeTopLevelDeclsFromPreamble(); + return TopLevelDecls.end(); + } + + std::size_t top_level_size() const { + assert(!isMainFileAST() && "Invalid call for AST based ASTUnit!"); + return TopLevelDeclsInPreamble.size() + TopLevelDecls.size(); + } + + bool top_level_empty() const { + assert(!isMainFileAST() && "Invalid call for AST based ASTUnit!"); + return TopLevelDeclsInPreamble.empty() && TopLevelDecls.empty(); + } + + /// \brief Add a new top-level declaration. + void addTopLevelDecl(Decl *D) { + TopLevelDecls.push_back(D); + } + + /// \brief Add a new local file-level declaration. + void addFileLevelDecl(Decl *D); + + /// \brief Get the decls that are contained in a file in the Offset/Length + /// range. \arg Length can be 0 to indicate a point at \arg Offset instead of + /// a range. + void findFileRegionDecls(FileID File, unsigned Offset, unsigned Length, + SmallVectorImpl<Decl *> &Decls); + + /// \brief Add a new top-level declaration, identified by its ID in + /// the precompiled preamble. + void addTopLevelDeclFromPreamble(serialization::DeclID D) { + TopLevelDeclsInPreamble.push_back(D); + } + + /// \brief Retrieve a reference to the current top-level name hash value. + /// + /// Note: This is used internally by the top-level tracking action + unsigned &getCurrentTopLevelHashValue() { return CurrentTopLevelHashValue; } + + /// \brief Get the source location for the given file:line:col triplet. + /// + /// The difference with SourceManager::getLocation is that this method checks + /// whether the requested location points inside the precompiled preamble + /// in which case the returned source location will be a "loaded" one. + SourceLocation getLocation(const FileEntry *File, + unsigned Line, unsigned Col) const; + + /// \brief Get the source location for the given file:offset pair. + SourceLocation getLocation(const FileEntry *File, unsigned Offset) const; + + /// \brief If \arg Loc is a loaded location from the preamble, returns + /// the corresponding local location of the main file, otherwise it returns + /// \arg Loc. + SourceLocation mapLocationFromPreamble(SourceLocation Loc); + + /// \brief If \arg Loc is a local location of the main file but inside the + /// preamble chunk, returns the corresponding loaded location from the + /// preamble, otherwise it returns \arg Loc. + SourceLocation mapLocationToPreamble(SourceLocation Loc); + + bool isInPreambleFileID(SourceLocation Loc); + bool isInMainFileID(SourceLocation Loc); + SourceLocation getStartOfMainFileID(); + SourceLocation getEndOfPreambleFileID(); + + /// \brief \see mapLocationFromPreamble. + SourceRange mapRangeFromPreamble(SourceRange R) { + return SourceRange(mapLocationFromPreamble(R.getBegin()), + mapLocationFromPreamble(R.getEnd())); + } + + /// \brief \see mapLocationToPreamble. + SourceRange mapRangeToPreamble(SourceRange R) { + return SourceRange(mapLocationToPreamble(R.getBegin()), + mapLocationToPreamble(R.getEnd())); + } + + // Retrieve the diagnostics associated with this AST + typedef StoredDiagnostic *stored_diag_iterator; + typedef const StoredDiagnostic *stored_diag_const_iterator; + stored_diag_const_iterator stored_diag_begin() const { + return StoredDiagnostics.begin(); + } + stored_diag_iterator stored_diag_begin() { + return StoredDiagnostics.begin(); + } + stored_diag_const_iterator stored_diag_end() const { + return StoredDiagnostics.end(); + } + stored_diag_iterator stored_diag_end() { + return StoredDiagnostics.end(); + } + unsigned stored_diag_size() const { return StoredDiagnostics.size(); } + + stored_diag_iterator stored_diag_afterDriver_begin() { + if (NumStoredDiagnosticsFromDriver > StoredDiagnostics.size()) + NumStoredDiagnosticsFromDriver = 0; + return StoredDiagnostics.begin() + NumStoredDiagnosticsFromDriver; + } + + typedef std::vector<CachedCodeCompletionResult>::iterator + cached_completion_iterator; + + cached_completion_iterator cached_completion_begin() { + return CachedCompletionResults.begin(); + } + + cached_completion_iterator cached_completion_end() { + return CachedCompletionResults.end(); + } + + unsigned cached_completion_size() const { + return CachedCompletionResults.size(); + } + + llvm::MemoryBuffer *getBufferForFile(StringRef Filename, + std::string *ErrorStr = 0); + + /// \brief Determine what kind of translation unit this AST represents. + TranslationUnitKind getTranslationUnitKind() const { return TUKind; } + + typedef llvm::PointerUnion<const char *, const llvm::MemoryBuffer *> + FilenameOrMemBuf; + /// \brief A mapping from a file name to the memory buffer that stores the + /// remapped contents of that file. + typedef std::pair<std::string, FilenameOrMemBuf> RemappedFile; + + /// \brief Create a ASTUnit. Gets ownership of the passed CompilerInvocation. + static ASTUnit *create(CompilerInvocation *CI, + IntrusiveRefCntPtr<DiagnosticsEngine> Diags, + bool CaptureDiagnostics = false); + + /// \brief Create a ASTUnit from an AST file. + /// + /// \param Filename - The AST file to load. + /// + /// \param Diags - The diagnostics engine to use for reporting errors; its + /// lifetime is expected to extend past that of the returned ASTUnit. + /// + /// \returns - The initialized ASTUnit or null if the AST failed to load. + static ASTUnit *LoadFromASTFile(const std::string &Filename, + IntrusiveRefCntPtr<DiagnosticsEngine> Diags, + const FileSystemOptions &FileSystemOpts, + bool OnlyLocalDecls = false, + RemappedFile *RemappedFiles = 0, + unsigned NumRemappedFiles = 0, + bool CaptureDiagnostics = false, + bool AllowPCHWithCompilerErrors = false); + +private: + /// \brief Helper function for \c LoadFromCompilerInvocation() and + /// \c LoadFromCommandLine(), which loads an AST from a compiler invocation. + /// + /// \param PrecompilePreamble Whether to precompile the preamble of this + /// translation unit, to improve the performance of reparsing. + /// + /// \returns \c true if a catastrophic failure occurred (which means that the + /// \c ASTUnit itself is invalid), or \c false otherwise. + bool LoadFromCompilerInvocation(bool PrecompilePreamble); + +public: + + /// \brief Create an ASTUnit from a source file, via a CompilerInvocation + /// object, by invoking the optionally provided ASTFrontendAction. + /// + /// \param CI - The compiler invocation to use; it must have exactly one input + /// source file. The ASTUnit takes ownership of the CompilerInvocation object. + /// + /// \param Diags - The diagnostics engine to use for reporting errors; its + /// lifetime is expected to extend past that of the returned ASTUnit. + /// + /// \param Action - The ASTFrontendAction to invoke. Its ownership is not + /// transfered. + /// + /// \param Unit - optionally an already created ASTUnit. Its ownership is not + /// transfered. + /// + /// \param Persistent - if true the returned ASTUnit will be complete. + /// false means the caller is only interested in getting info through the + /// provided \see Action. + /// + /// \param ErrAST - If non-null and parsing failed without any AST to return + /// (e.g. because the PCH could not be loaded), this accepts the ASTUnit + /// mainly to allow the caller to see the diagnostics. + /// This will only receive an ASTUnit if a new one was created. If an already + /// created ASTUnit was passed in \param Unit then the caller can check that. + /// + static ASTUnit *LoadFromCompilerInvocationAction(CompilerInvocation *CI, + IntrusiveRefCntPtr<DiagnosticsEngine> Diags, + ASTFrontendAction *Action = 0, + ASTUnit *Unit = 0, + bool Persistent = true, + StringRef ResourceFilesPath = StringRef(), + bool OnlyLocalDecls = false, + bool CaptureDiagnostics = false, + bool PrecompilePreamble = false, + bool CacheCodeCompletionResults = false, + OwningPtr<ASTUnit> *ErrAST = 0); + + /// LoadFromCompilerInvocation - Create an ASTUnit from a source file, via a + /// CompilerInvocation object. + /// + /// \param CI - The compiler invocation to use; it must have exactly one input + /// source file. The ASTUnit takes ownership of the CompilerInvocation object. + /// + /// \param Diags - The diagnostics engine to use for reporting errors; its + /// lifetime is expected to extend past that of the returned ASTUnit. + // + // FIXME: Move OnlyLocalDecls, UseBumpAllocator to setters on the ASTUnit, we + // shouldn't need to specify them at construction time. + static ASTUnit *LoadFromCompilerInvocation(CompilerInvocation *CI, + IntrusiveRefCntPtr<DiagnosticsEngine> Diags, + bool OnlyLocalDecls = false, + bool CaptureDiagnostics = false, + bool PrecompilePreamble = false, + TranslationUnitKind TUKind = TU_Complete, + bool CacheCodeCompletionResults = false); + + /// LoadFromCommandLine - Create an ASTUnit from a vector of command line + /// arguments, which must specify exactly one source file. + /// + /// \param ArgBegin - The beginning of the argument vector. + /// + /// \param ArgEnd - The end of the argument vector. + /// + /// \param Diags - The diagnostics engine to use for reporting errors; its + /// lifetime is expected to extend past that of the returned ASTUnit. + /// + /// \param ResourceFilesPath - The path to the compiler resource files. + /// + /// \param ErrAST - If non-null and parsing failed without any AST to return + /// (e.g. because the PCH could not be loaded), this accepts the ASTUnit + /// mainly to allow the caller to see the diagnostics. + /// + // FIXME: Move OnlyLocalDecls, UseBumpAllocator to setters on the ASTUnit, we + // shouldn't need to specify them at construction time. + static ASTUnit *LoadFromCommandLine(const char **ArgBegin, + const char **ArgEnd, + IntrusiveRefCntPtr<DiagnosticsEngine> Diags, + StringRef ResourceFilesPath, + bool OnlyLocalDecls = false, + bool CaptureDiagnostics = false, + RemappedFile *RemappedFiles = 0, + unsigned NumRemappedFiles = 0, + bool RemappedFilesKeepOriginalName = true, + bool PrecompilePreamble = false, + TranslationUnitKind TUKind = TU_Complete, + bool CacheCodeCompletionResults = false, + bool AllowPCHWithCompilerErrors = false, + bool SkipFunctionBodies = false, + OwningPtr<ASTUnit> *ErrAST = 0); + + /// \brief Reparse the source files using the same command-line options that + /// were originally used to produce this translation unit. + /// + /// \returns True if a failure occurred that causes the ASTUnit not to + /// contain any translation-unit information, false otherwise. + bool Reparse(RemappedFile *RemappedFiles = 0, + unsigned NumRemappedFiles = 0); + + /// \brief Perform code completion at the given file, line, and + /// column within this translation unit. + /// + /// \param File The file in which code completion will occur. + /// + /// \param Line The line at which code completion will occur. + /// + /// \param Column The column at which code completion will occur. + /// + /// \param IncludeMacros Whether to include macros in the code-completion + /// results. + /// + /// \param IncludeCodePatterns Whether to include code patterns (such as a + /// for loop) in the code-completion results. + /// + /// FIXME: The Diag, LangOpts, SourceMgr, FileMgr, StoredDiagnostics, and + /// OwnedBuffers parameters are all disgusting hacks. They will go away. + void CodeComplete(StringRef File, unsigned Line, unsigned Column, + RemappedFile *RemappedFiles, unsigned NumRemappedFiles, + bool IncludeMacros, bool IncludeCodePatterns, + CodeCompleteConsumer &Consumer, + DiagnosticsEngine &Diag, LangOptions &LangOpts, + SourceManager &SourceMgr, FileManager &FileMgr, + SmallVectorImpl<StoredDiagnostic> &StoredDiagnostics, + SmallVectorImpl<const llvm::MemoryBuffer *> &OwnedBuffers); + + /// \brief Save this translation unit to a file with the given name. + /// + /// \returns An indication of whether the save was successful or not. + CXSaveError Save(StringRef File); + + /// \brief Serialize this translation unit with the given output stream. + /// + /// \returns True if an error occurred, false otherwise. + bool serialize(raw_ostream &OS); + + virtual Module *loadModule(SourceLocation ImportLoc, ModuleIdPath Path, + Module::NameVisibilityKind Visibility, + bool IsInclusionDirective) { + // ASTUnit doesn't know how to load modules (not that this matters). + return 0; + } +}; + +} // namespace clang + +#endif diff --git a/clang/include/clang/Frontend/Analyses.def b/clang/include/clang/Frontend/Analyses.def new file mode 100644 index 0000000..902575f --- /dev/null +++ b/clang/include/clang/Frontend/Analyses.def @@ -0,0 +1,66 @@ +//===-- Analyses.def - Metadata about Static Analyses -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the set of static analyses used by AnalysisConsumer. +// +//===----------------------------------------------------------------------===// + +#ifndef ANALYSIS_STORE +#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN) +#endif + +ANALYSIS_STORE(RegionStore, "region", "Use region-based analyzer store", CreateRegionStoreManager) + +#ifndef ANALYSIS_CONSTRAINTS +#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN) +#endif + +ANALYSIS_CONSTRAINTS(BasicConstraints, "basic", "Use basic constraint tracking", CreateBasicConstraintManager) +ANALYSIS_CONSTRAINTS(RangeConstraints, "range", "Use constraint tracking of concrete value ranges", CreateRangeConstraintManager) +ANALYSIS_CONSTRAINTS(IntervalConstraints, "interval", "Use constraint tracking of intervals", CreateIntervalConstraintManager) + +#ifndef ANALYSIS_DIAGNOSTICS +#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN, AUTOCREATE) +#endif + +ANALYSIS_DIAGNOSTICS(HTML, "html", "Output analysis results using HTML", createHTMLDiagnosticConsumer, false) +ANALYSIS_DIAGNOSTICS(PLIST, "plist", "Output analysis results using Plists", createPlistDiagnosticConsumer, true) +ANALYSIS_DIAGNOSTICS(PLIST_MULTI_FILE, "plist-multi-file", "Output analysis results using Plists (allowing for mult-file bugs)", createPlistMultiFileDiagnosticConsumer, true) +ANALYSIS_DIAGNOSTICS(PLIST_HTML, "plist-html", "Output analysis results using HTML wrapped with Plists", createPlistHTMLDiagnosticConsumer, true) +ANALYSIS_DIAGNOSTICS(TEXT, "text", "Text output of analysis results", createTextPathDiagnosticConsumer, true) + +#ifndef ANALYSIS_PURGE +#define ANALYSIS_PURGE(NAME, CMDFLAG, DESC) +#endif + +ANALYSIS_PURGE(PurgeStmt, "statement", "Purge symbols, bindings, and constraints before every statement") +ANALYSIS_PURGE(PurgeBlock, "block", "Purge symbols, bindings, and constraints before every basic block") +ANALYSIS_PURGE(PurgeNone, "none", "Do not purge symbols, bindings, or constraints") + +#ifndef ANALYSIS_IPA +#define ANALYSIS_IPA(NAME, CMDFLAG, DESC) +#endif + +ANALYSIS_IPA(None, "none", "Perform only intra-procedural analysis") +ANALYSIS_IPA(Inlining, "inlining", "Experimental: Inline callees when their definitions are available") + +#ifndef ANALYSIS_INLINING_MODE +#define ANALYSIS_INLINING_MODE(NAME, CMDFLAG, DESC) +#endif + +ANALYSIS_INLINING_MODE(All, "all", "Analyze all functions in the order defined in the TU") +ANALYSIS_INLINING_MODE(NoRedundancy, "noredundancy", "Do not analyze a function which has been previously inlined, use call graph to order") + +#undef ANALYSIS_STORE +#undef ANALYSIS_CONSTRAINTS +#undef ANALYSIS_DIAGNOSTICS +#undef ANALYSIS_PURGE +#undef ANALYSIS_INLINING_MODE +#undef ANALYSIS_IPA + diff --git a/clang/include/clang/Frontend/AnalyzerOptions.h b/clang/include/clang/Frontend/AnalyzerOptions.h new file mode 100644 index 0000000..847bfbd --- /dev/null +++ b/clang/include/clang/Frontend/AnalyzerOptions.h @@ -0,0 +1,137 @@ +//===--- AnalyzerOptions.h - Analysis Engine Options ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header contains the structures necessary for a front-end to specify +// various analyses. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_ANALYZEROPTIONS_H +#define LLVM_CLANG_FRONTEND_ANALYZEROPTIONS_H + +#include <string> +#include <vector> + +namespace clang { +class ASTConsumer; +class DiagnosticsEngine; +class Preprocessor; +class LangOptions; + +/// Analysis - Set of available source code analyses. +enum Analyses { +#define ANALYSIS(NAME, CMDFLAG, DESC, SCOPE) NAME, +#include "clang/Frontend/Analyses.def" +NumAnalyses +}; + +/// AnalysisStores - Set of available analysis store models. +enum AnalysisStores { +#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN) NAME##Model, +#include "clang/Frontend/Analyses.def" +NumStores +}; + +/// AnalysisConstraints - Set of available constraint models. +enum AnalysisConstraints { +#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN) NAME##Model, +#include "clang/Frontend/Analyses.def" +NumConstraints +}; + +/// AnalysisDiagClients - Set of available diagnostic clients for rendering +/// analysis results. +enum AnalysisDiagClients { +#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN, AUTOCREAT) PD_##NAME, +#include "clang/Frontend/Analyses.def" +NUM_ANALYSIS_DIAG_CLIENTS +}; + +/// AnalysisPurgeModes - Set of available strategies for dead symbol removal. +enum AnalysisPurgeMode { +#define ANALYSIS_PURGE(NAME, CMDFLAG, DESC) NAME, +#include "clang/Frontend/Analyses.def" +NumPurgeModes +}; + +/// AnalysisIPAMode - Set of inter-procedural modes. +enum AnalysisIPAMode { +#define ANALYSIS_IPA(NAME, CMDFLAG, DESC) NAME, +#include "clang/Frontend/Analyses.def" +NumIPAModes +}; + +/// AnalysisInlineFunctionSelection - Set of inlining function selection heuristics. +enum AnalysisInliningMode { +#define ANALYSIS_INLINING_MODE(NAME, CMDFLAG, DESC) NAME, +#include "clang/Frontend/Analyses.def" +NumInliningModes +}; + +class AnalyzerOptions { +public: + /// \brief Pair of checker name and enable/disable. + std::vector<std::pair<std::string, bool> > CheckersControlList; + AnalysisStores AnalysisStoreOpt; + AnalysisConstraints AnalysisConstraintsOpt; + AnalysisDiagClients AnalysisDiagOpt; + AnalysisPurgeMode AnalysisPurgeOpt; + AnalysisIPAMode IPAMode; + std::string AnalyzeSpecificFunction; + unsigned MaxNodes; + unsigned MaxLoop; + unsigned ShowCheckerHelp : 1; + unsigned AnalyzeAll : 1; + unsigned AnalyzerDisplayProgress : 1; + unsigned AnalyzeNestedBlocks : 1; + unsigned EagerlyAssume : 1; + unsigned TrimGraph : 1; + unsigned VisualizeEGDot : 1; + unsigned VisualizeEGUbi : 1; + unsigned UnoptimizedCFG : 1; + unsigned CFGAddImplicitDtors : 1; + unsigned CFGAddInitializers : 1; + unsigned EagerlyTrimEGraph : 1; + unsigned PrintStats : 1; + unsigned NoRetryExhausted : 1; + unsigned InlineMaxStackDepth; + unsigned InlineMaxFunctionSize; + AnalysisInliningMode InliningMode; + +public: + AnalyzerOptions() { + AnalysisStoreOpt = RegionStoreModel; + AnalysisConstraintsOpt = RangeConstraintsModel; + AnalysisDiagOpt = PD_HTML; + AnalysisPurgeOpt = PurgeStmt; + IPAMode = Inlining; + ShowCheckerHelp = 0; + AnalyzeAll = 0; + AnalyzerDisplayProgress = 0; + AnalyzeNestedBlocks = 0; + EagerlyAssume = 0; + TrimGraph = 0; + VisualizeEGDot = 0; + VisualizeEGUbi = 0; + UnoptimizedCFG = 0; + CFGAddImplicitDtors = 0; + CFGAddInitializers = 0; + EagerlyTrimEGraph = 0; + PrintStats = 0; + NoRetryExhausted = 0; + // Cap the stack depth at 4 calls (5 stack frames, base + 4 calls). + InlineMaxStackDepth = 5; + InlineMaxFunctionSize = 200; + InliningMode = NoRedundancy; + } +}; + +} + +#endif diff --git a/clang/include/clang/Frontend/ChainedDiagnosticConsumer.h b/clang/include/clang/Frontend/ChainedDiagnosticConsumer.h new file mode 100644 index 0000000..ce2b242 --- /dev/null +++ b/clang/include/clang/Frontend/ChainedDiagnosticConsumer.h @@ -0,0 +1,73 @@ +//===- ChainedDiagnosticConsumer.h - Chain Diagnostic Clients ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_CHAINEDDIAGNOSTICCONSUMER_H +#define LLVM_CLANG_FRONTEND_CHAINEDDIAGNOSTICCONSUMER_H + +#include "clang/Basic/Diagnostic.h" +#include "llvm/ADT/OwningPtr.h" + +namespace clang { +class LangOptions; + +/// ChainedDiagnosticConsumer - Chain two diagnostic clients so that diagnostics +/// go to the first client and then the second. The first diagnostic client +/// should be the "primary" client, and will be used for computing whether the +/// diagnostics should be included in counts. +class ChainedDiagnosticConsumer : public DiagnosticConsumer { + virtual void anchor(); + OwningPtr<DiagnosticConsumer> Primary; + OwningPtr<DiagnosticConsumer> Secondary; + +public: + ChainedDiagnosticConsumer(DiagnosticConsumer *_Primary, + DiagnosticConsumer *_Secondary) { + Primary.reset(_Primary); + Secondary.reset(_Secondary); + } + + virtual void BeginSourceFile(const LangOptions &LO, + const Preprocessor *PP) { + Primary->BeginSourceFile(LO, PP); + Secondary->BeginSourceFile(LO, PP); + } + + virtual void EndSourceFile() { + Secondary->EndSourceFile(); + Primary->EndSourceFile(); + } + + virtual void finish() { + Secondary->finish(); + Primary->finish(); + } + + virtual bool IncludeInDiagnosticCounts() const { + return Primary->IncludeInDiagnosticCounts(); + } + + virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, + const Diagnostic &Info) { + // Default implementation (Warnings/errors count). + DiagnosticConsumer::HandleDiagnostic(DiagLevel, Info); + + Primary->HandleDiagnostic(DiagLevel, Info); + Secondary->HandleDiagnostic(DiagLevel, Info); + } + + DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const { + return new ChainedDiagnosticConsumer(Primary->clone(Diags), + Secondary->clone(Diags)); + } + +}; + +} // end namspace clang + +#endif diff --git a/clang/include/clang/Frontend/ChainedIncludesSource.h b/clang/include/clang/Frontend/ChainedIncludesSource.h new file mode 100644 index 0000000..d7119e9 --- /dev/null +++ b/clang/include/clang/Frontend/ChainedIncludesSource.h @@ -0,0 +1,75 @@ +//===- ChainedIncludesSource.h - Chained PCHs in Memory ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ChainedIncludesSource class, which converts headers +// to chained PCHs in memory, mainly used for testing. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_SERIALIZATION_CHAINEDINCLUDESSOURCE_H +#define LLVM_CLANG_SERIALIZATION_CHAINEDINCLUDESSOURCE_H + +#include "clang/Sema/ExternalSemaSource.h" +#include <vector> + +namespace clang { + class CompilerInstance; + +class ChainedIncludesSource : public ExternalSemaSource { +public: + virtual ~ChainedIncludesSource(); + + static ChainedIncludesSource *create(CompilerInstance &CI); + +private: + ExternalSemaSource &getFinalReader() const { return *FinalReader; } + + std::vector<CompilerInstance *> CIs; + OwningPtr<ExternalSemaSource> FinalReader; + + +protected: + +//===----------------------------------------------------------------------===// +// ExternalASTSource interface. +//===----------------------------------------------------------------------===// + + virtual Decl *GetExternalDecl(uint32_t ID); + virtual Selector GetExternalSelector(uint32_t ID); + virtual uint32_t GetNumExternalSelectors(); + virtual Stmt *GetExternalDeclStmt(uint64_t Offset); + virtual CXXBaseSpecifier *GetExternalCXXBaseSpecifiers(uint64_t Offset); + virtual DeclContextLookupResult + FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name); + virtual ExternalLoadResult FindExternalLexicalDecls(const DeclContext *DC, + bool (*isKindWeWant)(Decl::Kind), + SmallVectorImpl<Decl*> &Result); + virtual void CompleteType(TagDecl *Tag); + virtual void CompleteType(ObjCInterfaceDecl *Class); + virtual void StartedDeserializing(); + virtual void FinishedDeserializing(); + virtual void StartTranslationUnit(ASTConsumer *Consumer); + virtual void PrintStats(); + + /// Return the amount of memory used by memory buffers, breaking down + /// by heap-backed versus mmap'ed memory. + virtual void getMemoryBufferSizes(MemoryBufferSizes &sizes) const; + +//===----------------------------------------------------------------------===// +// ExternalSemaSource interface. +//===----------------------------------------------------------------------===// + + virtual void InitializeSema(Sema &S); + virtual void ForgetSema(); + virtual void ReadMethodPool(Selector Sel); + virtual bool LookupUnqualified(LookupResult &R, Scope *S); +}; + +} + +#endif diff --git a/clang/include/clang/Frontend/CodeGenOptions.h b/clang/include/clang/Frontend/CodeGenOptions.h new file mode 100644 index 0000000..e844f88 --- /dev/null +++ b/clang/include/clang/Frontend/CodeGenOptions.h @@ -0,0 +1,231 @@ +//===--- CodeGenOptions.h ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the CodeGenOptions interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_CODEGENOPTIONS_H +#define LLVM_CLANG_FRONTEND_CODEGENOPTIONS_H + +#include <string> +#include <vector> + +namespace clang { + +/// CodeGenOptions - Track various options which control how the code +/// is optimized and passed to the backend. +class CodeGenOptions { +public: + enum InliningMethod { + NoInlining, // Perform no inlining whatsoever. + NormalInlining, // Use the standard function inlining pass. + OnlyAlwaysInlining // Only run the always inlining pass. + }; + + enum ObjCDispatchMethodKind { + Legacy = 0, + NonLegacy = 1, + Mixed = 2 + }; + + unsigned AsmVerbose : 1; /// -dA, -fverbose-asm. + unsigned ObjCAutoRefCountExceptions : 1; /// Whether ARC should be EH-safe. + unsigned CUDAIsDevice : 1; /// Set when compiling for CUDA device. + unsigned CXAAtExit : 1; /// Use __cxa_atexit for calling destructors. + unsigned CXXCtorDtorAliases: 1; /// Emit complete ctors/dtors as linker + /// aliases to base ctors when possible. + unsigned DataSections : 1; /// Set when -fdata-sections is enabled + unsigned DebugInfo : 1; /// Should generate debug info (-g). + unsigned LimitDebugInfo : 1; /// Limit generated debug info to reduce size. + unsigned DisableFPElim : 1; /// Set when -fomit-frame-pointer is enabled. + unsigned DisableLLVMOpts : 1; /// Don't run any optimizations, for use in + /// getting .bc files that correspond to the + /// internal state before optimizations are + /// done. + unsigned DisableRedZone : 1; /// Set when -mno-red-zone is enabled. + unsigned DisableTailCalls : 1; /// Do not emit tail calls. + unsigned EmitDeclMetadata : 1; /// Emit special metadata indicating what + /// Decl* various IR entities came from. Only + /// useful when running CodeGen as a + /// subroutine. + unsigned EmitGcovArcs : 1; /// Emit coverage data files, aka. GCDA. + unsigned EmitGcovNotes : 1; /// Emit coverage "notes" files, aka GCNO. + unsigned ForbidGuardVariables : 1; /// Issue errors if C++ guard variables + /// are required + unsigned FunctionSections : 1; /// Set when -ffunction-sections is enabled + unsigned HiddenWeakTemplateVTables : 1; /// Emit weak vtables and RTTI for + /// template classes with hidden visibility + unsigned HiddenWeakVTables : 1; /// Emit weak vtables, RTTI, and thunks with + /// hidden visibility. + unsigned InstrumentFunctions : 1; /// Set when -finstrument-functions is + /// enabled. + unsigned InstrumentForProfiling : 1; /// Set when -pg is enabled + unsigned LessPreciseFPMAD : 1; /// Enable less precise MAD instructions to be + /// generated. + unsigned MergeAllConstants : 1; /// Merge identical constants. + unsigned NoCommon : 1; /// Set when -fno-common or C++ is enabled. + unsigned NoDwarf2CFIAsm : 1; /// Set when -fno-dwarf2-cfi-asm is enabled. + unsigned NoDwarfDirectoryAsm : 1; /// Set when -fno-dwarf-directory-asm is + /// enabled. + unsigned NoExecStack : 1; /// Set when -Wa,--noexecstack is enabled. + unsigned NoGlobalMerge : 1; /// Set when -mno-global-merge is enabled. + unsigned NoImplicitFloat : 1; /// Set when -mno-implicit-float is enabled. + unsigned NoInfsFPMath : 1; /// Assume FP arguments, results not +-Inf. + unsigned NoInline : 1; /// Set when -fno-inline is enabled. Disables + /// use of the inline keyword. + unsigned NoNaNsFPMath : 1; /// Assume FP arguments, results not NaN. + unsigned NoZeroInitializedInBSS : 1; /// -fno-zero-initialized-in-bss + unsigned ObjCDispatchMethod : 2; /// Method of Objective-C dispatch to use. + unsigned ObjCRuntimeHasARC : 1; /// The target runtime supports ARC natively + unsigned ObjCRuntimeHasTerminate : 1; /// The ObjC runtime has objc_terminate + unsigned OmitLeafFramePointer : 1; /// Set when -momit-leaf-frame-pointer is + /// enabled. + unsigned OptimizationLevel : 3; /// The -O[0-4] option specified. + unsigned OptimizeSize : 2; /// If -Os (==1) or -Oz (==2) is specified. + unsigned RelaxAll : 1; /// Relax all machine code instructions. + unsigned RelaxedAliasing : 1; /// Set when -fno-strict-aliasing is enabled. + unsigned SaveTempLabels : 1; /// Save temporary labels. + unsigned SimplifyLibCalls : 1; /// Set when -fbuiltin is enabled. + unsigned SoftFloat : 1; /// -soft-float. + unsigned StrictEnums : 1; /// Optimize based on strict enum definition. + unsigned TimePasses : 1; /// Set when -ftime-report is enabled. + unsigned UnitAtATime : 1; /// Unused. For mirroring GCC optimization + /// selection. + unsigned UnrollLoops : 1; /// Control whether loops are unrolled. + unsigned UnsafeFPMath : 1; /// Allow unsafe floating point optzns. + unsigned UnwindTables : 1; /// Emit unwind tables. + + /// Attempt to use register sized accesses to bit-fields in structures, when + /// possible. + unsigned UseRegisterSizedBitfieldAccess : 1; + + unsigned VerifyModule : 1; /// Control whether the module should be run + /// through the LLVM Verifier. + + unsigned StackRealignment : 1; /// Control whether to permit stack + /// realignment. + unsigned StackAlignment; /// Overrides default stack alignment, + /// if not 0. + + /// The code model to use (-mcmodel). + std::string CodeModel; + + /// The filename with path we use for coverage files. The extension will be + /// replaced. + std::string CoverageFile; + + /// Enable additional debugging information. + std::string DebugPass; + + /// The string to embed in debug information as the current working directory. + std::string DebugCompilationDir; + + /// The string to embed in the debug information for the compile unit, if + /// non-empty. + std::string DwarfDebugFlags; + + /// The ABI to use for passing floating point arguments. + std::string FloatABI; + + /// The float precision limit to use, if non-empty. + std::string LimitFloatPrecision; + + /// The name of the bitcode file to link before optzns. + std::string LinkBitcodeFile; + + /// The kind of inlining to perform. + InliningMethod Inlining; + + /// The user provided name for the "main file", if non-empty. This is useful + /// in situations where the input file name does not match the original input + /// file, for example with -save-temps. + std::string MainFileName; + + /// The name of the relocation model to use. + std::string RelocationModel; + + /// If not an empty string, trap intrinsics are lowered to calls to this + /// function instead of to trap instructions. + std::string TrapFuncName; + + /// A list of command-line options to forward to the LLVM backend. + std::vector<std::string> BackendOptions; + + /// The user specified number of registers to be used for integral arguments, + /// or 0 if unspecified. + unsigned NumRegisterParameters; + +public: + CodeGenOptions() { + AsmVerbose = 0; + CUDAIsDevice = 0; + CXAAtExit = 1; + CXXCtorDtorAliases = 0; + DataSections = 0; + DebugInfo = 0; + LimitDebugInfo = 0; + DisableFPElim = 0; + DisableLLVMOpts = 0; + DisableRedZone = 0; + DisableTailCalls = 0; + EmitDeclMetadata = 0; + EmitGcovArcs = 0; + EmitGcovNotes = 0; + ForbidGuardVariables = 0; + FunctionSections = 0; + HiddenWeakTemplateVTables = 0; + HiddenWeakVTables = 0; + InstrumentFunctions = 0; + InstrumentForProfiling = 0; + LessPreciseFPMAD = 0; + MergeAllConstants = 1; + NoCommon = 0; + NoDwarf2CFIAsm = 0; + NoImplicitFloat = 0; + NoInfsFPMath = 0; + NoInline = 0; + NoNaNsFPMath = 0; + NoZeroInitializedInBSS = 0; + NumRegisterParameters = 0; + ObjCAutoRefCountExceptions = 0; + ObjCDispatchMethod = Legacy; + ObjCRuntimeHasARC = 0; + ObjCRuntimeHasTerminate = 0; + OmitLeafFramePointer = 0; + OptimizationLevel = 0; + OptimizeSize = 0; + RelaxAll = 0; + RelaxedAliasing = 0; + SaveTempLabels = 0; + SimplifyLibCalls = 1; + SoftFloat = 0; + StrictEnums = 0; + TimePasses = 0; + UnitAtATime = 1; + UnrollLoops = 0; + UnsafeFPMath = 0; + UnwindTables = 0; + UseRegisterSizedBitfieldAccess = 0; + VerifyModule = 1; + StackRealignment = 0; + StackAlignment = 0; + + Inlining = NoInlining; + RelocationModel = "pic"; + } + + ObjCDispatchMethodKind getObjCDispatchMethod() const { + return ObjCDispatchMethodKind(ObjCDispatchMethod); + } +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Frontend/CommandLineSourceLoc.h b/clang/include/clang/Frontend/CommandLineSourceLoc.h new file mode 100644 index 0000000..c01f91d --- /dev/null +++ b/clang/include/clang/Frontend/CommandLineSourceLoc.h @@ -0,0 +1,87 @@ + +//===--- CommandLineSourceLoc.h - Parsing for source locations-*- C++ -*---===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Command line parsing for source locations. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_COMMANDLINESOURCELOC_H +#define LLVM_CLANG_FRONTEND_COMMANDLINESOURCELOC_H + +#include "clang/Basic/LLVM.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/raw_ostream.h" + +namespace clang { + +/// \brief A source location that has been parsed on the command line. +struct ParsedSourceLocation { + std::string FileName; + unsigned Line; + unsigned Column; + +public: + /// Construct a parsed source location from a string; the Filename is empty on + /// error. + static ParsedSourceLocation FromString(StringRef Str) { + ParsedSourceLocation PSL; + std::pair<StringRef, StringRef> ColSplit = Str.rsplit(':'); + std::pair<StringRef, StringRef> LineSplit = + ColSplit.first.rsplit(':'); + + // If both tail splits were valid integers, return success. + if (!ColSplit.second.getAsInteger(10, PSL.Column) && + !LineSplit.second.getAsInteger(10, PSL.Line)) { + PSL.FileName = LineSplit.first; + + // On the command-line, stdin may be specified via "-". Inside the + // compiler, stdin is called "<stdin>". + if (PSL.FileName == "-") + PSL.FileName = "<stdin>"; + } + + return PSL; + } +}; + +} + +namespace llvm { + namespace cl { + /// \brief Command-line option parser that parses source locations. + /// + /// Source locations are of the form filename:line:column. + template<> + class parser<clang::ParsedSourceLocation> + : public basic_parser<clang::ParsedSourceLocation> { + public: + inline bool parse(Option &O, StringRef ArgName, StringRef ArgValue, + clang::ParsedSourceLocation &Val); + }; + + bool + parser<clang::ParsedSourceLocation>:: + parse(Option &O, StringRef ArgName, StringRef ArgValue, + clang::ParsedSourceLocation &Val) { + using namespace clang; + + Val = ParsedSourceLocation::FromString(ArgValue); + if (Val.FileName.empty()) { + errs() << "error: " + << "source location must be of the form filename:line:column\n"; + return true; + } + + return false; + } + } +} + +#endif diff --git a/clang/include/clang/Frontend/CompilerInstance.h b/clang/include/clang/Frontend/CompilerInstance.h new file mode 100644 index 0000000..1bb7695 --- /dev/null +++ b/clang/include/clang/Frontend/CompilerInstance.h @@ -0,0 +1,664 @@ +//===-- CompilerInstance.h - Clang Compiler Instance ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_COMPILERINSTANCE_H_ +#define LLVM_CLANG_FRONTEND_COMPILERINSTANCE_H_ + +#include "clang/Frontend/CompilerInvocation.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Lex/ModuleLoader.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/OwningPtr.h" +#include <cassert> +#include <list> +#include <string> +#include <utility> + +namespace llvm { +class raw_fd_ostream; +class Timer; +} + +namespace clang { +class ASTContext; +class ASTConsumer; +class ASTReader; +class CodeCompleteConsumer; +class DiagnosticsEngine; +class DiagnosticConsumer; +class ExternalASTSource; +class FileEntry; +class FileManager; +class FrontendAction; +class Module; +class Preprocessor; +class Sema; +class SourceManager; +class TargetInfo; + +/// CompilerInstance - Helper class for managing a single instance of the Clang +/// compiler. +/// +/// The CompilerInstance serves two purposes: +/// (1) It manages the various objects which are necessary to run the compiler, +/// for example the preprocessor, the target information, and the AST +/// context. +/// (2) It provides utility routines for constructing and manipulating the +/// common Clang objects. +/// +/// The compiler instance generally owns the instance of all the objects that it +/// manages. However, clients can still share objects by manually setting the +/// object and retaking ownership prior to destroying the CompilerInstance. +/// +/// The compiler instance is intended to simplify clients, but not to lock them +/// in to the compiler instance for everything. When possible, utility functions +/// come in two forms; a short form that reuses the CompilerInstance objects, +/// and a long form that takes explicit instances of any required objects. +class CompilerInstance : public ModuleLoader { + /// The options used in this compiler instance. + IntrusiveRefCntPtr<CompilerInvocation> Invocation; + + /// The diagnostics engine instance. + IntrusiveRefCntPtr<DiagnosticsEngine> Diagnostics; + + /// The target being compiled for. + IntrusiveRefCntPtr<TargetInfo> Target; + + /// The file manager. + IntrusiveRefCntPtr<FileManager> FileMgr; + + /// The source manager. + IntrusiveRefCntPtr<SourceManager> SourceMgr; + + /// The preprocessor. + IntrusiveRefCntPtr<Preprocessor> PP; + + /// The AST context. + IntrusiveRefCntPtr<ASTContext> Context; + + /// The AST consumer. + OwningPtr<ASTConsumer> Consumer; + + /// The code completion consumer. + OwningPtr<CodeCompleteConsumer> CompletionConsumer; + + /// \brief The semantic analysis object. + OwningPtr<Sema> TheSema; + + /// \brief The frontend timer + OwningPtr<llvm::Timer> FrontendTimer; + + /// \brief Non-owning reference to the ASTReader, if one exists. + ASTReader *ModuleManager; + + /// \brief The set of top-level modules that has already been loaded, + /// along with the module map + llvm::DenseMap<const IdentifierInfo *, Module *> KnownModules; + + /// \brief The location of the module-import keyword for the last module + /// import. + SourceLocation LastModuleImportLoc; + + /// \brief The result of the last module import. + /// + Module *LastModuleImportResult; + + /// \brief Holds information about the output file. + /// + /// If TempFilename is not empty we must rename it to Filename at the end. + /// TempFilename may be empty and Filename non empty if creating the temporary + /// failed. + struct OutputFile { + std::string Filename; + std::string TempFilename; + raw_ostream *OS; + + OutputFile(const std::string &filename, const std::string &tempFilename, + raw_ostream *os) + : Filename(filename), TempFilename(tempFilename), OS(os) { } + }; + + /// The list of active output files. + std::list<OutputFile> OutputFiles; + + void operator=(const CompilerInstance &); // DO NOT IMPLEMENT + CompilerInstance(const CompilerInstance&); // DO NOT IMPLEMENT +public: + CompilerInstance(); + ~CompilerInstance(); + + /// @name High-Level Operations + /// { + + /// ExecuteAction - Execute the provided action against the compiler's + /// CompilerInvocation object. + /// + /// This function makes the following assumptions: + /// + /// - The invocation options should be initialized. This function does not + /// handle the '-help' or '-version' options, clients should handle those + /// directly. + /// + /// - The diagnostics engine should have already been created by the client. + /// + /// - No other CompilerInstance state should have been initialized (this is + /// an unchecked error). + /// + /// - Clients should have initialized any LLVM target features that may be + /// required. + /// + /// - Clients should eventually call llvm_shutdown() upon the completion of + /// this routine to ensure that any managed objects are properly destroyed. + /// + /// Note that this routine may write output to 'stderr'. + /// + /// \param Act - The action to execute. + /// \return - True on success. + // + // FIXME: This function should take the stream to write any debugging / + // verbose output to as an argument. + // + // FIXME: Eliminate the llvm_shutdown requirement, that should either be part + // of the context or else not CompilerInstance specific. + bool ExecuteAction(FrontendAction &Act); + + /// } + /// @name Compiler Invocation and Options + /// { + + bool hasInvocation() const { return Invocation != 0; } + + CompilerInvocation &getInvocation() { + assert(Invocation && "Compiler instance has no invocation!"); + return *Invocation; + } + + /// setInvocation - Replace the current invocation. + void setInvocation(CompilerInvocation *Value); + + /// } + /// @name Forwarding Methods + /// { + + AnalyzerOptions &getAnalyzerOpts() { + return Invocation->getAnalyzerOpts(); + } + const AnalyzerOptions &getAnalyzerOpts() const { + return Invocation->getAnalyzerOpts(); + } + + CodeGenOptions &getCodeGenOpts() { + return Invocation->getCodeGenOpts(); + } + const CodeGenOptions &getCodeGenOpts() const { + return Invocation->getCodeGenOpts(); + } + + DependencyOutputOptions &getDependencyOutputOpts() { + return Invocation->getDependencyOutputOpts(); + } + const DependencyOutputOptions &getDependencyOutputOpts() const { + return Invocation->getDependencyOutputOpts(); + } + + DiagnosticOptions &getDiagnosticOpts() { + return Invocation->getDiagnosticOpts(); + } + const DiagnosticOptions &getDiagnosticOpts() const { + return Invocation->getDiagnosticOpts(); + } + + const FileSystemOptions &getFileSystemOpts() const { + return Invocation->getFileSystemOpts(); + } + + FrontendOptions &getFrontendOpts() { + return Invocation->getFrontendOpts(); + } + const FrontendOptions &getFrontendOpts() const { + return Invocation->getFrontendOpts(); + } + + HeaderSearchOptions &getHeaderSearchOpts() { + return Invocation->getHeaderSearchOpts(); + } + const HeaderSearchOptions &getHeaderSearchOpts() const { + return Invocation->getHeaderSearchOpts(); + } + + LangOptions &getLangOpts() { + return *Invocation->getLangOpts(); + } + const LangOptions &getLangOpts() const { + return *Invocation->getLangOpts(); + } + + PreprocessorOptions &getPreprocessorOpts() { + return Invocation->getPreprocessorOpts(); + } + const PreprocessorOptions &getPreprocessorOpts() const { + return Invocation->getPreprocessorOpts(); + } + + PreprocessorOutputOptions &getPreprocessorOutputOpts() { + return Invocation->getPreprocessorOutputOpts(); + } + const PreprocessorOutputOptions &getPreprocessorOutputOpts() const { + return Invocation->getPreprocessorOutputOpts(); + } + + TargetOptions &getTargetOpts() { + return Invocation->getTargetOpts(); + } + const TargetOptions &getTargetOpts() const { + return Invocation->getTargetOpts(); + } + + /// } + /// @name Diagnostics Engine + /// { + + bool hasDiagnostics() const { return Diagnostics != 0; } + + /// Get the current diagnostics engine. + DiagnosticsEngine &getDiagnostics() const { + assert(Diagnostics && "Compiler instance has no diagnostics!"); + return *Diagnostics; + } + + /// setDiagnostics - Replace the current diagnostics engine. + void setDiagnostics(DiagnosticsEngine *Value); + + DiagnosticConsumer &getDiagnosticClient() const { + assert(Diagnostics && Diagnostics->getClient() && + "Compiler instance has no diagnostic client!"); + return *Diagnostics->getClient(); + } + + /// } + /// @name Target Info + /// { + + bool hasTarget() const { return Target != 0; } + + TargetInfo &getTarget() const { + assert(Target && "Compiler instance has no target!"); + return *Target; + } + + /// Replace the current diagnostics engine. + void setTarget(TargetInfo *Value); + + /// } + /// @name File Manager + /// { + + bool hasFileManager() const { return FileMgr != 0; } + + /// Return the current file manager to the caller. + FileManager &getFileManager() const { + assert(FileMgr && "Compiler instance has no file manager!"); + return *FileMgr; + } + + void resetAndLeakFileManager() { + FileMgr.resetWithoutRelease(); + } + + /// setFileManager - Replace the current file manager. + void setFileManager(FileManager *Value); + + /// } + /// @name Source Manager + /// { + + bool hasSourceManager() const { return SourceMgr != 0; } + + /// Return the current source manager. + SourceManager &getSourceManager() const { + assert(SourceMgr && "Compiler instance has no source manager!"); + return *SourceMgr; + } + + void resetAndLeakSourceManager() { + SourceMgr.resetWithoutRelease(); + } + + /// setSourceManager - Replace the current source manager. + void setSourceManager(SourceManager *Value); + + /// } + /// @name Preprocessor + /// { + + bool hasPreprocessor() const { return PP != 0; } + + /// Return the current preprocessor. + Preprocessor &getPreprocessor() const { + assert(PP && "Compiler instance has no preprocessor!"); + return *PP; + } + + void resetAndLeakPreprocessor() { + PP.resetWithoutRelease(); + } + + /// Replace the current preprocessor. + void setPreprocessor(Preprocessor *Value); + + /// } + /// @name ASTContext + /// { + + bool hasASTContext() const { return Context != 0; } + + ASTContext &getASTContext() const { + assert(Context && "Compiler instance has no AST context!"); + return *Context; + } + + void resetAndLeakASTContext() { + Context.resetWithoutRelease(); + } + + /// setASTContext - Replace the current AST context. + void setASTContext(ASTContext *Value); + + /// \brief Replace the current Sema; the compiler instance takes ownership + /// of S. + void setSema(Sema *S); + + /// } + /// @name ASTConsumer + /// { + + bool hasASTConsumer() const { return Consumer != 0; } + + ASTConsumer &getASTConsumer() const { + assert(Consumer && "Compiler instance has no AST consumer!"); + return *Consumer; + } + + /// takeASTConsumer - Remove the current AST consumer and give ownership to + /// the caller. + ASTConsumer *takeASTConsumer() { return Consumer.take(); } + + /// setASTConsumer - Replace the current AST consumer; the compiler instance + /// takes ownership of \arg Value. + void setASTConsumer(ASTConsumer *Value); + + /// } + /// @name Semantic analysis + /// { + bool hasSema() const { return TheSema != 0; } + + Sema &getSema() const { + assert(TheSema && "Compiler instance has no Sema object!"); + return *TheSema; + } + + Sema *takeSema() { return TheSema.take(); } + + /// } + /// @name Module Management + /// { + + ASTReader *getModuleManager() const { return ModuleManager; } + + /// } + /// @name Code Completion + /// { + + bool hasCodeCompletionConsumer() const { return CompletionConsumer != 0; } + + CodeCompleteConsumer &getCodeCompletionConsumer() const { + assert(CompletionConsumer && + "Compiler instance has no code completion consumer!"); + return *CompletionConsumer; + } + + /// takeCodeCompletionConsumer - Remove the current code completion consumer + /// and give ownership to the caller. + CodeCompleteConsumer *takeCodeCompletionConsumer() { + return CompletionConsumer.take(); + } + + /// setCodeCompletionConsumer - Replace the current code completion consumer; + /// the compiler instance takes ownership of \arg Value. + void setCodeCompletionConsumer(CodeCompleteConsumer *Value); + + /// } + /// @name Frontend timer + /// { + + bool hasFrontendTimer() const { return FrontendTimer != 0; } + + llvm::Timer &getFrontendTimer() const { + assert(FrontendTimer && "Compiler instance has no frontend timer!"); + return *FrontendTimer; + } + + /// } + /// @name Output Files + /// { + + /// addOutputFile - Add an output file onto the list of tracked output files. + /// + /// \param OutFile - The output file info. + void addOutputFile(const OutputFile &OutFile); + + /// clearOutputFiles - Clear the output file list, destroying the contained + /// output streams. + /// + /// \param EraseFiles - If true, attempt to erase the files from disk. + void clearOutputFiles(bool EraseFiles); + + /// } + /// @name Construction Utility Methods + /// { + + /// Create the diagnostics engine using the invocation's diagnostic options + /// and replace any existing one with it. + /// + /// Note that this routine also replaces the diagnostic client, + /// allocating one if one is not provided. + /// + /// \param Client If non-NULL, a diagnostic client that will be + /// attached to (and, then, owned by) the DiagnosticsEngine inside this AST + /// unit. + /// + /// \param ShouldOwnClient If Client is non-NULL, specifies whether + /// the diagnostic object should take ownership of the client. + /// + /// \param ShouldCloneClient If Client is non-NULL, specifies whether that + /// client should be cloned. + void createDiagnostics(int Argc, const char* const *Argv, + DiagnosticConsumer *Client = 0, + bool ShouldOwnClient = true, + bool ShouldCloneClient = true); + + /// Create a DiagnosticsEngine object with a the TextDiagnosticPrinter. + /// + /// The \arg Argc and \arg Argv arguments are used only for logging purposes, + /// when the diagnostic options indicate that the compiler should output + /// logging information. + /// + /// If no diagnostic client is provided, this creates a + /// DiagnosticConsumer that is owned by the returned diagnostic + /// object, if using directly the caller is responsible for + /// releasing the returned DiagnosticsEngine's client eventually. + /// + /// \param Opts - The diagnostic options; note that the created text + /// diagnostic object contains a reference to these options and its lifetime + /// must extend past that of the diagnostic engine. + /// + /// \param Client If non-NULL, a diagnostic client that will be + /// attached to (and, then, owned by) the returned DiagnosticsEngine + /// object. + /// + /// \param CodeGenOpts If non-NULL, the code gen options in use, which may be + /// used by some diagnostics printers (for logging purposes only). + /// + /// \return The new object on success, or null on failure. + static IntrusiveRefCntPtr<DiagnosticsEngine> + createDiagnostics(const DiagnosticOptions &Opts, int Argc, + const char* const *Argv, + DiagnosticConsumer *Client = 0, + bool ShouldOwnClient = true, + bool ShouldCloneClient = true, + const CodeGenOptions *CodeGenOpts = 0); + + /// Create the file manager and replace any existing one with it. + void createFileManager(); + + /// Create the source manager and replace any existing one with it. + void createSourceManager(FileManager &FileMgr); + + /// Create the preprocessor, using the invocation, file, and source managers, + /// and replace any existing one with it. + void createPreprocessor(); + + /// Create the AST context. + void createASTContext(); + + /// Create an external AST source to read a PCH file and attach it to the AST + /// context. + void createPCHExternalASTSource(StringRef Path, + bool DisablePCHValidation, + bool DisableStatCache, + bool AllowPCHWithCompilerErrors, + void *DeserializationListener); + + /// Create an external AST source to read a PCH file. + /// + /// \return - The new object on success, or null on failure. + static ExternalASTSource * + createPCHExternalASTSource(StringRef Path, const std::string &Sysroot, + bool DisablePCHValidation, + bool DisableStatCache, + bool AllowPCHWithCompilerErrors, + Preprocessor &PP, ASTContext &Context, + void *DeserializationListener, bool Preamble); + + /// Create a code completion consumer using the invocation; note that this + /// will cause the source manager to truncate the input source file at the + /// completion point. + void createCodeCompletionConsumer(); + + /// Create a code completion consumer to print code completion results, at + /// \arg Filename, \arg Line, and \arg Column, to the given output stream \arg + /// OS. + static CodeCompleteConsumer * + createCodeCompletionConsumer(Preprocessor &PP, const std::string &Filename, + unsigned Line, unsigned Column, + bool ShowMacros, + bool ShowCodePatterns, bool ShowGlobals, + raw_ostream &OS); + + /// \brief Create the Sema object to be used for parsing. + void createSema(TranslationUnitKind TUKind, + CodeCompleteConsumer *CompletionConsumer); + + /// Create the frontend timer and replace any existing one with it. + void createFrontendTimer(); + + /// Create the default output file (from the invocation's options) and add it + /// to the list of tracked output files. + /// + /// The files created by this function always use temporary files to write to + /// their result (that is, the data is written to a temporary file which will + /// atomically replace the target output on success). + /// + /// \return - Null on error. + llvm::raw_fd_ostream * + createDefaultOutputFile(bool Binary = true, StringRef BaseInput = "", + StringRef Extension = ""); + + /// Create a new output file and add it to the list of tracked output files, + /// optionally deriving the output path name. + /// + /// \return - Null on error. + llvm::raw_fd_ostream * + createOutputFile(StringRef OutputPath, + bool Binary = true, bool RemoveFileOnSignal = true, + StringRef BaseInput = "", + StringRef Extension = "", + bool UseTemporary = false, + bool CreateMissingDirectories = false); + + /// Create a new output file, optionally deriving the output path name. + /// + /// If \arg OutputPath is empty, then createOutputFile will derive an output + /// path location as \arg BaseInput, with any suffix removed, and \arg + /// Extension appended. If OutputPath is not stdout and \arg UseTemporary + /// is true, createOutputFile will create a new temporary file that must be + /// renamed to OutputPath in the end. + /// + /// \param OutputPath - If given, the path to the output file. + /// \param Error [out] - On failure, the error message. + /// \param BaseInput - If \arg OutputPath is empty, the input path name to use + /// for deriving the output path. + /// \param Extension - The extension to use for derived output names. + /// \param Binary - The mode to open the file in. + /// \param RemoveFileOnSignal - Whether the file should be registered with + /// llvm::sys::RemoveFileOnSignal. Note that this is not safe for + /// multithreaded use, as the underlying signal mechanism is not reentrant + /// \param UseTemporary - Create a new temporary file that must be renamed to + /// OutputPath in the end. + /// \param CreateMissingDirectories - When \arg UseTemporary is true, create + /// missing directories in the output path. + /// \param ResultPathName [out] - If given, the result path name will be + /// stored here on success. + /// \param TempPathName [out] - If given, the temporary file path name + /// will be stored here on success. + static llvm::raw_fd_ostream * + createOutputFile(StringRef OutputPath, std::string &Error, + bool Binary = true, bool RemoveFileOnSignal = true, + StringRef BaseInput = "", + StringRef Extension = "", + bool UseTemporary = false, + bool CreateMissingDirectories = false, + std::string *ResultPathName = 0, + std::string *TempPathName = 0); + + /// } + /// @name Initialization Utility Methods + /// { + + /// InitializeSourceManager - Initialize the source manager to set InputFile + /// as the main file. + /// + /// \return True on success. + bool InitializeSourceManager(StringRef InputFile, + SrcMgr::CharacteristicKind Kind = SrcMgr::C_User); + + /// InitializeSourceManager - Initialize the source manager to set InputFile + /// as the main file. + /// + /// \return True on success. + static bool InitializeSourceManager(StringRef InputFile, + SrcMgr::CharacteristicKind Kind, + DiagnosticsEngine &Diags, + FileManager &FileMgr, + SourceManager &SourceMgr, + const FrontendOptions &Opts); + + /// } + + virtual Module *loadModule(SourceLocation ImportLoc, ModuleIdPath Path, + Module::NameVisibilityKind Visibility, + bool IsInclusionDirective); +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Frontend/CompilerInvocation.h b/clang/include/clang/Frontend/CompilerInvocation.h new file mode 100644 index 0000000..0d2260a --- /dev/null +++ b/clang/include/clang/Frontend/CompilerInvocation.h @@ -0,0 +1,221 @@ +//===-- CompilerInvocation.h - Compiler Invocation Helper Data --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_COMPILERINVOCATION_H_ +#define LLVM_CLANG_FRONTEND_COMPILERINVOCATION_H_ + +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/TargetOptions.h" +#include "clang/Basic/FileSystemOptions.h" +#include "clang/Frontend/AnalyzerOptions.h" +#include "clang/Frontend/MigratorOptions.h" +#include "clang/Frontend/CodeGenOptions.h" +#include "clang/Frontend/DependencyOutputOptions.h" +#include "clang/Frontend/DiagnosticOptions.h" +#include "clang/Frontend/FrontendOptions.h" +#include "clang/Frontend/HeaderSearchOptions.h" +#include "clang/Frontend/LangStandard.h" +#include "clang/Frontend/PreprocessorOptions.h" +#include "clang/Frontend/PreprocessorOutputOptions.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringMap.h" +#include <string> +#include <vector> + +namespace clang { + +class CompilerInvocation; +class DiagnosticsEngine; + +namespace driver { +class ArgList; +} + +/// CompilerInvocation - Fill out Opts based on the options given in Args. +/// Args must have been created from the OptTable returned by +/// createCC1OptTable(). When errors are encountered, return false and, +/// if Diags is non-null, report the error(s). +bool ParseDiagnosticArgs(DiagnosticOptions &Opts, driver::ArgList &Args, + DiagnosticsEngine *Diags = 0); + +class CompilerInvocationBase : public RefCountedBase<CompilerInvocation> { +protected: + /// Options controlling the language variant. + IntrusiveRefCntPtr<LangOptions> LangOpts; +public: + CompilerInvocationBase(); + + CompilerInvocationBase(const CompilerInvocationBase &X); + + LangOptions *getLangOpts() { return LangOpts.getPtr(); } + const LangOptions *getLangOpts() const { return LangOpts.getPtr(); } +}; + +/// CompilerInvocation - Helper class for holding the data necessary to invoke +/// the compiler. +/// +/// This class is designed to represent an abstract "invocation" of the +/// compiler, including data such as the include paths, the code generation +/// options, the warning flags, and so on. +class CompilerInvocation : public CompilerInvocationBase { + /// Options controlling the static analyzer. + AnalyzerOptions AnalyzerOpts; + + MigratorOptions MigratorOpts; + + /// Options controlling IRgen and the backend. + CodeGenOptions CodeGenOpts; + + /// Options controlling dependency output. + DependencyOutputOptions DependencyOutputOpts; + + /// Options controlling the diagnostic engine. + DiagnosticOptions DiagnosticOpts; + + /// Options controlling file system operations. + FileSystemOptions FileSystemOpts; + + /// Options controlling the frontend itself. + FrontendOptions FrontendOpts; + + /// Options controlling the #include directive. + HeaderSearchOptions HeaderSearchOpts; + + /// Options controlling the preprocessor (aside from #include handling). + PreprocessorOptions PreprocessorOpts; + + /// Options controlling preprocessed output. + PreprocessorOutputOptions PreprocessorOutputOpts; + + /// Options controlling the target. + TargetOptions TargetOpts; + +public: + CompilerInvocation() {} + + /// @name Utility Methods + /// @{ + + /// CreateFromArgs - Create a compiler invocation from a list of input + /// options. Returns true on success. + /// + /// \param Res [out] - The resulting invocation. + /// \param ArgBegin - The first element in the argument vector. + /// \param ArgEnd - The last element in the argument vector. + /// \param Diags - The diagnostic engine to use for errors. + static bool CreateFromArgs(CompilerInvocation &Res, + const char* const *ArgBegin, + const char* const *ArgEnd, + DiagnosticsEngine &Diags); + + /// GetBuiltinIncludePath - Get the directory where the compiler headers + /// reside, relative to the compiler binary (found by the passed in + /// arguments). + /// + /// \param Argv0 - The program path (from argv[0]), for finding the builtin + /// compiler path. + /// \param MainAddr - The address of main (or some other function in the main + /// executable), for finding the builtin compiler path. + static std::string GetResourcesPath(const char *Argv0, void *MainAddr); + + /// toArgs - Convert the CompilerInvocation to a list of strings suitable for + /// passing to CreateFromArgs. + void toArgs(std::vector<std::string> &Res); + + /// setLangDefaults - Set language defaults for the given input language and + /// language standard in this CompilerInvocation. + /// + /// \param IK - The input language. + /// \param LangStd - The input language standard. + void setLangDefaults(InputKind IK, + LangStandard::Kind LangStd = LangStandard::lang_unspecified) { + setLangDefaults(*getLangOpts(), IK, LangStd); + } + + /// setLangDefaults - Set language defaults for the given input language and + /// language standard in the given LangOptions object. + /// + /// \param LangOpts - The LangOptions object to set up. + /// \param IK - The input language. + /// \param LangStd - The input language standard. + static void setLangDefaults(LangOptions &Opts, InputKind IK, + LangStandard::Kind LangStd = LangStandard::lang_unspecified); + + /// \brief Retrieve a module hash string that is suitable for uniquely + /// identifying the conditions under which the module was built. + std::string getModuleHash() const; + + /// @} + /// @name Option Subgroups + /// @{ + + AnalyzerOptions &getAnalyzerOpts() { return AnalyzerOpts; } + const AnalyzerOptions &getAnalyzerOpts() const { + return AnalyzerOpts; + } + + MigratorOptions &getMigratorOpts() { return MigratorOpts; } + const MigratorOptions &getMigratorOpts() const { + return MigratorOpts; + } + + CodeGenOptions &getCodeGenOpts() { return CodeGenOpts; } + const CodeGenOptions &getCodeGenOpts() const { + return CodeGenOpts; + } + + DependencyOutputOptions &getDependencyOutputOpts() { + return DependencyOutputOpts; + } + const DependencyOutputOptions &getDependencyOutputOpts() const { + return DependencyOutputOpts; + } + + DiagnosticOptions &getDiagnosticOpts() { return DiagnosticOpts; } + const DiagnosticOptions &getDiagnosticOpts() const { return DiagnosticOpts; } + + FileSystemOptions &getFileSystemOpts() { return FileSystemOpts; } + const FileSystemOptions &getFileSystemOpts() const { + return FileSystemOpts; + } + + HeaderSearchOptions &getHeaderSearchOpts() { return HeaderSearchOpts; } + const HeaderSearchOptions &getHeaderSearchOpts() const { + return HeaderSearchOpts; + } + + FrontendOptions &getFrontendOpts() { return FrontendOpts; } + const FrontendOptions &getFrontendOpts() const { + return FrontendOpts; + } + + PreprocessorOptions &getPreprocessorOpts() { return PreprocessorOpts; } + const PreprocessorOptions &getPreprocessorOpts() const { + return PreprocessorOpts; + } + + PreprocessorOutputOptions &getPreprocessorOutputOpts() { + return PreprocessorOutputOpts; + } + const PreprocessorOutputOptions &getPreprocessorOutputOpts() const { + return PreprocessorOutputOpts; + } + + TargetOptions &getTargetOpts() { return TargetOpts; } + const TargetOptions &getTargetOpts() const { + return TargetOpts; + } + + /// @} +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Frontend/DependencyOutputOptions.h b/clang/include/clang/Frontend/DependencyOutputOptions.h new file mode 100644 index 0000000..83976c3 --- /dev/null +++ b/clang/include/clang/Frontend/DependencyOutputOptions.h @@ -0,0 +1,56 @@ +//===--- DependencyOutputOptions.h ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_DEPENDENCYOUTPUTOPTIONS_H +#define LLVM_CLANG_FRONTEND_DEPENDENCYOUTPUTOPTIONS_H + +#include <string> +#include <vector> + +namespace clang { + +/// DependencyOutputOptions - Options for controlling the compiler dependency +/// file generation. +class DependencyOutputOptions { +public: + unsigned IncludeSystemHeaders : 1; ///< Include system header dependencies. + unsigned ShowHeaderIncludes : 1; ///< Show header inclusions (-H). + unsigned UsePhonyTargets : 1; ///< Include phony targets for each + /// dependency, which can avoid some 'make' + /// problems. + unsigned AddMissingHeaderDeps : 1; ///< Add missing headers to dependency list + + /// The file to write dependency output to. + std::string OutputFile; + + /// The file to write header include output to. This is orthogonal to + /// ShowHeaderIncludes (-H) and will include headers mentioned in the + /// predefines buffer. If the output file is "-", output will be sent to + /// stderr. + std::string HeaderIncludeOutputFile; + + /// A list of names to use as the targets in the dependency file; this list + /// must contain at least one entry. + std::vector<std::string> Targets; + + /// \brief The file to write GraphViz-formatted header dependencies to. + std::string DOTOutputFile; + +public: + DependencyOutputOptions() { + IncludeSystemHeaders = 0; + ShowHeaderIncludes = 0; + UsePhonyTargets = 0; + AddMissingHeaderDeps = 0; + } +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Frontend/DiagnosticOptions.h b/clang/include/clang/Frontend/DiagnosticOptions.h new file mode 100644 index 0000000..1c6ba6a --- /dev/null +++ b/clang/include/clang/Frontend/DiagnosticOptions.h @@ -0,0 +1,108 @@ +//===--- DiagnosticOptions.h ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_DIAGNOSTICOPTIONS_H +#define LLVM_CLANG_FRONTEND_DIAGNOSTICOPTIONS_H + +#include "clang/Basic/Diagnostic.h" + +#include <string> +#include <vector> + +namespace clang { + +/// DiagnosticOptions - Options for controlling the compiler diagnostics +/// engine. +class DiagnosticOptions { +public: + unsigned IgnoreWarnings : 1; /// -w + unsigned NoRewriteMacros : 1; /// -Wno-rewrite-macros + unsigned Pedantic : 1; /// -pedantic + unsigned PedanticErrors : 1; /// -pedantic-errors + unsigned ShowColumn : 1; /// Show column number on diagnostics. + unsigned ShowLocation : 1; /// Show source location information. + unsigned ShowCarets : 1; /// Show carets in diagnostics. + unsigned ShowFixits : 1; /// Show fixit information. + unsigned ShowSourceRanges : 1; /// Show source ranges in numeric form. + unsigned ShowParseableFixits : 1; /// Show machine parseable fix-its. + unsigned ShowOptionNames : 1; /// Show the option name for mappable + /// diagnostics. + unsigned ShowNoteIncludeStack : 1; /// Show include stacks for notes. + unsigned ShowCategories : 2; /// Show categories: 0 -> none, 1 -> Number, + /// 2 -> Full Name. + + unsigned Format : 2; /// Format for diagnostics: + enum TextDiagnosticFormat { Clang, Msvc, Vi }; + + unsigned ShowColors : 1; /// Show diagnostics with ANSI color sequences. + unsigned ShowOverloads : 1; /// Overload candidates to show. Values from + /// DiagnosticsEngine::OverloadsShown + unsigned VerifyDiagnostics: 1; /// Check that diagnostics match the expected + /// diagnostics, indicated by markers in the + /// input source file. + + unsigned ErrorLimit; /// Limit # errors emitted. + unsigned MacroBacktraceLimit; /// Limit depth of macro expansion backtrace. + unsigned TemplateBacktraceLimit; /// Limit depth of instantiation backtrace. + unsigned ConstexprBacktraceLimit; /// Limit depth of constexpr backtrace. + + /// The distance between tab stops. + unsigned TabStop; + enum { DefaultTabStop = 8, MaxTabStop = 100, + DefaultMacroBacktraceLimit = 6, + DefaultTemplateBacktraceLimit = 10, + DefaultConstexprBacktraceLimit = 10 }; + + /// Column limit for formatting message diagnostics, or 0 if unused. + unsigned MessageLength; + + /// If non-empty, a file to log extended build information to, for development + /// testing and analysis. + std::string DumpBuildInformation; + + /// The file to log diagnostic output to. + std::string DiagnosticLogFile; + + /// The file to serialize diagnostics to (non-appending). + std::string DiagnosticSerializationFile; + + /// The list of -W... options used to alter the diagnostic mappings, with the + /// prefixes removed. + std::vector<std::string> Warnings; + +public: + DiagnosticOptions() { + IgnoreWarnings = 0; + TabStop = DefaultTabStop; + MessageLength = 0; + NoRewriteMacros = 0; + Pedantic = 0; + PedanticErrors = 0; + ShowCarets = 1; + ShowColors = 0; + ShowOverloads = DiagnosticsEngine::Ovl_All; + ShowColumn = 1; + ShowFixits = 1; + ShowLocation = 1; + ShowOptionNames = 0; + ShowCategories = 0; + Format = Clang; + ShowSourceRanges = 0; + ShowParseableFixits = 0; + VerifyDiagnostics = 0; + ErrorLimit = 0; + TemplateBacktraceLimit = DefaultTemplateBacktraceLimit; + MacroBacktraceLimit = DefaultMacroBacktraceLimit; + ConstexprBacktraceLimit = DefaultConstexprBacktraceLimit; + } +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Frontend/DiagnosticRenderer.h b/clang/include/clang/Frontend/DiagnosticRenderer.h new file mode 100644 index 0000000..5ad88a8 --- /dev/null +++ b/clang/include/clang/Frontend/DiagnosticRenderer.h @@ -0,0 +1,149 @@ +//===--- DiagnosticRenderer.h - Diagnostic Pretty-Printing ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This is a utility class that provides support for pretty-printing of +// diagnostics. It is used to implement the different code paths which require +// such functionality in a consistent way. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_DIAGNOSTIC_RENDERER_H_ +#define LLVM_CLANG_FRONTEND_DIAGNOSTIC_RENDERER_H_ + +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/PointerUnion.h" + +namespace clang { + +class DiagnosticOptions; +class LangOptions; +class SourceManager; + +typedef llvm::PointerUnion<const Diagnostic *, + const StoredDiagnostic *> DiagOrStoredDiag; + +/// \brief Class to encapsulate the logic for formatting a diagnostic message. +/// Actual "printing" logic is implemented by subclasses. +/// +/// This class provides an interface for building and emitting +/// diagnostic, including all of the macro backtraces, caret diagnostics, FixIt +/// Hints, and code snippets. In the presence of macros this involves +/// a recursive process, synthesizing notes for each macro expansion. +/// +/// A brief worklist: +/// FIXME: Sink the recursive printing of template instantiations into this +/// class. +class DiagnosticRenderer { +protected: + const SourceManager &SM; + const LangOptions &LangOpts; + const DiagnosticOptions &DiagOpts; + + /// \brief The location of the previous diagnostic if known. + /// + /// This will be invalid in cases where there is no (known) previous + /// diagnostic location, or that location itself is invalid or comes from + /// a different source manager than SM. + SourceLocation LastLoc; + + /// \brief The location of the last include whose stack was printed if known. + /// + /// Same restriction as \see LastLoc essentially, but tracking include stack + /// root locations rather than diagnostic locations. + SourceLocation LastIncludeLoc; + + /// \brief The level of the last diagnostic emitted. + /// + /// The level of the last diagnostic emitted. Used to detect level changes + /// which change the amount of information displayed. + DiagnosticsEngine::Level LastLevel; + + DiagnosticRenderer(const SourceManager &SM, + const LangOptions &LangOpts, + const DiagnosticOptions &DiagOpts); + + virtual ~DiagnosticRenderer(); + + virtual void emitDiagnosticMessage(SourceLocation Loc, PresumedLoc PLoc, + DiagnosticsEngine::Level Level, + StringRef Message, + ArrayRef<CharSourceRange> Ranges, + DiagOrStoredDiag Info) = 0; + + virtual void emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc, + DiagnosticsEngine::Level Level, + ArrayRef<CharSourceRange> Ranges) = 0; + + virtual void emitBasicNote(StringRef Message) = 0; + + virtual void emitCodeContext(SourceLocation Loc, + DiagnosticsEngine::Level Level, + SmallVectorImpl<CharSourceRange>& Ranges, + ArrayRef<FixItHint> Hints) = 0; + + virtual void emitIncludeLocation(SourceLocation Loc, PresumedLoc PLoc) = 0; + + virtual void beginDiagnostic(DiagOrStoredDiag D, + DiagnosticsEngine::Level Level) {} + virtual void endDiagnostic(DiagOrStoredDiag D, + DiagnosticsEngine::Level Level) {} + + +private: + void emitIncludeStack(SourceLocation Loc, DiagnosticsEngine::Level Level); + void emitIncludeStackRecursively(SourceLocation Loc); + void emitMacroExpansionsAndCarets(SourceLocation Loc, + DiagnosticsEngine::Level Level, + SmallVectorImpl<CharSourceRange>& Ranges, + ArrayRef<FixItHint> Hints, + unsigned &MacroDepth, + unsigned OnMacroInst = 0); +public: + /// \brief Emit a diagnostic. + /// + /// This is the primary entry point for emitting diagnostic messages. + /// It handles formatting and rendering the message as well as any ancillary + /// information needed based on macros whose expansions impact the + /// diagnostic. + /// + /// \param Loc The location for this caret. + /// \param Level The level of the diagnostic to be emitted. + /// \param Message The diagnostic message to emit. + /// \param Ranges The underlined ranges for this code snippet. + /// \param FixItHints The FixIt hints active for this diagnostic. + void emitDiagnostic(SourceLocation Loc, DiagnosticsEngine::Level Level, + StringRef Message, ArrayRef<CharSourceRange> Ranges, + ArrayRef<FixItHint> FixItHints, + DiagOrStoredDiag D = (Diagnostic *)0); + + void emitStoredDiagnostic(StoredDiagnostic &Diag); +}; + +/// Subclass of DiagnosticRender that turns all subdiagostics into explicit +/// notes. It is up to subclasses to further define the behavior. +class DiagnosticNoteRenderer : public DiagnosticRenderer { +public: + DiagnosticNoteRenderer(const SourceManager &SM, + const LangOptions &LangOpts, + const DiagnosticOptions &DiagOpts) + : DiagnosticRenderer(SM, LangOpts, DiagOpts) {} + + virtual ~DiagnosticNoteRenderer(); + + virtual void emitBasicNote(StringRef Message); + + virtual void emitIncludeLocation(SourceLocation Loc, + PresumedLoc PLoc); + + virtual void emitNote(SourceLocation Loc, StringRef Message) = 0; +}; +} // end clang namespace +#endif diff --git a/clang/include/clang/Frontend/FrontendAction.h b/clang/include/clang/Frontend/FrontendAction.h new file mode 100644 index 0000000..6839028 --- /dev/null +++ b/clang/include/clang/Frontend/FrontendAction.h @@ -0,0 +1,277 @@ +//===-- FrontendAction.h - Generic Frontend Action Interface ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_FRONTENDACTION_H +#define LLVM_CLANG_FRONTEND_FRONTENDACTION_H + +#include "clang/Basic/LLVM.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Frontend/FrontendOptions.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/OwningPtr.h" +#include <string> +#include <vector> + +namespace clang { +class ASTConsumer; +class ASTMergeAction; +class ASTUnit; +class CompilerInstance; + +/// FrontendAction - Abstract base class for actions which can be performed by +/// the frontend. +class FrontendAction { + FrontendInputFile CurrentInput; + OwningPtr<ASTUnit> CurrentASTUnit; + CompilerInstance *Instance; + friend class ASTMergeAction; + friend class WrapperFrontendAction; + +private: + ASTConsumer* CreateWrappedASTConsumer(CompilerInstance &CI, + StringRef InFile); + +protected: + /// @name Implementation Action Interface + /// @{ + + /// CreateASTConsumer - Create the AST consumer object for this action, if + /// supported. + /// + /// This routine is called as part of \see BeginSourceAction(), which will + /// fail if the AST consumer cannot be created. This will not be called if the + /// action has indicated that it only uses the preprocessor. + /// + /// \param CI - The current compiler instance, provided as a convenience, \see + /// getCompilerInstance(). + /// + /// \param InFile - The current input file, provided as a convenience, \see + /// getCurrentFile(). + /// + /// \return The new AST consumer, or 0 on failure. + virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) = 0; + + /// \brief Callback before starting processing a single input, giving the + /// opportunity to modify the CompilerInvocation or do some other action + /// before BeginSourceFileAction is called. + /// + /// \return True on success; on failure \see BeginSourceFileAction() and + /// ExecutionAction() and EndSourceFileAction() will not be called. + virtual bool BeginInvocation(CompilerInstance &CI) { return true; } + + /// BeginSourceFileAction - Callback at the start of processing a single + /// input. + /// + /// \return True on success; on failure \see ExecutionAction() and + /// EndSourceFileAction() will not be called. + virtual bool BeginSourceFileAction(CompilerInstance &CI, + StringRef Filename) { + return true; + } + + /// ExecuteAction - Callback to run the program action, using the initialized + /// compiler instance. + /// + /// This routine is guaranteed to only be called between \see + /// BeginSourceFileAction() and \see EndSourceFileAction(). + virtual void ExecuteAction() = 0; + + /// EndSourceFileAction - Callback at the end of processing a single input; + /// this is guaranteed to only be called following a successful call to + /// BeginSourceFileAction (and BeginSourceFile). + virtual void EndSourceFileAction() {} + + /// @} + +public: + FrontendAction(); + virtual ~FrontendAction(); + + /// @name Compiler Instance Access + /// @{ + + CompilerInstance &getCompilerInstance() const { + assert(Instance && "Compiler instance not registered!"); + return *Instance; + } + + void setCompilerInstance(CompilerInstance *Value) { Instance = Value; } + + /// @} + /// @name Current File Information + /// @{ + + bool isCurrentFileAST() const { + assert(!CurrentInput.File.empty() && "No current file!"); + return CurrentASTUnit != 0; + } + + const FrontendInputFile &getCurrentInput() const { + return CurrentInput; + } + + const std::string &getCurrentFile() const { + assert(!CurrentInput.File.empty() && "No current file!"); + return CurrentInput.File; + } + + InputKind getCurrentFileKind() const { + assert(!CurrentInput.File.empty() && "No current file!"); + return CurrentInput.Kind; + } + + ASTUnit &getCurrentASTUnit() const { + assert(CurrentASTUnit && "No current AST unit!"); + return *CurrentASTUnit; + } + + ASTUnit *takeCurrentASTUnit() { + return CurrentASTUnit.take(); + } + + void setCurrentInput(const FrontendInputFile &CurrentInput, ASTUnit *AST = 0); + + /// @} + /// @name Supported Modes + /// @{ + + /// usesPreprocessorOnly - Does this action only use the preprocessor? If so + /// no AST context will be created and this action will be invalid with AST + /// file inputs. + virtual bool usesPreprocessorOnly() const = 0; + + /// \brief For AST-based actions, the kind of translation unit we're handling. + virtual TranslationUnitKind getTranslationUnitKind() { return TU_Complete; } + + /// hasPCHSupport - Does this action support use with PCH? + virtual bool hasPCHSupport() const { return !usesPreprocessorOnly(); } + + /// hasASTFileSupport - Does this action support use with AST files? + virtual bool hasASTFileSupport() const { return !usesPreprocessorOnly(); } + + /// hasIRSupport - Does this action support use with IR files? + virtual bool hasIRSupport() const { return false; } + + /// hasCodeCompletionSupport - Does this action support use with code + /// completion? + virtual bool hasCodeCompletionSupport() const { return false; } + + /// @} + /// @name Public Action Interface + /// @{ + + /// BeginSourceFile - Prepare the action for processing the input file \arg + /// Filename; this is run after the options and frontend have been + /// initialized, but prior to executing any per-file processing. + /// + /// \param CI - The compiler instance this action is being run from. The + /// action may store and use this object up until the matching EndSourceFile + /// action. + /// + /// \param Input - The input filename and kind. Some input kinds are handled + /// specially, for example AST inputs, since the AST file itself contains + /// several objects which would normally be owned by the + /// CompilerInstance. When processing AST input files, these objects should + /// generally not be initialized in the CompilerInstance -- they will + /// automatically be shared with the AST file in between \see + /// BeginSourceFile() and \see EndSourceFile(). + /// + /// \return True on success; on failure the compilation of this file should + /// be aborted and neither Execute nor EndSourceFile should be called. + bool BeginSourceFile(CompilerInstance &CI, const FrontendInputFile &Input); + + /// Execute - Set the source managers main input file, and run the action. + void Execute(); + + /// EndSourceFile - Perform any per-file post processing, deallocate per-file + /// objects, and run statistics and output file cleanup code. + void EndSourceFile(); + + /// @} +}; + +/// ASTFrontendAction - Abstract base class to use for AST consumer based +/// frontend actions. +class ASTFrontendAction : public FrontendAction { +protected: + /// ExecuteAction - Implement the ExecuteAction interface by running Sema on + /// the already initialized AST consumer. + /// + /// This will also take care of instantiating a code completion consumer if + /// the user requested it and the action supports it. + virtual void ExecuteAction(); + +public: + virtual bool usesPreprocessorOnly() const { return false; } +}; + +class PluginASTAction : public ASTFrontendAction { + virtual void anchor(); +protected: + virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) = 0; + +public: + /// ParseArgs - Parse the given plugin command line arguments. + /// + /// \param CI - The compiler instance, for use in reporting diagnostics. + /// \return True if the parsing succeeded; otherwise the plugin will be + /// destroyed and no action run. The plugin is responsible for using the + /// CompilerInstance's Diagnostic object to report errors. + virtual bool ParseArgs(const CompilerInstance &CI, + const std::vector<std::string> &arg) = 0; +}; + +/// PreprocessorFrontendAction - Abstract base class to use for preprocessor +/// based frontend actions. +class PreprocessorFrontendAction : public FrontendAction { +protected: + /// CreateASTConsumer - Provide a default implementation which returns aborts, + /// this method should never be called by FrontendAction clients. + virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, + StringRef InFile); + +public: + virtual bool usesPreprocessorOnly() const { return true; } +}; + +/// WrapperFrontendAction - A frontend action which simply wraps some other +/// runtime specified frontend action. Deriving from this class allows an +/// action to inject custom logic around some existing action's behavior. It +/// implements every virtual method in the FrontendAction interface by +/// forwarding to the wrapped action. +class WrapperFrontendAction : public FrontendAction { + OwningPtr<FrontendAction> WrappedAction; + +protected: + virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, + StringRef InFile); + virtual bool BeginInvocation(CompilerInstance &CI); + virtual bool BeginSourceFileAction(CompilerInstance &CI, + StringRef Filename); + virtual void ExecuteAction(); + virtual void EndSourceFileAction(); + +public: + /// Construct a WrapperFrontendAction from an existing action, taking + /// ownership of it. + WrapperFrontendAction(FrontendAction *WrappedAction); + + virtual bool usesPreprocessorOnly() const; + virtual TranslationUnitKind getTranslationUnitKind(); + virtual bool hasPCHSupport() const; + virtual bool hasASTFileSupport() const; + virtual bool hasIRSupport() const; + virtual bool hasCodeCompletionSupport() const; +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Frontend/FrontendActions.h b/clang/include/clang/Frontend/FrontendActions.h new file mode 100644 index 0000000..8f7fe87 --- /dev/null +++ b/clang/include/clang/Frontend/FrontendActions.h @@ -0,0 +1,209 @@ +//===-- FrontendActions.h - Useful Frontend Actions -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_FRONTENDACTIONS_H +#define LLVM_CLANG_FRONTEND_FRONTENDACTIONS_H + +#include "clang/Frontend/FrontendAction.h" +#include <string> +#include <vector> + +namespace clang { + +class Module; + +//===----------------------------------------------------------------------===// +// Custom Consumer Actions +//===----------------------------------------------------------------------===// + +class InitOnlyAction : public FrontendAction { + virtual void ExecuteAction(); + + virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, + StringRef InFile); + +public: + // Don't claim to only use the preprocessor, we want to follow the AST path, + // but do nothing. + virtual bool usesPreprocessorOnly() const { return false; } +}; + +//===----------------------------------------------------------------------===// +// AST Consumer Actions +//===----------------------------------------------------------------------===// + +class ASTPrintAction : public ASTFrontendAction { +protected: + virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, + StringRef InFile); +}; + +class ASTDumpAction : public ASTFrontendAction { +protected: + virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, + StringRef InFile); +}; + +class ASTDumpXMLAction : public ASTFrontendAction { +protected: + virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, + StringRef InFile); +}; + +class ASTViewAction : public ASTFrontendAction { +protected: + virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, + StringRef InFile); +}; + +class DeclContextPrintAction : public ASTFrontendAction { +protected: + virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, + StringRef InFile); +}; + +class GeneratePCHAction : public ASTFrontendAction { +protected: + virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, + StringRef InFile); + + virtual TranslationUnitKind getTranslationUnitKind() { + return TU_Prefix; + } + + virtual bool hasASTFileSupport() const { return false; } + +public: + /// \brief Compute the AST consumer arguments that will be used to + /// create the PCHGenerator instance returned by CreateASTConsumer. + /// + /// \returns true if an error occurred, false otherwise. + static bool ComputeASTConsumerArguments(CompilerInstance &CI, + StringRef InFile, + std::string &Sysroot, + std::string &OutputFile, + raw_ostream *&OS); +}; + +class GenerateModuleAction : public ASTFrontendAction { + clang::Module *Module; + +protected: + virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, + StringRef InFile); + + virtual TranslationUnitKind getTranslationUnitKind() { + return TU_Module; + } + + virtual bool hasASTFileSupport() const { return false; } + +public: + virtual bool BeginSourceFileAction(CompilerInstance &CI, StringRef Filename); + + /// \brief Compute the AST consumer arguments that will be used to + /// create the PCHGenerator instance returned by CreateASTConsumer. + /// + /// \returns true if an error occurred, false otherwise. + static bool ComputeASTConsumerArguments(CompilerInstance &CI, + StringRef InFile, + std::string &Sysroot, + std::string &OutputFile, + raw_ostream *&OS); +}; + +class SyntaxOnlyAction : public ASTFrontendAction { +protected: + virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, + StringRef InFile); + +public: + virtual bool hasCodeCompletionSupport() const { return true; } +}; + +/** + * \brief Frontend action adaptor that merges ASTs together. + * + * This action takes an existing AST file and "merges" it into the AST + * context, producing a merged context. This action is an action + * adaptor, which forwards most of its calls to another action that + * will consume the merged context. + */ +class ASTMergeAction : public FrontendAction { + /// \brief The action that the merge action adapts. + FrontendAction *AdaptedAction; + + /// \brief The set of AST files to merge. + std::vector<std::string> ASTFiles; + +protected: + virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, + StringRef InFile); + + virtual bool BeginSourceFileAction(CompilerInstance &CI, + StringRef Filename); + + virtual void ExecuteAction(); + virtual void EndSourceFileAction(); + +public: + ASTMergeAction(FrontendAction *AdaptedAction, ArrayRef<std::string> ASTFiles); + virtual ~ASTMergeAction(); + + virtual bool usesPreprocessorOnly() const; + virtual TranslationUnitKind getTranslationUnitKind(); + virtual bool hasPCHSupport() const; + virtual bool hasASTFileSupport() const; + virtual bool hasCodeCompletionSupport() const; +}; + +class PrintPreambleAction : public FrontendAction { +protected: + void ExecuteAction(); + virtual ASTConsumer *CreateASTConsumer(CompilerInstance &, StringRef) { + return 0; + } + + virtual bool usesPreprocessorOnly() const { return true; } +}; + +//===----------------------------------------------------------------------===// +// Preprocessor Actions +//===----------------------------------------------------------------------===// + +class DumpRawTokensAction : public PreprocessorFrontendAction { +protected: + void ExecuteAction(); +}; + +class DumpTokensAction : public PreprocessorFrontendAction { +protected: + void ExecuteAction(); +}; + +class GeneratePTHAction : public PreprocessorFrontendAction { +protected: + void ExecuteAction(); +}; + +class PreprocessOnlyAction : public PreprocessorFrontendAction { +protected: + void ExecuteAction(); +}; + +class PrintPreprocessedAction : public PreprocessorFrontendAction { +protected: + void ExecuteAction(); + + virtual bool hasPCHSupport() const { return true; } +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Frontend/FrontendDiagnostic.h b/clang/include/clang/Frontend/FrontendDiagnostic.h new file mode 100644 index 0000000..0b05b74 --- /dev/null +++ b/clang/include/clang/Frontend/FrontendDiagnostic.h @@ -0,0 +1,28 @@ +//===--- DiagnosticFrontend.h - Diagnostics for frontend --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTENDDIAGNOSTIC_H +#define LLVM_CLANG_FRONTENDDIAGNOSTIC_H + +#include "clang/Basic/Diagnostic.h" + +namespace clang { + namespace diag { + enum { +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\ + SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM, +#define FRONTENDSTART +#include "clang/Basic/DiagnosticFrontendKinds.inc" +#undef DIAG + NUM_BUILTIN_FRONTEND_DIAGNOSTICS + }; + } // end namespace diag +} // end namespace clang + +#endif diff --git a/clang/include/clang/Frontend/FrontendOptions.h b/clang/include/clang/Frontend/FrontendOptions.h new file mode 100644 index 0000000..888388c --- /dev/null +++ b/clang/include/clang/Frontend/FrontendOptions.h @@ -0,0 +1,208 @@ +//===--- FrontendOptions.h --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_FRONTENDOPTIONS_H +#define LLVM_CLANG_FRONTEND_FRONTENDOPTIONS_H + +#include "clang/Frontend/CommandLineSourceLoc.h" +#include "llvm/ADT/StringRef.h" +#include <string> +#include <vector> + +namespace clang { + +namespace frontend { + enum ActionKind { + ASTDump, ///< Parse ASTs and dump them. + ASTDumpXML, ///< Parse ASTs and dump them in XML. + ASTPrint, ///< Parse ASTs and print them. + ASTView, ///< Parse ASTs and view them in Graphviz. + DumpRawTokens, ///< Dump out raw tokens. + DumpTokens, ///< Dump out preprocessed tokens. + EmitAssembly, ///< Emit a .s file. + EmitBC, ///< Emit a .bc file. + EmitHTML, ///< Translate input source into HTML. + EmitLLVM, ///< Emit a .ll file. + EmitLLVMOnly, ///< Generate LLVM IR, but do not emit anything. + EmitCodeGenOnly, ///< Generate machine code, but don't emit anything. + EmitObj, ///< Emit a .o file. + FixIt, ///< Parse and apply any fixits to the source. + GenerateModule, ///< Generate pre-compiled module. + GeneratePCH, ///< Generate pre-compiled header. + GeneratePTH, ///< Generate pre-tokenized header. + InitOnly, ///< Only execute frontend initialization. + ParseSyntaxOnly, ///< Parse and perform semantic analysis. + PluginAction, ///< Run a plugin action, \see ActionName. + PrintDeclContext, ///< Print DeclContext and their Decls. + PrintPreamble, ///< Print the "preamble" of the input file + PrintPreprocessedInput, ///< -E mode. + RewriteMacros, ///< Expand macros but not #includes. + RewriteObjC, ///< ObjC->C Rewriter. + RewriteTest, ///< Rewriter playground + RunAnalysis, ///< Run one or more source code analyses. + MigrateSource, ///< Run migrator. + RunPreprocessorOnly ///< Just lex, no output. + }; +} + +enum InputKind { + IK_None, + IK_Asm, + IK_C, + IK_CXX, + IK_ObjC, + IK_ObjCXX, + IK_PreprocessedC, + IK_PreprocessedCXX, + IK_PreprocessedObjC, + IK_PreprocessedObjCXX, + IK_OpenCL, + IK_CUDA, + IK_AST, + IK_LLVM_IR +}; + + +/// \brief An input file for the front end. +struct FrontendInputFile { + /// \brief The file name, or "-" to read from standard input. + std::string File; + + /// \brief The kind of input, e.g., C source, AST file, LLVM IR. + InputKind Kind; + + /// \brief Whether we're dealing with a 'system' input (vs. a 'user' input). + bool IsSystem; + + FrontendInputFile() : Kind(IK_None) { } + FrontendInputFile(StringRef File, InputKind Kind, bool IsSystem = false) + : File(File.str()), Kind(Kind), IsSystem(IsSystem) { } +}; + +/// FrontendOptions - Options for controlling the behavior of the frontend. +class FrontendOptions { +public: + unsigned DisableFree : 1; ///< Disable memory freeing on exit. + unsigned RelocatablePCH : 1; ///< When generating PCH files, + /// instruct the AST writer to create + /// relocatable PCH files. + unsigned ShowHelp : 1; ///< Show the -help text. + unsigned ShowMacrosInCodeCompletion : 1; ///< Show macros in code completion + /// results. + unsigned ShowCodePatternsInCodeCompletion : 1; ///< Show code patterns in code + /// completion results. + unsigned ShowGlobalSymbolsInCodeCompletion : 1; ///< Show top-level decls in + /// code completion results. + unsigned ShowStats : 1; ///< Show frontend performance + /// metrics and statistics. + unsigned ShowTimers : 1; ///< Show timers for individual + /// actions. + unsigned ShowVersion : 1; ///< Show the -version text. + unsigned FixWhatYouCan : 1; ///< Apply fixes even if there are + /// unfixable errors. + unsigned FixOnlyWarnings : 1; ///< Apply fixes only for warnings. + unsigned FixAndRecompile : 1; ///< Apply fixes and recompile. + unsigned FixToTemporaries : 1; ///< Apply fixes to temporary files. + unsigned ARCMTMigrateEmitARCErrors : 1; /// Emit ARC errors even if the + /// migrator can fix them + unsigned SkipFunctionBodies : 1; ///< Skip over function bodies to + /// speed up parsing in cases you do + /// not need them (e.g. with code + /// completion). + + enum { + ARCMT_None, + ARCMT_Check, + ARCMT_Modify, + ARCMT_Migrate + } ARCMTAction; + + enum { + ObjCMT_None = 0, + /// \brief Enable migration to modern ObjC literals. + ObjCMT_Literals = 0x1, + /// \brief Enable migration to modern ObjC subscripting. + ObjCMT_Subscripting = 0x2 + }; + unsigned ObjCMTAction; + + std::string MTMigrateDir; + std::string ARCMTMigrateReportOut; + + /// The input files and their types. + std::vector<FrontendInputFile> Inputs; + + /// The output file, if any. + std::string OutputFile; + + /// If given, the new suffix for fix-it rewritten files. + std::string FixItSuffix; + + /// If given, enable code completion at the provided location. + ParsedSourceLocation CodeCompletionAt; + + /// The frontend action to perform. + frontend::ActionKind ProgramAction; + + /// The name of the action to run when using a plugin action. + std::string ActionName; + + /// Args to pass to the plugin + std::vector<std::string> PluginArgs; + + /// The list of plugin actions to run in addition to the normal action. + std::vector<std::string> AddPluginActions; + + /// Args to pass to the additional plugins + std::vector<std::vector<std::string> > AddPluginArgs; + + /// The list of plugins to load. + std::vector<std::string> Plugins; + + /// \brief The list of AST files to merge. + std::vector<std::string> ASTMergeFiles; + + /// \brief A list of arguments to forward to LLVM's option processing; this + /// should only be used for debugging and experimental features. + std::vector<std::string> LLVMArgs; + + /// \brief File name of the file that will provide record layouts + /// (in the format produced by -fdump-record-layouts). + std::string OverrideRecordLayoutsFile; + +public: + FrontendOptions() { + DisableFree = 0; + ProgramAction = frontend::ParseSyntaxOnly; + ActionName = ""; + RelocatablePCH = 0; + ShowHelp = 0; + ShowMacrosInCodeCompletion = 0; + ShowCodePatternsInCodeCompletion = 0; + ShowGlobalSymbolsInCodeCompletion = 1; + ShowStats = 0; + ShowTimers = 0; + ShowVersion = 0; + ARCMTAction = ARCMT_None; + ARCMTMigrateEmitARCErrors = 0; + SkipFunctionBodies = 0; + ObjCMTAction = ObjCMT_None; + } + + /// getInputKindForExtension - Return the appropriate input kind for a file + /// extension. For example, "c" would return IK_C. + /// + /// \return The input kind for the extension, or IK_None if the extension is + /// not recognized. + static InputKind getInputKindForExtension(StringRef Extension); +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Frontend/FrontendPluginRegistry.h b/clang/include/clang/Frontend/FrontendPluginRegistry.h new file mode 100644 index 0000000..ec925ad --- /dev/null +++ b/clang/include/clang/Frontend/FrontendPluginRegistry.h @@ -0,0 +1,23 @@ +//===-- FrontendAction.h - Pluggable Frontend Action Interface --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_PLUGINFRONTENDACTION_H +#define LLVM_CLANG_FRONTEND_PLUGINFRONTENDACTION_H + +#include "clang/Frontend/FrontendAction.h" +#include "llvm/Support/Registry.h" + +namespace clang { + +/// The frontend plugin registry. +typedef llvm::Registry<PluginASTAction> FrontendPluginRegistry; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Frontend/HeaderSearchOptions.h b/clang/include/clang/Frontend/HeaderSearchOptions.h new file mode 100644 index 0000000..687f439 --- /dev/null +++ b/clang/include/clang/Frontend/HeaderSearchOptions.h @@ -0,0 +1,124 @@ +//===--- HeaderSearchOptions.h ----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_HEADERSEARCHOPTIONS_H +#define LLVM_CLANG_FRONTEND_HEADERSEARCHOPTIONS_H + +#include "llvm/ADT/StringRef.h" +#include <vector> + +namespace clang { + +namespace frontend { + /// IncludeDirGroup - Identifiers the group a include entry belongs to, which + /// represents its relative positive in the search list. A #include of a "" + /// path starts at the -iquote group, then searches the Angled group, then + /// searches the system group, etc. + enum IncludeDirGroup { + Quoted = 0, ///< '#include ""' paths, added by'gcc -iquote'. + Angled, ///< Paths for '#include <>' added by '-I'. + IndexHeaderMap, ///< Like Angled, but marks header maps used when + /// building frameworks. + System, ///< Like Angled, but marks system directories. + CSystem, ///< Like System, but only used for C. + CXXSystem, ///< Like System, but only used for C++. + ObjCSystem, ///< Like System, but only used for ObjC. + ObjCXXSystem, ///< Like System, but only used for ObjC++. + After ///< Like System, but searched after the system directories. + }; +} + +/// HeaderSearchOptions - Helper class for storing options related to the +/// initialization of the HeaderSearch object. +class HeaderSearchOptions { +public: + struct Entry { + std::string Path; + frontend::IncludeDirGroup Group; + unsigned IsUserSupplied : 1; + unsigned IsFramework : 1; + + /// IgnoreSysRoot - This is false if an absolute path should be treated + /// relative to the sysroot, or true if it should always be the absolute + /// path. + unsigned IgnoreSysRoot : 1; + + /// \brief True if this entry is an internal search path. + /// + /// This typically indicates that users didn't directly provide it, but + /// instead it was provided by a compatibility layer for a particular + /// system. This isn't redundant with IsUserSupplied (even though perhaps + /// it should be) because that is false for user provided '-iwithprefix' + /// header search entries. + unsigned IsInternal : 1; + + /// \brief True if this entry's headers should be wrapped in extern "C". + unsigned ImplicitExternC : 1; + + Entry(StringRef path, frontend::IncludeDirGroup group, + bool isUserSupplied, bool isFramework, bool ignoreSysRoot, + bool isInternal, bool implicitExternC) + : Path(path), Group(group), IsUserSupplied(isUserSupplied), + IsFramework(isFramework), IgnoreSysRoot(ignoreSysRoot), + IsInternal(isInternal), ImplicitExternC(implicitExternC) {} + }; + + /// If non-empty, the directory to use as a "virtual system root" for include + /// paths. + std::string Sysroot; + + /// User specified include entries. + std::vector<Entry> UserEntries; + + /// The directory which holds the compiler resource files (builtin includes, + /// etc.). + std::string ResourceDir; + + /// \brief The directory used for the module cache. + std::string ModuleCachePath; + + /// \brief Whether we should disable the use of the hash string within the + /// module cache. + /// + /// Note: Only used for testing! + unsigned DisableModuleHash : 1; + + /// Include the compiler builtin includes. + unsigned UseBuiltinIncludes : 1; + + /// Include the system standard include search directories. + unsigned UseStandardSystemIncludes : 1; + + /// Include the system standard C++ library include search directories. + unsigned UseStandardCXXIncludes : 1; + + /// Use libc++ instead of the default libstdc++. + unsigned UseLibcxx : 1; + + /// Whether header search information should be output as for -v. + unsigned Verbose : 1; + +public: + HeaderSearchOptions(StringRef _Sysroot = "/") + : Sysroot(_Sysroot), DisableModuleHash(0), UseBuiltinIncludes(true), + UseStandardSystemIncludes(true), UseStandardCXXIncludes(true), + UseLibcxx(false), Verbose(false) {} + + /// AddPath - Add the \arg Path path to the specified \arg Group list. + void AddPath(StringRef Path, frontend::IncludeDirGroup Group, + bool IsUserSupplied, bool IsFramework, bool IgnoreSysRoot, + bool IsInternal = false, bool ImplicitExternC = false) { + UserEntries.push_back(Entry(Path, Group, IsUserSupplied, IsFramework, + IgnoreSysRoot, IsInternal, ImplicitExternC)); + } +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Frontend/LangStandard.h b/clang/include/clang/Frontend/LangStandard.h new file mode 100644 index 0000000..e6f4403 --- /dev/null +++ b/clang/include/clang/Frontend/LangStandard.h @@ -0,0 +1,92 @@ +//===--- LangStandard.h -----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_LANGSTANDARD_H +#define LLVM_CLANG_FRONTEND_LANGSTANDARD_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/StringRef.h" + +namespace clang { + +namespace frontend { + +enum LangFeatures { + BCPLComment = (1 << 0), + C89 = (1 << 1), + C99 = (1 << 2), + C11 = (1 << 3), + CPlusPlus = (1 << 4), + CPlusPlus0x = (1 << 5), + Digraphs = (1 << 6), + GNUMode = (1 << 7), + HexFloat = (1 << 8), + ImplicitInt = (1 << 9) +}; + +} + +/// LangStandard - Information about the properties of a particular language +/// standard. +struct LangStandard { + enum Kind { +#define LANGSTANDARD(id, name, desc, features) \ + lang_##id, +#include "clang/Frontend/LangStandards.def" + lang_unspecified + }; + + const char *ShortName; + const char *Description; + unsigned Flags; + +public: + /// getName - Get the name of this standard. + const char *getName() const { return ShortName; } + + /// getDescription - Get the description of this standard. + const char *getDescription() const { return Description; } + + /// hasBCPLComments - Language supports '//' comments. + bool hasBCPLComments() const { return Flags & frontend::BCPLComment; } + + /// isC89 - Language is a superset of C89. + bool isC89() const { return Flags & frontend::C89; } + + /// isC99 - Language is a superset of C99. + bool isC99() const { return Flags & frontend::C99; } + + /// isC11 - Language is a superset of C11. + bool isC11() const { return Flags & frontend::C11; } + + /// isCPlusPlus - Language is a C++ variant. + bool isCPlusPlus() const { return Flags & frontend::CPlusPlus; } + + /// isCPlusPlus0x - Language is a C++0x variant. + bool isCPlusPlus0x() const { return Flags & frontend::CPlusPlus0x; } + + /// hasDigraphs - Language supports digraphs. + bool hasDigraphs() const { return Flags & frontend::Digraphs; } + + /// isGNUMode - Language includes GNU extensions. + bool isGNUMode() const { return Flags & frontend::GNUMode; } + + /// hasHexFloats - Language supports hexadecimal float constants. + bool hasHexFloats() const { return Flags & frontend::HexFloat; } + + /// hasImplicitInt - Language allows variables to be typed as int implicitly. + bool hasImplicitInt() const { return Flags & frontend::ImplicitInt; } + + static const LangStandard &getLangStandardForKind(Kind K); + static const LangStandard *getLangStandardForName(StringRef Name); +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Frontend/LangStandards.def b/clang/include/clang/Frontend/LangStandards.def new file mode 100644 index 0000000..4bcff4a --- /dev/null +++ b/clang/include/clang/Frontend/LangStandards.def @@ -0,0 +1,120 @@ +//===-- LangStandards.def - Language Standard Data --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LANGSTANDARD +#error "LANGSTANDARD must be defined before including this file" +#endif + +/// LANGSTANDARD(IDENT, NAME, DESC, FEATURES) +/// +/// \param IDENT - The name of the standard as a C++ identifier. +/// \param NAME - The name of the standard. +/// \param DESC - A short description of the standard. +/// \param FEATURES - The standard features as flags, these are enums from the +/// clang::frontend namespace, which is assumed to be be available. + +// C89-ish modes. +LANGSTANDARD(c89, "c89", + "ISO C 1990", + C89 | ImplicitInt) +LANGSTANDARD(c90, "c90", + "ISO C 1990", + C89 | ImplicitInt) +LANGSTANDARD(iso9899_1990, "iso9899:1990", + "ISO C 1990", + C89 | ImplicitInt) + +LANGSTANDARD(c94, "iso9899:199409", + "ISO C 1990 with amendment 1", + C89 | Digraphs | ImplicitInt) + +LANGSTANDARD(gnu89, "gnu89", + "ISO C 1990 with GNU extensions", + BCPLComment | C89 | Digraphs | GNUMode | ImplicitInt) +LANGSTANDARD(gnu90, "gnu90", + "ISO C 1990 with GNU extensions", + BCPLComment | C89 | Digraphs | GNUMode | ImplicitInt) + +// C99-ish modes +LANGSTANDARD(c99, "c99", + "ISO C 1999", + BCPLComment | C99 | Digraphs | HexFloat) +LANGSTANDARD(c9x, "c9x", + "ISO C 1999", + BCPLComment | C99 | Digraphs | HexFloat) +LANGSTANDARD(iso9899_1999, + "iso9899:1999", "ISO C 1999", + BCPLComment | C99 | Digraphs | HexFloat) +LANGSTANDARD(iso9899_199x, + "iso9899:199x", "ISO C 1999", + BCPLComment | C99 | Digraphs | HexFloat) + +LANGSTANDARD(gnu99, "gnu99", + "ISO C 1999 with GNU extensions", + BCPLComment | C99 | Digraphs | GNUMode | HexFloat) +LANGSTANDARD(gnu9x, "gnu9x", + "ISO C 1999 with GNU extensions", + BCPLComment | C99 | Digraphs | GNUMode | HexFloat) + +// C11 modes +LANGSTANDARD(c11, "c11", + "ISO C 2011", + BCPLComment | C99 | C11 | Digraphs | HexFloat) +LANGSTANDARD(c1x, "c1x", + "ISO C 2011", + BCPLComment | C99 | C11 | Digraphs | HexFloat) +LANGSTANDARD(iso9899_2011, + "iso9899:2011", "ISO C 2011", + BCPLComment | C99 | C11 | Digraphs | HexFloat) +LANGSTANDARD(iso9899_201x, + "iso9899:2011", "ISO C 2011", + BCPLComment | C99 | C11 | Digraphs | HexFloat) + +LANGSTANDARD(gnu11, "gnu11", + "ISO C 2011 with GNU extensions", + BCPLComment | C99 | C11 | Digraphs | GNUMode | HexFloat) +LANGSTANDARD(gnu1x, "gnu1x", + "ISO C 2011 with GNU extensions", + BCPLComment | C99 | C11 | Digraphs | GNUMode | HexFloat) + +// C++ modes +LANGSTANDARD(cxx98, "c++98", + "ISO C++ 1998 with amendments", + BCPLComment | CPlusPlus | Digraphs) +LANGSTANDARD(cxx03, "c++03", + "ISO C++ 1998 with amendments", + BCPLComment | CPlusPlus | Digraphs) +LANGSTANDARD(gnucxx98, "gnu++98", + "ISO C++ 1998 with amendments and GNU extensions", + BCPLComment | CPlusPlus | Digraphs | GNUMode) + +LANGSTANDARD(cxx0x, "c++0x", + "ISO C++ 2011 with amendments", + BCPLComment | CPlusPlus | CPlusPlus0x | Digraphs) +LANGSTANDARD(cxx11, "c++11", + "ISO C++ 2011 with amendments", + BCPLComment | CPlusPlus | CPlusPlus0x | Digraphs) +LANGSTANDARD(gnucxx0x, "gnu++0x", + "ISO C++ 2011 with amendments and GNU extensions", + BCPLComment | CPlusPlus | CPlusPlus0x | Digraphs | GNUMode) +LANGSTANDARD(gnucxx11, "gnu++11", + "ISO C++ 2011 with amendments and GNU extensions", + BCPLComment | CPlusPlus | CPlusPlus0x | Digraphs | GNUMode) + +// OpenCL +LANGSTANDARD(opencl, "cl", + "OpenCL 1.0", + BCPLComment | C99 | Digraphs | HexFloat) + +// CUDA +LANGSTANDARD(cuda, "cuda", + "NVIDIA CUDA(tm)", + BCPLComment | CPlusPlus | Digraphs) + +#undef LANGSTANDARD diff --git a/clang/include/clang/Frontend/LayoutOverrideSource.h b/clang/include/clang/Frontend/LayoutOverrideSource.h new file mode 100644 index 0000000..225efe6 --- /dev/null +++ b/clang/include/clang/Frontend/LayoutOverrideSource.h @@ -0,0 +1,61 @@ +//===--- LayoutOverrideSource.h --Override Record Layouts -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_LAYOUTOVERRIDESOURCE_H +#define LLVM_CLANG_FRONTEND_LAYOUTOVERRIDESOURCE_H + +#include "clang/AST/ExternalASTSource.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" + +namespace clang { + /// \brief An external AST source that overrides the layout of + /// a specified set of record types. + /// + /// This class is used only for testing the ability of external AST sources + /// to override the layout of record types. Its input is the output format + /// of the command-line argument -fdump-record-layouts. + class LayoutOverrideSource : public ExternalASTSource { + /// \brief The layout of a given record. + struct Layout { + /// \brief The size of the record. + uint64_t Size; + + /// \brief The alignment of the record. + uint64_t Align; + + /// \brief The offsets of the fields, in source order. + llvm::SmallVector<uint64_t, 8> FieldOffsets; + }; + + /// \brief The set of layouts that will be overridden. + llvm::StringMap<Layout> Layouts; + + public: + /// \brief Create a new AST source that overrides the layout of some + /// set of record types. + /// + /// The file is the result of passing -fdump-record-layouts to a file. + explicit LayoutOverrideSource(llvm::StringRef Filename); + + /// \brief If this particular record type has an overridden layout, + /// return that layout. + virtual bool + layoutRecordType(const RecordDecl *Record, + uint64_t &Size, uint64_t &Alignment, + llvm::DenseMap<const FieldDecl *, uint64_t> &FieldOffsets, + llvm::DenseMap<const CXXRecordDecl *, CharUnits> &BaseOffsets, + llvm::DenseMap<const CXXRecordDecl *, CharUnits> &VirtualBaseOffsets); + + /// \brief Dump the overridden layouts. + void dump(); + }; +} + +#endif diff --git a/clang/include/clang/Frontend/LogDiagnosticPrinter.h b/clang/include/clang/Frontend/LogDiagnosticPrinter.h new file mode 100644 index 0000000..4de15f2 --- /dev/null +++ b/clang/include/clang/Frontend/LogDiagnosticPrinter.h @@ -0,0 +1,79 @@ +//===--- LogDiagnosticPrinter.h - Log Diagnostic Client ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_LOG_DIAGNOSTIC_PRINTER_H_ +#define LLVM_CLANG_FRONTEND_LOG_DIAGNOSTIC_PRINTER_H_ + +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/SmallVector.h" + +namespace clang { +class DiagnosticOptions; +class LangOptions; + +class LogDiagnosticPrinter : public DiagnosticConsumer { + struct DiagEntry { + /// The primary message line of the diagnostic. + std::string Message; + + /// The source file name, if available. + std::string Filename; + + /// The source file line number, if available. + unsigned Line; + + /// The source file column number, if available. + unsigned Column; + + /// The ID of the diagnostic. + unsigned DiagnosticID; + + /// The level of the diagnostic. + DiagnosticsEngine::Level DiagnosticLevel; + }; + + raw_ostream &OS; + const LangOptions *LangOpts; + const DiagnosticOptions *DiagOpts; + + SourceLocation LastWarningLoc; + FullSourceLoc LastLoc; + unsigned OwnsOutputStream : 1; + + SmallVector<DiagEntry, 8> Entries; + + std::string MainFilename; + std::string DwarfDebugFlags; + +public: + LogDiagnosticPrinter(raw_ostream &OS, const DiagnosticOptions &Diags, + bool OwnsOutputStream = false); + virtual ~LogDiagnosticPrinter(); + + void setDwarfDebugFlags(StringRef Value) { + DwarfDebugFlags = Value; + } + + void BeginSourceFile(const LangOptions &LO, const Preprocessor *PP) { + LangOpts = &LO; + } + + void EndSourceFile(); + + virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, + const Diagnostic &Info); + + DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const; +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Frontend/MigratorOptions.h b/clang/include/clang/Frontend/MigratorOptions.h new file mode 100644 index 0000000..f9554e4 --- /dev/null +++ b/clang/include/clang/Frontend/MigratorOptions.h @@ -0,0 +1,31 @@ +//===--- MigratorOptions.h - MigratorOptions Options ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header contains the structures necessary for a front-end to specify +// various migration analysis. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_MIGRATOROPTIONS +#define LLVM_CLANG_FRONTEND_MIGRATOROPTIONS + +namespace clang { + +class MigratorOptions { +public: + unsigned NoNSAllocReallocError : 1; + unsigned NoFinalizeRemoval : 1; + MigratorOptions() { + NoNSAllocReallocError = 0; + NoFinalizeRemoval = 0; + } +}; + +} +#endif diff --git a/clang/include/clang/Frontend/MultiplexConsumer.h b/clang/include/clang/Frontend/MultiplexConsumer.h new file mode 100644 index 0000000..ffa7b4a --- /dev/null +++ b/clang/include/clang/Frontend/MultiplexConsumer.h @@ -0,0 +1,64 @@ +//===-- MultiplexConsumer.h - AST Consumer for PCH Generation ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the MultiplexConsumer class, which can be used to +// multiplex ASTConsumer and SemaConsumer messages to many consumers. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_FRONTEND_MULTIPLEXCONSUMER_H +#define CLANG_FRONTEND_MULTIPLEXCONSUMER_H + +#include "clang/Basic/LLVM.h" +#include "clang/Sema/SemaConsumer.h" +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/OwningPtr.h" +#include <vector> + +namespace clang { + +class MultiplexASTMutationListener; +class MultiplexASTDeserializationListener; + +// Has a list of ASTConsumers and calls each of them. Owns its children. +class MultiplexConsumer : public SemaConsumer { +public: + // Takes ownership of the pointers in C. + MultiplexConsumer(ArrayRef<ASTConsumer*> C); + ~MultiplexConsumer(); + + // ASTConsumer + virtual void Initialize(ASTContext &Context); + virtual void HandleCXXStaticMemberVarInstantiation(VarDecl *VD); + virtual bool HandleTopLevelDecl(DeclGroupRef D); + virtual void HandleInterestingDecl(DeclGroupRef D); + virtual void HandleTranslationUnit(ASTContext &Ctx); + virtual void HandleTagDeclDefinition(TagDecl *D); + virtual void HandleCXXImplicitFunctionInstantiation(FunctionDecl *D); + virtual void HandleTopLevelDeclInObjCContainer(DeclGroupRef D); + virtual void CompleteTentativeDefinition(VarDecl *D); + virtual void HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired); + virtual ASTMutationListener *GetASTMutationListener(); + virtual ASTDeserializationListener *GetASTDeserializationListener(); + virtual void PrintStats(); + + // SemaConsumer + virtual void InitializeSema(Sema &S); + virtual void ForgetSema(); + + static bool classof(const MultiplexConsumer *) { return true; } +private: + std::vector<ASTConsumer*> Consumers; // Owns these. + OwningPtr<MultiplexASTMutationListener> MutationListener; + OwningPtr<MultiplexASTDeserializationListener> DeserializationListener; +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Frontend/PreprocessorOptions.h b/clang/include/clang/Frontend/PreprocessorOptions.h new file mode 100644 index 0000000..d86a923 --- /dev/null +++ b/clang/include/clang/Frontend/PreprocessorOptions.h @@ -0,0 +1,224 @@ +//===--- PreprocessorOptions.h ----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_PREPROCESSOROPTIONS_H_ +#define LLVM_CLANG_FRONTEND_PREPROCESSOROPTIONS_H_ + +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include <cassert> +#include <string> +#include <utility> +#include <vector> +#include <set> + +namespace llvm { + class MemoryBuffer; +} + +namespace clang { + +class Preprocessor; +class LangOptions; + +/// \brief Enumerate the kinds of standard library that +enum ObjCXXARCStandardLibraryKind { + ARCXX_nolib, + /// \brief libc++ + ARCXX_libcxx, + /// \brief libstdc++ + ARCXX_libstdcxx +}; + +/// PreprocessorOptions - This class is used for passing the various options +/// used in preprocessor initialization to InitializePreprocessor(). +class PreprocessorOptions { +public: + std::vector<std::pair<std::string, bool/*isUndef*/> > Macros; + std::vector<std::string> Includes; + std::vector<std::string> MacroIncludes; + + unsigned UsePredefines : 1; /// Initialize the preprocessor with the compiler + /// and target specific predefines. + + unsigned DetailedRecord : 1; /// Whether we should maintain a detailed + /// record of all macro definitions and + /// expansions. + unsigned DetailedRecordConditionalDirectives : 1; /// Whether in the + /// preprocessing record we should also keep + /// track of locations of conditional directives + /// in non-system files. + + /// The implicit PCH included at the start of the translation unit, or empty. + std::string ImplicitPCHInclude; + + /// \brief Headers that will be converted to chained PCHs in memory. + std::vector<std::string> ChainedIncludes; + + /// \brief When true, disables most of the normal validation performed on + /// precompiled headers. + bool DisablePCHValidation; + + /// \brief When true, disables the use of the stat cache within a + /// precompiled header or AST file. + bool DisableStatCache; + + /// \brief When true, a PCH with compiler errors will not be rejected. + bool AllowPCHWithCompilerErrors; + + /// \brief Dump declarations that are deserialized from PCH, for testing. + bool DumpDeserializedPCHDecls; + + /// \brief This is a set of names for decls that we do not want to be + /// deserialized, and we emit an error if they are; for testing purposes. + std::set<std::string> DeserializedPCHDeclsToErrorOn; + + /// \brief If non-zero, the implicit PCH include is actually a precompiled + /// preamble that covers this number of bytes in the main source file. + /// + /// The boolean indicates whether the preamble ends at the start of a new + /// line. + std::pair<unsigned, bool> PrecompiledPreambleBytes; + + /// The implicit PTH input included at the start of the translation unit, or + /// empty. + std::string ImplicitPTHInclude; + + /// If given, a PTH cache file to use for speeding up header parsing. + std::string TokenCache; + + /// \brief True if the SourceManager should report the original file name for + /// contents of files that were remapped to other files. Defaults to true. + bool RemappedFilesKeepOriginalName; + + /// \brief The set of file remappings, which take existing files on + /// the system (the first part of each pair) and gives them the + /// contents of other files on the system (the second part of each + /// pair). + std::vector<std::pair<std::string, std::string> > RemappedFiles; + + /// \brief The set of file-to-buffer remappings, which take existing files + /// on the system (the first part of each pair) and gives them the contents + /// of the specified memory buffer (the second part of each pair). + std::vector<std::pair<std::string, const llvm::MemoryBuffer *> > + RemappedFileBuffers; + + /// \brief Whether the compiler instance should retain (i.e., not free) + /// the buffers associated with remapped files. + /// + /// This flag defaults to false; it can be set true only through direct + /// manipulation of the compiler invocation object, in cases where the + /// compiler invocation and its buffers will be reused. + bool RetainRemappedFileBuffers; + + /// \brief The Objective-C++ ARC standard library that we should support, + /// by providing appropriate definitions to retrofit the standard library + /// with support for lifetime-qualified pointers. + ObjCXXARCStandardLibraryKind ObjCXXARCStandardLibrary; + + /// \brief The path of modules being build, which is used to detect + /// cycles in the module dependency graph as modules are being built. + /// + /// There is no way to set this value from the command line. If we ever need + /// to do so (e.g., if on-demand module construction moves out-of-process), + /// we can add a cc1-level option to do so. + SmallVector<std::string, 2> ModuleBuildPath; + + typedef std::vector<std::pair<std::string, std::string> >::iterator + remapped_file_iterator; + typedef std::vector<std::pair<std::string, std::string> >::const_iterator + const_remapped_file_iterator; + remapped_file_iterator remapped_file_begin() { + return RemappedFiles.begin(); + } + const_remapped_file_iterator remapped_file_begin() const { + return RemappedFiles.begin(); + } + remapped_file_iterator remapped_file_end() { + return RemappedFiles.end(); + } + const_remapped_file_iterator remapped_file_end() const { + return RemappedFiles.end(); + } + + typedef std::vector<std::pair<std::string, const llvm::MemoryBuffer *> >:: + iterator remapped_file_buffer_iterator; + typedef std::vector<std::pair<std::string, const llvm::MemoryBuffer *> >:: + const_iterator const_remapped_file_buffer_iterator; + remapped_file_buffer_iterator remapped_file_buffer_begin() { + return RemappedFileBuffers.begin(); + } + const_remapped_file_buffer_iterator remapped_file_buffer_begin() const { + return RemappedFileBuffers.begin(); + } + remapped_file_buffer_iterator remapped_file_buffer_end() { + return RemappedFileBuffers.end(); + } + const_remapped_file_buffer_iterator remapped_file_buffer_end() const { + return RemappedFileBuffers.end(); + } + +public: + PreprocessorOptions() : UsePredefines(true), DetailedRecord(false), + DetailedRecordConditionalDirectives(false), + DisablePCHValidation(false), DisableStatCache(false), + AllowPCHWithCompilerErrors(false), + DumpDeserializedPCHDecls(false), + PrecompiledPreambleBytes(0, true), + RemappedFilesKeepOriginalName(true), + RetainRemappedFileBuffers(false), + ObjCXXARCStandardLibrary(ARCXX_nolib) { } + + void addMacroDef(StringRef Name) { + Macros.push_back(std::make_pair(Name, false)); + } + void addMacroUndef(StringRef Name) { + Macros.push_back(std::make_pair(Name, true)); + } + void addRemappedFile(StringRef From, StringRef To) { + RemappedFiles.push_back(std::make_pair(From, To)); + } + + remapped_file_iterator eraseRemappedFile(remapped_file_iterator Remapped) { + return RemappedFiles.erase(Remapped); + } + + void addRemappedFile(StringRef From, const llvm::MemoryBuffer * To) { + RemappedFileBuffers.push_back(std::make_pair(From, To)); + } + + remapped_file_buffer_iterator + eraseRemappedFile(remapped_file_buffer_iterator Remapped) { + return RemappedFileBuffers.erase(Remapped); + } + + void clearRemappedFiles() { + RemappedFiles.clear(); + RemappedFileBuffers.clear(); + } + + /// \brief Reset any options that are not considered when building a + /// module. + void resetNonModularOptions() { + Includes.clear(); + MacroIncludes.clear(); + ChainedIncludes.clear(); + DumpDeserializedPCHDecls = false; + ImplicitPCHInclude.clear(); + ImplicitPTHInclude.clear(); + TokenCache.clear(); + RetainRemappedFileBuffers = true; + PrecompiledPreambleBytes.first = 0; + PrecompiledPreambleBytes.second = 0; + } +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Frontend/PreprocessorOutputOptions.h b/clang/include/clang/Frontend/PreprocessorOutputOptions.h new file mode 100644 index 0000000..1eda0d4 --- /dev/null +++ b/clang/include/clang/Frontend/PreprocessorOutputOptions.h @@ -0,0 +1,37 @@ +//===--- PreprocessorOutputOptions.h ----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_PREPROCESSOROUTPUTOPTIONS_H +#define LLVM_CLANG_FRONTEND_PREPROCESSOROUTPUTOPTIONS_H + +namespace clang { + +/// PreprocessorOutputOptions - Options for controlling the C preprocessor +/// output (e.g., -E). +class PreprocessorOutputOptions { +public: + unsigned ShowCPP : 1; ///< Print normal preprocessed output. + unsigned ShowComments : 1; ///< Show comments. + unsigned ShowLineMarkers : 1; ///< Show #line markers. + unsigned ShowMacroComments : 1; ///< Show comments, even in macros. + unsigned ShowMacros : 1; ///< Print macro definitions. + +public: + PreprocessorOutputOptions() { + ShowCPP = 1; + ShowComments = 0; + ShowLineMarkers = 1; + ShowMacroComments = 0; + ShowMacros = 0; + } +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Frontend/SerializedDiagnosticPrinter.h b/clang/include/clang/Frontend/SerializedDiagnosticPrinter.h new file mode 100644 index 0000000..aa0695f --- /dev/null +++ b/clang/include/clang/Frontend/SerializedDiagnosticPrinter.h @@ -0,0 +1,62 @@ +//===--- SerializedDiagnosticPrinter.h - Serializer for diagnostics -------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_SERIALIZE_DIAGNOSTIC_PRINTER_H_ +#define LLVM_CLANG_FRONTEND_SERIALIZE_DIAGNOSTIC_PRINTER_H_ + +#include "llvm/Bitcode/BitstreamWriter.h" + +namespace llvm { +class raw_ostream; +} + +namespace clang { +class DiagnosticConsumer; +class DiagnosticsEngine; +class DiagnosticOptions; + +namespace serialized_diags { + +enum BlockIDs { + /// \brief A top-level block which represents any meta data associated + /// with the diagostics, including versioning of the format. + BLOCK_META = llvm::bitc::FIRST_APPLICATION_BLOCKID, + + /// \brief The this block acts as a container for all the information + /// for a specific diagnostic. + BLOCK_DIAG +}; + +enum RecordIDs { + RECORD_VERSION = 1, + RECORD_DIAG, + RECORD_SOURCE_RANGE, + RECORD_DIAG_FLAG, + RECORD_CATEGORY, + RECORD_FILENAME, + RECORD_FIXIT, + RECORD_FIRST = RECORD_VERSION, + RECORD_LAST = RECORD_FIXIT +}; + +/// \brief Returns a DiagnosticConsumer that serializes diagnostics to +/// a bitcode file. +/// +/// The created DiagnosticConsumer is designed for quick and lightweight +/// transfer of of diagnostics to the enclosing build system (e.g., an IDE). +/// This allows wrapper tools for Clang to get diagnostics from Clang +/// (via libclang) without needing to parse Clang's command line output. +/// +DiagnosticConsumer *create(llvm::raw_ostream *OS, + const DiagnosticOptions &diags); + +} // end serialized_diags namespace +} // end clang namespace + +#endif diff --git a/clang/include/clang/Frontend/TextDiagnostic.h b/clang/include/clang/Frontend/TextDiagnostic.h new file mode 100644 index 0000000..314003b --- /dev/null +++ b/clang/include/clang/Frontend/TextDiagnostic.h @@ -0,0 +1,123 @@ +//===--- TextDiagnostic.h - Text Diagnostic Pretty-Printing -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This is a utility class that provides support for textual pretty-printing of +// diagnostics. It is used to implement the different code paths which require +// such functionality in a consistent way. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_TEXT_DIAGNOSTIC_H_ +#define LLVM_CLANG_FRONTEND_TEXT_DIAGNOSTIC_H_ + +#include "clang/Frontend/DiagnosticRenderer.h" + +struct SourceColumnMap; + +namespace clang { + +/// \brief Class to encapsulate the logic for formatting and printing a textual +/// diagnostic message. +/// +/// This class provides an interface for building and emitting a textual +/// diagnostic, including all of the macro backtraces, caret diagnostics, FixIt +/// Hints, and code snippets. In the presence of macros this involves +/// a recursive process, synthesizing notes for each macro expansion. +/// +/// The purpose of this class is to isolate the implementation of printing +/// beautiful text diagnostics from any particular interfaces. The Clang +/// DiagnosticClient is implemented through this class as is diagnostic +/// printing coming out of libclang. +class TextDiagnostic : public DiagnosticRenderer { + raw_ostream &OS; + +public: + TextDiagnostic(raw_ostream &OS, + const SourceManager &SM, + const LangOptions &LangOpts, + const DiagnosticOptions &DiagOpts); + + virtual ~TextDiagnostic(); + + /// \brief Print the diagonstic level to a raw_ostream. + /// + /// This is a static helper that handles colorizing the level and formatting + /// it into an arbitrary output stream. This is used internally by the + /// TextDiagnostic emission code, but it can also be used directly by + /// consumers that don't have a source manager or other state that the full + /// TextDiagnostic logic requires. + static void printDiagnosticLevel(raw_ostream &OS, + DiagnosticsEngine::Level Level, + bool ShowColors); + + /// \brief Pretty-print a diagnostic message to a raw_ostream. + /// + /// This is a static helper to handle the line wrapping, colorizing, and + /// rendering of a diagnostic message to a particular ostream. It is + /// publically visible so that clients which do not have sufficient state to + /// build a complete TextDiagnostic object can still get consistent + /// formatting of their diagnostic messages. + /// + /// \param OS Where the message is printed + /// \param Level Used to colorizing the message + /// \param Message The text actually printed + /// \param CurrentColumn The starting column of the first line, accounting + /// for any prefix. + /// \param Columns The number of columns to use in line-wrapping, 0 disables + /// all line-wrapping. + /// \param ShowColors Enable colorizing of the message. + static void printDiagnosticMessage(raw_ostream &OS, + DiagnosticsEngine::Level Level, + StringRef Message, + unsigned CurrentColumn, unsigned Columns, + bool ShowColors); + +protected: + virtual void emitDiagnosticMessage(SourceLocation Loc,PresumedLoc PLoc, + DiagnosticsEngine::Level Level, + StringRef Message, + ArrayRef<CharSourceRange> Ranges, + DiagOrStoredDiag D); + + virtual void emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc, + DiagnosticsEngine::Level Level, + ArrayRef<CharSourceRange> Ranges); + + virtual void emitCodeContext(SourceLocation Loc, + DiagnosticsEngine::Level Level, + SmallVectorImpl<CharSourceRange>& Ranges, + ArrayRef<FixItHint> Hints) { + emitSnippetAndCaret(Loc, Level, Ranges, Hints); + } + + virtual void emitBasicNote(StringRef Message); + + virtual void emitIncludeLocation(SourceLocation Loc, PresumedLoc PLoc); + +private: + void emitSnippetAndCaret(SourceLocation Loc, DiagnosticsEngine::Level Level, + SmallVectorImpl<CharSourceRange>& Ranges, + ArrayRef<FixItHint> Hints); + + void emitSnippet(StringRef SourceLine); + + void highlightRange(const CharSourceRange &R, + unsigned LineNo, FileID FID, + const SourceColumnMap &map, + std::string &CaretLine); + + std::string buildFixItInsertionLine(unsigned LineNo, + const SourceColumnMap &map, + ArrayRef<FixItHint> Hints); + void emitParseableFixits(ArrayRef<FixItHint> Hints); +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Frontend/TextDiagnosticBuffer.h b/clang/include/clang/Frontend/TextDiagnosticBuffer.h new file mode 100644 index 0000000..6f1c0e8 --- /dev/null +++ b/clang/include/clang/Frontend/TextDiagnosticBuffer.h @@ -0,0 +1,54 @@ +//===--- TextDiagnosticBuffer.h - Buffer Text Diagnostics -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This is a concrete diagnostic client, which buffers the diagnostic messages. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_TEXT_DIAGNOSTIC_BUFFER_H_ +#define LLVM_CLANG_FRONTEND_TEXT_DIAGNOSTIC_BUFFER_H_ + +#include "clang/Basic/Diagnostic.h" +#include <vector> + +namespace clang { + +class Preprocessor; +class SourceManager; + +class TextDiagnosticBuffer : public DiagnosticConsumer { +public: + typedef std::vector<std::pair<SourceLocation, std::string> > DiagList; + typedef DiagList::iterator iterator; + typedef DiagList::const_iterator const_iterator; +private: + DiagList Errors, Warnings, Notes; +public: + const_iterator err_begin() const { return Errors.begin(); } + const_iterator err_end() const { return Errors.end(); } + + const_iterator warn_begin() const { return Warnings.begin(); } + const_iterator warn_end() const { return Warnings.end(); } + + const_iterator note_begin() const { return Notes.begin(); } + const_iterator note_end() const { return Notes.end(); } + + virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, + const Diagnostic &Info); + + /// FlushDiagnostics - Flush the buffered diagnostics to an given + /// diagnostic engine. + void FlushDiagnostics(DiagnosticsEngine &Diags) const; + + virtual DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const; +}; + +} // end namspace clang + +#endif diff --git a/clang/include/clang/Frontend/TextDiagnosticPrinter.h b/clang/include/clang/Frontend/TextDiagnosticPrinter.h new file mode 100644 index 0000000..9b6ac24 --- /dev/null +++ b/clang/include/clang/Frontend/TextDiagnosticPrinter.h @@ -0,0 +1,59 @@ +//===--- TextDiagnosticPrinter.h - Text Diagnostic Client -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This is a concrete diagnostic client, which prints the diagnostics to +// standard error. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_TEXT_DIAGNOSTIC_PRINTER_H_ +#define LLVM_CLANG_FRONTEND_TEXT_DIAGNOSTIC_PRINTER_H_ + +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/OwningPtr.h" + +namespace clang { +class DiagnosticOptions; +class LangOptions; +class TextDiagnostic; + +class TextDiagnosticPrinter : public DiagnosticConsumer { + raw_ostream &OS; + const LangOptions *LangOpts; + const DiagnosticOptions *DiagOpts; + const SourceManager *SM; + + /// \brief Handle to the currently active text diagnostic emitter. + OwningPtr<TextDiagnostic> TextDiag; + + /// A string to prefix to error messages. + std::string Prefix; + + unsigned OwnsOutputStream : 1; + +public: + TextDiagnosticPrinter(raw_ostream &os, const DiagnosticOptions &diags, + bool OwnsOutputStream = false); + virtual ~TextDiagnosticPrinter(); + + /// setPrefix - Set the diagnostic printer prefix string, which will be + /// printed at the start of any diagnostics. If empty, no prefix string is + /// used. + void setPrefix(std::string Value) { Prefix = Value; } + + void BeginSourceFile(const LangOptions &LO, const Preprocessor *PP); + void EndSourceFile(); + void HandleDiagnostic(DiagnosticsEngine::Level Level, const Diagnostic &Info); + DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const; +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Frontend/Utils.h b/clang/include/clang/Frontend/Utils.h new file mode 100644 index 0000000..6b1fc63 --- /dev/null +++ b/clang/include/clang/Frontend/Utils.h @@ -0,0 +1,108 @@ +//===--- Utils.h - Misc utilities for the front-end -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header contains miscellaneous utilities for various front-end actions. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_UTILS_H +#define LLVM_CLANG_FRONTEND_UTILS_H + +#include "clang/Basic/Diagnostic.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/StringRef.h" + +namespace llvm { +class raw_fd_ostream; +class Triple; +} + +namespace clang { +class ASTConsumer; +class CompilerInstance; +class CompilerInvocation; +class Decl; +class DependencyOutputOptions; +class DiagnosticsEngine; +class DiagnosticOptions; +class FileManager; +class HeaderSearch; +class HeaderSearchOptions; +class IdentifierTable; +class LangOptions; +class Preprocessor; +class PreprocessorOptions; +class PreprocessorOutputOptions; +class SourceManager; +class Stmt; +class TargetInfo; +class FrontendOptions; + +/// Apply the header search options to get given HeaderSearch object. +void ApplyHeaderSearchOptions(HeaderSearch &HS, + const HeaderSearchOptions &HSOpts, + const LangOptions &Lang, + const llvm::Triple &triple); + +/// InitializePreprocessor - Initialize the preprocessor getting it and the +/// environment ready to process a single file. +void InitializePreprocessor(Preprocessor &PP, + const PreprocessorOptions &PPOpts, + const HeaderSearchOptions &HSOpts, + const FrontendOptions &FEOpts); + +/// ProcessWarningOptions - Initialize the diagnostic client and process the +/// warning options specified on the command line. +void ProcessWarningOptions(DiagnosticsEngine &Diags, + const DiagnosticOptions &Opts); + +/// DoPrintPreprocessedInput - Implement -E mode. +void DoPrintPreprocessedInput(Preprocessor &PP, raw_ostream* OS, + const PreprocessorOutputOptions &Opts); + +/// AttachDependencyFileGen - Create a dependency file generator, and attach +/// it to the given preprocessor. This takes ownership of the output stream. +void AttachDependencyFileGen(Preprocessor &PP, + const DependencyOutputOptions &Opts); + +/// AttachDependencyGraphGen - Create a dependency graph generator, and attach +/// it to the given preprocessor. + void AttachDependencyGraphGen(Preprocessor &PP, StringRef OutputFile, + StringRef SysRoot); + +/// AttachHeaderIncludeGen - Create a header include list generator, and attach +/// it to the given preprocessor. +/// +/// \param ShowAllHeaders - If true, show all header information instead of just +/// headers following the predefines buffer. This is useful for making sure +/// includes mentioned on the command line are also reported, but differs from +/// the default behavior used by -H. +/// \param OutputPath - If non-empty, a path to write the header include +/// information to, instead of writing to stderr. +void AttachHeaderIncludeGen(Preprocessor &PP, bool ShowAllHeaders = false, + StringRef OutputPath = "", + bool ShowDepth = true); + +/// CacheTokens - Cache tokens for use with PCH. Note that this requires +/// a seekable stream. +void CacheTokens(Preprocessor &PP, llvm::raw_fd_ostream* OS); + +/// createInvocationFromCommandLine - Construct a compiler invocation object for +/// a command line argument vector. +/// +/// \return A CompilerInvocation, or 0 if none was built for the given +/// argument vector. +CompilerInvocation * +createInvocationFromCommandLine(ArrayRef<const char *> Args, + IntrusiveRefCntPtr<DiagnosticsEngine> Diags = + IntrusiveRefCntPtr<DiagnosticsEngine>()); + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Frontend/VerifyDiagnosticConsumer.h b/clang/include/clang/Frontend/VerifyDiagnosticConsumer.h new file mode 100644 index 0000000..2fc6ccc --- /dev/null +++ b/clang/include/clang/Frontend/VerifyDiagnosticConsumer.h @@ -0,0 +1,97 @@ +//===- VerifyDiagnosticConsumer.h - Verifying Diagnostic Client -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_VERIFYDIAGNOSTICSCLIENT_H +#define LLVM_CLANG_FRONTEND_VERIFYDIAGNOSTICSCLIENT_H + +#include "clang/Basic/Diagnostic.h" +#include "llvm/ADT/OwningPtr.h" + +namespace clang { + +class DiagnosticsEngine; +class TextDiagnosticBuffer; + +/// VerifyDiagnosticConsumer - Create a diagnostic client which will use +/// markers in the input source to check that all the emitted diagnostics match +/// those expected. +/// +/// USING THE DIAGNOSTIC CHECKER: +/// +/// Indicating that a line expects an error or a warning is simple. Put a +/// comment on the line that has the diagnostic, use: +/// +/// expected-{error,warning,note} +/// +/// to tag if it's an expected error or warning, and place the expected text +/// between {{ and }} markers. The full text doesn't have to be included, only +/// enough to ensure that the correct diagnostic was emitted. +/// +/// Here's an example: +/// +/// int A = B; // expected-error {{use of undeclared identifier 'B'}} +/// +/// You can place as many diagnostics on one line as you wish. To make the code +/// more readable, you can use slash-newline to separate out the diagnostics. +/// +/// The simple syntax above allows each specification to match exactly one +/// error. You can use the extended syntax to customize this. The extended +/// syntax is "expected-<type> <n> {{diag text}}", where <type> is one of +/// "error", "warning" or "note", and <n> is a positive integer. This allows the +/// diagnostic to appear as many times as specified. Example: +/// +/// void f(); // expected-note 2 {{previous declaration is here}} +/// +/// Regex matching mode may be selected by appending '-re' to type. Example: +/// +/// expected-error-re +/// +/// Examples matching error: "variable has incomplete type 'struct s'" +/// +/// // expected-error {{variable has incomplete type 'struct s'}} +/// // expected-error {{variable has incomplete type}} +/// +/// // expected-error-re {{variable has has type 'struct .'}} +/// // expected-error-re {{variable has has type 'struct .*'}} +/// // expected-error-re {{variable has has type 'struct (.*)'}} +/// // expected-error-re {{variable has has type 'struct[[:space:]](.*)'}} +/// +class VerifyDiagnosticConsumer: public DiagnosticConsumer { +public: + DiagnosticsEngine &Diags; + DiagnosticConsumer *PrimaryClient; + bool OwnsPrimaryClient; + OwningPtr<TextDiagnosticBuffer> Buffer; + Preprocessor *CurrentPreprocessor; + +private: + FileID FirstErrorFID; // FileID of first diagnostic + void CheckDiagnostics(); + +public: + /// Create a new verifying diagnostic client, which will issue errors to \arg + /// the currently-attached diagnostic client when a diagnostic does not match + /// what is expected (as indicated in the source file). + VerifyDiagnosticConsumer(DiagnosticsEngine &Diags); + ~VerifyDiagnosticConsumer(); + + virtual void BeginSourceFile(const LangOptions &LangOpts, + const Preprocessor *PP); + + virtual void EndSourceFile(); + + virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, + const Diagnostic &Info); + + virtual DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const; +}; + +} // end namspace clang + +#endif diff --git a/clang/include/clang/FrontendTool/Utils.h b/clang/include/clang/FrontendTool/Utils.h new file mode 100644 index 0000000..031ee7d --- /dev/null +++ b/clang/include/clang/FrontendTool/Utils.h @@ -0,0 +1,30 @@ +//===--- Utils.h - Misc utilities for the front-end -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header contains miscellaneous utilities for various front-end actions +// which were split from Frontend to minimise Frontend's dependencies. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTENDTOOL_UTILS_H +#define LLVM_CLANG_FRONTENDTOOL_UTILS_H + +namespace clang { + +class CompilerInstance; + +/// ExecuteCompilerInvocation - Execute the given actions described by the +/// compiler invocation object in the given compiler instance. +/// +/// \return - True on success. +bool ExecuteCompilerInvocation(CompilerInstance *Clang); + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Lex/CMakeLists.txt b/clang/include/clang/Lex/CMakeLists.txt new file mode 100644 index 0000000..38055eb --- /dev/null +++ b/clang/include/clang/Lex/CMakeLists.txt @@ -0,0 +1,5 @@ +clang_tablegen(AttrSpellings.inc -gen-clang-attr-spelling-list + -I ${CMAKE_CURRENT_SOURCE_DIR}/../../ + SOURCE ../Basic/Attr.td + TARGET ClangAttrSpellings + DEPENDS AttrSpellings.inc) diff --git a/clang/include/clang/Lex/CodeCompletionHandler.h b/clang/include/clang/Lex/CodeCompletionHandler.h new file mode 100644 index 0000000..d876776 --- /dev/null +++ b/clang/include/clang/Lex/CodeCompletionHandler.h @@ -0,0 +1,71 @@ +//===--- CodeCompletionHandler.h - Preprocessor code completion -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the CodeCompletionHandler interface, which provides +// code-completion callbacks for the preprocessor. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_LEX_CODECOMPLETIONHANDLER_H +#define LLVM_CLANG_LEX_CODECOMPLETIONHANDLER_H + +namespace clang { + +class IdentifierInfo; +class MacroInfo; + +/// \brief Callback handler that receives notifications when performing code +/// completion within the preprocessor. +class CodeCompletionHandler { +public: + virtual ~CodeCompletionHandler(); + + /// \brief Callback invoked when performing code completion for a preprocessor + /// directive. + /// + /// This callback will be invoked when the preprocessor processes a '#' at the + /// start of a line, followed by the code-completion token. + /// + /// \param InConditional Whether we're inside a preprocessor conditional + /// already. + virtual void CodeCompleteDirective(bool InConditional) { } + + /// \brief Callback invoked when performing code completion within a block of + /// code that was excluded due to preprocessor conditionals. + virtual void CodeCompleteInConditionalExclusion() { } + + /// \brief Callback invoked when performing code completion in a context + /// where the name of a macro is expected. + /// + /// \param IsDefinition Whether this is the definition of a macro, e.g., + /// in a #define. + virtual void CodeCompleteMacroName(bool IsDefinition) { } + + /// \brief Callback invoked when performing code completion in a preprocessor + /// expression, such as the condition of an #if or #elif directive. + virtual void CodeCompletePreprocessorExpression() { } + + /// \brief Callback invoked when performing code completion inside a + /// function-like macro argument. + /// + /// There will be another callback invocation after the macro arguments are + /// parsed, so this callback should generally be used to note that the next + /// callback is invoked inside a macro argument. + virtual void CodeCompleteMacroArgument(IdentifierInfo *Macro, + MacroInfo *MacroInfo, + unsigned ArgumentIndex) { } + + /// \brief Callback invoked when performing code completion in a part of the + /// file where we expect natural language, e.g., a comment, string, or + /// #error directive. + virtual void CodeCompleteNaturalLanguage() { } +}; + +} + +#endif // LLVM_CLANG_LEX_CODECOMPLETIONHANDLER_H diff --git a/clang/include/clang/Lex/DirectoryLookup.h b/clang/include/clang/Lex/DirectoryLookup.h new file mode 100644 index 0000000..95f0d27 --- /dev/null +++ b/clang/include/clang/Lex/DirectoryLookup.h @@ -0,0 +1,170 @@ +//===--- DirectoryLookup.h - Info for searching for headers -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the DirectoryLookup interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_DIRECTORYLOOKUP_H +#define LLVM_CLANG_LEX_DIRECTORYLOOKUP_H + +#include "clang/Basic/LLVM.h" +#include "clang/Basic/SourceManager.h" + +namespace clang { +class HeaderMap; +class DirectoryEntry; +class FileEntry; +class HeaderSearch; +class Module; + +/// DirectoryLookup - This class represents one entry in the search list that +/// specifies the search order for directories in #include directives. It +/// represents either a directory, a framework, or a headermap. +/// +class DirectoryLookup { +public: + enum LookupType_t { + LT_NormalDir, + LT_Framework, + LT_HeaderMap + }; +private: + union { // This union is discriminated by isHeaderMap. + /// Dir - This is the actual directory that we're referring to for a normal + /// directory or a framework. + const DirectoryEntry *Dir; + + /// Map - This is the HeaderMap if this is a headermap lookup. + /// + const HeaderMap *Map; + } u; + + /// DirCharacteristic - The type of directory this is: this is an instance of + /// SrcMgr::CharacteristicKind. + unsigned DirCharacteristic : 2; + + /// UserSupplied - True if this is a user-supplied directory. + /// + bool UserSupplied : 1; + + /// LookupType - This indicates whether this DirectoryLookup object is a + /// normal directory, a framework, or a headermap. + unsigned LookupType : 2; + + /// \brief Whether this is a header map used when building a framework. + unsigned IsIndexHeaderMap : 1; + +public: + /// DirectoryLookup ctor - Note that this ctor *does not take ownership* of + /// 'dir'. + DirectoryLookup(const DirectoryEntry *dir, SrcMgr::CharacteristicKind DT, + bool isUser, bool isFramework) + : DirCharacteristic(DT), UserSupplied(isUser), + LookupType(isFramework ? LT_Framework : LT_NormalDir), + IsIndexHeaderMap(false) { + u.Dir = dir; + } + + /// DirectoryLookup ctor - Note that this ctor *does not take ownership* of + /// 'map'. + DirectoryLookup(const HeaderMap *map, SrcMgr::CharacteristicKind DT, + bool isUser, bool isIndexHeaderMap) + : DirCharacteristic(DT), UserSupplied(isUser), LookupType(LT_HeaderMap), + IsIndexHeaderMap(isIndexHeaderMap) { + u.Map = map; + } + + /// getLookupType - Return the kind of directory lookup that this is: either a + /// normal directory, a framework path, or a HeaderMap. + LookupType_t getLookupType() const { return (LookupType_t)LookupType; } + + /// getName - Return the directory or filename corresponding to this lookup + /// object. + const char *getName() const; + + /// getDir - Return the directory that this entry refers to. + /// + const DirectoryEntry *getDir() const { return isNormalDir() ? u.Dir : 0; } + + /// getFrameworkDir - Return the directory that this framework refers to. + /// + const DirectoryEntry *getFrameworkDir() const { + return isFramework() ? u.Dir : 0; + } + + /// getHeaderMap - Return the directory that this entry refers to. + /// + const HeaderMap *getHeaderMap() const { return isHeaderMap() ? u.Map : 0; } + + /// isNormalDir - Return true if this is a normal directory, not a header map. + bool isNormalDir() const { return getLookupType() == LT_NormalDir; } + + /// isFramework - True if this is a framework directory. + /// + bool isFramework() const { return getLookupType() == LT_Framework; } + + /// isHeaderMap - Return true if this is a header map, not a normal directory. + bool isHeaderMap() const { return getLookupType() == LT_HeaderMap; } + + /// DirCharacteristic - The type of directory this is, one of the DirType enum + /// values. + SrcMgr::CharacteristicKind getDirCharacteristic() const { + return (SrcMgr::CharacteristicKind)DirCharacteristic; + } + + /// isUserSupplied - True if this is a user-supplied directory. + /// + bool isUserSupplied() const { return UserSupplied; } + + /// \brief Whether this header map is building a framework or not. + bool isIndexHeaderMap() const { + return isHeaderMap() && IsIndexHeaderMap; + } + + /// LookupFile - Lookup the specified file in this search path, returning it + /// if it exists or returning null if not. + /// + /// \param Filename The file to look up relative to the search paths. + /// + /// \param HS The header search instance to search with. + /// + /// \param SearchPath If not NULL, will be set to the search path relative + /// to which the file was found. + /// + /// \param RelativePath If not NULL, will be set to the path relative to + /// SearchPath at which the file was found. This only differs from the + /// Filename for framework includes. + /// + /// \param SuggestedModule If non-null, and the file found is semantically + /// part of a known module, this will be set to the module that should + /// be imported instead of preprocessing/parsing the file found. + /// + /// \param InUserSpecifiedSystemHeader [out] If the file is found, set to true + /// if the file is located in a framework that has been user-specified to be + /// treated as a system framework. + const FileEntry *LookupFile(StringRef Filename, HeaderSearch &HS, + SmallVectorImpl<char> *SearchPath, + SmallVectorImpl<char> *RelativePath, + Module **SuggestedModule, + bool &InUserSpecifiedSystemHeader) const; + +private: + const FileEntry *DoFrameworkLookup( + StringRef Filename, HeaderSearch &HS, + SmallVectorImpl<char> *SearchPath, + SmallVectorImpl<char> *RelativePath, + Module **SuggestedModule, + bool &InUserSpecifiedSystemHeader) const; + +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Lex/ExternalPreprocessorSource.h b/clang/include/clang/Lex/ExternalPreprocessorSource.h new file mode 100644 index 0000000..f172b5c --- /dev/null +++ b/clang/include/clang/Lex/ExternalPreprocessorSource.h @@ -0,0 +1,40 @@ +//===- ExternalPreprocessorSource.h - Abstract Macro Interface --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ExternalPreprocessorSource interface, which enables +// construction of macro definitions from some external source. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_LEX_EXTERNAL_PREPROCESSOR_SOURCE_H +#define LLVM_CLANG_LEX_EXTERNAL_PREPROCESSOR_SOURCE_H + +namespace clang { + +/// \brief Abstract interface for external sources of preprocessor +/// information. +/// +/// This abstract class allows an external sources (such as the \c ASTReader) +/// to provide additional macro definitions. +class ExternalPreprocessorSource { +public: + virtual ~ExternalPreprocessorSource(); + + /// \brief Read the set of macros defined by this external macro source. + virtual void ReadDefinedMacros() = 0; + + /// \brief Read the definition for the given macro. + virtual void LoadMacroDefinition(IdentifierInfo *II) = 0; + + /// \brief Update an out-of-date identifier. + virtual void updateOutOfDateIdentifier(IdentifierInfo &II) = 0; +}; + +} + +#endif // LLVM_CLANG_LEX_EXTERNAL_PREPROCESSOR_SOURCE_H diff --git a/clang/include/clang/Lex/HeaderMap.h b/clang/include/clang/Lex/HeaderMap.h new file mode 100644 index 0000000..08bc5b6 --- /dev/null +++ b/clang/include/clang/Lex/HeaderMap.h @@ -0,0 +1,72 @@ +//===--- HeaderMap.h - A file that acts like dir of symlinks ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the HeaderMap interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_HEADERMAP_H +#define LLVM_CLANG_LEX_HEADERMAP_H + +#include "clang/Basic/LLVM.h" + +namespace llvm { + class MemoryBuffer; +} +namespace clang { + class FileEntry; + class FileManager; + struct HMapBucket; + struct HMapHeader; + +/// This class represents an Apple concept known as a 'header map'. To the +/// #include file resolution process, it basically acts like a directory of +/// symlinks to files. Its advantages are that it is dense and more efficient +/// to create and process than a directory of symlinks. +class HeaderMap { + HeaderMap(const HeaderMap&); // DO NOT IMPLEMENT + void operator=(const HeaderMap&); // DO NOT IMPLEMENT + + const llvm::MemoryBuffer *FileBuffer; + bool NeedsBSwap; + + HeaderMap(const llvm::MemoryBuffer *File, bool BSwap) + : FileBuffer(File), NeedsBSwap(BSwap) { + } +public: + ~HeaderMap(); + + /// HeaderMap::Create - This attempts to load the specified file as a header + /// map. If it doesn't look like a HeaderMap, it gives up and returns null. + static const HeaderMap *Create(const FileEntry *FE, FileManager &FM); + + /// LookupFile - Check to see if the specified relative filename is located in + /// this HeaderMap. If so, open it and return its FileEntry. + /// If RawPath is not NULL and the file is found, RawPath will be set to the + /// raw path at which the file was found in the file system. For example, + /// for a search path ".." and a filename "../file.h" this would be + /// "../../file.h". + const FileEntry *LookupFile(StringRef Filename, FileManager &FM) const; + + /// getFileName - Return the filename of the headermap. + const char *getFileName() const; + + /// dump - Print the contents of this headermap to stderr. + void dump() const; + +private: + unsigned getEndianAdjustedWord(unsigned X) const; + const HMapHeader &getHeader() const; + HMapBucket getBucket(unsigned BucketNo) const; + const char *getString(unsigned StrTabIdx) const; +}; + +} // end namespace clang. + +#endif diff --git a/clang/include/clang/Lex/HeaderSearch.h b/clang/include/clang/Lex/HeaderSearch.h new file mode 100644 index 0000000..5128ce6 --- /dev/null +++ b/clang/include/clang/Lex/HeaderSearch.h @@ -0,0 +1,562 @@ +//===--- HeaderSearch.h - Resolve Header File Locations ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the HeaderSearch interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_HEADERSEARCH_H +#define LLVM_CLANG_LEX_HEADERSEARCH_H + +#include "clang/Lex/DirectoryLookup.h" +#include "clang/Lex/ModuleMap.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringSet.h" +#include "llvm/Support/Allocator.h" +#include "llvm/ADT/OwningPtr.h" +#include <vector> + +namespace clang { + +class DiagnosticsEngine; +class ExternalIdentifierLookup; +class FileEntry; +class FileManager; +class IdentifierInfo; + +/// HeaderFileInfo - The preprocessor keeps track of this information for each +/// file that is #included. +struct HeaderFileInfo { + /// isImport - True if this is a #import'd or #pragma once file. + unsigned isImport : 1; + + /// isPragmaOnce - True if this is #pragma once file. + unsigned isPragmaOnce : 1; + + /// DirInfo - Keep track of whether this is a system header, and if so, + /// whether it is C++ clean or not. This can be set by the include paths or + /// by #pragma gcc system_header. This is an instance of + /// SrcMgr::CharacteristicKind. + unsigned DirInfo : 2; + + /// \brief Whether this header file info was supplied by an external source. + unsigned External : 1; + + /// \brief Whether this structure is considered to already have been + /// "resolved", meaning that it was loaded from the external source. + unsigned Resolved : 1; + + /// \brief Whether this is a header inside a framework that is currently + /// being built. + /// + /// When a framework is being built, the headers have not yet been placed + /// into the appropriate framework subdirectories, and therefore are + /// provided via a header map. This bit indicates when this is one of + /// those framework headers. + unsigned IndexHeaderMapHeader : 1; + + /// NumIncludes - This is the number of times the file has been included + /// already. + unsigned short NumIncludes; + + /// \brief The ID number of the controlling macro. + /// + /// This ID number will be non-zero when there is a controlling + /// macro whose IdentifierInfo may not yet have been loaded from + /// external storage. + unsigned ControllingMacroID; + + /// ControllingMacro - If this file has a #ifndef XXX (or equivalent) guard + /// that protects the entire contents of the file, this is the identifier + /// for the macro that controls whether or not it has any effect. + /// + /// Note: Most clients should use getControllingMacro() to access + /// the controlling macro of this header, since + /// getControllingMacro() is able to load a controlling macro from + /// external storage. + const IdentifierInfo *ControllingMacro; + + /// \brief If this header came from a framework include, this is the name + /// of the framework. + StringRef Framework; + + HeaderFileInfo() + : isImport(false), isPragmaOnce(false), DirInfo(SrcMgr::C_User), + External(false), Resolved(false), IndexHeaderMapHeader(false), + NumIncludes(0), ControllingMacroID(0), ControllingMacro(0) {} + + /// \brief Retrieve the controlling macro for this header file, if + /// any. + const IdentifierInfo *getControllingMacro(ExternalIdentifierLookup *External); + + /// \brief Determine whether this is a non-default header file info, e.g., + /// it corresponds to an actual header we've included or tried to include. + bool isNonDefault() const { + return isImport || isPragmaOnce || NumIncludes || ControllingMacro || + ControllingMacroID; + } +}; + +/// \brief An external source of header file information, which may supply +/// information about header files already included. +class ExternalHeaderFileInfoSource { +public: + virtual ~ExternalHeaderFileInfoSource(); + + /// \brief Retrieve the header file information for the given file entry. + /// + /// \returns Header file information for the given file entry, with the + /// \c External bit set. If the file entry is not known, return a + /// default-constructed \c HeaderFileInfo. + virtual HeaderFileInfo GetHeaderFileInfo(const FileEntry *FE) = 0; +}; + +/// HeaderSearch - This class encapsulates the information needed to find the +/// file referenced by a #include or #include_next, (sub-)framework lookup, etc. +class HeaderSearch { + /// This structure is used to record entries in our framework cache. + struct FrameworkCacheEntry { + /// The directory entry which should be used for the cached framework. + const DirectoryEntry *Directory; + + /// Whether this framework has been "user-specified" to be treated as if it + /// were a system framework (even if it was found outside a system framework + /// directory). + bool IsUserSpecifiedSystemFramework; + }; + + FileManager &FileMgr; + DiagnosticsEngine &Diags; + /// #include search path information. Requests for #include "x" search the + /// directory of the #including file first, then each directory in SearchDirs + /// consecutively. Requests for <x> search the current dir first, then each + /// directory in SearchDirs, starting at AngledDirIdx, consecutively. If + /// NoCurDirSearch is true, then the check for the file in the current + /// directory is suppressed. + std::vector<DirectoryLookup> SearchDirs; + unsigned AngledDirIdx; + unsigned SystemDirIdx; + bool NoCurDirSearch; + + /// \brief The path to the module cache. + std::string ModuleCachePath; + + /// FileInfo - This contains all of the preprocessor-specific data about files + /// that are included. The vector is indexed by the FileEntry's UID. + /// + std::vector<HeaderFileInfo> FileInfo; + + /// LookupFileCache - This is keeps track of each lookup performed by + /// LookupFile. The first part of the value is the starting index in + /// SearchDirs that the cached search was performed from. If there is a hit + /// and this value doesn't match the current query, the cache has to be + /// ignored. The second value is the entry in SearchDirs that satisfied the + /// query. + llvm::StringMap<std::pair<unsigned, unsigned>, llvm::BumpPtrAllocator> + LookupFileCache; + + /// FrameworkMap - This is a collection mapping a framework or subframework + /// name like "Carbon" to the Carbon.framework directory. + llvm::StringMap<FrameworkCacheEntry, llvm::BumpPtrAllocator> FrameworkMap; + + /// IncludeAliases - maps include file names (including the quotes or + /// angle brackets) to other include file names. This is used to support the + /// include_alias pragma for Microsoft compatibility. + typedef llvm::StringMap<std::string, llvm::BumpPtrAllocator> + IncludeAliasMap; + OwningPtr<IncludeAliasMap> IncludeAliases; + + /// HeaderMaps - This is a mapping from FileEntry -> HeaderMap, uniquing + /// headermaps. This vector owns the headermap. + std::vector<std::pair<const FileEntry*, const HeaderMap*> > HeaderMaps; + + /// \brief The mapping between modules and headers. + ModuleMap ModMap; + + /// \brief Describes whether a given directory has a module map in it. + llvm::DenseMap<const DirectoryEntry *, bool> DirectoryHasModuleMap; + + /// \brief Uniqued set of framework names, which is used to track which + /// headers were included as framework headers. + llvm::StringSet<llvm::BumpPtrAllocator> FrameworkNames; + + /// \brief Entity used to resolve the identifier IDs of controlling + /// macros into IdentifierInfo pointers, as needed. + ExternalIdentifierLookup *ExternalLookup; + + /// \brief Entity used to look up stored header file information. + ExternalHeaderFileInfoSource *ExternalSource; + + // Various statistics we track for performance analysis. + unsigned NumIncluded; + unsigned NumMultiIncludeFileOptzn; + unsigned NumFrameworkLookups, NumSubFrameworkLookups; + + // HeaderSearch doesn't support default or copy construction. + explicit HeaderSearch(); + explicit HeaderSearch(const HeaderSearch&); + void operator=(const HeaderSearch&); + + friend class DirectoryLookup; + +public: + HeaderSearch(FileManager &FM, DiagnosticsEngine &Diags, + const LangOptions &LangOpts, const TargetInfo *Target); + ~HeaderSearch(); + + FileManager &getFileMgr() const { return FileMgr; } + + /// SetSearchPaths - Interface for setting the file search paths. + /// + void SetSearchPaths(const std::vector<DirectoryLookup> &dirs, + unsigned angledDirIdx, unsigned systemDirIdx, + bool noCurDirSearch) { + assert(angledDirIdx <= systemDirIdx && systemDirIdx <= dirs.size() && + "Directory indicies are unordered"); + SearchDirs = dirs; + AngledDirIdx = angledDirIdx; + SystemDirIdx = systemDirIdx; + NoCurDirSearch = noCurDirSearch; + //LookupFileCache.clear(); + } + + /// AddSearchPath - Add an additional search path. + void AddSearchPath(const DirectoryLookup &dir, bool isAngled) { + unsigned idx = isAngled ? SystemDirIdx : AngledDirIdx; + SearchDirs.insert(SearchDirs.begin() + idx, dir); + if (!isAngled) + AngledDirIdx++; + SystemDirIdx++; + } + + /// HasIncludeAliasMap - Checks whether the map exists or not + bool HasIncludeAliasMap() const { + return IncludeAliases; + } + + /// AddIncludeAlias - Map the source include name to the dest include name. + /// The Source should include the angle brackets or quotes, the dest + /// should not. This allows for distinction between <> and "" headers. + void AddIncludeAlias(StringRef Source, StringRef Dest) { + if (!IncludeAliases) + IncludeAliases.reset(new IncludeAliasMap); + (*IncludeAliases)[Source] = Dest; + } + + /// MapHeaderToIncludeAlias - Maps one header file name to a different header + /// file name, for use with the include_alias pragma. Note that the source + /// file name should include the angle brackets or quotes. Returns StringRef + /// as null if the header cannot be mapped. + StringRef MapHeaderToIncludeAlias(StringRef Source) { + assert(IncludeAliases && "Trying to map headers when there's no map"); + + // Do any filename replacements before anything else + IncludeAliasMap::const_iterator Iter = IncludeAliases->find(Source); + if (Iter != IncludeAliases->end()) + return Iter->second; + return StringRef(); + } + + /// \brief Set the path to the module cache. + void setModuleCachePath(StringRef CachePath) { + ModuleCachePath = CachePath; + } + + /// \brief Retrieve the path to the module cache. + StringRef getModuleCachePath() const { return ModuleCachePath; } + + /// ClearFileInfo - Forget everything we know about headers so far. + void ClearFileInfo() { + FileInfo.clear(); + } + + void SetExternalLookup(ExternalIdentifierLookup *EIL) { + ExternalLookup = EIL; + } + + ExternalIdentifierLookup *getExternalLookup() const { + return ExternalLookup; + } + + /// \brief Set the external source of header information. + void SetExternalSource(ExternalHeaderFileInfoSource *ES) { + ExternalSource = ES; + } + + /// \brief Set the target information for the header search, if not + /// already known. + void setTarget(const TargetInfo &Target); + + /// LookupFile - Given a "foo" or <foo> reference, look up the indicated file, + /// return null on failure. + /// + /// \returns If successful, this returns 'UsedDir', the DirectoryLookup member + /// the file was found in, or null if not applicable. + /// + /// \param isAngled indicates whether the file reference is a <> reference. + /// + /// \param CurDir If non-null, the file was found in the specified directory + /// search location. This is used to implement #include_next. + /// + /// \param CurFileEnt If non-null, indicates where the #including file is, in + /// case a relative search is needed. + /// + /// \param SearchPath If non-null, will be set to the search path relative + /// to which the file was found. If the include path is absolute, SearchPath + /// will be set to an empty string. + /// + /// \param RelativePath If non-null, will be set to the path relative to + /// SearchPath at which the file was found. This only differs from the + /// Filename for framework includes. + /// + /// \param SuggestedModule If non-null, and the file found is semantically + /// part of a known module, this will be set to the module that should + /// be imported instead of preprocessing/parsing the file found. + const FileEntry *LookupFile(StringRef Filename, bool isAngled, + const DirectoryLookup *FromDir, + const DirectoryLookup *&CurDir, + const FileEntry *CurFileEnt, + SmallVectorImpl<char> *SearchPath, + SmallVectorImpl<char> *RelativePath, + Module **SuggestedModule, + bool SkipCache = false); + + /// LookupSubframeworkHeader - Look up a subframework for the specified + /// #include file. For example, if #include'ing <HIToolbox/HIToolbox.h> from + /// within ".../Carbon.framework/Headers/Carbon.h", check to see if HIToolbox + /// is a subframework within Carbon.framework. If so, return the FileEntry + /// for the designated file, otherwise return null. + const FileEntry *LookupSubframeworkHeader( + StringRef Filename, + const FileEntry *RelativeFileEnt, + SmallVectorImpl<char> *SearchPath, + SmallVectorImpl<char> *RelativePath); + + /// LookupFrameworkCache - Look up the specified framework name in our + /// framework cache, returning the DirectoryEntry it is in if we know, + /// otherwise, return null. + FrameworkCacheEntry &LookupFrameworkCache(StringRef FWName) { + return FrameworkMap.GetOrCreateValue(FWName).getValue(); + } + + /// ShouldEnterIncludeFile - Mark the specified file as a target of of a + /// #include, #include_next, or #import directive. Return false if #including + /// the file will have no effect or true if we should include it. + bool ShouldEnterIncludeFile(const FileEntry *File, bool isImport); + + + /// getFileDirFlavor - Return whether the specified file is a normal header, + /// a system header, or a C++ friendly system header. + SrcMgr::CharacteristicKind getFileDirFlavor(const FileEntry *File) { + return (SrcMgr::CharacteristicKind)getFileInfo(File).DirInfo; + } + + /// MarkFileIncludeOnce - Mark the specified file as a "once only" file, e.g. + /// due to #pragma once. + void MarkFileIncludeOnce(const FileEntry *File) { + HeaderFileInfo &FI = getFileInfo(File); + FI.isImport = true; + FI.isPragmaOnce = true; + } + + /// MarkFileSystemHeader - Mark the specified file as a system header, e.g. + /// due to #pragma GCC system_header. + void MarkFileSystemHeader(const FileEntry *File) { + getFileInfo(File).DirInfo = SrcMgr::C_System; + } + + /// IncrementIncludeCount - Increment the count for the number of times the + /// specified FileEntry has been entered. + void IncrementIncludeCount(const FileEntry *File) { + ++getFileInfo(File).NumIncludes; + } + + /// SetFileControllingMacro - Mark the specified file as having a controlling + /// macro. This is used by the multiple-include optimization to eliminate + /// no-op #includes. + void SetFileControllingMacro(const FileEntry *File, + const IdentifierInfo *ControllingMacro) { + getFileInfo(File).ControllingMacro = ControllingMacro; + } + + /// \brief Determine whether this file is intended to be safe from + /// multiple inclusions, e.g., it has #pragma once or a controlling + /// macro. + /// + /// This routine does not consider the effect of #import + bool isFileMultipleIncludeGuarded(const FileEntry *File); + + /// CreateHeaderMap - This method returns a HeaderMap for the specified + /// FileEntry, uniquing them through the the 'HeaderMaps' datastructure. + const HeaderMap *CreateHeaderMap(const FileEntry *FE); + + /// \brief Retrieve the name of the module file that should be used to + /// load the given module. + /// + /// \param Module The module whose module file name will be returned. + /// + /// \returns The name of the module file that corresponds to this module, + /// or an empty string if this module does not correspond to any module file. + std::string getModuleFileName(Module *Module); + + /// \brief Retrieve the name of the module file that should be used to + /// load a module with the given name. + /// + /// \param Module The module whose module file name will be returned. + /// + /// \returns The name of the module file that corresponds to this module, + /// or an empty string if this module does not correspond to any module file. + std::string getModuleFileName(StringRef ModuleName); + + /// \brief Lookup a module Search for a module with the given name. + /// + /// \param ModuleName The name of the module we're looking for. + /// + /// \param AllowSearch Whether we are allowed to search in the various + /// search directories to produce a module definition. If not, this lookup + /// will only return an already-known module. + /// + /// \returns The module with the given name. + Module *lookupModule(StringRef ModuleName, bool AllowSearch = true); + + void IncrementFrameworkLookupCount() { ++NumFrameworkLookups; } + + /// \brief Determine whether there is a module map that may map the header + /// with the given file name to a (sub)module. + /// + /// \param Filename The name of the file. + /// + /// \param Root The "root" directory, at which we should stop looking for + /// module maps. + bool hasModuleMap(StringRef Filename, const DirectoryEntry *Root); + + /// \brief Retrieve the module that corresponds to the given file, if any. + /// + /// \param File The header that we wish to map to a module. + Module *findModuleForHeader(const FileEntry *File); + + /// \brief Read the contents of the given module map file. + /// + /// \param File The module map file. + /// + /// \param OnlyModule If non-NULL, this will receive the + /// + /// \returns true if an error occurred, false otherwise. + bool loadModuleMapFile(const FileEntry *File); + + /// \brief Collect the set of all known, top-level modules. + /// + /// \param Modules Will be filled with the set of known, top-level modules. + void collectAllModules(llvm::SmallVectorImpl<Module *> &Modules); + +private: + /// \brief Retrieve a module with the given name, which may be part of the + /// given framework. + /// + /// \param Name The name of the module to retrieve. + /// + /// \param Dir The framework directory (e.g., ModuleName.framework). + /// + /// \param IsSystem Whether the framework directory is part of the system + /// frameworks. + /// + /// \returns The module, if found; otherwise, null. + Module *loadFrameworkModule(StringRef Name, + const DirectoryEntry *Dir, + bool IsSystem); + +public: + /// \brief Retrieve the module map. + ModuleMap &getModuleMap() { return ModMap; } + + unsigned header_file_size() const { return FileInfo.size(); } + + // Used by ASTReader. + void setHeaderFileInfoForUID(HeaderFileInfo HFI, unsigned UID); + + /// getFileInfo - Return the HeaderFileInfo structure for the specified + /// FileEntry. + const HeaderFileInfo &getFileInfo(const FileEntry *FE) const { + return const_cast<HeaderSearch*>(this)->getFileInfo(FE); + } + + // Used by external tools + typedef std::vector<DirectoryLookup>::const_iterator search_dir_iterator; + search_dir_iterator search_dir_begin() const { return SearchDirs.begin(); } + search_dir_iterator search_dir_end() const { return SearchDirs.end(); } + unsigned search_dir_size() const { return SearchDirs.size(); } + + search_dir_iterator quoted_dir_begin() const { + return SearchDirs.begin(); + } + search_dir_iterator quoted_dir_end() const { + return SearchDirs.begin() + AngledDirIdx; + } + + search_dir_iterator angled_dir_begin() const { + return SearchDirs.begin() + AngledDirIdx; + } + search_dir_iterator angled_dir_end() const { + return SearchDirs.begin() + SystemDirIdx; + } + + search_dir_iterator system_dir_begin() const { + return SearchDirs.begin() + SystemDirIdx; + } + search_dir_iterator system_dir_end() const { return SearchDirs.end(); } + + /// \brief Retrieve a uniqued framework name. + StringRef getUniqueFrameworkName(StringRef Framework); + + void PrintStats(); + + size_t getTotalMemory() const; + + static std::string NormalizeDashIncludePath(StringRef File, + FileManager &FileMgr); + +private: + /// \brief Describes what happened when we tried to load a module map file. + enum LoadModuleMapResult { + /// \brief The module map file had already been loaded. + LMM_AlreadyLoaded, + /// \brief The module map file was loaded by this invocation. + LMM_NewlyLoaded, + /// \brief There is was directory with the given name. + LMM_NoDirectory, + /// \brief There was either no module map file or the module map file was + /// invalid. + LMM_InvalidModuleMap + }; + + /// \brief Try to load the module map file in the given directory. + /// + /// \param DirName The name of the directory where we will look for a module + /// map file. + /// + /// \returns The result of attempting to load the module map file from the + /// named directory. + LoadModuleMapResult loadModuleMapFile(StringRef DirName); + + /// \brief Try to load the module map file in the given directory. + /// + /// \param Dir The directory where we will look for a module map file. + /// + /// \returns The result of attempting to load the module map file from the + /// named directory. + LoadModuleMapResult loadModuleMapFile(const DirectoryEntry *Dir); + + /// getFileInfo - Return the HeaderFileInfo structure for the specified + /// FileEntry. + HeaderFileInfo &getFileInfo(const FileEntry *FE); +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Lex/LexDiagnostic.h b/clang/include/clang/Lex/LexDiagnostic.h new file mode 100644 index 0000000..41b9396 --- /dev/null +++ b/clang/include/clang/Lex/LexDiagnostic.h @@ -0,0 +1,28 @@ +//===--- DiagnosticLex.h - Diagnostics for liblex ---------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_DIAGNOSTICLEX_H +#define LLVM_CLANG_DIAGNOSTICLEX_H + +#include "clang/Basic/Diagnostic.h" + +namespace clang { + namespace diag { + enum { +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\ + SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM, +#define LEXSTART +#include "clang/Basic/DiagnosticLexKinds.inc" +#undef DIAG + NUM_BUILTIN_LEX_DIAGNOSTICS + }; + } // end namespace diag +} // end namespace clang + +#endif diff --git a/clang/include/clang/Lex/Lexer.h b/clang/include/clang/Lex/Lexer.h new file mode 100644 index 0000000..04bcead --- /dev/null +++ b/clang/include/clang/Lex/Lexer.h @@ -0,0 +1,563 @@ +//===--- Lexer.h - C Language Family Lexer ----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Lexer interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEXER_H +#define LLVM_CLANG_LEXER_H + +#include "clang/Lex/PreprocessorLexer.h" +#include "clang/Basic/LangOptions.h" +#include "llvm/ADT/SmallVector.h" +#include <string> +#include <cassert> + +namespace clang { +class DiagnosticsEngine; +class SourceManager; +class Preprocessor; +class DiagnosticBuilder; + +/// ConflictMarkerKind - Kinds of conflict marker which the lexer might be +/// recovering from. +enum ConflictMarkerKind { + /// Not within a conflict marker. + CMK_None, + /// A normal or diff3 conflict marker, initiated by at least 7 <s, + /// separated by at least 7 =s or |s, and terminated by at least 7 >s. + CMK_Normal, + /// A Perforce-style conflict marker, initiated by 4 >s, separated by 4 =s, + /// and terminated by 4 <s. + CMK_Perforce +}; + +/// Lexer - This provides a simple interface that turns a text buffer into a +/// stream of tokens. This provides no support for file reading or buffering, +/// or buffering/seeking of tokens, only forward lexing is supported. It relies +/// on the specified Preprocessor object to handle preprocessor directives, etc. +class Lexer : public PreprocessorLexer { + virtual void anchor(); + + //===--------------------------------------------------------------------===// + // Constant configuration values for this lexer. + const char *BufferStart; // Start of the buffer. + const char *BufferEnd; // End of the buffer. + SourceLocation FileLoc; // Location for start of file. + LangOptions LangOpts; // LangOpts enabled by this language (cache). + bool Is_PragmaLexer; // True if lexer for _Pragma handling. + + //===--------------------------------------------------------------------===// + // Context-specific lexing flags set by the preprocessor. + // + + /// ExtendedTokenMode - The lexer can optionally keep comments and whitespace + /// and return them as tokens. This is used for -C and -CC modes, and + /// whitespace preservation can be useful for some clients that want to lex + /// the file in raw mode and get every character from the file. + /// + /// When this is set to 2 it returns comments and whitespace. When set to 1 + /// it returns comments, when it is set to 0 it returns normal tokens only. + unsigned char ExtendedTokenMode; + + //===--------------------------------------------------------------------===// + // Context that changes as the file is lexed. + // NOTE: any state that mutates when in raw mode must have save/restore code + // in Lexer::isNextPPTokenLParen. + + // BufferPtr - Current pointer into the buffer. This is the next character + // to be lexed. + const char *BufferPtr; + + // IsAtStartOfLine - True if the next lexed token should get the "start of + // line" flag set on it. + bool IsAtStartOfLine; + + // CurrentConflictMarkerState - The kind of conflict marker we are handling. + ConflictMarkerKind CurrentConflictMarkerState; + + Lexer(const Lexer&); // DO NOT IMPLEMENT + void operator=(const Lexer&); // DO NOT IMPLEMENT + friend class Preprocessor; + + void InitLexer(const char *BufStart, const char *BufPtr, const char *BufEnd); +public: + + /// Lexer constructor - Create a new lexer object for the specified buffer + /// with the specified preprocessor managing the lexing process. This lexer + /// assumes that the associated file buffer and Preprocessor objects will + /// outlive it, so it doesn't take ownership of either of them. + Lexer(FileID FID, const llvm::MemoryBuffer *InputBuffer, Preprocessor &PP); + + /// Lexer constructor - Create a new raw lexer object. This object is only + /// suitable for calls to 'LexRawToken'. This lexer assumes that the text + /// range will outlive it, so it doesn't take ownership of it. + Lexer(SourceLocation FileLoc, const LangOptions &LangOpts, + const char *BufStart, const char *BufPtr, const char *BufEnd); + + /// Lexer constructor - Create a new raw lexer object. This object is only + /// suitable for calls to 'LexRawToken'. This lexer assumes that the text + /// range will outlive it, so it doesn't take ownership of it. + Lexer(FileID FID, const llvm::MemoryBuffer *InputBuffer, + const SourceManager &SM, const LangOptions &LangOpts); + + /// Create_PragmaLexer: Lexer constructor - Create a new lexer object for + /// _Pragma expansion. This has a variety of magic semantics that this method + /// sets up. It returns a new'd Lexer that must be delete'd when done. + static Lexer *Create_PragmaLexer(SourceLocation SpellingLoc, + SourceLocation ExpansionLocStart, + SourceLocation ExpansionLocEnd, + unsigned TokLen, Preprocessor &PP); + + + /// getLangOpts - Return the language features currently enabled. + /// NOTE: this lexer modifies features as a file is parsed! + const LangOptions &getLangOpts() const { return LangOpts; } + + /// getFileLoc - Return the File Location for the file we are lexing out of. + /// The physical location encodes the location where the characters come from, + /// the virtual location encodes where we should *claim* the characters came + /// from. Currently this is only used by _Pragma handling. + SourceLocation getFileLoc() const { return FileLoc; } + + /// Lex - Return the next token in the file. If this is the end of file, it + /// return the tok::eof token. Return true if an error occurred and + /// compilation should terminate, false if normal. This implicitly involves + /// the preprocessor. + void Lex(Token &Result) { + // Start a new token. + Result.startToken(); + + // NOTE, any changes here should also change code after calls to + // Preprocessor::HandleDirective + if (IsAtStartOfLine) { + Result.setFlag(Token::StartOfLine); + IsAtStartOfLine = false; + } + + // Get a token. Note that this may delete the current lexer if the end of + // file is reached. + LexTokenInternal(Result); + } + + /// isPragmaLexer - Returns true if this Lexer is being used to lex a pragma. + bool isPragmaLexer() const { return Is_PragmaLexer; } + + /// IndirectLex - An indirect call to 'Lex' that can be invoked via + /// the PreprocessorLexer interface. + void IndirectLex(Token &Result) { Lex(Result); } + + /// LexFromRawLexer - Lex a token from a designated raw lexer (one with no + /// associated preprocessor object. Return true if the 'next character to + /// read' pointer points at the end of the lexer buffer, false otherwise. + bool LexFromRawLexer(Token &Result) { + assert(LexingRawMode && "Not already in raw mode!"); + Lex(Result); + // Note that lexing to the end of the buffer doesn't implicitly delete the + // lexer when in raw mode. + return BufferPtr == BufferEnd; + } + + /// isKeepWhitespaceMode - Return true if the lexer should return tokens for + /// every character in the file, including whitespace and comments. This + /// should only be used in raw mode, as the preprocessor is not prepared to + /// deal with the excess tokens. + bool isKeepWhitespaceMode() const { + return ExtendedTokenMode > 1; + } + + /// SetKeepWhitespaceMode - This method lets clients enable or disable + /// whitespace retention mode. + void SetKeepWhitespaceMode(bool Val) { + assert((!Val || LexingRawMode) && + "Can only enable whitespace retention in raw mode"); + ExtendedTokenMode = Val ? 2 : 0; + } + + /// inKeepCommentMode - Return true if the lexer should return comments as + /// tokens. + bool inKeepCommentMode() const { + return ExtendedTokenMode > 0; + } + + /// SetCommentRetentionMode - Change the comment retention mode of the lexer + /// to the specified mode. This is really only useful when lexing in raw + /// mode, because otherwise the lexer needs to manage this. + void SetCommentRetentionState(bool Mode) { + assert(!isKeepWhitespaceMode() && + "Can't play with comment retention state when retaining whitespace"); + ExtendedTokenMode = Mode ? 1 : 0; + } + + const char *getBufferStart() const { return BufferStart; } + + /// ReadToEndOfLine - Read the rest of the current preprocessor line as an + /// uninterpreted string. This switches the lexer out of directive mode. + std::string ReadToEndOfLine(); + + + /// Diag - Forwarding function for diagnostics. This translate a source + /// position in the current buffer into a SourceLocation object for rendering. + DiagnosticBuilder Diag(const char *Loc, unsigned DiagID) const; + + /// getSourceLocation - Return a source location identifier for the specified + /// offset in the current file. + SourceLocation getSourceLocation(const char *Loc, unsigned TokLen = 1) const; + + /// getSourceLocation - Return a source location for the next character in + /// the current file. + SourceLocation getSourceLocation() { return getSourceLocation(BufferPtr); } + + /// \brief Return the current location in the buffer. + const char *getBufferLocation() const { return BufferPtr; } + + /// Stringify - Convert the specified string into a C string by escaping '\' + /// and " characters. This does not add surrounding ""'s to the string. + /// If Charify is true, this escapes the ' character instead of ". + static std::string Stringify(const std::string &Str, bool Charify = false); + + /// Stringify - Convert the specified string into a C string by escaping '\' + /// and " characters. This does not add surrounding ""'s to the string. + static void Stringify(SmallVectorImpl<char> &Str); + + + /// getSpelling - This method is used to get the spelling of a token into a + /// preallocated buffer, instead of as an std::string. The caller is required + /// to allocate enough space for the token, which is guaranteed to be at least + /// Tok.getLength() bytes long. The length of the actual result is returned. + /// + /// Note that this method may do two possible things: it may either fill in + /// the buffer specified with characters, or it may *change the input pointer* + /// to point to a constant buffer with the data already in it (avoiding a + /// copy). The caller is not allowed to modify the returned buffer pointer + /// if an internal buffer is returned. + static unsigned getSpelling(const Token &Tok, const char *&Buffer, + const SourceManager &SourceMgr, + const LangOptions &LangOpts, + bool *Invalid = 0); + + /// getSpelling() - Return the 'spelling' of the Tok token. The spelling of a + /// token is the characters used to represent the token in the source file + /// after trigraph expansion and escaped-newline folding. In particular, this + /// wants to get the true, uncanonicalized, spelling of things like digraphs + /// UCNs, etc. + static std::string getSpelling(const Token &Tok, + const SourceManager &SourceMgr, + const LangOptions &LangOpts, + bool *Invalid = 0); + + /// getSpelling - This method is used to get the spelling of the + /// token at the given source location. If, as is usually true, it + /// is not necessary to copy any data, then the returned string may + /// not point into the provided buffer. + /// + /// This method lexes at the expansion depth of the given + /// location and does not jump to the expansion or spelling + /// location. + static StringRef getSpelling(SourceLocation loc, + SmallVectorImpl<char> &buffer, + const SourceManager &SourceMgr, + const LangOptions &LangOpts, + bool *invalid = 0); + + /// MeasureTokenLength - Relex the token at the specified location and return + /// its length in bytes in the input file. If the token needs cleaning (e.g. + /// includes a trigraph or an escaped newline) then this count includes bytes + /// that are part of that. + static unsigned MeasureTokenLength(SourceLocation Loc, + const SourceManager &SM, + const LangOptions &LangOpts); + + /// \brief Given a location any where in a source buffer, find the location + /// that corresponds to the beginning of the token in which the original + /// source location lands. + /// + /// \param Loc + static SourceLocation GetBeginningOfToken(SourceLocation Loc, + const SourceManager &SM, + const LangOptions &LangOpts); + + /// AdvanceToTokenCharacter - If the current SourceLocation specifies a + /// location at the start of a token, return a new location that specifies a + /// character within the token. This handles trigraphs and escaped newlines. + static SourceLocation AdvanceToTokenCharacter(SourceLocation TokStart, + unsigned Character, + const SourceManager &SM, + const LangOptions &LangOpts); + + /// \brief Computes the source location just past the end of the + /// token at this source location. + /// + /// This routine can be used to produce a source location that + /// points just past the end of the token referenced by \p Loc, and + /// is generally used when a diagnostic needs to point just after a + /// token where it expected something different that it received. If + /// the returned source location would not be meaningful (e.g., if + /// it points into a macro), this routine returns an invalid + /// source location. + /// + /// \param Offset an offset from the end of the token, where the source + /// location should refer to. The default offset (0) produces a source + /// location pointing just past the end of the token; an offset of 1 produces + /// a source location pointing to the last character in the token, etc. + static SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset, + const SourceManager &SM, + const LangOptions &LangOpts); + + /// \brief Returns true if the given MacroID location points at the first + /// token of the macro expansion. + /// + /// \param MacroBegin If non-null and function returns true, it is set to + /// begin location of the macro. + static bool isAtStartOfMacroExpansion(SourceLocation loc, + const SourceManager &SM, + const LangOptions &LangOpts, + SourceLocation *MacroBegin = 0); + + /// \brief Returns true if the given MacroID location points at the last + /// token of the macro expansion. + /// + /// \param MacroBegin If non-null and function returns true, it is set to + /// end location of the macro. + static bool isAtEndOfMacroExpansion(SourceLocation loc, + const SourceManager &SM, + const LangOptions &LangOpts, + SourceLocation *MacroEnd = 0); + + /// \brief Accepts a range and returns a character range with file locations. + /// + /// Returns a null range if a part of the range resides inside a macro + /// expansion or the range does not reside on the same FileID. + static CharSourceRange makeFileCharRange(CharSourceRange Range, + const SourceManager &SM, + const LangOptions &LangOpts); + + /// \brief Returns a string for the source that the range encompasses. + static StringRef getSourceText(CharSourceRange Range, + const SourceManager &SM, + const LangOptions &LangOpts, + bool *Invalid = 0); + + /// \brief Retrieve the name of the immediate macro expansion. + /// + /// This routine starts from a source location, and finds the name of the macro + /// responsible for its immediate expansion. It looks through any intervening + /// macro argument expansions to compute this. It returns a StringRef which + /// refers to the SourceManager-owned buffer of the source where that macro + /// name is spelled. Thus, the result shouldn't out-live that SourceManager. + static StringRef getImmediateMacroName(SourceLocation Loc, + const SourceManager &SM, + const LangOptions &LangOpts); + + /// \brief Compute the preamble of the given file. + /// + /// The preamble of a file contains the initial comments, include directives, + /// and other preprocessor directives that occur before the code in this + /// particular file actually begins. The preamble of the main source file is + /// a potential prefix header. + /// + /// \param Buffer The memory buffer containing the file's contents. + /// + /// \param MaxLines If non-zero, restrict the length of the preamble + /// to fewer than this number of lines. + /// + /// \returns The offset into the file where the preamble ends and the rest + /// of the file begins along with a boolean value indicating whether + /// the preamble ends at the beginning of a new line. + static std::pair<unsigned, bool> + ComputePreamble(const llvm::MemoryBuffer *Buffer, const LangOptions &LangOpts, + unsigned MaxLines = 0); + + //===--------------------------------------------------------------------===// + // Internal implementation interfaces. +private: + + /// LexTokenInternal - Internal interface to lex a preprocessing token. Called + /// by Lex. + /// + void LexTokenInternal(Token &Result); + + /// FormTokenWithChars - When we lex a token, we have identified a span + /// starting at BufferPtr, going to TokEnd that forms the token. This method + /// takes that range and assigns it to the token as its location and size. In + /// addition, since tokens cannot overlap, this also updates BufferPtr to be + /// TokEnd. + void FormTokenWithChars(Token &Result, const char *TokEnd, + tok::TokenKind Kind) { + unsigned TokLen = TokEnd-BufferPtr; + Result.setLength(TokLen); + Result.setLocation(getSourceLocation(BufferPtr, TokLen)); + Result.setKind(Kind); + BufferPtr = TokEnd; + } + + /// isNextPPTokenLParen - Return 1 if the next unexpanded token will return a + /// tok::l_paren token, 0 if it is something else and 2 if there are no more + /// tokens in the buffer controlled by this lexer. + unsigned isNextPPTokenLParen(); + + //===--------------------------------------------------------------------===// + // Lexer character reading interfaces. +public: + + // This lexer is built on two interfaces for reading characters, both of which + // automatically provide phase 1/2 translation. getAndAdvanceChar is used + // when we know that we will be reading a character from the input buffer and + // that this character will be part of the result token. This occurs in (f.e.) + // string processing, because we know we need to read until we find the + // closing '"' character. + // + // The second interface is the combination of getCharAndSize with + // ConsumeChar. getCharAndSize reads a phase 1/2 translated character, + // returning it and its size. If the lexer decides that this character is + // part of the current token, it calls ConsumeChar on it. This two stage + // approach allows us to emit diagnostics for characters (e.g. warnings about + // trigraphs), knowing that they only are emitted if the character is + // consumed. + + /// isObviouslySimpleCharacter - Return true if the specified character is + /// obviously the same in translation phase 1 and translation phase 3. This + /// can return false for characters that end up being the same, but it will + /// never return true for something that needs to be mapped. + static bool isObviouslySimpleCharacter(char C) { + return C != '?' && C != '\\'; + } + + /// getAndAdvanceChar - Read a single 'character' from the specified buffer, + /// advance over it, and return it. This is tricky in several cases. Here we + /// just handle the trivial case and fall-back to the non-inlined + /// getCharAndSizeSlow method to handle the hard case. + inline char getAndAdvanceChar(const char *&Ptr, Token &Tok) { + // If this is not a trigraph and not a UCN or escaped newline, return + // quickly. + if (isObviouslySimpleCharacter(Ptr[0])) return *Ptr++; + + unsigned Size = 0; + char C = getCharAndSizeSlow(Ptr, Size, &Tok); + Ptr += Size; + return C; + } + +private: + /// ConsumeChar - When a character (identified by getCharAndSize) is consumed + /// and added to a given token, check to see if there are diagnostics that + /// need to be emitted or flags that need to be set on the token. If so, do + /// it. + const char *ConsumeChar(const char *Ptr, unsigned Size, Token &Tok) { + // Normal case, we consumed exactly one token. Just return it. + if (Size == 1) + return Ptr+Size; + + // Otherwise, re-lex the character with a current token, allowing + // diagnostics to be emitted and flags to be set. + Size = 0; + getCharAndSizeSlow(Ptr, Size, &Tok); + return Ptr+Size; + } + + /// getCharAndSize - Peek a single 'character' from the specified buffer, + /// get its size, and return it. This is tricky in several cases. Here we + /// just handle the trivial case and fall-back to the non-inlined + /// getCharAndSizeSlow method to handle the hard case. + inline char getCharAndSize(const char *Ptr, unsigned &Size) { + // If this is not a trigraph and not a UCN or escaped newline, return + // quickly. + if (isObviouslySimpleCharacter(Ptr[0])) { + Size = 1; + return *Ptr; + } + + Size = 0; + return getCharAndSizeSlow(Ptr, Size); + } + + /// getCharAndSizeSlow - Handle the slow/uncommon case of the getCharAndSize + /// method. + char getCharAndSizeSlow(const char *Ptr, unsigned &Size, Token *Tok = 0); +public: + + /// getCharAndSizeNoWarn - Like the getCharAndSize method, but does not ever + /// emit a warning. + static inline char getCharAndSizeNoWarn(const char *Ptr, unsigned &Size, + const LangOptions &LangOpts) { + // If this is not a trigraph and not a UCN or escaped newline, return + // quickly. + if (isObviouslySimpleCharacter(Ptr[0])) { + Size = 1; + return *Ptr; + } + + Size = 0; + return getCharAndSizeSlowNoWarn(Ptr, Size, LangOpts); + } + + /// getEscapedNewLineSize - Return the size of the specified escaped newline, + /// or 0 if it is not an escaped newline. P[-1] is known to be a "\" on entry + /// to this function. + static unsigned getEscapedNewLineSize(const char *P); + + /// SkipEscapedNewLines - If P points to an escaped newline (or a series of + /// them), skip over them and return the first non-escaped-newline found, + /// otherwise return P. + static const char *SkipEscapedNewLines(const char *P); + + /// \brief Checks that the given token is the first token that occurs after + /// the given location (this excludes comments and whitespace). Returns the + /// location immediately after the specified token. If the token is not found + /// or the location is inside a macro, the returned source location will be + /// invalid. + static SourceLocation findLocationAfterToken(SourceLocation loc, + tok::TokenKind TKind, + const SourceManager &SM, + const LangOptions &LangOpts, + bool SkipTrailingWhitespaceAndNewLine); + +private: + + /// getCharAndSizeSlowNoWarn - Same as getCharAndSizeSlow, but never emits a + /// diagnostic. + static char getCharAndSizeSlowNoWarn(const char *Ptr, unsigned &Size, + const LangOptions &LangOpts); + + //===--------------------------------------------------------------------===// + // Other lexer functions. + + void SkipBytes(unsigned Bytes, bool StartOfLine); + + const char *LexUDSuffix(Token &Result, const char *CurPtr); + + // Helper functions to lex the remainder of a token of the specific type. + void LexIdentifier (Token &Result, const char *CurPtr); + void LexNumericConstant (Token &Result, const char *CurPtr); + void LexStringLiteral (Token &Result, const char *CurPtr, + tok::TokenKind Kind); + void LexRawStringLiteral (Token &Result, const char *CurPtr, + tok::TokenKind Kind); + void LexAngledStringLiteral(Token &Result, const char *CurPtr); + void LexCharConstant (Token &Result, const char *CurPtr, + tok::TokenKind Kind); + bool LexEndOfFile (Token &Result, const char *CurPtr); + + bool SkipWhitespace (Token &Result, const char *CurPtr); + bool SkipBCPLComment (Token &Result, const char *CurPtr); + bool SkipBlockComment (Token &Result, const char *CurPtr); + bool SaveBCPLComment (Token &Result, const char *CurPtr); + + bool IsStartOfConflictMarker(const char *CurPtr); + bool HandleEndOfConflictMarker(const char *CurPtr); + + bool isCodeCompletionPoint(const char *CurPtr) const; + void cutOffLexing() { BufferPtr = BufferEnd; } +}; + + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Lex/LiteralSupport.h b/clang/include/clang/Lex/LiteralSupport.h new file mode 100644 index 0000000..7e7f82f --- /dev/null +++ b/clang/include/clang/Lex/LiteralSupport.h @@ -0,0 +1,239 @@ +//===--- LiteralSupport.h ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the NumericLiteralParser, CharLiteralParser, and +// StringLiteralParser interfaces. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_LITERALSUPPORT_H +#define CLANG_LITERALSUPPORT_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/APFloat.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/DataTypes.h" +#include "clang/Basic/TokenKinds.h" +#include <cctype> + +namespace clang { + +class DiagnosticsEngine; +class Preprocessor; +class Token; +class SourceLocation; +class TargetInfo; +class SourceManager; +class LangOptions; + +/// NumericLiteralParser - This performs strict semantic analysis of the content +/// of a ppnumber, classifying it as either integer, floating, or erroneous, +/// determines the radix of the value and can convert it to a useful value. +class NumericLiteralParser { + Preprocessor &PP; // needed for diagnostics + + const char *const ThisTokBegin; + const char *const ThisTokEnd; + const char *DigitsBegin, *SuffixBegin; // markers + const char *s; // cursor + + unsigned radix; + + bool saw_exponent, saw_period, saw_ud_suffix; + +public: + NumericLiteralParser(const char *begin, const char *end, + SourceLocation Loc, Preprocessor &PP); + bool hadError; + bool isUnsigned; + bool isLong; // This is *not* set for long long. + bool isLongLong; + bool isFloat; // 1.0f + bool isImaginary; // 1.0i + bool isMicrosoftInteger; // Microsoft suffix extension i8, i16, i32, or i64. + + bool isIntegerLiteral() const { + return !saw_period && !saw_exponent; + } + bool isFloatingLiteral() const { + return saw_period || saw_exponent; + } + + bool hasUDSuffix() const { + return saw_ud_suffix; + } + StringRef getUDSuffix() const { + assert(saw_ud_suffix); + return StringRef(SuffixBegin, ThisTokEnd - SuffixBegin); + } + unsigned getUDSuffixOffset() const { + assert(saw_ud_suffix); + return SuffixBegin - ThisTokBegin; + } + + unsigned getRadix() const { return radix; } + + /// GetIntegerValue - Convert this numeric literal value to an APInt that + /// matches Val's input width. If there is an overflow (i.e., if the unsigned + /// value read is larger than the APInt's bits will hold), set Val to the low + /// bits of the result and return true. Otherwise, return false. + bool GetIntegerValue(llvm::APInt &Val); + + /// GetFloatValue - Convert this numeric literal to a floating value, using + /// the specified APFloat fltSemantics (specifying float, double, etc). + /// The optional bool isExact (passed-by-reference) has its value + /// set to true if the returned APFloat can represent the number in the + /// literal exactly, and false otherwise. + llvm::APFloat::opStatus GetFloatValue(llvm::APFloat &Result); + +private: + + void ParseNumberStartingWithZero(SourceLocation TokLoc); + + /// SkipHexDigits - Read and skip over any hex digits, up to End. + /// Return a pointer to the first non-hex digit or End. + const char *SkipHexDigits(const char *ptr) { + while (ptr != ThisTokEnd && isxdigit(*ptr)) + ptr++; + return ptr; + } + + /// SkipOctalDigits - Read and skip over any octal digits, up to End. + /// Return a pointer to the first non-hex digit or End. + const char *SkipOctalDigits(const char *ptr) { + while (ptr != ThisTokEnd && ((*ptr >= '0') && (*ptr <= '7'))) + ptr++; + return ptr; + } + + /// SkipDigits - Read and skip over any digits, up to End. + /// Return a pointer to the first non-hex digit or End. + const char *SkipDigits(const char *ptr) { + while (ptr != ThisTokEnd && isdigit(*ptr)) + ptr++; + return ptr; + } + + /// SkipBinaryDigits - Read and skip over any binary digits, up to End. + /// Return a pointer to the first non-binary digit or End. + const char *SkipBinaryDigits(const char *ptr) { + while (ptr != ThisTokEnd && (*ptr == '0' || *ptr == '1')) + ptr++; + return ptr; + } + +}; + +/// CharLiteralParser - Perform interpretation and semantic analysis of a +/// character literal. +class CharLiteralParser { + uint64_t Value; + tok::TokenKind Kind; + bool IsMultiChar; + bool HadError; + SmallString<32> UDSuffixBuf; + unsigned UDSuffixOffset; +public: + CharLiteralParser(const char *begin, const char *end, + SourceLocation Loc, Preprocessor &PP, + tok::TokenKind kind); + + bool hadError() const { return HadError; } + bool isAscii() const { return Kind == tok::char_constant; } + bool isWide() const { return Kind == tok::wide_char_constant; } + bool isUTF16() const { return Kind == tok::utf16_char_constant; } + bool isUTF32() const { return Kind == tok::utf32_char_constant; } + bool isMultiChar() const { return IsMultiChar; } + uint64_t getValue() const { return Value; } + StringRef getUDSuffix() const { return UDSuffixBuf; } + unsigned getUDSuffixOffset() const { + assert(!UDSuffixBuf.empty() && "no ud-suffix"); + return UDSuffixOffset; + } +}; + +/// StringLiteralParser - This decodes string escape characters and performs +/// wide string analysis and Translation Phase #6 (concatenation of string +/// literals) (C99 5.1.1.2p1). +class StringLiteralParser { + const SourceManager &SM; + const LangOptions &Features; + const TargetInfo &Target; + DiagnosticsEngine *Diags; + + unsigned MaxTokenLength; + unsigned SizeBound; + unsigned CharByteWidth; + tok::TokenKind Kind; + SmallString<512> ResultBuf; + char *ResultPtr; // cursor + SmallString<32> UDSuffixBuf; + unsigned UDSuffixToken; + unsigned UDSuffixOffset; +public: + StringLiteralParser(const Token *StringToks, unsigned NumStringToks, + Preprocessor &PP, bool Complain = true); + StringLiteralParser(const Token *StringToks, unsigned NumStringToks, + const SourceManager &sm, const LangOptions &features, + const TargetInfo &target, DiagnosticsEngine *diags = 0) + : SM(sm), Features(features), Target(target), Diags(diags), + MaxTokenLength(0), SizeBound(0), CharByteWidth(0), Kind(tok::unknown), + ResultPtr(ResultBuf.data()), hadError(false), Pascal(false) { + init(StringToks, NumStringToks); + } + + + bool hadError; + bool Pascal; + + StringRef GetString() const { + return StringRef(ResultBuf.data(), GetStringLength()); + } + unsigned GetStringLength() const { return ResultPtr-ResultBuf.data(); } + + unsigned GetNumStringChars() const { + return GetStringLength() / CharByteWidth; + } + /// getOffsetOfStringByte - This function returns the offset of the + /// specified byte of the string data represented by Token. This handles + /// advancing over escape sequences in the string. + /// + /// If the Diagnostics pointer is non-null, then this will do semantic + /// checking of the string literal and emit errors and warnings. + unsigned getOffsetOfStringByte(const Token &TheTok, unsigned ByteNo) const; + + bool isAscii() const { return Kind == tok::string_literal; } + bool isWide() const { return Kind == tok::wide_string_literal; } + bool isUTF8() const { return Kind == tok::utf8_string_literal; } + bool isUTF16() const { return Kind == tok::utf16_string_literal; } + bool isUTF32() const { return Kind == tok::utf32_string_literal; } + bool isPascal() const { return Pascal; } + + StringRef getUDSuffix() const { return UDSuffixBuf; } + + /// Get the index of a token containing a ud-suffix. + unsigned getUDSuffixToken() const { + assert(!UDSuffixBuf.empty() && "no ud-suffix"); + return UDSuffixToken; + } + /// Get the spelling offset of the first byte of the ud-suffix. + unsigned getUDSuffixOffset() const { + assert(!UDSuffixBuf.empty() && "no ud-suffix"); + return UDSuffixOffset; + } + +private: + void init(const Token *StringToks, unsigned NumStringToks); + bool CopyStringFragment(StringRef Fragment); + bool DiagnoseBadString(const Token& Tok); +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Lex/MacroInfo.h b/clang/include/clang/Lex/MacroInfo.h new file mode 100644 index 0000000..8775d39 --- /dev/null +++ b/clang/include/clang/Lex/MacroInfo.h @@ -0,0 +1,305 @@ +//===--- MacroInfo.h - Information about #defined identifiers ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the MacroInfo interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_MACROINFO_H +#define LLVM_CLANG_MACROINFO_H + +#include "clang/Lex/Token.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/Allocator.h" +#include <cassert> + +namespace clang { + class Preprocessor; + +/// MacroInfo - Each identifier that is #define'd has an instance of this class +/// associated with it, used to implement macro expansion. +class MacroInfo { + //===--------------------------------------------------------------------===// + // State set when the macro is defined. + + /// Location - This is the place the macro is defined. + SourceLocation Location; + /// EndLocation - The location of the last token in the macro. + SourceLocation EndLocation; + + /// Arguments - The list of arguments for a function-like macro. This can be + /// empty, for, e.g. "#define X()". In a C99-style variadic macro, this + /// includes the __VA_ARGS__ identifier on the list. + IdentifierInfo **ArgumentList; + unsigned NumArguments; + + /// \brief The location at which this macro was either explicitly exported + /// from its module or marked as private. + /// + /// If invalid, this macro has not been explicitly given any visibility. + SourceLocation VisibilityLocation; + + /// ReplacementTokens - This is the list of tokens that the macro is defined + /// to. + SmallVector<Token, 8> ReplacementTokens; + + /// \brief Length in characters of the macro definition. + mutable unsigned DefinitionLength; + mutable bool IsDefinitionLengthCached : 1; + + /// IsFunctionLike - True if this macro is a function-like macro, false if it + /// is an object-like macro. + bool IsFunctionLike : 1; + + /// IsC99Varargs - True if this macro is of the form "#define X(...)" or + /// "#define X(Y,Z,...)". The __VA_ARGS__ token should be replaced with the + /// contents of "..." in an invocation. + bool IsC99Varargs : 1; + + /// IsGNUVarargs - True if this macro is of the form "#define X(a...)". The + /// "a" identifier in the replacement list will be replaced with all arguments + /// of the macro starting with the specified one. + bool IsGNUVarargs : 1; + + /// IsBuiltinMacro - True if this is a builtin macro, such as __LINE__, and if + /// it has not yet been redefined or undefined. + bool IsBuiltinMacro : 1; + + /// IsFromAST - True if this macro was loaded from an AST file. + bool IsFromAST : 1; + + /// \brief Whether this macro changed after it was loaded from an AST file. + bool ChangedAfterLoad : 1; + +private: + //===--------------------------------------------------------------------===// + // State that changes as the macro is used. + + /// IsDisabled - True if we have started an expansion of this macro already. + /// This disbles recursive expansion, which would be quite bad for things like + /// #define A A. + bool IsDisabled : 1; + + /// IsUsed - True if this macro is either defined in the main file and has + /// been used, or if it is not defined in the main file. This is used to + /// emit -Wunused-macros diagnostics. + bool IsUsed : 1; + + /// AllowRedefinitionsWithoutWarning - True if this macro can be redefined + /// without emitting a warning. + bool IsAllowRedefinitionsWithoutWarning : 1; + + /// \brief Must warn if the macro is unused at the end of translation unit. + bool IsWarnIfUnused : 1; + + /// \brief Whether the macro has public (when described in a module). + bool IsPublic : 1; + + ~MacroInfo() { + assert(ArgumentList == 0 && "Didn't call destroy before dtor!"); + } + +public: + MacroInfo(SourceLocation DefLoc); + MacroInfo(const MacroInfo &MI, llvm::BumpPtrAllocator &PPAllocator); + + /// FreeArgumentList - Free the argument list of the macro, restoring it to a + /// state where it can be reused for other devious purposes. + void FreeArgumentList() { + ArgumentList = 0; + NumArguments = 0; + } + + /// Destroy - destroy this MacroInfo object. + void Destroy() { + FreeArgumentList(); + this->~MacroInfo(); + } + + /// getDefinitionLoc - Return the location that the macro was defined at. + /// + SourceLocation getDefinitionLoc() const { return Location; } + + /// setDefinitionEndLoc - Set the location of the last token in the macro. + /// + void setDefinitionEndLoc(SourceLocation EndLoc) { EndLocation = EndLoc; } + /// getDefinitionEndLoc - Return the location of the last token in the macro. + /// + SourceLocation getDefinitionEndLoc() const { return EndLocation; } + + /// \brief Get length in characters of the macro definition. + unsigned getDefinitionLength(SourceManager &SM) const { + if (IsDefinitionLengthCached) + return DefinitionLength; + return getDefinitionLengthSlow(SM); + } + + /// isIdenticalTo - Return true if the specified macro definition is equal to + /// this macro in spelling, arguments, and whitespace. This is used to emit + /// duplicate definition warnings. This implements the rules in C99 6.10.3. + bool isIdenticalTo(const MacroInfo &Other, Preprocessor &PP) const; + + /// setIsBuiltinMacro - Set or clear the isBuiltinMacro flag. + /// + void setIsBuiltinMacro(bool Val = true) { + IsBuiltinMacro = Val; + } + + /// setIsUsed - Set the value of the IsUsed flag. + /// + void setIsUsed(bool Val) { + IsUsed = Val; + } + + /// setIsAllowRedefinitionsWithoutWarning - Set the value of the + /// IsAllowRedefinitionsWithoutWarning flag. + void setIsAllowRedefinitionsWithoutWarning(bool Val) { + IsAllowRedefinitionsWithoutWarning = Val; + } + + /// \brief Set the value of the IsWarnIfUnused flag. + void setIsWarnIfUnused(bool val) { + IsWarnIfUnused = val; + } + + /// setArgumentList - Set the specified list of identifiers as the argument + /// list for this macro. + void setArgumentList(IdentifierInfo* const *List, unsigned NumArgs, + llvm::BumpPtrAllocator &PPAllocator) { + assert(ArgumentList == 0 && NumArguments == 0 && + "Argument list already set!"); + if (NumArgs == 0) return; + + NumArguments = NumArgs; + ArgumentList = PPAllocator.Allocate<IdentifierInfo*>(NumArgs); + for (unsigned i = 0; i != NumArgs; ++i) + ArgumentList[i] = List[i]; + } + + /// Arguments - The list of arguments for a function-like macro. This can be + /// empty, for, e.g. "#define X()". + typedef IdentifierInfo* const *arg_iterator; + bool arg_empty() const { return NumArguments == 0; } + arg_iterator arg_begin() const { return ArgumentList; } + arg_iterator arg_end() const { return ArgumentList+NumArguments; } + unsigned getNumArgs() const { return NumArguments; } + + /// getArgumentNum - Return the argument number of the specified identifier, + /// or -1 if the identifier is not a formal argument identifier. + int getArgumentNum(IdentifierInfo *Arg) const { + for (arg_iterator I = arg_begin(), E = arg_end(); I != E; ++I) + if (*I == Arg) return I-arg_begin(); + return -1; + } + + /// Function/Object-likeness. Keep track of whether this macro has formal + /// parameters. + void setIsFunctionLike() { IsFunctionLike = true; } + bool isFunctionLike() const { return IsFunctionLike; } + bool isObjectLike() const { return !IsFunctionLike; } + + /// Varargs querying methods. This can only be set for function-like macros. + void setIsC99Varargs() { IsC99Varargs = true; } + void setIsGNUVarargs() { IsGNUVarargs = true; } + bool isC99Varargs() const { return IsC99Varargs; } + bool isGNUVarargs() const { return IsGNUVarargs; } + bool isVariadic() const { return IsC99Varargs | IsGNUVarargs; } + + /// isBuiltinMacro - Return true if this macro is a builtin macro, such as + /// __LINE__, which requires processing before expansion. + bool isBuiltinMacro() const { return IsBuiltinMacro; } + + /// isFromAST - Return true if this macro was loaded from an AST file. + bool isFromAST() const { return IsFromAST; } + + /// setIsFromAST - Set whether this macro was loaded from an AST file. + void setIsFromAST(bool FromAST = true) { IsFromAST = FromAST; } + + /// \brief Determine whether this macro has changed since it was loaded from + /// an AST file. + bool hasChangedAfterLoad() const { return ChangedAfterLoad; } + + /// \brief Note whether this macro has changed after it was loaded from an + /// AST file. + void setChangedAfterLoad(bool CAL = true) { ChangedAfterLoad = CAL; } + + /// isUsed - Return false if this macro is defined in the main file and has + /// not yet been used. + bool isUsed() const { return IsUsed; } + + /// isAllowRedefinitionsWithoutWarning - Return true if this macro can be + /// redefined without warning. + bool isAllowRedefinitionsWithoutWarning() const { + return IsAllowRedefinitionsWithoutWarning; + } + + /// \brief Return true if we should emit a warning if the macro is unused. + bool isWarnIfUnused() const { + return IsWarnIfUnused; + } + + /// getNumTokens - Return the number of tokens that this macro expands to. + /// + unsigned getNumTokens() const { + return ReplacementTokens.size(); + } + + const Token &getReplacementToken(unsigned Tok) const { + assert(Tok < ReplacementTokens.size() && "Invalid token #"); + return ReplacementTokens[Tok]; + } + + typedef SmallVector<Token, 8>::const_iterator tokens_iterator; + tokens_iterator tokens_begin() const { return ReplacementTokens.begin(); } + tokens_iterator tokens_end() const { return ReplacementTokens.end(); } + bool tokens_empty() const { return ReplacementTokens.empty(); } + + /// AddTokenToBody - Add the specified token to the replacement text for the + /// macro. + void AddTokenToBody(const Token &Tok) { + assert(!IsDefinitionLengthCached && + "Changing replacement tokens after definition length got calculated"); + ReplacementTokens.push_back(Tok); + } + + /// isEnabled - Return true if this macro is enabled: in other words, that we + /// are not currently in an expansion of this macro. + bool isEnabled() const { return !IsDisabled; } + + void EnableMacro() { + assert(IsDisabled && "Cannot enable an already-enabled macro!"); + IsDisabled = false; + } + + void DisableMacro() { + assert(!IsDisabled && "Cannot disable an already-disabled macro!"); + IsDisabled = true; + } + + /// \brief Set the export location for this macro. + void setVisibility(bool Public, SourceLocation Loc) { + VisibilityLocation = Loc; + IsPublic = Public; + } + + /// \brief Determine whether this macro is part of the public API of its + /// module. + bool isPublic() const { return IsPublic; } + + /// \brief Determine the location where this macro was explicitly made + /// public or private within its module. + SourceLocation getVisibilityLocation() { return VisibilityLocation; } + +private: + unsigned getDefinitionLengthSlow(SourceManager &SM) const; +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Lex/Makefile b/clang/include/clang/Lex/Makefile new file mode 100644 index 0000000..762b9a2 --- /dev/null +++ b/clang/include/clang/Lex/Makefile @@ -0,0 +1,13 @@ +CLANG_LEVEL := ../../.. +TD_SRC_DIR = $(PROJ_SRC_DIR)/../Basic +BUILT_SOURCES = AttrSpellings.inc + +TABLEGEN_INC_FILES_COMMON = 1 + +include $(CLANG_LEVEL)/Makefile + +$(ObjDir)/AttrSpellings.inc.tmp : $(TD_SRC_DIR)/Attr.td $(CLANG_TBLGEN) \ + $(ObjDir)/.dir + $(Echo) "Building Clang attribute spellings with tblgen" + $(Verb) $(ClangTableGen) -gen-clang-attr-spelling-list -o $(call SYSPATH, $@) \ + -I $(PROJ_SRC_DIR)/../../ $< diff --git a/clang/include/clang/Lex/ModuleLoader.h b/clang/include/clang/Lex/ModuleLoader.h new file mode 100644 index 0000000..36d03c0 --- /dev/null +++ b/clang/include/clang/Lex/ModuleLoader.h @@ -0,0 +1,65 @@ +//===--- ModuleLoader.h - Module Loader Interface ---------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ModuleLoader interface, which is responsible for +// loading named modules. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_LEX_MODULE_LOADER_H +#define LLVM_CLANG_LEX_MODULE_LOADER_H + +#include "clang/Basic/Module.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/ArrayRef.h" + +namespace clang { + +class IdentifierInfo; + +/// \brief A sequence of identifier/location pairs used to describe a particular +/// module or submodule, e.g., std.vector. +typedef llvm::ArrayRef<std::pair<IdentifierInfo*, SourceLocation> > + ModuleIdPath; + +/// \brief Abstract interface for a module loader. +/// +/// This abstract interface describes a module loader, which is responsible +/// for resolving a module name (e.g., "std") to an actual module file, and +/// then loading that module. +class ModuleLoader { +public: + virtual ~ModuleLoader(); + + /// \brief Attempt to load the given module. + /// + /// This routine attempts to load the module described by the given + /// parameters. + /// + /// \param ImportLoc The location of the 'import' keyword. + /// + /// \param Path The identifiers (and their locations) of the module + /// "path", e.g., "std.vector" would be split into "std" and "vector". + /// + /// \param Visibility The visibility provided for the names in the loaded + /// module. + /// + /// \param IsInclusionDirective Indicates that this module is being loaded + /// implicitly, due to the presence of an inclusion directive. Otherwise, + /// it is being loaded due to an import declaration. + /// + /// \returns If successful, returns the loaded module. Otherwise, returns + /// NULL to indicate that the module could not be loaded. + virtual Module *loadModule(SourceLocation ImportLoc, ModuleIdPath Path, + Module::NameVisibilityKind Visibility, + bool IsInclusionDirective) = 0; +}; + +} + +#endif diff --git a/clang/include/clang/Lex/ModuleMap.h b/clang/include/clang/Lex/ModuleMap.h new file mode 100644 index 0000000..4ebb1d4 --- /dev/null +++ b/clang/include/clang/Lex/ModuleMap.h @@ -0,0 +1,237 @@ +//===--- ModuleMap.h - Describe the layout of modules -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ModuleMap interface, which describes the layout of a +// module as it relates to headers. +// +//===----------------------------------------------------------------------===// + + +#ifndef LLVM_CLANG_LEX_MODULEMAP_H +#define LLVM_CLANG_LEX_MODULEMAP_H + +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/Module.h" +#include "clang/Basic/SourceManager.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringMap.h" +#include <string> + +namespace clang { + +class DirectoryEntry; +class FileEntry; +class FileManager; +class DiagnosticConsumer; +class DiagnosticsEngine; +class ModuleMapParser; + +class ModuleMap { + SourceManager *SourceMgr; + IntrusiveRefCntPtr<DiagnosticsEngine> Diags; + const LangOptions &LangOpts; + const TargetInfo *Target; + + /// \brief The directory used for Clang-supplied, builtin include headers, + /// such as "stdint.h". + const DirectoryEntry *BuiltinIncludeDir; + + /// \brief Language options used to parse the module map itself. + /// + /// These are always simple C language options. + LangOptions MMapLangOpts; + + /// \brief The top-level modules that are known. + llvm::StringMap<Module *> Modules; + + /// \brief Mapping from each header to the module that owns the contents of the + /// that header. + llvm::DenseMap<const FileEntry *, Module *> Headers; + + /// \brief Mapping from directories with umbrella headers to the module + /// that is generated from the umbrella header. + /// + /// This mapping is used to map headers that haven't explicitly been named + /// in the module map over to the module that includes them via its umbrella + /// header. + llvm::DenseMap<const DirectoryEntry *, Module *> UmbrellaDirs; + + friend class ModuleMapParser; + + /// \brief Resolve the given export declaration into an actual export + /// declaration. + /// + /// \param Mod The module in which we're resolving the export declaration. + /// + /// \param Unresolved The export declaration to resolve. + /// + /// \param Complain Whether this routine should complain about unresolvable + /// exports. + /// + /// \returns The resolved export declaration, which will have a NULL pointer + /// if the export could not be resolved. + Module::ExportDecl + resolveExport(Module *Mod, const Module::UnresolvedExportDecl &Unresolved, + bool Complain); + +public: + /// \brief Construct a new module map. + /// + /// \param FileMgr The file manager used to find module files and headers. + /// This file manager should be shared with the header-search mechanism, since + /// they will refer to the same headers. + /// + /// \param DC A diagnostic consumer that will be cloned for use in generating + /// diagnostics. + /// + /// \param LangOpts Language options for this translation unit. + /// + /// \param Target The target for this translation unit. + ModuleMap(FileManager &FileMgr, const DiagnosticConsumer &DC, + const LangOptions &LangOpts, const TargetInfo *Target); + + /// \brief Destroy the module map. + /// + ~ModuleMap(); + + /// \brief Set the target information. + void setTarget(const TargetInfo &Target); + + /// \brief Set the directory that contains Clang-supplied include + /// files, such as our stdarg.h or tgmath.h. + void setBuiltinIncludeDir(const DirectoryEntry *Dir) { + BuiltinIncludeDir = Dir; + } + + /// \brief Retrieve the module that owns the given header file, if any. + /// + /// \param File The header file that is likely to be included. + /// + /// \returns The module that owns the given header file, or null to indicate + /// that no module owns this header file. + Module *findModuleForHeader(const FileEntry *File); + + /// \brief Determine whether the given header is part of a module + /// marked 'unavailable'. + bool isHeaderInUnavailableModule(const FileEntry *Header); + + /// \brief Retrieve a module with the given name. + /// + /// \param The name of the module to look up. + /// + /// \returns The named module, if known; otherwise, returns null. + Module *findModule(StringRef Name); + + /// \brief Retrieve a module with the given name using lexical name lookup, + /// starting at the given context. + /// + /// \param The name of the module to look up. + /// + /// \param Context The module context, from which we will perform lexical + /// name lookup. + /// + /// \returns The named module, if known; otherwise, returns null. + Module *lookupModuleUnqualified(StringRef Name, Module *Context); + + /// \brief Retrieve a module with the given name within the given context, + /// using direct (qualified) name lookup. + /// + /// \param The name of the module to look up. + /// + /// \param Context The module for which we will look for a submodule. If + /// null, we will look for a top-level module. + /// + /// \returns The named submodule, if known; otherwose, returns null. + Module *lookupModuleQualified(StringRef Name, Module *Context); + + /// \brief Find a new module or submodule, or create it if it does not already + /// exist. + /// + /// \param Name The name of the module to find or create. + /// + /// \param Parent The module that will act as the parent of this submodule, + /// or NULL to indicate that this is a top-level module. + /// + /// \param IsFramework Whether this is a framework module. + /// + /// \param IsExplicit Whether this is an explicit submodule. + /// + /// \returns The found or newly-created module, along with a boolean value + /// that will be true if the module is newly-created. + std::pair<Module *, bool> findOrCreateModule(StringRef Name, Module *Parent, + bool IsFramework, + bool IsExplicit); + + /// \brief Infer the contents of a framework module map from the given + /// framework directory. + Module *inferFrameworkModule(StringRef ModuleName, + const DirectoryEntry *FrameworkDir, + bool IsSystem, Module *Parent); + + /// \brief Retrieve the module map file containing the definition of the given + /// module. + /// + /// \param Module The module whose module map file will be returned, if known. + /// + /// \returns The file entry for the module map file containing the given + /// module, or NULL if the module definition was inferred. + const FileEntry *getContainingModuleMapFile(Module *Module); + + /// \brief Resolve all of the unresolved exports in the given module. + /// + /// \param Mod The module whose exports should be resolved. + /// + /// \param Complain Whether to emit diagnostics for failures. + /// + /// \returns true if any errors were encountered while resolving exports, + /// false otherwise. + bool resolveExports(Module *Mod, bool Complain); + + /// \brief Infers the (sub)module based on the given source location and + /// source manager. + /// + /// \param Loc The location within the source that we are querying, along + /// with its source manager. + /// + /// \returns The module that owns this source location, or null if no + /// module owns this source location. + Module *inferModuleFromLocation(FullSourceLoc Loc); + + /// \brief Sets the umbrella header of the given module to the given + /// header. + void setUmbrellaHeader(Module *Mod, const FileEntry *UmbrellaHeader); + + /// \brief Sets the umbrella directory of the given module to the given + /// directory. + void setUmbrellaDir(Module *Mod, const DirectoryEntry *UmbrellaDir); + + /// \brief Adds this header to the given module. + void addHeader(Module *Mod, const FileEntry *Header); + + /// \brief Parse the given module map file, and record any modules we + /// encounter. + /// + /// \param File The file to be parsed. + /// + /// \returns true if an error occurred, false otherwise. + bool parseModuleMapFile(const FileEntry *File); + + /// \brief Dump the contents of the module map, for debugging purposes. + void dump(); + + typedef llvm::StringMap<Module *>::const_iterator module_iterator; + module_iterator module_begin() const { return Modules.begin(); } + module_iterator module_end() const { return Modules.end(); } +}; + +} +#endif diff --git a/clang/include/clang/Lex/MultipleIncludeOpt.h b/clang/include/clang/Lex/MultipleIncludeOpt.h new file mode 100644 index 0000000..95b00df --- /dev/null +++ b/clang/include/clang/Lex/MultipleIncludeOpt.h @@ -0,0 +1,130 @@ +//===--- MultipleIncludeOpt.h - Header Multiple-Include Optzn ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the MultipleIncludeOpt interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_MULTIPLEINCLUDEOPT_H +#define LLVM_CLANG_MULTIPLEINCLUDEOPT_H + +namespace clang { +class IdentifierInfo; + +/// MultipleIncludeOpt - This class implements the simple state machine that the +/// Lexer class uses to detect files subject to the 'multiple-include' +/// optimization. The public methods in this class are triggered by various +/// events that occur when a file is lexed, and after the entire file is lexed, +/// information about which macro (if any) controls the header is returned. +class MultipleIncludeOpt { + /// ReadAnyTokens - This is set to false when a file is first opened and true + /// any time a token is returned to the client or a (non-multiple-include) + /// directive is parsed. When the final #endif is parsed this is reset back + /// to false, that way any tokens before the first #ifdef or after the last + /// #endif can be easily detected. + bool ReadAnyTokens; + + /// ReadAnyTokens - This is set to false when a file is first opened and true + /// any time a token is returned to the client or a (non-multiple-include) + /// directive is parsed. When the final #endif is parsed this is reset back + /// to false, that way any tokens before the first #ifdef or after the last + /// #endif can be easily detected. + bool DidMacroExpansion; + + /// TheMacro - The controlling macro for a file, if valid. + /// + const IdentifierInfo *TheMacro; +public: + MultipleIncludeOpt() { + ReadAnyTokens = false; + DidMacroExpansion = false; + TheMacro = 0; + } + + /// Invalidate - Permanently mark this file as not being suitable for the + /// include-file optimization. + void Invalidate() { + // If we have read tokens but have no controlling macro, the state-machine + // below can never "accept". + ReadAnyTokens = true; + TheMacro = 0; + } + + /// getHasReadAnyTokensVal - This is used for the #ifndef hande-shake at the + /// top of the file when reading preprocessor directives. Otherwise, reading + /// the "ifndef x" would count as reading tokens. + bool getHasReadAnyTokensVal() const { return ReadAnyTokens; } + + // If a token is read, remember that we have seen a side-effect in this file. + void ReadToken() { ReadAnyTokens = true; } + + /// ExpandedMacro - When a macro is expanded with this lexer as the current + /// buffer, this method is called to disable the MIOpt if needed. + void ExpandedMacro() { DidMacroExpansion = true; } + + /// EnterTopLevelIFNDEF - When entering a top-level #ifndef directive (or the + /// "#if !defined" equivalent) without any preceding tokens, this method is + /// called. + /// + /// Note, we don't care about the input value of 'ReadAnyTokens'. The caller + /// ensures that this is only called if there are no tokens read before the + /// #ifndef. The caller is required to do this, because reading the #if line + /// obviously reads in in tokens. + void EnterTopLevelIFNDEF(const IdentifierInfo *M) { + // If the macro is already set, this is after the top-level #endif. + if (TheMacro) + return Invalidate(); + + // If we have already expanded a macro by the end of the #ifndef line, then + // there is a macro expansion *in* the #ifndef line. This means that the + // condition could evaluate differently when subsequently #included. Reject + // this. + if (DidMacroExpansion) + return Invalidate(); + + // Remember that we're in the #if and that we have the macro. + ReadAnyTokens = true; + TheMacro = M; + } + + /// EnterTopLevelConditional - This is invoked when a top level conditional + /// (except #ifndef) is found. + void EnterTopLevelConditional() { + /// If a conditional directive (except #ifndef) is found at the top level, + /// there is a chunk of the file not guarded by the controlling macro. + Invalidate(); + } + + /// ExitTopLevelConditional - This method is called when the lexer exits the + /// top-level conditional. + void ExitTopLevelConditional() { + // If we have a macro, that means the top of the file was ok. Set our state + // back to "not having read any tokens" so we can detect anything after the + // #endif. + if (!TheMacro) return Invalidate(); + + // At this point, we haven't "read any tokens" but we do have a controlling + // macro. + ReadAnyTokens = false; + } + + /// GetControllingMacroAtEndOfFile - Once the entire file has been lexed, if + /// there is a controlling macro, return it. + const IdentifierInfo *GetControllingMacroAtEndOfFile() const { + // If we haven't read any tokens after the #endif, return the controlling + // macro if it's valid (if it isn't, it will be null). + if (!ReadAnyTokens) + return TheMacro; + return 0; + } +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Lex/PPCallbacks.h b/clang/include/clang/Lex/PPCallbacks.h new file mode 100644 index 0000000..33558c8 --- /dev/null +++ b/clang/include/clang/Lex/PPCallbacks.h @@ -0,0 +1,385 @@ +//===--- PPCallbacks.h - Callbacks for Preprocessor actions -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the PPCallbacks interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_PPCALLBACKS_H +#define LLVM_CLANG_LEX_PPCALLBACKS_H + +#include "clang/Lex/DirectoryLookup.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/DiagnosticIDs.h" +#include "llvm/ADT/StringRef.h" +#include <string> + +namespace clang { + class SourceLocation; + class Token; + class IdentifierInfo; + class MacroInfo; + +/// PPCallbacks - This interface provides a way to observe the actions of the +/// preprocessor as it does its thing. Clients can define their hooks here to +/// implement preprocessor level tools. +class PPCallbacks { +public: + virtual ~PPCallbacks(); + + enum FileChangeReason { + EnterFile, ExitFile, SystemHeaderPragma, RenameFile + }; + + /// FileChanged - This callback is invoked whenever a source file is + /// entered or exited. The SourceLocation indicates the new location, and + /// EnteringFile indicates whether this is because we are entering a new + /// #include'd file (when true) or whether we're exiting one because we ran + /// off the end (when false). + /// + /// \param PrevFID the file that was exited if \arg Reason is ExitFile. + virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason, + SrcMgr::CharacteristicKind FileType, + FileID PrevFID = FileID()) { + } + + /// FileSkipped - This callback is invoked whenever a source file is + /// skipped as the result of header guard optimization. ParentFile + /// is the file that #includes the skipped file. FilenameTok is the + /// token in ParentFile that indicates the skipped file. + virtual void FileSkipped(const FileEntry &ParentFile, + const Token &FilenameTok, + SrcMgr::CharacteristicKind FileType) { + } + + /// FileNotFound - This callback is invoked whenever an inclusion directive + /// results in a file-not-found error. + /// + /// \param FileName The name of the file being included, as written in the + /// source code. + /// + /// \param RecoveryPath If this client indicates that it can recover from + /// this missing file, the client should set this as an additional header + /// search patch. + /// + /// \returns true to indicate that the preprocessor should attempt to recover + /// by adding \p RecoveryPath as a header search path. + virtual bool FileNotFound(StringRef FileName, + SmallVectorImpl<char> &RecoveryPath) { + return false; + } + + /// \brief This callback is invoked whenever an inclusion directive of + /// any kind (\c #include, \c #import, etc.) has been processed, regardless + /// of whether the inclusion will actually result in an inclusion. + /// + /// \param HashLoc The location of the '#' that starts the inclusion + /// directive. + /// + /// \param IncludeTok The token that indicates the kind of inclusion + /// directive, e.g., 'include' or 'import'. + /// + /// \param FileName The name of the file being included, as written in the + /// source code. + /// + /// \param IsAngled Whether the file name was enclosed in angle brackets; + /// otherwise, it was enclosed in quotes. + /// + /// \param File The actual file that may be included by this inclusion + /// directive. + /// + /// \param EndLoc The location of the last token within the inclusion + /// directive. + /// + /// \param SearchPath Contains the search path which was used to find the file + /// in the file system. If the file was found via an absolute include path, + /// SearchPath will be empty. For framework includes, the SearchPath and + /// RelativePath will be split up. For example, if an include of "Some/Some.h" + /// is found via the framework path + /// "path/to/Frameworks/Some.framework/Headers/Some.h", SearchPath will be + /// "path/to/Frameworks/Some.framework/Headers" and RelativePath will be + /// "Some.h". + /// + /// \param RelativePath The path relative to SearchPath, at which the include + /// file was found. This is equal to FileName except for framework includes. + virtual void InclusionDirective(SourceLocation HashLoc, + const Token &IncludeTok, + StringRef FileName, + bool IsAngled, + const FileEntry *File, + SourceLocation EndLoc, + StringRef SearchPath, + StringRef RelativePath) { + } + + /// EndOfMainFile - This callback is invoked when the end of the main file is + /// reach, no subsequent callbacks will be made. + virtual void EndOfMainFile() { + } + + /// Ident - This callback is invoked when a #ident or #sccs directive is read. + /// \param Loc The location of the directive. + /// \param str The text of the directive. + /// + virtual void Ident(SourceLocation Loc, const std::string &str) { + } + + /// PragmaComment - This callback is invoked when a #pragma comment directive + /// is read. + /// + virtual void PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind, + const std::string &Str) { + } + + /// PragmaMessage - This callback is invoked when a #pragma message directive + /// is read. + /// \param Loc The location of the message directive. + /// \param str The text of the message directive. + /// + virtual void PragmaMessage(SourceLocation Loc, StringRef Str) { + } + + /// PragmaDiagnosticPush - This callback is invoked when a + /// #pragma gcc dianostic push directive is read. + virtual void PragmaDiagnosticPush(SourceLocation Loc, + StringRef Namespace) { + } + + /// PragmaDiagnosticPop - This callback is invoked when a + /// #pragma gcc dianostic pop directive is read. + virtual void PragmaDiagnosticPop(SourceLocation Loc, + StringRef Namespace) { + } + + /// PragmaDiagnostic - This callback is invoked when a + /// #pragma gcc dianostic directive is read. + virtual void PragmaDiagnostic(SourceLocation Loc, StringRef Namespace, + diag::Mapping mapping, StringRef Str) { + } + + /// MacroExpands - This is called by + /// Preprocessor::HandleMacroExpandedIdentifier when a macro invocation is + /// found. + virtual void MacroExpands(const Token &MacroNameTok, const MacroInfo* MI, + SourceRange Range) { + } + + /// MacroDefined - This hook is called whenever a macro definition is seen. + virtual void MacroDefined(const Token &MacroNameTok, const MacroInfo *MI) { + } + + /// MacroUndefined - This hook is called whenever a macro #undef is seen. + /// MI is released immediately following this callback. + virtual void MacroUndefined(const Token &MacroNameTok, const MacroInfo *MI) { + } + + /// Defined - This hook is called whenever the 'defined' operator is seen. + virtual void Defined(const Token &MacroNameTok) { + } + + /// SourceRangeSkipped - This hook is called when a source range is skipped. + /// \param Range The SourceRange that was skipped. The range begins at the + /// #if/#else directive and ends after the #endif/#else directive. + virtual void SourceRangeSkipped(SourceRange Range) { + } + + /// If -- This hook is called whenever an #if is seen. + /// \param Loc the source location of the directive. + /// \param ConditionRange The SourceRange of the expression being tested. + // FIXME: better to pass in a list (or tree!) of Tokens. + virtual void If(SourceLocation Loc, SourceRange ConditionRange) { + } + + /// Elif -- This hook is called whenever an #elif is seen. + /// \param Loc the source location of the directive. + /// \param ConditionRange The SourceRange of the expression being tested. + /// \param IfLoc the source location of the #if/#ifdef/#ifndef directive. + // FIXME: better to pass in a list (or tree!) of Tokens. + virtual void Elif(SourceLocation Loc, SourceRange ConditionRange, + SourceLocation IfLoc) { + } + + /// Ifdef -- This hook is called whenever an #ifdef is seen. + /// \param Loc the source location of the directive. + /// \param II Information on the token being tested. + virtual void Ifdef(SourceLocation Loc, const Token &MacroNameTok) { + } + + /// Ifndef -- This hook is called whenever an #ifndef is seen. + /// \param Loc the source location of the directive. + /// \param II Information on the token being tested. + virtual void Ifndef(SourceLocation Loc, const Token &MacroNameTok) { + } + + /// Else -- This hook is called whenever an #else is seen. + /// \param Loc the source location of the directive. + /// \param IfLoc the source location of the #if/#ifdef/#ifndef directive. + virtual void Else(SourceLocation Loc, SourceLocation IfLoc) { + } + + /// Endif -- This hook is called whenever an #endif is seen. + /// \param Loc the source location of the directive. + /// \param IfLoc the source location of the #if/#ifdef/#ifndef directive. + virtual void Endif(SourceLocation Loc, SourceLocation IfLoc) { + } +}; + +/// PPChainedCallbacks - Simple wrapper class for chaining callbacks. +class PPChainedCallbacks : public PPCallbacks { + virtual void anchor(); + PPCallbacks *First, *Second; + +public: + PPChainedCallbacks(PPCallbacks *_First, PPCallbacks *_Second) + : First(_First), Second(_Second) {} + ~PPChainedCallbacks() { + delete Second; + delete First; + } + + virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason, + SrcMgr::CharacteristicKind FileType, + FileID PrevFID) { + First->FileChanged(Loc, Reason, FileType, PrevFID); + Second->FileChanged(Loc, Reason, FileType, PrevFID); + } + + virtual void FileSkipped(const FileEntry &ParentFile, + const Token &FilenameTok, + SrcMgr::CharacteristicKind FileType) { + First->FileSkipped(ParentFile, FilenameTok, FileType); + Second->FileSkipped(ParentFile, FilenameTok, FileType); + } + + virtual bool FileNotFound(StringRef FileName, + SmallVectorImpl<char> &RecoveryPath) { + return First->FileNotFound(FileName, RecoveryPath) || + Second->FileNotFound(FileName, RecoveryPath); + } + + virtual void InclusionDirective(SourceLocation HashLoc, + const Token &IncludeTok, + StringRef FileName, + bool IsAngled, + const FileEntry *File, + SourceLocation EndLoc, + StringRef SearchPath, + StringRef RelativePath) { + First->InclusionDirective(HashLoc, IncludeTok, FileName, IsAngled, File, + EndLoc, SearchPath, RelativePath); + Second->InclusionDirective(HashLoc, IncludeTok, FileName, IsAngled, File, + EndLoc, SearchPath, RelativePath); + } + + virtual void EndOfMainFile() { + First->EndOfMainFile(); + Second->EndOfMainFile(); + } + + virtual void Ident(SourceLocation Loc, const std::string &str) { + First->Ident(Loc, str); + Second->Ident(Loc, str); + } + + virtual void PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind, + const std::string &Str) { + First->PragmaComment(Loc, Kind, Str); + Second->PragmaComment(Loc, Kind, Str); + } + + virtual void PragmaMessage(SourceLocation Loc, StringRef Str) { + First->PragmaMessage(Loc, Str); + Second->PragmaMessage(Loc, Str); + } + + virtual void PragmaDiagnosticPush(SourceLocation Loc, + StringRef Namespace) { + First->PragmaDiagnosticPush(Loc, Namespace); + Second->PragmaDiagnosticPush(Loc, Namespace); + } + + virtual void PragmaDiagnosticPop(SourceLocation Loc, + StringRef Namespace) { + First->PragmaDiagnosticPop(Loc, Namespace); + Second->PragmaDiagnosticPop(Loc, Namespace); + } + + virtual void PragmaDiagnostic(SourceLocation Loc, StringRef Namespace, + diag::Mapping mapping, StringRef Str) { + First->PragmaDiagnostic(Loc, Namespace, mapping, Str); + Second->PragmaDiagnostic(Loc, Namespace, mapping, Str); + } + + virtual void MacroExpands(const Token &MacroNameTok, const MacroInfo* MI, + SourceRange Range) { + First->MacroExpands(MacroNameTok, MI, Range); + Second->MacroExpands(MacroNameTok, MI, Range); + } + + virtual void MacroDefined(const Token &MacroNameTok, const MacroInfo *MI) { + First->MacroDefined(MacroNameTok, MI); + Second->MacroDefined(MacroNameTok, MI); + } + + virtual void MacroUndefined(const Token &MacroNameTok, const MacroInfo *MI) { + First->MacroUndefined(MacroNameTok, MI); + Second->MacroUndefined(MacroNameTok, MI); + } + + virtual void Defined(const Token &MacroNameTok) { + First->Defined(MacroNameTok); + Second->Defined(MacroNameTok); + } + + virtual void SourceRangeSkipped(SourceRange Range) { + First->SourceRangeSkipped(Range); + Second->SourceRangeSkipped(Range); + } + + /// If -- This hook is called whenever an #if is seen. + virtual void If(SourceLocation Loc, SourceRange ConditionRange) { + First->If(Loc, ConditionRange); + Second->If(Loc, ConditionRange); + } + + /// Elif -- This hook is called whenever an #if is seen. + virtual void Elif(SourceLocation Loc, SourceRange ConditionRange, + SourceLocation IfLoc) { + First->Elif(Loc, ConditionRange, IfLoc); + Second->Elif(Loc, ConditionRange, IfLoc); + } + + /// Ifdef -- This hook is called whenever an #ifdef is seen. + virtual void Ifdef(SourceLocation Loc, const Token &MacroNameTok) { + First->Ifdef(Loc, MacroNameTok); + Second->Ifdef(Loc, MacroNameTok); + } + + /// Ifndef -- This hook is called whenever an #ifndef is seen. + virtual void Ifndef(SourceLocation Loc, const Token &MacroNameTok) { + First->Ifndef(Loc, MacroNameTok); + Second->Ifndef(Loc, MacroNameTok); + } + + /// Else -- This hook is called whenever an #else is seen. + virtual void Else(SourceLocation Loc, SourceLocation IfLoc) { + First->Else(Loc, IfLoc); + Second->Else(Loc, IfLoc); + } + + /// Endif -- This hook is called whenever an #endif is seen. + virtual void Endif(SourceLocation Loc, SourceLocation IfLoc) { + First->Endif(Loc, IfLoc); + Second->Endif(Loc, IfLoc); + } +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Lex/PTHLexer.h b/clang/include/clang/Lex/PTHLexer.h new file mode 100644 index 0000000..f6a97a0 --- /dev/null +++ b/clang/include/clang/Lex/PTHLexer.h @@ -0,0 +1,105 @@ +//===--- PTHLexer.h - Lexer based on Pre-tokenized input --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the PTHLexer interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_PTHLEXER_H +#define LLVM_CLANG_PTHLEXER_H + +#include "clang/Lex/PreprocessorLexer.h" + +namespace clang { + +class PTHManager; +class PTHSpellingSearch; + +class PTHLexer : public PreprocessorLexer { + SourceLocation FileStartLoc; + + /// TokBuf - Buffer from PTH file containing raw token data. + const unsigned char* TokBuf; + + /// CurPtr - Pointer into current offset of the token buffer where + /// the next token will be read. + const unsigned char* CurPtr; + + /// LastHashTokPtr - Pointer into TokBuf of the last processed '#' + /// token that appears at the start of a line. + const unsigned char* LastHashTokPtr; + + /// PPCond - Pointer to a side table in the PTH file that provides a + /// a consise summary of the preproccessor conditional block structure. + /// This is used to perform quick skipping of conditional blocks. + const unsigned char* PPCond; + + /// CurPPCondPtr - Pointer inside PPCond that refers to the next entry + /// to process when doing quick skipping of preprocessor blocks. + const unsigned char* CurPPCondPtr; + + PTHLexer(const PTHLexer&); // DO NOT IMPLEMENT + void operator=(const PTHLexer&); // DO NOT IMPLEMENT + + /// ReadToken - Used by PTHLexer to read tokens TokBuf. + void ReadToken(Token& T); + + bool LexEndOfFile(Token &Result); + + /// PTHMgr - The PTHManager object that created this PTHLexer. + PTHManager& PTHMgr; + + Token EofToken; + +protected: + friend class PTHManager; + + /// Create a PTHLexer for the specified token stream. + PTHLexer(Preprocessor& pp, FileID FID, const unsigned char *D, + const unsigned char* ppcond, PTHManager &PM); +public: + + ~PTHLexer() {} + + /// Lex - Return the next token. + void Lex(Token &Tok); + + void getEOF(Token &Tok); + + /// DiscardToEndOfLine - Read the rest of the current preprocessor line as an + /// uninterpreted string. This switches the lexer out of directive mode. + void DiscardToEndOfLine(); + + /// isNextPPTokenLParen - Return 1 if the next unexpanded token will return a + /// tok::l_paren token, 0 if it is something else and 2 if there are no more + /// tokens controlled by this lexer. + unsigned isNextPPTokenLParen() { + // isNextPPTokenLParen is not on the hot path, and all we care about is + // whether or not we are at a token with kind tok::eof or tok::l_paren. + // Just read the first byte from the current token pointer to determine + // its kind. + tok::TokenKind x = (tok::TokenKind)*CurPtr; + return x == tok::eof ? 2 : x == tok::l_paren; + } + + /// IndirectLex - An indirect call to 'Lex' that can be invoked via + /// the PreprocessorLexer interface. + void IndirectLex(Token &Result) { Lex(Result); } + + /// getSourceLocation - Return a source location for the token in + /// the current file. + SourceLocation getSourceLocation(); + + /// SkipBlock - Used by Preprocessor to skip the current conditional block. + bool SkipBlock(); +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Lex/PTHManager.h b/clang/include/clang/Lex/PTHManager.h new file mode 100644 index 0000000..25a4903 --- /dev/null +++ b/clang/include/clang/Lex/PTHManager.h @@ -0,0 +1,140 @@ +//===--- PTHManager.h - Manager object for PTH processing -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the PTHManager interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_PTHMANAGER_H +#define LLVM_CLANG_PTHMANAGER_H + +#include "clang/Lex/PTHLexer.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/Diagnostic.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/Support/Allocator.h" +#include <string> + +namespace llvm { + class MemoryBuffer; +} + +namespace clang { + +class FileEntry; +class PTHLexer; +class DiagnosticsEngine; +class FileSystemStatCache; + +class PTHManager : public IdentifierInfoLookup { + friend class PTHLexer; + + /// The memory mapped PTH file. + const llvm::MemoryBuffer* Buf; + + /// Alloc - Allocator used for IdentifierInfo objects. + llvm::BumpPtrAllocator Alloc; + + /// IdMap - A lazily generated cache mapping from persistent identifiers to + /// IdentifierInfo*. + IdentifierInfo** PerIDCache; + + /// FileLookup - Abstract data structure used for mapping between files + /// and token data in the PTH file. + void* FileLookup; + + /// IdDataTable - Array representing the mapping from persistent IDs to the + /// data offset within the PTH file containing the information to + /// reconsitute an IdentifierInfo. + const unsigned char* const IdDataTable; + + /// SortedIdTable - Abstract data structure mapping from strings to + /// persistent IDs. This is used by get(). + void* StringIdLookup; + + /// NumIds - The number of identifiers in the PTH file. + const unsigned NumIds; + + /// PP - The Preprocessor object that will use this PTHManager to create + /// PTHLexer objects. + Preprocessor* PP; + + /// SpellingBase - The base offset within the PTH memory buffer that + /// contains the cached spellings for literals. + const unsigned char* const SpellingBase; + + /// OriginalSourceFile - A null-terminated C-string that specifies the name + /// if the file (if any) that was to used to generate the PTH cache. + const char* OriginalSourceFile; + + /// This constructor is intended to only be called by the static 'Create' + /// method. + PTHManager(const llvm::MemoryBuffer* buf, void* fileLookup, + const unsigned char* idDataTable, IdentifierInfo** perIDCache, + void* stringIdLookup, unsigned numIds, + const unsigned char* spellingBase, const char *originalSourceFile); + + // Do not implement. + PTHManager(); + void operator=(const PTHManager&); + + /// getSpellingAtPTHOffset - Used by PTHLexer classes to get the cached + /// spelling for a token. + unsigned getSpellingAtPTHOffset(unsigned PTHOffset, const char*& Buffer); + + /// GetIdentifierInfo - Used to reconstruct IdentifierInfo objects from the + /// PTH file. + inline IdentifierInfo* GetIdentifierInfo(unsigned PersistentID) { + // Check if the IdentifierInfo has already been resolved. + if (IdentifierInfo* II = PerIDCache[PersistentID]) + return II; + return LazilyCreateIdentifierInfo(PersistentID); + } + IdentifierInfo* LazilyCreateIdentifierInfo(unsigned PersistentID); + +public: + // The current PTH version. + enum { Version = 9 }; + + ~PTHManager(); + + /// getOriginalSourceFile - Return the full path to the original header + /// file name that was used to generate the PTH cache. + const char* getOriginalSourceFile() const { + return OriginalSourceFile; + } + + /// get - Return the identifier token info for the specified named identifier. + /// Unlike the version in IdentifierTable, this returns a pointer instead + /// of a reference. If the pointer is NULL then the IdentifierInfo cannot + /// be found. + IdentifierInfo *get(StringRef Name); + + /// Create - This method creates PTHManager objects. The 'file' argument + /// is the name of the PTH file. This method returns NULL upon failure. + static PTHManager *Create(const std::string& file, DiagnosticsEngine &Diags); + + void setPreprocessor(Preprocessor *pp) { PP = pp; } + + /// CreateLexer - Return a PTHLexer that "lexes" the cached tokens for the + /// specified file. This method returns NULL if no cached tokens exist. + /// It is the responsibility of the caller to 'delete' the returned object. + PTHLexer *CreateLexer(FileID FID); + + /// createStatCache - Returns a FileSystemStatCache object for use with + /// FileManager objects. These objects use the PTH data to speed up + /// calls to stat by memoizing their results from when the PTH file + /// was generated. + FileSystemStatCache *createStatCache(); +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Lex/Pragma.h b/clang/include/clang/Lex/Pragma.h new file mode 100644 index 0000000..4868811 --- /dev/null +++ b/clang/include/clang/Lex/Pragma.h @@ -0,0 +1,126 @@ +//===--- Pragma.h - Pragma registration and handling ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the PragmaHandler and PragmaTable interfaces. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_PRAGMA_H +#define LLVM_CLANG_PRAGMA_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include <cassert> + +namespace clang { + class Preprocessor; + class Token; + class IdentifierInfo; + class PragmaNamespace; + + /** + * \brief Describes how the pragma was introduced, e.g., with #pragma, + * _Pragma, or __pragma. + */ + enum PragmaIntroducerKind { + /** + * \brief The pragma was introduced via #pragma. + */ + PIK_HashPragma, + + /** + * \brief The pragma was introduced via the C99 _Pragma(string-literal). + */ + PIK__Pragma, + + /** + * \brief The pragma was introduced via the Microsoft + * __pragma(token-string). + */ + PIK___pragma + }; + +/// PragmaHandler - Instances of this interface defined to handle the various +/// pragmas that the language front-end uses. Each handler optionally has a +/// name (e.g. "pack") and the HandlePragma method is invoked when a pragma with +/// that identifier is found. If a handler does not match any of the declared +/// pragmas the handler with a null identifier is invoked, if it exists. +/// +/// Note that the PragmaNamespace class can be used to subdivide pragmas, e.g. +/// we treat "#pragma STDC" and "#pragma GCC" as namespaces that contain other +/// pragmas. +class PragmaHandler { + std::string Name; +public: + explicit PragmaHandler(StringRef name) : Name(name) {} + PragmaHandler() {} + virtual ~PragmaHandler(); + + StringRef getName() const { return Name; } + virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &FirstToken) = 0; + + /// getIfNamespace - If this is a namespace, return it. This is equivalent to + /// using a dynamic_cast, but doesn't require RTTI. + virtual PragmaNamespace *getIfNamespace() { return 0; } +}; + +/// EmptyPragmaHandler - A pragma handler which takes no action, which can be +/// used to ignore particular pragmas. +class EmptyPragmaHandler : public PragmaHandler { +public: + EmptyPragmaHandler(); + + virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &FirstToken); +}; + +/// PragmaNamespace - This PragmaHandler subdivides the namespace of pragmas, +/// allowing hierarchical pragmas to be defined. Common examples of namespaces +/// are "#pragma GCC", "#pragma STDC", and "#pragma omp", but any namespaces may +/// be (potentially recursively) defined. +class PragmaNamespace : public PragmaHandler { + /// Handlers - This is a map of the handlers in this namespace with their name + /// as key. + /// + llvm::StringMap<PragmaHandler*> Handlers; +public: + explicit PragmaNamespace(StringRef Name) : PragmaHandler(Name) {} + virtual ~PragmaNamespace(); + + /// FindHandler - Check to see if there is already a handler for the + /// specified name. If not, return the handler for the null name if it + /// exists, otherwise return null. If IgnoreNull is true (the default) then + /// the null handler isn't returned on failure to match. + PragmaHandler *FindHandler(StringRef Name, + bool IgnoreNull = true) const; + + /// AddPragma - Add a pragma to this namespace. + /// + void AddPragma(PragmaHandler *Handler); + + /// RemovePragmaHandler - Remove the given handler from the + /// namespace. + void RemovePragmaHandler(PragmaHandler *Handler); + + bool IsEmpty() { + return Handlers.empty(); + } + + virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &FirstToken); + + virtual PragmaNamespace *getIfNamespace() { return this; } +}; + + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Lex/PreprocessingRecord.h b/clang/include/clang/Lex/PreprocessingRecord.h new file mode 100644 index 0000000..45e3a5d --- /dev/null +++ b/clang/include/clang/Lex/PreprocessingRecord.h @@ -0,0 +1,637 @@ +//===--- PreprocessingRecord.h - Record of Preprocessing --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the PreprocessingRecord class, which maintains a record +// of what occurred during preprocessing. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_LEX_PREPROCESSINGRECORD_H +#define LLVM_CLANG_LEX_PREPROCESSINGRECORD_H + +#include "clang/Lex/PPCallbacks.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/IdentifierTable.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/Optional.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/Compiler.h" +#include <vector> + +namespace clang { + class IdentifierInfo; + class PreprocessingRecord; +} + +/// \brief Allocates memory within a Clang preprocessing record. +void* operator new(size_t bytes, clang::PreprocessingRecord& PR, + unsigned alignment = 8) throw(); + +/// \brief Frees memory allocated in a Clang preprocessing record. +void operator delete(void* ptr, clang::PreprocessingRecord& PR, + unsigned) throw(); + +namespace clang { + class MacroDefinition; + class FileEntry; + + /// \brief Base class that describes a preprocessed entity, which may be a + /// preprocessor directive or macro expansion. + class PreprocessedEntity { + public: + /// \brief The kind of preprocessed entity an object describes. + enum EntityKind { + /// \brief Indicates a problem trying to load the preprocessed entity. + InvalidKind, + + /// \brief A macro expansion. + MacroExpansionKind, + + /// \defgroup Preprocessing directives + /// @{ + + /// \brief A macro definition. + MacroDefinitionKind, + + /// \brief An inclusion directive, such as \c #include, \c + /// #import, or \c #include_next. + InclusionDirectiveKind, + + /// @} + + FirstPreprocessingDirective = MacroDefinitionKind, + LastPreprocessingDirective = InclusionDirectiveKind + }; + + private: + /// \brief The kind of preprocessed entity that this object describes. + EntityKind Kind; + + /// \brief The source range that covers this preprocessed entity. + SourceRange Range; + + protected: + PreprocessedEntity(EntityKind Kind, SourceRange Range) + : Kind(Kind), Range(Range) { } + + friend class PreprocessingRecord; + + public: + /// \brief Retrieve the kind of preprocessed entity stored in this object. + EntityKind getKind() const { return Kind; } + + /// \brief Retrieve the source range that covers this entire preprocessed + /// entity. + SourceRange getSourceRange() const LLVM_READONLY { return Range; } + + /// \brief Returns true if there was a problem loading the preprocessed + /// entity. + bool isInvalid() const { return Kind == InvalidKind; } + + // Implement isa/cast/dyncast/etc. + static bool classof(const PreprocessedEntity *) { return true; } + + // Only allow allocation of preprocessed entities using the allocator + // in PreprocessingRecord or by doing a placement new. + void* operator new(size_t bytes, PreprocessingRecord& PR, + unsigned alignment = 8) throw() { + return ::operator new(bytes, PR, alignment); + } + + void* operator new(size_t bytes, void* mem) throw() { + return mem; + } + + void operator delete(void* ptr, PreprocessingRecord& PR, + unsigned alignment) throw() { + return ::operator delete(ptr, PR, alignment); + } + + void operator delete(void*, std::size_t) throw() { } + void operator delete(void*, void*) throw() { } + + private: + // Make vanilla 'new' and 'delete' illegal for preprocessed entities. + void* operator new(size_t bytes) throw(); + void operator delete(void* data) throw(); + }; + + /// \brief Records the presence of a preprocessor directive. + class PreprocessingDirective : public PreprocessedEntity { + public: + PreprocessingDirective(EntityKind Kind, SourceRange Range) + : PreprocessedEntity(Kind, Range) { } + + // Implement isa/cast/dyncast/etc. + static bool classof(const PreprocessedEntity *PD) { + return PD->getKind() >= FirstPreprocessingDirective && + PD->getKind() <= LastPreprocessingDirective; + } + static bool classof(const PreprocessingDirective *) { return true; } + }; + + /// \brief Record the location of a macro definition. + class MacroDefinition : public PreprocessingDirective { + /// \brief The name of the macro being defined. + const IdentifierInfo *Name; + + public: + explicit MacroDefinition(const IdentifierInfo *Name, SourceRange Range) + : PreprocessingDirective(MacroDefinitionKind, Range), Name(Name) { } + + /// \brief Retrieve the name of the macro being defined. + const IdentifierInfo *getName() const { return Name; } + + /// \brief Retrieve the location of the macro name in the definition. + SourceLocation getLocation() const { return getSourceRange().getBegin(); } + + // Implement isa/cast/dyncast/etc. + static bool classof(const PreprocessedEntity *PE) { + return PE->getKind() == MacroDefinitionKind; + } + static bool classof(const MacroDefinition *) { return true; } + }; + + /// \brief Records the location of a macro expansion. + class MacroExpansion : public PreprocessedEntity { + /// \brief The definition of this macro or the name of the macro if it is + /// a builtin macro. + llvm::PointerUnion<IdentifierInfo *, MacroDefinition *> NameOrDef; + + public: + MacroExpansion(IdentifierInfo *BuiltinName, SourceRange Range) + : PreprocessedEntity(MacroExpansionKind, Range), + NameOrDef(BuiltinName) { } + + MacroExpansion(MacroDefinition *Definition, SourceRange Range) + : PreprocessedEntity(MacroExpansionKind, Range), + NameOrDef(Definition) { } + + /// \brief True if it is a builtin macro. + bool isBuiltinMacro() const { return NameOrDef.is<IdentifierInfo *>(); } + + /// \brief The name of the macro being expanded. + const IdentifierInfo *getName() const { + if (MacroDefinition *Def = getDefinition()) + return Def->getName(); + return NameOrDef.get<IdentifierInfo*>(); + } + + /// \brief The definition of the macro being expanded. May return null if + /// this is a builtin macro. + MacroDefinition *getDefinition() const { + return NameOrDef.dyn_cast<MacroDefinition *>(); + } + + // Implement isa/cast/dyncast/etc. + static bool classof(const PreprocessedEntity *PE) { + return PE->getKind() == MacroExpansionKind; + } + static bool classof(const MacroExpansion *) { return true; } + }; + + /// \brief Record the location of an inclusion directive, such as an + /// \c #include or \c #import statement. + class InclusionDirective : public PreprocessingDirective { + public: + /// \brief The kind of inclusion directives known to the + /// preprocessor. + enum InclusionKind { + /// \brief An \c #include directive. + Include, + /// \brief An Objective-C \c #import directive. + Import, + /// \brief A GNU \c #include_next directive. + IncludeNext, + /// \brief A Clang \c #__include_macros directive. + IncludeMacros + }; + + private: + /// \brief The name of the file that was included, as written in + /// the source. + StringRef FileName; + + /// \brief Whether the file name was in quotation marks; otherwise, it was + /// in angle brackets. + unsigned InQuotes : 1; + + /// \brief The kind of inclusion directive we have. + /// + /// This is a value of type InclusionKind. + unsigned Kind : 2; + + /// \brief The file that was included. + const FileEntry *File; + + public: + InclusionDirective(PreprocessingRecord &PPRec, + InclusionKind Kind, StringRef FileName, + bool InQuotes, const FileEntry *File, SourceRange Range); + + /// \brief Determine what kind of inclusion directive this is. + InclusionKind getKind() const { return static_cast<InclusionKind>(Kind); } + + /// \brief Retrieve the included file name as it was written in the source. + StringRef getFileName() const { return FileName; } + + /// \brief Determine whether the included file name was written in quotes; + /// otherwise, it was written in angle brackets. + bool wasInQuotes() const { return InQuotes; } + + /// \brief Retrieve the file entry for the actual file that was included + /// by this directive. + const FileEntry *getFile() const { return File; } + + // Implement isa/cast/dyncast/etc. + static bool classof(const PreprocessedEntity *PE) { + return PE->getKind() == InclusionDirectiveKind; + } + static bool classof(const InclusionDirective *) { return true; } + }; + + /// \brief An abstract class that should be subclassed by any external source + /// of preprocessing record entries. + class ExternalPreprocessingRecordSource { + public: + virtual ~ExternalPreprocessingRecordSource(); + + /// \brief Read a preallocated preprocessed entity from the external source. + /// + /// \returns null if an error occurred that prevented the preprocessed + /// entity from being loaded. + virtual PreprocessedEntity *ReadPreprocessedEntity(unsigned Index) = 0; + + /// \brief Returns a pair of [Begin, End) indices of preallocated + /// preprocessed entities that \arg Range encompasses. + virtual std::pair<unsigned, unsigned> + findPreprocessedEntitiesInRange(SourceRange Range) = 0; + + /// \brief Optionally returns true or false if the preallocated preprocessed + /// entity with index \arg Index came from file \arg FID. + virtual llvm::Optional<bool> isPreprocessedEntityInFileID(unsigned Index, + FileID FID) { + return llvm::Optional<bool>(); + } + }; + + /// \brief A record of the steps taken while preprocessing a source file, + /// including the various preprocessing directives processed, macros + /// expanded, etc. + class PreprocessingRecord : public PPCallbacks { + SourceManager &SourceMgr; + + /// \brief Allocator used to store preprocessing objects. + llvm::BumpPtrAllocator BumpAlloc; + + /// \brief The set of preprocessed entities in this record, in order they + /// were seen. + std::vector<PreprocessedEntity *> PreprocessedEntities; + + /// \brief The set of preprocessed entities in this record that have been + /// loaded from external sources. + /// + /// The entries in this vector are loaded lazily from the external source, + /// and are referenced by the iterator using negative indices. + std::vector<PreprocessedEntity *> LoadedPreprocessedEntities; + + bool RecordCondDirectives; + unsigned CondDirectiveNextIdx; + SmallVector<unsigned, 6> CondDirectiveStack; + + class CondDirectiveLoc { + SourceLocation Loc; + unsigned Idx; + + public: + CondDirectiveLoc(SourceLocation Loc, unsigned Idx) : Loc(Loc), Idx(Idx) {} + + SourceLocation getLoc() const { return Loc; } + unsigned getIdx() const { return Idx; } + + class Comp { + SourceManager &SM; + public: + explicit Comp(SourceManager &SM) : SM(SM) {} + bool operator()(const CondDirectiveLoc &LHS, + const CondDirectiveLoc &RHS) { + return SM.isBeforeInTranslationUnit(LHS.getLoc(), RHS.getLoc()); + } + bool operator()(const CondDirectiveLoc &LHS, SourceLocation RHS) { + return SM.isBeforeInTranslationUnit(LHS.getLoc(), RHS); + } + bool operator()(SourceLocation LHS, const CondDirectiveLoc &RHS) { + return SM.isBeforeInTranslationUnit(LHS, RHS.getLoc()); + } + }; + }; + + typedef std::vector<CondDirectiveLoc> CondDirectiveLocsTy; + /// \brief The locations of conditional directives in source order. + CondDirectiveLocsTy CondDirectiveLocs; + + void addCondDirectiveLoc(CondDirectiveLoc DirLoc); + unsigned findCondDirectiveIdx(SourceLocation Loc) const; + + /// \brief Global (loaded or local) ID for a preprocessed entity. + /// Negative values are used to indicate preprocessed entities + /// loaded from the external source while non-negative values are used to + /// indicate preprocessed entities introduced by the current preprocessor. + /// If M is the number of loaded preprocessed entities, value -M + /// corresponds to element 0 in the loaded entities vector, position -M+1 + /// corresponds to element 1 in the loaded entities vector, etc. + typedef int PPEntityID; + + PPEntityID getPPEntityID(unsigned Index, bool isLoaded) const { + return isLoaded ? PPEntityID(Index) - LoadedPreprocessedEntities.size() + : Index; + } + + /// \brief Mapping from MacroInfo structures to their definitions. + llvm::DenseMap<const MacroInfo *, PPEntityID> MacroDefinitions; + + /// \brief External source of preprocessed entities. + ExternalPreprocessingRecordSource *ExternalSource; + + /// \brief Retrieve the preprocessed entity at the given ID. + PreprocessedEntity *getPreprocessedEntity(PPEntityID PPID); + + /// \brief Retrieve the loaded preprocessed entity at the given index. + PreprocessedEntity *getLoadedPreprocessedEntity(unsigned Index); + + /// \brief Determine the number of preprocessed entities that were + /// loaded (or can be loaded) from an external source. + unsigned getNumLoadedPreprocessedEntities() const { + return LoadedPreprocessedEntities.size(); + } + + /// \brief Returns a pair of [Begin, End) indices of local preprocessed + /// entities that \arg Range encompasses. + std::pair<unsigned, unsigned> + findLocalPreprocessedEntitiesInRange(SourceRange Range) const; + unsigned findBeginLocalPreprocessedEntity(SourceLocation Loc) const; + unsigned findEndLocalPreprocessedEntity(SourceLocation Loc) const; + + /// \brief Allocate space for a new set of loaded preprocessed entities. + /// + /// \returns The index into the set of loaded preprocessed entities, which + /// corresponds to the first newly-allocated entity. + unsigned allocateLoadedEntities(unsigned NumEntities); + + /// \brief Register a new macro definition. + void RegisterMacroDefinition(MacroInfo *Macro, PPEntityID PPID); + + public: + /// \brief Construct a new preprocessing record. + PreprocessingRecord(SourceManager &SM, bool RecordConditionalDirectives); + + /// \brief Allocate memory in the preprocessing record. + void *Allocate(unsigned Size, unsigned Align = 8) { + return BumpAlloc.Allocate(Size, Align); + } + + /// \brief Deallocate memory in the preprocessing record. + void Deallocate(void *Ptr) { } + + size_t getTotalMemory() const; + + SourceManager &getSourceManager() const { return SourceMgr; } + + // Iteration over the preprocessed entities. + class iterator { + PreprocessingRecord *Self; + + /// \brief Position within the preprocessed entity sequence. + /// + /// In a complete iteration, the Position field walks the range [-M, N), + /// where negative values are used to indicate preprocessed entities + /// loaded from the external source while non-negative values are used to + /// indicate preprocessed entities introduced by the current preprocessor. + /// However, to provide iteration in source order (for, e.g., chained + /// precompiled headers), dereferencing the iterator flips the negative + /// values (corresponding to loaded entities), so that position -M + /// corresponds to element 0 in the loaded entities vector, position -M+1 + /// corresponds to element 1 in the loaded entities vector, etc. This + /// gives us a reasonably efficient, source-order walk. + PPEntityID Position; + + public: + typedef PreprocessedEntity *value_type; + typedef value_type& reference; + typedef value_type* pointer; + typedef std::random_access_iterator_tag iterator_category; + typedef int difference_type; + + iterator() : Self(0), Position(0) { } + + iterator(PreprocessingRecord *Self, PPEntityID Position) + : Self(Self), Position(Position) { } + + value_type operator*() const { + return Self->getPreprocessedEntity(Position); + } + + value_type operator[](difference_type D) { + return *(*this + D); + } + + iterator &operator++() { + ++Position; + return *this; + } + + iterator operator++(int) { + iterator Prev(*this); + ++Position; + return Prev; + } + + iterator &operator--() { + --Position; + return *this; + } + + iterator operator--(int) { + iterator Prev(*this); + --Position; + return Prev; + } + + friend bool operator==(const iterator &X, const iterator &Y) { + return X.Position == Y.Position; + } + + friend bool operator!=(const iterator &X, const iterator &Y) { + return X.Position != Y.Position; + } + + friend bool operator<(const iterator &X, const iterator &Y) { + return X.Position < Y.Position; + } + + friend bool operator>(const iterator &X, const iterator &Y) { + return X.Position > Y.Position; + } + + friend bool operator<=(const iterator &X, const iterator &Y) { + return X.Position < Y.Position; + } + + friend bool operator>=(const iterator &X, const iterator &Y) { + return X.Position > Y.Position; + } + + friend iterator& operator+=(iterator &X, difference_type D) { + X.Position += D; + return X; + } + + friend iterator& operator-=(iterator &X, difference_type D) { + X.Position -= D; + return X; + } + + friend iterator operator+(iterator X, difference_type D) { + X.Position += D; + return X; + } + + friend iterator operator+(difference_type D, iterator X) { + X.Position += D; + return X; + } + + friend difference_type operator-(const iterator &X, const iterator &Y) { + return X.Position - Y.Position; + } + + friend iterator operator-(iterator X, difference_type D) { + X.Position -= D; + return X; + } + friend class PreprocessingRecord; + }; + friend class iterator; + + /// \brief Begin iterator for all preprocessed entities. + iterator begin() { + return iterator(this, -(int)LoadedPreprocessedEntities.size()); + } + + /// \brief End iterator for all preprocessed entities. + iterator end() { + return iterator(this, PreprocessedEntities.size()); + } + + /// \brief Begin iterator for local, non-loaded, preprocessed entities. + iterator local_begin() { + return iterator(this, 0); + } + + /// \brief End iterator for local, non-loaded, preprocessed entities. + iterator local_end() { + return iterator(this, PreprocessedEntities.size()); + } + + /// \brief Returns a pair of [Begin, End) iterators of preprocessed entities + /// that source range \arg R encompasses. + /// + /// \param R the range to look for preprocessed entities. + /// + std::pair<iterator, iterator> getPreprocessedEntitiesInRange(SourceRange R); + + /// \brief Returns true if the preprocessed entity that \arg PPEI iterator + /// points to is coming from the file \arg FID. + /// + /// Can be used to avoid implicit deserializations of preallocated + /// preprocessed entities if we only care about entities of a specific file + /// and not from files #included in the range given at + /// \see getPreprocessedEntitiesInRange. + bool isEntityInFileID(iterator PPEI, FileID FID); + + /// \brief Add a new preprocessed entity to this record. + PPEntityID addPreprocessedEntity(PreprocessedEntity *Entity); + + /// \brief Returns true if this PreprocessingRecord is keeping track of + /// conditional directives locations. + bool isRecordingConditionalDirectives() const { + return RecordCondDirectives; + } + + /// \brief Returns true if the given range intersects with a conditional + /// directive. if a #if/#endif block is fully contained within the range, + /// this function will return false. + bool rangeIntersectsConditionalDirective(SourceRange Range) const; + + /// \brief Returns true if the given locations are in different regions, + /// separated by conditional directive blocks. + bool areInDifferentConditionalDirectiveRegion(SourceLocation LHS, + SourceLocation RHS) const { + return findCondDirectiveIdx(LHS) != findCondDirectiveIdx(RHS); + } + + /// \brief Set the external source for preprocessed entities. + void SetExternalSource(ExternalPreprocessingRecordSource &Source); + + /// \brief Retrieve the external source for preprocessed entities. + ExternalPreprocessingRecordSource *getExternalSource() const { + return ExternalSource; + } + + /// \brief Retrieve the macro definition that corresponds to the given + /// \c MacroInfo. + MacroDefinition *findMacroDefinition(const MacroInfo *MI); + + private: + virtual void MacroExpands(const Token &Id, const MacroInfo* MI, + SourceRange Range); + virtual void MacroDefined(const Token &Id, const MacroInfo *MI); + virtual void MacroUndefined(const Token &Id, const MacroInfo *MI); + virtual void InclusionDirective(SourceLocation HashLoc, + const Token &IncludeTok, + StringRef FileName, + bool IsAngled, + const FileEntry *File, + SourceLocation EndLoc, + StringRef SearchPath, + StringRef RelativePath); + virtual void If(SourceLocation Loc, SourceRange ConditionRange); + virtual void Elif(SourceLocation Loc, SourceRange ConditionRange, + SourceLocation IfLoc); + virtual void Ifdef(SourceLocation Loc, const Token &MacroNameTok); + virtual void Ifndef(SourceLocation Loc, const Token &MacroNameTok); + virtual void Else(SourceLocation Loc, SourceLocation IfLoc); + virtual void Endif(SourceLocation Loc, SourceLocation IfLoc); + + /// \brief Cached result of the last \see getPreprocessedEntitiesInRange + /// query. + struct { + SourceRange Range; + std::pair<PPEntityID, PPEntityID> Result; + } CachedRangeQuery; + + std::pair<PPEntityID, PPEntityID> + getPreprocessedEntitiesInRangeSlow(SourceRange R); + + friend class ASTReader; + friend class ASTWriter; + }; +} // end namespace clang + +inline void* operator new(size_t bytes, clang::PreprocessingRecord& PR, + unsigned alignment) throw() { + return PR.Allocate(bytes, alignment); +} + +inline void operator delete(void* ptr, clang::PreprocessingRecord& PR, + unsigned) throw() { + PR.Deallocate(ptr); +} + +#endif // LLVM_CLANG_LEX_PREPROCESSINGRECORD_H diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h new file mode 100644 index 0000000..055008f --- /dev/null +++ b/clang/include/clang/Lex/Preprocessor.h @@ -0,0 +1,1308 @@ +//===--- Preprocessor.h - C Language Family Preprocessor --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Preprocessor interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_PREPROCESSOR_H +#define LLVM_CLANG_LEX_PREPROCESSOR_H + +#include "clang/Lex/MacroInfo.h" +#include "clang/Lex/Lexer.h" +#include "clang/Lex/PTHLexer.h" +#include "clang/Lex/PPCallbacks.h" +#include "clang/Lex/TokenLexer.h" +#include "clang/Lex/PTHManager.h" +#include "clang/Basic/Builtins.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/Allocator.h" +#include <vector> + +namespace llvm { + template<unsigned InternalLen> class SmallString; +} + +namespace clang { + +class SourceManager; +class ExternalPreprocessorSource; +class FileManager; +class FileEntry; +class HeaderSearch; +class PragmaNamespace; +class PragmaHandler; +class CommentHandler; +class ScratchBuffer; +class TargetInfo; +class PPCallbacks; +class CodeCompletionHandler; +class DirectoryLookup; +class PreprocessingRecord; +class ModuleLoader; + +/// Preprocessor - This object engages in a tight little dance with the lexer to +/// efficiently preprocess tokens. Lexers know only about tokens within a +/// single source file, and don't know anything about preprocessor-level issues +/// like the #include stack, token expansion, etc. +/// +class Preprocessor : public RefCountedBase<Preprocessor> { + DiagnosticsEngine *Diags; + LangOptions &LangOpts; + const TargetInfo *Target; + FileManager &FileMgr; + SourceManager &SourceMgr; + ScratchBuffer *ScratchBuf; + HeaderSearch &HeaderInfo; + ModuleLoader &TheModuleLoader; + + /// \brief External source of macros. + ExternalPreprocessorSource *ExternalSource; + + + /// PTH - An optional PTHManager object used for getting tokens from + /// a token cache rather than lexing the original source file. + OwningPtr<PTHManager> PTH; + + /// BP - A BumpPtrAllocator object used to quickly allocate and release + /// objects internal to the Preprocessor. + llvm::BumpPtrAllocator BP; + + /// Identifiers for builtin macros and other builtins. + IdentifierInfo *Ident__LINE__, *Ident__FILE__; // __LINE__, __FILE__ + IdentifierInfo *Ident__DATE__, *Ident__TIME__; // __DATE__, __TIME__ + IdentifierInfo *Ident__INCLUDE_LEVEL__; // __INCLUDE_LEVEL__ + IdentifierInfo *Ident__BASE_FILE__; // __BASE_FILE__ + IdentifierInfo *Ident__TIMESTAMP__; // __TIMESTAMP__ + IdentifierInfo *Ident__COUNTER__; // __COUNTER__ + IdentifierInfo *Ident_Pragma, *Ident__pragma; // _Pragma, __pragma + IdentifierInfo *Ident__VA_ARGS__; // __VA_ARGS__ + IdentifierInfo *Ident__has_feature; // __has_feature + IdentifierInfo *Ident__has_extension; // __has_extension + IdentifierInfo *Ident__has_builtin; // __has_builtin + IdentifierInfo *Ident__has_attribute; // __has_attribute + IdentifierInfo *Ident__has_include; // __has_include + IdentifierInfo *Ident__has_include_next; // __has_include_next + IdentifierInfo *Ident__has_warning; // __has_warning + + SourceLocation DATELoc, TIMELoc; + unsigned CounterValue; // Next __COUNTER__ value. + + enum { + /// MaxIncludeStackDepth - Maximum depth of #includes. + MaxAllowedIncludeStackDepth = 200 + }; + + // State that is set before the preprocessor begins. + bool KeepComments : 1; + bool KeepMacroComments : 1; + bool SuppressIncludeNotFoundError : 1; + + // State that changes while the preprocessor runs: + bool InMacroArgs : 1; // True if parsing fn macro invocation args. + + /// Whether the preprocessor owns the header search object. + bool OwnsHeaderSearch : 1; + + /// DisableMacroExpansion - True if macro expansion is disabled. + bool DisableMacroExpansion : 1; + + /// \brief Whether we have already loaded macros from the external source. + mutable bool ReadMacrosFromExternalSource : 1; + + /// \brief True if we are pre-expanding macro arguments. + bool InMacroArgPreExpansion; + + /// Identifiers - This is mapping/lookup information for all identifiers in + /// the program, including program keywords. + mutable IdentifierTable Identifiers; + + /// Selectors - This table contains all the selectors in the program. Unlike + /// IdentifierTable above, this table *isn't* populated by the preprocessor. + /// It is declared/expanded here because it's role/lifetime is + /// conceptually similar the IdentifierTable. In addition, the current control + /// flow (in clang::ParseAST()), make it convenient to put here. + /// FIXME: Make sure the lifetime of Identifiers/Selectors *isn't* tied to + /// the lifetime of the preprocessor. + SelectorTable Selectors; + + /// BuiltinInfo - Information about builtins. + Builtin::Context BuiltinInfo; + + /// PragmaHandlers - This tracks all of the pragmas that the client registered + /// with this preprocessor. + PragmaNamespace *PragmaHandlers; + + /// \brief Tracks all of the comment handlers that the client registered + /// with this preprocessor. + std::vector<CommentHandler *> CommentHandlers; + + /// \brief True if we want to ignore EOF token and continue later on (thus + /// avoid tearing the Lexer and etc. down). + bool IncrementalProcessing; + + /// \brief The code-completion handler. + CodeCompletionHandler *CodeComplete; + + /// \brief The file that we're performing code-completion for, if any. + const FileEntry *CodeCompletionFile; + + /// \brief The offset in file for the code-completion point. + unsigned CodeCompletionOffset; + + /// \brief The location for the code-completion point. This gets instantiated + /// when the CodeCompletionFile gets #include'ed for preprocessing. + SourceLocation CodeCompletionLoc; + + /// \brief The start location for the file of the code-completion point. + /// This gets instantiated when the CodeCompletionFile gets #include'ed + /// for preprocessing. + SourceLocation CodeCompletionFileLoc; + + /// \brief The source location of the 'import' contextual keyword we just + /// lexed, if any. + SourceLocation ModuleImportLoc; + + /// \brief The module import path that we're currently processing. + llvm::SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> + ModuleImportPath; + + /// \brief Whether the module import expectes an identifier next. Otherwise, + /// it expects a '.' or ';'. + bool ModuleImportExpectsIdentifier; + + /// \brief The source location of the currently-active + /// #pragma clang arc_cf_code_audited begin. + SourceLocation PragmaARCCFCodeAuditedLoc; + + /// \brief True if we hit the code-completion point. + bool CodeCompletionReached; + + /// \brief The number of bytes that we will initially skip when entering the + /// main file, which is used when loading a precompiled preamble, along + /// with a flag that indicates whether skipping this number of bytes will + /// place the lexer at the start of a line. + std::pair<unsigned, bool> SkipMainFilePreamble; + + /// CurLexer - This is the current top of the stack that we're lexing from if + /// not expanding a macro and we are lexing directly from source code. + /// Only one of CurLexer, CurPTHLexer, or CurTokenLexer will be non-null. + OwningPtr<Lexer> CurLexer; + + /// CurPTHLexer - This is the current top of stack that we're lexing from if + /// not expanding from a macro and we are lexing from a PTH cache. + /// Only one of CurLexer, CurPTHLexer, or CurTokenLexer will be non-null. + OwningPtr<PTHLexer> CurPTHLexer; + + /// CurPPLexer - This is the current top of the stack what we're lexing from + /// if not expanding a macro. This is an alias for either CurLexer or + /// CurPTHLexer. + PreprocessorLexer *CurPPLexer; + + /// CurLookup - The DirectoryLookup structure used to find the current + /// FileEntry, if CurLexer is non-null and if applicable. This allows us to + /// implement #include_next and find directory-specific properties. + const DirectoryLookup *CurDirLookup; + + /// CurTokenLexer - This is the current macro we are expanding, if we are + /// expanding a macro. One of CurLexer and CurTokenLexer must be null. + OwningPtr<TokenLexer> CurTokenLexer; + + /// \brief The kind of lexer we're currently working with. + enum CurLexerKind { + CLK_Lexer, + CLK_PTHLexer, + CLK_TokenLexer, + CLK_CachingLexer, + CLK_LexAfterModuleImport + } CurLexerKind; + + /// IncludeMacroStack - This keeps track of the stack of files currently + /// #included, and macros currently being expanded from, not counting + /// CurLexer/CurTokenLexer. + struct IncludeStackInfo { + enum CurLexerKind CurLexerKind; + Lexer *TheLexer; + PTHLexer *ThePTHLexer; + PreprocessorLexer *ThePPLexer; + TokenLexer *TheTokenLexer; + const DirectoryLookup *TheDirLookup; + + IncludeStackInfo(enum CurLexerKind K, Lexer *L, PTHLexer* P, + PreprocessorLexer* PPL, + TokenLexer* TL, const DirectoryLookup *D) + : CurLexerKind(K), TheLexer(L), ThePTHLexer(P), ThePPLexer(PPL), + TheTokenLexer(TL), TheDirLookup(D) {} + }; + std::vector<IncludeStackInfo> IncludeMacroStack; + + /// Callbacks - These are actions invoked when some preprocessor activity is + /// encountered (e.g. a file is #included, etc). + PPCallbacks *Callbacks; + + /// Macros - For each IdentifierInfo with 'HasMacro' set, we keep a mapping + /// to the actual definition of the macro. + llvm::DenseMap<IdentifierInfo*, MacroInfo*> Macros; + + /// \brief Macros that we want to warn because they are not used at the end + /// of the translation unit; we store just their SourceLocations instead + /// something like MacroInfo*. The benefit of this is that when we are + /// deserializing from PCH, we don't need to deserialize identifier & macros + /// just so that we can report that they are unused, we just warn using + /// the SourceLocations of this set (that will be filled by the ASTReader). + /// We are using SmallPtrSet instead of a vector for faster removal. + typedef llvm::SmallPtrSet<SourceLocation, 32> WarnUnusedMacroLocsTy; + WarnUnusedMacroLocsTy WarnUnusedMacroLocs; + + /// MacroArgCache - This is a "freelist" of MacroArg objects that can be + /// reused for quick allocation. + MacroArgs *MacroArgCache; + friend class MacroArgs; + + /// PragmaPushMacroInfo - For each IdentifierInfo used in a #pragma + /// push_macro directive, we keep a MacroInfo stack used to restore + /// previous macro value. + llvm::DenseMap<IdentifierInfo*, std::vector<MacroInfo*> > PragmaPushMacroInfo; + + // Various statistics we track for performance analysis. + unsigned NumDirectives, NumIncluded, NumDefined, NumUndefined, NumPragma; + unsigned NumIf, NumElse, NumEndif; + unsigned NumEnteredSourceFiles, MaxIncludeStackDepth; + unsigned NumMacroExpanded, NumFnMacroExpanded, NumBuiltinMacroExpanded; + unsigned NumFastMacroExpanded, NumTokenPaste, NumFastTokenPaste; + unsigned NumSkipped; + + /// Predefines - This string is the predefined macros that preprocessor + /// should use from the command line etc. + std::string Predefines; + + /// TokenLexerCache - Cache macro expanders to reduce malloc traffic. + enum { TokenLexerCacheSize = 8 }; + unsigned NumCachedTokenLexers; + TokenLexer *TokenLexerCache[TokenLexerCacheSize]; + + /// \brief Keeps macro expanded tokens for TokenLexers. + // + /// Works like a stack; a TokenLexer adds the macro expanded tokens that is + /// going to lex in the cache and when it finishes the tokens are removed + /// from the end of the cache. + SmallVector<Token, 16> MacroExpandedTokens; + std::vector<std::pair<TokenLexer *, size_t> > MacroExpandingLexersStack; + + /// \brief A record of the macro definitions and expansions that + /// occurred during preprocessing. + /// + /// This is an optional side structure that can be enabled with + /// \c createPreprocessingRecord() prior to preprocessing. + PreprocessingRecord *Record; + +private: // Cached tokens state. + typedef SmallVector<Token, 1> CachedTokensTy; + + /// CachedTokens - Cached tokens are stored here when we do backtracking or + /// lookahead. They are "lexed" by the CachingLex() method. + CachedTokensTy CachedTokens; + + /// CachedLexPos - The position of the cached token that CachingLex() should + /// "lex" next. If it points beyond the CachedTokens vector, it means that + /// a normal Lex() should be invoked. + CachedTokensTy::size_type CachedLexPos; + + /// BacktrackPositions - Stack of backtrack positions, allowing nested + /// backtracks. The EnableBacktrackAtThisPos() method pushes a position to + /// indicate where CachedLexPos should be set when the BackTrack() method is + /// invoked (at which point the last position is popped). + std::vector<CachedTokensTy::size_type> BacktrackPositions; + + struct MacroInfoChain { + MacroInfo MI; + MacroInfoChain *Next; + MacroInfoChain *Prev; + }; + + /// MacroInfos are managed as a chain for easy disposal. This is the head + /// of that list. + MacroInfoChain *MIChainHead; + + /// MICache - A "freelist" of MacroInfo objects that can be reused for quick + /// allocation. + MacroInfoChain *MICache; + + MacroInfo *getInfoForMacro(IdentifierInfo *II) const; + +public: + Preprocessor(DiagnosticsEngine &diags, LangOptions &opts, + const TargetInfo *target, + SourceManager &SM, HeaderSearch &Headers, + ModuleLoader &TheModuleLoader, + IdentifierInfoLookup *IILookup = 0, + bool OwnsHeaderSearch = false, + bool DelayInitialization = false, + bool IncrProcessing = false); + + ~Preprocessor(); + + /// \brief Initialize the preprocessor, if the constructor did not already + /// perform the initialization. + /// + /// \param Target Information about the target. + void Initialize(const TargetInfo &Target); + + DiagnosticsEngine &getDiagnostics() const { return *Diags; } + void setDiagnostics(DiagnosticsEngine &D) { Diags = &D; } + + const LangOptions &getLangOpts() const { return LangOpts; } + const TargetInfo &getTargetInfo() const { return *Target; } + FileManager &getFileManager() const { return FileMgr; } + SourceManager &getSourceManager() const { return SourceMgr; } + HeaderSearch &getHeaderSearchInfo() const { return HeaderInfo; } + + IdentifierTable &getIdentifierTable() { return Identifiers; } + SelectorTable &getSelectorTable() { return Selectors; } + Builtin::Context &getBuiltinInfo() { return BuiltinInfo; } + llvm::BumpPtrAllocator &getPreprocessorAllocator() { return BP; } + + void setPTHManager(PTHManager* pm); + + PTHManager *getPTHManager() { return PTH.get(); } + + void setExternalSource(ExternalPreprocessorSource *Source) { + ExternalSource = Source; + } + + ExternalPreprocessorSource *getExternalSource() const { + return ExternalSource; + } + + /// \brief Retrieve the module loader associated with this preprocessor. + ModuleLoader &getModuleLoader() const { return TheModuleLoader; } + + /// SetCommentRetentionState - Control whether or not the preprocessor retains + /// comments in output. + void SetCommentRetentionState(bool KeepComments, bool KeepMacroComments) { + this->KeepComments = KeepComments | KeepMacroComments; + this->KeepMacroComments = KeepMacroComments; + } + + bool getCommentRetentionState() const { return KeepComments; } + + void SetSuppressIncludeNotFoundError(bool Suppress) { + SuppressIncludeNotFoundError = Suppress; + } + + bool GetSuppressIncludeNotFoundError() { + return SuppressIncludeNotFoundError; + } + + /// isCurrentLexer - Return true if we are lexing directly from the specified + /// lexer. + bool isCurrentLexer(const PreprocessorLexer *L) const { + return CurPPLexer == L; + } + + /// getCurrentLexer - Return the current lexer being lexed from. Note + /// that this ignores any potentially active macro expansions and _Pragma + /// expansions going on at the time. + PreprocessorLexer *getCurrentLexer() const { return CurPPLexer; } + + /// getCurrentFileLexer - Return the current file lexer being lexed from. + /// Note that this ignores any potentially active macro expansions and _Pragma + /// expansions going on at the time. + PreprocessorLexer *getCurrentFileLexer() const; + + /// getPPCallbacks/addPPCallbacks - Accessors for preprocessor callbacks. + /// Note that this class takes ownership of any PPCallbacks object given to + /// it. + PPCallbacks *getPPCallbacks() const { return Callbacks; } + void addPPCallbacks(PPCallbacks *C) { + if (Callbacks) + C = new PPChainedCallbacks(C, Callbacks); + Callbacks = C; + } + + /// getMacroInfo - Given an identifier, return the MacroInfo it is #defined to + /// or null if it isn't #define'd. + MacroInfo *getMacroInfo(IdentifierInfo *II) const { + if (!II->hasMacroDefinition()) + return 0; + + return getInfoForMacro(II); + } + + /// setMacroInfo - Specify a macro for this identifier. + /// + void setMacroInfo(IdentifierInfo *II, MacroInfo *MI, + bool LoadedFromAST = false); + + /// macro_iterator/macro_begin/macro_end - This allows you to walk the current + /// state of the macro table. This visits every currently-defined macro. + typedef llvm::DenseMap<IdentifierInfo*, + MacroInfo*>::const_iterator macro_iterator; + macro_iterator macro_begin(bool IncludeExternalMacros = true) const; + macro_iterator macro_end(bool IncludeExternalMacros = true) const; + + const std::string &getPredefines() const { return Predefines; } + /// setPredefines - Set the predefines for this Preprocessor. These + /// predefines are automatically injected when parsing the main file. + void setPredefines(const char *P) { Predefines = P; } + void setPredefines(const std::string &P) { Predefines = P; } + + /// getIdentifierInfo - Return information about the specified preprocessor + /// identifier token. The version of this method that takes two character + /// pointers is preferred unless the identifier is already available as a + /// string (this avoids allocation and copying of memory to construct an + /// std::string). + IdentifierInfo *getIdentifierInfo(StringRef Name) const { + return &Identifiers.get(Name); + } + + /// AddPragmaHandler - Add the specified pragma handler to the preprocessor. + /// If 'Namespace' is non-null, then it is a token required to exist on the + /// pragma line before the pragma string starts, e.g. "STDC" or "GCC". + void AddPragmaHandler(StringRef Namespace, PragmaHandler *Handler); + void AddPragmaHandler(PragmaHandler *Handler) { + AddPragmaHandler(StringRef(), Handler); + } + + /// RemovePragmaHandler - Remove the specific pragma handler from + /// the preprocessor. If \arg Namespace is non-null, then it should + /// be the namespace that \arg Handler was added to. It is an error + /// to remove a handler that has not been registered. + void RemovePragmaHandler(StringRef Namespace, PragmaHandler *Handler); + void RemovePragmaHandler(PragmaHandler *Handler) { + RemovePragmaHandler(StringRef(), Handler); + } + + /// \brief Add the specified comment handler to the preprocessor. + void AddCommentHandler(CommentHandler *Handler); + + /// \brief Remove the specified comment handler. + /// + /// It is an error to remove a handler that has not been registered. + void RemoveCommentHandler(CommentHandler *Handler); + + /// \brief Set the code completion handler to the given object. + void setCodeCompletionHandler(CodeCompletionHandler &Handler) { + CodeComplete = &Handler; + } + + /// \brief Retrieve the current code-completion handler. + CodeCompletionHandler *getCodeCompletionHandler() const { + return CodeComplete; + } + + /// \brief Clear out the code completion handler. + void clearCodeCompletionHandler() { + CodeComplete = 0; + } + + /// \brief Hook used by the lexer to invoke the "natural language" code + /// completion point. + void CodeCompleteNaturalLanguage(); + + /// \brief Retrieve the preprocessing record, or NULL if there is no + /// preprocessing record. + PreprocessingRecord *getPreprocessingRecord() const { return Record; } + + /// \brief Create a new preprocessing record, which will keep track of + /// all macro expansions, macro definitions, etc. + void createPreprocessingRecord(bool RecordConditionalDirectives); + + /// EnterMainSourceFile - Enter the specified FileID as the main source file, + /// which implicitly adds the builtin defines etc. + void EnterMainSourceFile(); + + /// EndSourceFile - Inform the preprocessor callbacks that processing is + /// complete. + void EndSourceFile(); + + /// EnterSourceFile - Add a source file to the top of the include stack and + /// start lexing tokens from it instead of the current buffer. Emit an error + /// and don't enter the file on error. + void EnterSourceFile(FileID CurFileID, const DirectoryLookup *Dir, + SourceLocation Loc); + + /// EnterMacro - Add a Macro to the top of the include stack and start lexing + /// tokens from it instead of the current buffer. Args specifies the + /// tokens input to a function-like macro. + /// + /// ILEnd specifies the location of the ')' for a function-like macro or the + /// identifier for an object-like macro. + void EnterMacro(Token &Identifier, SourceLocation ILEnd, MacroArgs *Args); + + /// EnterTokenStream - Add a "macro" context to the top of the include stack, + /// which will cause the lexer to start returning the specified tokens. + /// + /// If DisableMacroExpansion is true, tokens lexed from the token stream will + /// not be subject to further macro expansion. Otherwise, these tokens will + /// be re-macro-expanded when/if expansion is enabled. + /// + /// If OwnsTokens is false, this method assumes that the specified stream of + /// tokens has a permanent owner somewhere, so they do not need to be copied. + /// If it is true, it assumes the array of tokens is allocated with new[] and + /// must be freed. + /// + void EnterTokenStream(const Token *Toks, unsigned NumToks, + bool DisableMacroExpansion, bool OwnsTokens); + + /// RemoveTopOfLexerStack - Pop the current lexer/macro exp off the top of the + /// lexer stack. This should only be used in situations where the current + /// state of the top-of-stack lexer is known. + void RemoveTopOfLexerStack(); + + /// EnableBacktrackAtThisPos - From the point that this method is called, and + /// until CommitBacktrackedTokens() or Backtrack() is called, the Preprocessor + /// keeps track of the lexed tokens so that a subsequent Backtrack() call will + /// make the Preprocessor re-lex the same tokens. + /// + /// Nested backtracks are allowed, meaning that EnableBacktrackAtThisPos can + /// be called multiple times and CommitBacktrackedTokens/Backtrack calls will + /// be combined with the EnableBacktrackAtThisPos calls in reverse order. + /// + /// NOTE: *DO NOT* forget to call either CommitBacktrackedTokens or Backtrack + /// at some point after EnableBacktrackAtThisPos. If you don't, caching of + /// tokens will continue indefinitely. + /// + void EnableBacktrackAtThisPos(); + + /// CommitBacktrackedTokens - Disable the last EnableBacktrackAtThisPos call. + void CommitBacktrackedTokens(); + + /// Backtrack - Make Preprocessor re-lex the tokens that were lexed since + /// EnableBacktrackAtThisPos() was previously called. + void Backtrack(); + + /// isBacktrackEnabled - True if EnableBacktrackAtThisPos() was called and + /// caching of tokens is on. + bool isBacktrackEnabled() const { return !BacktrackPositions.empty(); } + + /// Lex - To lex a token from the preprocessor, just pull a token from the + /// current lexer or macro object. + void Lex(Token &Result) { + switch (CurLexerKind) { + case CLK_Lexer: CurLexer->Lex(Result); break; + case CLK_PTHLexer: CurPTHLexer->Lex(Result); break; + case CLK_TokenLexer: CurTokenLexer->Lex(Result); break; + case CLK_CachingLexer: CachingLex(Result); break; + case CLK_LexAfterModuleImport: LexAfterModuleImport(Result); break; + } + } + + void LexAfterModuleImport(Token &Result); + + /// LexNonComment - Lex a token. If it's a comment, keep lexing until we get + /// something not a comment. This is useful in -E -C mode where comments + /// would foul up preprocessor directive handling. + void LexNonComment(Token &Result) { + do + Lex(Result); + while (Result.getKind() == tok::comment); + } + + /// LexUnexpandedToken - This is just like Lex, but this disables macro + /// expansion of identifier tokens. + void LexUnexpandedToken(Token &Result) { + // Disable macro expansion. + bool OldVal = DisableMacroExpansion; + DisableMacroExpansion = true; + // Lex the token. + Lex(Result); + + // Reenable it. + DisableMacroExpansion = OldVal; + } + + /// LexUnexpandedNonComment - Like LexNonComment, but this disables macro + /// expansion of identifier tokens. + void LexUnexpandedNonComment(Token &Result) { + do + LexUnexpandedToken(Result); + while (Result.getKind() == tok::comment); + } + + /// LookAhead - This peeks ahead N tokens and returns that token without + /// consuming any tokens. LookAhead(0) returns the next token that would be + /// returned by Lex(), LookAhead(1) returns the token after it, etc. This + /// returns normal tokens after phase 5. As such, it is equivalent to using + /// 'Lex', not 'LexUnexpandedToken'. + const Token &LookAhead(unsigned N) { + if (CachedLexPos + N < CachedTokens.size()) + return CachedTokens[CachedLexPos+N]; + else + return PeekAhead(N+1); + } + + /// RevertCachedTokens - When backtracking is enabled and tokens are cached, + /// this allows to revert a specific number of tokens. + /// Note that the number of tokens being reverted should be up to the last + /// backtrack position, not more. + void RevertCachedTokens(unsigned N) { + assert(isBacktrackEnabled() && + "Should only be called when tokens are cached for backtracking"); + assert(signed(CachedLexPos) - signed(N) >= signed(BacktrackPositions.back()) + && "Should revert tokens up to the last backtrack position, not more"); + assert(signed(CachedLexPos) - signed(N) >= 0 && + "Corrupted backtrack positions ?"); + CachedLexPos -= N; + } + + /// EnterToken - Enters a token in the token stream to be lexed next. If + /// BackTrack() is called afterwards, the token will remain at the insertion + /// point. + void EnterToken(const Token &Tok) { + EnterCachingLexMode(); + CachedTokens.insert(CachedTokens.begin()+CachedLexPos, Tok); + } + + /// AnnotateCachedTokens - We notify the Preprocessor that if it is caching + /// tokens (because backtrack is enabled) it should replace the most recent + /// cached tokens with the given annotation token. This function has no effect + /// if backtracking is not enabled. + /// + /// Note that the use of this function is just for optimization; so that the + /// cached tokens doesn't get re-parsed and re-resolved after a backtrack is + /// invoked. + void AnnotateCachedTokens(const Token &Tok) { + assert(Tok.isAnnotation() && "Expected annotation token"); + if (CachedLexPos != 0 && isBacktrackEnabled()) + AnnotatePreviousCachedTokens(Tok); + } + + /// \brief Replace the last token with an annotation token. + /// + /// Like AnnotateCachedTokens(), this routine replaces an + /// already-parsed (and resolved) token with an annotation + /// token. However, this routine only replaces the last token with + /// the annotation token; it does not affect any other cached + /// tokens. This function has no effect if backtracking is not + /// enabled. + void ReplaceLastTokenWithAnnotation(const Token &Tok) { + assert(Tok.isAnnotation() && "Expected annotation token"); + if (CachedLexPos != 0 && isBacktrackEnabled()) + CachedTokens[CachedLexPos-1] = Tok; + } + + /// \brief Recompute the current lexer kind based on the CurLexer/CurPTHLexer/ + /// CurTokenLexer pointers. + void recomputeCurLexerKind(); + + /// \brief Returns true if incremental processing is enabled + bool isIncrementalProcessingEnabled() const { return IncrementalProcessing; } + + /// \brief Enables the incremental processing + void enableIncrementalProcessing(bool value = true) { + IncrementalProcessing = value; + } + + /// \brief Specify the point at which code-completion will be performed. + /// + /// \param File the file in which code completion should occur. If + /// this file is included multiple times, code-completion will + /// perform completion the first time it is included. If NULL, this + /// function clears out the code-completion point. + /// + /// \param Line the line at which code completion should occur + /// (1-based). + /// + /// \param Column the column at which code completion should occur + /// (1-based). + /// + /// \returns true if an error occurred, false otherwise. + bool SetCodeCompletionPoint(const FileEntry *File, + unsigned Line, unsigned Column); + + /// \brief Determine if we are performing code completion. + bool isCodeCompletionEnabled() const { return CodeCompletionFile != 0; } + + /// \brief Returns the location of the code-completion point. + /// Returns an invalid location if code-completion is not enabled or the file + /// containing the code-completion point has not been lexed yet. + SourceLocation getCodeCompletionLoc() const { return CodeCompletionLoc; } + + /// \brief Returns the start location of the file of code-completion point. + /// Returns an invalid location if code-completion is not enabled or the file + /// containing the code-completion point has not been lexed yet. + SourceLocation getCodeCompletionFileLoc() const { + return CodeCompletionFileLoc; + } + + /// \brief Returns true if code-completion is enabled and we have hit the + /// code-completion point. + bool isCodeCompletionReached() const { return CodeCompletionReached; } + + /// \brief Note that we hit the code-completion point. + void setCodeCompletionReached() { + assert(isCodeCompletionEnabled() && "Code-completion not enabled!"); + CodeCompletionReached = true; + // Silence any diagnostics that occur after we hit the code-completion. + getDiagnostics().setSuppressAllDiagnostics(true); + } + + /// \brief The location of the currently-active #pragma clang + /// arc_cf_code_audited begin. Returns an invalid location if there + /// is no such pragma active. + SourceLocation getPragmaARCCFCodeAuditedLoc() const { + return PragmaARCCFCodeAuditedLoc; + } + + /// \brief Set the location of the currently-active #pragma clang + /// arc_cf_code_audited begin. An invalid location ends the pragma. + void setPragmaARCCFCodeAuditedLoc(SourceLocation Loc) { + PragmaARCCFCodeAuditedLoc = Loc; + } + + /// \brief Instruct the preprocessor to skip part of the main + /// the main source file. + /// + /// \brief Bytes The number of bytes in the preamble to skip. + /// + /// \brief StartOfLine Whether skipping these bytes puts the lexer at the + /// start of a line. + void setSkipMainFilePreamble(unsigned Bytes, bool StartOfLine) { + SkipMainFilePreamble.first = Bytes; + SkipMainFilePreamble.second = StartOfLine; + } + + /// Diag - Forwarding function for diagnostics. This emits a diagnostic at + /// the specified Token's location, translating the token's start + /// position in the current buffer into a SourcePosition object for rendering. + DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) const { + return Diags->Report(Loc, DiagID); + } + + DiagnosticBuilder Diag(const Token &Tok, unsigned DiagID) const { + return Diags->Report(Tok.getLocation(), DiagID); + } + + /// getSpelling() - Return the 'spelling' of the token at the given + /// location; does not go up to the spelling location or down to the + /// expansion location. + /// + /// \param buffer A buffer which will be used only if the token requires + /// "cleaning", e.g. if it contains trigraphs or escaped newlines + /// \param invalid If non-null, will be set \c true if an error occurs. + StringRef getSpelling(SourceLocation loc, + SmallVectorImpl<char> &buffer, + bool *invalid = 0) const { + return Lexer::getSpelling(loc, buffer, SourceMgr, LangOpts, invalid); + } + + /// getSpelling() - Return the 'spelling' of the Tok token. The spelling of a + /// token is the characters used to represent the token in the source file + /// after trigraph expansion and escaped-newline folding. In particular, this + /// wants to get the true, uncanonicalized, spelling of things like digraphs + /// UCNs, etc. + /// + /// \param Invalid If non-null, will be set \c true if an error occurs. + std::string getSpelling(const Token &Tok, bool *Invalid = 0) const { + return Lexer::getSpelling(Tok, SourceMgr, LangOpts, Invalid); + } + + /// getSpelling - This method is used to get the spelling of a token into a + /// preallocated buffer, instead of as an std::string. The caller is required + /// to allocate enough space for the token, which is guaranteed to be at least + /// Tok.getLength() bytes long. The length of the actual result is returned. + /// + /// Note that this method may do two possible things: it may either fill in + /// the buffer specified with characters, or it may *change the input pointer* + /// to point to a constant buffer with the data already in it (avoiding a + /// copy). The caller is not allowed to modify the returned buffer pointer + /// if an internal buffer is returned. + unsigned getSpelling(const Token &Tok, const char *&Buffer, + bool *Invalid = 0) const { + return Lexer::getSpelling(Tok, Buffer, SourceMgr, LangOpts, Invalid); + } + + /// getSpelling - This method is used to get the spelling of a token into a + /// SmallVector. Note that the returned StringRef may not point to the + /// supplied buffer if a copy can be avoided. + StringRef getSpelling(const Token &Tok, + SmallVectorImpl<char> &Buffer, + bool *Invalid = 0) const; + + /// getSpellingOfSingleCharacterNumericConstant - Tok is a numeric constant + /// with length 1, return the character. + char getSpellingOfSingleCharacterNumericConstant(const Token &Tok, + bool *Invalid = 0) const { + assert(Tok.is(tok::numeric_constant) && + Tok.getLength() == 1 && "Called on unsupported token"); + assert(!Tok.needsCleaning() && "Token can't need cleaning with length 1"); + + // If the token is carrying a literal data pointer, just use it. + if (const char *D = Tok.getLiteralData()) + return *D; + + // Otherwise, fall back on getCharacterData, which is slower, but always + // works. + return *SourceMgr.getCharacterData(Tok.getLocation(), Invalid); + } + + /// \brief Retrieve the name of the immediate macro expansion. + /// + /// This routine starts from a source location, and finds the name of the macro + /// responsible for its immediate expansion. It looks through any intervening + /// macro argument expansions to compute this. It returns a StringRef which + /// refers to the SourceManager-owned buffer of the source where that macro + /// name is spelled. Thus, the result shouldn't out-live the SourceManager. + StringRef getImmediateMacroName(SourceLocation Loc) { + return Lexer::getImmediateMacroName(Loc, SourceMgr, getLangOpts()); + } + + /// CreateString - Plop the specified string into a scratch buffer and set the + /// specified token's location and length to it. If specified, the source + /// location provides a location of the expansion point of the token. + void CreateString(const char *Buf, unsigned Len, Token &Tok, + SourceLocation ExpansionLocStart = SourceLocation(), + SourceLocation ExpansionLocEnd = SourceLocation()); + + /// \brief Computes the source location just past the end of the + /// token at this source location. + /// + /// This routine can be used to produce a source location that + /// points just past the end of the token referenced by \p Loc, and + /// is generally used when a diagnostic needs to point just after a + /// token where it expected something different that it received. If + /// the returned source location would not be meaningful (e.g., if + /// it points into a macro), this routine returns an invalid + /// source location. + /// + /// \param Offset an offset from the end of the token, where the source + /// location should refer to. The default offset (0) produces a source + /// location pointing just past the end of the token; an offset of 1 produces + /// a source location pointing to the last character in the token, etc. + SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset = 0) { + return Lexer::getLocForEndOfToken(Loc, Offset, SourceMgr, LangOpts); + } + + /// \brief Returns true if the given MacroID location points at the first + /// token of the macro expansion. + /// + /// \param MacroBegin If non-null and function returns true, it is set to + /// begin location of the macro. + bool isAtStartOfMacroExpansion(SourceLocation loc, + SourceLocation *MacroBegin = 0) const { + return Lexer::isAtStartOfMacroExpansion(loc, SourceMgr, LangOpts, + MacroBegin); + } + + /// \brief Returns true if the given MacroID location points at the last + /// token of the macro expansion. + /// + /// \param MacroBegin If non-null and function returns true, it is set to + /// end location of the macro. + bool isAtEndOfMacroExpansion(SourceLocation loc, + SourceLocation *MacroEnd = 0) const { + return Lexer::isAtEndOfMacroExpansion(loc, SourceMgr, LangOpts, MacroEnd); + } + + /// DumpToken - Print the token to stderr, used for debugging. + /// + void DumpToken(const Token &Tok, bool DumpFlags = false) const; + void DumpLocation(SourceLocation Loc) const; + void DumpMacro(const MacroInfo &MI) const; + + /// AdvanceToTokenCharacter - Given a location that specifies the start of a + /// token, return a new location that specifies a character within the token. + SourceLocation AdvanceToTokenCharacter(SourceLocation TokStart, + unsigned Char) const { + return Lexer::AdvanceToTokenCharacter(TokStart, Char, SourceMgr, LangOpts); + } + + /// IncrementPasteCounter - Increment the counters for the number of token + /// paste operations performed. If fast was specified, this is a 'fast paste' + /// case we handled. + /// + void IncrementPasteCounter(bool isFast) { + if (isFast) + ++NumFastTokenPaste; + else + ++NumTokenPaste; + } + + void PrintStats(); + + size_t getTotalMemory() const; + + /// HandleMicrosoftCommentPaste - When the macro expander pastes together a + /// comment (/##/) in microsoft mode, this method handles updating the current + /// state, returning the token on the next source line. + void HandleMicrosoftCommentPaste(Token &Tok); + + //===--------------------------------------------------------------------===// + // Preprocessor callback methods. These are invoked by a lexer as various + // directives and events are found. + + /// LookUpIdentifierInfo - Given a tok::raw_identifier token, look up the + /// identifier information for the token and install it into the token, + /// updating the token kind accordingly. + IdentifierInfo *LookUpIdentifierInfo(Token &Identifier) const; + +private: + llvm::DenseMap<IdentifierInfo*,unsigned> PoisonReasons; + +public: + + // SetPoisonReason - Call this function to indicate the reason for + // poisoning an identifier. If that identifier is accessed while + // poisoned, then this reason will be used instead of the default + // "poisoned" diagnostic. + void SetPoisonReason(IdentifierInfo *II, unsigned DiagID); + + // HandlePoisonedIdentifier - Display reason for poisoned + // identifier. + void HandlePoisonedIdentifier(Token & Tok); + + void MaybeHandlePoisonedIdentifier(Token & Identifier) { + if(IdentifierInfo * II = Identifier.getIdentifierInfo()) { + if(II->isPoisoned()) { + HandlePoisonedIdentifier(Identifier); + } + } + } + +private: + /// Identifiers used for SEH handling in Borland. These are only + /// allowed in particular circumstances + // __except block + IdentifierInfo *Ident__exception_code, + *Ident___exception_code, + *Ident_GetExceptionCode; + // __except filter expression + IdentifierInfo *Ident__exception_info, + *Ident___exception_info, + *Ident_GetExceptionInfo; + // __finally + IdentifierInfo *Ident__abnormal_termination, + *Ident___abnormal_termination, + *Ident_AbnormalTermination; +public: + void PoisonSEHIdentifiers(bool Poison = true); // Borland + + /// HandleIdentifier - This callback is invoked when the lexer reads an + /// identifier and has filled in the tokens IdentifierInfo member. This + /// callback potentially macro expands it or turns it into a named token (like + /// 'for'). + void HandleIdentifier(Token &Identifier); + + + /// HandleEndOfFile - This callback is invoked when the lexer hits the end of + /// the current file. This either returns the EOF token and returns true, or + /// pops a level off the include stack and returns false, at which point the + /// client should call lex again. + bool HandleEndOfFile(Token &Result, bool isEndOfMacro = false); + + /// HandleEndOfTokenLexer - This callback is invoked when the current + /// TokenLexer hits the end of its token stream. + bool HandleEndOfTokenLexer(Token &Result); + + /// HandleDirective - This callback is invoked when the lexer sees a # token + /// at the start of a line. This consumes the directive, modifies the + /// lexer/preprocessor state, and advances the lexer(s) so that the next token + /// read is the correct one. + void HandleDirective(Token &Result); + + /// CheckEndOfDirective - Ensure that the next token is a tok::eod token. If + /// not, emit a diagnostic and consume up until the eod. If EnableMacros is + /// true, then we consider macros that expand to zero tokens as being ok. + void CheckEndOfDirective(const char *Directive, bool EnableMacros = false); + + /// DiscardUntilEndOfDirective - Read and discard all tokens remaining on the + /// current line until the tok::eod token is found. + void DiscardUntilEndOfDirective(); + + /// SawDateOrTime - This returns true if the preprocessor has seen a use of + /// __DATE__ or __TIME__ in the file so far. + bool SawDateOrTime() const { + return DATELoc != SourceLocation() || TIMELoc != SourceLocation(); + } + unsigned getCounterValue() const { return CounterValue; } + void setCounterValue(unsigned V) { CounterValue = V; } + + /// \brief Retrieves the module that we're currently building, if any. + Module *getCurrentModule(); + + /// AllocateMacroInfo - Allocate a new MacroInfo object with the provide + /// SourceLocation. + MacroInfo *AllocateMacroInfo(SourceLocation L); + + /// CloneMacroInfo - Allocate a new MacroInfo object which is clone of MI. + MacroInfo *CloneMacroInfo(const MacroInfo &MI); + + /// GetIncludeFilenameSpelling - Turn the specified lexer token into a fully + /// checked and spelled filename, e.g. as an operand of #include. This returns + /// true if the input filename was in <>'s or false if it were in ""'s. The + /// caller is expected to provide a buffer that is large enough to hold the + /// spelling of the filename, but is also expected to handle the case when + /// this method decides to use a different buffer. + bool GetIncludeFilenameSpelling(SourceLocation Loc,StringRef &Filename); + + /// LookupFile - Given a "foo" or <foo> reference, look up the indicated file, + /// return null on failure. isAngled indicates whether the file reference is + /// for system #include's or not (i.e. using <> instead of ""). + const FileEntry *LookupFile(StringRef Filename, + bool isAngled, const DirectoryLookup *FromDir, + const DirectoryLookup *&CurDir, + SmallVectorImpl<char> *SearchPath, + SmallVectorImpl<char> *RelativePath, + Module **SuggestedModule, + bool SkipCache = false); + + /// GetCurLookup - The DirectoryLookup structure used to find the current + /// FileEntry, if CurLexer is non-null and if applicable. This allows us to + /// implement #include_next and find directory-specific properties. + const DirectoryLookup *GetCurDirLookup() { return CurDirLookup; } + + /// isInPrimaryFile - Return true if we're in the top-level file, not in a + /// #include. + bool isInPrimaryFile() const; + + /// ConcatenateIncludeName - Handle cases where the #include name is expanded + /// from a macro as multiple tokens, which need to be glued together. This + /// occurs for code like: + /// #define FOO <a/b.h> + /// #include FOO + /// because in this case, "<a/b.h>" is returned as 7 tokens, not one. + /// + /// This code concatenates and consumes tokens up to the '>' token. It + /// returns false if the > was found, otherwise it returns true if it finds + /// and consumes the EOD marker. + bool ConcatenateIncludeName(SmallString<128> &FilenameBuffer, + SourceLocation &End); + + /// LexOnOffSwitch - Lex an on-off-switch (C99 6.10.6p2) and verify that it is + /// followed by EOD. Return true if the token is not a valid on-off-switch. + bool LexOnOffSwitch(tok::OnOffSwitch &OOS); + +private: + + void PushIncludeMacroStack() { + IncludeMacroStack.push_back(IncludeStackInfo(CurLexerKind, + CurLexer.take(), + CurPTHLexer.take(), + CurPPLexer, + CurTokenLexer.take(), + CurDirLookup)); + CurPPLexer = 0; + } + + void PopIncludeMacroStack() { + CurLexer.reset(IncludeMacroStack.back().TheLexer); + CurPTHLexer.reset(IncludeMacroStack.back().ThePTHLexer); + CurPPLexer = IncludeMacroStack.back().ThePPLexer; + CurTokenLexer.reset(IncludeMacroStack.back().TheTokenLexer); + CurDirLookup = IncludeMacroStack.back().TheDirLookup; + CurLexerKind = IncludeMacroStack.back().CurLexerKind; + IncludeMacroStack.pop_back(); + } + + /// AllocateMacroInfo - Allocate a new MacroInfo object. + MacroInfo *AllocateMacroInfo(); + + /// ReleaseMacroInfo - Release the specified MacroInfo. This memory will + /// be reused for allocating new MacroInfo objects. + void ReleaseMacroInfo(MacroInfo* MI); + + /// ReadMacroName - Lex and validate a macro name, which occurs after a + /// #define or #undef. This emits a diagnostic, sets the token kind to eod, + /// and discards the rest of the macro line if the macro name is invalid. + void ReadMacroName(Token &MacroNameTok, char isDefineUndef = 0); + + /// ReadMacroDefinitionArgList - The ( starting an argument list of a macro + /// definition has just been read. Lex the rest of the arguments and the + /// closing ), updating MI with what we learn and saving in LastTok the + /// last token read. + /// Return true if an error occurs parsing the arg list. + bool ReadMacroDefinitionArgList(MacroInfo *MI, Token& LastTok); + + /// SkipExcludedConditionalBlock - We just read a #if or related directive and + /// decided that the subsequent tokens are in the #if'd out portion of the + /// file. Lex the rest of the file, until we see an #endif. If + /// FoundNonSkipPortion is true, then we have already emitted code for part of + /// this #if directive, so #else/#elif blocks should never be entered. If + /// FoundElse is false, then #else directives are ok, if not, then we have + /// already seen one so a #else directive is a duplicate. When this returns, + /// the caller can lex the first valid token. + void SkipExcludedConditionalBlock(SourceLocation IfTokenLoc, + bool FoundNonSkipPortion, bool FoundElse, + SourceLocation ElseLoc = SourceLocation()); + + /// PTHSkipExcludedConditionalBlock - A fast PTH version of + /// SkipExcludedConditionalBlock. + void PTHSkipExcludedConditionalBlock(); + + /// EvaluateDirectiveExpression - Evaluate an integer constant expression that + /// may occur after a #if or #elif directive and return it as a bool. If the + /// expression is equivalent to "!defined(X)" return X in IfNDefMacro. + bool EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro); + + /// RegisterBuiltinPragmas - Install the standard preprocessor pragmas: + /// #pragma GCC poison/system_header/dependency and #pragma once. + void RegisterBuiltinPragmas(); + + /// RegisterBuiltinMacros - Register builtin macros, such as __LINE__ with the + /// identifier table. + void RegisterBuiltinMacros(); + + /// HandleMacroExpandedIdentifier - If an identifier token is read that is to + /// be expanded as a macro, handle it and return the next token as 'Tok'. If + /// the macro should not be expanded return true, otherwise return false. + bool HandleMacroExpandedIdentifier(Token &Tok, MacroInfo *MI); + + /// \brief Cache macro expanded tokens for TokenLexers. + // + /// Works like a stack; a TokenLexer adds the macro expanded tokens that is + /// going to lex in the cache and when it finishes the tokens are removed + /// from the end of the cache. + Token *cacheMacroExpandedTokens(TokenLexer *tokLexer, + ArrayRef<Token> tokens); + void removeCachedMacroExpandedTokensOfLastLexer(); + friend void TokenLexer::ExpandFunctionArguments(); + + /// isNextPPTokenLParen - Determine whether the next preprocessor token to be + /// lexed is a '('. If so, consume the token and return true, if not, this + /// method should have no observable side-effect on the lexed tokens. + bool isNextPPTokenLParen(); + + /// ReadFunctionLikeMacroArgs - After reading "MACRO(", this method is + /// invoked to read all of the formal arguments specified for the macro + /// invocation. This returns null on error. + MacroArgs *ReadFunctionLikeMacroArgs(Token &MacroName, MacroInfo *MI, + SourceLocation &ExpansionEnd); + + /// ExpandBuiltinMacro - If an identifier token is read that is to be expanded + /// as a builtin macro, handle it and return the next token as 'Tok'. + void ExpandBuiltinMacro(Token &Tok); + + /// Handle_Pragma - Read a _Pragma directive, slice it up, process it, then + /// return the first token after the directive. The _Pragma token has just + /// been read into 'Tok'. + void Handle_Pragma(Token &Tok); + + /// HandleMicrosoft__pragma - Like Handle_Pragma except the pragma text + /// is not enclosed within a string literal. + void HandleMicrosoft__pragma(Token &Tok); + + /// EnterSourceFileWithLexer - Add a lexer to the top of the include stack and + /// start lexing tokens from it instead of the current buffer. + void EnterSourceFileWithLexer(Lexer *TheLexer, const DirectoryLookup *Dir); + + /// EnterSourceFileWithPTH - Add a lexer to the top of the include stack and + /// start getting tokens from it using the PTH cache. + void EnterSourceFileWithPTH(PTHLexer *PL, const DirectoryLookup *Dir); + + /// IsFileLexer - Returns true if we are lexing from a file and not a + /// pragma or a macro. + static bool IsFileLexer(const Lexer* L, const PreprocessorLexer* P) { + return L ? !L->isPragmaLexer() : P != 0; + } + + static bool IsFileLexer(const IncludeStackInfo& I) { + return IsFileLexer(I.TheLexer, I.ThePPLexer); + } + + bool IsFileLexer() const { + return IsFileLexer(CurLexer.get(), CurPPLexer); + } + + //===--------------------------------------------------------------------===// + // Caching stuff. + void CachingLex(Token &Result); + bool InCachingLexMode() const { + // If the Lexer pointers are 0 and IncludeMacroStack is empty, it means + // that we are past EOF, not that we are in CachingLex mode. + return CurPPLexer == 0 && CurTokenLexer == 0 && CurPTHLexer == 0 && + !IncludeMacroStack.empty(); + } + void EnterCachingLexMode(); + void ExitCachingLexMode() { + if (InCachingLexMode()) + RemoveTopOfLexerStack(); + } + const Token &PeekAhead(unsigned N); + void AnnotatePreviousCachedTokens(const Token &Tok); + + //===--------------------------------------------------------------------===// + /// Handle*Directive - implement the various preprocessor directives. These + /// should side-effect the current preprocessor object so that the next call + /// to Lex() will return the appropriate token next. + void HandleLineDirective(Token &Tok); + void HandleDigitDirective(Token &Tok); + void HandleUserDiagnosticDirective(Token &Tok, bool isWarning); + void HandleIdentSCCSDirective(Token &Tok); + void HandleMacroPublicDirective(Token &Tok); + void HandleMacroPrivateDirective(Token &Tok); + + // File inclusion. + void HandleIncludeDirective(SourceLocation HashLoc, + Token &Tok, + const DirectoryLookup *LookupFrom = 0, + bool isImport = false); + void HandleIncludeNextDirective(SourceLocation HashLoc, Token &Tok); + void HandleIncludeMacrosDirective(SourceLocation HashLoc, Token &Tok); + void HandleImportDirective(SourceLocation HashLoc, Token &Tok); + void HandleMicrosoftImportDirective(Token &Tok); + + // Macro handling. + void HandleDefineDirective(Token &Tok); + void HandleUndefDirective(Token &Tok); + + // Conditional Inclusion. + void HandleIfdefDirective(Token &Tok, bool isIfndef, + bool ReadAnyTokensBeforeDirective); + void HandleIfDirective(Token &Tok, bool ReadAnyTokensBeforeDirective); + void HandleEndifDirective(Token &Tok); + void HandleElseDirective(Token &Tok); + void HandleElifDirective(Token &Tok); + + // Pragmas. + void HandlePragmaDirective(unsigned Introducer); +public: + void HandlePragmaOnce(Token &OnceTok); + void HandlePragmaMark(); + void HandlePragmaPoison(Token &PoisonTok); + void HandlePragmaSystemHeader(Token &SysHeaderTok); + void HandlePragmaDependency(Token &DependencyTok); + void HandlePragmaComment(Token &CommentTok); + void HandlePragmaMessage(Token &MessageTok); + void HandlePragmaPushMacro(Token &Tok); + void HandlePragmaPopMacro(Token &Tok); + void HandlePragmaIncludeAlias(Token &Tok); + IdentifierInfo *ParsePragmaPushOrPopMacro(Token &Tok); + + // Return true and store the first token only if any CommentHandler + // has inserted some tokens and getCommentRetentionState() is false. + bool HandleComment(Token &Token, SourceRange Comment); + + /// \brief A macro is used, update information about macros that need unused + /// warnings. + void markMacroAsUsed(MacroInfo *MI); +}; + +/// \brief Abstract base class that describes a handler that will receive +/// source ranges for each of the comments encountered in the source file. +class CommentHandler { +public: + virtual ~CommentHandler(); + + // The handler shall return true if it has pushed any tokens + // to be read using e.g. EnterToken or EnterTokenStream. + virtual bool HandleComment(Preprocessor &PP, SourceRange Comment) = 0; +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Lex/PreprocessorLexer.h b/clang/include/clang/Lex/PreprocessorLexer.h new file mode 100644 index 0000000..b551cd4 --- /dev/null +++ b/clang/include/clang/Lex/PreprocessorLexer.h @@ -0,0 +1,180 @@ +//===--- PreprocessorLexer.h - C Language Family Lexer ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the PreprocessorLexer interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_PreprocessorLexer_H +#define LLVM_CLANG_PreprocessorLexer_H + +#include "clang/Lex/MultipleIncludeOpt.h" +#include "clang/Lex/Token.h" +#include "llvm/ADT/SmallVector.h" + +namespace clang { + +class FileEntry; +class Preprocessor; + +class PreprocessorLexer { + virtual void anchor(); +protected: + Preprocessor *PP; // Preprocessor object controlling lexing. + + /// The SourceManager FileID corresponding to the file being lexed. + const FileID FID; + + /// \brief Number of SLocEntries before lexing the file. + unsigned InitialNumSLocEntries; + + //===--------------------------------------------------------------------===// + // Context-specific lexing flags set by the preprocessor. + //===--------------------------------------------------------------------===// + + /// ParsingPreprocessorDirective - This is true when parsing #XXX. This turns + /// '\n' into a tok::eod token. + bool ParsingPreprocessorDirective; + + /// ParsingFilename - True after #include: this turns <xx> into a + /// tok::angle_string_literal token. + bool ParsingFilename; + + /// LexingRawMode - True if in raw mode: This flag disables interpretation of + /// tokens and is a far faster mode to lex in than non-raw-mode. This flag: + /// 1. If EOF of the current lexer is found, the include stack isn't popped. + /// 2. Identifier information is not looked up for identifier tokens. As an + /// effect of this, implicit macro expansion is naturally disabled. + /// 3. "#" tokens at the start of a line are treated as normal tokens, not + /// implicitly transformed by the lexer. + /// 4. All diagnostic messages are disabled. + /// 5. No callbacks are made into the preprocessor. + /// + /// Note that in raw mode that the PP pointer may be null. + bool LexingRawMode; + + /// MIOpt - This is a state machine that detects the #ifndef-wrapping a file + /// idiom for the multiple-include optimization. + MultipleIncludeOpt MIOpt; + + /// ConditionalStack - Information about the set of #if/#ifdef/#ifndef blocks + /// we are currently in. + SmallVector<PPConditionalInfo, 4> ConditionalStack; + + PreprocessorLexer(const PreprocessorLexer&); // DO NOT IMPLEMENT + void operator=(const PreprocessorLexer&); // DO NOT IMPLEMENT + friend class Preprocessor; + + PreprocessorLexer(Preprocessor *pp, FileID fid); + + PreprocessorLexer() + : PP(0), InitialNumSLocEntries(0), + ParsingPreprocessorDirective(false), + ParsingFilename(false), + LexingRawMode(false) {} + + virtual ~PreprocessorLexer() {} + + virtual void IndirectLex(Token& Result) = 0; + + /// getSourceLocation - Return the source location for the next observable + /// location. + virtual SourceLocation getSourceLocation() = 0; + + //===--------------------------------------------------------------------===// + // #if directive handling. + + /// pushConditionalLevel - When we enter a #if directive, this keeps track of + /// what we are currently in for diagnostic emission (e.g. #if with missing + /// #endif). + void pushConditionalLevel(SourceLocation DirectiveStart, bool WasSkipping, + bool FoundNonSkip, bool FoundElse) { + PPConditionalInfo CI; + CI.IfLoc = DirectiveStart; + CI.WasSkipping = WasSkipping; + CI.FoundNonSkip = FoundNonSkip; + CI.FoundElse = FoundElse; + ConditionalStack.push_back(CI); + } + void pushConditionalLevel(const PPConditionalInfo &CI) { + ConditionalStack.push_back(CI); + } + + /// popConditionalLevel - Remove an entry off the top of the conditional + /// stack, returning information about it. If the conditional stack is empty, + /// this returns true and does not fill in the arguments. + bool popConditionalLevel(PPConditionalInfo &CI) { + if (ConditionalStack.empty()) return true; + CI = ConditionalStack.back(); + ConditionalStack.pop_back(); + return false; + } + + /// peekConditionalLevel - Return the top of the conditional stack. This + /// requires that there be a conditional active. + PPConditionalInfo &peekConditionalLevel() { + assert(!ConditionalStack.empty() && "No conditionals active!"); + return ConditionalStack.back(); + } + + unsigned getConditionalStackDepth() const { return ConditionalStack.size(); } + +public: + + //===--------------------------------------------------------------------===// + // Misc. lexing methods. + + /// LexIncludeFilename - After the preprocessor has parsed a #include, lex and + /// (potentially) macro expand the filename. If the sequence parsed is not + /// lexically legal, emit a diagnostic and return a result EOD token. + void LexIncludeFilename(Token &Result); + + /// setParsingPreprocessorDirective - Inform the lexer whether or not + /// we are currently lexing a preprocessor directive. + void setParsingPreprocessorDirective(bool f) { + ParsingPreprocessorDirective = f; + } + + /// isLexingRawMode - Return true if this lexer is in raw mode or not. + bool isLexingRawMode() const { return LexingRawMode; } + + /// getPP - Return the preprocessor object for this lexer. + Preprocessor *getPP() const { return PP; } + + FileID getFileID() const { + assert(PP && + "PreprocessorLexer::getFileID() should only be used with a Preprocessor"); + return FID; + } + + /// \brief Number of SLocEntries before lexing the file. + unsigned getInitialNumSLocEntries() const { + return InitialNumSLocEntries; + } + + /// getFileEntry - Return the FileEntry corresponding to this FileID. Like + /// getFileID(), this only works for lexers with attached preprocessors. + const FileEntry *getFileEntry() const; + + /// \brief Iterator that traverses the current stack of preprocessor + /// conditional directives (#if/#ifdef/#ifndef). + typedef SmallVectorImpl<PPConditionalInfo>::const_iterator + conditional_iterator; + + conditional_iterator conditional_begin() const { + return ConditionalStack.begin(); + } + conditional_iterator conditional_end() const { + return ConditionalStack.end(); + } +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Lex/ScratchBuffer.h b/clang/include/clang/Lex/ScratchBuffer.h new file mode 100644 index 0000000..f03515f --- /dev/null +++ b/clang/include/clang/Lex/ScratchBuffer.h @@ -0,0 +1,45 @@ +//===--- ScratchBuffer.h - Scratch space for forming tokens -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ScratchBuffer interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SCRATCHBUFFER_H +#define LLVM_CLANG_SCRATCHBUFFER_H + +#include "clang/Basic/SourceLocation.h" + +namespace clang { + class SourceManager; + +/// ScratchBuffer - This class exposes a simple interface for the dynamic +/// construction of tokens. This is used for builtin macros (e.g. __LINE__) as +/// well as token pasting, etc. +class ScratchBuffer { + SourceManager &SourceMgr; + char *CurBuffer; + SourceLocation BufferStartLoc; + unsigned BytesUsed; +public: + ScratchBuffer(SourceManager &SM); + + /// getToken - Splat the specified text into a temporary MemoryBuffer and + /// return a SourceLocation that refers to the token. This is just like the + /// previous method, but returns a location that indicates the physloc of the + /// token. + SourceLocation getToken(const char *Buf, unsigned Len, const char *&DestPtr); + +private: + void AllocScratchBuffer(unsigned RequestLen); +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Lex/Token.h b/clang/include/clang/Lex/Token.h new file mode 100644 index 0000000..a88f607 --- /dev/null +++ b/clang/include/clang/Lex/Token.h @@ -0,0 +1,299 @@ +//===--- Token.h - Token interface ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Token interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOKEN_H +#define LLVM_CLANG_TOKEN_H + +#include "clang/Basic/TemplateKinds.h" +#include "clang/Basic/TokenKinds.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/OperatorKinds.h" +#include <cstdlib> + +namespace clang { + +class IdentifierInfo; + +/// Token - This structure provides full information about a lexed token. +/// It is not intended to be space efficient, it is intended to return as much +/// information as possible about each returned token. This is expected to be +/// compressed into a smaller form if memory footprint is important. +/// +/// The parser can create a special "annotation token" representing a stream of +/// tokens that were parsed and semantically resolved, e.g.: "foo::MyClass<int>" +/// can be represented by a single typename annotation token that carries +/// information about the SourceRange of the tokens and the type object. +class Token { + /// The location of the token. + SourceLocation Loc; + + // Conceptually these next two fields could be in a union. However, this + // causes gcc 4.2 to pessimize LexTokenInternal, a very performance critical + // routine. Keeping as separate members with casts until a more beautiful fix + // presents itself. + + /// UintData - This holds either the length of the token text, when + /// a normal token, or the end of the SourceRange when an annotation + /// token. + unsigned UintData; + + /// PtrData - This is a union of four different pointer types, which depends + /// on what type of token this is: + /// Identifiers, keywords, etc: + /// This is an IdentifierInfo*, which contains the uniqued identifier + /// spelling. + /// Literals: isLiteral() returns true. + /// This is a pointer to the start of the token in a text buffer, which + /// may be dirty (have trigraphs / escaped newlines). + /// Annotations (resolved type names, C++ scopes, etc): isAnnotation(). + /// This is a pointer to sema-specific data for the annotation token. + /// Other: + /// This is null. + void *PtrData; + + /// Kind - The actual flavor of token this is. + /// + unsigned short Kind; + + /// Flags - Bits we track about this token, members of the TokenFlags enum. + unsigned char Flags; +public: + + // Various flags set per token: + enum TokenFlags { + StartOfLine = 0x01, // At start of line or only after whitespace. + LeadingSpace = 0x02, // Whitespace exists before this token. + DisableExpand = 0x04, // This identifier may never be macro expanded. + NeedsCleaning = 0x08, // Contained an escaped newline or trigraph. + LeadingEmptyMacro = 0x10, // Empty macro exists before this token. + HasUDSuffix = 0x20 // This string or character literal has a ud-suffix. + }; + + tok::TokenKind getKind() const { return (tok::TokenKind)Kind; } + void setKind(tok::TokenKind K) { Kind = K; } + + /// is/isNot - Predicates to check if this token is a specific kind, as in + /// "if (Tok.is(tok::l_brace)) {...}". + bool is(tok::TokenKind K) const { return Kind == (unsigned) K; } + bool isNot(tok::TokenKind K) const { return Kind != (unsigned) K; } + + /// isAnyIdentifier - Return true if this is a raw identifier (when lexing + /// in raw mode) or a non-keyword identifier (when lexing in non-raw mode). + bool isAnyIdentifier() const { + return is(tok::identifier) || is(tok::raw_identifier); + } + + /// isLiteral - Return true if this is a "literal", like a numeric + /// constant, string, etc. + bool isLiteral() const { + return is(tok::numeric_constant) || is(tok::char_constant) || + is(tok::wide_char_constant) || is(tok::utf16_char_constant) || + is(tok::utf32_char_constant) || is(tok::string_literal) || + is(tok::wide_string_literal) || is(tok::utf8_string_literal) || + is(tok::utf16_string_literal) || is(tok::utf32_string_literal) || + is(tok::angle_string_literal); + } + + bool isAnnotation() const { +#define ANNOTATION(NAME) \ + if (is(tok::annot_##NAME)) \ + return true; +#include "clang/Basic/TokenKinds.def" + return false; + } + + /// getLocation - Return a source location identifier for the specified + /// offset in the current file. + SourceLocation getLocation() const { return Loc; } + unsigned getLength() const { + assert(!isAnnotation() && "Annotation tokens have no length field"); + return UintData; + } + + void setLocation(SourceLocation L) { Loc = L; } + void setLength(unsigned Len) { + assert(!isAnnotation() && "Annotation tokens have no length field"); + UintData = Len; + } + + SourceLocation getAnnotationEndLoc() const { + assert(isAnnotation() && "Used AnnotEndLocID on non-annotation token"); + return SourceLocation::getFromRawEncoding(UintData); + } + void setAnnotationEndLoc(SourceLocation L) { + assert(isAnnotation() && "Used AnnotEndLocID on non-annotation token"); + UintData = L.getRawEncoding(); + } + + SourceLocation getLastLoc() const { + return isAnnotation() ? getAnnotationEndLoc() : getLocation(); + } + + /// getAnnotationRange - SourceRange of the group of tokens that this + /// annotation token represents. + SourceRange getAnnotationRange() const { + return SourceRange(getLocation(), getAnnotationEndLoc()); + } + void setAnnotationRange(SourceRange R) { + setLocation(R.getBegin()); + setAnnotationEndLoc(R.getEnd()); + } + + const char *getName() const { + return tok::getTokenName( (tok::TokenKind) Kind); + } + + /// startToken - Reset all flags to cleared. + /// + void startToken() { + Kind = tok::unknown; + Flags = 0; + PtrData = 0; + UintData = 0; + Loc = SourceLocation(); + } + + IdentifierInfo *getIdentifierInfo() const { + assert(isNot(tok::raw_identifier) && + "getIdentifierInfo() on a tok::raw_identifier token!"); + assert(!isAnnotation() && + "getIdentifierInfo() on an annotation token!"); + if (isLiteral()) return 0; + return (IdentifierInfo*) PtrData; + } + void setIdentifierInfo(IdentifierInfo *II) { + PtrData = (void*) II; + } + + /// getRawIdentifierData - For a raw identifier token (i.e., an identifier + /// lexed in raw mode), returns a pointer to the start of it in the text + /// buffer if known, null otherwise. + const char *getRawIdentifierData() const { + assert(is(tok::raw_identifier)); + return reinterpret_cast<const char*>(PtrData); + } + void setRawIdentifierData(const char *Ptr) { + assert(is(tok::raw_identifier)); + PtrData = const_cast<char*>(Ptr); + } + + /// getLiteralData - For a literal token (numeric constant, string, etc), this + /// returns a pointer to the start of it in the text buffer if known, null + /// otherwise. + const char *getLiteralData() const { + assert(isLiteral() && "Cannot get literal data of non-literal"); + return reinterpret_cast<const char*>(PtrData); + } + void setLiteralData(const char *Ptr) { + assert(isLiteral() && "Cannot set literal data of non-literal"); + PtrData = const_cast<char*>(Ptr); + } + + void *getAnnotationValue() const { + assert(isAnnotation() && "Used AnnotVal on non-annotation token"); + return PtrData; + } + void setAnnotationValue(void *val) { + assert(isAnnotation() && "Used AnnotVal on non-annotation token"); + PtrData = val; + } + + /// setFlag - Set the specified flag. + void setFlag(TokenFlags Flag) { + Flags |= Flag; + } + + /// clearFlag - Unset the specified flag. + void clearFlag(TokenFlags Flag) { + Flags &= ~Flag; + } + + /// getFlags - Return the internal represtation of the flags. + /// Only intended for low-level operations such as writing tokens to + // disk. + unsigned getFlags() const { + return Flags; + } + + /// setFlagValue - Set a flag to either true or false. + void setFlagValue(TokenFlags Flag, bool Val) { + if (Val) + setFlag(Flag); + else + clearFlag(Flag); + } + + /// isAtStartOfLine - Return true if this token is at the start of a line. + /// + bool isAtStartOfLine() const { return (Flags & StartOfLine) ? true : false; } + + /// hasLeadingSpace - Return true if this token has whitespace before it. + /// + bool hasLeadingSpace() const { return (Flags & LeadingSpace) ? true : false; } + + /// isExpandDisabled - Return true if this identifier token should never + /// be expanded in the future, due to C99 6.10.3.4p2. + bool isExpandDisabled() const { + return (Flags & DisableExpand) ? true : false; + } + + /// isObjCAtKeyword - Return true if we have an ObjC keyword identifier. + bool isObjCAtKeyword(tok::ObjCKeywordKind objcKey) const; + + /// getObjCKeywordID - Return the ObjC keyword kind. + tok::ObjCKeywordKind getObjCKeywordID() const; + + /// needsCleaning - Return true if this token has trigraphs or escaped + /// newlines in it. + /// + bool needsCleaning() const { return (Flags & NeedsCleaning) ? true : false; } + + /// \brief Return true if this token has an empty macro before it. + /// + bool hasLeadingEmptyMacro() const { + return (Flags & LeadingEmptyMacro) ? true : false; + } + + /// \brief Return true if this token is a string or character literal which + /// has a ud-suffix. + bool hasUDSuffix() const { return (Flags & HasUDSuffix) ? true : false; } +}; + +/// PPConditionalInfo - Information about the conditional stack (#if directives) +/// currently active. +struct PPConditionalInfo { + /// IfLoc - Location where the conditional started. + /// + SourceLocation IfLoc; + + /// WasSkipping - True if this was contained in a skipping directive, e.g. + /// in a "#if 0" block. + bool WasSkipping; + + /// FoundNonSkip - True if we have emitted tokens already, and now we're in + /// an #else block or something. Only useful in Skipping blocks. + bool FoundNonSkip; + + /// FoundElse - True if we've seen a #else in this block. If so, + /// #elif/#else directives are not allowed. + bool FoundElse; +}; + +} // end namespace clang + +namespace llvm { + template <> + struct isPodLike<clang::Token> { static const bool value = true; }; +} // end namespace llvm + +#endif diff --git a/clang/include/clang/Lex/TokenConcatenation.h b/clang/include/clang/Lex/TokenConcatenation.h new file mode 100644 index 0000000..551300f --- /dev/null +++ b/clang/include/clang/Lex/TokenConcatenation.h @@ -0,0 +1,72 @@ +//===--- TokenConcatenation.h - Token Concatenation Avoidance ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the TokenConcatenation class. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_LEX_TOKEN_CONCATENATION_H +#define CLANG_LEX_TOKEN_CONCATENATION_H + +#include "clang/Basic/TokenKinds.h" + +namespace clang { + class Preprocessor; + class Token; + + /// TokenConcatenation class, which answers the question of + /// "Is it safe to emit two tokens without a whitespace between them, or + /// would that cause implicit concatenation of the tokens?" + /// + /// For example, it emitting two identifiers "foo" and "bar" next to each + /// other would cause the lexer to produce one "foobar" token. Emitting "1" + /// and ")" next to each other is safe. + /// + class TokenConcatenation { + Preprocessor &PP; + + enum AvoidConcatInfo { + /// By default, a token never needs to avoid concatenation. Most tokens + /// (e.g. ',', ')', etc) don't cause a problem when concatenated. + aci_never_avoid_concat = 0, + + /// aci_custom_firstchar - AvoidConcat contains custom code to handle this + /// token's requirements, and it needs to know the first character of the + /// token. + aci_custom_firstchar = 1, + + /// aci_custom - AvoidConcat contains custom code to handle this token's + /// requirements, but it doesn't need to know the first character of the + /// token. + aci_custom = 2, + + /// aci_avoid_equal - Many tokens cannot be safely followed by an '=' + /// character. For example, "<<" turns into "<<=" when followed by an =. + aci_avoid_equal = 4 + }; + + /// TokenInfo - This array contains information for each token on what + /// action to take when avoiding concatenation of tokens in the AvoidConcat + /// method. + char TokenInfo[tok::NUM_TOKENS]; + public: + TokenConcatenation(Preprocessor &PP); + + bool AvoidConcat(const Token &PrevPrevTok, + const Token &PrevTok, + const Token &Tok) const; + + private: + /// IsIdentifierStringPrefix - Return true if the spelling of the token + /// is literally 'L', 'u', 'U', or 'u8'. + bool IsIdentifierStringPrefix(const Token &Tok) const; + }; + } // end clang namespace + +#endif diff --git a/clang/include/clang/Lex/TokenLexer.h b/clang/include/clang/Lex/TokenLexer.h new file mode 100644 index 0000000..1330ad5 --- /dev/null +++ b/clang/include/clang/Lex/TokenLexer.h @@ -0,0 +1,187 @@ +//===--- TokenLexer.h - Lex from a token buffer -----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the TokenLexer interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOKENLEXER_H +#define LLVM_CLANG_TOKENLEXER_H + +#include "clang/Basic/SourceLocation.h" + +namespace clang { + class MacroInfo; + class Preprocessor; + class Token; + class MacroArgs; + +/// TokenLexer - This implements a lexer that returns token from a macro body +/// or token stream instead of lexing from a character buffer. This is used for +/// macro expansion and _Pragma handling, for example. +/// +class TokenLexer { + /// Macro - The macro we are expanding from. This is null if expanding a + /// token stream. + /// + MacroInfo *Macro; + + /// ActualArgs - The actual arguments specified for a function-like macro, or + /// null. The TokenLexer owns the pointed-to object. + MacroArgs *ActualArgs; + + /// PP - The current preprocessor object we are expanding for. + /// + Preprocessor &PP; + + /// Tokens - This is the pointer to an array of tokens that the macro is + /// defined to, with arguments expanded for function-like macros. If this is + /// a token stream, these are the tokens we are returning. This points into + /// the macro definition we are lexing from, a cache buffer that is owned by + /// the preprocessor, or some other buffer that we may or may not own + /// (depending on OwnsTokens). + /// Note that if it points into Preprocessor's cache buffer, the Preprocessor + /// may update the pointer as needed. + const Token *Tokens; + friend class Preprocessor; + + /// NumTokens - This is the length of the Tokens array. + /// + unsigned NumTokens; + + /// CurToken - This is the next token that Lex will return. + /// + unsigned CurToken; + + /// ExpandLocStart/End - The source location range where this macro was + /// expanded. + SourceLocation ExpandLocStart, ExpandLocEnd; + + /// \brief Source location pointing at the source location entry chunk that + /// was reserved for the current macro expansion. + SourceLocation MacroExpansionStart; + + /// \brief The offset of the macro expansion in the + /// "source location address space". + unsigned MacroStartSLocOffset; + + /// \brief Location of the macro definition. + SourceLocation MacroDefStart; + /// \brief Length of the macro definition. + unsigned MacroDefLength; + + /// Lexical information about the expansion point of the macro: the identifier + /// that the macro expanded from had these properties. + bool AtStartOfLine : 1; + bool HasLeadingSpace : 1; + + /// OwnsTokens - This is true if this TokenLexer allocated the Tokens + /// array, and thus needs to free it when destroyed. For simple object-like + /// macros (for example) we just point into the token buffer of the macro + /// definition, we don't make a copy of it. + bool OwnsTokens : 1; + + /// DisableMacroExpansion - This is true when tokens lexed from the TokenLexer + /// should not be subject to further macro expansion. + bool DisableMacroExpansion : 1; + + TokenLexer(const TokenLexer&); // DO NOT IMPLEMENT + void operator=(const TokenLexer&); // DO NOT IMPLEMENT +public: + /// Create a TokenLexer for the specified macro with the specified actual + /// arguments. Note that this ctor takes ownership of the ActualArgs pointer. + /// ILEnd specifies the location of the ')' for a function-like macro or the + /// identifier for an object-like macro. + TokenLexer(Token &Tok, SourceLocation ILEnd, MacroArgs *ActualArgs, + Preprocessor &pp) + : Macro(0), ActualArgs(0), PP(pp), OwnsTokens(false) { + Init(Tok, ILEnd, ActualArgs); + } + + /// Init - Initialize this TokenLexer to expand from the specified macro + /// with the specified argument information. Note that this ctor takes + /// ownership of the ActualArgs pointer. ILEnd specifies the location of the + /// ')' for a function-like macro or the identifier for an object-like macro. + void Init(Token &Tok, SourceLocation ILEnd, MacroArgs *ActualArgs); + + /// Create a TokenLexer for the specified token stream. If 'OwnsTokens' is + /// specified, this takes ownership of the tokens and delete[]'s them when + /// the token lexer is empty. + TokenLexer(const Token *TokArray, unsigned NumToks, bool DisableExpansion, + bool ownsTokens, Preprocessor &pp) + : Macro(0), ActualArgs(0), PP(pp), OwnsTokens(false) { + Init(TokArray, NumToks, DisableExpansion, ownsTokens); + } + + /// Init - Initialize this TokenLexer with the specified token stream. + /// This does not take ownership of the specified token vector. + /// + /// DisableExpansion is true when macro expansion of tokens lexed from this + /// stream should be disabled. + void Init(const Token *TokArray, unsigned NumToks, + bool DisableMacroExpansion, bool OwnsTokens); + + ~TokenLexer() { destroy(); } + + /// isNextTokenLParen - If the next token lexed will pop this macro off the + /// expansion stack, return 2. If the next unexpanded token is a '(', return + /// 1, otherwise return 0. + unsigned isNextTokenLParen() const; + + /// Lex - Lex and return a token from this macro stream. + void Lex(Token &Tok); + + /// isParsingPreprocessorDirective - Return true if we are in the middle of a + /// preprocessor directive. + bool isParsingPreprocessorDirective() const; + +private: + void destroy(); + + /// isAtEnd - Return true if the next lex call will pop this macro off the + /// include stack. + bool isAtEnd() const { + return CurToken == NumTokens; + } + + /// PasteTokens - Tok is the LHS of a ## operator, and CurToken is the ## + /// operator. Read the ## and RHS, and paste the LHS/RHS together. If there + /// are is another ## after it, chomp it iteratively. Return the result as + /// Tok. If this returns true, the caller should immediately return the + /// token. + bool PasteTokens(Token &Tok); + + /// Expand the arguments of a function-like macro so that we can quickly + /// return preexpanded tokens from Tokens. + void ExpandFunctionArguments(); + + /// HandleMicrosoftCommentPaste - In microsoft compatibility mode, /##/ pastes + /// together to form a comment that comments out everything in the current + /// macro, other active macros, and anything left on the current physical + /// source line of the expanded buffer. Handle this by returning the + /// first token on the next line. + void HandleMicrosoftCommentPaste(Token &Tok); + + /// \brief If \arg loc is a FileID and points inside the current macro + /// definition, returns the appropriate source location pointing at the + /// macro expansion source location entry. + SourceLocation getExpansionLocForMacroDefLoc(SourceLocation loc) const; + + /// \brief Creates SLocEntries and updates the locations of macro argument + /// tokens to their new expanded locations. + /// + /// \param ArgIdSpellLoc the location of the macro argument id inside the + /// macro definition. + void updateLocForMacroArgTokens(SourceLocation ArgIdSpellLoc, + Token *begin_tokens, Token *end_tokens); +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Makefile b/clang/include/clang/Makefile new file mode 100644 index 0000000..5f2077d --- /dev/null +++ b/clang/include/clang/Makefile @@ -0,0 +1,44 @@ +CLANG_LEVEL := ../.. +DIRS := AST Basic Driver Lex Parse Sema Serialization + +include $(CLANG_LEVEL)/Makefile + +install-local:: + $(Echo) Installing Clang include files + $(Verb) $(MKDIR) $(DESTDIR)$(PROJ_includedir) + $(Verb) if test -d "$(PROJ_SRC_DIR)" ; then \ + cd $(PROJ_SRC_DIR)/.. && \ + for hdr in `find clang -type f \ + '(' -name LICENSE.TXT \ + -o -name '*.def' \ + -o -name '*.h' \ + -o -name '*.inc' \ + ')' -print \ + | grep -v CVS | grep -v .svn | grep -v .dir` ; do \ + instdir=$(DESTDIR)`dirname "$(PROJ_includedir)/$$hdr"` ; \ + if test \! -d "$$instdir" ; then \ + $(EchoCmd) Making install directory $$instdir ; \ + $(MKDIR) $$instdir ;\ + fi ; \ + $(DataInstall) $$hdr $(DESTDIR)$(PROJ_includedir)/$$hdr ; \ + done ; \ + fi +ifneq ($(PROJ_SRC_ROOT),$(PROJ_OBJ_ROOT)) + $(Verb) if test -d "$(PROJ_OBJ_ROOT)/tools/clang/include/clang" ; then \ + cd $(PROJ_OBJ_ROOT)/tools/clang/include && \ + for hdr in `find clang -type f \ + '(' -name LICENSE.TXT \ + -o -name '*.def' \ + -o -name '*.h' \ + -o -name '*.inc' \ + ')' -print \ + | grep -v CVS | grep -v .tmp | grep -v .dir` ; do \ + instdir=$(DESTDIR)`dirname "$(PROJ_includedir)/$$hdr"` ; \ + if test \! -d "$$instdir" ; then \ + $(EchoCmd) Making install directory $$instdir ; \ + $(MKDIR) $$instdir ;\ + fi ; \ + $(DataInstall) $$hdr $(DESTDIR)$(PROJ_includedir)/$$hdr ; \ + done ; \ + fi +endif diff --git a/clang/include/clang/Parse/CMakeLists.txt b/clang/include/clang/Parse/CMakeLists.txt new file mode 100644 index 0000000..d1ff2ab --- /dev/null +++ b/clang/include/clang/Parse/CMakeLists.txt @@ -0,0 +1,4 @@ +clang_tablegen(AttrLateParsed.inc -gen-clang-attr-late-parsed-list + -I ${CMAKE_CURRENT_SOURCE_DIR}/../../ + SOURCE ../Basic/Attr.td + TARGET ClangAttrLateParsed) diff --git a/clang/include/clang/Parse/Makefile b/clang/include/clang/Parse/Makefile new file mode 100644 index 0000000..296892c --- /dev/null +++ b/clang/include/clang/Parse/Makefile @@ -0,0 +1,13 @@ +CLANG_LEVEL := ../../.. +TD_SRC_DIR = $(PROJ_SRC_DIR)/../Basic +BUILT_SOURCES = AttrLateParsed.inc + +TABLEGEN_INC_FILES_COMMON = 1 + +include $(CLANG_LEVEL)/Makefile + +$(ObjDir)/AttrLateParsed.inc.tmp : $(TD_SRC_DIR)/Attr.td $(CLANG_TBLGEN) \ + $(ObjDir)/.dir + $(Echo) "Building Clang attribute late-parsed table with tblgen" + $(Verb) $(ClangTableGen) -gen-clang-attr-late-parsed-list -o $(call SYSPATH, $@) \ + -I $(PROJ_SRC_DIR)/../../ $<
\ No newline at end of file diff --git a/clang/include/clang/Parse/ParseAST.h b/clang/include/clang/Parse/ParseAST.h new file mode 100644 index 0000000..2405a0c --- /dev/null +++ b/clang/include/clang/Parse/ParseAST.h @@ -0,0 +1,49 @@ +//===--- ParseAST.h - Define the ParseAST method ----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the clang::ParseAST method. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_PARSE_PARSEAST_H +#define LLVM_CLANG_PARSE_PARSEAST_H + +#include "clang/Basic/LangOptions.h" + +namespace clang { + class Preprocessor; + class ASTConsumer; + class ASTContext; + class CodeCompleteConsumer; + class Sema; + + /// \brief Parse the entire file specified, notifying the ASTConsumer as + /// the file is parsed. + /// + /// This operation inserts the parsed decls into the translation + /// unit held by Ctx. + /// + /// \param TUKind The kind of translation unit being parsed. + /// + /// \param CompletionConsumer If given, an object to consume code completion + /// results. + void ParseAST(Preprocessor &pp, ASTConsumer *C, + ASTContext &Ctx, bool PrintStats = false, + TranslationUnitKind TUKind = TU_Complete, + CodeCompleteConsumer *CompletionConsumer = 0, + bool SkipFunctionBodies = false); + + /// \brief Parse the main file known to the preprocessor, producing an + /// abstract syntax tree. + void ParseAST(Sema &S, bool PrintStats = false, + bool SkipFunctionBodies = false); + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Parse/ParseDiagnostic.h b/clang/include/clang/Parse/ParseDiagnostic.h new file mode 100644 index 0000000..0d47292 --- /dev/null +++ b/clang/include/clang/Parse/ParseDiagnostic.h @@ -0,0 +1,28 @@ +//===--- DiagnosticParse.h - Diagnostics for libparse -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_DIAGNOSTICPARSE_H +#define LLVM_CLANG_DIAGNOSTICPARSE_H + +#include "clang/Basic/Diagnostic.h" + +namespace clang { + namespace diag { + enum { +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\ + SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM, +#define PARSESTART +#include "clang/Basic/DiagnosticParseKinds.inc" +#undef DIAG + NUM_BUILTIN_PARSE_DIAGNOSTICS + }; + } // end namespace diag +} // end namespace clang + +#endif diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h new file mode 100644 index 0000000..0ae5dc8 --- /dev/null +++ b/clang/include/clang/Parse/Parser.h @@ -0,0 +1,2231 @@ +//===--- Parser.h - C Language Parser ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Parser interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_PARSE_PARSER_H +#define LLVM_CLANG_PARSE_PARSER_H + +#include "clang/Basic/Specifiers.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Lex/CodeCompletionHandler.h" +#include "clang/Sema/Sema.h" +#include "clang/Sema/DeclSpec.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/PrettyStackTrace.h" +#include <stack> + +namespace clang { + class PragmaHandler; + class Scope; + class DeclGroupRef; + class DiagnosticBuilder; + class Parser; + class PragmaUnusedHandler; + class ColonProtectionRAIIObject; + class InMessageExpressionRAIIObject; + class PoisonSEHIdentifiersRAIIObject; + class VersionTuple; + +/// PrettyStackTraceParserEntry - If a crash happens while the parser is active, +/// an entry is printed for it. +class PrettyStackTraceParserEntry : public llvm::PrettyStackTraceEntry { + const Parser &P; +public: + PrettyStackTraceParserEntry(const Parser &p) : P(p) {} + virtual void print(raw_ostream &OS) const; +}; + +/// PrecedenceLevels - These are precedences for the binary/ternary +/// operators in the C99 grammar. These have been named to relate +/// with the C99 grammar productions. Low precedences numbers bind +/// more weakly than high numbers. +namespace prec { + enum Level { + Unknown = 0, // Not binary operator. + Comma = 1, // , + Assignment = 2, // =, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |= + Conditional = 3, // ? + LogicalOr = 4, // || + LogicalAnd = 5, // && + InclusiveOr = 6, // | + ExclusiveOr = 7, // ^ + And = 8, // & + Equality = 9, // ==, != + Relational = 10, // >=, <=, >, < + Shift = 11, // <<, >> + Additive = 12, // -, + + Multiplicative = 13, // *, /, % + PointerToMember = 14 // .*, ->* + }; +} + +/// Parser - This implements a parser for the C family of languages. After +/// parsing units of the grammar, productions are invoked to handle whatever has +/// been read. +/// +class Parser : public CodeCompletionHandler { + friend class PragmaUnusedHandler; + friend class ColonProtectionRAIIObject; + friend class InMessageExpressionRAIIObject; + friend class PoisonSEHIdentifiersRAIIObject; + friend class ParenBraceBracketBalancer; + + Preprocessor &PP; + + /// Tok - The current token we are peeking ahead. All parsing methods assume + /// that this is valid. + Token Tok; + + // PrevTokLocation - The location of the token we previously + // consumed. This token is used for diagnostics where we expected to + // see a token following another token (e.g., the ';' at the end of + // a statement). + SourceLocation PrevTokLocation; + + unsigned short ParenCount, BracketCount, BraceCount; + + /// Actions - These are the callbacks we invoke as we parse various constructs + /// in the file. + Sema &Actions; + + DiagnosticsEngine &Diags; + + /// ScopeCache - Cache scopes to reduce malloc traffic. + enum { ScopeCacheSize = 16 }; + unsigned NumCachedScopes; + Scope *ScopeCache[ScopeCacheSize]; + + /// Identifiers used for SEH handling in Borland. These are only + /// allowed in particular circumstances + // __except block + IdentifierInfo *Ident__exception_code, + *Ident___exception_code, + *Ident_GetExceptionCode; + // __except filter expression + IdentifierInfo *Ident__exception_info, + *Ident___exception_info, + *Ident_GetExceptionInfo; + // __finally + IdentifierInfo *Ident__abnormal_termination, + *Ident___abnormal_termination, + *Ident_AbnormalTermination; + + /// Contextual keywords for Microsoft extensions. + IdentifierInfo *Ident__except; + + /// Ident_super - IdentifierInfo for "super", to support fast + /// comparison. + IdentifierInfo *Ident_super; + /// Ident_vector and Ident_pixel - cached IdentifierInfo's for + /// "vector" and "pixel" fast comparison. Only present if + /// AltiVec enabled. + IdentifierInfo *Ident_vector; + IdentifierInfo *Ident_pixel; + + /// Objective-C contextual keywords. + mutable IdentifierInfo *Ident_instancetype; + + /// \brief Identifier for "introduced". + IdentifierInfo *Ident_introduced; + + /// \brief Identifier for "deprecated". + IdentifierInfo *Ident_deprecated; + + /// \brief Identifier for "obsoleted". + IdentifierInfo *Ident_obsoleted; + + /// \brief Identifier for "unavailable". + IdentifierInfo *Ident_unavailable; + + /// \brief Identifier for "message". + IdentifierInfo *Ident_message; + + /// C++0x contextual keywords. + mutable IdentifierInfo *Ident_final; + mutable IdentifierInfo *Ident_override; + + OwningPtr<PragmaHandler> AlignHandler; + OwningPtr<PragmaHandler> GCCVisibilityHandler; + OwningPtr<PragmaHandler> OptionsHandler; + OwningPtr<PragmaHandler> PackHandler; + OwningPtr<PragmaHandler> MSStructHandler; + OwningPtr<PragmaHandler> UnusedHandler; + OwningPtr<PragmaHandler> WeakHandler; + OwningPtr<PragmaHandler> RedefineExtnameHandler; + OwningPtr<PragmaHandler> FPContractHandler; + OwningPtr<PragmaHandler> OpenCLExtensionHandler; + + /// Whether the '>' token acts as an operator or not. This will be + /// true except when we are parsing an expression within a C++ + /// template argument list, where the '>' closes the template + /// argument list. + bool GreaterThanIsOperator; + + /// ColonIsSacred - When this is false, we aggressively try to recover from + /// code like "foo : bar" as if it were a typo for "foo :: bar". This is not + /// safe in case statements and a few other things. This is managed by the + /// ColonProtectionRAIIObject RAII object. + bool ColonIsSacred; + + /// \brief When true, we are directly inside an Objective-C messsage + /// send expression. + /// + /// This is managed by the \c InMessageExpressionRAIIObject class, and + /// should not be set directly. + bool InMessageExpression; + + /// The "depth" of the template parameters currently being parsed. + unsigned TemplateParameterDepth; + + /// Factory object for creating AttributeList objects. + AttributeFactory AttrFactory; + + /// \brief Gathers and cleans up TemplateIdAnnotations when parsing of a + /// top-level declaration is finished. + SmallVector<TemplateIdAnnotation *, 16> TemplateIds; + + IdentifierInfo *getSEHExceptKeyword(); + + bool SkipFunctionBodies; + +public: + Parser(Preprocessor &PP, Sema &Actions, bool SkipFunctionBodies); + ~Parser(); + + const LangOptions &getLangOpts() const { return PP.getLangOpts(); } + const TargetInfo &getTargetInfo() const { return PP.getTargetInfo(); } + Preprocessor &getPreprocessor() const { return PP; } + Sema &getActions() const { return Actions; } + + const Token &getCurToken() const { return Tok; } + Scope *getCurScope() const { return Actions.getCurScope(); } + + Decl *getObjCDeclContext() const { return Actions.getObjCDeclContext(); } + + // Type forwarding. All of these are statically 'void*', but they may all be + // different actual classes based on the actions in place. + typedef OpaquePtr<DeclGroupRef> DeclGroupPtrTy; + typedef OpaquePtr<TemplateName> TemplateTy; + + typedef SmallVector<TemplateParameterList *, 4> TemplateParameterLists; + + typedef clang::ExprResult ExprResult; + typedef clang::StmtResult StmtResult; + typedef clang::BaseResult BaseResult; + typedef clang::MemInitResult MemInitResult; + typedef clang::TypeResult TypeResult; + + typedef Expr *ExprArg; + typedef ASTMultiPtr<Stmt*> MultiStmtArg; + typedef Sema::FullExprArg FullExprArg; + + /// Adorns a ExprResult with Actions to make it an ExprResult + ExprResult Owned(ExprResult res) { + return ExprResult(res); + } + /// Adorns a StmtResult with Actions to make it an StmtResult + StmtResult Owned(StmtResult res) { + return StmtResult(res); + } + + ExprResult ExprError() { return ExprResult(true); } + StmtResult StmtError() { return StmtResult(true); } + + ExprResult ExprError(const DiagnosticBuilder &) { return ExprError(); } + StmtResult StmtError(const DiagnosticBuilder &) { return StmtError(); } + + ExprResult ExprEmpty() { return ExprResult(false); } + + // Parsing methods. + + /// ParseTranslationUnit - All in one method that initializes parses, and + /// shuts down the parser. + void ParseTranslationUnit(); + + /// Initialize - Warm up the parser. + /// + void Initialize(); + + /// ParseTopLevelDecl - Parse one top-level declaration. Returns true if + /// the EOF was encountered. + bool ParseTopLevelDecl(DeclGroupPtrTy &Result); + +private: + //===--------------------------------------------------------------------===// + // Low-Level token peeking and consumption methods. + // + + /// isTokenParen - Return true if the cur token is '(' or ')'. + bool isTokenParen() const { + return Tok.getKind() == tok::l_paren || Tok.getKind() == tok::r_paren; + } + /// isTokenBracket - Return true if the cur token is '[' or ']'. + bool isTokenBracket() const { + return Tok.getKind() == tok::l_square || Tok.getKind() == tok::r_square; + } + /// isTokenBrace - Return true if the cur token is '{' or '}'. + bool isTokenBrace() const { + return Tok.getKind() == tok::l_brace || Tok.getKind() == tok::r_brace; + } + + /// isTokenStringLiteral - True if this token is a string-literal. + /// + bool isTokenStringLiteral() const { + return Tok.getKind() == tok::string_literal || + Tok.getKind() == tok::wide_string_literal || + Tok.getKind() == tok::utf8_string_literal || + Tok.getKind() == tok::utf16_string_literal || + Tok.getKind() == tok::utf32_string_literal; + } + + /// \brief Returns true if the current token is '=' or is a type of '='. + /// For typos, give a fixit to '=' + bool isTokenEqualOrEqualTypo(); + + /// ConsumeToken - Consume the current 'peek token' and lex the next one. + /// This does not work with all kinds of tokens: strings and specific other + /// tokens must be consumed with custom methods below. This returns the + /// location of the consumed token. + SourceLocation ConsumeToken() { + assert(!isTokenStringLiteral() && !isTokenParen() && !isTokenBracket() && + !isTokenBrace() && + "Should consume special tokens with Consume*Token"); + + if (Tok.is(tok::code_completion)) + return handleUnexpectedCodeCompletionToken(); + + PrevTokLocation = Tok.getLocation(); + PP.Lex(Tok); + return PrevTokLocation; + } + + /// ConsumeAnyToken - Dispatch to the right Consume* method based on the + /// current token type. This should only be used in cases where the type of + /// the token really isn't known, e.g. in error recovery. + SourceLocation ConsumeAnyToken() { + if (isTokenParen()) + return ConsumeParen(); + else if (isTokenBracket()) + return ConsumeBracket(); + else if (isTokenBrace()) + return ConsumeBrace(); + else if (isTokenStringLiteral()) + return ConsumeStringToken(); + else + return ConsumeToken(); + } + + /// ConsumeParen - This consume method keeps the paren count up-to-date. + /// + SourceLocation ConsumeParen() { + assert(isTokenParen() && "wrong consume method"); + if (Tok.getKind() == tok::l_paren) + ++ParenCount; + else if (ParenCount) + --ParenCount; // Don't let unbalanced )'s drive the count negative. + PrevTokLocation = Tok.getLocation(); + PP.Lex(Tok); + return PrevTokLocation; + } + + /// ConsumeBracket - This consume method keeps the bracket count up-to-date. + /// + SourceLocation ConsumeBracket() { + assert(isTokenBracket() && "wrong consume method"); + if (Tok.getKind() == tok::l_square) + ++BracketCount; + else if (BracketCount) + --BracketCount; // Don't let unbalanced ]'s drive the count negative. + + PrevTokLocation = Tok.getLocation(); + PP.Lex(Tok); + return PrevTokLocation; + } + + /// ConsumeBrace - This consume method keeps the brace count up-to-date. + /// + SourceLocation ConsumeBrace() { + assert(isTokenBrace() && "wrong consume method"); + if (Tok.getKind() == tok::l_brace) + ++BraceCount; + else if (BraceCount) + --BraceCount; // Don't let unbalanced }'s drive the count negative. + + PrevTokLocation = Tok.getLocation(); + PP.Lex(Tok); + return PrevTokLocation; + } + + /// ConsumeStringToken - Consume the current 'peek token', lexing a new one + /// and returning the token kind. This method is specific to strings, as it + /// handles string literal concatenation, as per C99 5.1.1.2, translation + /// phase #6. + SourceLocation ConsumeStringToken() { + assert(isTokenStringLiteral() && + "Should only consume string literals with this method"); + PrevTokLocation = Tok.getLocation(); + PP.Lex(Tok); + return PrevTokLocation; + } + + /// \brief Consume the current code-completion token. + /// + /// This routine should be called to consume the code-completion token once + /// a code-completion action has already been invoked. + SourceLocation ConsumeCodeCompletionToken() { + assert(Tok.is(tok::code_completion)); + PrevTokLocation = Tok.getLocation(); + PP.Lex(Tok); + return PrevTokLocation; + } + + ///\ brief When we are consuming a code-completion token without having + /// matched specific position in the grammar, provide code-completion results + /// based on context. + /// + /// \returns the source location of the code-completion token. + SourceLocation handleUnexpectedCodeCompletionToken(); + + /// \brief Abruptly cut off parsing; mainly used when we have reached the + /// code-completion point. + void cutOffParsing() { + PP.setCodeCompletionReached(); + // Cut off parsing by acting as if we reached the end-of-file. + Tok.setKind(tok::eof); + } + + /// \brief Handle the annotation token produced for #pragma unused(...) + void HandlePragmaUnused(); + + /// \brief Handle the annotation token produced for + /// #pragma GCC visibility... + void HandlePragmaVisibility(); + + /// \brief Handle the annotation token produced for + /// #pragma pack... + void HandlePragmaPack(); + + /// GetLookAheadToken - This peeks ahead N tokens and returns that token + /// without consuming any tokens. LookAhead(0) returns 'Tok', LookAhead(1) + /// returns the token after Tok, etc. + /// + /// Note that this differs from the Preprocessor's LookAhead method, because + /// the Parser always has one token lexed that the preprocessor doesn't. + /// + const Token &GetLookAheadToken(unsigned N) { + if (N == 0 || Tok.is(tok::eof)) return Tok; + return PP.LookAhead(N-1); + } + + /// NextToken - This peeks ahead one token and returns it without + /// consuming it. + const Token &NextToken() { + return PP.LookAhead(0); + } + + /// \brief RAII class that helps handle the parsing of an open/close delimiter + /// pair, such as braces { ... } or parentheses ( ... ). + class BalancedDelimiterTracker { + Parser& P; + tok::TokenKind Kind, Close; + SourceLocation (Parser::*Consumer)(); + SourceLocation LOpen, LClose; + + unsigned short &getDepth() { + switch (Kind) { + case tok::l_brace: return P.BraceCount; + case tok::l_square: return P.BracketCount; + case tok::l_paren: return P.ParenCount; + default: llvm_unreachable("Wrong token kind"); + } + } + + enum { MaxDepth = 256 }; + + bool diagnoseOverflow(); + bool diagnoseMissingClose(); + + public: + BalancedDelimiterTracker(Parser& p, tok::TokenKind k) : P(p), Kind(k) { + switch (Kind) { + default: llvm_unreachable("Unexpected balanced token"); + case tok::l_brace: + Close = tok::r_brace; + Consumer = &Parser::ConsumeBrace; + break; + case tok::l_paren: + Close = tok::r_paren; + Consumer = &Parser::ConsumeParen; + break; + + case tok::l_square: + Close = tok::r_square; + Consumer = &Parser::ConsumeBracket; + break; + } + } + + SourceLocation getOpenLocation() const { return LOpen; } + SourceLocation getCloseLocation() const { return LClose; } + SourceRange getRange() const { return SourceRange(LOpen, LClose); } + + bool consumeOpen() { + if (!P.Tok.is(Kind)) + return true; + + if (getDepth() < MaxDepth) { + LOpen = (P.*Consumer)(); + return false; + } + + return diagnoseOverflow(); + } + + bool expectAndConsume(unsigned DiagID, + const char *Msg = "", + tok::TokenKind SkipToTok = tok::unknown); + bool consumeClose() { + if (P.Tok.is(Close)) { + LClose = (P.*Consumer)(); + return false; + } + + return diagnoseMissingClose(); + } + void skipToEnd(); + }; + + /// getTypeAnnotation - Read a parsed type out of an annotation token. + static ParsedType getTypeAnnotation(Token &Tok) { + return ParsedType::getFromOpaquePtr(Tok.getAnnotationValue()); + } + + static void setTypeAnnotation(Token &Tok, ParsedType T) { + Tok.setAnnotationValue(T.getAsOpaquePtr()); + } + + /// \brief Read an already-translated primary expression out of an annotation + /// token. + static ExprResult getExprAnnotation(Token &Tok) { + if (Tok.getAnnotationValue()) + return ExprResult((Expr *)Tok.getAnnotationValue()); + + return ExprResult(true); + } + + /// \brief Set the primary expression corresponding to the given annotation + /// token. + static void setExprAnnotation(Token &Tok, ExprResult ER) { + if (ER.isInvalid()) + Tok.setAnnotationValue(0); + else + Tok.setAnnotationValue(ER.get()); + } + + // If NeedType is true, then TryAnnotateTypeOrScopeToken will try harder to + // find a type name by attempting typo correction. + bool TryAnnotateTypeOrScopeToken(bool EnteringContext = false, + bool NeedType = false); + bool TryAnnotateCXXScopeToken(bool EnteringContext = false); + + /// TryAltiVecToken - Check for context-sensitive AltiVec identifier tokens, + /// replacing them with the non-context-sensitive keywords. This returns + /// true if the token was replaced. + bool TryAltiVecToken(DeclSpec &DS, SourceLocation Loc, + const char *&PrevSpec, unsigned &DiagID, + bool &isInvalid) { + if (!getLangOpts().AltiVec || + (Tok.getIdentifierInfo() != Ident_vector && + Tok.getIdentifierInfo() != Ident_pixel)) + return false; + + return TryAltiVecTokenOutOfLine(DS, Loc, PrevSpec, DiagID, isInvalid); + } + + /// TryAltiVecVectorToken - Check for context-sensitive AltiVec vector + /// identifier token, replacing it with the non-context-sensitive __vector. + /// This returns true if the token was replaced. + bool TryAltiVecVectorToken() { + if (!getLangOpts().AltiVec || + Tok.getIdentifierInfo() != Ident_vector) return false; + return TryAltiVecVectorTokenOutOfLine(); + } + + bool TryAltiVecVectorTokenOutOfLine(); + bool TryAltiVecTokenOutOfLine(DeclSpec &DS, SourceLocation Loc, + const char *&PrevSpec, unsigned &DiagID, + bool &isInvalid); + + /// \brief Get the TemplateIdAnnotation from the token. + TemplateIdAnnotation *takeTemplateIdAnnotation(const Token &tok); + + /// TentativeParsingAction - An object that is used as a kind of "tentative + /// parsing transaction". It gets instantiated to mark the token position and + /// after the token consumption is done, Commit() or Revert() is called to + /// either "commit the consumed tokens" or revert to the previously marked + /// token position. Example: + /// + /// TentativeParsingAction TPA(*this); + /// ConsumeToken(); + /// .... + /// TPA.Revert(); + /// + class TentativeParsingAction { + Parser &P; + Token PrevTok; + unsigned short PrevParenCount, PrevBracketCount, PrevBraceCount; + bool isActive; + + public: + explicit TentativeParsingAction(Parser& p) : P(p) { + PrevTok = P.Tok; + PrevParenCount = P.ParenCount; + PrevBracketCount = P.BracketCount; + PrevBraceCount = P.BraceCount; + P.PP.EnableBacktrackAtThisPos(); + isActive = true; + } + void Commit() { + assert(isActive && "Parsing action was finished!"); + P.PP.CommitBacktrackedTokens(); + isActive = false; + } + void Revert() { + assert(isActive && "Parsing action was finished!"); + P.PP.Backtrack(); + P.Tok = PrevTok; + P.ParenCount = PrevParenCount; + P.BracketCount = PrevBracketCount; + P.BraceCount = PrevBraceCount; + isActive = false; + } + ~TentativeParsingAction() { + assert(!isActive && "Forgot to call Commit or Revert!"); + } + }; + + /// ObjCDeclContextSwitch - An object used to switch context from + /// an objective-c decl context to its enclosing decl context and + /// back. + class ObjCDeclContextSwitch { + Parser &P; + Decl *DC; + public: + explicit ObjCDeclContextSwitch(Parser &p) : P(p), + DC(p.getObjCDeclContext()) { + if (DC) + P.Actions.ActOnObjCTemporaryExitContainerContext(cast<DeclContext>(DC)); + } + ~ObjCDeclContextSwitch() { + if (DC) + P.Actions.ActOnObjCReenterContainerContext(cast<DeclContext>(DC)); + } + }; + + /// ExpectAndConsume - The parser expects that 'ExpectedTok' is next in the + /// input. If so, it is consumed and false is returned. + /// + /// If the input is malformed, this emits the specified diagnostic. Next, if + /// SkipToTok is specified, it calls SkipUntil(SkipToTok). Finally, true is + /// returned. + bool ExpectAndConsume(tok::TokenKind ExpectedTok, unsigned Diag, + const char *DiagMsg = "", + tok::TokenKind SkipToTok = tok::unknown); + + /// \brief The parser expects a semicolon and, if present, will consume it. + /// + /// If the next token is not a semicolon, this emits the specified diagnostic, + /// or, if there's just some closing-delimiter noise (e.g., ')' or ']') prior + /// to the semicolon, consumes that extra token. + bool ExpectAndConsumeSemi(unsigned DiagID); + + //===--------------------------------------------------------------------===// + // Scope manipulation + + /// ParseScope - Introduces a new scope for parsing. The kind of + /// scope is determined by ScopeFlags. Objects of this type should + /// be created on the stack to coincide with the position where the + /// parser enters the new scope, and this object's constructor will + /// create that new scope. Similarly, once the object is destroyed + /// the parser will exit the scope. + class ParseScope { + Parser *Self; + ParseScope(const ParseScope&); // do not implement + ParseScope& operator=(const ParseScope&); // do not implement + + public: + // ParseScope - Construct a new object to manage a scope in the + // parser Self where the new Scope is created with the flags + // ScopeFlags, but only when ManageScope is true (the default). If + // ManageScope is false, this object does nothing. + ParseScope(Parser *Self, unsigned ScopeFlags, bool ManageScope = true) + : Self(Self) { + if (ManageScope) + Self->EnterScope(ScopeFlags); + else + this->Self = 0; + } + + // Exit - Exit the scope associated with this object now, rather + // than waiting until the object is destroyed. + void Exit() { + if (Self) { + Self->ExitScope(); + Self = 0; + } + } + + ~ParseScope() { + Exit(); + } + }; + + /// EnterScope - Start a new scope. + void EnterScope(unsigned ScopeFlags); + + /// ExitScope - Pop a scope off the scope stack. + void ExitScope(); + + /// \brief RAII object used to modify the scope flags for the current scope. + class ParseScopeFlags { + Scope *CurScope; + unsigned OldFlags; + ParseScopeFlags(const ParseScopeFlags &); // do not implement + void operator=(const ParseScopeFlags &); // do not implement + + public: + ParseScopeFlags(Parser *Self, unsigned ScopeFlags, bool ManageFlags = true); + ~ParseScopeFlags(); + }; + + //===--------------------------------------------------------------------===// + // Diagnostic Emission and Error recovery. + +public: + DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID); + DiagnosticBuilder Diag(const Token &Tok, unsigned DiagID); + +private: + void SuggestParentheses(SourceLocation Loc, unsigned DK, + SourceRange ParenRange); + void CheckNestedObjCContexts(SourceLocation AtLoc); + + /// SkipUntil - Read tokens until we get to the specified token, then consume + /// it (unless DontConsume is true). Because we cannot guarantee that the + /// token will ever occur, this skips to the next token, or to some likely + /// good stopping point. If StopAtSemi is true, skipping will stop at a ';' + /// character. + /// + /// If SkipUntil finds the specified token, it returns true, otherwise it + /// returns false. + bool SkipUntil(tok::TokenKind T, bool StopAtSemi = true, + bool DontConsume = false, bool StopAtCodeCompletion = false) { + return SkipUntil(llvm::makeArrayRef(T), StopAtSemi, DontConsume, + StopAtCodeCompletion); + } + bool SkipUntil(tok::TokenKind T1, tok::TokenKind T2, bool StopAtSemi = true, + bool DontConsume = false, bool StopAtCodeCompletion = false) { + tok::TokenKind TokArray[] = {T1, T2}; + return SkipUntil(TokArray, StopAtSemi, DontConsume,StopAtCodeCompletion); + } + bool SkipUntil(tok::TokenKind T1, tok::TokenKind T2, tok::TokenKind T3, + bool StopAtSemi = true, bool DontConsume = false, + bool StopAtCodeCompletion = false) { + tok::TokenKind TokArray[] = {T1, T2, T3}; + return SkipUntil(TokArray, StopAtSemi, DontConsume,StopAtCodeCompletion); + } + bool SkipUntil(ArrayRef<tok::TokenKind> Toks, bool StopAtSemi = true, + bool DontConsume = false, bool StopAtCodeCompletion = false); + + /// SkipMalformedDecl - Read tokens until we get to some likely good stopping + /// point for skipping past a simple-declaration. + void SkipMalformedDecl(); + + //===--------------------------------------------------------------------===// + // Lexing and parsing of C++ inline methods. + + struct ParsingClass; + + /// [class.mem]p1: "... the class is regarded as complete within + /// - function bodies + /// - default arguments + /// - exception-specifications (TODO: C++0x) + /// - and brace-or-equal-initializers for non-static data members + /// (including such things in nested classes)." + /// LateParsedDeclarations build the tree of those elements so they can + /// be parsed after parsing the top-level class. + class LateParsedDeclaration { + public: + virtual ~LateParsedDeclaration(); + + virtual void ParseLexedMethodDeclarations(); + virtual void ParseLexedMemberInitializers(); + virtual void ParseLexedMethodDefs(); + virtual void ParseLexedAttributes(); + }; + + /// Inner node of the LateParsedDeclaration tree that parses + /// all its members recursively. + class LateParsedClass : public LateParsedDeclaration { + public: + LateParsedClass(Parser *P, ParsingClass *C); + virtual ~LateParsedClass(); + + virtual void ParseLexedMethodDeclarations(); + virtual void ParseLexedMemberInitializers(); + virtual void ParseLexedMethodDefs(); + virtual void ParseLexedAttributes(); + + private: + Parser *Self; + ParsingClass *Class; + }; + + /// Contains the lexed tokens of an attribute with arguments that + /// may reference member variables and so need to be parsed at the + /// end of the class declaration after parsing all other member + /// member declarations. + /// FIXME: Perhaps we should change the name of LateParsedDeclaration to + /// LateParsedTokens. + struct LateParsedAttribute : public LateParsedDeclaration { + Parser *Self; + CachedTokens Toks; + IdentifierInfo &AttrName; + SourceLocation AttrNameLoc; + SmallVector<Decl*, 2> Decls; + + explicit LateParsedAttribute(Parser *P, IdentifierInfo &Name, + SourceLocation Loc) + : Self(P), AttrName(Name), AttrNameLoc(Loc) {} + + virtual void ParseLexedAttributes(); + + void addDecl(Decl *D) { Decls.push_back(D); } + }; + + /// A list of late parsed attributes. Used by ParseGNUAttributes. + typedef llvm::SmallVector<LateParsedAttribute*, 2> LateParsedAttrList; + + + /// Contains the lexed tokens of a member function definition + /// which needs to be parsed at the end of the class declaration + /// after parsing all other member declarations. + struct LexedMethod : public LateParsedDeclaration { + Parser *Self; + Decl *D; + CachedTokens Toks; + + /// \brief Whether this member function had an associated template + /// scope. When true, D is a template declaration. + /// othewise, it is a member function declaration. + bool TemplateScope; + + explicit LexedMethod(Parser* P, Decl *MD) + : Self(P), D(MD), TemplateScope(false) {} + + virtual void ParseLexedMethodDefs(); + }; + + /// LateParsedDefaultArgument - Keeps track of a parameter that may + /// have a default argument that cannot be parsed yet because it + /// occurs within a member function declaration inside the class + /// (C++ [class.mem]p2). + struct LateParsedDefaultArgument { + explicit LateParsedDefaultArgument(Decl *P, + CachedTokens *Toks = 0) + : Param(P), Toks(Toks) { } + + /// Param - The parameter declaration for this parameter. + Decl *Param; + + /// Toks - The sequence of tokens that comprises the default + /// argument expression, not including the '=' or the terminating + /// ')' or ','. This will be NULL for parameters that have no + /// default argument. + CachedTokens *Toks; + }; + + /// LateParsedMethodDeclaration - A method declaration inside a class that + /// contains at least one entity whose parsing needs to be delayed + /// until the class itself is completely-defined, such as a default + /// argument (C++ [class.mem]p2). + struct LateParsedMethodDeclaration : public LateParsedDeclaration { + explicit LateParsedMethodDeclaration(Parser *P, Decl *M) + : Self(P), Method(M), TemplateScope(false), ExceptionSpecTokens(0) { } + + virtual void ParseLexedMethodDeclarations(); + + Parser* Self; + + /// Method - The method declaration. + Decl *Method; + + /// \brief Whether this member function had an associated template + /// scope. When true, D is a template declaration. + /// othewise, it is a member function declaration. + bool TemplateScope; + + /// DefaultArgs - Contains the parameters of the function and + /// their default arguments. At least one of the parameters will + /// have a default argument, but all of the parameters of the + /// method will be stored so that they can be reintroduced into + /// scope at the appropriate times. + SmallVector<LateParsedDefaultArgument, 8> DefaultArgs; + + /// \brief The set of tokens that make up an exception-specification that + /// has not yet been parsed. + CachedTokens *ExceptionSpecTokens; + }; + + /// LateParsedMemberInitializer - An initializer for a non-static class data + /// member whose parsing must to be delayed until the class is completely + /// defined (C++11 [class.mem]p2). + struct LateParsedMemberInitializer : public LateParsedDeclaration { + LateParsedMemberInitializer(Parser *P, Decl *FD) + : Self(P), Field(FD) { } + + virtual void ParseLexedMemberInitializers(); + + Parser *Self; + + /// Field - The field declaration. + Decl *Field; + + /// CachedTokens - The sequence of tokens that comprises the initializer, + /// including any leading '='. + CachedTokens Toks; + }; + + /// LateParsedDeclarationsContainer - During parsing of a top (non-nested) + /// C++ class, its method declarations that contain parts that won't be + /// parsed until after the definition is completed (C++ [class.mem]p2), + /// the method declarations and possibly attached inline definitions + /// will be stored here with the tokens that will be parsed to create those + /// entities. + typedef SmallVector<LateParsedDeclaration*,2> LateParsedDeclarationsContainer; + + /// \brief Representation of a class that has been parsed, including + /// any member function declarations or definitions that need to be + /// parsed after the corresponding top-level class is complete. + struct ParsingClass { + ParsingClass(Decl *TagOrTemplate, bool TopLevelClass) + : TopLevelClass(TopLevelClass), TemplateScope(false), + TagOrTemplate(TagOrTemplate) { } + + /// \brief Whether this is a "top-level" class, meaning that it is + /// not nested within another class. + bool TopLevelClass : 1; + + /// \brief Whether this class had an associated template + /// scope. When true, TagOrTemplate is a template declaration; + /// othewise, it is a tag declaration. + bool TemplateScope : 1; + + /// \brief The class or class template whose definition we are parsing. + Decl *TagOrTemplate; + + /// LateParsedDeclarations - Method declarations, inline definitions and + /// nested classes that contain pieces whose parsing will be delayed until + /// the top-level class is fully defined. + LateParsedDeclarationsContainer LateParsedDeclarations; + }; + + /// \brief The stack of classes that is currently being + /// parsed. Nested and local classes will be pushed onto this stack + /// when they are parsed, and removed afterward. + std::stack<ParsingClass *> ClassStack; + + ParsingClass &getCurrentClass() { + assert(!ClassStack.empty() && "No lexed method stacks!"); + return *ClassStack.top(); + } + + /// \brief RAII object used to inform the actions that we're + /// currently parsing a declaration. This is active when parsing a + /// variable's initializer, but not when parsing the body of a + /// class or function definition. + class ParsingDeclRAIIObject { + Sema &Actions; + Sema::ParsingDeclState State; + bool Popped; + + public: + ParsingDeclRAIIObject(Parser &P) : Actions(P.Actions) { + push(); + } + + ParsingDeclRAIIObject(Parser &P, ParsingDeclRAIIObject *Other) + : Actions(P.Actions) { + if (Other) steal(*Other); + else push(); + } + + /// Creates a RAII object which steals the state from a different + /// object instead of pushing. + ParsingDeclRAIIObject(ParsingDeclRAIIObject &Other) + : Actions(Other.Actions) { + steal(Other); + } + + ~ParsingDeclRAIIObject() { + abort(); + } + + /// Resets the RAII object for a new declaration. + void reset() { + abort(); + push(); + } + + /// Signals that the context was completed without an appropriate + /// declaration being parsed. + void abort() { + pop(0); + } + + void complete(Decl *D) { + assert(!Popped && "ParsingDeclaration has already been popped!"); + pop(D); + } + + private: + void steal(ParsingDeclRAIIObject &Other) { + State = Other.State; + Popped = Other.Popped; + Other.Popped = true; + } + + void push() { + State = Actions.PushParsingDeclaration(); + Popped = false; + } + + void pop(Decl *D) { + if (!Popped) { + Actions.PopParsingDeclaration(State, D); + Popped = true; + } + } + }; + + /// A class for parsing a DeclSpec. + class ParsingDeclSpec : public DeclSpec { + ParsingDeclRAIIObject ParsingRAII; + + public: + ParsingDeclSpec(Parser &P) : DeclSpec(P.AttrFactory), ParsingRAII(P) {} + ParsingDeclSpec(Parser &P, ParsingDeclRAIIObject *RAII) + : DeclSpec(P.AttrFactory), ParsingRAII(P, RAII) {} + + void complete(Decl *D) { + ParsingRAII.complete(D); + } + + void abort() { + ParsingRAII.abort(); + } + }; + + /// A class for parsing a declarator. + class ParsingDeclarator : public Declarator { + ParsingDeclRAIIObject ParsingRAII; + + public: + ParsingDeclarator(Parser &P, const ParsingDeclSpec &DS, TheContext C) + : Declarator(DS, C), ParsingRAII(P) { + } + + const ParsingDeclSpec &getDeclSpec() const { + return static_cast<const ParsingDeclSpec&>(Declarator::getDeclSpec()); + } + + ParsingDeclSpec &getMutableDeclSpec() const { + return const_cast<ParsingDeclSpec&>(getDeclSpec()); + } + + void clear() { + Declarator::clear(); + ParsingRAII.reset(); + } + + void complete(Decl *D) { + ParsingRAII.complete(D); + } + }; + + /// \brief RAII object used to + class ParsingClassDefinition { + Parser &P; + bool Popped; + Sema::ParsingClassState State; + + public: + ParsingClassDefinition(Parser &P, Decl *TagOrTemplate, bool TopLevelClass) + : P(P), Popped(false), + State(P.PushParsingClass(TagOrTemplate, TopLevelClass)) { + } + + /// \brief Pop this class of the stack. + void Pop() { + assert(!Popped && "Nested class has already been popped"); + Popped = true; + P.PopParsingClass(State); + } + + ~ParsingClassDefinition() { + if (!Popped) + P.PopParsingClass(State); + } + }; + + /// \brief Contains information about any template-specific + /// information that has been parsed prior to parsing declaration + /// specifiers. + struct ParsedTemplateInfo { + ParsedTemplateInfo() + : Kind(NonTemplate), TemplateParams(0), TemplateLoc() { } + + ParsedTemplateInfo(TemplateParameterLists *TemplateParams, + bool isSpecialization, + bool lastParameterListWasEmpty = false) + : Kind(isSpecialization? ExplicitSpecialization : Template), + TemplateParams(TemplateParams), + LastParameterListWasEmpty(lastParameterListWasEmpty) { } + + explicit ParsedTemplateInfo(SourceLocation ExternLoc, + SourceLocation TemplateLoc) + : Kind(ExplicitInstantiation), TemplateParams(0), + ExternLoc(ExternLoc), TemplateLoc(TemplateLoc), + LastParameterListWasEmpty(false){ } + + /// \brief The kind of template we are parsing. + enum { + /// \brief We are not parsing a template at all. + NonTemplate = 0, + /// \brief We are parsing a template declaration. + Template, + /// \brief We are parsing an explicit specialization. + ExplicitSpecialization, + /// \brief We are parsing an explicit instantiation. + ExplicitInstantiation + } Kind; + + /// \brief The template parameter lists, for template declarations + /// and explicit specializations. + TemplateParameterLists *TemplateParams; + + /// \brief The location of the 'extern' keyword, if any, for an explicit + /// instantiation + SourceLocation ExternLoc; + + /// \brief The location of the 'template' keyword, for an explicit + /// instantiation. + SourceLocation TemplateLoc; + + /// \brief Whether the last template parameter list was empty. + bool LastParameterListWasEmpty; + + SourceRange getSourceRange() const LLVM_READONLY; + }; + + /// \brief Contains a late templated function. + /// Will be parsed at the end of the translation unit. + struct LateParsedTemplatedFunction { + explicit LateParsedTemplatedFunction(Decl *MD) + : D(MD) {} + + CachedTokens Toks; + + /// \brief The template function declaration to be late parsed. + Decl *D; + }; + + void LexTemplateFunctionForLateParsing(CachedTokens &Toks); + void ParseLateTemplatedFuncDef(LateParsedTemplatedFunction &LMT); + typedef llvm::DenseMap<const FunctionDecl*, LateParsedTemplatedFunction*> + LateParsedTemplateMapT; + LateParsedTemplateMapT LateParsedTemplateMap; + + static void LateTemplateParserCallback(void *P, const FunctionDecl *FD); + void LateTemplateParser(const FunctionDecl *FD); + + Sema::ParsingClassState + PushParsingClass(Decl *TagOrTemplate, bool TopLevelClass); + void DeallocateParsedClasses(ParsingClass *Class); + void PopParsingClass(Sema::ParsingClassState); + + Decl *ParseCXXInlineMethodDef(AccessSpecifier AS, AttributeList *AccessAttrs, + ParsingDeclarator &D, + const ParsedTemplateInfo &TemplateInfo, + const VirtSpecifiers& VS, + FunctionDefinitionKind DefinitionKind, + ExprResult& Init); + void ParseCXXNonStaticMemberInitializer(Decl *VarD); + void ParseLexedAttributes(ParsingClass &Class); + void ParseLexedAttributeList(LateParsedAttrList &LAs, Decl *D, + bool EnterScope, bool OnDefinition); + void ParseLexedAttribute(LateParsedAttribute &LA, + bool EnterScope, bool OnDefinition); + void ParseLexedMethodDeclarations(ParsingClass &Class); + void ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM); + void ParseLexedMethodDefs(ParsingClass &Class); + void ParseLexedMethodDef(LexedMethod &LM); + void ParseLexedMemberInitializers(ParsingClass &Class); + void ParseLexedMemberInitializer(LateParsedMemberInitializer &MI); + Decl *ParseLexedObjCMethodDefs(LexedMethod &LM); + bool ConsumeAndStoreFunctionPrologue(CachedTokens &Toks); + bool ConsumeAndStoreUntil(tok::TokenKind T1, + CachedTokens &Toks, + bool StopAtSemi = true, + bool ConsumeFinalToken = true) { + return ConsumeAndStoreUntil(T1, T1, Toks, StopAtSemi, ConsumeFinalToken); + } + bool ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2, + CachedTokens &Toks, + bool StopAtSemi = true, + bool ConsumeFinalToken = true); + + //===--------------------------------------------------------------------===// + // C99 6.9: External Definitions. + struct ParsedAttributesWithRange : ParsedAttributes { + ParsedAttributesWithRange(AttributeFactory &factory) + : ParsedAttributes(factory) {} + + SourceRange Range; + }; + + DeclGroupPtrTy ParseExternalDeclaration(ParsedAttributesWithRange &attrs, + ParsingDeclSpec *DS = 0); + bool isDeclarationAfterDeclarator(); + bool isStartOfFunctionDefinition(const ParsingDeclarator &Declarator); + DeclGroupPtrTy ParseDeclarationOrFunctionDefinition(ParsedAttributes &attrs, + AccessSpecifier AS = AS_none); + DeclGroupPtrTy ParseDeclarationOrFunctionDefinition(ParsingDeclSpec &DS, + AccessSpecifier AS = AS_none); + + Decl *ParseFunctionDefinition(ParsingDeclarator &D, + const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(), + LateParsedAttrList *LateParsedAttrs = 0); + void ParseKNRParamDeclarations(Declarator &D); + // EndLoc, if non-NULL, is filled with the location of the last token of + // the simple-asm. + ExprResult ParseSimpleAsm(SourceLocation *EndLoc = 0); + ExprResult ParseAsmStringLiteral(); + + // Objective-C External Declarations + DeclGroupPtrTy ParseObjCAtDirectives(); + DeclGroupPtrTy ParseObjCAtClassDeclaration(SourceLocation atLoc); + Decl *ParseObjCAtInterfaceDeclaration(SourceLocation AtLoc, + ParsedAttributes &prefixAttrs); + void ParseObjCClassInstanceVariables(Decl *interfaceDecl, + tok::ObjCKeywordKind visibility, + SourceLocation atLoc); + bool ParseObjCProtocolReferences(SmallVectorImpl<Decl *> &P, + SmallVectorImpl<SourceLocation> &PLocs, + bool WarnOnDeclarations, + SourceLocation &LAngleLoc, + SourceLocation &EndProtoLoc); + bool ParseObjCProtocolQualifiers(DeclSpec &DS); + void ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey, + Decl *CDecl); + DeclGroupPtrTy ParseObjCAtProtocolDeclaration(SourceLocation atLoc, + ParsedAttributes &prefixAttrs); + + struct ObjCImplParsingDataRAII { + Parser &P; + Decl *Dcl; + typedef SmallVector<LexedMethod*, 8> LateParsedObjCMethodContainer; + LateParsedObjCMethodContainer LateParsedObjCMethods; + + ObjCImplParsingDataRAII(Parser &parser, Decl *D) + : P(parser), Dcl(D) { + P.CurParsedObjCImpl = this; + Finished = false; + } + ~ObjCImplParsingDataRAII(); + + void finish(SourceRange AtEnd); + bool isFinished() const { return Finished; } + + private: + bool Finished; + }; + ObjCImplParsingDataRAII *CurParsedObjCImpl; + + DeclGroupPtrTy ParseObjCAtImplementationDeclaration(SourceLocation AtLoc); + DeclGroupPtrTy ParseObjCAtEndDeclaration(SourceRange atEnd); + Decl *ParseObjCAtAliasDeclaration(SourceLocation atLoc); + Decl *ParseObjCPropertySynthesize(SourceLocation atLoc); + Decl *ParseObjCPropertyDynamic(SourceLocation atLoc); + + IdentifierInfo *ParseObjCSelectorPiece(SourceLocation &MethodLocation); + // Definitions for Objective-c context sensitive keywords recognition. + enum ObjCTypeQual { + objc_in=0, objc_out, objc_inout, objc_oneway, objc_bycopy, objc_byref, + objc_NumQuals + }; + IdentifierInfo *ObjCTypeQuals[objc_NumQuals]; + + bool isTokIdentifier_in() const; + + ParsedType ParseObjCTypeName(ObjCDeclSpec &DS, Declarator::TheContext Ctx, + ParsedAttributes *ParamAttrs); + void ParseObjCMethodRequirement(); + Decl *ParseObjCMethodPrototype( + tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword, + bool MethodDefinition = true); + Decl *ParseObjCMethodDecl(SourceLocation mLoc, tok::TokenKind mType, + tok::ObjCKeywordKind MethodImplKind = tok::objc_not_keyword, + bool MethodDefinition=true); + void ParseObjCPropertyAttribute(ObjCDeclSpec &DS); + + Decl *ParseObjCMethodDefinition(); + + //===--------------------------------------------------------------------===// + // C99 6.5: Expressions. + + /// TypeCastState - State whether an expression is or may be a type cast. + enum TypeCastState { + NotTypeCast = 0, + MaybeTypeCast, + IsTypeCast + }; + + ExprResult ParseExpression(TypeCastState isTypeCast = NotTypeCast); + ExprResult ParseConstantExpression(TypeCastState isTypeCast = NotTypeCast); + // Expr that doesn't include commas. + ExprResult ParseAssignmentExpression(TypeCastState isTypeCast = NotTypeCast); + + ExprResult ParseExpressionWithLeadingAt(SourceLocation AtLoc); + + ExprResult ParseExpressionWithLeadingExtension(SourceLocation ExtLoc); + + ExprResult ParseRHSOfBinaryExpression(ExprResult LHS, + prec::Level MinPrec); + ExprResult ParseCastExpression(bool isUnaryExpression, + bool isAddressOfOperand, + bool &NotCastExpr, + TypeCastState isTypeCast); + ExprResult ParseCastExpression(bool isUnaryExpression, + bool isAddressOfOperand = false, + TypeCastState isTypeCast = NotTypeCast); + + /// Returns true if the next token would start a postfix-expression + /// suffix. + bool isPostfixExpressionSuffixStart() { + tok::TokenKind K = Tok.getKind(); + return (K == tok::l_square || K == tok::l_paren || + K == tok::period || K == tok::arrow || + K == tok::plusplus || K == tok::minusminus); + } + + ExprResult ParsePostfixExpressionSuffix(ExprResult LHS); + ExprResult ParseUnaryExprOrTypeTraitExpression(); + ExprResult ParseBuiltinPrimaryExpression(); + + ExprResult ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok, + bool &isCastExpr, + ParsedType &CastTy, + SourceRange &CastRange); + + typedef SmallVector<Expr*, 20> ExprListTy; + typedef SmallVector<SourceLocation, 20> CommaLocsTy; + + /// ParseExpressionList - Used for C/C++ (argument-)expression-list. + bool ParseExpressionList(SmallVectorImpl<Expr*> &Exprs, + SmallVectorImpl<SourceLocation> &CommaLocs, + void (Sema::*Completer)(Scope *S, + Expr *Data, + llvm::ArrayRef<Expr *> Args) = 0, + Expr *Data = 0); + + /// ParenParseOption - Control what ParseParenExpression will parse. + enum ParenParseOption { + SimpleExpr, // Only parse '(' expression ')' + CompoundStmt, // Also allow '(' compound-statement ')' + CompoundLiteral, // Also allow '(' type-name ')' '{' ... '}' + CastExpr // Also allow '(' type-name ')' <anything> + }; + ExprResult ParseParenExpression(ParenParseOption &ExprType, + bool stopIfCastExpr, + bool isTypeCast, + ParsedType &CastTy, + SourceLocation &RParenLoc); + + ExprResult ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType, + ParsedType &CastTy, + BalancedDelimiterTracker &Tracker); + ExprResult ParseCompoundLiteralExpression(ParsedType Ty, + SourceLocation LParenLoc, + SourceLocation RParenLoc); + + ExprResult ParseStringLiteralExpression(bool AllowUserDefinedLiteral = false); + + ExprResult ParseGenericSelectionExpression(); + + ExprResult ParseObjCBoolLiteral(); + + //===--------------------------------------------------------------------===// + // C++ Expressions + ExprResult ParseCXXIdExpression(bool isAddressOfOperand = false); + + void CheckForTemplateAndDigraph(Token &Next, ParsedType ObjectTypePtr, + bool EnteringContext, IdentifierInfo &II, + CXXScopeSpec &SS); + + bool ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, + ParsedType ObjectType, + bool EnteringContext, + bool *MayBePseudoDestructor = 0, + bool IsTypename = false); + + //===--------------------------------------------------------------------===// + // C++0x 5.1.2: Lambda expressions + + // [...] () -> type {...} + ExprResult ParseLambdaExpression(); + ExprResult TryParseLambdaExpression(); + llvm::Optional<unsigned> ParseLambdaIntroducer(LambdaIntroducer &Intro); + bool TryParseLambdaIntroducer(LambdaIntroducer &Intro); + ExprResult ParseLambdaExpressionAfterIntroducer( + LambdaIntroducer &Intro); + + //===--------------------------------------------------------------------===// + // C++ 5.2p1: C++ Casts + ExprResult ParseCXXCasts(); + + //===--------------------------------------------------------------------===// + // C++ 5.2p1: C++ Type Identification + ExprResult ParseCXXTypeid(); + + //===--------------------------------------------------------------------===// + // C++ : Microsoft __uuidof Expression + ExprResult ParseCXXUuidof(); + + //===--------------------------------------------------------------------===// + // C++ 5.2.4: C++ Pseudo-Destructor Expressions + ExprResult ParseCXXPseudoDestructor(ExprArg Base, SourceLocation OpLoc, + tok::TokenKind OpKind, + CXXScopeSpec &SS, + ParsedType ObjectType); + + //===--------------------------------------------------------------------===// + // C++ 9.3.2: C++ 'this' pointer + ExprResult ParseCXXThis(); + + //===--------------------------------------------------------------------===// + // C++ 15: C++ Throw Expression + ExprResult ParseThrowExpression(); + + ExceptionSpecificationType tryParseExceptionSpecification( + SourceRange &SpecificationRange, + SmallVectorImpl<ParsedType> &DynamicExceptions, + SmallVectorImpl<SourceRange> &DynamicExceptionRanges, + ExprResult &NoexceptExpr); + + // EndLoc is filled with the location of the last token of the specification. + ExceptionSpecificationType ParseDynamicExceptionSpecification( + SourceRange &SpecificationRange, + SmallVectorImpl<ParsedType> &Exceptions, + SmallVectorImpl<SourceRange> &Ranges); + + //===--------------------------------------------------------------------===// + // C++0x 8: Function declaration trailing-return-type + TypeResult ParseTrailingReturnType(SourceRange &Range); + + //===--------------------------------------------------------------------===// + // C++ 2.13.5: C++ Boolean Literals + ExprResult ParseCXXBoolLiteral(); + + //===--------------------------------------------------------------------===// + // C++ 5.2.3: Explicit type conversion (functional notation) + ExprResult ParseCXXTypeConstructExpression(const DeclSpec &DS); + + bool isCXXSimpleTypeSpecifier() const; + + /// ParseCXXSimpleTypeSpecifier - [C++ 7.1.5.2] Simple type specifiers. + /// This should only be called when the current token is known to be part of + /// simple-type-specifier. + void ParseCXXSimpleTypeSpecifier(DeclSpec &DS); + + bool ParseCXXTypeSpecifierSeq(DeclSpec &DS); + + //===--------------------------------------------------------------------===// + // C++ 5.3.4 and 5.3.5: C++ new and delete + bool ParseExpressionListOrTypeId(SmallVectorImpl<Expr*> &Exprs, + Declarator &D); + void ParseDirectNewDeclarator(Declarator &D); + ExprResult ParseCXXNewExpression(bool UseGlobal, SourceLocation Start); + ExprResult ParseCXXDeleteExpression(bool UseGlobal, + SourceLocation Start); + + //===--------------------------------------------------------------------===// + // C++ if/switch/while condition expression. + bool ParseCXXCondition(ExprResult &ExprResult, Decl *&DeclResult, + SourceLocation Loc, bool ConvertToBoolean); + + //===--------------------------------------------------------------------===// + // C++ types + + //===--------------------------------------------------------------------===// + // C99 6.7.8: Initialization. + + /// ParseInitializer + /// initializer: [C99 6.7.8] + /// assignment-expression + /// '{' ... + ExprResult ParseInitializer() { + if (Tok.isNot(tok::l_brace)) + return ParseAssignmentExpression(); + return ParseBraceInitializer(); + } + bool MayBeDesignationStart(); + ExprResult ParseBraceInitializer(); + ExprResult ParseInitializerWithPotentialDesignator(); + + //===--------------------------------------------------------------------===// + // clang Expressions + + ExprResult ParseBlockLiteralExpression(); // ^{...} + + //===--------------------------------------------------------------------===// + // Objective-C Expressions + ExprResult ParseObjCAtExpression(SourceLocation AtLocation); + ExprResult ParseObjCStringLiteral(SourceLocation AtLoc); + ExprResult ParseObjCCharacterLiteral(SourceLocation AtLoc); + ExprResult ParseObjCNumericLiteral(SourceLocation AtLoc); + ExprResult ParseObjCBooleanLiteral(SourceLocation AtLoc, bool ArgValue); + ExprResult ParseObjCArrayLiteral(SourceLocation AtLoc); + ExprResult ParseObjCDictionaryLiteral(SourceLocation AtLoc); + ExprResult ParseObjCEncodeExpression(SourceLocation AtLoc); + ExprResult ParseObjCSelectorExpression(SourceLocation AtLoc); + ExprResult ParseObjCProtocolExpression(SourceLocation AtLoc); + bool isSimpleObjCMessageExpression(); + ExprResult ParseObjCMessageExpression(); + ExprResult ParseObjCMessageExpressionBody(SourceLocation LBracloc, + SourceLocation SuperLoc, + ParsedType ReceiverType, + ExprArg ReceiverExpr); + ExprResult ParseAssignmentExprWithObjCMessageExprStart( + SourceLocation LBracloc, SourceLocation SuperLoc, + ParsedType ReceiverType, ExprArg ReceiverExpr); + bool ParseObjCXXMessageReceiver(bool &IsExpr, void *&TypeOrExpr); + + //===--------------------------------------------------------------------===// + // C99 6.8: Statements and Blocks. + + StmtResult ParseStatement(SourceLocation *TrailingElseLoc = 0) { + StmtVector Stmts(Actions); + return ParseStatementOrDeclaration(Stmts, true, TrailingElseLoc); + } + StmtResult ParseStatementOrDeclaration(StmtVector &Stmts, + bool OnlyStatement, + SourceLocation *TrailingElseLoc = 0); + StmtResult ParseStatementOrDeclarationAfterAttributes( + StmtVector &Stmts, + bool OnlyStatement, + SourceLocation *TrailingElseLoc, + ParsedAttributesWithRange &Attrs); + StmtResult ParseExprStatement(); + StmtResult ParseLabeledStatement(ParsedAttributesWithRange &attrs); + StmtResult ParseCaseStatement(bool MissingCase = false, + ExprResult Expr = ExprResult()); + StmtResult ParseDefaultStatement(); + StmtResult ParseCompoundStatement(bool isStmtExpr = false); + StmtResult ParseCompoundStatement(bool isStmtExpr, + unsigned ScopeFlags); + StmtResult ParseCompoundStatementBody(bool isStmtExpr = false); + bool ParseParenExprOrCondition(ExprResult &ExprResult, + Decl *&DeclResult, + SourceLocation Loc, + bool ConvertToBoolean); + StmtResult ParseIfStatement(SourceLocation *TrailingElseLoc); + StmtResult ParseSwitchStatement(SourceLocation *TrailingElseLoc); + StmtResult ParseWhileStatement(SourceLocation *TrailingElseLoc); + StmtResult ParseDoStatement(); + StmtResult ParseForStatement(SourceLocation *TrailingElseLoc); + StmtResult ParseGotoStatement(); + StmtResult ParseContinueStatement(); + StmtResult ParseBreakStatement(); + StmtResult ParseReturnStatement(); + StmtResult ParseAsmStatement(bool &msAsm); + StmtResult ParseMicrosoftAsmStatement(SourceLocation AsmLoc); + + /// \brief Describes the behavior that should be taken for an __if_exists + /// block. + enum IfExistsBehavior { + /// \brief Parse the block; this code is always used. + IEB_Parse, + /// \brief Skip the block entirely; this code is never used. + IEB_Skip, + /// \brief Parse the block as a dependent block, which may be used in + /// some template instantiations but not others. + IEB_Dependent + }; + + /// \brief Describes the condition of a Microsoft __if_exists or + /// __if_not_exists block. + struct IfExistsCondition { + /// \brief The location of the initial keyword. + SourceLocation KeywordLoc; + /// \brief Whether this is an __if_exists block (rather than an + /// __if_not_exists block). + bool IsIfExists; + + /// \brief Nested-name-specifier preceding the name. + CXXScopeSpec SS; + + /// \brief The name we're looking for. + UnqualifiedId Name; + + /// \brief The behavior of this __if_exists or __if_not_exists block + /// should. + IfExistsBehavior Behavior; + }; + + bool ParseMicrosoftIfExistsCondition(IfExistsCondition& Result); + void ParseMicrosoftIfExistsStatement(StmtVector &Stmts); + void ParseMicrosoftIfExistsExternalDeclaration(); + void ParseMicrosoftIfExistsClassDeclaration(DeclSpec::TST TagType, + AccessSpecifier& CurAS); + bool ParseMicrosoftIfExistsBraceInitializer(ExprVector &InitExprs, + bool &InitExprsOk); + bool ParseAsmOperandsOpt(SmallVectorImpl<IdentifierInfo *> &Names, + SmallVectorImpl<Expr *> &Constraints, + SmallVectorImpl<Expr *> &Exprs); + + //===--------------------------------------------------------------------===// + // C++ 6: Statements and Blocks + + StmtResult ParseCXXTryBlock(); + StmtResult ParseCXXTryBlockCommon(SourceLocation TryLoc); + StmtResult ParseCXXCatchBlock(); + + //===--------------------------------------------------------------------===// + // MS: SEH Statements and Blocks + + StmtResult ParseSEHTryBlock(); + StmtResult ParseSEHTryBlockCommon(SourceLocation Loc); + StmtResult ParseSEHExceptBlock(SourceLocation Loc); + StmtResult ParseSEHFinallyBlock(SourceLocation Loc); + + //===--------------------------------------------------------------------===// + // Objective-C Statements + + StmtResult ParseObjCAtStatement(SourceLocation atLoc); + StmtResult ParseObjCTryStmt(SourceLocation atLoc); + StmtResult ParseObjCThrowStmt(SourceLocation atLoc); + StmtResult ParseObjCSynchronizedStmt(SourceLocation atLoc); + StmtResult ParseObjCAutoreleasePoolStmt(SourceLocation atLoc); + + + //===--------------------------------------------------------------------===// + // C99 6.7: Declarations. + + /// A context for parsing declaration specifiers. TODO: flesh this + /// out, there are other significant restrictions on specifiers than + /// would be best implemented in the parser. + enum DeclSpecContext { + DSC_normal, // normal context + DSC_class, // class context, enables 'friend' + DSC_type_specifier, // C++ type-specifier-seq + DSC_trailing, // C++11 trailing-type-specifier in a trailing return type + DSC_top_level // top-level/namespace declaration context + }; + + /// Information on a C++0x for-range-initializer found while parsing a + /// declaration which turns out to be a for-range-declaration. + struct ForRangeInit { + SourceLocation ColonLoc; + ExprResult RangeExpr; + + bool ParsedForRangeDecl() { return !ColonLoc.isInvalid(); } + }; + + DeclGroupPtrTy ParseDeclaration(StmtVector &Stmts, + unsigned Context, SourceLocation &DeclEnd, + ParsedAttributesWithRange &attrs); + DeclGroupPtrTy ParseSimpleDeclaration(StmtVector &Stmts, + unsigned Context, + SourceLocation &DeclEnd, + ParsedAttributes &attrs, + bool RequireSemi, + ForRangeInit *FRI = 0); + bool MightBeDeclarator(unsigned Context); + DeclGroupPtrTy ParseDeclGroup(ParsingDeclSpec &DS, unsigned Context, + bool AllowFunctionDefinitions, + SourceLocation *DeclEnd = 0, + ForRangeInit *FRI = 0); + Decl *ParseDeclarationAfterDeclarator(Declarator &D, + const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo()); + bool ParseAsmAttributesAfterDeclarator(Declarator &D); + Decl *ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, + const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo()); + Decl *ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope); + Decl *ParseFunctionTryBlock(Decl *Decl, ParseScope &BodyScope); + + /// \brief When in code-completion, skip parsing of the function/method body + /// unless the body contains the code-completion point. + /// + /// \returns true if the function body was skipped. + bool trySkippingFunctionBody(); + + bool ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, + const ParsedTemplateInfo &TemplateInfo, + AccessSpecifier AS, DeclSpecContext DSC); + DeclSpecContext getDeclSpecContextFromDeclaratorContext(unsigned Context); + void ParseDeclarationSpecifiers(DeclSpec &DS, + const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(), + AccessSpecifier AS = AS_none, + DeclSpecContext DSC = DSC_normal, + LateParsedAttrList *LateAttrs = 0); + + void ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS = AS_none, + DeclSpecContext DSC = DSC_normal); + + void ParseObjCTypeQualifierList(ObjCDeclSpec &DS, + Declarator::TheContext Context); + + void ParseEnumSpecifier(SourceLocation TagLoc, DeclSpec &DS, + const ParsedTemplateInfo &TemplateInfo, + AccessSpecifier AS, DeclSpecContext DSC); + void ParseEnumBody(SourceLocation StartLoc, Decl *TagDecl); + void ParseStructUnionBody(SourceLocation StartLoc, unsigned TagType, + Decl *TagDecl); + + struct FieldCallback { + virtual Decl *invoke(FieldDeclarator &Field) = 0; + virtual ~FieldCallback() {} + + private: + virtual void _anchor(); + }; + struct ObjCPropertyCallback; + + void ParseStructDeclaration(DeclSpec &DS, FieldCallback &Callback); + + bool isDeclarationSpecifier(bool DisambiguatingWithExpression = false); + bool isTypeSpecifierQualifier(); + bool isTypeQualifier() const; + + /// isKnownToBeTypeSpecifier - Return true if we know that the specified token + /// is definitely a type-specifier. Return false if it isn't part of a type + /// specifier or if we're not sure. + bool isKnownToBeTypeSpecifier(const Token &Tok) const; + + /// isDeclarationStatement - Disambiguates between a declaration or an + /// expression statement, when parsing function bodies. + /// Returns true for declaration, false for expression. + bool isDeclarationStatement() { + if (getLangOpts().CPlusPlus) + return isCXXDeclarationStatement(); + return isDeclarationSpecifier(true); + } + + /// isForInitDeclaration - Disambiguates between a declaration or an + /// expression in the context of the C 'clause-1' or the C++ + // 'for-init-statement' part of a 'for' statement. + /// Returns true for declaration, false for expression. + bool isForInitDeclaration() { + if (getLangOpts().CPlusPlus) + return isCXXSimpleDeclaration(/*AllowForRangeDecl=*/true); + return isDeclarationSpecifier(true); + } + + /// \brief Determine whether we are currently at the start of an Objective-C + /// class message that appears to be missing the open bracket '['. + bool isStartOfObjCClassMessageMissingOpenBracket(); + + /// \brief Starting with a scope specifier, identifier, or + /// template-id that refers to the current class, determine whether + /// this is a constructor declarator. + bool isConstructorDeclarator(); + + /// \brief Specifies the context in which type-id/expression + /// disambiguation will occur. + enum TentativeCXXTypeIdContext { + TypeIdInParens, + TypeIdAsTemplateArgument + }; + + + /// isTypeIdInParens - Assumes that a '(' was parsed and now we want to know + /// whether the parens contain an expression or a type-id. + /// Returns true for a type-id and false for an expression. + bool isTypeIdInParens(bool &isAmbiguous) { + if (getLangOpts().CPlusPlus) + return isCXXTypeId(TypeIdInParens, isAmbiguous); + isAmbiguous = false; + return isTypeSpecifierQualifier(); + } + bool isTypeIdInParens() { + bool isAmbiguous; + return isTypeIdInParens(isAmbiguous); + } + + /// isCXXDeclarationStatement - C++-specialized function that disambiguates + /// between a declaration or an expression statement, when parsing function + /// bodies. Returns true for declaration, false for expression. + bool isCXXDeclarationStatement(); + + /// isCXXSimpleDeclaration - C++-specialized function that disambiguates + /// between a simple-declaration or an expression-statement. + /// If during the disambiguation process a parsing error is encountered, + /// the function returns true to let the declaration parsing code handle it. + /// Returns false if the statement is disambiguated as expression. + bool isCXXSimpleDeclaration(bool AllowForRangeDecl); + + /// isCXXFunctionDeclarator - Disambiguates between a function declarator or + /// a constructor-style initializer, when parsing declaration statements. + /// Returns true for function declarator and false for constructor-style + /// initializer. If 'warnIfAmbiguous' is true a warning will be emitted to + /// indicate that the parens were disambiguated as function declarator. + /// If during the disambiguation process a parsing error is encountered, + /// the function returns true to let the declaration parsing code handle it. + bool isCXXFunctionDeclarator(bool warnIfAmbiguous); + + /// isCXXConditionDeclaration - Disambiguates between a declaration or an + /// expression for a condition of a if/switch/while/for statement. + /// If during the disambiguation process a parsing error is encountered, + /// the function returns true to let the declaration parsing code handle it. + bool isCXXConditionDeclaration(); + + bool isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous); + bool isCXXTypeId(TentativeCXXTypeIdContext Context) { + bool isAmbiguous; + return isCXXTypeId(Context, isAmbiguous); + } + + /// TPResult - Used as the result value for functions whose purpose is to + /// disambiguate C++ constructs by "tentatively parsing" them. + /// This is a class instead of a simple enum because the implicit enum-to-bool + /// conversions may cause subtle bugs. + class TPResult { + enum Result { + TPR_true, + TPR_false, + TPR_ambiguous, + TPR_error + }; + Result Res; + TPResult(Result result) : Res(result) {} + public: + static TPResult True() { return TPR_true; } + static TPResult False() { return TPR_false; } + static TPResult Ambiguous() { return TPR_ambiguous; } + static TPResult Error() { return TPR_error; } + + bool operator==(const TPResult &RHS) const { return Res == RHS.Res; } + bool operator!=(const TPResult &RHS) const { return Res != RHS.Res; } + }; + + /// \brief Based only on the given token kind, determine whether we know that + /// we're at the start of an expression or a type-specifier-seq (which may + /// be an expression, in C++). + /// + /// This routine does not attempt to resolve any of the trick cases, e.g., + /// those involving lookup of identifiers. + /// + /// \returns \c TPR_true if this token starts an expression, \c TPR_false if + /// this token starts a type-specifier-seq, or \c TPR_ambiguous if it cannot + /// tell. + TPResult isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind); + + /// isCXXDeclarationSpecifier - Returns TPResult::True() if it is a + /// declaration specifier, TPResult::False() if it is not, + /// TPResult::Ambiguous() if it could be either a decl-specifier or a + /// function-style cast, and TPResult::Error() if a parsing error was + /// encountered. If it could be a braced C++11 function-style cast, returns + /// BracedCastResult. + /// Doesn't consume tokens. + TPResult + isCXXDeclarationSpecifier(TPResult BracedCastResult = TPResult::False()); + + // "Tentative parsing" functions, used for disambiguation. If a parsing error + // is encountered they will return TPResult::Error(). + // Returning TPResult::True()/False() indicates that the ambiguity was + // resolved and tentative parsing may stop. TPResult::Ambiguous() indicates + // that more tentative parsing is necessary for disambiguation. + // They all consume tokens, so backtracking should be used after calling them. + + TPResult TryParseDeclarationSpecifier(); + TPResult TryParseSimpleDeclaration(bool AllowForRangeDecl); + TPResult TryParseTypeofSpecifier(); + TPResult TryParseProtocolQualifiers(); + TPResult TryParseInitDeclaratorList(); + TPResult TryParseDeclarator(bool mayBeAbstract, bool mayHaveIdentifier=true); + TPResult TryParseParameterDeclarationClause(); + TPResult TryParseFunctionDeclarator(); + TPResult TryParseBracketDeclarator(); + + TypeResult ParseTypeName(SourceRange *Range = 0, + Declarator::TheContext Context + = Declarator::TypeNameContext, + AccessSpecifier AS = AS_none, + Decl **OwnedType = 0); + void ParseBlockId(); + + // Check for the start of a C++11 attribute-specifier-seq in a context where + // an attribute is not allowed. + bool CheckProhibitedCXX11Attribute() { + assert(Tok.is(tok::l_square)); + if (!getLangOpts().CPlusPlus0x || NextToken().isNot(tok::l_square)) + return false; + return DiagnoseProhibitedCXX11Attribute(); + } + bool DiagnoseProhibitedCXX11Attribute(); + + void ProhibitAttributes(ParsedAttributesWithRange &attrs) { + if (!attrs.Range.isValid()) return; + DiagnoseProhibitedAttributes(attrs); + attrs.clear(); + } + void DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs); + + void MaybeParseGNUAttributes(Declarator &D, + LateParsedAttrList *LateAttrs = 0) { + if (Tok.is(tok::kw___attribute)) { + ParsedAttributes attrs(AttrFactory); + SourceLocation endLoc; + ParseGNUAttributes(attrs, &endLoc, LateAttrs); + D.takeAttributes(attrs, endLoc); + } + } + void MaybeParseGNUAttributes(ParsedAttributes &attrs, + SourceLocation *endLoc = 0, + LateParsedAttrList *LateAttrs = 0) { + if (Tok.is(tok::kw___attribute)) + ParseGNUAttributes(attrs, endLoc, LateAttrs); + } + void ParseGNUAttributes(ParsedAttributes &attrs, + SourceLocation *endLoc = 0, + LateParsedAttrList *LateAttrs = 0); + void ParseGNUAttributeArgs(IdentifierInfo *AttrName, + SourceLocation AttrNameLoc, + ParsedAttributes &Attrs, + SourceLocation *EndLoc); + + void MaybeParseCXX0XAttributes(Declarator &D) { + if (getLangOpts().CPlusPlus0x && isCXX11AttributeSpecifier()) { + ParsedAttributesWithRange attrs(AttrFactory); + SourceLocation endLoc; + ParseCXX11Attributes(attrs, &endLoc); + D.takeAttributes(attrs, endLoc); + } + } + void MaybeParseCXX0XAttributes(ParsedAttributes &attrs, + SourceLocation *endLoc = 0) { + if (getLangOpts().CPlusPlus0x && isCXX11AttributeSpecifier()) { + ParsedAttributesWithRange attrsWithRange(AttrFactory); + ParseCXX11Attributes(attrsWithRange, endLoc); + attrs.takeAllFrom(attrsWithRange); + } + } + void MaybeParseCXX0XAttributes(ParsedAttributesWithRange &attrs, + SourceLocation *endLoc = 0, + bool OuterMightBeMessageSend = false) { + if (getLangOpts().CPlusPlus0x && + isCXX11AttributeSpecifier(false, OuterMightBeMessageSend)) + ParseCXX11Attributes(attrs, endLoc); + } + + void ParseCXX11AttributeSpecifier(ParsedAttributes &attrs, + SourceLocation *EndLoc = 0); + void ParseCXX11Attributes(ParsedAttributesWithRange &attrs, + SourceLocation *EndLoc = 0); + IdentifierInfo *TryParseCXX11AttributeIdentifier(SourceLocation &Loc); + + void MaybeParseMicrosoftAttributes(ParsedAttributes &attrs, + SourceLocation *endLoc = 0) { + if (getLangOpts().MicrosoftExt && Tok.is(tok::l_square)) + ParseMicrosoftAttributes(attrs, endLoc); + } + void ParseMicrosoftAttributes(ParsedAttributes &attrs, + SourceLocation *endLoc = 0); + void ParseMicrosoftDeclSpec(ParsedAttributes &attrs); + void ParseMicrosoftTypeAttributes(ParsedAttributes &attrs); + void ParseBorlandTypeAttributes(ParsedAttributes &attrs); + void ParseOpenCLAttributes(ParsedAttributes &attrs); + void ParseOpenCLQualifiers(DeclSpec &DS); + + VersionTuple ParseVersionTuple(SourceRange &Range); + void ParseAvailabilityAttribute(IdentifierInfo &Availability, + SourceLocation AvailabilityLoc, + ParsedAttributes &attrs, + SourceLocation *endLoc); + + bool IsThreadSafetyAttribute(llvm::StringRef AttrName); + void ParseThreadSafetyAttribute(IdentifierInfo &AttrName, + SourceLocation AttrNameLoc, + ParsedAttributes &Attrs, + SourceLocation *EndLoc); + + + void ParseTypeofSpecifier(DeclSpec &DS); + SourceLocation ParseDecltypeSpecifier(DeclSpec &DS); + void AnnotateExistingDecltypeSpecifier(const DeclSpec &DS, + SourceLocation StartLoc, + SourceLocation EndLoc); + void ParseUnderlyingTypeSpecifier(DeclSpec &DS); + void ParseAtomicSpecifier(DeclSpec &DS); + + ExprResult ParseAlignArgument(SourceLocation Start, + SourceLocation &EllipsisLoc); + void ParseAlignmentSpecifier(ParsedAttributes &Attrs, + SourceLocation *endLoc = 0); + + VirtSpecifiers::Specifier isCXX0XVirtSpecifier(const Token &Tok) const; + VirtSpecifiers::Specifier isCXX0XVirtSpecifier() const { + return isCXX0XVirtSpecifier(Tok); + } + void ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS); + + bool isCXX0XFinalKeyword() const; + + /// DeclaratorScopeObj - RAII object used in Parser::ParseDirectDeclarator to + /// enter a new C++ declarator scope and exit it when the function is + /// finished. + class DeclaratorScopeObj { + Parser &P; + CXXScopeSpec &SS; + bool EnteredScope; + bool CreatedScope; + public: + DeclaratorScopeObj(Parser &p, CXXScopeSpec &ss) + : P(p), SS(ss), EnteredScope(false), CreatedScope(false) {} + + void EnterDeclaratorScope() { + assert(!EnteredScope && "Already entered the scope!"); + assert(SS.isSet() && "C++ scope was not set!"); + + CreatedScope = true; + P.EnterScope(0); // Not a decl scope. + + if (!P.Actions.ActOnCXXEnterDeclaratorScope(P.getCurScope(), SS)) + EnteredScope = true; + } + + ~DeclaratorScopeObj() { + if (EnteredScope) { + assert(SS.isSet() && "C++ scope was cleared ?"); + P.Actions.ActOnCXXExitDeclaratorScope(P.getCurScope(), SS); + } + if (CreatedScope) + P.ExitScope(); + } + }; + + /// ParseDeclarator - Parse and verify a newly-initialized declarator. + void ParseDeclarator(Declarator &D); + /// A function that parses a variant of direct-declarator. + typedef void (Parser::*DirectDeclParseFunction)(Declarator&); + void ParseDeclaratorInternal(Declarator &D, + DirectDeclParseFunction DirectDeclParser); + + void ParseTypeQualifierListOpt(DeclSpec &DS, bool GNUAttributesAllowed = true, + bool CXX0XAttributesAllowed = true); + void ParseDirectDeclarator(Declarator &D); + void ParseParenDeclarator(Declarator &D); + void ParseFunctionDeclarator(Declarator &D, + ParsedAttributes &attrs, + BalancedDelimiterTracker &Tracker, + bool RequiresArg = false); + bool isFunctionDeclaratorIdentifierList(); + void ParseFunctionDeclaratorIdentifierList( + Declarator &D, + SmallVector<DeclaratorChunk::ParamInfo, 16> &ParamInfo); + void ParseParameterDeclarationClause( + Declarator &D, + ParsedAttributes &attrs, + SmallVector<DeclaratorChunk::ParamInfo, 16> &ParamInfo, + SourceLocation &EllipsisLoc); + void ParseBracketDeclarator(Declarator &D); + + //===--------------------------------------------------------------------===// + // C++ 7: Declarations [dcl.dcl] + + /// The kind of attribute specifier we have found. + enum CXX11AttributeKind { + /// This is not an attribute specifier. + CAK_NotAttributeSpecifier, + /// This should be treated as an attribute-specifier. + CAK_AttributeSpecifier, + /// The next tokens are '[[', but this is not an attribute-specifier. This + /// is ill-formed by C++11 [dcl.attr.grammar]p6. + CAK_InvalidAttributeSpecifier + }; + CXX11AttributeKind + isCXX11AttributeSpecifier(bool Disambiguate = false, + bool OuterMightBeMessageSend = false); + + Decl *ParseNamespace(unsigned Context, SourceLocation &DeclEnd, + SourceLocation InlineLoc = SourceLocation()); + void ParseInnerNamespace(std::vector<SourceLocation>& IdentLoc, + std::vector<IdentifierInfo*>& Ident, + std::vector<SourceLocation>& NamespaceLoc, + unsigned int index, SourceLocation& InlineLoc, + ParsedAttributes& attrs, + BalancedDelimiterTracker &Tracker); + Decl *ParseLinkage(ParsingDeclSpec &DS, unsigned Context); + Decl *ParseUsingDirectiveOrDeclaration(unsigned Context, + const ParsedTemplateInfo &TemplateInfo, + SourceLocation &DeclEnd, + ParsedAttributesWithRange &attrs, + Decl **OwnedType = 0); + Decl *ParseUsingDirective(unsigned Context, + SourceLocation UsingLoc, + SourceLocation &DeclEnd, + ParsedAttributes &attrs); + Decl *ParseUsingDeclaration(unsigned Context, + const ParsedTemplateInfo &TemplateInfo, + SourceLocation UsingLoc, + SourceLocation &DeclEnd, + AccessSpecifier AS = AS_none, + Decl **OwnedType = 0); + Decl *ParseStaticAssertDeclaration(SourceLocation &DeclEnd); + Decl *ParseNamespaceAlias(SourceLocation NamespaceLoc, + SourceLocation AliasLoc, IdentifierInfo *Alias, + SourceLocation &DeclEnd); + + //===--------------------------------------------------------------------===// + // C++ 9: classes [class] and C structs/unions. + void ParseClassSpecifier(tok::TokenKind TagTokKind, SourceLocation TagLoc, + DeclSpec &DS, const ParsedTemplateInfo &TemplateInfo, + AccessSpecifier AS, bool EnteringContext, + DeclSpecContext DSC); + void ParseCXXMemberSpecification(SourceLocation StartLoc, unsigned TagType, + Decl *TagDecl); + ExprResult ParseCXXMemberInitializer(Decl *D, bool IsFunction, + SourceLocation &EqualLoc); + void ParseCXXClassMemberDeclaration(AccessSpecifier AS, AttributeList *Attr, + const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(), + ParsingDeclRAIIObject *DiagsFromTParams = 0); + void ParseConstructorInitializer(Decl *ConstructorDecl); + MemInitResult ParseMemInitializer(Decl *ConstructorDecl); + void HandleMemberFunctionDeclDelays(Declarator& DeclaratorInfo, + Decl *ThisDecl); + + //===--------------------------------------------------------------------===// + // C++ 10: Derived classes [class.derived] + TypeResult ParseBaseTypeSpecifier(SourceLocation &BaseLoc, + SourceLocation &EndLocation); + void ParseBaseClause(Decl *ClassDecl); + BaseResult ParseBaseSpecifier(Decl *ClassDecl); + AccessSpecifier getAccessSpecifierIfPresent() const; + + bool ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, + IdentifierInfo *Name, + SourceLocation NameLoc, + bool EnteringContext, + ParsedType ObjectType, + UnqualifiedId &Id, + bool AssumeTemplateId); + bool ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext, + ParsedType ObjectType, + UnqualifiedId &Result); + bool ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, + bool AllowDestructorName, + bool AllowConstructorName, + ParsedType ObjectType, + SourceLocation& TemplateKWLoc, + UnqualifiedId &Result); + + //===--------------------------------------------------------------------===// + // C++ 14: Templates [temp] + + // C++ 14.1: Template Parameters [temp.param] + Decl *ParseDeclarationStartingWithTemplate(unsigned Context, + SourceLocation &DeclEnd, + AccessSpecifier AS = AS_none, + AttributeList *AccessAttrs = 0); + Decl *ParseTemplateDeclarationOrSpecialization(unsigned Context, + SourceLocation &DeclEnd, + AccessSpecifier AS, + AttributeList *AccessAttrs); + Decl *ParseSingleDeclarationAfterTemplate( + unsigned Context, + const ParsedTemplateInfo &TemplateInfo, + ParsingDeclRAIIObject &DiagsFromParams, + SourceLocation &DeclEnd, + AccessSpecifier AS=AS_none, + AttributeList *AccessAttrs = 0); + bool ParseTemplateParameters(unsigned Depth, + SmallVectorImpl<Decl*> &TemplateParams, + SourceLocation &LAngleLoc, + SourceLocation &RAngleLoc); + bool ParseTemplateParameterList(unsigned Depth, + SmallVectorImpl<Decl*> &TemplateParams); + bool isStartOfTemplateTypeParameter(); + Decl *ParseTemplateParameter(unsigned Depth, unsigned Position); + Decl *ParseTypeParameter(unsigned Depth, unsigned Position); + Decl *ParseTemplateTemplateParameter(unsigned Depth, unsigned Position); + Decl *ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position); + // C++ 14.3: Template arguments [temp.arg] + typedef SmallVector<ParsedTemplateArgument, 16> TemplateArgList; + + bool ParseTemplateIdAfterTemplateName(TemplateTy Template, + SourceLocation TemplateNameLoc, + const CXXScopeSpec &SS, + bool ConsumeLastToken, + SourceLocation &LAngleLoc, + TemplateArgList &TemplateArgs, + SourceLocation &RAngleLoc); + + bool AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, + CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, + UnqualifiedId &TemplateName, + bool AllowTypeAnnotation = true); + void AnnotateTemplateIdTokenAsType(); + bool IsTemplateArgumentList(unsigned Skip = 0); + bool ParseTemplateArgumentList(TemplateArgList &TemplateArgs); + ParsedTemplateArgument ParseTemplateTemplateArgument(); + ParsedTemplateArgument ParseTemplateArgument(); + Decl *ParseExplicitInstantiation(unsigned Context, + SourceLocation ExternLoc, + SourceLocation TemplateLoc, + SourceLocation &DeclEnd, + AccessSpecifier AS = AS_none); + + //===--------------------------------------------------------------------===// + // Modules + DeclGroupPtrTy ParseModuleImport(SourceLocation AtLoc); + + //===--------------------------------------------------------------------===// + // GNU G++: Type Traits [Type-Traits.html in the GCC manual] + ExprResult ParseUnaryTypeTrait(); + ExprResult ParseBinaryTypeTrait(); + ExprResult ParseTypeTrait(); + + //===--------------------------------------------------------------------===// + // Embarcadero: Arary and Expression Traits + ExprResult ParseArrayTypeTrait(); + ExprResult ParseExpressionTrait(); + + //===--------------------------------------------------------------------===// + // Preprocessor code-completion pass-through + virtual void CodeCompleteDirective(bool InConditional); + virtual void CodeCompleteInConditionalExclusion(); + virtual void CodeCompleteMacroName(bool IsDefinition); + virtual void CodeCompletePreprocessorExpression(); + virtual void CodeCompleteMacroArgument(IdentifierInfo *Macro, + MacroInfo *MacroInfo, + unsigned ArgumentIndex); + virtual void CodeCompleteNaturalLanguage(); +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Rewrite/ASTConsumers.h b/clang/include/clang/Rewrite/ASTConsumers.h new file mode 100644 index 0000000..c9c92e3 --- /dev/null +++ b/clang/include/clang/Rewrite/ASTConsumers.h @@ -0,0 +1,48 @@ +//===--- ASTConsumers.h - ASTConsumer implementations -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// AST Consumers. +// +//===----------------------------------------------------------------------===// + +#ifndef REWRITE_ASTCONSUMERS_H +#define REWRITE_ASTCONSUMERS_H + +#include "clang/Basic/LLVM.h" +#include <string> + +namespace clang { + +class ASTConsumer; +class DiagnosticsEngine; +class LangOptions; +class Preprocessor; + +// ObjC rewriter: attempts to rewrite ObjC constructs into pure C code. +// This is considered experimental, and only works with Apple's ObjC runtime. +ASTConsumer *CreateObjCRewriter(const std::string &InFile, + raw_ostream *OS, + DiagnosticsEngine &Diags, + const LangOptions &LOpts, + bool SilenceRewriteMacroWarning); +ASTConsumer *CreateModernObjCRewriter(const std::string &InFile, + raw_ostream *OS, + DiagnosticsEngine &Diags, + const LangOptions &LOpts, + bool SilenceRewriteMacroWarning); + +/// CreateHTMLPrinter - Create an AST consumer which rewrites source code to +/// HTML with syntax highlighting suitable for viewing in a web-browser. +ASTConsumer *CreateHTMLPrinter(raw_ostream *OS, Preprocessor &PP, + bool SyntaxHighlight = true, + bool HighlightMacros = true); + +} // end clang namespace + +#endif diff --git a/clang/include/clang/Rewrite/DeltaTree.h b/clang/include/clang/Rewrite/DeltaTree.h new file mode 100644 index 0000000..f32906a --- /dev/null +++ b/clang/include/clang/Rewrite/DeltaTree.h @@ -0,0 +1,48 @@ +//===--- DeltaTree.h - B-Tree for Rewrite Delta tracking --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the DeltaTree class. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_REWRITE_DELTATREE_H +#define CLANG_REWRITE_DELTATREE_H + +namespace clang { + + /// DeltaTree - a multiway search tree (BTree) structure with some fancy + /// features. B-Trees are generally more memory and cache efficient than + /// binary trees, because they store multiple keys/values in each node. This + /// implements a key/value mapping from index to delta, and allows fast lookup + /// on index. However, an added (important) bonus is that it can also + /// efficiently tell us the full accumulated delta for a specific file offset + /// as well, without traversing the whole tree. + class DeltaTree { + void *Root; // "DeltaTreeNode *" + void operator=(const DeltaTree&); // DO NOT IMPLEMENT + public: + DeltaTree(); + + // Note: Currently we only support copying when the RHS is empty. + DeltaTree(const DeltaTree &RHS); + ~DeltaTree(); + + /// getDeltaAt - Return the accumulated delta at the specified file offset. + /// This includes all insertions or delections that occurred *before* the + /// specified file index. + int getDeltaAt(unsigned FileIndex) const; + + /// AddDelta - When a change is made that shifts around the text buffer, + /// this method is used to record that info. It inserts a delta of 'Delta' + /// into the current DeltaTree at offset FileIndex. + void AddDelta(unsigned FileIndex, int Delta); + }; +} // end namespace clang + +#endif diff --git a/clang/include/clang/Rewrite/FixItRewriter.h b/clang/include/clang/Rewrite/FixItRewriter.h new file mode 100644 index 0000000..44f0611 --- /dev/null +++ b/clang/include/clang/Rewrite/FixItRewriter.h @@ -0,0 +1,130 @@ +//===--- FixItRewriter.h - Fix-It Rewriter Diagnostic Client ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This is a diagnostic client adaptor that performs rewrites as +// suggested by code modification hints attached to diagnostics. It +// then forwards any diagnostics to the adapted diagnostic client. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_REWRITE_FIX_IT_REWRITER_H +#define LLVM_CLANG_REWRITE_FIX_IT_REWRITER_H + +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Rewrite/Rewriter.h" +#include "clang/Edit/EditedSource.h" + +namespace clang { + +class SourceManager; +class FileEntry; + +class FixItOptions { +public: + FixItOptions() : FixWhatYouCan(false), + FixOnlyWarnings(false), Silent(false) { } + + virtual ~FixItOptions(); + + /// \brief This file is about to be rewritten. Return the name of the file + /// that is okay to write to. + /// + /// \param fd out parameter for file descriptor. After the call it may be set + /// to an open file descriptor for the returned filename, or it will be -1 + /// otherwise. + /// + virtual std::string RewriteFilename(const std::string &Filename, int &fd) = 0; + + /// \brief Whether to abort fixing a file when not all errors could be fixed. + bool FixWhatYouCan; + + /// \brief Whether to only fix warnings and not errors. + bool FixOnlyWarnings; + + /// \brief If true, only pass the diagnostic to the actual diagnostic consumer + /// if it is an error or a fixit was applied as part of the diagnostic. + /// It basically silences warnings without accompanying fixits. + bool Silent; +}; + +class FixItRewriter : public DiagnosticConsumer { + /// \brief The diagnostics machinery. + DiagnosticsEngine &Diags; + + edit::EditedSource Editor; + + /// \brief The rewriter used to perform the various code + /// modifications. + Rewriter Rewrite; + + /// \brief The diagnostic client that performs the actual formatting + /// of error messages. + DiagnosticConsumer *Client; + bool OwnsClient; + + /// \brief Turn an input path into an output path. NULL implies overwriting + /// the original. + FixItOptions *FixItOpts; + + /// \brief The number of rewriter failures. + unsigned NumFailures; + + /// \brief Whether the previous diagnostic was not passed to the consumer. + bool PrevDiagSilenced; + +public: + typedef Rewriter::buffer_iterator iterator; + + /// \brief Initialize a new fix-it rewriter. + FixItRewriter(DiagnosticsEngine &Diags, SourceManager &SourceMgr, + const LangOptions &LangOpts, FixItOptions *FixItOpts); + + /// \brief Destroy the fix-it rewriter. + ~FixItRewriter(); + + /// \brief Check whether there are modifications for a given file. + bool IsModified(FileID ID) const { + return Rewrite.getRewriteBufferFor(ID) != NULL; + } + + // Iteration over files with changes. + iterator buffer_begin() { return Rewrite.buffer_begin(); } + iterator buffer_end() { return Rewrite.buffer_end(); } + + /// \brief Write a single modified source file. + /// + /// \returns true if there was an error, false otherwise. + bool WriteFixedFile(FileID ID, raw_ostream &OS); + + /// \brief Write the modified source files. + /// + /// \returns true if there was an error, false otherwise. + bool WriteFixedFiles( + std::vector<std::pair<std::string, std::string> > *RewrittenFiles = 0); + + /// IncludeInDiagnosticCounts - This method (whose default implementation + /// returns true) indicates whether the diagnostics handled by this + /// DiagnosticConsumer should be included in the number of diagnostics + /// reported by DiagnosticsEngine. + virtual bool IncludeInDiagnosticCounts() const; + + /// HandleDiagnostic - Handle this diagnostic, reporting it to the user or + /// capturing it to a log as needed. + virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, + const Diagnostic &Info); + + /// \brief Emit a diagnostic via the adapted diagnostic client. + void Diag(SourceLocation Loc, unsigned DiagID); + + DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const; +}; + +} + +#endif // LLVM_CLANG_REWRITE_FIX_IT_REWRITER_H diff --git a/clang/include/clang/Rewrite/FrontendActions.h b/clang/include/clang/Rewrite/FrontendActions.h new file mode 100644 index 0000000..6e9ecac --- /dev/null +++ b/clang/include/clang/Rewrite/FrontendActions.h @@ -0,0 +1,78 @@ +//===-- FrontendActions.h - Useful Frontend Actions -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_REWRITE_FRONTENDACTIONS_H +#define LLVM_CLANG_REWRITE_FRONTENDACTIONS_H + +#include "clang/Frontend/FrontendAction.h" + +namespace clang { +class FixItRewriter; +class FixItOptions; + +//===----------------------------------------------------------------------===// +// AST Consumer Actions +//===----------------------------------------------------------------------===// + +class HTMLPrintAction : public ASTFrontendAction { +protected: + virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, + StringRef InFile); +}; + +class FixItAction : public ASTFrontendAction { +protected: + OwningPtr<FixItRewriter> Rewriter; + OwningPtr<FixItOptions> FixItOpts; + + virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, + StringRef InFile); + + virtual bool BeginSourceFileAction(CompilerInstance &CI, + StringRef Filename); + + virtual void EndSourceFileAction(); + + virtual bool hasASTFileSupport() const { return false; } + +public: + FixItAction(); + ~FixItAction(); +}; + +/// \brief Emits changes to temporary files and uses them for the original +/// frontend action. +class FixItRecompile : public WrapperFrontendAction { +public: + FixItRecompile(FrontendAction *WrappedAction) + : WrapperFrontendAction(WrappedAction) {} + +protected: + virtual bool BeginInvocation(CompilerInstance &CI); +}; + +class RewriteObjCAction : public ASTFrontendAction { +protected: + virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, + StringRef InFile); +}; + +class RewriteMacrosAction : public PreprocessorFrontendAction { +protected: + void ExecuteAction(); +}; + +class RewriteTestAction : public PreprocessorFrontendAction { +protected: + void ExecuteAction(); +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Rewrite/HTMLRewrite.h b/clang/include/clang/Rewrite/HTMLRewrite.h new file mode 100644 index 0000000..88caf85 --- /dev/null +++ b/clang/include/clang/Rewrite/HTMLRewrite.h @@ -0,0 +1,81 @@ +//==- HTMLRewrite.h - Translate source code into prettified HTML ---*- C++ -*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines a set of functions used for translating source code +// into beautified HTML. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_HTMLREWRITER_H +#define LLVM_CLANG_HTMLREWRITER_H + +#include "clang/Basic/SourceLocation.h" +#include <string> + +namespace clang { + +class Rewriter; +class RewriteBuffer; +class Preprocessor; + +namespace html { + + /// HighlightRange - Highlight a range in the source code with the specified + /// start/end tags. B/E must be in the same file. This ensures that + /// start/end tags are placed at the start/end of each line if the range is + /// multiline. + void HighlightRange(Rewriter &R, SourceLocation B, SourceLocation E, + const char *StartTag, const char *EndTag); + + /// HighlightRange - Highlight a range in the source code with the specified + /// start/end tags. The Start/end of the range must be in the same file. + /// This ensures that start/end tags are placed at the start/end of each line + /// if the range is multiline. + inline void HighlightRange(Rewriter &R, SourceRange Range, + const char *StartTag, const char *EndTag) { + HighlightRange(R, Range.getBegin(), Range.getEnd(), StartTag, EndTag); + } + + /// HighlightRange - This is the same as the above method, but takes + /// decomposed file locations. + void HighlightRange(RewriteBuffer &RB, unsigned B, unsigned E, + const char *BufferStart, + const char *StartTag, const char *EndTag); + + /// EscapeText - HTMLize a specified file so that special characters are + /// are translated so that they are not interpreted as HTML tags. + void EscapeText(Rewriter& R, FileID FID, + bool EscapeSpaces = false, bool ReplaceTabs = false); + + /// EscapeText - HTMLized the provided string so that special characters + /// in 's' are not interpreted as HTML tags. Unlike the version of + /// EscapeText that rewrites a file, this version by default replaces tabs + /// with spaces. + std::string EscapeText(const std::string& s, + bool EscapeSpaces = false, bool ReplaceTabs = false); + + void AddLineNumbers(Rewriter& R, FileID FID); + + void AddHeaderFooterInternalBuiltinCSS(Rewriter& R, FileID FID, + const char *title = NULL); + + /// SyntaxHighlight - Relex the specified FileID and annotate the HTML with + /// information about keywords, comments, etc. + void SyntaxHighlight(Rewriter &R, FileID FID, const Preprocessor &PP); + + /// HighlightMacros - This uses the macro table state from the end of the + /// file, to reexpand macros and insert (into the HTML) information about the + /// macro expansions. This won't be perfectly perfect, but it will be + /// reasonably close. + void HighlightMacros(Rewriter &R, FileID FID, const Preprocessor &PP); + +} // end html namespace +} // end clang namespace + +#endif diff --git a/clang/include/clang/Rewrite/RewriteRope.h b/clang/include/clang/Rewrite/RewriteRope.h new file mode 100644 index 0000000..cb3f8a8 --- /dev/null +++ b/clang/include/clang/Rewrite/RewriteRope.h @@ -0,0 +1,231 @@ +//===--- RewriteRope.h - Rope specialized for rewriter ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the RewriteRope class, which is a powerful string class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_REWRITEROPE_H +#define LLVM_CLANG_REWRITEROPE_H + +#include <cstring> +#include <cassert> +#include <cstddef> +#include <iterator> + +namespace clang { + //===--------------------------------------------------------------------===// + // RopeRefCountString Class + //===--------------------------------------------------------------------===// + + /// RopeRefCountString - This struct is allocated with 'new char[]' from the + /// heap, and represents a reference counted chunk of string data. When its + /// ref count drops to zero, it is delete[]'d. This is primarily managed + /// through the RopePiece class below. + struct RopeRefCountString { + unsigned RefCount; + char Data[1]; // Variable sized. + + void addRef() { + if (this) ++RefCount; + } + + void dropRef() { + if (this && --RefCount == 0) + delete [] (char*)this; + } + }; + + //===--------------------------------------------------------------------===// + // RopePiece Class + //===--------------------------------------------------------------------===// + + /// RopePiece - This class represents a view into a RopeRefCountString object. + /// This allows references to string data to be efficiently chopped up and + /// moved around without having to push around the string data itself. + /// + /// For example, we could have a 1M RopePiece and want to insert something + /// into the middle of it. To do this, we split it into two RopePiece objects + /// that both refer to the same underlying RopeRefCountString (just with + /// different offsets) which is a nice constant time operation. + struct RopePiece { + RopeRefCountString *StrData; + unsigned StartOffs; + unsigned EndOffs; + + RopePiece() : StrData(0), StartOffs(0), EndOffs(0) {} + + RopePiece(RopeRefCountString *Str, unsigned Start, unsigned End) + : StrData(Str), StartOffs(Start), EndOffs(End) { + StrData->addRef(); + } + RopePiece(const RopePiece &RP) + : StrData(RP.StrData), StartOffs(RP.StartOffs), EndOffs(RP.EndOffs) { + StrData->addRef(); + } + + ~RopePiece() { + StrData->dropRef(); + } + + void operator=(const RopePiece &RHS) { + if (StrData != RHS.StrData) { + StrData->dropRef(); + StrData = RHS.StrData; + StrData->addRef(); + } + StartOffs = RHS.StartOffs; + EndOffs = RHS.EndOffs; + } + + const char &operator[](unsigned Offset) const { + return StrData->Data[Offset+StartOffs]; + } + char &operator[](unsigned Offset) { + return StrData->Data[Offset+StartOffs]; + } + + unsigned size() const { return EndOffs-StartOffs; } + }; + + //===--------------------------------------------------------------------===// + // RopePieceBTreeIterator Class + //===--------------------------------------------------------------------===// + + /// RopePieceBTreeIterator - This class provides read-only forward iteration + /// over bytes that are in a RopePieceBTree. This first iterates over bytes + /// in a RopePiece, then iterates over RopePiece's in a RopePieceBTreeLeaf, + /// then iterates over RopePieceBTreeLeaf's in a RopePieceBTree. + class RopePieceBTreeIterator : + public std::iterator<std::forward_iterator_tag, const char, ptrdiff_t> { + /// CurNode - The current B+Tree node that we are inspecting. + const void /*RopePieceBTreeLeaf*/ *CurNode; + /// CurPiece - The current RopePiece in the B+Tree node that we're + /// inspecting. + const RopePiece *CurPiece; + /// CurChar - The current byte in the RopePiece we are pointing to. + unsigned CurChar; + public: + // begin iterator. + RopePieceBTreeIterator(const void /*RopePieceBTreeNode*/ *N); + // end iterator + RopePieceBTreeIterator() : CurNode(0), CurPiece(0), CurChar(0) {} + + char operator*() const { + return (*CurPiece)[CurChar]; + } + + bool operator==(const RopePieceBTreeIterator &RHS) const { + return CurPiece == RHS.CurPiece && CurChar == RHS.CurChar; + } + bool operator!=(const RopePieceBTreeIterator &RHS) const { + return !operator==(RHS); + } + + RopePieceBTreeIterator& operator++() { // Preincrement + if (CurChar+1 < CurPiece->size()) + ++CurChar; + else + MoveToNextPiece(); + return *this; + } + inline RopePieceBTreeIterator operator++(int) { // Postincrement + RopePieceBTreeIterator tmp = *this; ++*this; return tmp; + } + private: + void MoveToNextPiece(); + }; + + //===--------------------------------------------------------------------===// + // RopePieceBTree Class + //===--------------------------------------------------------------------===// + + class RopePieceBTree { + void /*RopePieceBTreeNode*/ *Root; + void operator=(const RopePieceBTree &); // DO NOT IMPLEMENT + public: + RopePieceBTree(); + RopePieceBTree(const RopePieceBTree &RHS); + ~RopePieceBTree(); + + typedef RopePieceBTreeIterator iterator; + iterator begin() const { return iterator(Root); } + iterator end() const { return iterator(); } + unsigned size() const; + unsigned empty() const { return size() == 0; } + + void clear(); + + void insert(unsigned Offset, const RopePiece &R); + + void erase(unsigned Offset, unsigned NumBytes); + }; + + //===--------------------------------------------------------------------===// + // RewriteRope Class + //===--------------------------------------------------------------------===// + +/// RewriteRope - A powerful string class. This class supports extremely +/// efficient insertions and deletions into the middle of it, even for +/// ridiculously long strings. +class RewriteRope { + RopePieceBTree Chunks; + + /// We allocate space for string data out of a buffer of size AllocChunkSize. + /// This keeps track of how much space is left. + RopeRefCountString *AllocBuffer; + unsigned AllocOffs; + enum { AllocChunkSize = 4080 }; + +public: + RewriteRope() : AllocBuffer(0), AllocOffs(AllocChunkSize) {} + RewriteRope(const RewriteRope &RHS) + : Chunks(RHS.Chunks), AllocBuffer(0), AllocOffs(AllocChunkSize) { + } + + ~RewriteRope() { + // If we had an allocation buffer, drop our reference to it. + AllocBuffer->dropRef(); + } + + typedef RopePieceBTree::iterator iterator; + typedef RopePieceBTree::iterator const_iterator; + iterator begin() const { return Chunks.begin(); } + iterator end() const { return Chunks.end(); } + unsigned size() const { return Chunks.size(); } + + void clear() { + Chunks.clear(); + } + + void assign(const char *Start, const char *End) { + clear(); + if (Start != End) + Chunks.insert(0, MakeRopeString(Start, End)); + } + + void insert(unsigned Offset, const char *Start, const char *End) { + assert(Offset <= size() && "Invalid position to insert!"); + if (Start == End) return; + Chunks.insert(Offset, MakeRopeString(Start, End)); + } + + void erase(unsigned Offset, unsigned NumBytes) { + assert(Offset+NumBytes <= size() && "Invalid region to erase!"); + if (NumBytes == 0) return; + Chunks.erase(Offset, NumBytes); + } + +private: + RopePiece MakeRopeString(const char *Start, const char *End); +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Rewrite/Rewriter.h b/clang/include/clang/Rewrite/Rewriter.h new file mode 100644 index 0000000..f1358a0 --- /dev/null +++ b/clang/include/clang/Rewrite/Rewriter.h @@ -0,0 +1,288 @@ +//===--- Rewriter.h - Code rewriting interface ------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Rewriter class, which is used for code +// transformations. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_REWRITER_H +#define LLVM_CLANG_REWRITER_H + +#include "clang/Basic/SourceLocation.h" +#include "clang/Rewrite/DeltaTree.h" +#include "clang/Rewrite/RewriteRope.h" +#include "llvm/ADT/StringRef.h" +#include <cstring> +#include <map> +#include <string> + +namespace clang { + class LangOptions; + class Rewriter; + class SourceManager; + class Stmt; + +/// RewriteBuffer - As code is rewritten, SourceBuffer's from the original +/// input with modifications get a new RewriteBuffer associated with them. The +/// RewriteBuffer captures the modified text itself as well as information used +/// to map between SourceLocation's in the original input and offsets in the +/// RewriteBuffer. For example, if text is inserted into the buffer, any +/// locations after the insertion point have to be mapped. +class RewriteBuffer { + friend class Rewriter; + /// Deltas - Keep track of all the deltas in the source code due to insertions + /// and deletions. + DeltaTree Deltas; + + /// Buffer - This is the actual buffer itself. Note that using a vector or + /// string is a horribly inefficient way to do this, we should use a rope + /// instead. + typedef RewriteRope BufferTy; + BufferTy Buffer; +public: + typedef BufferTy::const_iterator iterator; + iterator begin() const { return Buffer.begin(); } + iterator end() const { return Buffer.end(); } + unsigned size() const { return Buffer.size(); } + + raw_ostream &write(raw_ostream &) const; + + /// RemoveText - Remove the specified text. + void RemoveText(unsigned OrigOffset, unsigned Size, + bool removeLineIfEmpty = false); + + /// InsertText - Insert some text at the specified point, where the offset in + /// the buffer is specified relative to the original SourceBuffer. The + /// text is inserted after the specified location. + /// + void InsertText(unsigned OrigOffset, StringRef Str, + bool InsertAfter = true); + + + /// InsertTextBefore - Insert some text before the specified point, where the + /// offset in the buffer is specified relative to the original + /// SourceBuffer. The text is inserted before the specified location. This is + /// method is the same as InsertText with "InsertAfter == false". + void InsertTextBefore(unsigned OrigOffset, StringRef Str) { + InsertText(OrigOffset, Str, false); + } + + /// InsertTextAfter - Insert some text at the specified point, where the + /// offset in the buffer is specified relative to the original SourceBuffer. + /// The text is inserted after the specified location. + void InsertTextAfter(unsigned OrigOffset, StringRef Str) { + InsertText(OrigOffset, Str); + } + + /// ReplaceText - This method replaces a range of characters in the input + /// buffer with a new string. This is effectively a combined "remove/insert" + /// operation. + void ReplaceText(unsigned OrigOffset, unsigned OrigLength, + StringRef NewStr); + +private: // Methods only usable by Rewriter. + + /// Initialize - Start this rewrite buffer out with a copy of the unmodified + /// input buffer. + void Initialize(const char *BufStart, const char *BufEnd) { + Buffer.assign(BufStart, BufEnd); + } + + /// getMappedOffset - Given an offset into the original SourceBuffer that this + /// RewriteBuffer is based on, map it into the offset space of the + /// RewriteBuffer. If AfterInserts is true and if the OrigOffset indicates a + /// position where text is inserted, the location returned will be after any + /// inserted text at the position. + unsigned getMappedOffset(unsigned OrigOffset, + bool AfterInserts = false) const{ + return Deltas.getDeltaAt(2*OrigOffset+AfterInserts)+OrigOffset; + } + + /// AddInsertDelta - When an insertion is made at a position, this + /// method is used to record that information. + void AddInsertDelta(unsigned OrigOffset, int Change) { + return Deltas.AddDelta(2*OrigOffset, Change); + } + + /// AddReplaceDelta - When a replacement/deletion is made at a position, this + /// method is used to record that information. + void AddReplaceDelta(unsigned OrigOffset, int Change) { + return Deltas.AddDelta(2*OrigOffset+1, Change); + } +}; + + +/// Rewriter - This is the main interface to the rewrite buffers. Its primary +/// job is to dispatch high-level requests to the low-level RewriteBuffers that +/// are involved. +class Rewriter { + SourceManager *SourceMgr; + const LangOptions *LangOpts; + std::map<FileID, RewriteBuffer> RewriteBuffers; +public: + struct RewriteOptions { + /// \brief Given a source range, true to include previous inserts at the + /// beginning of the range as part of the range itself (true by default). + bool IncludeInsertsAtBeginOfRange; + /// \brief Given a source range, true to include previous inserts at the + /// end of the range as part of the range itself (true by default). + bool IncludeInsertsAtEndOfRange; + /// \brief If true and removing some text leaves a blank line + /// also remove the empty line (false by default). + bool RemoveLineIfEmpty; + + RewriteOptions() + : IncludeInsertsAtBeginOfRange(true), + IncludeInsertsAtEndOfRange(true), + RemoveLineIfEmpty(false) { } + }; + + typedef std::map<FileID, RewriteBuffer>::iterator buffer_iterator; + + explicit Rewriter(SourceManager &SM, const LangOptions &LO) + : SourceMgr(&SM), LangOpts(&LO) {} + explicit Rewriter() : SourceMgr(0), LangOpts(0) {} + + void setSourceMgr(SourceManager &SM, const LangOptions &LO) { + SourceMgr = &SM; + LangOpts = &LO; + } + SourceManager &getSourceMgr() const { return *SourceMgr; } + const LangOptions &getLangOpts() const { return *LangOpts; } + + /// isRewritable - Return true if this location is a raw file location, which + /// is rewritable. Locations from macros, etc are not rewritable. + static bool isRewritable(SourceLocation Loc) { + return Loc.isFileID(); + } + + /// getRangeSize - Return the size in bytes of the specified range if they + /// are in the same file. If not, this returns -1. + int getRangeSize(SourceRange Range, + RewriteOptions opts = RewriteOptions()) const; + int getRangeSize(const CharSourceRange &Range, + RewriteOptions opts = RewriteOptions()) const; + + /// getRewrittenText - Return the rewritten form of the text in the specified + /// range. If the start or end of the range was unrewritable or if they are + /// in different buffers, this returns an empty string. + /// + /// Note that this method is not particularly efficient. + /// + std::string getRewrittenText(SourceRange Range) const; + + /// InsertText - Insert the specified string at the specified location in the + /// original buffer. This method returns true (and does nothing) if the input + /// location was not rewritable, false otherwise. + /// + /// \param indentNewLines if true new lines in the string are indented + /// using the indentation of the source line in position \arg Loc. + bool InsertText(SourceLocation Loc, StringRef Str, + bool InsertAfter = true, bool indentNewLines = false); + + /// InsertTextAfter - Insert the specified string at the specified location in + /// the original buffer. This method returns true (and does nothing) if + /// the input location was not rewritable, false otherwise. Text is + /// inserted after any other text that has been previously inserted + /// at the some point (the default behavior for InsertText). + bool InsertTextAfter(SourceLocation Loc, StringRef Str) { + return InsertText(Loc, Str); + } + + /// \brief Insert the specified string after the token in the + /// specified location. + bool InsertTextAfterToken(SourceLocation Loc, StringRef Str); + + /// InsertText - Insert the specified string at the specified location in the + /// original buffer. This method returns true (and does nothing) if the input + /// location was not rewritable, false otherwise. Text is + /// inserted before any other text that has been previously inserted + /// at the some point. + bool InsertTextBefore(SourceLocation Loc, StringRef Str) { + return InsertText(Loc, Str, false); + } + + /// RemoveText - Remove the specified text region. + bool RemoveText(SourceLocation Start, unsigned Length, + RewriteOptions opts = RewriteOptions()); + + /// \brief Remove the specified text region. + bool RemoveText(CharSourceRange range, + RewriteOptions opts = RewriteOptions()) { + return RemoveText(range.getBegin(), getRangeSize(range, opts), opts); + } + + /// \brief Remove the specified text region. + bool RemoveText(SourceRange range, RewriteOptions opts = RewriteOptions()) { + return RemoveText(range.getBegin(), getRangeSize(range, opts), opts); + } + + /// ReplaceText - This method replaces a range of characters in the input + /// buffer with a new string. This is effectively a combined "remove/insert" + /// operation. + bool ReplaceText(SourceLocation Start, unsigned OrigLength, + StringRef NewStr); + + /// ReplaceText - This method replaces a range of characters in the input + /// buffer with a new string. This is effectively a combined "remove/insert" + /// operation. + bool ReplaceText(SourceRange range, StringRef NewStr) { + return ReplaceText(range.getBegin(), getRangeSize(range), NewStr); + } + + /// ReplaceText - This method replaces a range of characters in the input + /// buffer with a new string. This is effectively a combined "remove/insert" + /// operation. + bool ReplaceText(SourceRange range, SourceRange replacementRange); + + /// ReplaceStmt - This replaces a Stmt/Expr with another, using the pretty + /// printer to generate the replacement code. This returns true if the input + /// could not be rewritten, or false if successful. + bool ReplaceStmt(Stmt *From, Stmt *To); + + /// \brief Increase indentation for the lines between the given source range. + /// To determine what the indentation should be, 'parentIndent' is used + /// that should be at a source location with an indentation one degree + /// lower than the given range. + bool IncreaseIndentation(CharSourceRange range, SourceLocation parentIndent); + bool IncreaseIndentation(SourceRange range, SourceLocation parentIndent) { + return IncreaseIndentation(CharSourceRange::getTokenRange(range), + parentIndent); + } + + /// ConvertToString converts statement 'From' to a string using the + /// pretty printer. + std::string ConvertToString(Stmt *From); + + /// getEditBuffer - This is like getRewriteBufferFor, but always returns a + /// buffer, and allows you to write on it directly. This is useful if you + /// want efficient low-level access to apis for scribbling on one specific + /// FileID's buffer. + RewriteBuffer &getEditBuffer(FileID FID); + + /// getRewriteBufferFor - Return the rewrite buffer for the specified FileID. + /// If no modification has been made to it, return null. + const RewriteBuffer *getRewriteBufferFor(FileID FID) const { + std::map<FileID, RewriteBuffer>::const_iterator I = + RewriteBuffers.find(FID); + return I == RewriteBuffers.end() ? 0 : &I->second; + } + + // Iterators over rewrite buffers. + buffer_iterator buffer_begin() { return RewriteBuffers.begin(); } + buffer_iterator buffer_end() { return RewriteBuffers.end(); } + +private: + unsigned getLocationOffsetAndFileID(SourceLocation Loc, FileID &FID) const; +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Rewrite/Rewriters.h b/clang/include/clang/Rewrite/Rewriters.h new file mode 100644 index 0000000..203b9bc --- /dev/null +++ b/clang/include/clang/Rewrite/Rewriters.h @@ -0,0 +1,30 @@ +//===--- Rewriters.h - Rewriter implementations -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header contains miscellaneous utilities for various front-end actions. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_REWRITE_REWRITERS_H +#define LLVM_CLANG_REWRITE_REWRITERS_H + +#include "clang/Basic/LLVM.h" + +namespace clang { +class Preprocessor; + +/// RewriteMacrosInInput - Implement -rewrite-macros mode. +void RewriteMacrosInInput(Preprocessor &PP, raw_ostream *OS); + +/// DoRewriteTest - A simple test for the TokenRewriter class. +void DoRewriteTest(Preprocessor &PP, raw_ostream *OS); + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Rewrite/TokenRewriter.h b/clang/include/clang/Rewrite/TokenRewriter.h new file mode 100644 index 0000000..9ebd33a --- /dev/null +++ b/clang/include/clang/Rewrite/TokenRewriter.h @@ -0,0 +1,79 @@ +//===--- TokenRewriter.h - Token-based Rewriter -----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the TokenRewriter class, which is used for code +// transformations. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOKENREWRITER_H +#define LLVM_CLANG_TOKENREWRITER_H + +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/OwningPtr.h" +#include <list> +#include <map> + +namespace clang { + class Token; + class LangOptions; + class ScratchBuffer; + + class TokenRewriter { + /// TokenList - This is the list of raw tokens that make up this file. Each + /// of these tokens has a unique SourceLocation, which is a FileID. + std::list<Token> TokenList; + + /// TokenRefTy - This is the type used to refer to a token in the TokenList. + typedef std::list<Token>::iterator TokenRefTy; + + /// TokenAtLoc - This map indicates which token exists at a specific + /// SourceLocation. Since each token has a unique SourceLocation, this is a + /// one to one map. The token can return its own location directly, to map + /// backwards. + std::map<SourceLocation, TokenRefTy> TokenAtLoc; + + /// ScratchBuf - This is the buffer that we create scratch tokens from. + /// + OwningPtr<ScratchBuffer> ScratchBuf; + + TokenRewriter(const TokenRewriter&); // DO NOT IMPLEMENT + void operator=(const TokenRewriter&); // DO NOT IMPLEMENT. + public: + /// TokenRewriter - This creates a TokenRewriter for the file with the + /// specified FileID. + TokenRewriter(FileID FID, SourceManager &SM, const LangOptions &LO); + ~TokenRewriter(); + + typedef std::list<Token>::const_iterator token_iterator; + token_iterator token_begin() const { return TokenList.begin(); } + token_iterator token_end() const { return TokenList.end(); } + + + token_iterator AddTokenBefore(token_iterator I, const char *Val); + token_iterator AddTokenAfter(token_iterator I, const char *Val) { + assert(I != token_end() && "Cannot insert after token_end()!"); + return AddTokenBefore(++I, Val); + } + + private: + /// RemapIterator - Convert from token_iterator (a const iterator) to + /// TokenRefTy (a non-const iterator). + TokenRefTy RemapIterator(token_iterator I); + + /// AddToken - Add the specified token into the Rewriter before the other + /// position. + TokenRefTy AddToken(const Token &T, TokenRefTy Where); + }; + + + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Sema/AnalysisBasedWarnings.h b/clang/include/clang/Sema/AnalysisBasedWarnings.h new file mode 100644 index 0000000..eeac973 --- /dev/null +++ b/clang/include/clang/Sema/AnalysisBasedWarnings.h @@ -0,0 +1,102 @@ +//=- AnalysisBasedWarnings.h - Sema warnings based on libAnalysis -*- C++ -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines AnalysisBasedWarnings, a worker object used by Sema +// that issues warnings based on dataflow-analysis. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_ANALYSIS_WARNINGS_H +#define LLVM_CLANG_SEMA_ANALYSIS_WARNINGS_H + +#include "llvm/ADT/DenseMap.h" + +namespace clang { + +class BlockExpr; +class Decl; +class FunctionDecl; +class ObjCMethodDecl; +class QualType; +class Sema; +namespace sema { + class FunctionScopeInfo; +} + +namespace sema { + +class AnalysisBasedWarnings { +public: + class Policy { + friend class AnalysisBasedWarnings; + // The warnings to run. + unsigned enableCheckFallThrough : 1; + unsigned enableCheckUnreachable : 1; + unsigned enableThreadSafetyAnalysis : 1; + public: + Policy(); + void disableCheckFallThrough() { enableCheckFallThrough = 0; } + }; + +private: + Sema &S; + Policy DefaultPolicy; + + enum VisitFlag { NotVisited = 0, Visited = 1, Pending = 2 }; + llvm::DenseMap<const FunctionDecl*, VisitFlag> VisitedFD; + + /// \name Statistics + /// @{ + + /// \brief Number of function CFGs built and analyzed. + unsigned NumFunctionsAnalyzed; + + /// \brief Number of functions for which the CFG could not be successfully + /// built. + unsigned NumFunctionsWithBadCFGs; + + /// \brief Total number of blocks across all CFGs. + unsigned NumCFGBlocks; + + /// \brief Largest number of CFG blocks for a single function analyzed. + unsigned MaxCFGBlocksPerFunction; + + /// \brief Total number of CFGs with variables analyzed for uninitialized + /// uses. + unsigned NumUninitAnalysisFunctions; + + /// \brief Total number of variables analyzed for uninitialized uses. + unsigned NumUninitAnalysisVariables; + + /// \brief Max number of variables analyzed for uninitialized uses in a single + /// function. + unsigned MaxUninitAnalysisVariablesPerFunction; + + /// \brief Total number of block visits during uninitialized use analysis. + unsigned NumUninitAnalysisBlockVisits; + + /// \brief Max number of block visits during uninitialized use analysis of + /// a single function. + unsigned MaxUninitAnalysisBlockVisitsPerFunction; + + /// @} + +public: + AnalysisBasedWarnings(Sema &s); + + void IssueWarnings(Policy P, FunctionScopeInfo *fscope, + const Decl *D, const BlockExpr *blkExpr); + + Policy getDefaultPolicy() { return DefaultPolicy; } + + void PrintStats() const; +}; + +}} // end namespace clang::sema + +#endif diff --git a/clang/include/clang/Sema/AttributeList.h b/clang/include/clang/Sema/AttributeList.h new file mode 100644 index 0000000..142f144 --- /dev/null +++ b/clang/include/clang/Sema/AttributeList.h @@ -0,0 +1,555 @@ +//===--- AttributeList.h - Parsed attribute sets ----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the AttributeList class, which is used to collect +// parsed attributes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_ATTRLIST_H +#define LLVM_CLANG_SEMA_ATTRLIST_H + +#include "llvm/Support/Allocator.h" +#include "llvm/ADT/SmallVector.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/VersionTuple.h" +#include <cassert> + +namespace clang { + class ASTContext; + class IdentifierInfo; + class Expr; + +/// \brief Represents information about a change in availability for +/// an entity, which is part of the encoding of the 'availability' +/// attribute. +struct AvailabilityChange { + /// \brief The location of the keyword indicating the kind of change. + SourceLocation KeywordLoc; + + /// \brief The version number at which the change occurred. + VersionTuple Version; + + /// \brief The source range covering the version number. + SourceRange VersionRange; + + /// \brief Determine whether this availability change is valid. + bool isValid() const { return !Version.empty(); } +}; + +/// AttributeList - Represents GCC's __attribute__ declaration. There are +/// 4 forms of this construct...they are: +/// +/// 1: __attribute__(( const )). ParmName/Args/NumArgs will all be unused. +/// 2: __attribute__(( mode(byte) )). ParmName used, Args/NumArgs unused. +/// 3: __attribute__(( format(printf, 1, 2) )). ParmName/Args/NumArgs all used. +/// 4: __attribute__(( aligned(16) )). ParmName is unused, Args/Num used. +/// +class AttributeList { // TODO: This should really be called ParsedAttribute +private: + IdentifierInfo *AttrName; + IdentifierInfo *ScopeName; + IdentifierInfo *ParmName; + SourceRange AttrRange; + SourceLocation ScopeLoc; + SourceLocation ParmLoc; + + /// The number of expression arguments this attribute has. + /// The expressions themselves are stored after the object. + unsigned NumArgs : 16; + + /// True if Microsoft style: declspec(foo). + unsigned DeclspecAttribute : 1; + + /// True if C++0x-style: [[foo]]. + unsigned CXX0XAttribute : 1; + + /// True if already diagnosed as invalid. + mutable unsigned Invalid : 1; + + /// True if this attribute was used as a type attribute. + mutable unsigned UsedAsTypeAttr : 1; + + /// True if this has the extra information associated with an + /// availability attribute. + unsigned IsAvailability : 1; + + unsigned AttrKind : 8; + + /// \brief The location of the 'unavailable' keyword in an + /// availability attribute. + SourceLocation UnavailableLoc; + + const Expr *MessageExpr; + + /// The next attribute in the current position. + AttributeList *NextInPosition; + + /// The next attribute allocated in the current Pool. + AttributeList *NextInPool; + + Expr **getArgsBuffer() { + return reinterpret_cast<Expr**>(this+1); + } + Expr * const *getArgsBuffer() const { + return reinterpret_cast<Expr* const *>(this+1); + } + + enum AvailabilitySlot { + IntroducedSlot, DeprecatedSlot, ObsoletedSlot + }; + + AvailabilityChange &getAvailabilitySlot(AvailabilitySlot index) { + return reinterpret_cast<AvailabilityChange*>(this+1)[index]; + } + const AvailabilityChange &getAvailabilitySlot(AvailabilitySlot index) const { + return reinterpret_cast<const AvailabilityChange*>(this+1)[index]; + } + + AttributeList(const AttributeList &); // DO NOT IMPLEMENT + void operator=(const AttributeList &); // DO NOT IMPLEMENT + void operator delete(void *); // DO NOT IMPLEMENT + ~AttributeList(); // DO NOT IMPLEMENT + + size_t allocated_size() const; + + AttributeList(IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + IdentifierInfo *parmName, SourceLocation parmLoc, + Expr **args, unsigned numArgs, + bool declspec, bool cxx0x) + : AttrName(attrName), ScopeName(scopeName), ParmName(parmName), + AttrRange(attrRange), ScopeLoc(scopeLoc), ParmLoc(parmLoc), + NumArgs(numArgs), + DeclspecAttribute(declspec), CXX0XAttribute(cxx0x), Invalid(false), + UsedAsTypeAttr(false), IsAvailability(false), + NextInPosition(0), NextInPool(0) { + if (numArgs) memcpy(getArgsBuffer(), args, numArgs * sizeof(Expr*)); + AttrKind = getKind(getName()); + } + + AttributeList(IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + IdentifierInfo *parmName, SourceLocation parmLoc, + const AvailabilityChange &introduced, + const AvailabilityChange &deprecated, + const AvailabilityChange &obsoleted, + SourceLocation unavailable, + const Expr *messageExpr, + bool declspec, bool cxx0x) + : AttrName(attrName), ScopeName(scopeName), ParmName(parmName), + AttrRange(attrRange), ScopeLoc(scopeLoc), ParmLoc(parmLoc), + NumArgs(0), DeclspecAttribute(declspec), CXX0XAttribute(cxx0x), + Invalid(false), UsedAsTypeAttr(false), IsAvailability(true), + UnavailableLoc(unavailable), MessageExpr(messageExpr), + NextInPosition(0), NextInPool(0) { + new (&getAvailabilitySlot(IntroducedSlot)) AvailabilityChange(introduced); + new (&getAvailabilitySlot(DeprecatedSlot)) AvailabilityChange(deprecated); + new (&getAvailabilitySlot(ObsoletedSlot)) AvailabilityChange(obsoleted); + AttrKind = getKind(getName()); + } + + friend class AttributePool; + friend class AttributeFactory; + +public: + enum Kind { + #define PARSED_ATTR(NAME) AT_##NAME, + #include "clang/Sema/AttrParsedAttrList.inc" + PARSED_ATTR(address_space) + PARSED_ATTR(base_check) + PARSED_ATTR(cf_returns_autoreleased) + PARSED_ATTR(ext_vector_type) + PARSED_ATTR(mode) + PARSED_ATTR(neon_polyvector_type) + PARSED_ATTR(neon_vector_type) + PARSED_ATTR(objc_gc) + PARSED_ATTR(objc_ownership) + PARSED_ATTR(opencl_image_access) + PARSED_ATTR(vector_size) + #undef PARSED_ATTR + IgnoredAttribute, + UnknownAttribute + }; + + IdentifierInfo *getName() const { return AttrName; } + SourceLocation getLoc() const { return AttrRange.getBegin(); } + SourceRange getRange() const { return AttrRange; } + + bool hasScope() const { return ScopeName; } + IdentifierInfo *getScopeName() const { return ScopeName; } + SourceLocation getScopeLoc() const { return ScopeLoc; } + + IdentifierInfo *getParameterName() const { return ParmName; } + SourceLocation getParameterLoc() const { return ParmLoc; } + + bool isDeclspecAttribute() const { return DeclspecAttribute; } + bool isCXX0XAttribute() const { return CXX0XAttribute; } + + bool isInvalid() const { return Invalid; } + void setInvalid(bool b = true) const { Invalid = b; } + + bool isUsedAsTypeAttr() const { return UsedAsTypeAttr; } + void setUsedAsTypeAttr() { UsedAsTypeAttr = true; } + + Kind getKind() const { return Kind(AttrKind); } + static Kind getKind(const IdentifierInfo *Name); + + AttributeList *getNext() const { return NextInPosition; } + void setNext(AttributeList *N) { NextInPosition = N; } + + /// getNumArgs - Return the number of actual arguments to this attribute. + unsigned getNumArgs() const { return NumArgs; } + + /// hasParameterOrArguments - Return true if this attribute has a parameter, + /// or has a non empty argument expression list. + bool hasParameterOrArguments() const { return ParmName || NumArgs; } + + /// getArg - Return the specified argument. + Expr *getArg(unsigned Arg) const { + assert(Arg < NumArgs && "Arg access out of range!"); + return getArgsBuffer()[Arg]; + } + + class arg_iterator { + Expr * const *X; + unsigned Idx; + public: + arg_iterator(Expr * const *x, unsigned idx) : X(x), Idx(idx) {} + + arg_iterator& operator++() { + ++Idx; + return *this; + } + + bool operator==(const arg_iterator& I) const { + assert (X == I.X && + "compared arg_iterators are for different argument lists"); + return Idx == I.Idx; + } + + bool operator!=(const arg_iterator& I) const { + return !operator==(I); + } + + Expr* operator*() const { + return X[Idx]; + } + + unsigned getArgNum() const { + return Idx+1; + } + }; + + arg_iterator arg_begin() const { + return arg_iterator(getArgsBuffer(), 0); + } + + arg_iterator arg_end() const { + return arg_iterator(getArgsBuffer(), NumArgs); + } + + const AvailabilityChange &getAvailabilityIntroduced() const { + assert(getKind() == AT_availability && "Not an availability attribute"); + return getAvailabilitySlot(IntroducedSlot); + } + + const AvailabilityChange &getAvailabilityDeprecated() const { + assert(getKind() == AT_availability && "Not an availability attribute"); + return getAvailabilitySlot(DeprecatedSlot); + } + + const AvailabilityChange &getAvailabilityObsoleted() const { + assert(getKind() == AT_availability && "Not an availability attribute"); + return getAvailabilitySlot(ObsoletedSlot); + } + + SourceLocation getUnavailableLoc() const { + assert(getKind() == AT_availability && "Not an availability attribute"); + return UnavailableLoc; + } + + const Expr * getMessageExpr() const { + assert(getKind() == AT_availability && "Not an availability attribute"); + return MessageExpr; + } +}; + +/// A factory, from which one makes pools, from which one creates +/// individual attributes which are deallocated with the pool. +/// +/// Note that it's tolerably cheap to create and destroy one of +/// these as long as you don't actually allocate anything in it. +class AttributeFactory { +public: + enum { + /// The required allocation size of an availability attribute, + /// which we want to ensure is a multiple of sizeof(void*). + AvailabilityAllocSize = + sizeof(AttributeList) + + ((3 * sizeof(AvailabilityChange) + sizeof(void*) - 1) + / sizeof(void*) * sizeof(void*)) + }; + +private: + enum { + /// The number of free lists we want to be sure to support + /// inline. This is just enough that availability attributes + /// don't surpass it. It's actually very unlikely we'll see an + /// attribute that needs more than that; on x86-64 you'd need 10 + /// expression arguments, and on i386 you'd need 19. + InlineFreeListsCapacity = + 1 + (AvailabilityAllocSize - sizeof(AttributeList)) / sizeof(void*) + }; + + llvm::BumpPtrAllocator Alloc; + + /// Free lists. The index is determined by the following formula: + /// (size - sizeof(AttributeList)) / sizeof(void*) + SmallVector<AttributeList*, InlineFreeListsCapacity> FreeLists; + + // The following are the private interface used by AttributePool. + friend class AttributePool; + + /// Allocate an attribute of the given size. + void *allocate(size_t size); + + /// Reclaim all the attributes in the given pool chain, which is + /// non-empty. Note that the current implementation is safe + /// against reclaiming things which were not actually allocated + /// with the allocator, although of course it's important to make + /// sure that their allocator lives at least as long as this one. + void reclaimPool(AttributeList *head); + +public: + AttributeFactory(); + ~AttributeFactory(); +}; + +class AttributePool { + AttributeFactory &Factory; + AttributeList *Head; + + void *allocate(size_t size) { + return Factory.allocate(size); + } + + AttributeList *add(AttributeList *attr) { + // We don't care about the order of the pool. + attr->NextInPool = Head; + Head = attr; + return attr; + } + + void takePool(AttributeList *pool); + +public: + /// Create a new pool for a factory. + AttributePool(AttributeFactory &factory) : Factory(factory), Head(0) {} + + /// Move the given pool's allocations to this pool. + AttributePool(AttributePool &pool) : Factory(pool.Factory), Head(pool.Head) { + pool.Head = 0; + } + + AttributeFactory &getFactory() const { return Factory; } + + void clear() { + if (Head) { + Factory.reclaimPool(Head); + Head = 0; + } + } + + /// Take the given pool's allocations and add them to this pool. + void takeAllFrom(AttributePool &pool) { + if (pool.Head) { + takePool(pool.Head); + pool.Head = 0; + } + } + + ~AttributePool() { + if (Head) Factory.reclaimPool(Head); + } + + AttributeList *create(IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + IdentifierInfo *parmName, SourceLocation parmLoc, + Expr **args, unsigned numArgs, + bool declspec = false, bool cxx0x = false) { + void *memory = allocate(sizeof(AttributeList) + + numArgs * sizeof(Expr*)); + return add(new (memory) AttributeList(attrName, attrRange, + scopeName, scopeLoc, + parmName, parmLoc, + args, numArgs, + declspec, cxx0x)); + } + + AttributeList *create(IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + IdentifierInfo *parmName, SourceLocation parmLoc, + const AvailabilityChange &introduced, + const AvailabilityChange &deprecated, + const AvailabilityChange &obsoleted, + SourceLocation unavailable, + const Expr *MessageExpr, + bool declspec = false, bool cxx0x = false) { + void *memory = allocate(AttributeFactory::AvailabilityAllocSize); + return add(new (memory) AttributeList(attrName, attrRange, + scopeName, scopeLoc, + parmName, parmLoc, + introduced, deprecated, obsoleted, + unavailable, MessageExpr, + declspec, cxx0x)); + } + + AttributeList *createIntegerAttribute(ASTContext &C, IdentifierInfo *Name, + SourceLocation TokLoc, int Arg); +}; + +/// addAttributeLists - Add two AttributeLists together +/// The right-hand list is appended to the left-hand list, if any +/// A pointer to the joined list is returned. +/// Note: the lists are not left unmodified. +inline AttributeList *addAttributeLists(AttributeList *Left, + AttributeList *Right) { + if (!Left) + return Right; + + AttributeList *next = Left, *prev; + do { + prev = next; + next = next->getNext(); + } while (next); + prev->setNext(Right); + return Left; +} + +/// CXX0XAttributeList - A wrapper around a C++0x attribute list. +/// Stores, in addition to the list proper, whether or not an actual list was +/// (as opposed to an empty list, which may be ill-formed in some places) and +/// the source range of the list. +struct CXX0XAttributeList { + AttributeList *AttrList; + SourceRange Range; + bool HasAttr; + CXX0XAttributeList (AttributeList *attrList, SourceRange range, bool hasAttr) + : AttrList(attrList), Range(range), HasAttr (hasAttr) { + } + CXX0XAttributeList () + : AttrList(0), Range(), HasAttr(false) { + } +}; + +/// ParsedAttributes - A collection of parsed attributes. Currently +/// we don't differentiate between the various attribute syntaxes, +/// which is basically silly. +/// +/// Right now this is a very lightweight container, but the expectation +/// is that this will become significantly more serious. +class ParsedAttributes { +public: + ParsedAttributes(AttributeFactory &factory) + : pool(factory), list(0) { + } + + ParsedAttributes(ParsedAttributes &attrs) + : pool(attrs.pool), list(attrs.list) { + attrs.list = 0; + } + + AttributePool &getPool() const { return pool; } + + bool empty() const { return list == 0; } + + void add(AttributeList *newAttr) { + assert(newAttr); + assert(newAttr->getNext() == 0); + newAttr->setNext(list); + list = newAttr; + } + + void addAll(AttributeList *newList) { + if (!newList) return; + + AttributeList *lastInNewList = newList; + while (AttributeList *next = lastInNewList->getNext()) + lastInNewList = next; + + lastInNewList->setNext(list); + list = newList; + } + + void set(AttributeList *newList) { + list = newList; + } + + void takeAllFrom(ParsedAttributes &attrs) { + addAll(attrs.list); + attrs.list = 0; + pool.takeAllFrom(attrs.pool); + } + + void clear() { list = 0; pool.clear(); } + AttributeList *getList() const { return list; } + + /// Returns a reference to the attribute list. Try not to introduce + /// dependencies on this method, it may not be long-lived. + AttributeList *&getListRef() { return list; } + + + AttributeList *addNew(IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + IdentifierInfo *parmName, SourceLocation parmLoc, + Expr **args, unsigned numArgs, + bool declspec = false, bool cxx0x = false) { + AttributeList *attr = + pool.create(attrName, attrRange, scopeName, scopeLoc, parmName, parmLoc, + args, numArgs, declspec, cxx0x); + add(attr); + return attr; + } + + AttributeList *addNew(IdentifierInfo *attrName, SourceRange attrRange, + IdentifierInfo *scopeName, SourceLocation scopeLoc, + IdentifierInfo *parmName, SourceLocation parmLoc, + const AvailabilityChange &introduced, + const AvailabilityChange &deprecated, + const AvailabilityChange &obsoleted, + SourceLocation unavailable, + const Expr *MessageExpr, + bool declspec = false, bool cxx0x = false) { + AttributeList *attr = + pool.create(attrName, attrRange, scopeName, scopeLoc, parmName, parmLoc, + introduced, deprecated, obsoleted, unavailable, + MessageExpr, + declspec, cxx0x); + add(attr); + return attr; + } + + AttributeList *addNewInteger(ASTContext &C, IdentifierInfo *name, + SourceLocation loc, int arg) { + AttributeList *attr = + pool.createIntegerAttribute(C, name, loc, arg); + add(attr); + return attr; + } + + +private: + mutable AttributePool pool; + AttributeList *list; +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Sema/CMakeLists.txt b/clang/include/clang/Sema/CMakeLists.txt new file mode 100644 index 0000000..03f99a3 --- /dev/null +++ b/clang/include/clang/Sema/CMakeLists.txt @@ -0,0 +1,14 @@ +clang_tablegen(AttrTemplateInstantiate.inc -gen-clang-attr-template-instantiate + -I ${CMAKE_CURRENT_SOURCE_DIR}/../../ + SOURCE ../Basic/Attr.td + TARGET ClangAttrTemplateInstantiate) + +clang_tablegen(AttrParsedAttrList.inc -gen-clang-attr-parsed-attr-list + -I ${CMAKE_CURRENT_SOURCE_DIR}/../../ + SOURCE ../Basic/Attr.td + TARGET ClangAttrParsedAttrList) + +clang_tablegen(AttrParsedAttrKinds.inc -gen-clang-attr-parsed-attr-kinds + -I ${CMAKE_CURRENT_SOURCE_DIR}/../../ + SOURCE ../Basic/Attr.td + TARGET ClangAttrParsedAttrKinds)
\ No newline at end of file diff --git a/clang/include/clang/Sema/CXXFieldCollector.h b/clang/include/clang/Sema/CXXFieldCollector.h new file mode 100644 index 0000000..6f3c0b4 --- /dev/null +++ b/clang/include/clang/Sema/CXXFieldCollector.h @@ -0,0 +1,79 @@ +//===- CXXFieldCollector.h - Utility class for C++ class semantic analysis ===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides CXXFieldCollector that is used during parsing & semantic +// analysis of C++ classes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_CXXFIELDCOLLECTOR_H +#define LLVM_CLANG_SEMA_CXXFIELDCOLLECTOR_H + +#include "llvm/ADT/SmallVector.h" + +namespace clang { + class FieldDecl; + +/// CXXFieldCollector - Used to keep track of CXXFieldDecls during parsing of +/// C++ classes. +class CXXFieldCollector { + /// Fields - Contains all FieldDecls collected during parsing of a C++ + /// class. When a nested class is entered, its fields are appended to the + /// fields of its parent class, when it is exited its fields are removed. + SmallVector<FieldDecl*, 32> Fields; + + /// FieldCount - Each entry represents the number of fields collected during + /// the parsing of a C++ class. When a nested class is entered, a new field + /// count is pushed, when it is exited, the field count is popped. + SmallVector<size_t, 4> FieldCount; + + // Example: + // + // class C { + // int x,y; + // class NC { + // int q; + // // At this point, Fields contains [x,y,q] decls and FieldCount contains + // // [2,1]. + // }; + // int z; + // // At this point, Fields contains [x,y,z] decls and FieldCount contains + // // [3]. + // }; + +public: + /// StartClass - Called by Sema::ActOnStartCXXClassDef. + void StartClass() { FieldCount.push_back(0); } + + /// Add - Called by Sema::ActOnCXXMemberDeclarator. + void Add(FieldDecl *D) { + Fields.push_back(D); + ++FieldCount.back(); + } + + /// getCurNumField - The number of fields added to the currently parsed class. + size_t getCurNumFields() const { + assert(!FieldCount.empty() && "no currently-parsed class"); + return FieldCount.back(); + } + + /// getCurFields - Pointer to array of fields added to the currently parsed + /// class. + FieldDecl **getCurFields() { return &*(Fields.end() - getCurNumFields()); } + + /// FinishClass - Called by Sema::ActOnFinishCXXClassDef. + void FinishClass() { + Fields.resize(Fields.size() - getCurNumFields()); + FieldCount.pop_back(); + } +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Sema/CodeCompleteConsumer.h b/clang/include/clang/Sema/CodeCompleteConsumer.h new file mode 100644 index 0000000..fe9bed5 --- /dev/null +++ b/clang/include/clang/Sema/CodeCompleteConsumer.h @@ -0,0 +1,992 @@ +//===---- CodeCompleteConsumer.h - Code Completion Interface ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the CodeCompleteConsumer class. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_SEMA_CODECOMPLETECONSUMER_H +#define LLVM_CLANG_SEMA_CODECOMPLETECONSUMER_H + +#include "clang/AST/Type.h" +#include "clang/AST/CanonicalType.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Allocator.h" +#include "clang-c/Index.h" +#include <string> + +namespace clang { + +class Decl; + +/// \brief Default priority values for code-completion results based +/// on their kind. +enum { + /// \brief Priority for the next initialization in a constructor initializer + /// list. + CCP_NextInitializer = 7, + /// \brief Priority for an enumeration constant inside a switch whose + /// condition is of the enumeration type. + CCP_EnumInCase = 7, + /// \brief Priority for a send-to-super completion. + CCP_SuperCompletion = 20, + /// \brief Priority for a declaration that is in the local scope. + CCP_LocalDeclaration = 34, + /// \brief Priority for a member declaration found from the current + /// method or member function. + CCP_MemberDeclaration = 35, + /// \brief Priority for a language keyword (that isn't any of the other + /// categories). + CCP_Keyword = 40, + /// \brief Priority for a code pattern. + CCP_CodePattern = 40, + /// \brief Priority for a non-type declaration. + CCP_Declaration = 50, + /// \brief Priority for a type. + CCP_Type = CCP_Declaration, + /// \brief Priority for a constant value (e.g., enumerator). + CCP_Constant = 65, + /// \brief Priority for a preprocessor macro. + CCP_Macro = 70, + /// \brief Priority for a nested-name-specifier. + CCP_NestedNameSpecifier = 75, + /// \brief Priority for a result that isn't likely to be what the user wants, + /// but is included for completeness. + CCP_Unlikely = 80, + + /// \brief Priority for the Objective-C "_cmd" implicit parameter. + CCP_ObjC_cmd = CCP_Unlikely +}; + +/// \brief Priority value deltas that are added to code-completion results +/// based on the context of the result. +enum { + /// \brief The result is in a base class. + CCD_InBaseClass = 2, + /// \brief The result is a C++ non-static member function whose qualifiers + /// exactly match the object type on which the member function can be called. + CCD_ObjectQualifierMatch = -1, + /// \brief The selector of the given message exactly matches the selector + /// of the current method, which might imply that some kind of delegation + /// is occurring. + CCD_SelectorMatch = -3, + + /// \brief Adjustment to the "bool" type in Objective-C, where the typedef + /// "BOOL" is preferred. + CCD_bool_in_ObjC = 1, + + /// \brief Adjustment for KVC code pattern priorities when it doesn't look + /// like the + CCD_ProbablyNotObjCCollection = 15, + + /// \brief An Objective-C method being used as a property. + CCD_MethodAsProperty = 2 +}; + +/// \brief Priority value factors by which we will divide or multiply the +/// priority of a code-completion result. +enum { + /// \brief Divide by this factor when a code-completion result's type exactly + /// matches the type we expect. + CCF_ExactTypeMatch = 4, + /// \brief Divide by this factor when a code-completion result's type is + /// similar to the type we expect (e.g., both arithmetic types, both + /// Objective-C object pointer types). + CCF_SimilarTypeMatch = 2 +}; + +/// \brief A simplified classification of types used when determining +/// "similar" types for code completion. +enum SimplifiedTypeClass { + STC_Arithmetic, + STC_Array, + STC_Block, + STC_Function, + STC_ObjectiveC, + STC_Other, + STC_Pointer, + STC_Record, + STC_Void +}; + +/// \brief Determine the simplified type class of the given canonical type. +SimplifiedTypeClass getSimplifiedTypeClass(CanQualType T); + +/// \brief Determine the type that this declaration will have if it is used +/// as a type or in an expression. +QualType getDeclUsageType(ASTContext &C, NamedDecl *ND); + +/// \brief Determine the priority to be given to a macro code completion result +/// with the given name. +/// +/// \param MacroName The name of the macro. +/// +/// \param LangOpts Options describing the current language dialect. +/// +/// \param PreferredTypeIsPointer Whether the preferred type for the context +/// of this macro is a pointer type. +unsigned getMacroUsagePriority(StringRef MacroName, + const LangOptions &LangOpts, + bool PreferredTypeIsPointer = false); + +/// \brief Determine the libclang cursor kind associated with the given +/// declaration. +CXCursorKind getCursorKindForDecl(Decl *D); + +class FunctionDecl; +class FunctionType; +class FunctionTemplateDecl; +class IdentifierInfo; +class NamedDecl; +class NestedNameSpecifier; +class Sema; + +/// \brief The context in which code completion occurred, so that the +/// code-completion consumer can process the results accordingly. +class CodeCompletionContext { +public: + enum Kind { + /// \brief An unspecified code-completion context. + CCC_Other, + /// \brief An unspecified code-completion context where we should also add + /// macro completions. + CCC_OtherWithMacros, + /// \brief Code completion occurred within a "top-level" completion context, + /// e.g., at namespace or global scope. + CCC_TopLevel, + /// \brief Code completion occurred within an Objective-C interface, + /// protocol, or category interface. + CCC_ObjCInterface, + /// \brief Code completion occurred within an Objective-C implementation + /// or category implementation. + CCC_ObjCImplementation, + /// \brief Code completion occurred within the instance variable list of + /// an Objective-C interface, implementation, or category implementation. + CCC_ObjCIvarList, + /// \brief Code completion occurred within a class, struct, or union. + CCC_ClassStructUnion, + /// \brief Code completion occurred where a statement (or declaration) is + /// expected in a function, method, or block. + CCC_Statement, + /// \brief Code completion occurred where an expression is expected. + CCC_Expression, + /// \brief Code completion occurred where an Objective-C message receiver + /// is expected. + CCC_ObjCMessageReceiver, + /// \brief Code completion occurred on the right-hand side of a member + /// access expression using the dot operator. + /// + /// The results of this completion are the members of the type being + /// accessed. The type itself is available via + /// \c CodeCompletionContext::getType(). + CCC_DotMemberAccess, + /// \brief Code completion occurred on the right-hand side of a member + /// access expression using the arrow operator. + /// + /// The results of this completion are the members of the type being + /// accessed. The type itself is available via + /// \c CodeCompletionContext::getType(). + CCC_ArrowMemberAccess, + /// \brief Code completion occurred on the right-hand side of an Objective-C + /// property access expression. + /// + /// The results of this completion are the members of the type being + /// accessed. The type itself is available via + /// \c CodeCompletionContext::getType(). + CCC_ObjCPropertyAccess, + /// \brief Code completion occurred after the "enum" keyword, to indicate + /// an enumeration name. + CCC_EnumTag, + /// \brief Code completion occurred after the "union" keyword, to indicate + /// a union name. + CCC_UnionTag, + /// \brief Code completion occurred after the "struct" or "class" keyword, + /// to indicate a struct or class name. + CCC_ClassOrStructTag, + /// \brief Code completion occurred where a protocol name is expected. + CCC_ObjCProtocolName, + /// \brief Code completion occurred where a namespace or namespace alias + /// is expected. + CCC_Namespace, + /// \brief Code completion occurred where a type name is expected. + CCC_Type, + /// \brief Code completion occurred where a new name is expected. + CCC_Name, + /// \brief Code completion occurred where a new name is expected and a + /// qualified name is permissible. + CCC_PotentiallyQualifiedName, + /// \brief Code completion occurred where an macro is being defined. + CCC_MacroName, + /// \brief Code completion occurred where a macro name is expected + /// (without any arguments, in the case of a function-like macro). + CCC_MacroNameUse, + /// \brief Code completion occurred within a preprocessor expression. + CCC_PreprocessorExpression, + /// \brief Code completion occurred where a preprocessor directive is + /// expected. + CCC_PreprocessorDirective, + /// \brief Code completion occurred in a context where natural language is + /// expected, e.g., a comment or string literal. + /// + /// This context usually implies that no completions should be added, + /// unless they come from an appropriate natural-language dictionary. + CCC_NaturalLanguage, + /// \brief Code completion for a selector, as in an @selector expression. + CCC_SelectorName, + /// \brief Code completion within a type-qualifier list. + CCC_TypeQualifiers, + /// \brief Code completion in a parenthesized expression, which means that + /// we may also have types here in C and Objective-C (as well as in C++). + CCC_ParenthesizedExpression, + /// \brief Code completion where an Objective-C instance message is expcted. + CCC_ObjCInstanceMessage, + /// \brief Code completion where an Objective-C class message is expected. + CCC_ObjCClassMessage, + /// \brief Code completion where the name of an Objective-C class is + /// expected. + CCC_ObjCInterfaceName, + /// \brief Code completion where an Objective-C category name is expected. + CCC_ObjCCategoryName, + /// \brief An unknown context, in which we are recovering from a parsing + /// error and don't know which completions we should give. + CCC_Recovery + }; + +private: + enum Kind Kind; + + /// \brief The type that would prefer to see at this point (e.g., the type + /// of an initializer or function parameter). + QualType PreferredType; + + /// \brief The type of the base object in a member access expression. + QualType BaseType; + + /// \brief The identifiers for Objective-C selector parts. + IdentifierInfo **SelIdents; + + /// \brief The number of Objective-C selector parts. + unsigned NumSelIdents; + +public: + /// \brief Construct a new code-completion context of the given kind. + CodeCompletionContext(enum Kind Kind) : Kind(Kind), SelIdents(NULL), + NumSelIdents(0) { } + + /// \brief Construct a new code-completion context of the given kind. + CodeCompletionContext(enum Kind Kind, QualType T, + IdentifierInfo **SelIdents = NULL, + unsigned NumSelIdents = 0) : Kind(Kind), + SelIdents(SelIdents), + NumSelIdents(NumSelIdents) { + if (Kind == CCC_DotMemberAccess || Kind == CCC_ArrowMemberAccess || + Kind == CCC_ObjCPropertyAccess || Kind == CCC_ObjCClassMessage || + Kind == CCC_ObjCInstanceMessage) + BaseType = T; + else + PreferredType = T; + } + + /// \brief Retrieve the kind of code-completion context. + enum Kind getKind() const { return Kind; } + + /// \brief Retrieve the type that this expression would prefer to have, e.g., + /// if the expression is a variable initializer or a function argument, the + /// type of the corresponding variable or function parameter. + QualType getPreferredType() const { return PreferredType; } + + /// \brief Retrieve the type of the base object in a member-access + /// expression. + QualType getBaseType() const { return BaseType; } + + /// \brief Retrieve the Objective-C selector identifiers. + IdentifierInfo **getSelIdents() const { return SelIdents; } + + /// \brief Retrieve the number of Objective-C selector identifiers. + unsigned getNumSelIdents() const { return NumSelIdents; } + + /// \brief Determines whether we want C++ constructors as results within this + /// context. + bool wantConstructorResults() const; +}; + + +/// \brief A "string" used to describe how code completion can +/// be performed for an entity. +/// +/// A code completion string typically shows how a particular entity can be +/// used. For example, the code completion string for a function would show +/// the syntax to call it, including the parentheses, placeholders for the +/// arguments, etc. +class CodeCompletionString { +public: + /// \brief The different kinds of "chunks" that can occur within a code + /// completion string. + enum ChunkKind { + /// \brief The piece of text that the user is expected to type to + /// match the code-completion string, typically a keyword or the name of a + /// declarator or macro. + CK_TypedText, + /// \brief A piece of text that should be placed in the buffer, e.g., + /// parentheses or a comma in a function call. + CK_Text, + /// \brief A code completion string that is entirely optional. For example, + /// an optional code completion string that describes the default arguments + /// in a function call. + CK_Optional, + /// \brief A string that acts as a placeholder for, e.g., a function + /// call argument. + CK_Placeholder, + /// \brief A piece of text that describes something about the result but + /// should not be inserted into the buffer. + CK_Informative, + /// \brief A piece of text that describes the type of an entity or, for + /// functions and methods, the return type. + CK_ResultType, + /// \brief A piece of text that describes the parameter that corresponds + /// to the code-completion location within a function call, message send, + /// macro invocation, etc. + CK_CurrentParameter, + /// \brief A left parenthesis ('('). + CK_LeftParen, + /// \brief A right parenthesis (')'). + CK_RightParen, + /// \brief A left bracket ('['). + CK_LeftBracket, + /// \brief A right bracket (']'). + CK_RightBracket, + /// \brief A left brace ('{'). + CK_LeftBrace, + /// \brief A right brace ('}'). + CK_RightBrace, + /// \brief A left angle bracket ('<'). + CK_LeftAngle, + /// \brief A right angle bracket ('>'). + CK_RightAngle, + /// \brief A comma separator (','). + CK_Comma, + /// \brief A colon (':'). + CK_Colon, + /// \brief A semicolon (';'). + CK_SemiColon, + /// \brief An '=' sign. + CK_Equal, + /// \brief Horizontal whitespace (' '). + CK_HorizontalSpace, + /// \brief Verticle whitespace ('\n' or '\r\n', depending on the + /// platform). + CK_VerticalSpace + }; + + /// \brief One piece of the code completion string. + struct Chunk { + /// \brief The kind of data stored in this piece of the code completion + /// string. + ChunkKind Kind; + + union { + /// \brief The text string associated with a CK_Text, CK_Placeholder, + /// CK_Informative, or CK_Comma chunk. + /// The string is owned by the chunk and will be deallocated + /// (with delete[]) when the chunk is destroyed. + const char *Text; + + /// \brief The code completion string associated with a CK_Optional chunk. + /// The optional code completion string is owned by the chunk, and will + /// be deallocated (with delete) when the chunk is destroyed. + CodeCompletionString *Optional; + }; + + Chunk() : Kind(CK_Text), Text(0) { } + + explicit Chunk(ChunkKind Kind, const char *Text = ""); + + /// \brief Create a new text chunk. + static Chunk CreateText(const char *Text); + + /// \brief Create a new optional chunk. + static Chunk CreateOptional(CodeCompletionString *Optional); + + /// \brief Create a new placeholder chunk. + static Chunk CreatePlaceholder(const char *Placeholder); + + /// \brief Create a new informative chunk. + static Chunk CreateInformative(const char *Informative); + + /// \brief Create a new result type chunk. + static Chunk CreateResultType(const char *ResultType); + + /// \brief Create a new current-parameter chunk. + static Chunk CreateCurrentParameter(const char *CurrentParameter); + }; + +private: + /// \brief The number of chunks stored in this string. + unsigned NumChunks : 16; + + /// \brief The number of annotations for this code-completion result. + unsigned NumAnnotations : 16; + + /// \brief The priority of this code-completion string. + unsigned Priority : 16; + + /// \brief The availability of this code-completion result. + unsigned Availability : 2; + + /// \brief The kind of the parent context. + unsigned ParentKind : 14; + + /// \brief The name of the parent context. + StringRef ParentName; + + CodeCompletionString(const CodeCompletionString &); // DO NOT IMPLEMENT + CodeCompletionString &operator=(const CodeCompletionString &); // DITTO + + CodeCompletionString(const Chunk *Chunks, unsigned NumChunks, + unsigned Priority, CXAvailabilityKind Availability, + const char **Annotations, unsigned NumAnnotations, + CXCursorKind ParentKind, StringRef ParentName); + ~CodeCompletionString() { } + + friend class CodeCompletionBuilder; + friend class CodeCompletionResult; + +public: + typedef const Chunk *iterator; + iterator begin() const { return reinterpret_cast<const Chunk *>(this + 1); } + iterator end() const { return begin() + NumChunks; } + bool empty() const { return NumChunks == 0; } + unsigned size() const { return NumChunks; } + + const Chunk &operator[](unsigned I) const { + assert(I < size() && "Chunk index out-of-range"); + return begin()[I]; + } + + /// \brief Returns the text in the TypedText chunk. + const char *getTypedText() const; + + /// \brief Retrieve the priority of this code completion result. + unsigned getPriority() const { return Priority; } + + /// \brief Retrieve the availability of this code completion result. + unsigned getAvailability() const { return Availability; } + + /// \brief Retrieve the number of annotations for this code completion result. + unsigned getAnnotationCount() const; + + /// \brief Retrieve the annotation string specified by \c AnnotationNr. + const char *getAnnotation(unsigned AnnotationNr) const; + + /// \brief Retrieve parent context's cursor kind. + CXCursorKind getParentContextKind() const { + return (CXCursorKind)ParentKind; + } + + /// \brief Retrieve the name of the parent context. + StringRef getParentContextName() const { + return ParentName; + } + + /// \brief Retrieve a string representation of the code completion string, + /// which is mainly useful for debugging. + std::string getAsString() const; +}; + +/// \brief An allocator used specifically for the purpose of code completion. +class CodeCompletionAllocator : public llvm::BumpPtrAllocator { +public: + /// \brief Copy the given string into this allocator. + const char *CopyString(StringRef String); + + /// \brief Copy the given string into this allocator. + const char *CopyString(Twine String); + + // \brief Copy the given string into this allocator. + const char *CopyString(const char *String) { + return CopyString(StringRef(String)); + } + + /// \brief Copy the given string into this allocator. + const char *CopyString(const std::string &String) { + return CopyString(StringRef(String)); + } +}; + +/// \brief Allocator for a cached set of global code completions. +class GlobalCodeCompletionAllocator + : public CodeCompletionAllocator, + public RefCountedBase<GlobalCodeCompletionAllocator> +{ + +}; + +class CodeCompletionTUInfo { + llvm::DenseMap<DeclContext *, StringRef> ParentNames; + IntrusiveRefCntPtr<GlobalCodeCompletionAllocator> AllocatorRef; + +public: + explicit CodeCompletionTUInfo( + IntrusiveRefCntPtr<GlobalCodeCompletionAllocator> Allocator) + : AllocatorRef(Allocator) { } + + IntrusiveRefCntPtr<GlobalCodeCompletionAllocator> getAllocatorRef() const { + return AllocatorRef; + } + CodeCompletionAllocator &getAllocator() const { + assert(AllocatorRef); + return *AllocatorRef; + } + + StringRef getParentName(DeclContext *DC); +}; + +} // end namespace clang + +namespace llvm { + template <> struct isPodLike<clang::CodeCompletionString::Chunk> { + static const bool value = true; + }; +} + +namespace clang { + +/// \brief A builder class used to construct new code-completion strings. +class CodeCompletionBuilder { +public: + typedef CodeCompletionString::Chunk Chunk; + +private: + CodeCompletionAllocator &Allocator; + CodeCompletionTUInfo &CCTUInfo; + unsigned Priority; + CXAvailabilityKind Availability; + CXCursorKind ParentKind; + StringRef ParentName; + + /// \brief The chunks stored in this string. + SmallVector<Chunk, 4> Chunks; + + SmallVector<const char *, 2> Annotations; + +public: + CodeCompletionBuilder(CodeCompletionAllocator &Allocator, + CodeCompletionTUInfo &CCTUInfo) + : Allocator(Allocator), CCTUInfo(CCTUInfo), + Priority(0), Availability(CXAvailability_Available), + ParentKind(CXCursor_NotImplemented) { } + + CodeCompletionBuilder(CodeCompletionAllocator &Allocator, + CodeCompletionTUInfo &CCTUInfo, + unsigned Priority, CXAvailabilityKind Availability) + : Allocator(Allocator), CCTUInfo(CCTUInfo), + Priority(Priority), Availability(Availability), + ParentKind(CXCursor_NotImplemented) { } + + /// \brief Retrieve the allocator into which the code completion + /// strings should be allocated. + CodeCompletionAllocator &getAllocator() const { return Allocator; } + + CodeCompletionTUInfo &getCodeCompletionTUInfo() const { return CCTUInfo; } + + /// \brief Take the resulting completion string. + /// + /// This operation can only be performed once. + CodeCompletionString *TakeString(); + + /// \brief Add a new typed-text chunk. + void AddTypedTextChunk(const char *Text); + + /// \brief Add a new text chunk. + void AddTextChunk(const char *Text); + + /// \brief Add a new optional chunk. + void AddOptionalChunk(CodeCompletionString *Optional); + + /// \brief Add a new placeholder chunk. + void AddPlaceholderChunk(const char *Placeholder); + + /// \brief Add a new informative chunk. + void AddInformativeChunk(const char *Text); + + /// \brief Add a new result-type chunk. + void AddResultTypeChunk(const char *ResultType); + + /// \brief Add a new current-parameter chunk. + void AddCurrentParameterChunk(const char *CurrentParameter); + + /// \brief Add a new chunk. + void AddChunk(CodeCompletionString::ChunkKind CK, const char *Text = ""); + + void AddAnnotation(const char *A) { Annotations.push_back(A); } + + /// \brief Add the parent context information to this code completion. + void addParentContext(DeclContext *DC); + + CXCursorKind getParentKind() const { return ParentKind; } + StringRef getParentName() const { return ParentName; } +}; + +/// \brief Captures a result of code completion. +class CodeCompletionResult { +public: + /// \brief Describes the kind of result generated. + enum ResultKind { + RK_Declaration = 0, //< Refers to a declaration + RK_Keyword, //< Refers to a keyword or symbol. + RK_Macro, //< Refers to a macro + RK_Pattern //< Refers to a precomputed pattern. + }; + + /// \brief The kind of result stored here. + ResultKind Kind; + + /// \brief When Kind == RK_Declaration or RK_Pattern, the declaration we are + /// referring to. In the latter case, the declaration might be NULL. + NamedDecl *Declaration; + + union { + /// \brief When Kind == RK_Keyword, the string representing the keyword + /// or symbol's spelling. + const char *Keyword; + + /// \brief When Kind == RK_Pattern, the code-completion string that + /// describes the completion text to insert. + CodeCompletionString *Pattern; + + /// \brief When Kind == RK_Macro, the identifier that refers to a macro. + IdentifierInfo *Macro; + }; + + /// \brief The priority of this particular code-completion result. + unsigned Priority; + + /// \brief The cursor kind that describes this result. + CXCursorKind CursorKind; + + /// \brief The availability of this result. + CXAvailabilityKind Availability; + + /// \brief Specifies which parameter (of a function, Objective-C method, + /// macro, etc.) we should start with when formatting the result. + unsigned StartParameter; + + /// \brief Whether this result is hidden by another name. + bool Hidden : 1; + + /// \brief Whether this result was found via lookup into a base class. + bool QualifierIsInformative : 1; + + /// \brief Whether this declaration is the beginning of a + /// nested-name-specifier and, therefore, should be followed by '::'. + bool StartsNestedNameSpecifier : 1; + + /// \brief Whether all parameters (of a function, Objective-C + /// method, etc.) should be considered "informative". + bool AllParametersAreInformative : 1; + + /// \brief Whether we're completing a declaration of the given entity, + /// rather than a use of that entity. + bool DeclaringEntity : 1; + + /// \brief If the result should have a nested-name-specifier, this is it. + /// When \c QualifierIsInformative, the nested-name-specifier is + /// informative rather than required. + NestedNameSpecifier *Qualifier; + + /// \brief Build a result that refers to a declaration. + CodeCompletionResult(NamedDecl *Declaration, + NestedNameSpecifier *Qualifier = 0, + bool QualifierIsInformative = false, + bool Accessible = true) + : Kind(RK_Declaration), Declaration(Declaration), + Priority(getPriorityFromDecl(Declaration)), + Availability(CXAvailability_Available), StartParameter(0), + Hidden(false), QualifierIsInformative(QualifierIsInformative), + StartsNestedNameSpecifier(false), AllParametersAreInformative(false), + DeclaringEntity(false), Qualifier(Qualifier) { + computeCursorKindAndAvailability(Accessible); + } + + /// \brief Build a result that refers to a keyword or symbol. + CodeCompletionResult(const char *Keyword, unsigned Priority = CCP_Keyword) + : Kind(RK_Keyword), Declaration(0), Keyword(Keyword), Priority(Priority), + Availability(CXAvailability_Available), + StartParameter(0), Hidden(false), QualifierIsInformative(0), + StartsNestedNameSpecifier(false), AllParametersAreInformative(false), + DeclaringEntity(false), Qualifier(0) { + computeCursorKindAndAvailability(); + } + + /// \brief Build a result that refers to a macro. + CodeCompletionResult(IdentifierInfo *Macro, unsigned Priority = CCP_Macro) + : Kind(RK_Macro), Declaration(0), Macro(Macro), Priority(Priority), + Availability(CXAvailability_Available), StartParameter(0), + Hidden(false), QualifierIsInformative(0), + StartsNestedNameSpecifier(false), AllParametersAreInformative(false), + DeclaringEntity(false), Qualifier(0) { + computeCursorKindAndAvailability(); + } + + /// \brief Build a result that refers to a pattern. + CodeCompletionResult(CodeCompletionString *Pattern, + unsigned Priority = CCP_CodePattern, + CXCursorKind CursorKind = CXCursor_NotImplemented, + CXAvailabilityKind Availability = CXAvailability_Available, + NamedDecl *D = 0) + : Kind(RK_Pattern), Declaration(D), Pattern(Pattern), Priority(Priority), + CursorKind(CursorKind), Availability(Availability), StartParameter(0), + Hidden(false), QualifierIsInformative(0), + StartsNestedNameSpecifier(false), AllParametersAreInformative(false), + DeclaringEntity(false), Qualifier(0) + { + } + + /// \brief Build a result that refers to a pattern with an associated + /// declaration. + CodeCompletionResult(CodeCompletionString *Pattern, NamedDecl *D, + unsigned Priority) + : Kind(RK_Pattern), Declaration(D), Pattern(Pattern), Priority(Priority), + Availability(CXAvailability_Available), StartParameter(0), + Hidden(false), QualifierIsInformative(false), + StartsNestedNameSpecifier(false), AllParametersAreInformative(false), + DeclaringEntity(false), Qualifier(0) { + computeCursorKindAndAvailability(); + } + + /// \brief Retrieve the declaration stored in this result. + NamedDecl *getDeclaration() const { + assert(Kind == RK_Declaration && "Not a declaration result"); + return Declaration; + } + + /// \brief Retrieve the keyword stored in this result. + const char *getKeyword() const { + assert(Kind == RK_Keyword && "Not a keyword result"); + return Keyword; + } + + /// \brief Create a new code-completion string that describes how to insert + /// this result into a program. + /// + /// \param S The semantic analysis that created the result. + /// + /// \param Allocator The allocator that will be used to allocate the + /// string itself. + CodeCompletionString *CreateCodeCompletionString(Sema &S, + CodeCompletionAllocator &Allocator, + CodeCompletionTUInfo &CCTUInfo); + CodeCompletionString *CreateCodeCompletionString(ASTContext &Ctx, + Preprocessor &PP, + CodeCompletionAllocator &Allocator, + CodeCompletionTUInfo &CCTUInfo); + + /// \brief Determine a base priority for the given declaration. + static unsigned getPriorityFromDecl(NamedDecl *ND); + +private: + void computeCursorKindAndAvailability(bool Accessible = true); +}; + +bool operator<(const CodeCompletionResult &X, const CodeCompletionResult &Y); + +inline bool operator>(const CodeCompletionResult &X, + const CodeCompletionResult &Y) { + return Y < X; +} + +inline bool operator<=(const CodeCompletionResult &X, + const CodeCompletionResult &Y) { + return !(Y < X); +} + +inline bool operator>=(const CodeCompletionResult &X, + const CodeCompletionResult &Y) { + return !(X < Y); +} + + +raw_ostream &operator<<(raw_ostream &OS, + const CodeCompletionString &CCS); + +/// \brief Abstract interface for a consumer of code-completion +/// information. +class CodeCompleteConsumer { +protected: + /// \brief Whether to include macros in the code-completion results. + bool IncludeMacros; + + /// \brief Whether to include code patterns (such as for loops) within + /// the completion results. + bool IncludeCodePatterns; + + /// \brief Whether to include global (top-level) declarations and names in + /// the completion results. + bool IncludeGlobals; + + /// \brief Whether the output format for the code-completion consumer is + /// binary. + bool OutputIsBinary; + +public: + class OverloadCandidate { + public: + /// \brief Describes the type of overload candidate. + enum CandidateKind { + /// \brief The candidate is a function declaration. + CK_Function, + /// \brief The candidate is a function template. + CK_FunctionTemplate, + /// \brief The "candidate" is actually a variable, expression, or block + /// for which we only have a function prototype. + CK_FunctionType + }; + + private: + /// \brief The kind of overload candidate. + CandidateKind Kind; + + union { + /// \brief The function overload candidate, available when + /// Kind == CK_Function. + FunctionDecl *Function; + + /// \brief The function template overload candidate, available when + /// Kind == CK_FunctionTemplate. + FunctionTemplateDecl *FunctionTemplate; + + /// \brief The function type that describes the entity being called, + /// when Kind == CK_FunctionType. + const FunctionType *Type; + }; + + public: + OverloadCandidate(FunctionDecl *Function) + : Kind(CK_Function), Function(Function) { } + + OverloadCandidate(FunctionTemplateDecl *FunctionTemplateDecl) + : Kind(CK_FunctionTemplate), FunctionTemplate(FunctionTemplateDecl) { } + + OverloadCandidate(const FunctionType *Type) + : Kind(CK_FunctionType), Type(Type) { } + + /// \brief Determine the kind of overload candidate. + CandidateKind getKind() const { return Kind; } + + /// \brief Retrieve the function overload candidate or the templated + /// function declaration for a function template. + FunctionDecl *getFunction() const; + + /// \brief Retrieve the function template overload candidate. + FunctionTemplateDecl *getFunctionTemplate() const { + assert(getKind() == CK_FunctionTemplate && "Not a function template"); + return FunctionTemplate; + } + + /// \brief Retrieve the function type of the entity, regardless of how the + /// function is stored. + const FunctionType *getFunctionType() const; + + /// \brief Create a new code-completion string that describes the function + /// signature of this overload candidate. + CodeCompletionString *CreateSignatureString(unsigned CurrentArg, + Sema &S, + CodeCompletionAllocator &Allocator, + CodeCompletionTUInfo &CCTUInfo) const; + }; + + CodeCompleteConsumer() : IncludeMacros(false), IncludeCodePatterns(false), + IncludeGlobals(true), OutputIsBinary(false) { } + + CodeCompleteConsumer(bool IncludeMacros, bool IncludeCodePatterns, + bool IncludeGlobals, bool OutputIsBinary) + : IncludeMacros(IncludeMacros), IncludeCodePatterns(IncludeCodePatterns), + IncludeGlobals(IncludeGlobals), OutputIsBinary(OutputIsBinary) { } + + /// \brief Whether the code-completion consumer wants to see macros. + bool includeMacros() const { return IncludeMacros; } + + /// \brief Whether the code-completion consumer wants to see code patterns. + bool includeCodePatterns() const { return IncludeCodePatterns; } + + /// \brief Whether to include global (top-level) declaration results. + bool includeGlobals() const { return IncludeGlobals; } + + /// \brief Determine whether the output of this consumer is binary. + bool isOutputBinary() const { return OutputIsBinary; } + + /// \brief Deregisters and destroys this code-completion consumer. + virtual ~CodeCompleteConsumer(); + + /// \name Code-completion callbacks + //@{ + /// \brief Process the finalized code-completion results. + virtual void ProcessCodeCompleteResults(Sema &S, + CodeCompletionContext Context, + CodeCompletionResult *Results, + unsigned NumResults) { } + + /// \param S the semantic-analyzer object for which code-completion is being + /// done. + /// + /// \param CurrentArg the index of the current argument. + /// + /// \param Candidates an array of overload candidates. + /// + /// \param NumCandidates the number of overload candidates + virtual void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg, + OverloadCandidate *Candidates, + unsigned NumCandidates) { } + //@} + + /// \brief Retrieve the allocator that will be used to allocate + /// code completion strings. + virtual CodeCompletionAllocator &getAllocator() = 0; + + virtual CodeCompletionTUInfo &getCodeCompletionTUInfo() = 0; +}; + +/// \brief A simple code-completion consumer that prints the results it +/// receives in a simple format. +class PrintingCodeCompleteConsumer : public CodeCompleteConsumer { + /// \brief The raw output stream. + raw_ostream &OS; + + CodeCompletionTUInfo CCTUInfo; + +public: + /// \brief Create a new printing code-completion consumer that prints its + /// results to the given raw output stream. + PrintingCodeCompleteConsumer(bool IncludeMacros, bool IncludeCodePatterns, + bool IncludeGlobals, + raw_ostream &OS) + : CodeCompleteConsumer(IncludeMacros, IncludeCodePatterns, IncludeGlobals, + false), OS(OS), + CCTUInfo(new GlobalCodeCompletionAllocator) {} + + /// \brief Prints the finalized code-completion results. + virtual void ProcessCodeCompleteResults(Sema &S, + CodeCompletionContext Context, + CodeCompletionResult *Results, + unsigned NumResults); + + virtual void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg, + OverloadCandidate *Candidates, + unsigned NumCandidates); + + virtual CodeCompletionAllocator &getAllocator() { + return CCTUInfo.getAllocator(); + } + + virtual CodeCompletionTUInfo &getCodeCompletionTUInfo() { return CCTUInfo; } +}; + +} // end namespace clang + +#endif // LLVM_CLANG_SEMA_CODECOMPLETECONSUMER_H diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h new file mode 100644 index 0000000..67fd393 --- /dev/null +++ b/clang/include/clang/Sema/DeclSpec.h @@ -0,0 +1,1984 @@ +//===--- DeclSpec.h - Parsed declaration specifiers -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the classes used to store parsed information about +// declaration-specifiers and declarators. +// +// static const int volatile x, *y, *(*(*z)[10])(const void *x); +// ------------------------- - -- --------------------------- +// declaration-specifiers \ | / +// declarators +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_DECLSPEC_H +#define LLVM_CLANG_SEMA_DECLSPEC_H + +#include "clang/Sema/AttributeList.h" +#include "clang/Sema/Ownership.h" +#include "clang/AST/NestedNameSpecifier.h" +#include "clang/Lex/Token.h" +#include "clang/Basic/ExceptionSpecificationType.h" +#include "clang/Basic/Lambda.h" +#include "clang/Basic/OperatorKinds.h" +#include "clang/Basic/Specifiers.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/ErrorHandling.h" + +namespace clang { + class ASTContext; + class TypeLoc; + class LangOptions; + class DiagnosticsEngine; + class IdentifierInfo; + class NamespaceAliasDecl; + class NamespaceDecl; + class NestedNameSpecifier; + class NestedNameSpecifierLoc; + class ObjCDeclSpec; + class Preprocessor; + class Sema; + class Declarator; + struct TemplateIdAnnotation; + +/// CXXScopeSpec - Represents a C++ nested-name-specifier or a global scope +/// specifier. These can be in 3 states: +/// 1) Not present, identified by isEmpty() +/// 2) Present, identified by isNotEmpty() +/// 2.a) Valid, idenified by isValid() +/// 2.b) Invalid, identified by isInvalid(). +/// +/// isSet() is deprecated because it mostly corresponded to "valid" but was +/// often used as if it meant "present". +/// +/// The actual scope is described by getScopeRep(). +class CXXScopeSpec { + SourceRange Range; + NestedNameSpecifierLocBuilder Builder; + +public: + const SourceRange &getRange() const { return Range; } + void setRange(const SourceRange &R) { Range = R; } + void setBeginLoc(SourceLocation Loc) { Range.setBegin(Loc); } + void setEndLoc(SourceLocation Loc) { Range.setEnd(Loc); } + SourceLocation getBeginLoc() const { return Range.getBegin(); } + SourceLocation getEndLoc() const { return Range.getEnd(); } + + /// \brief Retrieve the representation of the nested-name-specifier. + NestedNameSpecifier *getScopeRep() const { + return Builder.getRepresentation(); + } + + /// \brief Extend the current nested-name-specifier by another + /// nested-name-specifier component of the form 'type::'. + /// + /// \param Context The AST context in which this nested-name-specifier + /// resides. + /// + /// \param TemplateKWLoc The location of the 'template' keyword, if present. + /// + /// \param TL The TypeLoc that describes the type preceding the '::'. + /// + /// \param ColonColonLoc The location of the trailing '::'. + void Extend(ASTContext &Context, SourceLocation TemplateKWLoc, TypeLoc TL, + SourceLocation ColonColonLoc); + + /// \brief Extend the current nested-name-specifier by another + /// nested-name-specifier component of the form 'identifier::'. + /// + /// \param Context The AST context in which this nested-name-specifier + /// resides. + /// + /// \param Identifier The identifier. + /// + /// \param IdentifierLoc The location of the identifier. + /// + /// \param ColonColonLoc The location of the trailing '::'. + void Extend(ASTContext &Context, IdentifierInfo *Identifier, + SourceLocation IdentifierLoc, SourceLocation ColonColonLoc); + + /// \brief Extend the current nested-name-specifier by another + /// nested-name-specifier component of the form 'namespace::'. + /// + /// \param Context The AST context in which this nested-name-specifier + /// resides. + /// + /// \param Namespace The namespace. + /// + /// \param NamespaceLoc The location of the namespace name. + /// + /// \param ColonColonLoc The location of the trailing '::'. + void Extend(ASTContext &Context, NamespaceDecl *Namespace, + SourceLocation NamespaceLoc, SourceLocation ColonColonLoc); + + /// \brief Extend the current nested-name-specifier by another + /// nested-name-specifier component of the form 'namespace-alias::'. + /// + /// \param Context The AST context in which this nested-name-specifier + /// resides. + /// + /// \param Alias The namespace alias. + /// + /// \param AliasLoc The location of the namespace alias + /// name. + /// + /// \param ColonColonLoc The location of the trailing '::'. + void Extend(ASTContext &Context, NamespaceAliasDecl *Alias, + SourceLocation AliasLoc, SourceLocation ColonColonLoc); + + /// \brief Turn this (empty) nested-name-specifier into the global + /// nested-name-specifier '::'. + void MakeGlobal(ASTContext &Context, SourceLocation ColonColonLoc); + + /// \brief Make a new nested-name-specifier from incomplete source-location + /// information. + /// + /// FIXME: This routine should be used very, very rarely, in cases where we + /// need to synthesize a nested-name-specifier. Most code should instead use + /// \c Adopt() with a proper \c NestedNameSpecifierLoc. + void MakeTrivial(ASTContext &Context, NestedNameSpecifier *Qualifier, + SourceRange R); + + /// \brief Adopt an existing nested-name-specifier (with source-range + /// information). + void Adopt(NestedNameSpecifierLoc Other); + + /// \brief Retrieve a nested-name-specifier with location information, copied + /// into the given AST context. + /// + /// \param Context The context into which this nested-name-specifier will be + /// copied. + NestedNameSpecifierLoc getWithLocInContext(ASTContext &Context) const; + + /// \brief Retrieve the location of the name in the last qualifier + /// in this nested name specifier. For example: + /// ::foo::bar<0>:: + /// ^~~ + SourceLocation getLastQualifierNameLoc() const; + + /// No scope specifier. + bool isEmpty() const { return !Range.isValid(); } + /// A scope specifier is present, but may be valid or invalid. + bool isNotEmpty() const { return !isEmpty(); } + + /// An error occurred during parsing of the scope specifier. + bool isInvalid() const { return isNotEmpty() && getScopeRep() == 0; } + /// A scope specifier is present, and it refers to a real scope. + bool isValid() const { return isNotEmpty() && getScopeRep() != 0; } + + /// \brief Indicate that this nested-name-specifier is invalid. + void SetInvalid(SourceRange R) { + assert(R.isValid() && "Must have a valid source range"); + if (Range.getBegin().isInvalid()) + Range.setBegin(R.getBegin()); + Range.setEnd(R.getEnd()); + Builder.Clear(); + } + + /// Deprecated. Some call sites intend isNotEmpty() while others intend + /// isValid(). + bool isSet() const { return getScopeRep() != 0; } + + void clear() { + Range = SourceRange(); + Builder.Clear(); + } + + /// \brief Retrieve the data associated with the source-location information. + char *location_data() const { return Builder.getBuffer().first; } + + /// \brief Retrieve the size of the data associated with source-location + /// information. + unsigned location_size() const { return Builder.getBuffer().second; } +}; + +/// DeclSpec - This class captures information about "declaration specifiers", +/// which encompasses storage-class-specifiers, type-specifiers, +/// type-qualifiers, and function-specifiers. +class DeclSpec { +public: + // storage-class-specifier + // Note: The order of these enumerators is important for diagnostics. + enum SCS { + SCS_unspecified = 0, + SCS_typedef, + SCS_extern, + SCS_static, + SCS_auto, + SCS_register, + SCS_private_extern, + SCS_mutable + }; + + // Import type specifier width enumeration and constants. + typedef TypeSpecifierWidth TSW; + static const TSW TSW_unspecified = clang::TSW_unspecified; + static const TSW TSW_short = clang::TSW_short; + static const TSW TSW_long = clang::TSW_long; + static const TSW TSW_longlong = clang::TSW_longlong; + + enum TSC { + TSC_unspecified, + TSC_imaginary, + TSC_complex + }; + + // Import type specifier sign enumeration and constants. + typedef TypeSpecifierSign TSS; + static const TSS TSS_unspecified = clang::TSS_unspecified; + static const TSS TSS_signed = clang::TSS_signed; + static const TSS TSS_unsigned = clang::TSS_unsigned; + + // Import type specifier type enumeration and constants. + typedef TypeSpecifierType TST; + static const TST TST_unspecified = clang::TST_unspecified; + static const TST TST_void = clang::TST_void; + static const TST TST_char = clang::TST_char; + static const TST TST_wchar = clang::TST_wchar; + static const TST TST_char16 = clang::TST_char16; + static const TST TST_char32 = clang::TST_char32; + static const TST TST_int = clang::TST_int; + static const TST TST_int128 = clang::TST_int128; + static const TST TST_half = clang::TST_half; + static const TST TST_float = clang::TST_float; + static const TST TST_double = clang::TST_double; + static const TST TST_bool = clang::TST_bool; + static const TST TST_decimal32 = clang::TST_decimal32; + static const TST TST_decimal64 = clang::TST_decimal64; + static const TST TST_decimal128 = clang::TST_decimal128; + static const TST TST_enum = clang::TST_enum; + static const TST TST_union = clang::TST_union; + static const TST TST_struct = clang::TST_struct; + static const TST TST_class = clang::TST_class; + static const TST TST_typename = clang::TST_typename; + static const TST TST_typeofType = clang::TST_typeofType; + static const TST TST_typeofExpr = clang::TST_typeofExpr; + static const TST TST_decltype = clang::TST_decltype; + static const TST TST_underlyingType = clang::TST_underlyingType; + static const TST TST_auto = clang::TST_auto; + static const TST TST_unknown_anytype = clang::TST_unknown_anytype; + static const TST TST_atomic = clang::TST_atomic; + static const TST TST_error = clang::TST_error; + + // type-qualifiers + enum TQ { // NOTE: These flags must be kept in sync with Qualifiers::TQ. + TQ_unspecified = 0, + TQ_const = 1, + TQ_restrict = 2, + TQ_volatile = 4 + }; + + /// ParsedSpecifiers - Flags to query which specifiers were applied. This is + /// returned by getParsedSpecifiers. + enum ParsedSpecifiers { + PQ_None = 0, + PQ_StorageClassSpecifier = 1, + PQ_TypeSpecifier = 2, + PQ_TypeQualifier = 4, + PQ_FunctionSpecifier = 8 + }; + +private: + // storage-class-specifier + /*SCS*/unsigned StorageClassSpec : 3; + unsigned SCS_thread_specified : 1; + unsigned SCS_extern_in_linkage_spec : 1; + + // type-specifier + /*TSW*/unsigned TypeSpecWidth : 2; + /*TSC*/unsigned TypeSpecComplex : 2; + /*TSS*/unsigned TypeSpecSign : 2; + /*TST*/unsigned TypeSpecType : 5; + unsigned TypeAltiVecVector : 1; + unsigned TypeAltiVecPixel : 1; + unsigned TypeAltiVecBool : 1; + unsigned TypeSpecOwned : 1; + + // type-qualifiers + unsigned TypeQualifiers : 3; // Bitwise OR of TQ. + + // function-specifier + unsigned FS_inline_specified : 1; + unsigned FS_virtual_specified : 1; + unsigned FS_explicit_specified : 1; + + // friend-specifier + unsigned Friend_specified : 1; + + // constexpr-specifier + unsigned Constexpr_specified : 1; + + /*SCS*/unsigned StorageClassSpecAsWritten : 3; + + union { + UnionParsedType TypeRep; + Decl *DeclRep; + Expr *ExprRep; + }; + + // attributes. + ParsedAttributes Attrs; + + // Scope specifier for the type spec, if applicable. + CXXScopeSpec TypeScope; + + // List of protocol qualifiers for objective-c classes. Used for + // protocol-qualified interfaces "NString<foo>" and protocol-qualified id + // "id<foo>". + Decl * const *ProtocolQualifiers; + unsigned NumProtocolQualifiers; + SourceLocation ProtocolLAngleLoc; + SourceLocation *ProtocolLocs; + + // SourceLocation info. These are null if the item wasn't specified or if + // the setting was synthesized. + SourceRange Range; + + SourceLocation StorageClassSpecLoc, SCS_threadLoc; + SourceLocation TSWLoc, TSCLoc, TSSLoc, TSTLoc, AltiVecLoc; + /// TSTNameLoc - If TypeSpecType is any of class, enum, struct, union, + /// typename, then this is the location of the named type (if present); + /// otherwise, it is the same as TSTLoc. Hence, the pair TSTLoc and + /// TSTNameLoc provides source range info for tag types. + SourceLocation TSTNameLoc; + SourceRange TypeofParensRange; + SourceLocation TQ_constLoc, TQ_restrictLoc, TQ_volatileLoc; + SourceLocation FS_inlineLoc, FS_virtualLoc, FS_explicitLoc; + SourceLocation FriendLoc, ModulePrivateLoc, ConstexprLoc; + + WrittenBuiltinSpecs writtenBS; + void SaveWrittenBuiltinSpecs(); + void SaveStorageSpecifierAsWritten(); + + ObjCDeclSpec *ObjCQualifiers; + + static bool isTypeRep(TST T) { + return (T == TST_typename || T == TST_typeofType || + T == TST_underlyingType || T == TST_atomic); + } + static bool isExprRep(TST T) { + return (T == TST_typeofExpr || T == TST_decltype); + } + static bool isDeclRep(TST T) { + return (T == TST_enum || T == TST_struct || + T == TST_union || T == TST_class); + } + + DeclSpec(const DeclSpec&); // DO NOT IMPLEMENT + void operator=(const DeclSpec&); // DO NOT IMPLEMENT +public: + + DeclSpec(AttributeFactory &attrFactory) + : StorageClassSpec(SCS_unspecified), + SCS_thread_specified(false), + SCS_extern_in_linkage_spec(false), + TypeSpecWidth(TSW_unspecified), + TypeSpecComplex(TSC_unspecified), + TypeSpecSign(TSS_unspecified), + TypeSpecType(TST_unspecified), + TypeAltiVecVector(false), + TypeAltiVecPixel(false), + TypeAltiVecBool(false), + TypeSpecOwned(false), + TypeQualifiers(TQ_unspecified), + FS_inline_specified(false), + FS_virtual_specified(false), + FS_explicit_specified(false), + Friend_specified(false), + Constexpr_specified(false), + StorageClassSpecAsWritten(SCS_unspecified), + Attrs(attrFactory), + ProtocolQualifiers(0), + NumProtocolQualifiers(0), + ProtocolLocs(0), + writtenBS(), + ObjCQualifiers(0) { + } + ~DeclSpec() { + delete [] ProtocolQualifiers; + delete [] ProtocolLocs; + } + // storage-class-specifier + SCS getStorageClassSpec() const { return (SCS)StorageClassSpec; } + bool isThreadSpecified() const { return SCS_thread_specified; } + bool isExternInLinkageSpec() const { return SCS_extern_in_linkage_spec; } + void setExternInLinkageSpec(bool Value) { + SCS_extern_in_linkage_spec = Value; + } + + SourceLocation getStorageClassSpecLoc() const { return StorageClassSpecLoc; } + SourceLocation getThreadSpecLoc() const { return SCS_threadLoc; } + + void ClearStorageClassSpecs() { + StorageClassSpec = DeclSpec::SCS_unspecified; + SCS_thread_specified = false; + SCS_extern_in_linkage_spec = false; + StorageClassSpecLoc = SourceLocation(); + SCS_threadLoc = SourceLocation(); + } + + // type-specifier + TSW getTypeSpecWidth() const { return (TSW)TypeSpecWidth; } + TSC getTypeSpecComplex() const { return (TSC)TypeSpecComplex; } + TSS getTypeSpecSign() const { return (TSS)TypeSpecSign; } + TST getTypeSpecType() const { return (TST)TypeSpecType; } + bool isTypeAltiVecVector() const { return TypeAltiVecVector; } + bool isTypeAltiVecPixel() const { return TypeAltiVecPixel; } + bool isTypeAltiVecBool() const { return TypeAltiVecBool; } + bool isTypeSpecOwned() const { return TypeSpecOwned; } + ParsedType getRepAsType() const { + assert(isTypeRep((TST) TypeSpecType) && "DeclSpec does not store a type"); + return TypeRep; + } + Decl *getRepAsDecl() const { + assert(isDeclRep((TST) TypeSpecType) && "DeclSpec does not store a decl"); + return DeclRep; + } + Expr *getRepAsExpr() const { + assert(isExprRep((TST) TypeSpecType) && "DeclSpec does not store an expr"); + return ExprRep; + } + CXXScopeSpec &getTypeSpecScope() { return TypeScope; } + const CXXScopeSpec &getTypeSpecScope() const { return TypeScope; } + + const SourceRange &getSourceRange() const LLVM_READONLY { return Range; } + SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); } + SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); } + + SourceLocation getTypeSpecWidthLoc() const { return TSWLoc; } + SourceLocation getTypeSpecComplexLoc() const { return TSCLoc; } + SourceLocation getTypeSpecSignLoc() const { return TSSLoc; } + SourceLocation getTypeSpecTypeLoc() const { return TSTLoc; } + SourceLocation getAltiVecLoc() const { return AltiVecLoc; } + + SourceLocation getTypeSpecTypeNameLoc() const { + assert(isDeclRep((TST) TypeSpecType) || TypeSpecType == TST_typename); + return TSTNameLoc; + } + + SourceRange getTypeofParensRange() const { return TypeofParensRange; } + void setTypeofParensRange(SourceRange range) { TypeofParensRange = range; } + + /// getSpecifierName - Turn a type-specifier-type into a string like "_Bool" + /// or "union". + static const char *getSpecifierName(DeclSpec::TST T); + static const char *getSpecifierName(DeclSpec::TQ Q); + static const char *getSpecifierName(DeclSpec::TSS S); + static const char *getSpecifierName(DeclSpec::TSC C); + static const char *getSpecifierName(DeclSpec::TSW W); + static const char *getSpecifierName(DeclSpec::SCS S); + + // type-qualifiers + + /// getTypeQualifiers - Return a set of TQs. + unsigned getTypeQualifiers() const { return TypeQualifiers; } + SourceLocation getConstSpecLoc() const { return TQ_constLoc; } + SourceLocation getRestrictSpecLoc() const { return TQ_restrictLoc; } + SourceLocation getVolatileSpecLoc() const { return TQ_volatileLoc; } + + /// \brief Clear out all of the type qualifiers. + void ClearTypeQualifiers() { + TypeQualifiers = 0; + TQ_constLoc = SourceLocation(); + TQ_restrictLoc = SourceLocation(); + TQ_volatileLoc = SourceLocation(); + } + + // function-specifier + bool isInlineSpecified() const { return FS_inline_specified; } + SourceLocation getInlineSpecLoc() const { return FS_inlineLoc; } + + bool isVirtualSpecified() const { return FS_virtual_specified; } + SourceLocation getVirtualSpecLoc() const { return FS_virtualLoc; } + + bool isExplicitSpecified() const { return FS_explicit_specified; } + SourceLocation getExplicitSpecLoc() const { return FS_explicitLoc; } + + void ClearFunctionSpecs() { + FS_inline_specified = false; + FS_inlineLoc = SourceLocation(); + FS_virtual_specified = false; + FS_virtualLoc = SourceLocation(); + FS_explicit_specified = false; + FS_explicitLoc = SourceLocation(); + } + + /// hasTypeSpecifier - Return true if any type-specifier has been found. + bool hasTypeSpecifier() const { + return getTypeSpecType() != DeclSpec::TST_unspecified || + getTypeSpecWidth() != DeclSpec::TSW_unspecified || + getTypeSpecComplex() != DeclSpec::TSC_unspecified || + getTypeSpecSign() != DeclSpec::TSS_unspecified; + } + + /// getParsedSpecifiers - Return a bitmask of which flavors of specifiers this + /// DeclSpec includes. + /// + unsigned getParsedSpecifiers() const; + + SCS getStorageClassSpecAsWritten() const { + return (SCS)StorageClassSpecAsWritten; + } + + /// isEmpty - Return true if this declaration specifier is completely empty: + /// no tokens were parsed in the production of it. + bool isEmpty() const { + return getParsedSpecifiers() == DeclSpec::PQ_None; + } + + void SetRangeStart(SourceLocation Loc) { Range.setBegin(Loc); } + void SetRangeEnd(SourceLocation Loc) { Range.setEnd(Loc); } + + /// These methods set the specified attribute of the DeclSpec and + /// return false if there was no error. If an error occurs (for + /// example, if we tried to set "auto" on a spec with "extern" + /// already set), they return true and set PrevSpec and DiagID + /// such that + /// Diag(Loc, DiagID) << PrevSpec; + /// will yield a useful result. + /// + /// TODO: use a more general approach that still allows these + /// diagnostics to be ignored when desired. + bool SetStorageClassSpec(Sema &S, SCS SC, SourceLocation Loc, + const char *&PrevSpec, unsigned &DiagID); + bool SetStorageClassSpecThread(SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID); + bool SetTypeSpecWidth(TSW W, SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID); + bool SetTypeSpecComplex(TSC C, SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID); + bool SetTypeSpecSign(TSS S, SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID); + bool SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID); + bool SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID, ParsedType Rep); + bool SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID, Decl *Rep, bool Owned); + bool SetTypeSpecType(TST T, SourceLocation TagKwLoc, + SourceLocation TagNameLoc, const char *&PrevSpec, + unsigned &DiagID, ParsedType Rep); + bool SetTypeSpecType(TST T, SourceLocation TagKwLoc, + SourceLocation TagNameLoc, const char *&PrevSpec, + unsigned &DiagID, Decl *Rep, bool Owned); + + bool SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID, Expr *Rep); + bool SetTypeAltiVecVector(bool isAltiVecVector, SourceLocation Loc, + const char *&PrevSpec, unsigned &DiagID); + bool SetTypeAltiVecPixel(bool isAltiVecPixel, SourceLocation Loc, + const char *&PrevSpec, unsigned &DiagID); + bool SetTypeSpecError(); + void UpdateDeclRep(Decl *Rep) { + assert(isDeclRep((TST) TypeSpecType)); + DeclRep = Rep; + } + void UpdateTypeRep(ParsedType Rep) { + assert(isTypeRep((TST) TypeSpecType)); + TypeRep = Rep; + } + void UpdateExprRep(Expr *Rep) { + assert(isExprRep((TST) TypeSpecType)); + ExprRep = Rep; + } + + bool SetTypeQual(TQ T, SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID, const LangOptions &Lang); + + bool SetFunctionSpecInline(SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID); + bool SetFunctionSpecVirtual(SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID); + bool SetFunctionSpecExplicit(SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID); + + bool SetFriendSpec(SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID); + bool setModulePrivateSpec(SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID); + bool SetConstexprSpec(SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID); + + bool isFriendSpecified() const { return Friend_specified; } + SourceLocation getFriendSpecLoc() const { return FriendLoc; } + + bool isModulePrivateSpecified() const { return ModulePrivateLoc.isValid(); } + SourceLocation getModulePrivateSpecLoc() const { return ModulePrivateLoc; } + + bool isConstexprSpecified() const { return Constexpr_specified; } + SourceLocation getConstexprSpecLoc() const { return ConstexprLoc; } + + void ClearConstexprSpec() { + Constexpr_specified = false; + ConstexprLoc = SourceLocation(); + } + + AttributePool &getAttributePool() const { + return Attrs.getPool(); + } + + /// AddAttributes - contatenates two attribute lists. + /// The GCC attribute syntax allows for the following: + /// + /// short __attribute__(( unused, deprecated )) + /// int __attribute__(( may_alias, aligned(16) )) var; + /// + /// This declares 4 attributes using 2 lists. The following syntax is + /// also allowed and equivalent to the previous declaration. + /// + /// short __attribute__((unused)) __attribute__((deprecated)) + /// int __attribute__((may_alias)) __attribute__((aligned(16))) var; + /// + void addAttributes(AttributeList *AL) { + Attrs.addAll(AL); + } + void setAttributes(AttributeList *AL) { + Attrs.set(AL); + } + + bool hasAttributes() const { return !Attrs.empty(); } + + ParsedAttributes &getAttributes() { return Attrs; } + const ParsedAttributes &getAttributes() const { return Attrs; } + + /// TakeAttributes - Return the current attribute list and remove them from + /// the DeclSpec so that it doesn't own them. + ParsedAttributes takeAttributes() { + // The non-const "copy" constructor clears the operand automatically. + return Attrs; + } + + void takeAttributesFrom(ParsedAttributes &attrs) { + Attrs.takeAllFrom(attrs); + } + + typedef Decl * const *ProtocolQualifierListTy; + ProtocolQualifierListTy getProtocolQualifiers() const { + return ProtocolQualifiers; + } + SourceLocation *getProtocolLocs() const { return ProtocolLocs; } + unsigned getNumProtocolQualifiers() const { + return NumProtocolQualifiers; + } + SourceLocation getProtocolLAngleLoc() const { return ProtocolLAngleLoc; } + void setProtocolQualifiers(Decl * const *Protos, unsigned NP, + SourceLocation *ProtoLocs, + SourceLocation LAngleLoc); + + /// Finish - This does final analysis of the declspec, issuing diagnostics for + /// things like "_Imaginary" (lacking an FP type). After calling this method, + /// DeclSpec is guaranteed self-consistent, even if an error occurred. + void Finish(DiagnosticsEngine &D, Preprocessor &PP); + + const WrittenBuiltinSpecs& getWrittenBuiltinSpecs() const { + return writtenBS; + } + + ObjCDeclSpec *getObjCQualifiers() const { return ObjCQualifiers; } + void setObjCQualifiers(ObjCDeclSpec *quals) { ObjCQualifiers = quals; } + + /// isMissingDeclaratorOk - This checks if this DeclSpec can stand alone, + /// without a Declarator. Only tag declspecs can stand alone. + bool isMissingDeclaratorOk(); +}; + +/// ObjCDeclSpec - This class captures information about +/// "declaration specifiers" specific to objective-c +class ObjCDeclSpec { +public: + /// ObjCDeclQualifier - Qualifier used on types in method + /// declarations. Not all combinations are sensible. Parameters + /// can be one of { in, out, inout } with one of { bycopy, byref }. + /// Returns can either be { oneway } or not. + /// + /// This should be kept in sync with Decl::ObjCDeclQualifier. + enum ObjCDeclQualifier { + DQ_None = 0x0, + DQ_In = 0x1, + DQ_Inout = 0x2, + DQ_Out = 0x4, + DQ_Bycopy = 0x8, + DQ_Byref = 0x10, + DQ_Oneway = 0x20 + }; + + /// PropertyAttributeKind - list of property attributes. + enum ObjCPropertyAttributeKind { + DQ_PR_noattr = 0x0, + DQ_PR_readonly = 0x01, + DQ_PR_getter = 0x02, + DQ_PR_assign = 0x04, + DQ_PR_readwrite = 0x08, + DQ_PR_retain = 0x10, + DQ_PR_copy = 0x20, + DQ_PR_nonatomic = 0x40, + DQ_PR_setter = 0x80, + DQ_PR_atomic = 0x100, + DQ_PR_weak = 0x200, + DQ_PR_strong = 0x400, + DQ_PR_unsafe_unretained = 0x800 + }; + + + ObjCDeclSpec() + : objcDeclQualifier(DQ_None), PropertyAttributes(DQ_PR_noattr), + GetterName(0), SetterName(0) { } + ObjCDeclQualifier getObjCDeclQualifier() const { return objcDeclQualifier; } + void setObjCDeclQualifier(ObjCDeclQualifier DQVal) { + objcDeclQualifier = (ObjCDeclQualifier) (objcDeclQualifier | DQVal); + } + + ObjCPropertyAttributeKind getPropertyAttributes() const { + return ObjCPropertyAttributeKind(PropertyAttributes); + } + void setPropertyAttributes(ObjCPropertyAttributeKind PRVal) { + PropertyAttributes = + (ObjCPropertyAttributeKind)(PropertyAttributes | PRVal); + } + + const IdentifierInfo *getGetterName() const { return GetterName; } + IdentifierInfo *getGetterName() { return GetterName; } + void setGetterName(IdentifierInfo *name) { GetterName = name; } + + const IdentifierInfo *getSetterName() const { return SetterName; } + IdentifierInfo *getSetterName() { return SetterName; } + void setSetterName(IdentifierInfo *name) { SetterName = name; } + +private: + // FIXME: These two are unrelated and mutially exclusive. So perhaps + // we can put them in a union to reflect their mutual exclusiveness + // (space saving is negligible). + ObjCDeclQualifier objcDeclQualifier : 6; + + // NOTE: VC++ treats enums as signed, avoid using ObjCPropertyAttributeKind + unsigned PropertyAttributes : 12; + IdentifierInfo *GetterName; // getter name of NULL if no getter + IdentifierInfo *SetterName; // setter name of NULL if no setter +}; + +/// \brief Represents a C++ unqualified-id that has been parsed. +class UnqualifiedId { +private: + const UnqualifiedId &operator=(const UnqualifiedId &); // DO NOT IMPLEMENT + +public: + /// \brief Describes the kind of unqualified-id parsed. + enum IdKind { + /// \brief An identifier. + IK_Identifier, + /// \brief An overloaded operator name, e.g., operator+. + IK_OperatorFunctionId, + /// \brief A conversion function name, e.g., operator int. + IK_ConversionFunctionId, + /// \brief A user-defined literal name, e.g., operator "" _i. + IK_LiteralOperatorId, + /// \brief A constructor name. + IK_ConstructorName, + /// \brief A constructor named via a template-id. + IK_ConstructorTemplateId, + /// \brief A destructor name. + IK_DestructorName, + /// \brief A template-id, e.g., f<int>. + IK_TemplateId, + /// \brief An implicit 'self' parameter + IK_ImplicitSelfParam + } Kind; + + /// \brief Anonymous union that holds extra data associated with the + /// parsed unqualified-id. + union { + /// \brief When Kind == IK_Identifier, the parsed identifier, or when Kind + /// == IK_UserLiteralId, the identifier suffix. + IdentifierInfo *Identifier; + + /// \brief When Kind == IK_OperatorFunctionId, the overloaded operator + /// that we parsed. + struct { + /// \brief The kind of overloaded operator. + OverloadedOperatorKind Operator; + + /// \brief The source locations of the individual tokens that name + /// the operator, e.g., the "new", "[", and "]" tokens in + /// operator new []. + /// + /// Different operators have different numbers of tokens in their name, + /// up to three. Any remaining source locations in this array will be + /// set to an invalid value for operators with fewer than three tokens. + unsigned SymbolLocations[3]; + } OperatorFunctionId; + + /// \brief When Kind == IK_ConversionFunctionId, the type that the + /// conversion function names. + UnionParsedType ConversionFunctionId; + + /// \brief When Kind == IK_ConstructorName, the class-name of the type + /// whose constructor is being referenced. + UnionParsedType ConstructorName; + + /// \brief When Kind == IK_DestructorName, the type referred to by the + /// class-name. + UnionParsedType DestructorName; + + /// \brief When Kind == IK_TemplateId or IK_ConstructorTemplateId, + /// the template-id annotation that contains the template name and + /// template arguments. + TemplateIdAnnotation *TemplateId; + }; + + /// \brief The location of the first token that describes this unqualified-id, + /// which will be the location of the identifier, "operator" keyword, + /// tilde (for a destructor), or the template name of a template-id. + SourceLocation StartLocation; + + /// \brief The location of the last token that describes this unqualified-id. + SourceLocation EndLocation; + + UnqualifiedId() : Kind(IK_Identifier), Identifier(0) { } + + /// \brief Do not use this copy constructor. It is temporary, and only + /// exists because we are holding FieldDeclarators in a SmallVector when we + /// don't actually need them. + /// + /// FIXME: Kill this copy constructor. + UnqualifiedId(const UnqualifiedId &Other) + : Kind(IK_Identifier), Identifier(Other.Identifier), + StartLocation(Other.StartLocation), EndLocation(Other.EndLocation) { + assert(Other.Kind == IK_Identifier && "Cannot copy non-identifiers"); + } + + /// \brief Destroy this unqualified-id. + ~UnqualifiedId() { clear(); } + + /// \brief Clear out this unqualified-id, setting it to default (invalid) + /// state. + void clear(); + + /// \brief Determine whether this unqualified-id refers to a valid name. + bool isValid() const { return StartLocation.isValid(); } + + /// \brief Determine whether this unqualified-id refers to an invalid name. + bool isInvalid() const { return !isValid(); } + + /// \brief Determine what kind of name we have. + IdKind getKind() const { return Kind; } + void setKind(IdKind kind) { Kind = kind; } + + /// \brief Specify that this unqualified-id was parsed as an identifier. + /// + /// \param Id the parsed identifier. + /// \param IdLoc the location of the parsed identifier. + void setIdentifier(const IdentifierInfo *Id, SourceLocation IdLoc) { + Kind = IK_Identifier; + Identifier = const_cast<IdentifierInfo *>(Id); + StartLocation = EndLocation = IdLoc; + } + + /// \brief Specify that this unqualified-id was parsed as an + /// operator-function-id. + /// + /// \param OperatorLoc the location of the 'operator' keyword. + /// + /// \param Op the overloaded operator. + /// + /// \param SymbolLocations the locations of the individual operator symbols + /// in the operator. + void setOperatorFunctionId(SourceLocation OperatorLoc, + OverloadedOperatorKind Op, + SourceLocation SymbolLocations[3]); + + /// \brief Specify that this unqualified-id was parsed as a + /// conversion-function-id. + /// + /// \param OperatorLoc the location of the 'operator' keyword. + /// + /// \param Ty the type to which this conversion function is converting. + /// + /// \param EndLoc the location of the last token that makes up the type name. + void setConversionFunctionId(SourceLocation OperatorLoc, + ParsedType Ty, + SourceLocation EndLoc) { + Kind = IK_ConversionFunctionId; + StartLocation = OperatorLoc; + EndLocation = EndLoc; + ConversionFunctionId = Ty; + } + + /// \brief Specific that this unqualified-id was parsed as a + /// literal-operator-id. + /// + /// \param Id the parsed identifier. + /// + /// \param OpLoc the location of the 'operator' keyword. + /// + /// \param IdLoc the location of the identifier. + void setLiteralOperatorId(const IdentifierInfo *Id, SourceLocation OpLoc, + SourceLocation IdLoc) { + Kind = IK_LiteralOperatorId; + Identifier = const_cast<IdentifierInfo *>(Id); + StartLocation = OpLoc; + EndLocation = IdLoc; + } + + /// \brief Specify that this unqualified-id was parsed as a constructor name. + /// + /// \param ClassType the class type referred to by the constructor name. + /// + /// \param ClassNameLoc the location of the class name. + /// + /// \param EndLoc the location of the last token that makes up the type name. + void setConstructorName(ParsedType ClassType, + SourceLocation ClassNameLoc, + SourceLocation EndLoc) { + Kind = IK_ConstructorName; + StartLocation = ClassNameLoc; + EndLocation = EndLoc; + ConstructorName = ClassType; + } + + /// \brief Specify that this unqualified-id was parsed as a + /// template-id that names a constructor. + /// + /// \param TemplateId the template-id annotation that describes the parsed + /// template-id. This UnqualifiedId instance will take ownership of the + /// \p TemplateId and will free it on destruction. + void setConstructorTemplateId(TemplateIdAnnotation *TemplateId); + + /// \brief Specify that this unqualified-id was parsed as a destructor name. + /// + /// \param TildeLoc the location of the '~' that introduces the destructor + /// name. + /// + /// \param ClassType the name of the class referred to by the destructor name. + void setDestructorName(SourceLocation TildeLoc, + ParsedType ClassType, + SourceLocation EndLoc) { + Kind = IK_DestructorName; + StartLocation = TildeLoc; + EndLocation = EndLoc; + DestructorName = ClassType; + } + + /// \brief Specify that this unqualified-id was parsed as a template-id. + /// + /// \param TemplateId the template-id annotation that describes the parsed + /// template-id. This UnqualifiedId instance will take ownership of the + /// \p TemplateId and will free it on destruction. + void setTemplateId(TemplateIdAnnotation *TemplateId); + + /// \brief Return the source range that covers this unqualified-id. + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(StartLocation, EndLocation); + } + SourceLocation getLocStart() const LLVM_READONLY { return StartLocation; } + SourceLocation getLocEnd() const LLVM_READONLY { return EndLocation; } +}; + +/// CachedTokens - A set of tokens that has been cached for later +/// parsing. +typedef SmallVector<Token, 4> CachedTokens; + +/// DeclaratorChunk - One instance of this struct is used for each type in a +/// declarator that is parsed. +/// +/// This is intended to be a small value object. +struct DeclaratorChunk { + enum { + Pointer, Reference, Array, Function, BlockPointer, MemberPointer, Paren + } Kind; + + /// Loc - The place where this type was defined. + SourceLocation Loc; + /// EndLoc - If valid, the place where this chunck ends. + SourceLocation EndLoc; + + struct TypeInfoCommon { + AttributeList *AttrList; + }; + + struct PointerTypeInfo : TypeInfoCommon { + /// The type qualifiers: const/volatile/restrict. + unsigned TypeQuals : 3; + + /// The location of the const-qualifier, if any. + unsigned ConstQualLoc; + + /// The location of the volatile-qualifier, if any. + unsigned VolatileQualLoc; + + /// The location of the restrict-qualifier, if any. + unsigned RestrictQualLoc; + + void destroy() { + } + }; + + struct ReferenceTypeInfo : TypeInfoCommon { + /// The type qualifier: restrict. [GNU] C++ extension + bool HasRestrict : 1; + /// True if this is an lvalue reference, false if it's an rvalue reference. + bool LValueRef : 1; + void destroy() { + } + }; + + struct ArrayTypeInfo : TypeInfoCommon { + /// The type qualifiers for the array: const/volatile/restrict. + unsigned TypeQuals : 3; + + /// True if this dimension included the 'static' keyword. + bool hasStatic : 1; + + /// True if this dimension was [*]. In this case, NumElts is null. + bool isStar : 1; + + /// This is the size of the array, or null if [] or [*] was specified. + /// Since the parser is multi-purpose, and we don't want to impose a root + /// expression class on all clients, NumElts is untyped. + Expr *NumElts; + + void destroy() {} + }; + + /// ParamInfo - An array of paraminfo objects is allocated whenever a function + /// declarator is parsed. There are two interesting styles of arguments here: + /// K&R-style identifier lists and parameter type lists. K&R-style identifier + /// lists will have information about the identifier, but no type information. + /// Parameter type lists will have type info (if the actions module provides + /// it), but may have null identifier info: e.g. for 'void foo(int X, int)'. + struct ParamInfo { + IdentifierInfo *Ident; + SourceLocation IdentLoc; + Decl *Param; + + /// DefaultArgTokens - When the parameter's default argument + /// cannot be parsed immediately (because it occurs within the + /// declaration of a member function), it will be stored here as a + /// sequence of tokens to be parsed once the class definition is + /// complete. Non-NULL indicates that there is a default argument. + CachedTokens *DefaultArgTokens; + + ParamInfo() {} + ParamInfo(IdentifierInfo *ident, SourceLocation iloc, + Decl *param, + CachedTokens *DefArgTokens = 0) + : Ident(ident), IdentLoc(iloc), Param(param), + DefaultArgTokens(DefArgTokens) {} + }; + + struct TypeAndRange { + ParsedType Ty; + SourceRange Range; + }; + + struct FunctionTypeInfo : TypeInfoCommon { + /// hasPrototype - This is true if the function had at least one typed + /// argument. If the function is () or (a,b,c), then it has no prototype, + /// and is treated as a K&R-style function. + unsigned hasPrototype : 1; + + /// isVariadic - If this function has a prototype, and if that + /// proto ends with ',...)', this is true. When true, EllipsisLoc + /// contains the location of the ellipsis. + unsigned isVariadic : 1; + + /// \brief Whether the ref-qualifier (if any) is an lvalue reference. + /// Otherwise, it's an rvalue reference. + unsigned RefQualifierIsLValueRef : 1; + + /// The type qualifiers: const/volatile/restrict. + /// The qualifier bitmask values are the same as in QualType. + unsigned TypeQuals : 3; + + /// ExceptionSpecType - An ExceptionSpecificationType value. + unsigned ExceptionSpecType : 3; + + /// DeleteArgInfo - If this is true, we need to delete[] ArgInfo. + unsigned DeleteArgInfo : 1; + + /// When isVariadic is true, the location of the ellipsis in the source. + unsigned EllipsisLoc; + + /// NumArgs - This is the number of formal arguments provided for the + /// declarator. + unsigned NumArgs; + + /// NumExceptions - This is the number of types in the dynamic-exception- + /// decl, if the function has one. + unsigned NumExceptions; + + /// \brief The location of the ref-qualifier, if any. + /// + /// If this is an invalid location, there is no ref-qualifier. + unsigned RefQualifierLoc; + + /// \brief The location of the const-qualifier, if any. + /// + /// If this is an invalid location, there is no const-qualifier. + unsigned ConstQualifierLoc; + + /// \brief The location of the volatile-qualifier, if any. + /// + /// If this is an invalid location, there is no volatile-qualifier. + unsigned VolatileQualifierLoc; + + /// \brief The location of the 'mutable' qualifer in a lambda-declarator, if + /// any. + unsigned MutableLoc; + + /// \brief When ExceptionSpecType isn't EST_None or EST_Delayed, the + /// location of the keyword introducing the spec. + unsigned ExceptionSpecLoc; + + /// ArgInfo - This is a pointer to a new[]'d array of ParamInfo objects that + /// describe the arguments for this function declarator. This is null if + /// there are no arguments specified. + ParamInfo *ArgInfo; + + union { + /// \brief Pointer to a new[]'d array of TypeAndRange objects that + /// contain the types in the function's dynamic exception specification + /// and their locations, if there is one. + TypeAndRange *Exceptions; + + /// \brief Pointer to the expression in the noexcept-specifier of this + /// function, if it has one. + Expr *NoexceptExpr; + }; + + /// TrailingReturnType - If this isn't null, it's the trailing return type + /// specified. This is actually a ParsedType, but stored as void* to + /// allow union storage. + void *TrailingReturnType; + + /// freeArgs - reset the argument list to having zero arguments. This is + /// used in various places for error recovery. + void freeArgs() { + if (DeleteArgInfo) { + delete[] ArgInfo; + DeleteArgInfo = false; + } + NumArgs = 0; + } + + void destroy() { + if (DeleteArgInfo) + delete[] ArgInfo; + if (getExceptionSpecType() == EST_Dynamic) + delete[] Exceptions; + } + + /// isKNRPrototype - Return true if this is a K&R style identifier list, + /// like "void foo(a,b,c)". In a function definition, this will be followed + /// by the argument type definitions. + bool isKNRPrototype() const { + return !hasPrototype && NumArgs != 0; + } + + SourceLocation getEllipsisLoc() const { + return SourceLocation::getFromRawEncoding(EllipsisLoc); + } + SourceLocation getExceptionSpecLoc() const { + return SourceLocation::getFromRawEncoding(ExceptionSpecLoc); + } + + /// \brief Retrieve the location of the ref-qualifier, if any. + SourceLocation getRefQualifierLoc() const { + return SourceLocation::getFromRawEncoding(RefQualifierLoc); + } + + /// \brief Retrieve the location of the ref-qualifier, if any. + SourceLocation getConstQualifierLoc() const { + return SourceLocation::getFromRawEncoding(ConstQualifierLoc); + } + + /// \brief Retrieve the location of the ref-qualifier, if any. + SourceLocation getVolatileQualifierLoc() const { + return SourceLocation::getFromRawEncoding(VolatileQualifierLoc); + } + + /// \brief Retrieve the location of the 'mutable' qualifier, if any. + SourceLocation getMutableLoc() const { + return SourceLocation::getFromRawEncoding(MutableLoc); + } + + /// \brief Determine whether this function declaration contains a + /// ref-qualifier. + bool hasRefQualifier() const { return getRefQualifierLoc().isValid(); } + + /// \brief Determine whether this lambda-declarator contains a 'mutable' + /// qualifier. + bool hasMutableQualifier() const { return getMutableLoc().isValid(); } + + /// \brief Get the type of exception specification this function has. + ExceptionSpecificationType getExceptionSpecType() const { + return static_cast<ExceptionSpecificationType>(ExceptionSpecType); + } + }; + + struct BlockPointerTypeInfo : TypeInfoCommon { + /// For now, sema will catch these as invalid. + /// The type qualifiers: const/volatile/restrict. + unsigned TypeQuals : 3; + + void destroy() { + } + }; + + struct MemberPointerTypeInfo : TypeInfoCommon { + /// The type qualifiers: const/volatile/restrict. + unsigned TypeQuals : 3; + // CXXScopeSpec has a constructor, so it can't be a direct member. + // So we need some pointer-aligned storage and a bit of trickery. + union { + void *Aligner; + char Mem[sizeof(CXXScopeSpec)]; + } ScopeMem; + CXXScopeSpec &Scope() { + return *reinterpret_cast<CXXScopeSpec*>(ScopeMem.Mem); + } + const CXXScopeSpec &Scope() const { + return *reinterpret_cast<const CXXScopeSpec*>(ScopeMem.Mem); + } + void destroy() { + Scope().~CXXScopeSpec(); + } + }; + + union { + TypeInfoCommon Common; + PointerTypeInfo Ptr; + ReferenceTypeInfo Ref; + ArrayTypeInfo Arr; + FunctionTypeInfo Fun; + BlockPointerTypeInfo Cls; + MemberPointerTypeInfo Mem; + }; + + void destroy() { + switch (Kind) { + case DeclaratorChunk::Function: return Fun.destroy(); + case DeclaratorChunk::Pointer: return Ptr.destroy(); + case DeclaratorChunk::BlockPointer: return Cls.destroy(); + case DeclaratorChunk::Reference: return Ref.destroy(); + case DeclaratorChunk::Array: return Arr.destroy(); + case DeclaratorChunk::MemberPointer: return Mem.destroy(); + case DeclaratorChunk::Paren: return; + } + } + + /// getAttrs - If there are attributes applied to this declaratorchunk, return + /// them. + const AttributeList *getAttrs() const { + return Common.AttrList; + } + + AttributeList *&getAttrListRef() { + return Common.AttrList; + } + + /// getPointer - Return a DeclaratorChunk for a pointer. + /// + static DeclaratorChunk getPointer(unsigned TypeQuals, SourceLocation Loc, + SourceLocation ConstQualLoc, + SourceLocation VolatileQualLoc, + SourceLocation RestrictQualLoc) { + DeclaratorChunk I; + I.Kind = Pointer; + I.Loc = Loc; + I.Ptr.TypeQuals = TypeQuals; + I.Ptr.ConstQualLoc = ConstQualLoc.getRawEncoding(); + I.Ptr.VolatileQualLoc = VolatileQualLoc.getRawEncoding(); + I.Ptr.RestrictQualLoc = RestrictQualLoc.getRawEncoding(); + I.Ptr.AttrList = 0; + return I; + } + + /// getReference - Return a DeclaratorChunk for a reference. + /// + static DeclaratorChunk getReference(unsigned TypeQuals, SourceLocation Loc, + bool lvalue) { + DeclaratorChunk I; + I.Kind = Reference; + I.Loc = Loc; + I.Ref.HasRestrict = (TypeQuals & DeclSpec::TQ_restrict) != 0; + I.Ref.LValueRef = lvalue; + I.Ref.AttrList = 0; + return I; + } + + /// getArray - Return a DeclaratorChunk for an array. + /// + static DeclaratorChunk getArray(unsigned TypeQuals, + bool isStatic, bool isStar, Expr *NumElts, + SourceLocation LBLoc, SourceLocation RBLoc) { + DeclaratorChunk I; + I.Kind = Array; + I.Loc = LBLoc; + I.EndLoc = RBLoc; + I.Arr.AttrList = 0; + I.Arr.TypeQuals = TypeQuals; + I.Arr.hasStatic = isStatic; + I.Arr.isStar = isStar; + I.Arr.NumElts = NumElts; + return I; + } + + /// DeclaratorChunk::getFunction - Return a DeclaratorChunk for a function. + /// "TheDeclarator" is the declarator that this will be added to. + static DeclaratorChunk getFunction(bool hasProto, bool isVariadic, + SourceLocation EllipsisLoc, + ParamInfo *ArgInfo, unsigned NumArgs, + unsigned TypeQuals, + bool RefQualifierIsLvalueRef, + SourceLocation RefQualifierLoc, + SourceLocation ConstQualifierLoc, + SourceLocation VolatileQualifierLoc, + SourceLocation MutableLoc, + ExceptionSpecificationType ESpecType, + SourceLocation ESpecLoc, + ParsedType *Exceptions, + SourceRange *ExceptionRanges, + unsigned NumExceptions, + Expr *NoexceptExpr, + SourceLocation LocalRangeBegin, + SourceLocation LocalRangeEnd, + Declarator &TheDeclarator, + ParsedType TrailingReturnType = + ParsedType()); + + /// getBlockPointer - Return a DeclaratorChunk for a block. + /// + static DeclaratorChunk getBlockPointer(unsigned TypeQuals, + SourceLocation Loc) { + DeclaratorChunk I; + I.Kind = BlockPointer; + I.Loc = Loc; + I.Cls.TypeQuals = TypeQuals; + I.Cls.AttrList = 0; + return I; + } + + static DeclaratorChunk getMemberPointer(const CXXScopeSpec &SS, + unsigned TypeQuals, + SourceLocation Loc) { + DeclaratorChunk I; + I.Kind = MemberPointer; + I.Loc = Loc; + I.Mem.TypeQuals = TypeQuals; + I.Mem.AttrList = 0; + new (I.Mem.ScopeMem.Mem) CXXScopeSpec(SS); + return I; + } + + /// getParen - Return a DeclaratorChunk for a paren. + /// + static DeclaratorChunk getParen(SourceLocation LParenLoc, + SourceLocation RParenLoc) { + DeclaratorChunk I; + I.Kind = Paren; + I.Loc = LParenLoc; + I.EndLoc = RParenLoc; + I.Common.AttrList = 0; + return I; + } + +}; + +/// \brief Described the kind of function definition (if any) provided for +/// a function. +enum FunctionDefinitionKind { + FDK_Declaration, + FDK_Definition, + FDK_Defaulted, + FDK_Deleted +}; + +/// Declarator - Information about one declarator, including the parsed type +/// information and the identifier. When the declarator is fully formed, this +/// is turned into the appropriate Decl object. +/// +/// Declarators come in two types: normal declarators and abstract declarators. +/// Abstract declarators are used when parsing types, and don't have an +/// identifier. Normal declarators do have ID's. +/// +/// Instances of this class should be a transient object that lives on the +/// stack, not objects that are allocated in large quantities on the heap. +class Declarator { +public: + enum TheContext { + FileContext, // File scope declaration. + PrototypeContext, // Within a function prototype. + ObjCResultContext, // An ObjC method result type. + ObjCParameterContext,// An ObjC method parameter type. + KNRTypeListContext, // K&R type definition list for formals. + TypeNameContext, // Abstract declarator for types. + MemberContext, // Struct/Union field. + BlockContext, // Declaration within a block in a function. + ForContext, // Declaration within first part of a for loop. + ConditionContext, // Condition declaration in a C++ if/switch/while/for. + TemplateParamContext,// Within a template parameter list. + CXXNewContext, // C++ new-expression. + CXXCatchContext, // C++ catch exception-declaration + ObjCCatchContext, // Objective-C catch exception-declaration + BlockLiteralContext, // Block literal declarator. + LambdaExprContext, // Lambda-expression declarator. + TrailingReturnContext, // C++11 trailing-type-specifier. + TemplateTypeArgContext, // Template type argument. + AliasDeclContext, // C++11 alias-declaration. + AliasTemplateContext // C++11 alias-declaration template. + }; + +private: + const DeclSpec &DS; + CXXScopeSpec SS; + UnqualifiedId Name; + SourceRange Range; + + /// Context - Where we are parsing this declarator. + /// + TheContext Context; + + /// DeclTypeInfo - This holds each type that the declarator includes as it is + /// parsed. This is pushed from the identifier out, which means that element + /// #0 will be the most closely bound to the identifier, and + /// DeclTypeInfo.back() will be the least closely bound. + SmallVector<DeclaratorChunk, 8> DeclTypeInfo; + + /// InvalidType - Set by Sema::GetTypeForDeclarator(). + bool InvalidType : 1; + + /// GroupingParens - Set by Parser::ParseParenDeclarator(). + bool GroupingParens : 1; + + /// FunctionDefinition - Is this Declarator for a function or member + /// definition and, if so, what kind? + /// + /// Actually a FunctionDefinitionKind. + unsigned FunctionDefinition : 2; + + // Redeclaration - Is this Declarator is a redeclaration. + bool Redeclaration : 1; + + /// Attrs - Attributes. + ParsedAttributes Attrs; + + /// AsmLabel - The asm label, if specified. + Expr *AsmLabel; + + /// InlineParams - This is a local array used for the first function decl + /// chunk to avoid going to the heap for the common case when we have one + /// function chunk in the declarator. + DeclaratorChunk::ParamInfo InlineParams[16]; + bool InlineParamsUsed; + + /// Extension - true if the declaration is preceded by __extension__. + bool Extension : 1; + + /// \brief If this is the second or subsequent declarator in this declaration, + /// the location of the comma before this declarator. + SourceLocation CommaLoc; + + /// \brief If provided, the source location of the ellipsis used to describe + /// this declarator as a parameter pack. + SourceLocation EllipsisLoc; + + friend struct DeclaratorChunk; + +public: + Declarator(const DeclSpec &ds, TheContext C) + : DS(ds), Range(ds.getSourceRange()), Context(C), + InvalidType(DS.getTypeSpecType() == DeclSpec::TST_error), + GroupingParens(false), FunctionDefinition(FDK_Declaration), + Redeclaration(false), + Attrs(ds.getAttributePool().getFactory()), AsmLabel(0), + InlineParamsUsed(false), Extension(false) { + } + + ~Declarator() { + clear(); + } + + /// getDeclSpec - Return the declaration-specifier that this declarator was + /// declared with. + const DeclSpec &getDeclSpec() const { return DS; } + + /// getMutableDeclSpec - Return a non-const version of the DeclSpec. This + /// should be used with extreme care: declspecs can often be shared between + /// multiple declarators, so mutating the DeclSpec affects all of the + /// Declarators. This should only be done when the declspec is known to not + /// be shared or when in error recovery etc. + DeclSpec &getMutableDeclSpec() { return const_cast<DeclSpec &>(DS); } + + AttributePool &getAttributePool() const { + return Attrs.getPool(); + } + + /// getCXXScopeSpec - Return the C++ scope specifier (global scope or + /// nested-name-specifier) that is part of the declarator-id. + const CXXScopeSpec &getCXXScopeSpec() const { return SS; } + CXXScopeSpec &getCXXScopeSpec() { return SS; } + + /// \brief Retrieve the name specified by this declarator. + UnqualifiedId &getName() { return Name; } + + TheContext getContext() const { return Context; } + + bool isPrototypeContext() const { + return (Context == PrototypeContext || + Context == ObjCParameterContext || + Context == ObjCResultContext); + } + + /// getSourceRange - Get the source range that spans this declarator. + const SourceRange &getSourceRange() const LLVM_READONLY { return Range; } + SourceLocation getLocStart() const LLVM_READONLY { return Range.getBegin(); } + SourceLocation getLocEnd() const LLVM_READONLY { return Range.getEnd(); } + + void SetSourceRange(SourceRange R) { Range = R; } + /// SetRangeBegin - Set the start of the source range to Loc, unless it's + /// invalid. + void SetRangeBegin(SourceLocation Loc) { + if (!Loc.isInvalid()) + Range.setBegin(Loc); + } + /// SetRangeEnd - Set the end of the source range to Loc, unless it's invalid. + void SetRangeEnd(SourceLocation Loc) { + if (!Loc.isInvalid()) + Range.setEnd(Loc); + } + /// ExtendWithDeclSpec - Extend the declarator source range to include the + /// given declspec, unless its location is invalid. Adopts the range start if + /// the current range start is invalid. + void ExtendWithDeclSpec(const DeclSpec &DS) { + const SourceRange &SR = DS.getSourceRange(); + if (Range.getBegin().isInvalid()) + Range.setBegin(SR.getBegin()); + if (!SR.getEnd().isInvalid()) + Range.setEnd(SR.getEnd()); + } + + /// clear - Reset the contents of this Declarator. + void clear() { + SS.clear(); + Name.clear(); + Range = DS.getSourceRange(); + + for (unsigned i = 0, e = DeclTypeInfo.size(); i != e; ++i) + DeclTypeInfo[i].destroy(); + DeclTypeInfo.clear(); + Attrs.clear(); + AsmLabel = 0; + InlineParamsUsed = false; + CommaLoc = SourceLocation(); + EllipsisLoc = SourceLocation(); + } + + /// mayOmitIdentifier - Return true if the identifier is either optional or + /// not allowed. This is true for typenames, prototypes, and template + /// parameter lists. + bool mayOmitIdentifier() const { + switch (Context) { + case FileContext: + case KNRTypeListContext: + case MemberContext: + case BlockContext: + case ForContext: + case ConditionContext: + return false; + + case TypeNameContext: + case AliasDeclContext: + case AliasTemplateContext: + case PrototypeContext: + case ObjCParameterContext: + case ObjCResultContext: + case TemplateParamContext: + case CXXNewContext: + case CXXCatchContext: + case ObjCCatchContext: + case BlockLiteralContext: + case LambdaExprContext: + case TemplateTypeArgContext: + case TrailingReturnContext: + return true; + } + llvm_unreachable("unknown context kind!"); + } + + /// mayHaveIdentifier - Return true if the identifier is either optional or + /// required. This is true for normal declarators and prototypes, but not + /// typenames. + bool mayHaveIdentifier() const { + switch (Context) { + case FileContext: + case KNRTypeListContext: + case MemberContext: + case BlockContext: + case ForContext: + case ConditionContext: + case PrototypeContext: + case TemplateParamContext: + case CXXCatchContext: + case ObjCCatchContext: + return true; + + case TypeNameContext: + case CXXNewContext: + case AliasDeclContext: + case AliasTemplateContext: + case ObjCParameterContext: + case ObjCResultContext: + case BlockLiteralContext: + case LambdaExprContext: + case TemplateTypeArgContext: + case TrailingReturnContext: + return false; + } + llvm_unreachable("unknown context kind!"); + } + + /// mayBeFollowedByCXXDirectInit - Return true if the declarator can be + /// followed by a C++ direct initializer, e.g. "int x(1);". + bool mayBeFollowedByCXXDirectInit() const { + if (hasGroupingParens()) return false; + + if (getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) + return false; + + if (getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_extern && + Context != FileContext) + return false; + + // Special names can't have direct initializers. + if (Name.getKind() != UnqualifiedId::IK_Identifier) + return false; + + switch (Context) { + case FileContext: + case BlockContext: + case ForContext: + return true; + + case ConditionContext: + // This may not be followed by a direct initializer, but it can't be a + // function declaration either, and we'd prefer to perform a tentative + // parse in order to produce the right diagnostic. + return true; + + case KNRTypeListContext: + case MemberContext: + case PrototypeContext: + case ObjCParameterContext: + case ObjCResultContext: + case TemplateParamContext: + case CXXCatchContext: + case ObjCCatchContext: + case TypeNameContext: + case CXXNewContext: + case AliasDeclContext: + case AliasTemplateContext: + case BlockLiteralContext: + case LambdaExprContext: + case TemplateTypeArgContext: + case TrailingReturnContext: + return false; + } + llvm_unreachable("unknown context kind!"); + } + + /// isPastIdentifier - Return true if we have parsed beyond the point where + /// the + bool isPastIdentifier() const { return Name.isValid(); } + + /// hasName - Whether this declarator has a name, which might be an + /// identifier (accessible via getIdentifier()) or some kind of + /// special C++ name (constructor, destructor, etc.). + bool hasName() const { + return Name.getKind() != UnqualifiedId::IK_Identifier || Name.Identifier; + } + + IdentifierInfo *getIdentifier() const { + if (Name.getKind() == UnqualifiedId::IK_Identifier) + return Name.Identifier; + + return 0; + } + SourceLocation getIdentifierLoc() const { return Name.StartLocation; } + + /// \brief Set the name of this declarator to be the given identifier. + void SetIdentifier(IdentifierInfo *Id, SourceLocation IdLoc) { + Name.setIdentifier(Id, IdLoc); + } + + /// AddTypeInfo - Add a chunk to this declarator. Also extend the range to + /// EndLoc, which should be the last token of the chunk. + void AddTypeInfo(const DeclaratorChunk &TI, + ParsedAttributes &attrs, + SourceLocation EndLoc) { + DeclTypeInfo.push_back(TI); + DeclTypeInfo.back().getAttrListRef() = attrs.getList(); + getAttributePool().takeAllFrom(attrs.getPool()); + + if (!EndLoc.isInvalid()) + SetRangeEnd(EndLoc); + } + + /// AddInnermostTypeInfo - Add a new innermost chunk to this declarator. + void AddInnermostTypeInfo(const DeclaratorChunk &TI) { + DeclTypeInfo.insert(DeclTypeInfo.begin(), TI); + } + + /// getNumTypeObjects() - Return the number of types applied to this + /// declarator. + unsigned getNumTypeObjects() const { return DeclTypeInfo.size(); } + + /// Return the specified TypeInfo from this declarator. TypeInfo #0 is + /// closest to the identifier. + const DeclaratorChunk &getTypeObject(unsigned i) const { + assert(i < DeclTypeInfo.size() && "Invalid type chunk"); + return DeclTypeInfo[i]; + } + DeclaratorChunk &getTypeObject(unsigned i) { + assert(i < DeclTypeInfo.size() && "Invalid type chunk"); + return DeclTypeInfo[i]; + } + + void DropFirstTypeObject() + { + assert(!DeclTypeInfo.empty() && "No type chunks to drop."); + DeclTypeInfo.front().destroy(); + DeclTypeInfo.erase(DeclTypeInfo.begin()); + } + + /// isArrayOfUnknownBound - This method returns true if the declarator + /// is a declarator for an array of unknown bound (looking through + /// parentheses). + bool isArrayOfUnknownBound() const { + for (unsigned i = 0, i_end = DeclTypeInfo.size(); i < i_end; ++i) { + switch (DeclTypeInfo[i].Kind) { + case DeclaratorChunk::Paren: + continue; + case DeclaratorChunk::Function: + case DeclaratorChunk::Pointer: + case DeclaratorChunk::Reference: + case DeclaratorChunk::BlockPointer: + case DeclaratorChunk::MemberPointer: + return false; + case DeclaratorChunk::Array: + return !DeclTypeInfo[i].Arr.NumElts; + } + llvm_unreachable("Invalid type chunk"); + } + return false; + } + + /// isFunctionDeclarator - This method returns true if the declarator + /// is a function declarator (looking through parentheses). + /// If true is returned, then the reference type parameter idx is + /// assigned with the index of the declaration chunk. + bool isFunctionDeclarator(unsigned& idx) const { + for (unsigned i = 0, i_end = DeclTypeInfo.size(); i < i_end; ++i) { + switch (DeclTypeInfo[i].Kind) { + case DeclaratorChunk::Function: + idx = i; + return true; + case DeclaratorChunk::Paren: + continue; + case DeclaratorChunk::Pointer: + case DeclaratorChunk::Reference: + case DeclaratorChunk::Array: + case DeclaratorChunk::BlockPointer: + case DeclaratorChunk::MemberPointer: + return false; + } + llvm_unreachable("Invalid type chunk"); + } + return false; + } + + /// isFunctionDeclarator - Once this declarator is fully parsed and formed, + /// this method returns true if the identifier is a function declarator + /// (looking through parentheses). + bool isFunctionDeclarator() const { + unsigned index; + return isFunctionDeclarator(index); + } + + /// getFunctionTypeInfo - Retrieves the function type info object + /// (looking through parentheses). + DeclaratorChunk::FunctionTypeInfo &getFunctionTypeInfo() { + assert(isFunctionDeclarator() && "Not a function declarator!"); + unsigned index = 0; + isFunctionDeclarator(index); + return DeclTypeInfo[index].Fun; + } + + /// getFunctionTypeInfo - Retrieves the function type info object + /// (looking through parentheses). + const DeclaratorChunk::FunctionTypeInfo &getFunctionTypeInfo() const { + return const_cast<Declarator*>(this)->getFunctionTypeInfo(); + } + + /// \brief Determine whether the declaration that will be produced from + /// this declaration will be a function. + /// + /// A declaration can declare a function even if the declarator itself + /// isn't a function declarator, if the type specifier refers to a function + /// type. This routine checks for both cases. + bool isDeclarationOfFunction() const; + + /// takeAttributes - Takes attributes from the given parsed-attributes + /// set and add them to this declarator. + /// + /// These examples both add 3 attributes to "var": + /// short int var __attribute__((aligned(16),common,deprecated)); + /// short int x, __attribute__((aligned(16)) var + /// __attribute__((common,deprecated)); + /// + /// Also extends the range of the declarator. + void takeAttributes(ParsedAttributes &attrs, SourceLocation lastLoc) { + Attrs.takeAllFrom(attrs); + + if (!lastLoc.isInvalid()) + SetRangeEnd(lastLoc); + } + + const AttributeList *getAttributes() const { return Attrs.getList(); } + AttributeList *getAttributes() { return Attrs.getList(); } + + AttributeList *&getAttrListRef() { return Attrs.getListRef(); } + + /// hasAttributes - do we contain any attributes? + bool hasAttributes() const { + if (getAttributes() || getDeclSpec().hasAttributes()) return true; + for (unsigned i = 0, e = getNumTypeObjects(); i != e; ++i) + if (getTypeObject(i).getAttrs()) + return true; + return false; + } + + void setAsmLabel(Expr *E) { AsmLabel = E; } + Expr *getAsmLabel() const { return AsmLabel; } + + void setExtension(bool Val = true) { Extension = Val; } + bool getExtension() const { return Extension; } + + void setInvalidType(bool Val = true) { InvalidType = Val; } + bool isInvalidType() const { + return InvalidType || DS.getTypeSpecType() == DeclSpec::TST_error; + } + + void setGroupingParens(bool flag) { GroupingParens = flag; } + bool hasGroupingParens() const { return GroupingParens; } + + bool isFirstDeclarator() const { return !CommaLoc.isValid(); } + SourceLocation getCommaLoc() const { return CommaLoc; } + void setCommaLoc(SourceLocation CL) { CommaLoc = CL; } + + bool hasEllipsis() const { return EllipsisLoc.isValid(); } + SourceLocation getEllipsisLoc() const { return EllipsisLoc; } + void setEllipsisLoc(SourceLocation EL) { EllipsisLoc = EL; } + + void setFunctionDefinitionKind(FunctionDefinitionKind Val) { + FunctionDefinition = Val; + } + + bool isFunctionDefinition() const { + return getFunctionDefinitionKind() != FDK_Declaration; + } + + FunctionDefinitionKind getFunctionDefinitionKind() const { + return (FunctionDefinitionKind)FunctionDefinition; + } + + void setRedeclaration(bool Val) { Redeclaration = Val; } + bool isRedeclaration() const { return Redeclaration; } +}; + +/// FieldDeclarator - This little struct is used to capture information about +/// structure field declarators, which is basically just a bitfield size. +struct FieldDeclarator { + Declarator D; + Expr *BitfieldSize; + explicit FieldDeclarator(DeclSpec &DS) : D(DS, Declarator::MemberContext) { + BitfieldSize = 0; + } +}; + +/// VirtSpecifiers - Represents a C++0x virt-specifier-seq. +class VirtSpecifiers { +public: + enum Specifier { + VS_None = 0, + VS_Override = 1, + VS_Final = 2 + }; + + VirtSpecifiers() : Specifiers(0) { } + + bool SetSpecifier(Specifier VS, SourceLocation Loc, + const char *&PrevSpec); + + bool isOverrideSpecified() const { return Specifiers & VS_Override; } + SourceLocation getOverrideLoc() const { return VS_overrideLoc; } + + bool isFinalSpecified() const { return Specifiers & VS_Final; } + SourceLocation getFinalLoc() const { return VS_finalLoc; } + + void clear() { Specifiers = 0; } + + static const char *getSpecifierName(Specifier VS); + + SourceLocation getLastLocation() const { return LastLocation; } + +private: + unsigned Specifiers; + + SourceLocation VS_overrideLoc, VS_finalLoc; + SourceLocation LastLocation; +}; + +/// LambdaCapture - An individual capture in a lambda introducer. +struct LambdaCapture { + LambdaCaptureKind Kind; + SourceLocation Loc; + IdentifierInfo* Id; + SourceLocation EllipsisLoc; + + LambdaCapture(LambdaCaptureKind Kind, SourceLocation Loc, + IdentifierInfo* Id = 0, + SourceLocation EllipsisLoc = SourceLocation()) + : Kind(Kind), Loc(Loc), Id(Id), EllipsisLoc(EllipsisLoc) + {} +}; + +/// LambdaIntroducer - Represents a complete lambda introducer. +struct LambdaIntroducer { + SourceRange Range; + SourceLocation DefaultLoc; + LambdaCaptureDefault Default; + llvm::SmallVector<LambdaCapture, 4> Captures; + + LambdaIntroducer() + : Default(LCD_None) {} + + /// addCapture - Append a capture in a lambda introducer. + void addCapture(LambdaCaptureKind Kind, + SourceLocation Loc, + IdentifierInfo* Id = 0, + SourceLocation EllipsisLoc = SourceLocation()) { + Captures.push_back(LambdaCapture(Kind, Loc, Id, EllipsisLoc)); + } + +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Sema/DelayedDiagnostic.h b/clang/include/clang/Sema/DelayedDiagnostic.h new file mode 100644 index 0000000..3320cd8 --- /dev/null +++ b/clang/include/clang/Sema/DelayedDiagnostic.h @@ -0,0 +1,220 @@ +//===--- DelayedDiagnostic.h - Delayed declarator diagnostics ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the DelayedDiagnostic class, which is used to +// record diagnostics that are being conditionally produced during +// declarator parsing. Certain kinds of diagnostics --- notably +// deprecation and access control --- are suppressed based on +// semantic properties of the parsed declaration that aren't known +// until it is fully parsed. +// +// This file also defines AccessedEntity. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_DELAYED_DIAGNOSTIC_H +#define LLVM_CLANG_SEMA_DELAYED_DIAGNOSTIC_H + +#include "clang/AST/DeclCXX.h" + +namespace clang { +namespace sema { + +/// A declaration being accessed, together with information about how +/// it was accessed. +class AccessedEntity { +public: + /// A member declaration found through lookup. The target is the + /// member. + enum MemberNonce { Member }; + + /// A hierarchy (base-to-derived or derived-to-base) conversion. + /// The target is the base class. + enum BaseNonce { Base }; + + bool isMemberAccess() const { return IsMember; } + + AccessedEntity(ASTContext &Context, + MemberNonce _, + CXXRecordDecl *NamingClass, + DeclAccessPair FoundDecl, + QualType BaseObjectType) + : Access(FoundDecl.getAccess()), IsMember(true), + Target(FoundDecl.getDecl()), NamingClass(NamingClass), + BaseObjectType(BaseObjectType), Diag(0, Context.getDiagAllocator()) { + } + + AccessedEntity(ASTContext &Context, + BaseNonce _, + CXXRecordDecl *BaseClass, + CXXRecordDecl *DerivedClass, + AccessSpecifier Access) + : Access(Access), IsMember(false), + Target(BaseClass), + NamingClass(DerivedClass), + Diag(0, Context.getDiagAllocator()) { + } + + bool isQuiet() const { return Diag.getDiagID() == 0; } + + AccessSpecifier getAccess() const { return AccessSpecifier(Access); } + + // These apply to member decls... + NamedDecl *getTargetDecl() const { return Target; } + CXXRecordDecl *getNamingClass() const { return NamingClass; } + + // ...and these apply to hierarchy conversions. + CXXRecordDecl *getBaseClass() const { + assert(!IsMember); return cast<CXXRecordDecl>(Target); + } + CXXRecordDecl *getDerivedClass() const { return NamingClass; } + + /// Retrieves the base object type, important when accessing + /// an instance member. + QualType getBaseObjectType() const { return BaseObjectType; } + + /// Sets a diagnostic to be performed. The diagnostic is given + /// four (additional) arguments: + /// %0 - 0 if the entity was private, 1 if protected + /// %1 - the DeclarationName of the entity + /// %2 - the TypeDecl type of the naming class + /// %3 - the TypeDecl type of the declaring class + void setDiag(const PartialDiagnostic &PDiag) { + assert(isQuiet() && "partial diagnostic already defined"); + Diag = PDiag; + } + PartialDiagnostic &setDiag(unsigned DiagID) { + assert(isQuiet() && "partial diagnostic already defined"); + assert(DiagID && "creating null diagnostic"); + Diag.Reset(DiagID); + return Diag; + } + const PartialDiagnostic &getDiag() const { + return Diag; + } + +private: + unsigned Access : 2; + unsigned IsMember : 1; + NamedDecl *Target; + CXXRecordDecl *NamingClass; + QualType BaseObjectType; + PartialDiagnostic Diag; +}; + +/// A diagnostic message which has been conditionally emitted pending +/// the complete parsing of the current declaration. +class DelayedDiagnostic { +public: + enum DDKind { Deprecation, Access, ForbiddenType }; + + unsigned char Kind; // actually a DDKind + bool Triggered; + + SourceLocation Loc; + + void Destroy(); + + static DelayedDiagnostic makeDeprecation(SourceLocation Loc, + const NamedDecl *D, + const ObjCInterfaceDecl *UnknownObjCClass, + StringRef Msg); + + static DelayedDiagnostic makeAccess(SourceLocation Loc, + const AccessedEntity &Entity) { + DelayedDiagnostic DD; + DD.Kind = Access; + DD.Triggered = false; + DD.Loc = Loc; + new (&DD.getAccessData()) AccessedEntity(Entity); + return DD; + } + + static DelayedDiagnostic makeForbiddenType(SourceLocation loc, + unsigned diagnostic, + QualType type, + unsigned argument) { + DelayedDiagnostic DD; + DD.Kind = ForbiddenType; + DD.Triggered = false; + DD.Loc = loc; + DD.ForbiddenTypeData.Diagnostic = diagnostic; + DD.ForbiddenTypeData.OperandType = type.getAsOpaquePtr(); + DD.ForbiddenTypeData.Argument = argument; + return DD; + } + + AccessedEntity &getAccessData() { + assert(Kind == Access && "Not an access diagnostic."); + return *reinterpret_cast<AccessedEntity*>(AccessData); + } + const AccessedEntity &getAccessData() const { + assert(Kind == Access && "Not an access diagnostic."); + return *reinterpret_cast<const AccessedEntity*>(AccessData); + } + + const NamedDecl *getDeprecationDecl() const { + assert(Kind == Deprecation && "Not a deprecation diagnostic."); + return DeprecationData.Decl; + } + + StringRef getDeprecationMessage() const { + assert(Kind == Deprecation && "Not a deprecation diagnostic."); + return StringRef(DeprecationData.Message, + DeprecationData.MessageLen); + } + + /// The diagnostic ID to emit. Used like so: + /// Diag(diag.Loc, diag.getForbiddenTypeDiagnostic()) + /// << diag.getForbiddenTypeOperand() + /// << diag.getForbiddenTypeArgument(); + unsigned getForbiddenTypeDiagnostic() const { + assert(Kind == ForbiddenType && "not a forbidden-type diagnostic"); + return ForbiddenTypeData.Diagnostic; + } + + unsigned getForbiddenTypeArgument() const { + assert(Kind == ForbiddenType && "not a forbidden-type diagnostic"); + return ForbiddenTypeData.Argument; + } + + QualType getForbiddenTypeOperand() const { + assert(Kind == ForbiddenType && "not a forbidden-type diagnostic"); + return QualType::getFromOpaquePtr(ForbiddenTypeData.OperandType); + } + + const ObjCInterfaceDecl *getUnknownObjCClass() const { + return DeprecationData.UnknownObjCClass; + } + +private: + union { + /// Deprecation. + struct { + const NamedDecl *Decl; + const ObjCInterfaceDecl *UnknownObjCClass; + const char *Message; + size_t MessageLen; + } DeprecationData; + + struct { + unsigned Diagnostic; + unsigned Argument; + void *OperandType; + } ForbiddenTypeData; + + /// Access control. + char AccessData[sizeof(AccessedEntity)]; + }; +}; + +} +} + +#endif diff --git a/clang/include/clang/Sema/Designator.h b/clang/include/clang/Sema/Designator.h new file mode 100644 index 0000000..fe01f4d --- /dev/null +++ b/clang/include/clang/Sema/Designator.h @@ -0,0 +1,218 @@ +//===--- Designator.h - Initialization Designator ---------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines interfaces used to represent designators (a la +// C99 designated initializers) during parsing. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_DESIGNATOR_H +#define LLVM_CLANG_SEMA_DESIGNATOR_H + +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/SmallVector.h" + +namespace clang { + +class Expr; +class IdentifierInfo; +class Sema; + +/// Designator - A designator in a C99 designated initializer. +/// +/// This class is a discriminated union which holds the various +/// different sorts of designators possible. A Designation is an array of +/// these. An example of a designator are things like this: +/// [8] .field [47] // C99 designation: 3 designators +/// [8 ... 47] field: // GNU extensions: 2 designators +/// These occur in initializers, e.g.: +/// int a[10] = {2, 4, [8]=9, 10}; +/// +class Designator { +public: + enum DesignatorKind { + FieldDesignator, ArrayDesignator, ArrayRangeDesignator + }; +private: + DesignatorKind Kind; + + struct FieldDesignatorInfo { + const IdentifierInfo *II; + unsigned DotLoc; + unsigned NameLoc; + }; + struct ArrayDesignatorInfo { + Expr *Index; + unsigned LBracketLoc; + mutable unsigned RBracketLoc; + }; + struct ArrayRangeDesignatorInfo { + Expr *Start, *End; + unsigned LBracketLoc, EllipsisLoc; + mutable unsigned RBracketLoc; + }; + + union { + FieldDesignatorInfo FieldInfo; + ArrayDesignatorInfo ArrayInfo; + ArrayRangeDesignatorInfo ArrayRangeInfo; + }; + +public: + + DesignatorKind getKind() const { return Kind; } + bool isFieldDesignator() const { return Kind == FieldDesignator; } + bool isArrayDesignator() const { return Kind == ArrayDesignator; } + bool isArrayRangeDesignator() const { return Kind == ArrayRangeDesignator; } + + const IdentifierInfo *getField() const { + assert(isFieldDesignator() && "Invalid accessor"); + return FieldInfo.II; + } + + SourceLocation getDotLoc() const { + assert(isFieldDesignator() && "Invalid accessor"); + return SourceLocation::getFromRawEncoding(FieldInfo.DotLoc); + } + + SourceLocation getFieldLoc() const { + assert(isFieldDesignator() && "Invalid accessor"); + return SourceLocation::getFromRawEncoding(FieldInfo.NameLoc); + } + + Expr *getArrayIndex() const { + assert(isArrayDesignator() && "Invalid accessor"); + return ArrayInfo.Index; + } + + Expr *getArrayRangeStart() const { + assert(isArrayRangeDesignator() && "Invalid accessor"); + return ArrayRangeInfo.Start; + } + Expr *getArrayRangeEnd() const { + assert(isArrayRangeDesignator() && "Invalid accessor"); + return ArrayRangeInfo.End; + } + + SourceLocation getLBracketLoc() const { + assert((isArrayDesignator() || isArrayRangeDesignator()) && + "Invalid accessor"); + if (isArrayDesignator()) + return SourceLocation::getFromRawEncoding(ArrayInfo.LBracketLoc); + else + return SourceLocation::getFromRawEncoding(ArrayRangeInfo.LBracketLoc); + } + + SourceLocation getRBracketLoc() const { + assert((isArrayDesignator() || isArrayRangeDesignator()) && + "Invalid accessor"); + if (isArrayDesignator()) + return SourceLocation::getFromRawEncoding(ArrayInfo.RBracketLoc); + else + return SourceLocation::getFromRawEncoding(ArrayRangeInfo.RBracketLoc); + } + + SourceLocation getEllipsisLoc() const { + assert(isArrayRangeDesignator() && "Invalid accessor"); + return SourceLocation::getFromRawEncoding(ArrayRangeInfo.EllipsisLoc); + } + + static Designator getField(const IdentifierInfo *II, SourceLocation DotLoc, + SourceLocation NameLoc) { + Designator D; + D.Kind = FieldDesignator; + D.FieldInfo.II = II; + D.FieldInfo.DotLoc = DotLoc.getRawEncoding(); + D.FieldInfo.NameLoc = NameLoc.getRawEncoding(); + return D; + } + + static Designator getArray(Expr *Index, + SourceLocation LBracketLoc) { + Designator D; + D.Kind = ArrayDesignator; + D.ArrayInfo.Index = Index; + D.ArrayInfo.LBracketLoc = LBracketLoc.getRawEncoding(); + D.ArrayInfo.RBracketLoc = 0; + return D; + } + + static Designator getArrayRange(Expr *Start, + Expr *End, + SourceLocation LBracketLoc, + SourceLocation EllipsisLoc) { + Designator D; + D.Kind = ArrayRangeDesignator; + D.ArrayRangeInfo.Start = Start; + D.ArrayRangeInfo.End = End; + D.ArrayRangeInfo.LBracketLoc = LBracketLoc.getRawEncoding(); + D.ArrayRangeInfo.EllipsisLoc = EllipsisLoc.getRawEncoding(); + D.ArrayRangeInfo.RBracketLoc = 0; + return D; + } + + void setRBracketLoc(SourceLocation RBracketLoc) const { + assert((isArrayDesignator() || isArrayRangeDesignator()) && + "Invalid accessor"); + if (isArrayDesignator()) + ArrayInfo.RBracketLoc = RBracketLoc.getRawEncoding(); + else + ArrayRangeInfo.RBracketLoc = RBracketLoc.getRawEncoding(); + } + + /// ClearExprs - Null out any expression references, which prevents + /// them from being 'delete'd later. + void ClearExprs(Sema &Actions) {} + + /// FreeExprs - Release any unclaimed memory for the expressions in + /// this designator. + void FreeExprs(Sema &Actions) {} +}; + + +/// Designation - Represent a full designation, which is a sequence of +/// designators. This class is mostly a helper for InitListDesignations. +class Designation { + /// InitIndex - The index of the initializer expression this is for. For + /// example, if the initializer were "{ A, .foo=B, C }" a Designation would + /// exist with InitIndex=1, because element #1 has a designation. + unsigned InitIndex; + + /// Designators - The actual designators for this initializer. + SmallVector<Designator, 2> Designators; + + Designation(unsigned Idx) : InitIndex(Idx) {} +public: + Designation() : InitIndex(4000) {} + + /// AddDesignator - Add a designator to the end of this list. + void AddDesignator(Designator D) { + Designators.push_back(D); + } + + bool empty() const { return Designators.empty(); } + + unsigned getNumDesignators() const { return Designators.size(); } + const Designator &getDesignator(unsigned Idx) const { + assert(Idx < Designators.size()); + return Designators[Idx]; + } + + /// ClearExprs - Null out any expression references, which prevents them from + /// being 'delete'd later. + void ClearExprs(Sema &Actions) {} + + /// FreeExprs - Release any unclaimed memory for the expressions in this + /// designation. + void FreeExprs(Sema &Actions) {} +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Sema/ExternalSemaSource.h b/clang/include/clang/Sema/ExternalSemaSource.h new file mode 100644 index 0000000..785bf6a --- /dev/null +++ b/clang/include/clang/Sema/ExternalSemaSource.h @@ -0,0 +1,183 @@ +//===--- ExternalSemaSource.h - External Sema Interface ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ExternalSemaSource interface. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_SEMA_EXTERNAL_SEMA_SOURCE_H +#define LLVM_CLANG_SEMA_EXTERNAL_SEMA_SOURCE_H + +#include "clang/AST/ExternalASTSource.h" +#include "clang/Sema/Weak.h" +#include <utility> + +namespace clang { + +class CXXConstructorDecl; +class CXXRecordDecl; +class DeclaratorDecl; +class LookupResult; +struct ObjCMethodList; +class Scope; +class Sema; +class TypedefNameDecl; +class ValueDecl; +class VarDecl; + +/// \brief A simple structure that captures a vtable use for the purposes of +/// the \c ExternalSemaSource. +struct ExternalVTableUse { + CXXRecordDecl *Record; + SourceLocation Location; + bool DefinitionRequired; +}; + +/// \brief An abstract interface that should be implemented by +/// external AST sources that also provide information for semantic +/// analysis. +class ExternalSemaSource : public ExternalASTSource { +public: + ExternalSemaSource() { + ExternalASTSource::SemaSource = true; + } + + ~ExternalSemaSource(); + + /// \brief Initialize the semantic source with the Sema instance + /// being used to perform semantic analysis on the abstract syntax + /// tree. + virtual void InitializeSema(Sema &S) {} + + /// \brief Inform the semantic consumer that Sema is no longer available. + virtual void ForgetSema() {} + + /// \brief Load the contents of the global method pool for a given + /// selector. + virtual void ReadMethodPool(Selector Sel); + + /// \brief Load the set of namespaces that are known to the external source, + /// which will be used during typo correction. + virtual void ReadKnownNamespaces( + SmallVectorImpl<NamespaceDecl *> &Namespaces); + + /// \brief Do last resort, unqualified lookup on a LookupResult that + /// Sema cannot find. + /// + /// \param R a LookupResult that is being recovered. + /// + /// \param S the Scope of the identifier occurrence. + /// + /// \return true to tell Sema to recover using the LookupResult. + virtual bool LookupUnqualified(LookupResult &R, Scope *S) { return false; } + + /// \brief Read the set of tentative definitions known to the external Sema + /// source. + /// + /// The external source should append its own tentative definitions to the + /// given vector of tentative definitions. Note that this routine may be + /// invoked multiple times; the external source should take care not to + /// introduce the same declarations repeatedly. + virtual void ReadTentativeDefinitions( + SmallVectorImpl<VarDecl *> &TentativeDefs) {} + + /// \brief Read the set of unused file-scope declarations known to the + /// external Sema source. + /// + /// The external source should append its own unused, filed-scope to the + /// given vector of declarations. Note that this routine may be + /// invoked multiple times; the external source should take care not to + /// introduce the same declarations repeatedly. + virtual void ReadUnusedFileScopedDecls( + SmallVectorImpl<const DeclaratorDecl *> &Decls) {} + + /// \brief Read the set of delegating constructors known to the + /// external Sema source. + /// + /// The external source should append its own delegating constructors to the + /// given vector of declarations. Note that this routine may be + /// invoked multiple times; the external source should take care not to + /// introduce the same declarations repeatedly. + virtual void ReadDelegatingConstructors( + SmallVectorImpl<CXXConstructorDecl *> &Decls) {} + + /// \brief Read the set of ext_vector type declarations known to the + /// external Sema source. + /// + /// The external source should append its own ext_vector type declarations to + /// the given vector of declarations. Note that this routine may be + /// invoked multiple times; the external source should take care not to + /// introduce the same declarations repeatedly. + virtual void ReadExtVectorDecls(SmallVectorImpl<TypedefNameDecl *> &Decls) {} + + /// \brief Read the set of dynamic classes known to the external Sema source. + /// + /// The external source should append its own dynamic classes to + /// the given vector of declarations. Note that this routine may be + /// invoked multiple times; the external source should take care not to + /// introduce the same declarations repeatedly. + virtual void ReadDynamicClasses(SmallVectorImpl<CXXRecordDecl *> &Decls) {} + + /// \brief Read the set of locally-scoped external declarations known to the + /// external Sema source. + /// + /// The external source should append its own locally-scoped external + /// declarations to the given vector of declarations. Note that this routine + /// may be invoked multiple times; the external source should take care not + /// to introduce the same declarations repeatedly. + virtual void ReadLocallyScopedExternalDecls( + SmallVectorImpl<NamedDecl *> &Decls) {} + + /// \brief Read the set of referenced selectors known to the + /// external Sema source. + /// + /// The external source should append its own referenced selectors to the + /// given vector of selectors. Note that this routine + /// may be invoked multiple times; the external source should take care not + /// to introduce the same selectors repeatedly. + virtual void ReadReferencedSelectors( + SmallVectorImpl<std::pair<Selector, SourceLocation> > &Sels) {} + + /// \brief Read the set of weak, undeclared identifiers known to the + /// external Sema source. + /// + /// The external source should append its own weak, undeclared identifiers to + /// the given vector. Note that this routine may be invoked multiple times; + /// the external source should take care not to introduce the same identifiers + /// repeatedly. + virtual void ReadWeakUndeclaredIdentifiers( + SmallVectorImpl<std::pair<IdentifierInfo *, WeakInfo> > &WI) {} + + /// \brief Read the set of used vtables known to the external Sema source. + /// + /// The external source should append its own used vtables to the given + /// vector. Note that this routine may be invoked multiple times; the external + /// source should take care not to introduce the same vtables repeatedly. + virtual void ReadUsedVTables(SmallVectorImpl<ExternalVTableUse> &VTables) {} + + /// \brief Read the set of pending instantiations known to the external + /// Sema source. + /// + /// The external source should append its own pending instantiations to the + /// given vector. Note that this routine may be invoked multiple times; the + /// external source should take care not to introduce the same instantiations + /// repeatedly. + virtual void ReadPendingInstantiations( + SmallVectorImpl<std::pair<ValueDecl *, + SourceLocation> > &Pending) {} + + // isa/cast/dyn_cast support + static bool classof(const ExternalASTSource *Source) { + return Source->SemaSource; + } + static bool classof(const ExternalSemaSource *) { return true; } +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Sema/IdentifierResolver.h b/clang/include/clang/Sema/IdentifierResolver.h new file mode 100644 index 0000000..dff0134 --- /dev/null +++ b/clang/include/clang/Sema/IdentifierResolver.h @@ -0,0 +1,221 @@ +//===- IdentifierResolver.h - Lexical Scope Name lookup ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the IdentifierResolver class, which is used for lexical +// scoped lookup, based on declaration names. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_SEMA_IDENTIFIERRESOLVER_H +#define LLVM_CLANG_AST_SEMA_IDENTIFIERRESOLVER_H + +#include "clang/Basic/IdentifierTable.h" +#include "llvm/ADT/SmallVector.h" + +namespace clang { + +class ASTContext; +class Decl; +class DeclContext; +class DeclarationName; +class ExternalPreprocessorSource; +class NamedDecl; +class Preprocessor; +class Scope; + +/// IdentifierResolver - Keeps track of shadowed decls on enclosing +/// scopes. It manages the shadowing chains of declaration names and +/// implements efficient decl lookup based on a declaration name. +class IdentifierResolver { + + /// IdDeclInfo - Keeps track of information about decls associated + /// to a particular declaration name. IdDeclInfos are lazily + /// constructed and assigned to a declaration name the first time a + /// decl with that declaration name is shadowed in some scope. + class IdDeclInfo { + public: + typedef SmallVector<NamedDecl*, 2> DeclsTy; + + inline DeclsTy::iterator decls_begin() { return Decls.begin(); } + inline DeclsTy::iterator decls_end() { return Decls.end(); } + + void AddDecl(NamedDecl *D) { Decls.push_back(D); } + + /// RemoveDecl - Remove the decl from the scope chain. + /// The decl must already be part of the decl chain. + void RemoveDecl(NamedDecl *D); + + /// Replaces the Old declaration with the New declaration. If the + /// replacement is successful, returns true. If the old + /// declaration was not found, returns false. + bool ReplaceDecl(NamedDecl *Old, NamedDecl *New); + + /// \brief Insert the given declaration at the given position in the list. + void InsertDecl(DeclsTy::iterator Pos, NamedDecl *D) { + Decls.insert(Pos, D); + } + + private: + DeclsTy Decls; + }; + +public: + + /// iterator - Iterate over the decls of a specified declaration name. + /// It will walk or not the parent declaration contexts depending on how + /// it was instantiated. + class iterator { + public: + typedef NamedDecl * value_type; + typedef NamedDecl * reference; + typedef NamedDecl * pointer; + typedef std::input_iterator_tag iterator_category; + typedef std::ptrdiff_t difference_type; + + /// Ptr - There are 3 forms that 'Ptr' represents: + /// 1) A single NamedDecl. (Ptr & 0x1 == 0) + /// 2) A IdDeclInfo::DeclsTy::iterator that traverses only the decls of the + /// same declaration context. (Ptr & 0x3 == 0x1) + /// 3) A IdDeclInfo::DeclsTy::iterator that traverses the decls of parent + /// declaration contexts too. (Ptr & 0x3 == 0x3) + uintptr_t Ptr; + typedef IdDeclInfo::DeclsTy::iterator BaseIter; + + /// A single NamedDecl. (Ptr & 0x1 == 0) + iterator(NamedDecl *D) { + Ptr = reinterpret_cast<uintptr_t>(D); + assert((Ptr & 0x1) == 0 && "Invalid Ptr!"); + } + /// A IdDeclInfo::DeclsTy::iterator that walks or not the parent declaration + /// contexts depending on 'LookInParentCtx'. + iterator(BaseIter I) { + Ptr = reinterpret_cast<uintptr_t>(I) | 0x1; + } + + bool isIterator() const { return (Ptr & 0x1); } + + BaseIter getIterator() const { + assert(isIterator() && "Ptr not an iterator!"); + return reinterpret_cast<BaseIter>(Ptr & ~0x3); + } + + friend class IdentifierResolver; + + void incrementSlowCase(); + public: + iterator() : Ptr(0) {} + + NamedDecl *operator*() const { + if (isIterator()) + return *getIterator(); + else + return reinterpret_cast<NamedDecl*>(Ptr); + } + + bool operator==(const iterator &RHS) const { + return Ptr == RHS.Ptr; + } + bool operator!=(const iterator &RHS) const { + return Ptr != RHS.Ptr; + } + + // Preincrement. + iterator& operator++() { + if (!isIterator()) // common case. + Ptr = 0; + else + incrementSlowCase(); + return *this; + } + + uintptr_t getAsOpaqueValue() const { return Ptr; } + + static iterator getFromOpaqueValue(uintptr_t P) { + iterator Result; + Result.Ptr = P; + return Result; + } + }; + + /// begin - Returns an iterator for decls with the name 'Name'. + iterator begin(DeclarationName Name); + + /// end - Returns an iterator that has 'finished'. + iterator end() { + return iterator(); + } + + /// isDeclInScope - If 'Ctx' is a function/method, isDeclInScope returns true + /// if 'D' is in Scope 'S', otherwise 'S' is ignored and isDeclInScope returns + /// true if 'D' belongs to the given declaration context. + /// + /// \param ExplicitInstantiationOrSpecialization When true, we are checking + /// whether the declaration is in scope for the purposes of explicit template + /// instantiation or specialization. The default is false. + bool isDeclInScope(Decl *D, DeclContext *Ctx, ASTContext &Context, + Scope *S = 0, + bool ExplicitInstantiationOrSpecialization = false) const; + + /// AddDecl - Link the decl to its shadowed decl chain. + void AddDecl(NamedDecl *D); + + /// RemoveDecl - Unlink the decl from its shadowed decl chain. + /// The decl must already be part of the decl chain. + void RemoveDecl(NamedDecl *D); + + /// Replace the decl Old with the new declaration New on its + /// identifier chain. Returns true if the old declaration was found + /// (and, therefore, replaced). + bool ReplaceDecl(NamedDecl *Old, NamedDecl *New); + + /// \brief Insert the given declaration after the given iterator + /// position. + void InsertDeclAfter(iterator Pos, NamedDecl *D); + + /// \brief Try to add the given declaration to the top level scope, if it + /// (or a redeclaration of it) hasn't already been added. + /// + /// \param D The externally-produced declaration to add. + /// + /// \param Name The name of the externally-produced declaration. + /// + /// \returns true if the declaration was added, false otherwise. + bool tryAddTopLevelDecl(NamedDecl *D, DeclarationName Name); + + explicit IdentifierResolver(Preprocessor &PP); + ~IdentifierResolver(); + +private: + const LangOptions &LangOpt; + Preprocessor &PP; + + class IdDeclInfoMap; + IdDeclInfoMap *IdDeclInfos; + + void updatingIdentifier(IdentifierInfo &II); + void readingIdentifier(IdentifierInfo &II); + + /// FETokenInfo contains a Decl pointer if lower bit == 0. + static inline bool isDeclPtr(void *Ptr) { + return (reinterpret_cast<uintptr_t>(Ptr) & 0x1) == 0; + } + + /// FETokenInfo contains a IdDeclInfo pointer if lower bit == 1. + static inline IdDeclInfo *toIdDeclInfo(void *Ptr) { + assert((reinterpret_cast<uintptr_t>(Ptr) & 0x1) == 1 + && "Ptr not a IdDeclInfo* !"); + return reinterpret_cast<IdDeclInfo*>( + reinterpret_cast<uintptr_t>(Ptr) & ~0x1 + ); + } +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Sema/Initialization.h b/clang/include/clang/Sema/Initialization.h new file mode 100644 index 0000000..0dd6887 --- /dev/null +++ b/clang/include/clang/Sema/Initialization.h @@ -0,0 +1,1001 @@ +//===--- Initialization.h - Semantic Analysis for Initializers --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides supporting data types for initialization of objects. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_SEMA_INITIALIZATION_H +#define LLVM_CLANG_SEMA_INITIALIZATION_H + +#include "clang/Sema/Ownership.h" +#include "clang/Sema/Overload.h" +#include "clang/AST/Type.h" +#include "clang/AST/UnresolvedSet.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/SmallVector.h" +#include <cassert> + +namespace clang { + +class CXXBaseSpecifier; +class DeclaratorDecl; +class DeclaratorInfo; +class FieldDecl; +class FunctionDecl; +class ParmVarDecl; +class Sema; +class TypeLoc; +class VarDecl; + +/// \brief Describes an entity that is being initialized. +class InitializedEntity { +public: + /// \brief Specifies the kind of entity being initialized. + enum EntityKind { + /// \brief The entity being initialized is a variable. + EK_Variable, + /// \brief The entity being initialized is a function parameter. + EK_Parameter, + /// \brief The entity being initialized is the result of a function call. + EK_Result, + /// \brief The entity being initialized is an exception object that + /// is being thrown. + EK_Exception, + /// \brief The entity being initialized is a non-static data member + /// subobject. + EK_Member, + /// \brief The entity being initialized is an element of an array. + EK_ArrayElement, + /// \brief The entity being initialized is an object (or array of + /// objects) allocated via new. + EK_New, + /// \brief The entity being initialized is a temporary object. + EK_Temporary, + /// \brief The entity being initialized is a base member subobject. + EK_Base, + /// \brief The initialization is being done by a delegating constructor. + EK_Delegating, + /// \brief The entity being initialized is an element of a vector. + /// or vector. + EK_VectorElement, + /// \brief The entity being initialized is a field of block descriptor for + /// the copied-in c++ object. + EK_BlockElement, + /// \brief The entity being initialized is the real or imaginary part of a + /// complex number. + EK_ComplexElement, + /// \brief The entity being initialized is the field that captures a + /// variable in a lambda. + EK_LambdaCapture + }; + +private: + /// \brief The kind of entity being initialized. + EntityKind Kind; + + /// \brief If non-NULL, the parent entity in which this + /// initialization occurs. + const InitializedEntity *Parent; + + /// \brief The type of the object or reference being initialized. + QualType Type; + + union { + /// \brief When Kind == EK_Variable, or EK_Member, the VarDecl or + /// FieldDecl, respectively. + DeclaratorDecl *VariableOrMember; + + /// \brief When Kind == EK_Parameter, the ParmVarDecl, with the + /// low bit indicating whether the parameter is "consumed". + uintptr_t Parameter; + + /// \brief When Kind == EK_Temporary, the type source information for + /// the temporary. + TypeSourceInfo *TypeInfo; + + struct { + /// \brief When Kind == EK_Result, EK_Exception, EK_New, the + /// location of the 'return', 'throw', or 'new' keyword, + /// respectively. When Kind == EK_Temporary, the location where + /// the temporary is being created. + unsigned Location; + + /// \brief Whether the entity being initialized may end up using the + /// named return value optimization (NRVO). + bool NRVO; + } LocAndNRVO; + + /// \brief When Kind == EK_Base, the base specifier that provides the + /// base class. The lower bit specifies whether the base is an inherited + /// virtual base. + uintptr_t Base; + + /// \brief When Kind == EK_ArrayElement, EK_VectorElement, or + /// EK_ComplexElement, the index of the array or vector element being + /// initialized. + unsigned Index; + + struct { + /// \brief The variable being captured by an EK_LambdaCapture. + VarDecl *Var; + + /// \brief The source location at which the capture occurs. + unsigned Location; + } Capture; + }; + + InitializedEntity() { } + + /// \brief Create the initialization entity for a variable. + InitializedEntity(VarDecl *Var) + : Kind(EK_Variable), Parent(0), Type(Var->getType()), + VariableOrMember(Var) { } + + /// \brief Create the initialization entity for the result of a + /// function, throwing an object, performing an explicit cast, or + /// initializing a parameter for which there is no declaration. + InitializedEntity(EntityKind Kind, SourceLocation Loc, QualType Type, + bool NRVO = false) + : Kind(Kind), Parent(0), Type(Type) + { + LocAndNRVO.Location = Loc.getRawEncoding(); + LocAndNRVO.NRVO = NRVO; + } + + /// \brief Create the initialization entity for a member subobject. + InitializedEntity(FieldDecl *Member, const InitializedEntity *Parent) + : Kind(EK_Member), Parent(Parent), Type(Member->getType()), + VariableOrMember(Member) { } + + /// \brief Create the initialization entity for an array element. + InitializedEntity(ASTContext &Context, unsigned Index, + const InitializedEntity &Parent); + + /// \brief Create the initialization entity for a lambda capture. + InitializedEntity(VarDecl *Var, FieldDecl *Field, SourceLocation Loc) + : Kind(EK_LambdaCapture), Parent(0), Type(Field->getType()) + { + Capture.Var = Var; + Capture.Location = Loc.getRawEncoding(); + } + +public: + /// \brief Create the initialization entity for a variable. + static InitializedEntity InitializeVariable(VarDecl *Var) { + return InitializedEntity(Var); + } + + /// \brief Create the initialization entity for a parameter. + static InitializedEntity InitializeParameter(ASTContext &Context, + ParmVarDecl *Parm) { + bool Consumed = (Context.getLangOpts().ObjCAutoRefCount && + Parm->hasAttr<NSConsumedAttr>()); + + InitializedEntity Entity; + Entity.Kind = EK_Parameter; + Entity.Type = Context.getVariableArrayDecayedType( + Parm->getType().getUnqualifiedType()); + Entity.Parent = 0; + Entity.Parameter + = (static_cast<uintptr_t>(Consumed) | reinterpret_cast<uintptr_t>(Parm)); + return Entity; + } + + /// \brief Create the initialization entity for a parameter that is + /// only known by its type. + static InitializedEntity InitializeParameter(ASTContext &Context, + QualType Type, + bool Consumed) { + InitializedEntity Entity; + Entity.Kind = EK_Parameter; + Entity.Type = Context.getVariableArrayDecayedType(Type); + Entity.Parent = 0; + Entity.Parameter = (Consumed); + return Entity; + } + + /// \brief Create the initialization entity for the result of a function. + static InitializedEntity InitializeResult(SourceLocation ReturnLoc, + QualType Type, bool NRVO) { + return InitializedEntity(EK_Result, ReturnLoc, Type, NRVO); + } + + static InitializedEntity InitializeBlock(SourceLocation BlockVarLoc, + QualType Type, bool NRVO) { + return InitializedEntity(EK_BlockElement, BlockVarLoc, Type, NRVO); + } + + /// \brief Create the initialization entity for an exception object. + static InitializedEntity InitializeException(SourceLocation ThrowLoc, + QualType Type, bool NRVO) { + return InitializedEntity(EK_Exception, ThrowLoc, Type, NRVO); + } + + /// \brief Create the initialization entity for an object allocated via new. + static InitializedEntity InitializeNew(SourceLocation NewLoc, QualType Type) { + return InitializedEntity(EK_New, NewLoc, Type); + } + + /// \brief Create the initialization entity for a temporary. + static InitializedEntity InitializeTemporary(QualType Type) { + InitializedEntity Result(EK_Temporary, SourceLocation(), Type); + Result.TypeInfo = 0; + return Result; + } + + /// \brief Create the initialization entity for a temporary. + static InitializedEntity InitializeTemporary(TypeSourceInfo *TypeInfo) { + InitializedEntity Result(EK_Temporary, SourceLocation(), + TypeInfo->getType()); + Result.TypeInfo = TypeInfo; + return Result; + } + + /// \brief Create the initialization entity for a base class subobject. + static InitializedEntity InitializeBase(ASTContext &Context, + CXXBaseSpecifier *Base, + bool IsInheritedVirtualBase); + + /// \brief Create the initialization entity for a delegated constructor. + static InitializedEntity InitializeDelegation(QualType Type) { + return InitializedEntity(EK_Delegating, SourceLocation(), Type); + } + + /// \brief Create the initialization entity for a member subobject. + static InitializedEntity InitializeMember(FieldDecl *Member, + const InitializedEntity *Parent = 0) { + return InitializedEntity(Member, Parent); + } + + /// \brief Create the initialization entity for a member subobject. + static InitializedEntity InitializeMember(IndirectFieldDecl *Member, + const InitializedEntity *Parent = 0) { + return InitializedEntity(Member->getAnonField(), Parent); + } + + /// \brief Create the initialization entity for an array element. + static InitializedEntity InitializeElement(ASTContext &Context, + unsigned Index, + const InitializedEntity &Parent) { + return InitializedEntity(Context, Index, Parent); + } + + /// \brief Create the initialization entity for a lambda capture. + static InitializedEntity InitializeLambdaCapture(VarDecl *Var, + FieldDecl *Field, + SourceLocation Loc) { + return InitializedEntity(Var, Field, Loc); + } + + /// \brief Determine the kind of initialization. + EntityKind getKind() const { return Kind; } + + /// \brief Retrieve the parent of the entity being initialized, when + /// the initialization itself is occurring within the context of a + /// larger initialization. + const InitializedEntity *getParent() const { return Parent; } + + /// \brief Retrieve type being initialized. + QualType getType() const { return Type; } + + /// \brief Retrieve complete type-source information for the object being + /// constructed, if known. + TypeSourceInfo *getTypeSourceInfo() const { + if (Kind == EK_Temporary) + return TypeInfo; + + return 0; + } + + /// \brief Retrieve the name of the entity being initialized. + DeclarationName getName() const; + + /// \brief Retrieve the variable, parameter, or field being + /// initialized. + DeclaratorDecl *getDecl() const; + + /// \brief Determine whether this initialization allows the named return + /// value optimization, which also applies to thrown objects. + bool allowsNRVO() const; + + /// \brief Determine whether this initialization consumes the + /// parameter. + bool isParameterConsumed() const { + assert(getKind() == EK_Parameter && "Not a parameter"); + return (Parameter & 1); + } + + /// \brief Retrieve the base specifier. + CXXBaseSpecifier *getBaseSpecifier() const { + assert(getKind() == EK_Base && "Not a base specifier"); + return reinterpret_cast<CXXBaseSpecifier *>(Base & ~0x1); + } + + /// \brief Return whether the base is an inherited virtual base. + bool isInheritedVirtualBase() const { + assert(getKind() == EK_Base && "Not a base specifier"); + return Base & 0x1; + } + + /// \brief Determine the location of the 'return' keyword when initializing + /// the result of a function call. + SourceLocation getReturnLoc() const { + assert(getKind() == EK_Result && "No 'return' location!"); + return SourceLocation::getFromRawEncoding(LocAndNRVO.Location); + } + + /// \brief Determine the location of the 'throw' keyword when initializing + /// an exception object. + SourceLocation getThrowLoc() const { + assert(getKind() == EK_Exception && "No 'throw' location!"); + return SourceLocation::getFromRawEncoding(LocAndNRVO.Location); + } + + /// \brief If this is already the initializer for an array or vector + /// element, sets the element index. + void setElementIndex(unsigned Index) { + assert(getKind() == EK_ArrayElement || getKind() == EK_VectorElement || + getKind() == EK_ComplexElement); + this->Index = Index; + } + + /// \brief Retrieve the variable for a captured variable in a lambda. + VarDecl *getCapturedVar() const { + assert(getKind() == EK_LambdaCapture && "Not a lambda capture!"); + return Capture.Var; + } + + /// \brief Determine the location of the capture when initializing + /// field from a captured variable in a lambda. + SourceLocation getCaptureLoc() const { + assert(getKind() == EK_LambdaCapture && "Not a lambda capture!"); + return SourceLocation::getFromRawEncoding(Capture.Location); + } +}; + +/// \brief Describes the kind of initialization being performed, along with +/// location information for tokens related to the initialization (equal sign, +/// parentheses). +class InitializationKind { +public: + /// \brief The kind of initialization being performed. + enum InitKind { + IK_Direct, ///< Direct initialization + IK_DirectList, ///< Direct list-initialization + IK_Copy, ///< Copy initialization + IK_Default, ///< Default initialization + IK_Value ///< Value initialization + }; + +private: + /// \brief The context of the initialization. + enum InitContext { + IC_Normal, ///< Normal context + IC_ExplicitConvs, ///< Normal context, but allows explicit conversion funcs + IC_Implicit, ///< Implicit context (value initialization) + IC_StaticCast, ///< Static cast context + IC_CStyleCast, ///< C-style cast context + IC_FunctionalCast ///< Functional cast context + }; + + /// \brief The kind of initialization being performed. + InitKind Kind : 8; + + /// \brief The context of the initialization. + InitContext Context : 8; + + /// \brief The source locations involved in the initialization. + SourceLocation Locations[3]; + + InitializationKind(InitKind Kind, InitContext Context, SourceLocation Loc1, + SourceLocation Loc2, SourceLocation Loc3) + : Kind(Kind), Context(Context) + { + Locations[0] = Loc1; + Locations[1] = Loc2; + Locations[2] = Loc3; + } + +public: + /// \brief Create a direct initialization. + static InitializationKind CreateDirect(SourceLocation InitLoc, + SourceLocation LParenLoc, + SourceLocation RParenLoc) { + return InitializationKind(IK_Direct, IC_Normal, + InitLoc, LParenLoc, RParenLoc); + } + + static InitializationKind CreateDirectList(SourceLocation InitLoc) { + return InitializationKind(IK_DirectList, IC_Normal, + InitLoc, InitLoc, InitLoc); + } + + /// \brief Create a direct initialization due to a cast that isn't a C-style + /// or functional cast. + static InitializationKind CreateCast(SourceRange TypeRange) { + return InitializationKind(IK_Direct, IC_StaticCast, TypeRange.getBegin(), + TypeRange.getBegin(), TypeRange.getEnd()); + } + + /// \brief Create a direct initialization for a C-style cast. + static InitializationKind CreateCStyleCast(SourceLocation StartLoc, + SourceRange TypeRange, + bool InitList) { + // C++ cast syntax doesn't permit init lists, but C compound literals are + // exactly that. + return InitializationKind(InitList ? IK_DirectList : IK_Direct, + IC_CStyleCast, StartLoc, TypeRange.getBegin(), + TypeRange.getEnd()); + } + + /// \brief Create a direct initialization for a functional cast. + static InitializationKind CreateFunctionalCast(SourceRange TypeRange, + bool InitList) { + return InitializationKind(InitList ? IK_DirectList : IK_Direct, + IC_FunctionalCast, TypeRange.getBegin(), + TypeRange.getBegin(), TypeRange.getEnd()); + } + + /// \brief Create a copy initialization. + static InitializationKind CreateCopy(SourceLocation InitLoc, + SourceLocation EqualLoc, + bool AllowExplicitConvs = false) { + return InitializationKind(IK_Copy, + AllowExplicitConvs? IC_ExplicitConvs : IC_Normal, + InitLoc, EqualLoc, EqualLoc); + } + + /// \brief Create a default initialization. + static InitializationKind CreateDefault(SourceLocation InitLoc) { + return InitializationKind(IK_Default, IC_Normal, InitLoc, InitLoc, InitLoc); + } + + /// \brief Create a value initialization. + static InitializationKind CreateValue(SourceLocation InitLoc, + SourceLocation LParenLoc, + SourceLocation RParenLoc, + bool isImplicit = false) { + return InitializationKind(IK_Value, isImplicit ? IC_Implicit : IC_Normal, + InitLoc, LParenLoc, RParenLoc); + } + + /// \brief Determine the initialization kind. + InitKind getKind() const { + return Kind; + } + + /// \brief Determine whether this initialization is an explicit cast. + bool isExplicitCast() const { + return Context >= IC_StaticCast; + } + + /// \brief Determine whether this initialization is a C-style cast. + bool isCStyleOrFunctionalCast() const { + return Context >= IC_CStyleCast; + } + + /// \brief Determine whether this is a C-style cast. + bool isCStyleCast() const { + return Context == IC_CStyleCast; + } + + /// \brief Determine whether this is a functional-style cast. + bool isFunctionalCast() const { + return Context == IC_FunctionalCast; + } + + /// \brief Determine whether this initialization is an implicit + /// value-initialization, e.g., as occurs during aggregate + /// initialization. + bool isImplicitValueInit() const { return Context == IC_Implicit; } + + /// \brief Retrieve the location at which initialization is occurring. + SourceLocation getLocation() const { return Locations[0]; } + + /// \brief Retrieve the source range that covers the initialization. + SourceRange getRange() const { + return SourceRange(Locations[0], Locations[2]); + } + + /// \brief Retrieve the location of the equal sign for copy initialization + /// (if present). + SourceLocation getEqualLoc() const { + assert(Kind == IK_Copy && "Only copy initialization has an '='"); + return Locations[1]; + } + + bool isCopyInit() const { return Kind == IK_Copy; } + + /// \brief Retrieve whether this initialization allows the use of explicit + /// constructors. + bool AllowExplicit() const { return !isCopyInit(); } + + /// \brief Retrieve whether this initialization allows the use of explicit + /// conversion functions. + bool allowExplicitConversionFunctions() const { + return !isCopyInit() || Context == IC_ExplicitConvs; + } + + /// \brief Retrieve the source range containing the locations of the open + /// and closing parentheses for value and direct initializations. + SourceRange getParenRange() const { + assert((Kind == IK_Direct || Kind == IK_Value) && + "Only direct- and value-initialization have parentheses"); + return SourceRange(Locations[1], Locations[2]); + } +}; + +/// \brief Describes the sequence of initializations required to initialize +/// a given object or reference with a set of arguments. +class InitializationSequence { +public: + /// \brief Describes the kind of initialization sequence computed. + enum SequenceKind { + /// \brief A failed initialization sequence. The failure kind tells what + /// happened. + FailedSequence = 0, + + /// \brief A dependent initialization, which could not be + /// type-checked due to the presence of dependent types or + /// dependently-typed expressions. + DependentSequence, + + /// \brief A normal sequence. + NormalSequence + }; + + /// \brief Describes the kind of a particular step in an initialization + /// sequence. + enum StepKind { + /// \brief Resolve the address of an overloaded function to a specific + /// function declaration. + SK_ResolveAddressOfOverloadedFunction, + /// \brief Perform a derived-to-base cast, producing an rvalue. + SK_CastDerivedToBaseRValue, + /// \brief Perform a derived-to-base cast, producing an xvalue. + SK_CastDerivedToBaseXValue, + /// \brief Perform a derived-to-base cast, producing an lvalue. + SK_CastDerivedToBaseLValue, + /// \brief Reference binding to an lvalue. + SK_BindReference, + /// \brief Reference binding to a temporary. + SK_BindReferenceToTemporary, + /// \brief An optional copy of a temporary object to another + /// temporary object, which is permitted (but not required) by + /// C++98/03 but not C++0x. + SK_ExtraneousCopyToTemporary, + /// \brief Perform a user-defined conversion, either via a conversion + /// function or via a constructor. + SK_UserConversion, + /// \brief Perform a qualification conversion, producing an rvalue. + SK_QualificationConversionRValue, + /// \brief Perform a qualification conversion, producing an xvalue. + SK_QualificationConversionXValue, + /// \brief Perform a qualification conversion, producing an lvalue. + SK_QualificationConversionLValue, + /// \brief Perform an implicit conversion sequence. + SK_ConversionSequence, + /// \brief Perform list-initialization without a constructor + SK_ListInitialization, + /// \brief Perform list-initialization with a constructor. + SK_ListConstructorCall, + /// \brief Unwrap the single-element initializer list for a reference. + SK_UnwrapInitList, + /// \brief Rewrap the single-element initializer list for a reference. + SK_RewrapInitList, + /// \brief Perform initialization via a constructor. + SK_ConstructorInitialization, + /// \brief Zero-initialize the object + SK_ZeroInitialization, + /// \brief C assignment + SK_CAssignment, + /// \brief Initialization by string + SK_StringInit, + /// \brief An initialization that "converts" an Objective-C object + /// (not a point to an object) to another Objective-C object type. + SK_ObjCObjectConversion, + /// \brief Array initialization (from an array rvalue). + /// This is a GNU C extension. + SK_ArrayInit, + /// \brief Array initialization from a parenthesized initializer list. + /// This is a GNU C++ extension. + SK_ParenthesizedArrayInit, + /// \brief Pass an object by indirect copy-and-restore. + SK_PassByIndirectCopyRestore, + /// \brief Pass an object by indirect restore. + SK_PassByIndirectRestore, + /// \brief Produce an Objective-C object pointer. + SK_ProduceObjCObject, + /// \brief Construct a std::initializer_list from an initializer list. + SK_StdInitializerList + }; + + /// \brief A single step in the initialization sequence. + class Step { + public: + /// \brief The kind of conversion or initialization step we are taking. + StepKind Kind; + + // \brief The type that results from this initialization. + QualType Type; + + union { + /// \brief When Kind == SK_ResolvedOverloadedFunction or Kind == + /// SK_UserConversion, the function that the expression should be + /// resolved to or the conversion function to call, respectively. + /// When Kind == SK_ConstructorInitialization or SK_ListConstruction, + /// the constructor to be called. + /// + /// Always a FunctionDecl, plus a Boolean flag telling if it was + /// selected from an overloaded set having size greater than 1. + /// For conversion decls, the naming class is the source type. + /// For construct decls, the naming class is the target type. + struct { + bool HadMultipleCandidates; + FunctionDecl *Function; + DeclAccessPair FoundDecl; + } Function; + + /// \brief When Kind = SK_ConversionSequence, the implicit conversion + /// sequence. + ImplicitConversionSequence *ICS; + + /// \brief When Kind = SK_RewrapInitList, the syntactic form of the + /// wrapping list. + InitListExpr *WrappingSyntacticList; + }; + + void Destroy(); + }; + +private: + /// \brief The kind of initialization sequence computed. + enum SequenceKind SequenceKind; + + /// \brief Steps taken by this initialization. + SmallVector<Step, 4> Steps; + +public: + /// \brief Describes why initialization failed. + enum FailureKind { + /// \brief Too many initializers provided for a reference. + FK_TooManyInitsForReference, + /// \brief Array must be initialized with an initializer list. + FK_ArrayNeedsInitList, + /// \brief Array must be initialized with an initializer list or a + /// string literal. + FK_ArrayNeedsInitListOrStringLiteral, + /// \brief Array type mismatch. + FK_ArrayTypeMismatch, + /// \brief Non-constant array initializer + FK_NonConstantArrayInit, + /// \brief Cannot resolve the address of an overloaded function. + FK_AddressOfOverloadFailed, + /// \brief Overloading due to reference initialization failed. + FK_ReferenceInitOverloadFailed, + /// \brief Non-const lvalue reference binding to a temporary. + FK_NonConstLValueReferenceBindingToTemporary, + /// \brief Non-const lvalue reference binding to an lvalue of unrelated + /// type. + FK_NonConstLValueReferenceBindingToUnrelated, + /// \brief Rvalue reference binding to an lvalue. + FK_RValueReferenceBindingToLValue, + /// \brief Reference binding drops qualifiers. + FK_ReferenceInitDropsQualifiers, + /// \brief Reference binding failed. + FK_ReferenceInitFailed, + /// \brief Implicit conversion failed. + FK_ConversionFailed, + /// \brief Implicit conversion failed. + FK_ConversionFromPropertyFailed, + /// \brief Too many initializers for scalar + FK_TooManyInitsForScalar, + /// \brief Reference initialization from an initializer list + FK_ReferenceBindingToInitList, + /// \brief Initialization of some unused destination type with an + /// initializer list. + FK_InitListBadDestinationType, + /// \brief Overloading for a user-defined conversion failed. + FK_UserConversionOverloadFailed, + /// \brief Overloading for initialization by constructor failed. + FK_ConstructorOverloadFailed, + /// \brief Overloading for list-initialization by constructor failed. + FK_ListConstructorOverloadFailed, + /// \brief Default-initialization of a 'const' object. + FK_DefaultInitOfConst, + /// \brief Initialization of an incomplete type. + FK_Incomplete, + /// \brief Variable-length array must not have an initializer. + FK_VariableLengthArrayHasInitializer, + /// \brief List initialization failed at some point. + FK_ListInitializationFailed, + /// \brief Initializer has a placeholder type which cannot be + /// resolved by initialization. + FK_PlaceholderType, + /// \brief Failed to initialize a std::initializer_list because copy + /// construction of some element failed. + FK_InitListElementCopyFailure, + /// \brief List-copy-initialization chose an explicit constructor. + FK_ExplicitConstructor + }; + +private: + /// \brief The reason why initialization failed. + FailureKind Failure; + + /// \brief The failed result of overload resolution. + OverloadingResult FailedOverloadResult; + + /// \brief The candidate set created when initialization failed. + OverloadCandidateSet FailedCandidateSet; + + /// \brief The incomplete type that caused a failure. + QualType FailedIncompleteType; + + /// \brief Prints a follow-up note that highlights the location of + /// the initialized entity, if it's remote. + void PrintInitLocationNote(Sema &S, const InitializedEntity &Entity); + +public: + /// \brief Try to perform initialization of the given entity, creating a + /// record of the steps required to perform the initialization. + /// + /// The generated initialization sequence will either contain enough + /// information to diagnose + /// + /// \param S the semantic analysis object. + /// + /// \param Entity the entity being initialized. + /// + /// \param Kind the kind of initialization being performed. + /// + /// \param Args the argument(s) provided for initialization. + /// + /// \param NumArgs the number of arguments provided for initialization. + InitializationSequence(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + Expr **Args, + unsigned NumArgs); + + ~InitializationSequence(); + + /// \brief Perform the actual initialization of the given entity based on + /// the computed initialization sequence. + /// + /// \param S the semantic analysis object. + /// + /// \param Entity the entity being initialized. + /// + /// \param Kind the kind of initialization being performed. + /// + /// \param Args the argument(s) provided for initialization, ownership of + /// which is transferred into the routine. + /// + /// \param ResultType if non-NULL, will be set to the type of the + /// initialized object, which is the type of the declaration in most + /// cases. However, when the initialized object is a variable of + /// incomplete array type and the initializer is an initializer + /// list, this type will be set to the completed array type. + /// + /// \returns an expression that performs the actual object initialization, if + /// the initialization is well-formed. Otherwise, emits diagnostics + /// and returns an invalid expression. + ExprResult Perform(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + MultiExprArg Args, + QualType *ResultType = 0); + + /// \brief Diagnose an potentially-invalid initialization sequence. + /// + /// \returns true if the initialization sequence was ill-formed, + /// false otherwise. + bool Diagnose(Sema &S, + const InitializedEntity &Entity, + const InitializationKind &Kind, + Expr **Args, unsigned NumArgs); + + /// \brief Determine the kind of initialization sequence computed. + enum SequenceKind getKind() const { return SequenceKind; } + + /// \brief Set the kind of sequence computed. + void setSequenceKind(enum SequenceKind SK) { SequenceKind = SK; } + + /// \brief Determine whether the initialization sequence is valid. + operator bool() const { return !Failed(); } + + /// \brief Determine whether the initialization sequence is invalid. + bool Failed() const { return SequenceKind == FailedSequence; } + + typedef SmallVector<Step, 4>::const_iterator step_iterator; + step_iterator step_begin() const { return Steps.begin(); } + step_iterator step_end() const { return Steps.end(); } + + /// \brief Determine whether this initialization is a direct reference + /// binding (C++ [dcl.init.ref]). + bool isDirectReferenceBinding() const; + + /// \brief Determine whether this initialization failed due to an ambiguity. + bool isAmbiguous() const; + + /// \brief Determine whether this initialization is direct call to a + /// constructor. + bool isConstructorInitialization() const; + + /// \brief Returns whether the last step in this initialization sequence is a + /// narrowing conversion, defined by C++0x [dcl.init.list]p7. + /// + /// If this function returns true, *isInitializerConstant will be set to + /// describe whether *Initializer was a constant expression. If + /// *isInitializerConstant is set to true, *ConstantValue will be set to the + /// evaluated value of *Initializer. + bool endsWithNarrowing(ASTContext &Ctx, const Expr *Initializer, + bool *isInitializerConstant, + APValue *ConstantValue) const; + + /// \brief Add a new step in the initialization that resolves the address + /// of an overloaded function to a specific function declaration. + /// + /// \param Function the function to which the overloaded function reference + /// resolves. + void AddAddressOverloadResolutionStep(FunctionDecl *Function, + DeclAccessPair Found, + bool HadMultipleCandidates); + + /// \brief Add a new step in the initialization that performs a derived-to- + /// base cast. + /// + /// \param BaseType the base type to which we will be casting. + /// + /// \param IsLValue true if the result of this cast will be treated as + /// an lvalue. + void AddDerivedToBaseCastStep(QualType BaseType, + ExprValueKind Category); + + /// \brief Add a new step binding a reference to an object. + /// + /// \param BindingTemporary True if we are binding a reference to a temporary + /// object (thereby extending its lifetime); false if we are binding to an + /// lvalue or an lvalue treated as an rvalue. + /// + /// \param UnnecessaryCopy True if we should check for a copy + /// constructor for a completely unnecessary but + void AddReferenceBindingStep(QualType T, bool BindingTemporary); + + /// \brief Add a new step that makes an extraneous copy of the input + /// to a temporary of the same class type. + /// + /// This extraneous copy only occurs during reference binding in + /// C++98/03, where we are permitted (but not required) to introduce + /// an extra copy. At a bare minimum, we must check that we could + /// call the copy constructor, and produce a diagnostic if the copy + /// constructor is inaccessible or no copy constructor matches. + // + /// \param T The type of the temporary being created. + void AddExtraneousCopyToTemporary(QualType T); + + /// \brief Add a new step invoking a conversion function, which is either + /// a constructor or a conversion function. + void AddUserConversionStep(FunctionDecl *Function, + DeclAccessPair FoundDecl, + QualType T, + bool HadMultipleCandidates); + + /// \brief Add a new step that performs a qualification conversion to the + /// given type. + void AddQualificationConversionStep(QualType Ty, + ExprValueKind Category); + + /// \brief Add a new step that applies an implicit conversion sequence. + void AddConversionSequenceStep(const ImplicitConversionSequence &ICS, + QualType T); + + /// \brief Add a list-initialization step. + void AddListInitializationStep(QualType T); + + /// \brief Add a constructor-initialization step. + /// + /// \arg FromInitList The constructor call is syntactically an initializer + /// list. + /// \arg AsInitList The constructor is called as an init list constructor. + void AddConstructorInitializationStep(CXXConstructorDecl *Constructor, + AccessSpecifier Access, + QualType T, + bool HadMultipleCandidates, + bool FromInitList, bool AsInitList); + + /// \brief Add a zero-initialization step. + void AddZeroInitializationStep(QualType T); + + /// \brief Add a C assignment step. + // + // FIXME: It isn't clear whether this should ever be needed; + // ideally, we would handle everything needed in C in the common + // path. However, that isn't the case yet. + void AddCAssignmentStep(QualType T); + + /// \brief Add a string init step. + void AddStringInitStep(QualType T); + + /// \brief Add an Objective-C object conversion step, which is + /// always a no-op. + void AddObjCObjectConversionStep(QualType T); + + /// \brief Add an array initialization step. + void AddArrayInitStep(QualType T); + + /// \brief Add a parenthesized array initialization step. + void AddParenthesizedArrayInitStep(QualType T); + + /// \brief Add a step to pass an object by indirect copy-restore. + void AddPassByIndirectCopyRestoreStep(QualType T, bool shouldCopy); + + /// \brief Add a step to "produce" an Objective-C object (by + /// retaining it). + void AddProduceObjCObjectStep(QualType T); + + /// \brief Add a step to construct a std::initializer_list object from an + /// initializer list. + void AddStdInitializerListConstructionStep(QualType T); + + /// \brief Add steps to unwrap a initializer list for a reference around a + /// single element and rewrap it at the end. + void RewrapReferenceInitList(QualType T, InitListExpr *Syntactic); + + /// \brief Note that this initialization sequence failed. + void SetFailed(FailureKind Failure) { + SequenceKind = FailedSequence; + this->Failure = Failure; + assert((Failure != FK_Incomplete || !FailedIncompleteType.isNull()) && + "Incomplete type failure requires a type!"); + } + + /// \brief Note that this initialization sequence failed due to failed + /// overload resolution. + void SetOverloadFailure(FailureKind Failure, OverloadingResult Result); + + /// \brief Retrieve a reference to the candidate set when overload + /// resolution fails. + OverloadCandidateSet &getFailedCandidateSet() { + return FailedCandidateSet; + } + + /// \brief Get the overloading result, for when the initialization + /// sequence failed due to a bad overload. + OverloadingResult getFailedOverloadResult() const { + return FailedOverloadResult; + } + + /// \brief Note that this initialization sequence failed due to an + /// incomplete type. + void setIncompleteTypeFailure(QualType IncompleteType) { + FailedIncompleteType = IncompleteType; + SetFailed(FK_Incomplete); + } + + /// \brief Determine why initialization failed. + FailureKind getFailureKind() const { + assert(Failed() && "Not an initialization failure!"); + return Failure; + } + + /// \brief Dump a representation of this initialization sequence to + /// the given stream, for debugging purposes. + void dump(raw_ostream &OS) const; + + /// \brief Dump a representation of this initialization sequence to + /// standard error, for debugging purposes. + void dump() const; +}; + +} // end namespace clang + +#endif // LLVM_CLANG_SEMA_INITIALIZATION_H diff --git a/clang/include/clang/Sema/LocInfoType.h b/clang/include/clang/Sema/LocInfoType.h new file mode 100644 index 0000000..93cb8cb --- /dev/null +++ b/clang/include/clang/Sema/LocInfoType.h @@ -0,0 +1,63 @@ +//===--- LocInfoType.h - Parsed Type with Location Information---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the LocInfoType class, which holds a type and its +// source-location information. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_SEMA_LOCINFOTYPE_H +#define LLVM_CLANG_SEMA_LOCINFOTYPE_H + +#include "clang/AST/Type.h" + +namespace clang { + +class TypeSourceInfo; + +/// \brief Holds a QualType and a TypeSourceInfo* that came out of a declarator +/// parsing. +/// +/// LocInfoType is a "transient" type, only needed for passing to/from Parser +/// and Sema, when we want to preserve type source info for a parsed type. +/// It will not participate in the type system semantics in any way. +class LocInfoType : public Type { + enum { + // The last number that can fit in Type's TC. + // Avoids conflict with an existing Type class. + LocInfo = Type::TypeLast + 1 + }; + + TypeSourceInfo *DeclInfo; + + LocInfoType(QualType ty, TypeSourceInfo *TInfo) + : Type((TypeClass)LocInfo, ty, ty->isDependentType(), + ty->isInstantiationDependentType(), + ty->isVariablyModifiedType(), + ty->containsUnexpandedParameterPack()), + DeclInfo(TInfo) { + assert(getTypeClass() == (TypeClass)LocInfo && "LocInfo didn't fit in TC?"); + } + friend class Sema; + +public: + QualType getType() const { return getCanonicalTypeInternal(); } + TypeSourceInfo *getTypeSourceInfo() const { return DeclInfo; } + + void getAsStringInternal(std::string &Str, + const PrintingPolicy &Policy) const; + + static bool classof(const Type *T) { + return T->getTypeClass() == (TypeClass)LocInfo; + } + static bool classof(const LocInfoType *) { return true; } +}; + +} // end namespace clang + +#endif // LLVM_CLANG_SEMA_LOCINFOTYPE_H diff --git a/clang/include/clang/Sema/Lookup.h b/clang/include/clang/Sema/Lookup.h new file mode 100644 index 0000000..fe5d262 --- /dev/null +++ b/clang/include/clang/Sema/Lookup.h @@ -0,0 +1,715 @@ +//===--- Lookup.h - Classes for name lookup ---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the LookupResult class, which is integral to +// Sema's name-lookup subsystem. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_LOOKUP_H +#define LLVM_CLANG_SEMA_LOOKUP_H + +#include "clang/Sema/Sema.h" +#include "clang/AST/DeclCXX.h" + +namespace clang { + +/// @brief Represents the results of name lookup. +/// +/// An instance of the LookupResult class captures the results of a +/// single name lookup, which can return no result (nothing found), +/// a single declaration, a set of overloaded functions, or an +/// ambiguity. Use the getKind() method to determine which of these +/// results occurred for a given lookup. +class LookupResult { +public: + enum LookupResultKind { + /// @brief No entity found met the criteria. + NotFound = 0, + + /// @brief No entity found met the criteria within the current + /// instantiation,, but there were dependent base classes of the + /// current instantiation that could not be searched. + NotFoundInCurrentInstantiation, + + /// @brief Name lookup found a single declaration that met the + /// criteria. getFoundDecl() will return this declaration. + Found, + + /// @brief Name lookup found a set of overloaded functions that + /// met the criteria. + FoundOverloaded, + + /// @brief Name lookup found an unresolvable value declaration + /// and cannot yet complete. This only happens in C++ dependent + /// contexts with dependent using declarations. + FoundUnresolvedValue, + + /// @brief Name lookup results in an ambiguity; use + /// getAmbiguityKind to figure out what kind of ambiguity + /// we have. + Ambiguous + }; + + enum AmbiguityKind { + /// Name lookup results in an ambiguity because multiple + /// entities that meet the lookup criteria were found in + /// subobjects of different types. For example: + /// @code + /// struct A { void f(int); } + /// struct B { void f(double); } + /// struct C : A, B { }; + /// void test(C c) { + /// c.f(0); // error: A::f and B::f come from subobjects of different + /// // types. overload resolution is not performed. + /// } + /// @endcode + AmbiguousBaseSubobjectTypes, + + /// Name lookup results in an ambiguity because multiple + /// nonstatic entities that meet the lookup criteria were found + /// in different subobjects of the same type. For example: + /// @code + /// struct A { int x; }; + /// struct B : A { }; + /// struct C : A { }; + /// struct D : B, C { }; + /// int test(D d) { + /// return d.x; // error: 'x' is found in two A subobjects (of B and C) + /// } + /// @endcode + AmbiguousBaseSubobjects, + + /// Name lookup results in an ambiguity because multiple definitions + /// of entity that meet the lookup criteria were found in different + /// declaration contexts. + /// @code + /// namespace A { + /// int i; + /// namespace B { int i; } + /// int test() { + /// using namespace B; + /// return i; // error 'i' is found in namespace A and A::B + /// } + /// } + /// @endcode + AmbiguousReference, + + /// Name lookup results in an ambiguity because an entity with a + /// tag name was hidden by an entity with an ordinary name from + /// a different context. + /// @code + /// namespace A { struct Foo {}; } + /// namespace B { void Foo(); } + /// namespace C { + /// using namespace A; + /// using namespace B; + /// } + /// void test() { + /// C::Foo(); // error: tag 'A::Foo' is hidden by an object in a + /// // different namespace + /// } + /// @endcode + AmbiguousTagHiding + }; + + /// A little identifier for flagging temporary lookup results. + enum TemporaryToken { + Temporary + }; + + typedef UnresolvedSetImpl::iterator iterator; + + LookupResult(Sema &SemaRef, const DeclarationNameInfo &NameInfo, + Sema::LookupNameKind LookupKind, + Sema::RedeclarationKind Redecl = Sema::NotForRedeclaration) + : ResultKind(NotFound), + Paths(0), + NamingClass(0), + SemaRef(SemaRef), + NameInfo(NameInfo), + LookupKind(LookupKind), + IDNS(0), + Redecl(Redecl != Sema::NotForRedeclaration), + HideTags(true), + Diagnose(Redecl == Sema::NotForRedeclaration) + { + configure(); + } + + // TODO: consider whether this constructor should be restricted to take + // as input a const IndentifierInfo* (instead of Name), + // forcing other cases towards the constructor taking a DNInfo. + LookupResult(Sema &SemaRef, DeclarationName Name, + SourceLocation NameLoc, Sema::LookupNameKind LookupKind, + Sema::RedeclarationKind Redecl = Sema::NotForRedeclaration) + : ResultKind(NotFound), + Paths(0), + NamingClass(0), + SemaRef(SemaRef), + NameInfo(Name, NameLoc), + LookupKind(LookupKind), + IDNS(0), + Redecl(Redecl != Sema::NotForRedeclaration), + HideTags(true), + Diagnose(Redecl == Sema::NotForRedeclaration) + { + configure(); + } + + /// Creates a temporary lookup result, initializing its core data + /// using the information from another result. Diagnostics are always + /// disabled. + LookupResult(TemporaryToken _, const LookupResult &Other) + : ResultKind(NotFound), + Paths(0), + NamingClass(0), + SemaRef(Other.SemaRef), + NameInfo(Other.NameInfo), + LookupKind(Other.LookupKind), + IDNS(Other.IDNS), + Redecl(Other.Redecl), + HideTags(Other.HideTags), + Diagnose(false) + {} + + ~LookupResult() { + if (Diagnose) diagnose(); + if (Paths) deletePaths(Paths); + } + + /// Gets the name info to look up. + const DeclarationNameInfo &getLookupNameInfo() const { + return NameInfo; + } + + /// \brief Sets the name info to look up. + void setLookupNameInfo(const DeclarationNameInfo &NameInfo) { + this->NameInfo = NameInfo; + } + + /// Gets the name to look up. + DeclarationName getLookupName() const { + return NameInfo.getName(); + } + + /// \brief Sets the name to look up. + void setLookupName(DeclarationName Name) { + NameInfo.setName(Name); + } + + /// Gets the kind of lookup to perform. + Sema::LookupNameKind getLookupKind() const { + return LookupKind; + } + + /// True if this lookup is just looking for an existing declaration. + bool isForRedeclaration() const { + return Redecl; + } + + /// \brief Determine whether this lookup is permitted to see hidden + /// declarations, such as those in modules that have not yet been imported. + bool isHiddenDeclarationVisible() const { + return Redecl || LookupKind == Sema::LookupTagName; + } + + /// Sets whether tag declarations should be hidden by non-tag + /// declarations during resolution. The default is true. + void setHideTags(bool Hide) { + HideTags = Hide; + } + + bool isAmbiguous() const { + return getResultKind() == Ambiguous; + } + + /// Determines if this names a single result which is not an + /// unresolved value using decl. If so, it is safe to call + /// getFoundDecl(). + bool isSingleResult() const { + return getResultKind() == Found; + } + + /// Determines if the results are overloaded. + bool isOverloadedResult() const { + return getResultKind() == FoundOverloaded; + } + + bool isUnresolvableResult() const { + return getResultKind() == FoundUnresolvedValue; + } + + LookupResultKind getResultKind() const { + sanity(); + return ResultKind; + } + + AmbiguityKind getAmbiguityKind() const { + assert(isAmbiguous()); + return Ambiguity; + } + + const UnresolvedSetImpl &asUnresolvedSet() const { + return Decls; + } + + iterator begin() const { return iterator(Decls.begin()); } + iterator end() const { return iterator(Decls.end()); } + + /// \brief Return true if no decls were found + bool empty() const { return Decls.empty(); } + + /// \brief Return the base paths structure that's associated with + /// these results, or null if none is. + CXXBasePaths *getBasePaths() const { + return Paths; + } + + /// \brief Determine whether the given declaration is visible to the + /// program. + static bool isVisible(NamedDecl *D) { + // If this declaration is not hidden, it's visible. + if (!D->isHidden()) + return true; + + // FIXME: We should be allowed to refer to a module-private name from + // within the same module, e.g., during template instantiation. + // This requires us know which module a particular declaration came from. + return false; + } + + /// \brief Retrieve the accepted (re)declaration of the given declaration, + /// if there is one. + NamedDecl *getAcceptableDecl(NamedDecl *D) const { + if (!D->isInIdentifierNamespace(IDNS)) + return 0; + + if (isHiddenDeclarationVisible() || isVisible(D)) + return D; + + return getAcceptableDeclSlow(D); + } + +private: + NamedDecl *getAcceptableDeclSlow(NamedDecl *D) const; +public: + + /// \brief Returns the identifier namespace mask for this lookup. + unsigned getIdentifierNamespace() const { + return IDNS; + } + + /// \brief Returns whether these results arose from performing a + /// lookup into a class. + bool isClassLookup() const { + return NamingClass != 0; + } + + /// \brief Returns the 'naming class' for this lookup, i.e. the + /// class which was looked into to find these results. + /// + /// C++0x [class.access.base]p5: + /// The access to a member is affected by the class in which the + /// member is named. This naming class is the class in which the + /// member name was looked up and found. [Note: this class can be + /// explicit, e.g., when a qualified-id is used, or implicit, + /// e.g., when a class member access operator (5.2.5) is used + /// (including cases where an implicit "this->" is added). If both + /// a class member access operator and a qualified-id are used to + /// name the member (as in p->T::m), the class naming the member + /// is the class named by the nested-name-specifier of the + /// qualified-id (that is, T). -- end note ] + /// + /// This is set by the lookup routines when they find results in a class. + CXXRecordDecl *getNamingClass() const { + return NamingClass; + } + + /// \brief Sets the 'naming class' for this lookup. + void setNamingClass(CXXRecordDecl *Record) { + NamingClass = Record; + } + + /// \brief Returns the base object type associated with this lookup; + /// important for [class.protected]. Most lookups do not have an + /// associated base object. + QualType getBaseObjectType() const { + return BaseObjectType; + } + + /// \brief Sets the base object type for this lookup. + void setBaseObjectType(QualType T) { + BaseObjectType = T; + } + + /// \brief Add a declaration to these results with its natural access. + /// Does not test the acceptance criteria. + void addDecl(NamedDecl *D) { + addDecl(D, D->getAccess()); + } + + /// \brief Add a declaration to these results with the given access. + /// Does not test the acceptance criteria. + void addDecl(NamedDecl *D, AccessSpecifier AS) { + Decls.addDecl(D, AS); + ResultKind = Found; + } + + /// \brief Add all the declarations from another set of lookup + /// results. + void addAllDecls(const LookupResult &Other) { + Decls.append(Other.Decls.begin(), Other.Decls.end()); + ResultKind = Found; + } + + /// \brief Determine whether no result was found because we could not + /// search into dependent base classes of the current instantiation. + bool wasNotFoundInCurrentInstantiation() const { + return ResultKind == NotFoundInCurrentInstantiation; + } + + /// \brief Note that while no result was found in the current instantiation, + /// there were dependent base classes that could not be searched. + void setNotFoundInCurrentInstantiation() { + assert(ResultKind == NotFound && Decls.empty()); + ResultKind = NotFoundInCurrentInstantiation; + } + + /// \brief Resolves the result kind of the lookup, possibly hiding + /// decls. + /// + /// This should be called in any environment where lookup might + /// generate multiple lookup results. + void resolveKind(); + + /// \brief Re-resolves the result kind of the lookup after a set of + /// removals has been performed. + void resolveKindAfterFilter() { + if (Decls.empty()) { + if (ResultKind != NotFoundInCurrentInstantiation) + ResultKind = NotFound; + + if (Paths) { + deletePaths(Paths); + Paths = 0; + } + } else { + AmbiguityKind SavedAK = Ambiguity; + ResultKind = Found; + resolveKind(); + + // If we didn't make the lookup unambiguous, restore the old + // ambiguity kind. + if (ResultKind == Ambiguous) { + Ambiguity = SavedAK; + } else if (Paths) { + deletePaths(Paths); + Paths = 0; + } + } + } + + template <class DeclClass> + DeclClass *getAsSingle() const { + if (getResultKind() != Found) return 0; + return dyn_cast<DeclClass>(getFoundDecl()); + } + + /// \brief Fetch the unique decl found by this lookup. Asserts + /// that one was found. + /// + /// This is intended for users who have examined the result kind + /// and are certain that there is only one result. + NamedDecl *getFoundDecl() const { + assert(getResultKind() == Found + && "getFoundDecl called on non-unique result"); + return (*begin())->getUnderlyingDecl(); + } + + /// Fetches a representative decl. Useful for lazy diagnostics. + NamedDecl *getRepresentativeDecl() const { + assert(!Decls.empty() && "cannot get representative of empty set"); + return *begin(); + } + + /// \brief Asks if the result is a single tag decl. + bool isSingleTagDecl() const { + return getResultKind() == Found && isa<TagDecl>(getFoundDecl()); + } + + /// \brief Make these results show that the name was found in + /// base classes of different types. + /// + /// The given paths object is copied and invalidated. + void setAmbiguousBaseSubobjectTypes(CXXBasePaths &P); + + /// \brief Make these results show that the name was found in + /// distinct base classes of the same type. + /// + /// The given paths object is copied and invalidated. + void setAmbiguousBaseSubobjects(CXXBasePaths &P); + + /// \brief Make these results show that the name was found in + /// different contexts and a tag decl was hidden by an ordinary + /// decl in a different context. + void setAmbiguousQualifiedTagHiding() { + setAmbiguous(AmbiguousTagHiding); + } + + /// \brief Clears out any current state. + void clear() { + ResultKind = NotFound; + Decls.clear(); + if (Paths) deletePaths(Paths); + Paths = NULL; + NamingClass = 0; + } + + /// \brief Clears out any current state and re-initializes for a + /// different kind of lookup. + void clear(Sema::LookupNameKind Kind) { + clear(); + LookupKind = Kind; + configure(); + } + + /// \brief Change this lookup's redeclaration kind. + void setRedeclarationKind(Sema::RedeclarationKind RK) { + Redecl = RK; + configure(); + } + + void print(raw_ostream &); + + /// Suppress the diagnostics that would normally fire because of this + /// lookup. This happens during (e.g.) redeclaration lookups. + void suppressDiagnostics() { + Diagnose = false; + } + + /// Determines whether this lookup is suppressing diagnostics. + bool isSuppressingDiagnostics() const { + return !Diagnose; + } + + /// Sets a 'context' source range. + void setContextRange(SourceRange SR) { + NameContextRange = SR; + } + + /// Gets the source range of the context of this name; for C++ + /// qualified lookups, this is the source range of the scope + /// specifier. + SourceRange getContextRange() const { + return NameContextRange; + } + + /// Gets the location of the identifier. This isn't always defined: + /// sometimes we're doing lookups on synthesized names. + SourceLocation getNameLoc() const { + return NameInfo.getLoc(); + } + + /// \brief Get the Sema object that this lookup result is searching + /// with. + Sema &getSema() const { return SemaRef; } + + /// A class for iterating through a result set and possibly + /// filtering out results. The results returned are possibly + /// sugared. + class Filter { + LookupResult &Results; + LookupResult::iterator I; + bool Changed; + bool CalledDone; + + friend class LookupResult; + Filter(LookupResult &Results) + : Results(Results), I(Results.begin()), Changed(false), CalledDone(false) + {} + + public: + ~Filter() { + assert(CalledDone && + "LookupResult::Filter destroyed without done() call"); + } + + bool hasNext() const { + return I != Results.end(); + } + + NamedDecl *next() { + assert(I != Results.end() && "next() called on empty filter"); + return *I++; + } + + /// Restart the iteration. + void restart() { + I = Results.begin(); + } + + /// Erase the last element returned from this iterator. + void erase() { + Results.Decls.erase(--I); + Changed = true; + } + + /// Replaces the current entry with the given one, preserving the + /// access bits. + void replace(NamedDecl *D) { + Results.Decls.replace(I-1, D); + Changed = true; + } + + /// Replaces the current entry with the given one. + void replace(NamedDecl *D, AccessSpecifier AS) { + Results.Decls.replace(I-1, D, AS); + Changed = true; + } + + void done() { + assert(!CalledDone && "done() called twice"); + CalledDone = true; + + if (Changed) + Results.resolveKindAfterFilter(); + } + }; + + /// Create a filter for this result set. + Filter makeFilter() { + return Filter(*this); + } + +private: + void diagnose() { + if (isAmbiguous()) + SemaRef.DiagnoseAmbiguousLookup(*this); + else if (isClassLookup() && SemaRef.getLangOpts().AccessControl) + SemaRef.CheckLookupAccess(*this); + } + + void setAmbiguous(AmbiguityKind AK) { + ResultKind = Ambiguous; + Ambiguity = AK; + } + + void addDeclsFromBasePaths(const CXXBasePaths &P); + void configure(); + + // Sanity checks. + void sanityImpl() const; + + void sanity() const { +#ifndef NDEBUG + sanityImpl(); +#endif + } + + bool sanityCheckUnresolved() const { + for (iterator I = begin(), E = end(); I != E; ++I) + if (isa<UnresolvedUsingValueDecl>(*I)) + return true; + return false; + } + + static void deletePaths(CXXBasePaths *); + + // Results. + LookupResultKind ResultKind; + AmbiguityKind Ambiguity; // ill-defined unless ambiguous + UnresolvedSet<8> Decls; + CXXBasePaths *Paths; + CXXRecordDecl *NamingClass; + QualType BaseObjectType; + + // Parameters. + Sema &SemaRef; + DeclarationNameInfo NameInfo; + SourceRange NameContextRange; + Sema::LookupNameKind LookupKind; + unsigned IDNS; // set by configure() + + bool Redecl; + + /// \brief True if tag declarations should be hidden if non-tags + /// are present + bool HideTags; + + bool Diagnose; +}; + + /// \brief Consumes visible declarations found when searching for + /// all visible names within a given scope or context. + /// + /// This abstract class is meant to be subclassed by clients of \c + /// Sema::LookupVisibleDecls(), each of which should override the \c + /// FoundDecl() function to process declarations as they are found. + class VisibleDeclConsumer { + public: + /// \brief Destroys the visible declaration consumer. + virtual ~VisibleDeclConsumer(); + + /// \brief Invoked each time \p Sema::LookupVisibleDecls() finds a + /// declaration visible from the current scope or context. + /// + /// \param ND the declaration found. + /// + /// \param Hiding a declaration that hides the declaration \p ND, + /// or NULL if no such declaration exists. + /// + /// \param Ctx the original context from which the lookup started. + /// + /// \param InBaseClass whether this declaration was found in base + /// class of the context we searched. + virtual void FoundDecl(NamedDecl *ND, NamedDecl *Hiding, DeclContext *Ctx, + bool InBaseClass) = 0; + }; + +/// \brief A class for storing results from argument-dependent lookup. +class ADLResult { +private: + /// A map from canonical decls to the 'most recent' decl. + llvm::DenseMap<NamedDecl*, NamedDecl*> Decls; + +public: + /// Adds a new ADL candidate to this map. + void insert(NamedDecl *D); + + /// Removes any data associated with a given decl. + void erase(NamedDecl *D) { + Decls.erase(cast<NamedDecl>(D->getCanonicalDecl())); + } + + class iterator { + typedef llvm::DenseMap<NamedDecl*,NamedDecl*>::iterator inner_iterator; + inner_iterator iter; + + friend class ADLResult; + iterator(const inner_iterator &iter) : iter(iter) {} + public: + iterator() {} + + iterator &operator++() { ++iter; return *this; } + iterator operator++(int) { return iterator(iter++); } + + NamedDecl *operator*() const { return iter->second; } + + bool operator==(const iterator &other) const { return iter == other.iter; } + bool operator!=(const iterator &other) const { return iter != other.iter; } + }; + + iterator begin() { return iterator(Decls.begin()); } + iterator end() { return iterator(Decls.end()); } +}; + +} + +#endif diff --git a/clang/include/clang/Sema/Makefile b/clang/include/clang/Sema/Makefile new file mode 100644 index 0000000..f6662d6 --- /dev/null +++ b/clang/include/clang/Sema/Makefile @@ -0,0 +1,27 @@ +CLANG_LEVEL := ../../.. +TD_SRC_DIR = $(PROJ_SRC_DIR)/../Basic +BUILT_SOURCES = AttrTemplateInstantiate.inc AttrParsedAttrList.inc AttrParsedAttrKinds.inc + +TABLEGEN_INC_FILES_COMMON = 1 + +include $(CLANG_LEVEL)/Makefile + +$(ObjDir)/AttrTemplateInstantiate.inc.tmp : $(TD_SRC_DIR)/Attr.td \ + $(CLANG_TBLGEN) $(ObjDir)/.dir + $(Echo) "Building Clang attribute template instantiate code with tablegen" + $(Verb) $(ClangTableGen) -gen-clang-attr-template-instantiate -o \ + $(call SYSPATH, $@) -I $(PROJ_SRC_DIR)/../../ $< + +$(ObjDir)/AttrParsedAttrList.inc.tmp : $(TD_SRC_DIR)/Attr.td \ + $(CLANG_TBLGEN) $(ObjDir)/.dir + $(Echo) "Building Clang parsed attribute list with tablegen" + $(Verb) $(ClangTableGen) -gen-clang-attr-parsed-attr-list -o \ + $(call SYSPATH, $@) -I $(PROJ_SRC_DIR)/../../ $< + +$(ObjDir)/AttrParsedAttrKinds.inc.tmp : $(TD_SRC_DIR)/Attr.td \ + $(CLANG_TBLGEN) $(ObjDir)/.dir + $(Echo) "Building Clang parsed attribute kinds with tablegen" + $(Verb) $(ClangTableGen) -gen-clang-attr-parsed-attr-kinds -o \ + $(call SYSPATH, $@) -I $(PROJ_SRC_DIR)/../../ $< + + diff --git a/clang/include/clang/Sema/ObjCMethodList.h b/clang/include/clang/Sema/ObjCMethodList.h new file mode 100644 index 0000000..225c137 --- /dev/null +++ b/clang/include/clang/Sema/ObjCMethodList.h @@ -0,0 +1,38 @@ +//===--- ObjCMethodList.h - A singly linked list of methods -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines ObjCMethodList, a singly-linked list of methods. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_OBJC_METHOD_LIST_H +#define LLVM_CLANG_SEMA_OBJC_METHOD_LIST_H + +namespace clang { + +class ObjCMethodDecl; + +/// ObjCMethodList - a linked list of methods with different signatures. +struct ObjCMethodList { + ObjCMethodDecl *Method; + ObjCMethodList *Next; + + ObjCMethodList() { + Method = 0; + Next = 0; + } + ObjCMethodList(ObjCMethodDecl *M, ObjCMethodList *C) { + Method = M; + Next = C; + } +}; + +} + +#endif diff --git a/clang/include/clang/Sema/Overload.h b/clang/include/clang/Sema/Overload.h new file mode 100644 index 0000000..d334447 --- /dev/null +++ b/clang/include/clang/Sema/Overload.h @@ -0,0 +1,813 @@ +//===--- Overload.h - C++ Overloading ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the data structures and types used in C++ +// overload resolution. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_OVERLOAD_H +#define LLVM_CLANG_SEMA_OVERLOAD_H + +#include "clang/AST/Decl.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/Expr.h" +#include "clang/AST/TemplateBase.h" +#include "clang/AST/Type.h" +#include "clang/AST/UnresolvedSet.h" +#include "clang/Sema/SemaFixItUtils.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/Allocator.h" + +namespace clang { + class ASTContext; + class CXXConstructorDecl; + class CXXConversionDecl; + class FunctionDecl; + class Sema; + + /// OverloadingResult - Capture the result of performing overload + /// resolution. + enum OverloadingResult { + OR_Success, ///< Overload resolution succeeded. + OR_No_Viable_Function, ///< No viable function found. + OR_Ambiguous, ///< Ambiguous candidates found. + OR_Deleted ///< Succeeded, but refers to a deleted function. + }; + + enum OverloadCandidateDisplayKind { + /// Requests that all candidates be shown. Viable candidates will + /// be printed first. + OCD_AllCandidates, + + /// Requests that only viable candidates be shown. + OCD_ViableCandidates + }; + + /// ImplicitConversionKind - The kind of implicit conversion used to + /// convert an argument to a parameter's type. The enumerator values + /// match with Table 9 of (C++ 13.3.3.1.1) and are listed such that + /// better conversion kinds have smaller values. + enum ImplicitConversionKind { + ICK_Identity = 0, ///< Identity conversion (no conversion) + ICK_Lvalue_To_Rvalue, ///< Lvalue-to-rvalue conversion (C++ 4.1) + ICK_Array_To_Pointer, ///< Array-to-pointer conversion (C++ 4.2) + ICK_Function_To_Pointer, ///< Function-to-pointer (C++ 4.3) + ICK_NoReturn_Adjustment, ///< Removal of noreturn from a type (Clang) + ICK_Qualification, ///< Qualification conversions (C++ 4.4) + ICK_Integral_Promotion, ///< Integral promotions (C++ 4.5) + ICK_Floating_Promotion, ///< Floating point promotions (C++ 4.6) + ICK_Complex_Promotion, ///< Complex promotions (Clang extension) + ICK_Integral_Conversion, ///< Integral conversions (C++ 4.7) + ICK_Floating_Conversion, ///< Floating point conversions (C++ 4.8) + ICK_Complex_Conversion, ///< Complex conversions (C99 6.3.1.6) + ICK_Floating_Integral, ///< Floating-integral conversions (C++ 4.9) + ICK_Pointer_Conversion, ///< Pointer conversions (C++ 4.10) + ICK_Pointer_Member, ///< Pointer-to-member conversions (C++ 4.11) + ICK_Boolean_Conversion, ///< Boolean conversions (C++ 4.12) + ICK_Compatible_Conversion, ///< Conversions between compatible types in C99 + ICK_Derived_To_Base, ///< Derived-to-base (C++ [over.best.ics]) + ICK_Vector_Conversion, ///< Vector conversions + ICK_Vector_Splat, ///< A vector splat from an arithmetic type + ICK_Complex_Real, ///< Complex-real conversions (C99 6.3.1.7) + ICK_Block_Pointer_Conversion, ///< Block Pointer conversions + ICK_TransparentUnionConversion, /// Transparent Union Conversions + ICK_Writeback_Conversion, ///< Objective-C ARC writeback conversion + ICK_Num_Conversion_Kinds ///< The number of conversion kinds + }; + + /// ImplicitConversionCategory - The category of an implicit + /// conversion kind. The enumerator values match with Table 9 of + /// (C++ 13.3.3.1.1) and are listed such that better conversion + /// categories have smaller values. + enum ImplicitConversionCategory { + ICC_Identity = 0, ///< Identity + ICC_Lvalue_Transformation, ///< Lvalue transformation + ICC_Qualification_Adjustment, ///< Qualification adjustment + ICC_Promotion, ///< Promotion + ICC_Conversion ///< Conversion + }; + + ImplicitConversionCategory + GetConversionCategory(ImplicitConversionKind Kind); + + /// ImplicitConversionRank - The rank of an implicit conversion + /// kind. The enumerator values match with Table 9 of (C++ + /// 13.3.3.1.1) and are listed such that better conversion ranks + /// have smaller values. + enum ImplicitConversionRank { + ICR_Exact_Match = 0, ///< Exact Match + ICR_Promotion, ///< Promotion + ICR_Conversion, ///< Conversion + ICR_Complex_Real_Conversion, ///< Complex <-> Real conversion + ICR_Writeback_Conversion ///< ObjC ARC writeback conversion + }; + + ImplicitConversionRank GetConversionRank(ImplicitConversionKind Kind); + + /// NarrowingKind - The kind of narrowing conversion being performed by a + /// standard conversion sequence according to C++11 [dcl.init.list]p7. + enum NarrowingKind { + /// Not a narrowing conversion. + NK_Not_Narrowing, + + /// A narrowing conversion by virtue of the source and destination types. + NK_Type_Narrowing, + + /// A narrowing conversion, because a constant expression got narrowed. + NK_Constant_Narrowing, + + /// A narrowing conversion, because a non-constant-expression variable might + /// have got narrowed. + NK_Variable_Narrowing + }; + + /// StandardConversionSequence - represents a standard conversion + /// sequence (C++ 13.3.3.1.1). A standard conversion sequence + /// contains between zero and three conversions. If a particular + /// conversion is not needed, it will be set to the identity conversion + /// (ICK_Identity). Note that the three conversions are + /// specified as separate members (rather than in an array) so that + /// we can keep the size of a standard conversion sequence to a + /// single word. + class StandardConversionSequence { + public: + /// First -- The first conversion can be an lvalue-to-rvalue + /// conversion, array-to-pointer conversion, or + /// function-to-pointer conversion. + ImplicitConversionKind First : 8; + + /// Second - The second conversion can be an integral promotion, + /// floating point promotion, integral conversion, floating point + /// conversion, floating-integral conversion, pointer conversion, + /// pointer-to-member conversion, or boolean conversion. + ImplicitConversionKind Second : 8; + + /// Third - The third conversion can be a qualification conversion. + ImplicitConversionKind Third : 8; + + /// \brief Whether this is the deprecated conversion of a + /// string literal to a pointer to non-const character data + /// (C++ 4.2p2). + unsigned DeprecatedStringLiteralToCharPtr : 1; + + /// \brief Whether the qualification conversion involves a change in the + /// Objective-C lifetime (for automatic reference counting). + unsigned QualificationIncludesObjCLifetime : 1; + + /// IncompatibleObjC - Whether this is an Objective-C conversion + /// that we should warn about (if we actually use it). + unsigned IncompatibleObjC : 1; + + /// ReferenceBinding - True when this is a reference binding + /// (C++ [over.ics.ref]). + unsigned ReferenceBinding : 1; + + /// DirectBinding - True when this is a reference binding that is a + /// direct binding (C++ [dcl.init.ref]). + unsigned DirectBinding : 1; + + /// \brief Whether this is an lvalue reference binding (otherwise, it's + /// an rvalue reference binding). + unsigned IsLvalueReference : 1; + + /// \brief Whether we're binding to a function lvalue. + unsigned BindsToFunctionLvalue : 1; + + /// \brief Whether we're binding to an rvalue. + unsigned BindsToRvalue : 1; + + /// \brief Whether this binds an implicit object argument to a + /// non-static member function without a ref-qualifier. + unsigned BindsImplicitObjectArgumentWithoutRefQualifier : 1; + + /// \brief Whether this binds a reference to an object with a different + /// Objective-C lifetime qualifier. + unsigned ObjCLifetimeConversionBinding : 1; + + /// FromType - The type that this conversion is converting + /// from. This is an opaque pointer that can be translated into a + /// QualType. + void *FromTypePtr; + + /// ToType - The types that this conversion is converting to in + /// each step. This is an opaque pointer that can be translated + /// into a QualType. + void *ToTypePtrs[3]; + + /// CopyConstructor - The copy constructor that is used to perform + /// this conversion, when the conversion is actually just the + /// initialization of an object via copy constructor. Such + /// conversions are either identity conversions or derived-to-base + /// conversions. + CXXConstructorDecl *CopyConstructor; + + void setFromType(QualType T) { FromTypePtr = T.getAsOpaquePtr(); } + void setToType(unsigned Idx, QualType T) { + assert(Idx < 3 && "To type index is out of range"); + ToTypePtrs[Idx] = T.getAsOpaquePtr(); + } + void setAllToTypes(QualType T) { + ToTypePtrs[0] = T.getAsOpaquePtr(); + ToTypePtrs[1] = ToTypePtrs[0]; + ToTypePtrs[2] = ToTypePtrs[0]; + } + + QualType getFromType() const { + return QualType::getFromOpaquePtr(FromTypePtr); + } + QualType getToType(unsigned Idx) const { + assert(Idx < 3 && "To type index is out of range"); + return QualType::getFromOpaquePtr(ToTypePtrs[Idx]); + } + + void setAsIdentityConversion(); + + bool isIdentityConversion() const { + return Second == ICK_Identity && Third == ICK_Identity; + } + + ImplicitConversionRank getRank() const; + NarrowingKind getNarrowingKind(ASTContext &Context, const Expr *Converted, + APValue &ConstantValue, + QualType &ConstantType) const; + bool isPointerConversionToBool() const; + bool isPointerConversionToVoidPointer(ASTContext& Context) const; + void DebugPrint() const; + }; + + /// UserDefinedConversionSequence - Represents a user-defined + /// conversion sequence (C++ 13.3.3.1.2). + struct UserDefinedConversionSequence { + /// \brief Represents the standard conversion that occurs before + /// the actual user-defined conversion. + /// + /// C++11 13.3.3.1.2p1: + /// If the user-defined conversion is specified by a constructor + /// (12.3.1), the initial standard conversion sequence converts + /// the source type to the type required by the argument of the + /// constructor. If the user-defined conversion is specified by + /// a conversion function (12.3.2), the initial standard + /// conversion sequence converts the source type to the implicit + /// object parameter of the conversion function. + StandardConversionSequence Before; + + /// EllipsisConversion - When this is true, it means user-defined + /// conversion sequence starts with a ... (elipsis) conversion, instead of + /// a standard conversion. In this case, 'Before' field must be ignored. + // FIXME. I much rather put this as the first field. But there seems to be + // a gcc code gen. bug which causes a crash in a test. Putting it here seems + // to work around the crash. + bool EllipsisConversion : 1; + + /// HadMultipleCandidates - When this is true, it means that the + /// conversion function was resolved from an overloaded set having + /// size greater than 1. + bool HadMultipleCandidates : 1; + + /// After - Represents the standard conversion that occurs after + /// the actual user-defined conversion. + StandardConversionSequence After; + + /// ConversionFunction - The function that will perform the + /// user-defined conversion. Null if the conversion is an + /// aggregate initialization from an initializer list. + FunctionDecl* ConversionFunction; + + /// \brief The declaration that we found via name lookup, which might be + /// the same as \c ConversionFunction or it might be a using declaration + /// that refers to \c ConversionFunction. + DeclAccessPair FoundConversionFunction; + + void DebugPrint() const; + }; + + /// Represents an ambiguous user-defined conversion sequence. + struct AmbiguousConversionSequence { + typedef SmallVector<FunctionDecl*, 4> ConversionSet; + + void *FromTypePtr; + void *ToTypePtr; + char Buffer[sizeof(ConversionSet)]; + + QualType getFromType() const { + return QualType::getFromOpaquePtr(FromTypePtr); + } + QualType getToType() const { + return QualType::getFromOpaquePtr(ToTypePtr); + } + void setFromType(QualType T) { FromTypePtr = T.getAsOpaquePtr(); } + void setToType(QualType T) { ToTypePtr = T.getAsOpaquePtr(); } + + ConversionSet &conversions() { + return *reinterpret_cast<ConversionSet*>(Buffer); + } + + const ConversionSet &conversions() const { + return *reinterpret_cast<const ConversionSet*>(Buffer); + } + + void addConversion(FunctionDecl *D) { + conversions().push_back(D); + } + + typedef ConversionSet::iterator iterator; + iterator begin() { return conversions().begin(); } + iterator end() { return conversions().end(); } + + typedef ConversionSet::const_iterator const_iterator; + const_iterator begin() const { return conversions().begin(); } + const_iterator end() const { return conversions().end(); } + + void construct(); + void destruct(); + void copyFrom(const AmbiguousConversionSequence &); + }; + + /// BadConversionSequence - Records information about an invalid + /// conversion sequence. + struct BadConversionSequence { + enum FailureKind { + no_conversion, + unrelated_class, + suppressed_user, + bad_qualifiers, + lvalue_ref_to_rvalue, + rvalue_ref_to_lvalue + }; + + // This can be null, e.g. for implicit object arguments. + Expr *FromExpr; + + FailureKind Kind; + + private: + // The type we're converting from (an opaque QualType). + void *FromTy; + + // The type we're converting to (an opaque QualType). + void *ToTy; + + public: + void init(FailureKind K, Expr *From, QualType To) { + init(K, From->getType(), To); + FromExpr = From; + } + void init(FailureKind K, QualType From, QualType To) { + Kind = K; + FromExpr = 0; + setFromType(From); + setToType(To); + } + + QualType getFromType() const { return QualType::getFromOpaquePtr(FromTy); } + QualType getToType() const { return QualType::getFromOpaquePtr(ToTy); } + + void setFromExpr(Expr *E) { + FromExpr = E; + setFromType(E->getType()); + } + void setFromType(QualType T) { FromTy = T.getAsOpaquePtr(); } + void setToType(QualType T) { ToTy = T.getAsOpaquePtr(); } + }; + + /// ImplicitConversionSequence - Represents an implicit conversion + /// sequence, which may be a standard conversion sequence + /// (C++ 13.3.3.1.1), user-defined conversion sequence (C++ 13.3.3.1.2), + /// or an ellipsis conversion sequence (C++ 13.3.3.1.3). + class ImplicitConversionSequence { + public: + /// Kind - The kind of implicit conversion sequence. BadConversion + /// specifies that there is no conversion from the source type to + /// the target type. AmbiguousConversion represents the unique + /// ambiguous conversion (C++0x [over.best.ics]p10). + enum Kind { + StandardConversion = 0, + UserDefinedConversion, + AmbiguousConversion, + EllipsisConversion, + BadConversion + }; + + private: + enum { + Uninitialized = BadConversion + 1 + }; + + /// ConversionKind - The kind of implicit conversion sequence. + unsigned ConversionKind : 30; + + /// \brief Whether the argument is an initializer list. + bool ListInitializationSequence : 1; + + /// \brief Whether the target is really a std::initializer_list, and the + /// sequence only represents the worst element conversion. + bool StdInitializerListElement : 1; + + void setKind(Kind K) { + destruct(); + ConversionKind = K; + } + + void destruct() { + if (ConversionKind == AmbiguousConversion) Ambiguous.destruct(); + } + + public: + union { + /// When ConversionKind == StandardConversion, provides the + /// details of the standard conversion sequence. + StandardConversionSequence Standard; + + /// When ConversionKind == UserDefinedConversion, provides the + /// details of the user-defined conversion sequence. + UserDefinedConversionSequence UserDefined; + + /// When ConversionKind == AmbiguousConversion, provides the + /// details of the ambiguous conversion. + AmbiguousConversionSequence Ambiguous; + + /// When ConversionKind == BadConversion, provides the details + /// of the bad conversion. + BadConversionSequence Bad; + }; + + ImplicitConversionSequence() + : ConversionKind(Uninitialized), ListInitializationSequence(false), + StdInitializerListElement(false) + {} + ~ImplicitConversionSequence() { + destruct(); + } + ImplicitConversionSequence(const ImplicitConversionSequence &Other) + : ConversionKind(Other.ConversionKind), + ListInitializationSequence(Other.ListInitializationSequence), + StdInitializerListElement(Other.StdInitializerListElement) + { + switch (ConversionKind) { + case Uninitialized: break; + case StandardConversion: Standard = Other.Standard; break; + case UserDefinedConversion: UserDefined = Other.UserDefined; break; + case AmbiguousConversion: Ambiguous.copyFrom(Other.Ambiguous); break; + case EllipsisConversion: break; + case BadConversion: Bad = Other.Bad; break; + } + } + + ImplicitConversionSequence & + operator=(const ImplicitConversionSequence &Other) { + destruct(); + new (this) ImplicitConversionSequence(Other); + return *this; + } + + Kind getKind() const { + assert(isInitialized() && "querying uninitialized conversion"); + return Kind(ConversionKind); + } + + /// \brief Return a ranking of the implicit conversion sequence + /// kind, where smaller ranks represent better conversion + /// sequences. + /// + /// In particular, this routine gives user-defined conversion + /// sequences and ambiguous conversion sequences the same rank, + /// per C++ [over.best.ics]p10. + unsigned getKindRank() const { + switch (getKind()) { + case StandardConversion: + return 0; + + case UserDefinedConversion: + case AmbiguousConversion: + return 1; + + case EllipsisConversion: + return 2; + + case BadConversion: + return 3; + } + + llvm_unreachable("Invalid ImplicitConversionSequence::Kind!"); + } + + bool isBad() const { return getKind() == BadConversion; } + bool isStandard() const { return getKind() == StandardConversion; } + bool isEllipsis() const { return getKind() == EllipsisConversion; } + bool isAmbiguous() const { return getKind() == AmbiguousConversion; } + bool isUserDefined() const { return getKind() == UserDefinedConversion; } + bool isFailure() const { return isBad() || isAmbiguous(); } + + /// Determines whether this conversion sequence has been + /// initialized. Most operations should never need to query + /// uninitialized conversions and should assert as above. + bool isInitialized() const { return ConversionKind != Uninitialized; } + + /// Sets this sequence as a bad conversion for an explicit argument. + void setBad(BadConversionSequence::FailureKind Failure, + Expr *FromExpr, QualType ToType) { + setKind(BadConversion); + Bad.init(Failure, FromExpr, ToType); + } + + /// Sets this sequence as a bad conversion for an implicit argument. + void setBad(BadConversionSequence::FailureKind Failure, + QualType FromType, QualType ToType) { + setKind(BadConversion); + Bad.init(Failure, FromType, ToType); + } + + void setStandard() { setKind(StandardConversion); } + void setEllipsis() { setKind(EllipsisConversion); } + void setUserDefined() { setKind(UserDefinedConversion); } + void setAmbiguous() { + if (ConversionKind == AmbiguousConversion) return; + ConversionKind = AmbiguousConversion; + Ambiguous.construct(); + } + + /// \brief Whether this sequence was created by the rules of + /// list-initialization sequences. + bool isListInitializationSequence() const { + return ListInitializationSequence; + } + + void setListInitializationSequence() { + ListInitializationSequence = true; + } + + /// \brief Whether the target is really a std::initializer_list, and the + /// sequence only represents the worst element conversion. + bool isStdInitializerListElement() const { + return StdInitializerListElement; + } + + void setStdInitializerListElement(bool V = true) { + StdInitializerListElement = V; + } + + // The result of a comparison between implicit conversion + // sequences. Use Sema::CompareImplicitConversionSequences to + // actually perform the comparison. + enum CompareKind { + Better = -1, + Indistinguishable = 0, + Worse = 1 + }; + + void DiagnoseAmbiguousConversion(Sema &S, + SourceLocation CaretLoc, + const PartialDiagnostic &PDiag) const; + + void DebugPrint() const; + }; + + enum OverloadFailureKind { + ovl_fail_too_many_arguments, + ovl_fail_too_few_arguments, + ovl_fail_bad_conversion, + ovl_fail_bad_deduction, + + /// This conversion candidate was not considered because it + /// duplicates the work of a trivial or derived-to-base + /// conversion. + ovl_fail_trivial_conversion, + + /// This conversion candidate is not viable because its result + /// type is not implicitly convertible to the desired type. + ovl_fail_bad_final_conversion, + + /// This conversion function template specialization candidate is not + /// viable because the final conversion was not an exact match. + ovl_fail_final_conversion_not_exact, + + /// (CUDA) This candidate was not viable because the callee + /// was not accessible from the caller's target (i.e. host->device, + /// global->host, device->host). + ovl_fail_bad_target + }; + + /// OverloadCandidate - A single candidate in an overload set (C++ 13.3). + struct OverloadCandidate { + /// Function - The actual function that this candidate + /// represents. When NULL, this is a built-in candidate + /// (C++ [over.oper]) or a surrogate for a conversion to a + /// function pointer or reference (C++ [over.call.object]). + FunctionDecl *Function; + + /// FoundDecl - The original declaration that was looked up / + /// invented / otherwise found, together with its access. + /// Might be a UsingShadowDecl or a FunctionTemplateDecl. + DeclAccessPair FoundDecl; + + // BuiltinTypes - Provides the return and parameter types of a + // built-in overload candidate. Only valid when Function is NULL. + struct { + QualType ResultTy; + QualType ParamTypes[3]; + } BuiltinTypes; + + /// Surrogate - The conversion function for which this candidate + /// is a surrogate, but only if IsSurrogate is true. + CXXConversionDecl *Surrogate; + + /// Conversions - The conversion sequences used to convert the + /// function arguments to the function parameters, the pointer points to a + /// fixed size array with NumConversions elements. The memory is owned by + /// the OverloadCandidateSet. + ImplicitConversionSequence *Conversions; + + /// The FixIt hints which can be used to fix the Bad candidate. + ConversionFixItGenerator Fix; + + /// NumConversions - The number of elements in the Conversions array. + unsigned NumConversions; + + /// Viable - True to indicate that this overload candidate is viable. + bool Viable; + + /// IsSurrogate - True to indicate that this candidate is a + /// surrogate for a conversion to a function pointer or reference + /// (C++ [over.call.object]). + bool IsSurrogate; + + /// IgnoreObjectArgument - True to indicate that the first + /// argument's conversion, which for this function represents the + /// implicit object argument, should be ignored. This will be true + /// when the candidate is a static member function (where the + /// implicit object argument is just a placeholder) or a + /// non-static member function when the call doesn't have an + /// object argument. + bool IgnoreObjectArgument; + + /// FailureKind - The reason why this candidate is not viable. + /// Actually an OverloadFailureKind. + unsigned char FailureKind; + + /// \brief The number of call arguments that were explicitly provided, + /// to be used while performing partial ordering of function templates. + unsigned ExplicitCallArguments; + + /// A structure used to record information about a failed + /// template argument deduction. + struct DeductionFailureInfo { + // A Sema::TemplateDeductionResult. + unsigned Result; + + /// \brief Opaque pointer containing additional data about + /// this deduction failure. + void *Data; + + /// \brief Retrieve the template parameter this deduction failure + /// refers to, if any. + TemplateParameter getTemplateParameter(); + + /// \brief Retrieve the template argument list associated with this + /// deduction failure, if any. + TemplateArgumentList *getTemplateArgumentList(); + + /// \brief Return the first template argument this deduction failure + /// refers to, if any. + const TemplateArgument *getFirstArg(); + + /// \brief Return the second template argument this deduction failure + /// refers to, if any. + const TemplateArgument *getSecondArg(); + + /// \brief Free any memory associated with this deduction failure. + void Destroy(); + }; + + union { + DeductionFailureInfo DeductionFailure; + + /// FinalConversion - For a conversion function (where Function is + /// a CXXConversionDecl), the standard conversion that occurs + /// after the call to the overload candidate to convert the result + /// of calling the conversion function to the required type. + StandardConversionSequence FinalConversion; + }; + + /// hasAmbiguousConversion - Returns whether this overload + /// candidate requires an ambiguous conversion or not. + bool hasAmbiguousConversion() const { + for (unsigned i = 0, e = NumConversions; i != e; ++i) { + if (!Conversions[i].isInitialized()) return false; + if (Conversions[i].isAmbiguous()) return true; + } + return false; + } + + bool TryToFixBadConversion(unsigned Idx, Sema &S) { + bool CanFix = Fix.tryToFixConversion( + Conversions[Idx].Bad.FromExpr, + Conversions[Idx].Bad.getFromType(), + Conversions[Idx].Bad.getToType(), S); + + // If at least one conversion fails, the candidate cannot be fixed. + if (!CanFix) + Fix.clear(); + + return CanFix; + } + }; + + /// OverloadCandidateSet - A set of overload candidates, used in C++ + /// overload resolution (C++ 13.3). + class OverloadCandidateSet { + SmallVector<OverloadCandidate, 16> Candidates; + llvm::SmallPtrSet<Decl *, 16> Functions; + + // Allocator for OverloadCandidate::Conversions. We store the first few + // elements inline to avoid allocation for small sets. + llvm::BumpPtrAllocator ConversionSequenceAllocator; + + SourceLocation Loc; + + unsigned NumInlineSequences; + char InlineSpace[16 * sizeof(ImplicitConversionSequence)]; + + OverloadCandidateSet(const OverloadCandidateSet &); + OverloadCandidateSet &operator=(const OverloadCandidateSet &); + + public: + OverloadCandidateSet(SourceLocation Loc) : Loc(Loc), NumInlineSequences(0){} + ~OverloadCandidateSet() { + for (iterator i = begin(), e = end(); i != e; ++i) + for (unsigned ii = 0, ie = i->NumConversions; ii != ie; ++ii) + i->Conversions[ii].~ImplicitConversionSequence(); + } + + SourceLocation getLocation() const { return Loc; } + + /// \brief Determine when this overload candidate will be new to the + /// overload set. + bool isNewCandidate(Decl *F) { + return Functions.insert(F->getCanonicalDecl()); + } + + /// \brief Clear out all of the candidates. + void clear(); + + typedef SmallVector<OverloadCandidate, 16>::iterator iterator; + iterator begin() { return Candidates.begin(); } + iterator end() { return Candidates.end(); } + + size_t size() const { return Candidates.size(); } + bool empty() const { return Candidates.empty(); } + + /// \brief Add a new candidate with NumConversions conversion sequence slots + /// to the overload set. + OverloadCandidate &addCandidate(unsigned NumConversions = 0) { + Candidates.push_back(OverloadCandidate()); + OverloadCandidate &C = Candidates.back(); + + // Assign space from the inline array if there are enough free slots + // available. + if (NumConversions + NumInlineSequences <= 16) { + ImplicitConversionSequence *I = + (ImplicitConversionSequence*)InlineSpace; + C.Conversions = &I[NumInlineSequences]; + NumInlineSequences += NumConversions; + } else { + // Otherwise get memory from the allocator. + C.Conversions = ConversionSequenceAllocator + .Allocate<ImplicitConversionSequence>(NumConversions); + } + + // Construct the new objects. + for (unsigned i = 0; i != NumConversions; ++i) + new (&C.Conversions[i]) ImplicitConversionSequence(); + + C.NumConversions = NumConversions; + return C; + } + + /// Find the best viable function on this overload set, if it exists. + OverloadingResult BestViableFunction(Sema &S, SourceLocation Loc, + OverloadCandidateSet::iterator& Best, + bool UserDefinedConversion = false); + + void NoteCandidates(Sema &S, + OverloadCandidateDisplayKind OCD, + llvm::ArrayRef<Expr *> Args, + const char *Opc = 0, + SourceLocation Loc = SourceLocation()); + }; + + bool isBetterOverloadCandidate(Sema &S, + const OverloadCandidate& Cand1, + const OverloadCandidate& Cand2, + SourceLocation Loc, + bool UserDefinedConversion = false); +} // end namespace clang + +#endif // LLVM_CLANG_SEMA_OVERLOAD_H diff --git a/clang/include/clang/Sema/Ownership.h b/clang/include/clang/Sema/Ownership.h new file mode 100644 index 0000000..fb9e368 --- /dev/null +++ b/clang/include/clang/Sema/Ownership.h @@ -0,0 +1,469 @@ +//===--- Ownership.h - Parser ownership helpers -----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains classes for managing ownership of Stmt and Expr nodes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_OWNERSHIP_H +#define LLVM_CLANG_SEMA_OWNERSHIP_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/PointerIntPair.h" + +//===----------------------------------------------------------------------===// +// OpaquePtr +//===----------------------------------------------------------------------===// + +namespace clang { + class Attr; + class CXXCtorInitializer; + class CXXBaseSpecifier; + class Decl; + class DeclGroupRef; + class Expr; + class NestedNameSpecifier; + class QualType; + class Sema; + class Stmt; + class TemplateName; + class TemplateParameterList; + + /// OpaquePtr - This is a very simple POD type that wraps a pointer that the + /// Parser doesn't know about but that Sema or another client does. The UID + /// template argument is used to make sure that "Decl" pointers are not + /// compatible with "Type" pointers for example. + template <class PtrTy> + class OpaquePtr { + void *Ptr; + explicit OpaquePtr(void *Ptr) : Ptr(Ptr) {} + + typedef llvm::PointerLikeTypeTraits<PtrTy> Traits; + + public: + OpaquePtr() : Ptr(0) {} + + static OpaquePtr make(PtrTy P) { OpaquePtr OP; OP.set(P); return OP; } + + template <typename T> T* getAs() const { + return get(); + } + + template <typename T> T getAsVal() const { + return get(); + } + + PtrTy get() const { + return Traits::getFromVoidPointer(Ptr); + } + + void set(PtrTy P) { + Ptr = Traits::getAsVoidPointer(P); + } + + operator bool() const { return Ptr != 0; } + + void *getAsOpaquePtr() const { return Ptr; } + static OpaquePtr getFromOpaquePtr(void *P) { return OpaquePtr(P); } + }; + + /// UnionOpaquePtr - A version of OpaquePtr suitable for membership + /// in a union. + template <class T> struct UnionOpaquePtr { + void *Ptr; + + static UnionOpaquePtr make(OpaquePtr<T> P) { + UnionOpaquePtr OP = { P.getAsOpaquePtr() }; + return OP; + } + + OpaquePtr<T> get() const { return OpaquePtr<T>::getFromOpaquePtr(Ptr); } + operator OpaquePtr<T>() const { return get(); } + + UnionOpaquePtr &operator=(OpaquePtr<T> P) { + Ptr = P.getAsOpaquePtr(); + return *this; + } + }; +} + +namespace llvm { + template <class T> + class PointerLikeTypeTraits<clang::OpaquePtr<T> > { + public: + static inline void *getAsVoidPointer(clang::OpaquePtr<T> P) { + // FIXME: Doesn't work? return P.getAs< void >(); + return P.getAsOpaquePtr(); + } + static inline clang::OpaquePtr<T> getFromVoidPointer(void *P) { + return clang::OpaquePtr<T>::getFromOpaquePtr(P); + } + enum { NumLowBitsAvailable = 0 }; + }; + + template <class T> + struct isPodLike<clang::OpaquePtr<T> > { static const bool value = true; }; +} + + + +// -------------------------- About Move Emulation -------------------------- // +// The smart pointer classes in this file attempt to emulate move semantics +// as they appear in C++0x with rvalue references. Since C++03 doesn't have +// rvalue references, some tricks are needed to get similar results. +// Move semantics in C++0x have the following properties: +// 1) "Moving" means transferring the value of an object to another object, +// similar to copying, but without caring what happens to the old object. +// In particular, this means that the new object can steal the old object's +// resources instead of creating a copy. +// 2) Since moving can modify the source object, it must either be explicitly +// requested by the user, or the modifications must be unnoticeable. +// 3) As such, C++0x moving is only allowed in three contexts: +// * By explicitly using std::move() to request it. +// * From a temporary object, since that object cannot be accessed +// afterwards anyway, thus making the state unobservable. +// * On function return, since the object is not observable afterwards. +// +// To sum up: moving from a named object should only be possible with an +// explicit std::move(), or on function return. Moving from a temporary should +// be implicitly done. Moving from a const object is forbidden. +// +// The emulation is not perfect, and has the following shortcomings: +// * move() is not in namespace std. +// * move() is required on function return. +// * There are difficulties with implicit conversions. +// * Microsoft's compiler must be given the /Za switch to successfully compile. +// +// -------------------------- Implementation -------------------------------- // +// The move emulation relies on the peculiar reference binding semantics of +// C++03: as a rule, a non-const reference may not bind to a temporary object, +// except for the implicit object parameter in a member function call, which +// can refer to a temporary even when not being const. +// The moveable object has five important functions to facilitate moving: +// * A private, unimplemented constructor taking a non-const reference to its +// own class. This constructor serves a two-fold purpose. +// - It prevents the creation of a copy constructor that takes a const +// reference. Temporaries would be able to bind to the argument of such a +// constructor, and that would be bad. +// - Named objects will bind to the non-const reference, but since it's +// private, this will fail to compile. This prevents implicit moving from +// named objects. +// There's also a copy assignment operator for the same purpose. +// * An implicit, non-const conversion operator to a special mover type. This +// type represents the rvalue reference of C++0x. Being a non-const member, +// its implicit this parameter can bind to temporaries. +// * A constructor that takes an object of this mover type. This constructor +// performs the actual move operation. There is an equivalent assignment +// operator. +// There is also a free move() function that takes a non-const reference to +// an object and returns a temporary. Internally, this function uses explicit +// constructor calls to move the value from the referenced object to the return +// value. +// +// There are now three possible scenarios of use. +// * Copying from a const object. Constructor overload resolution will find the +// non-const copy constructor, and the move constructor. The first is not +// viable because the const object cannot be bound to the non-const reference. +// The second fails because the conversion to the mover object is non-const. +// Moving from a const object fails as intended. +// * Copying from a named object. Constructor overload resolution will select +// the non-const copy constructor, but fail as intended, because this +// constructor is private. +// * Copying from a temporary. Constructor overload resolution cannot select +// the non-const copy constructor, because the temporary cannot be bound to +// the non-const reference. It thus selects the move constructor. The +// temporary can be bound to the implicit this parameter of the conversion +// operator, because of the special binding rule. Construction succeeds. +// Note that the Microsoft compiler, as an extension, allows binding +// temporaries against non-const references. The compiler thus selects the +// non-const copy constructor and fails, because the constructor is private. +// Passing /Za (disable extensions) disables this behaviour. +// The free move() function is used to move from a named object. +// +// Note that when passing an object of a different type (the classes below +// have OwningResult and OwningPtr, which should be mixable), you get a problem. +// Argument passing and function return use copy initialization rules. The +// effect of this is that, when the source object is not already of the target +// type, the compiler will first seek a way to convert the source object to the +// target type, and only then attempt to copy the resulting object. This means +// that when passing an OwningResult where an OwningPtr is expected, the +// compiler will first seek a conversion from OwningResult to OwningPtr, then +// copy the OwningPtr. The resulting conversion sequence is: +// OwningResult object -> ResultMover -> OwningResult argument to +// OwningPtr(OwningResult) -> OwningPtr -> PtrMover -> final OwningPtr +// This conversion sequence is too complex to be allowed. Thus the special +// move_* functions, which help the compiler out with some explicit +// conversions. + +namespace clang { + // Basic + class DiagnosticBuilder; + + // Determines whether the low bit of the result pointer for the + // given UID is always zero. If so, ActionResult will use that bit + // for it's "invalid" flag. + template<class Ptr> + struct IsResultPtrLowBitFree { + static const bool value = false; + }; + + /// ActionResult - This structure is used while parsing/acting on + /// expressions, stmts, etc. It encapsulates both the object returned by + /// the action, plus a sense of whether or not it is valid. + /// When CompressInvalid is true, the "invalid" flag will be + /// stored in the low bit of the Val pointer. + template<class PtrTy, + bool CompressInvalid = IsResultPtrLowBitFree<PtrTy>::value> + class ActionResult { + PtrTy Val; + bool Invalid; + + public: + ActionResult(bool Invalid = false) + : Val(PtrTy()), Invalid(Invalid) {} + ActionResult(PtrTy val) : Val(val), Invalid(false) {} + ActionResult(const DiagnosticBuilder &) : Val(PtrTy()), Invalid(true) {} + + // These two overloads prevent void* -> bool conversions. + ActionResult(const void *); + ActionResult(volatile void *); + + bool isInvalid() const { return Invalid; } + bool isUsable() const { return !Invalid && Val; } + + PtrTy get() const { return Val; } + PtrTy release() const { return Val; } + PtrTy take() const { return Val; } + template <typename T> T *takeAs() { return static_cast<T*>(get()); } + + void set(PtrTy V) { Val = V; } + + const ActionResult &operator=(PtrTy RHS) { + Val = RHS; + Invalid = false; + return *this; + } + }; + + // This ActionResult partial specialization places the "invalid" + // flag into the low bit of the pointer. + template<typename PtrTy> + class ActionResult<PtrTy, true> { + // A pointer whose low bit is 1 if this result is invalid, 0 + // otherwise. + uintptr_t PtrWithInvalid; + typedef llvm::PointerLikeTypeTraits<PtrTy> PtrTraits; + public: + ActionResult(bool Invalid = false) + : PtrWithInvalid(static_cast<uintptr_t>(Invalid)) { } + + ActionResult(PtrTy V) { + void *VP = PtrTraits::getAsVoidPointer(V); + PtrWithInvalid = reinterpret_cast<uintptr_t>(VP); + assert((PtrWithInvalid & 0x01) == 0 && "Badly aligned pointer"); + } + ActionResult(const DiagnosticBuilder &) : PtrWithInvalid(0x01) { } + + // These two overloads prevent void* -> bool conversions. + ActionResult(const void *); + ActionResult(volatile void *); + + bool isInvalid() const { return PtrWithInvalid & 0x01; } + bool isUsable() const { return PtrWithInvalid > 0x01; } + + PtrTy get() const { + void *VP = reinterpret_cast<void *>(PtrWithInvalid & ~0x01); + return PtrTraits::getFromVoidPointer(VP); + } + PtrTy take() const { return get(); } + PtrTy release() const { return get(); } + template <typename T> T *takeAs() { return static_cast<T*>(get()); } + + void set(PtrTy V) { + void *VP = PtrTraits::getAsVoidPointer(V); + PtrWithInvalid = reinterpret_cast<uintptr_t>(VP); + assert((PtrWithInvalid & 0x01) == 0 && "Badly aligned pointer"); + } + + const ActionResult &operator=(PtrTy RHS) { + void *VP = PtrTraits::getAsVoidPointer(RHS); + PtrWithInvalid = reinterpret_cast<uintptr_t>(VP); + assert((PtrWithInvalid & 0x01) == 0 && "Badly aligned pointer"); + return *this; + } + }; + + /// ASTMultiPtr - A moveable smart pointer to multiple AST nodes. Only owns + /// the individual pointers, not the array holding them. + template <typename PtrTy> class ASTMultiPtr; + + template <class PtrTy> + class ASTMultiPtr { + PtrTy *Nodes; + unsigned Count; + + public: + // Normal copying implicitly defined + ASTMultiPtr() : Nodes(0), Count(0) {} + explicit ASTMultiPtr(Sema &) : Nodes(0), Count(0) {} + ASTMultiPtr(Sema &, PtrTy *nodes, unsigned count) + : Nodes(nodes), Count(count) {} + // Fake mover in Parse/AstGuard.h needs this: + ASTMultiPtr(PtrTy *nodes, unsigned count) : Nodes(nodes), Count(count) {} + + /// Access to the raw pointers. + PtrTy *get() const { return Nodes; } + + /// Access to the count. + unsigned size() const { return Count; } + + PtrTy *release() { + return Nodes; + } + }; + + class ParsedTemplateArgument; + + class ASTTemplateArgsPtr { + ParsedTemplateArgument *Args; + mutable unsigned Count; + + public: + ASTTemplateArgsPtr(Sema &actions, ParsedTemplateArgument *args, + unsigned count) : + Args(args), Count(count) { } + + // FIXME: Lame, not-fully-type-safe emulation of 'move semantics'. + ASTTemplateArgsPtr(ASTTemplateArgsPtr &Other) : + Args(Other.Args), Count(Other.Count) { + } + + // FIXME: Lame, not-fully-type-safe emulation of 'move semantics'. + ASTTemplateArgsPtr& operator=(ASTTemplateArgsPtr &Other) { + Args = Other.Args; + Count = Other.Count; + return *this; + } + + ParsedTemplateArgument *getArgs() const { return Args; } + unsigned size() const { return Count; } + + void reset(ParsedTemplateArgument *args, unsigned count) { + Args = args; + Count = count; + } + + const ParsedTemplateArgument &operator[](unsigned Arg) const; + + ParsedTemplateArgument *release() const { + return Args; + } + }; + + /// \brief A small vector that owns a set of AST nodes. + template <class PtrTy, unsigned N = 8> + class ASTOwningVector : public SmallVector<PtrTy, N> { + ASTOwningVector(ASTOwningVector &); // do not implement + ASTOwningVector &operator=(ASTOwningVector &); // do not implement + + public: + explicit ASTOwningVector(Sema &Actions) + { } + + PtrTy *take() { + return &this->front(); + } + + template<typename T> T **takeAs() { return reinterpret_cast<T**>(take()); } + }; + + /// An opaque type for threading parsed type information through the + /// parser. + typedef OpaquePtr<QualType> ParsedType; + typedef UnionOpaquePtr<QualType> UnionParsedType; + + /// A SmallVector of statements, with stack size 32 (as that is the only one + /// used.) + typedef ASTOwningVector<Stmt*, 32> StmtVector; + /// A SmallVector of expressions, with stack size 12 (the maximum used.) + typedef ASTOwningVector<Expr*, 12> ExprVector; + /// A SmallVector of types. + typedef ASTOwningVector<ParsedType, 12> TypeVector; + + template <class T, unsigned N> inline + ASTMultiPtr<T> move_arg(ASTOwningVector<T, N> &vec) { + return ASTMultiPtr<T>(vec.take(), vec.size()); + } + + // These versions are hopefully no-ops. + template <class T, bool C> + inline ActionResult<T,C> move(ActionResult<T,C> &ptr) { + return ptr; + } + + template <class T> inline + ASTMultiPtr<T>& move(ASTMultiPtr<T> &ptr) { + return ptr; + } + + // We can re-use the low bit of expression, statement, base, and + // member-initializer pointers for the "invalid" flag of + // ActionResult. + template<> struct IsResultPtrLowBitFree<Expr*> { + static const bool value = true; + }; + template<> struct IsResultPtrLowBitFree<Stmt*> { + static const bool value = true; + }; + template<> struct IsResultPtrLowBitFree<CXXBaseSpecifier*> { + static const bool value = true; + }; + template<> struct IsResultPtrLowBitFree<CXXCtorInitializer*> { + static const bool value = true; + }; + + typedef ActionResult<Expr*> ExprResult; + typedef ActionResult<Stmt*> StmtResult; + typedef ActionResult<ParsedType> TypeResult; + typedef ActionResult<CXXBaseSpecifier*> BaseResult; + typedef ActionResult<CXXCtorInitializer*> MemInitResult; + + typedef ActionResult<Decl*> DeclResult; + typedef OpaquePtr<TemplateName> ParsedTemplateTy; + + inline Expr *move(Expr *E) { return E; } + inline Stmt *move(Stmt *S) { return S; } + + typedef ASTMultiPtr<Expr*> MultiExprArg; + typedef ASTMultiPtr<Stmt*> MultiStmtArg; + typedef ASTMultiPtr<ParsedType> MultiTypeArg; + typedef ASTMultiPtr<TemplateParameterList*> MultiTemplateParamsArg; + + inline ExprResult ExprError() { return ExprResult(true); } + inline StmtResult StmtError() { return StmtResult(true); } + + inline ExprResult ExprError(const DiagnosticBuilder&) { return ExprError(); } + inline StmtResult StmtError(const DiagnosticBuilder&) { return StmtError(); } + + inline ExprResult ExprEmpty() { return ExprResult(false); } + inline StmtResult StmtEmpty() { return StmtResult(false); } + + inline Expr *AssertSuccess(ExprResult R) { + assert(!R.isInvalid() && "operation was asserted to never fail!"); + return R.get(); + } + + inline Stmt *AssertSuccess(StmtResult R) { + assert(!R.isInvalid() && "operation was asserted to never fail!"); + return R.get(); + } +} + +#endif diff --git a/clang/include/clang/Sema/ParsedTemplate.h b/clang/include/clang/Sema/ParsedTemplate.h new file mode 100644 index 0000000..c1b4710 --- /dev/null +++ b/clang/include/clang/Sema/ParsedTemplate.h @@ -0,0 +1,219 @@ +//===--- ParsedTemplate.h - Template Parsing Data Types -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides data structures that store the parsed representation of +// templates. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_SEMA_PARSEDTEMPLATE_H +#define LLVM_CLANG_SEMA_PARSEDTEMPLATE_H + +#include "clang/Sema/DeclSpec.h" +#include "clang/Sema/Ownership.h" +#include <cassert> + +namespace clang { + /// \brief Represents the parsed form of a C++ template argument. + class ParsedTemplateArgument { + public: + /// \brief Describes the kind of template argument that was parsed. + enum KindType { + /// \brief A template type parameter, stored as a type. + Type, + /// \brief A non-type template parameter, stored as an expression. + NonType, + /// \brief A template template argument, stored as a template name. + Template + }; + + /// \brief Build an empty template argument. + /// + /// This template argument is invalid. + ParsedTemplateArgument() : Kind(Type), Arg(0) { } + + /// \brief Create a template type argument or non-type template argument. + /// + /// \param Arg the template type argument or non-type template argument. + /// \param Loc the location of the type. + ParsedTemplateArgument(KindType Kind, void *Arg, SourceLocation Loc) + : Kind(Kind), Arg(Arg), Loc(Loc) { } + + /// \brief Create a template template argument. + /// + /// \param SS the C++ scope specifier that precedes the template name, if + /// any. + /// + /// \param Template the template to which this template template + /// argument refers. + /// + /// \param TemplateLoc the location of the template name. + ParsedTemplateArgument(const CXXScopeSpec &SS, + ParsedTemplateTy Template, + SourceLocation TemplateLoc) + : Kind(ParsedTemplateArgument::Template), + Arg(Template.getAsOpaquePtr()), + Loc(TemplateLoc), SS(SS), EllipsisLoc() { } + + /// \brief Determine whether the given template argument is invalid. + bool isInvalid() const { return Arg == 0; } + + /// \brief Determine what kind of template argument we have. + KindType getKind() const { return Kind; } + + /// \brief Retrieve the template type argument's type. + ParsedType getAsType() const { + assert(Kind == Type && "Not a template type argument"); + return ParsedType::getFromOpaquePtr(Arg); + } + + /// \brief Retrieve the non-type template argument's expression. + Expr *getAsExpr() const { + assert(Kind == NonType && "Not a non-type template argument"); + return static_cast<Expr*>(Arg); + } + + /// \brief Retrieve the template template argument's template name. + ParsedTemplateTy getAsTemplate() const { + assert(Kind == Template && "Not a template template argument"); + return ParsedTemplateTy::getFromOpaquePtr(Arg); + } + + /// \brief Retrieve the location of the template argument. + SourceLocation getLocation() const { return Loc; } + + /// \brief Retrieve the nested-name-specifier that precedes the template + /// name in a template template argument. + const CXXScopeSpec &getScopeSpec() const { + assert(Kind == Template && + "Only template template arguments can have a scope specifier"); + return SS; + } + + /// \brief Retrieve the location of the ellipsis that makes a template + /// template argument into a pack expansion. + SourceLocation getEllipsisLoc() const { + assert(Kind == Template && + "Only template template arguments can have an ellipsis"); + return EllipsisLoc; + } + + /// \brief Retrieve a pack expansion of the given template template + /// argument. + /// + /// \param EllipsisLoc The location of the ellipsis. + ParsedTemplateArgument getTemplatePackExpansion( + SourceLocation EllipsisLoc) const; + + private: + KindType Kind; + + /// \brief The actual template argument representation, which may be + /// an \c ActionBase::TypeTy* (for a type), an Expr* (for an + /// expression), or an ActionBase::TemplateTy (for a template). + void *Arg; + + /// \brief the location of the template argument. + SourceLocation Loc; + + /// \brief The nested-name-specifier that can accompany a template template + /// argument. + CXXScopeSpec SS; + + /// \brief The ellipsis location that can accompany a template template + /// argument (turning it into a template template argument expansion). + SourceLocation EllipsisLoc; + }; + + /// \brief Information about a template-id annotation + /// token. + /// + /// A template-id annotation token contains the template declaration, + /// template arguments, whether those template arguments were types, + /// expressions, or template names, and the source locations for important + /// tokens. All of the information about template arguments is allocated + /// directly after this structure. + struct TemplateIdAnnotation { + /// \brief The nested-name-specifier that precedes the template name. + CXXScopeSpec SS; + + /// TemplateKWLoc - The location of the template keyword within the + /// source. + SourceLocation TemplateKWLoc; + + /// TemplateNameLoc - The location of the template name within the + /// source. + SourceLocation TemplateNameLoc; + + /// FIXME: Temporarily stores the name of a specialization + IdentifierInfo *Name; + + /// FIXME: Temporarily stores the overloaded operator kind. + OverloadedOperatorKind Operator; + + /// The declaration of the template corresponding to the + /// template-name. + ParsedTemplateTy Template; + + /// The kind of template that Template refers to. + TemplateNameKind Kind; + + /// The location of the '<' before the template argument + /// list. + SourceLocation LAngleLoc; + + /// The location of the '>' after the template argument + /// list. + SourceLocation RAngleLoc; + + /// NumArgs - The number of template arguments. + unsigned NumArgs; + + /// \brief Retrieves a pointer to the template arguments + ParsedTemplateArgument *getTemplateArgs() { + return reinterpret_cast<ParsedTemplateArgument *>(this + 1); + } + + /// \brief Creates a new TemplateIdAnnotation with NumArgs arguments and + /// appends it to List. + static TemplateIdAnnotation * + Allocate(unsigned NumArgs, SmallVectorImpl<TemplateIdAnnotation*> &List) { + TemplateIdAnnotation *TemplateId + = (TemplateIdAnnotation *)std::malloc(sizeof(TemplateIdAnnotation) + + sizeof(ParsedTemplateArgument) * NumArgs); + TemplateId->NumArgs = NumArgs; + + // Default-construct nested-name-specifier. + new (&TemplateId->SS) CXXScopeSpec(); + + // Default-construct parsed template arguments. + ParsedTemplateArgument *TemplateArgs = TemplateId->getTemplateArgs(); + for (unsigned I = 0; I != NumArgs; ++I) + new (TemplateArgs + I) ParsedTemplateArgument(); + + List.push_back(TemplateId); + return TemplateId; + } + + void Destroy() { + SS.~CXXScopeSpec(); + free(this); + } + }; + + /// Retrieves the range of the given template parameter lists. + SourceRange getTemplateParamsRange(TemplateParameterList const *const *Params, + unsigned NumParams); + + inline const ParsedTemplateArgument & + ASTTemplateArgsPtr::operator[](unsigned Arg) const { + return Args[Arg]; + } +} + +#endif diff --git a/clang/include/clang/Sema/PrettyDeclStackTrace.h b/clang/include/clang/Sema/PrettyDeclStackTrace.h new file mode 100644 index 0000000..aa55705 --- /dev/null +++ b/clang/include/clang/Sema/PrettyDeclStackTrace.h @@ -0,0 +1,47 @@ +//===- PrettyDeclStackTrace.h - Stack trace for decl processing -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines an llvm::PrettyStackTraceEntry object for showing +// that a particular declaration was being processed when a crash +// occurred. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_PRETTY_DECL_STACK_TRACE_H +#define LLVM_CLANG_SEMA_PRETTY_DECL_STACK_TRACE_H + +#include "clang/Basic/SourceLocation.h" +#include "llvm/Support/PrettyStackTrace.h" + +namespace clang { + +class Decl; +class Sema; +class SourceManager; + +/// PrettyDeclStackTraceEntry - If a crash occurs in the parser while +/// parsing something related to a declaration, include that +/// declaration in the stack trace. +class PrettyDeclStackTraceEntry : public llvm::PrettyStackTraceEntry { + Sema &S; + Decl *TheDecl; + SourceLocation Loc; + const char *Message; + +public: + PrettyDeclStackTraceEntry(Sema &S, Decl *D, SourceLocation Loc, + const char *Msg) + : S(S), TheDecl(D), Loc(Loc), Message(Msg) {} + + virtual void print(raw_ostream &OS) const; +}; + +} + +#endif diff --git a/clang/include/clang/Sema/Scope.h b/clang/include/clang/Sema/Scope.h new file mode 100644 index 0000000..48f5417 --- /dev/null +++ b/clang/include/clang/Sema/Scope.h @@ -0,0 +1,329 @@ +//===--- Scope.h - Scope interface ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Scope interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_SCOPE_H +#define LLVM_CLANG_SEMA_SCOPE_H + +#include "clang/Basic/Diagnostic.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" + +namespace clang { + +class Decl; +class UsingDirectiveDecl; + +/// Scope - A scope is a transient data structure that is used while parsing the +/// program. It assists with resolving identifiers to the appropriate +/// declaration. +/// +class Scope { +public: + /// ScopeFlags - These are bitfields that are or'd together when creating a + /// scope, which defines the sorts of things the scope contains. + enum ScopeFlags { + /// FnScope - This indicates that the scope corresponds to a function, which + /// means that labels are set here. + FnScope = 0x01, + + /// BreakScope - This is a while,do,switch,for, etc that can have break + /// stmts embedded into it. + BreakScope = 0x02, + + /// ContinueScope - This is a while,do,for, which can have continue + /// stmt embedded into it. + ContinueScope = 0x04, + + /// DeclScope - This is a scope that can contain a declaration. Some scopes + /// just contain loop constructs but don't contain decls. + DeclScope = 0x08, + + /// ControlScope - The controlling scope in a if/switch/while/for statement. + ControlScope = 0x10, + + /// ClassScope - The scope of a struct/union/class definition. + ClassScope = 0x20, + + /// BlockScope - This is a scope that corresponds to a block/closure object. + /// Blocks serve as top-level scopes for some objects like labels, they + /// also prevent things like break and continue. BlockScopes always have + /// the FnScope and DeclScope flags set as well. + BlockScope = 0x40, + + /// TemplateParamScope - This is a scope that corresponds to the + /// template parameters of a C++ template. Template parameter + /// scope starts at the 'template' keyword and ends when the + /// template declaration ends. + TemplateParamScope = 0x80, + + /// FunctionPrototypeScope - This is a scope that corresponds to the + /// parameters within a function prototype. + FunctionPrototypeScope = 0x100, + + /// AtCatchScope - This is a scope that corresponds to the Objective-C + /// @catch statement. + AtCatchScope = 0x200, + + /// ObjCMethodScope - This scope corresponds to an Objective-C method body. + /// It always has FnScope and DeclScope set as well. + ObjCMethodScope = 0x400, + + /// SwitchScope - This is a scope that corresponds to a switch statement. + SwitchScope = 0x800, + + /// TryScope - This is the scope of a C++ try statement. + TryScope = 0x1000 + }; +private: + /// The parent scope for this scope. This is null for the translation-unit + /// scope. + Scope *AnyParent; + + /// Depth - This is the depth of this scope. The translation-unit scope has + /// depth 0. + unsigned short Depth; + + /// Flags - This contains a set of ScopeFlags, which indicates how the scope + /// interrelates with other control flow statements. + unsigned short Flags; + + /// PrototypeDepth - This is the number of function prototype scopes + /// enclosing this scope, including this scope. + unsigned short PrototypeDepth; + + /// PrototypeIndex - This is the number of parameters currently + /// declared in this scope. + unsigned short PrototypeIndex; + + /// FnParent - If this scope has a parent scope that is a function body, this + /// pointer is non-null and points to it. This is used for label processing. + Scope *FnParent; + + /// BreakParent/ContinueParent - This is a direct link to the innermost + /// BreakScope/ContinueScope which contains the contents of this scope + /// for control flow purposes (and might be this scope itself), or null + /// if there is no such scope. + Scope *BreakParent, *ContinueParent; + + /// BlockParent - This is a direct link to the immediately containing + /// BlockScope if this scope is not one, or null if there is none. + Scope *BlockParent; + + /// TemplateParamParent - This is a direct link to the + /// immediately containing template parameter scope. In the + /// case of nested templates, template parameter scopes can have + /// other template parameter scopes as parents. + Scope *TemplateParamParent; + + /// DeclsInScope - This keeps track of all declarations in this scope. When + /// the declaration is added to the scope, it is set as the current + /// declaration for the identifier in the IdentifierTable. When the scope is + /// popped, these declarations are removed from the IdentifierTable's notion + /// of current declaration. It is up to the current Action implementation to + /// implement these semantics. + typedef llvm::SmallPtrSet<Decl *, 32> DeclSetTy; + DeclSetTy DeclsInScope; + + /// Entity - The entity with which this scope is associated. For + /// example, the entity of a class scope is the class itself, the + /// entity of a function scope is a function, etc. This field is + /// maintained by the Action implementation. + void *Entity; + + typedef SmallVector<UsingDirectiveDecl *, 2> UsingDirectivesTy; + UsingDirectivesTy UsingDirectives; + + /// \brief Used to determine if errors occurred in this scope. + DiagnosticErrorTrap ErrorTrap; + +public: + Scope(Scope *Parent, unsigned ScopeFlags, DiagnosticsEngine &Diag) + : ErrorTrap(Diag) { + Init(Parent, ScopeFlags); + } + + /// getFlags - Return the flags for this scope. + /// + unsigned getFlags() const { return Flags; } + void setFlags(unsigned F) { Flags = F; } + + /// isBlockScope - Return true if this scope correspond to a closure. + bool isBlockScope() const { return Flags & BlockScope; } + + /// getParent - Return the scope that this is nested in. + /// + const Scope *getParent() const { return AnyParent; } + Scope *getParent() { return AnyParent; } + + /// getFnParent - Return the closest scope that is a function body. + /// + const Scope *getFnParent() const { return FnParent; } + Scope *getFnParent() { return FnParent; } + + /// getContinueParent - Return the closest scope that a continue statement + /// would be affected by. + Scope *getContinueParent() { + return ContinueParent; + } + + const Scope *getContinueParent() const { + return const_cast<Scope*>(this)->getContinueParent(); + } + + /// getBreakParent - Return the closest scope that a break statement + /// would be affected by. + Scope *getBreakParent() { + return BreakParent; + } + const Scope *getBreakParent() const { + return const_cast<Scope*>(this)->getBreakParent(); + } + + Scope *getBlockParent() { return BlockParent; } + const Scope *getBlockParent() const { return BlockParent; } + + Scope *getTemplateParamParent() { return TemplateParamParent; } + const Scope *getTemplateParamParent() const { return TemplateParamParent; } + + /// Returns the number of function prototype scopes in this scope + /// chain. + unsigned getFunctionPrototypeDepth() const { + return PrototypeDepth; + } + + /// Return the number of parameters declared in this function + /// prototype, increasing it by one for the next call. + unsigned getNextFunctionPrototypeIndex() { + assert(isFunctionPrototypeScope()); + return PrototypeIndex++; + } + + typedef DeclSetTy::iterator decl_iterator; + decl_iterator decl_begin() const { return DeclsInScope.begin(); } + decl_iterator decl_end() const { return DeclsInScope.end(); } + bool decl_empty() const { return DeclsInScope.empty(); } + + void AddDecl(Decl *D) { + DeclsInScope.insert(D); + } + + void RemoveDecl(Decl *D) { + DeclsInScope.erase(D); + } + + /// isDeclScope - Return true if this is the scope that the specified decl is + /// declared in. + bool isDeclScope(Decl *D) { + return DeclsInScope.count(D) != 0; + } + + void* getEntity() const { return Entity; } + void setEntity(void *E) { Entity = E; } + + bool hasErrorOccurred() const { return ErrorTrap.hasErrorOccurred(); } + + /// isClassScope - Return true if this scope is a class/struct/union scope. + bool isClassScope() const { + return (getFlags() & Scope::ClassScope); + } + + /// isInCXXInlineMethodScope - Return true if this scope is a C++ inline + /// method scope or is inside one. + bool isInCXXInlineMethodScope() const { + if (const Scope *FnS = getFnParent()) { + assert(FnS->getParent() && "TUScope not created?"); + return FnS->getParent()->isClassScope(); + } + return false; + } + + /// isInObjcMethodScope - Return true if this scope is, or is contained in, an + /// Objective-C method body. Note that this method is not constant time. + bool isInObjcMethodScope() const { + for (const Scope *S = this; S; S = S->getParent()) { + // If this scope is an objc method scope, then we succeed. + if (S->getFlags() & ObjCMethodScope) + return true; + } + return false; + } + + /// isTemplateParamScope - Return true if this scope is a C++ + /// template parameter scope. + bool isTemplateParamScope() const { + return getFlags() & Scope::TemplateParamScope; + } + + /// isFunctionPrototypeScope - Return true if this scope is a + /// function prototype scope. + bool isFunctionPrototypeScope() const { + return getFlags() & Scope::FunctionPrototypeScope; + } + + /// isAtCatchScope - Return true if this scope is @catch. + bool isAtCatchScope() const { + return getFlags() & Scope::AtCatchScope; + } + + /// isSwitchScope - Return true if this scope is a switch scope. + bool isSwitchScope() const { + for (const Scope *S = this; S; S = S->getParent()) { + if (S->getFlags() & Scope::SwitchScope) + return true; + else if (S->getFlags() & (Scope::FnScope | Scope::ClassScope | + Scope::BlockScope | Scope::TemplateParamScope | + Scope::FunctionPrototypeScope | + Scope::AtCatchScope | Scope::ObjCMethodScope)) + return false; + } + return false; + } + + /// \brief Determine whether this scope is a C++ 'try' block. + bool isTryScope() const { return getFlags() & Scope::TryScope; } + + /// containedInPrototypeScope - Return true if this or a parent scope + /// is a FunctionPrototypeScope. + bool containedInPrototypeScope() const; + + typedef UsingDirectivesTy::iterator udir_iterator; + typedef UsingDirectivesTy::const_iterator const_udir_iterator; + + void PushUsingDirective(UsingDirectiveDecl *UDir) { + UsingDirectives.push_back(UDir); + } + + udir_iterator using_directives_begin() { + return UsingDirectives.begin(); + } + + udir_iterator using_directives_end() { + return UsingDirectives.end(); + } + + const_udir_iterator using_directives_begin() const { + return UsingDirectives.begin(); + } + + const_udir_iterator using_directives_end() const { + return UsingDirectives.end(); + } + + /// Init - This is used by the parser to implement scope caching. + /// + void Init(Scope *parent, unsigned flags); +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Sema/ScopeInfo.h b/clang/include/clang/Sema/ScopeInfo.h new file mode 100644 index 0000000..ceaf586 --- /dev/null +++ b/clang/include/clang/Sema/ScopeInfo.h @@ -0,0 +1,380 @@ +//===--- ScopeInfo.h - Information about a semantic context -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines FunctionScopeInfo and BlockScopeInfo. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_SCOPE_INFO_H +#define LLVM_CLANG_SEMA_SCOPE_INFO_H + +#include "clang/AST/Type.h" +#include "clang/Basic/PartialDiagnostic.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallVector.h" + +namespace clang { + +class BlockDecl; +class CXXMethodDecl; +class IdentifierInfo; +class LabelDecl; +class ReturnStmt; +class Scope; +class SwitchStmt; +class VarDecl; + +namespace sema { + +/// \brief Contains information about the compound statement currently being +/// parsed. +class CompoundScopeInfo { +public: + CompoundScopeInfo() + : HasEmptyLoopBodies(false) { } + + /// \brief Whether this compound stamement contains `for' or `while' loops + /// with empty bodies. + bool HasEmptyLoopBodies; + + void setHasEmptyLoopBodies() { + HasEmptyLoopBodies = true; + } +}; + +class PossiblyUnreachableDiag { +public: + PartialDiagnostic PD; + SourceLocation Loc; + const Stmt *stmt; + + PossiblyUnreachableDiag(const PartialDiagnostic &PD, SourceLocation Loc, + const Stmt *stmt) + : PD(PD), Loc(Loc), stmt(stmt) {} +}; + +/// \brief Retains information about a function, method, or block that is +/// currently being parsed. +class FunctionScopeInfo { +protected: + enum ScopeKind { + SK_Function, + SK_Block, + SK_Lambda + }; + +public: + /// \brief What kind of scope we are describing. + /// + ScopeKind Kind; + + /// \brief Whether this function contains a VLA, @try, try, C++ + /// initializer, or anything else that can't be jumped past. + bool HasBranchProtectedScope; + + /// \brief Whether this function contains any switches or direct gotos. + bool HasBranchIntoScope; + + /// \brief Whether this function contains any indirect gotos. + bool HasIndirectGoto; + + /// \brief Used to determine if errors occurred in this function or block. + DiagnosticErrorTrap ErrorTrap; + + /// SwitchStack - This is the current set of active switch statements in the + /// block. + SmallVector<SwitchStmt*, 8> SwitchStack; + + /// \brief The list of return statements that occur within the function or + /// block, if there is any chance of applying the named return value + /// optimization. + SmallVector<ReturnStmt*, 4> Returns; + + /// \brief The stack of currently active compound stamement scopes in the + /// function. + SmallVector<CompoundScopeInfo, 4> CompoundScopes; + + /// \brief A list of PartialDiagnostics created but delayed within the + /// current function scope. These diagnostics are vetted for reachability + /// prior to being emitted. + SmallVector<PossiblyUnreachableDiag, 4> PossiblyUnreachableDiags; + + void setHasBranchIntoScope() { + HasBranchIntoScope = true; + } + + void setHasBranchProtectedScope() { + HasBranchProtectedScope = true; + } + + void setHasIndirectGoto() { + HasIndirectGoto = true; + } + + bool NeedsScopeChecking() const { + return HasIndirectGoto || + (HasBranchProtectedScope && HasBranchIntoScope); + } + + FunctionScopeInfo(DiagnosticsEngine &Diag) + : Kind(SK_Function), + HasBranchProtectedScope(false), + HasBranchIntoScope(false), + HasIndirectGoto(false), + ErrorTrap(Diag) { } + + virtual ~FunctionScopeInfo(); + + /// \brief Clear out the information in this function scope, making it + /// suitable for reuse. + void Clear(); + + static bool classof(const FunctionScopeInfo *FSI) { return true; } +}; + +class CapturingScopeInfo : public FunctionScopeInfo { +public: + enum ImplicitCaptureStyle { + ImpCap_None, ImpCap_LambdaByval, ImpCap_LambdaByref, ImpCap_Block + }; + + ImplicitCaptureStyle ImpCaptureStyle; + + class Capture { + // There are two categories of capture: capturing 'this', and capturing + // local variables. There are three ways to capture a local variable: + // capture by copy in the C++11 sense, capture by reference + // in the C++11 sense, and __block capture. Lambdas explicitly specify + // capture by copy or capture by reference. For blocks, __block capture + // applies to variables with that annotation, variables of reference type + // are captured by reference, and other variables are captured by copy. + enum CaptureKind { + Cap_This, Cap_ByCopy, Cap_ByRef, Cap_Block + }; + + // The variable being captured (if we are not capturing 'this'), + // and misc bits descibing the capture. + llvm::PointerIntPair<VarDecl*, 2, CaptureKind> VarAndKind; + + // Expression to initialize a field of the given type, and whether this + // is a nested capture; the expression is only required if we are + // capturing ByVal and the variable's type has a non-trivial + // copy constructor. + llvm::PointerIntPair<Expr*, 1, bool> CopyExprAndNested; + + /// \brief The source location at which the first capture occurred.. + SourceLocation Loc; + + /// \brief The location of the ellipsis that expands a parameter pack. + SourceLocation EllipsisLoc; + + /// \brief The type as it was captured, which is in effect the type of the + /// non-static data member that would hold the capture. + QualType CaptureType; + + public: + Capture(VarDecl *Var, bool block, bool byRef, bool isNested, + SourceLocation Loc, SourceLocation EllipsisLoc, + QualType CaptureType, Expr *Cpy) + : VarAndKind(Var, block ? Cap_Block : byRef ? Cap_ByRef : Cap_ByCopy), + CopyExprAndNested(Cpy, isNested), Loc(Loc), EllipsisLoc(EllipsisLoc), + CaptureType(CaptureType){} + + enum IsThisCapture { ThisCapture }; + Capture(IsThisCapture, bool isNested, SourceLocation Loc, + QualType CaptureType, Expr *Cpy) + : VarAndKind(0, Cap_This), CopyExprAndNested(Cpy, isNested), Loc(Loc), + EllipsisLoc(), CaptureType(CaptureType) { } + + bool isThisCapture() const { return VarAndKind.getInt() == Cap_This; } + bool isVariableCapture() const { return !isThisCapture(); } + bool isCopyCapture() const { return VarAndKind.getInt() == Cap_ByCopy; } + bool isReferenceCapture() const { return VarAndKind.getInt() == Cap_ByRef; } + bool isBlockCapture() const { return VarAndKind.getInt() == Cap_Block; } + bool isNested() { return CopyExprAndNested.getInt(); } + + VarDecl *getVariable() const { + return VarAndKind.getPointer(); + } + + /// \brief Retrieve the location at which this variable was captured. + SourceLocation getLocation() const { return Loc; } + + /// \brief Retrieve the source location of the ellipsis, whose presence + /// indicates that the capture is a pack expansion. + SourceLocation getEllipsisLoc() const { return EllipsisLoc; } + + /// \brief Retrieve the capture type for this capture, which is effectively + /// the type of the non-static data member in the lambda/block structure + /// that would store this capture. + QualType getCaptureType() const { return CaptureType; } + + Expr *getCopyExpr() const { + return CopyExprAndNested.getPointer(); + } + }; + + CapturingScopeInfo(DiagnosticsEngine &Diag, ImplicitCaptureStyle Style) + : FunctionScopeInfo(Diag), ImpCaptureStyle(Style), CXXThisCaptureIndex(0), + HasImplicitReturnType(false) + {} + + /// CaptureMap - A map of captured variables to (index+1) into Captures. + llvm::DenseMap<VarDecl*, unsigned> CaptureMap; + + /// CXXThisCaptureIndex - The (index+1) of the capture of 'this'; + /// zero if 'this' is not captured. + unsigned CXXThisCaptureIndex; + + /// Captures - The captures. + SmallVector<Capture, 4> Captures; + + /// \brief - Whether the target type of return statements in this context + /// is deduced (e.g. a lambda or block with omitted return type). + bool HasImplicitReturnType; + + /// ReturnType - The target type of return statements in this context, + /// or null if unknown. + QualType ReturnType; + + void addCapture(VarDecl *Var, bool isBlock, bool isByref, bool isNested, + SourceLocation Loc, SourceLocation EllipsisLoc, + QualType CaptureType, Expr *Cpy) { + Captures.push_back(Capture(Var, isBlock, isByref, isNested, Loc, + EllipsisLoc, CaptureType, Cpy)); + CaptureMap[Var] = Captures.size(); + } + + void addThisCapture(bool isNested, SourceLocation Loc, QualType CaptureType, + Expr *Cpy) { + Captures.push_back(Capture(Capture::ThisCapture, isNested, Loc, CaptureType, + Cpy)); + CXXThisCaptureIndex = Captures.size(); + } + + /// \brief Determine whether the C++ 'this' is captured. + bool isCXXThisCaptured() const { return CXXThisCaptureIndex != 0; } + + /// \brief Retrieve the capture of C++ 'this', if it has been captured. + Capture &getCXXThisCapture() { + assert(isCXXThisCaptured() && "this has not been captured"); + return Captures[CXXThisCaptureIndex - 1]; + } + + /// \brief Determine whether the given variable has been captured. + bool isCaptured(VarDecl *Var) const { + return CaptureMap.count(Var); + } + + /// \brief Retrieve the capture of the given variable, if it has been + /// captured already. + Capture &getCapture(VarDecl *Var) { + assert(isCaptured(Var) && "Variable has not been captured"); + return Captures[CaptureMap[Var] - 1]; + } + + const Capture &getCapture(VarDecl *Var) const { + llvm::DenseMap<VarDecl*, unsigned>::const_iterator Known + = CaptureMap.find(Var); + assert(Known != CaptureMap.end() && "Variable has not been captured"); + return Captures[Known->second - 1]; + } + + static bool classof(const FunctionScopeInfo *FSI) { + return FSI->Kind == SK_Block || FSI->Kind == SK_Lambda; + } + static bool classof(const CapturingScopeInfo *BSI) { return true; } +}; + +/// \brief Retains information about a block that is currently being parsed. +class BlockScopeInfo : public CapturingScopeInfo { +public: + BlockDecl *TheDecl; + + /// TheScope - This is the scope for the block itself, which contains + /// arguments etc. + Scope *TheScope; + + /// BlockType - The function type of the block, if one was given. + /// Its return type may be BuiltinType::Dependent. + QualType FunctionType; + + BlockScopeInfo(DiagnosticsEngine &Diag, Scope *BlockScope, BlockDecl *Block) + : CapturingScopeInfo(Diag, ImpCap_Block), TheDecl(Block), + TheScope(BlockScope) + { + Kind = SK_Block; + } + + virtual ~BlockScopeInfo(); + + static bool classof(const FunctionScopeInfo *FSI) { + return FSI->Kind == SK_Block; + } + static bool classof(const BlockScopeInfo *BSI) { return true; } +}; + +class LambdaScopeInfo : public CapturingScopeInfo { +public: + /// \brief The class that describes the lambda. + CXXRecordDecl *Lambda; + + /// \brief The class that describes the lambda. + CXXMethodDecl *CallOperator; + + /// \brief Source range covering the lambda introducer [...]. + SourceRange IntroducerRange; + + /// \brief The number of captures in the \c Captures list that are + /// explicit captures. + unsigned NumExplicitCaptures; + + /// \brief Whether this is a mutable lambda. + bool Mutable; + + /// \brief Whether the (empty) parameter list is explicit. + bool ExplicitParams; + + /// \brief Whether any of the capture expressions requires cleanups. + bool ExprNeedsCleanups; + + /// \brief Variables used to index into by-copy array captures. + llvm::SmallVector<VarDecl *, 4> ArrayIndexVars; + + /// \brief Offsets into the ArrayIndexVars array at which each capture starts + /// its list of array index variables. + llvm::SmallVector<unsigned, 4> ArrayIndexStarts; + + LambdaScopeInfo(DiagnosticsEngine &Diag, CXXRecordDecl *Lambda, + CXXMethodDecl *CallOperator) + : CapturingScopeInfo(Diag, ImpCap_None), Lambda(Lambda), + CallOperator(CallOperator), NumExplicitCaptures(0), Mutable(false), + ExprNeedsCleanups(false) + { + Kind = SK_Lambda; + } + + virtual ~LambdaScopeInfo(); + + /// \brief Note when + void finishedExplicitCaptures() { + NumExplicitCaptures = Captures.size(); + } + + static bool classof(const FunctionScopeInfo *FSI) { + return FSI->Kind == SK_Lambda; + } + static bool classof(const LambdaScopeInfo *BSI) { return true; } + +}; + +} +} + +#endif diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h new file mode 100644 index 0000000..c8767b6 --- /dev/null +++ b/clang/include/clang/Sema/Sema.h @@ -0,0 +1,6879 @@ +//===--- Sema.h - Semantic Analysis & AST Building --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Sema class, which performs semantic analysis and +// builds ASTs. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_SEMA_H +#define LLVM_CLANG_SEMA_SEMA_H + +#include "clang/Sema/Ownership.h" +#include "clang/Sema/AnalysisBasedWarnings.h" +#include "clang/Sema/IdentifierResolver.h" +#include "clang/Sema/ObjCMethodList.h" +#include "clang/Sema/DeclSpec.h" +#include "clang/Sema/ExternalSemaSource.h" +#include "clang/Sema/LocInfoType.h" +#include "clang/Sema/TypoCorrection.h" +#include "clang/Sema/Weak.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprObjC.h" +#include "clang/AST/DeclarationName.h" +#include "clang/AST/ExternalASTSource.h" +#include "clang/AST/TypeLoc.h" +#include "clang/AST/NSAPI.h" +#include "clang/Lex/ModuleLoader.h" +#include "clang/Basic/Specifiers.h" +#include "clang/Basic/TemplateKinds.h" +#include "clang/Basic/TypeTraits.h" +#include "clang/Basic/ExpressionTraits.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" +#include <deque> +#include <string> + +namespace llvm { + class APSInt; + template <typename ValueT> struct DenseMapInfo; + template <typename ValueT, typename ValueInfoT> class DenseSet; + class SmallBitVector; +} + +namespace clang { + class ADLResult; + class ASTConsumer; + class ASTContext; + class ASTMutationListener; + class ASTReader; + class ASTWriter; + class ArrayType; + class AttributeList; + class BlockDecl; + class CXXBasePath; + class CXXBasePaths; + class CXXBindTemporaryExpr; + typedef SmallVector<CXXBaseSpecifier*, 4> CXXCastPath; + class CXXConstructorDecl; + class CXXConversionDecl; + class CXXDestructorDecl; + class CXXFieldCollector; + class CXXMemberCallExpr; + class CXXMethodDecl; + class CXXScopeSpec; + class CXXTemporary; + class CXXTryStmt; + class CallExpr; + class ClassTemplateDecl; + class ClassTemplatePartialSpecializationDecl; + class ClassTemplateSpecializationDecl; + class CodeCompleteConsumer; + class CodeCompletionAllocator; + class CodeCompletionTUInfo; + class CodeCompletionResult; + class Decl; + class DeclAccessPair; + class DeclContext; + class DeclRefExpr; + class DeclaratorDecl; + class DeducedTemplateArgument; + class DependentDiagnostic; + class DesignatedInitExpr; + class Designation; + class EnumConstantDecl; + class Expr; + class ExtVectorType; + class ExternalSemaSource; + class FormatAttr; + class FriendDecl; + class FunctionDecl; + class FunctionProtoType; + class FunctionTemplateDecl; + class ImplicitConversionSequence; + class InitListExpr; + class InitializationKind; + class InitializationSequence; + class InitializedEntity; + class IntegerLiteral; + class LabelStmt; + class LambdaExpr; + class LangOptions; + class LocalInstantiationScope; + class LookupResult; + class MacroInfo; + class MultiLevelTemplateArgumentList; + class NamedDecl; + class NonNullAttr; + class ObjCCategoryDecl; + class ObjCCategoryImplDecl; + class ObjCCompatibleAliasDecl; + class ObjCContainerDecl; + class ObjCImplDecl; + class ObjCImplementationDecl; + class ObjCInterfaceDecl; + class ObjCIvarDecl; + template <class T> class ObjCList; + class ObjCMessageExpr; + class ObjCMethodDecl; + class ObjCPropertyDecl; + class ObjCProtocolDecl; + class OverloadCandidateSet; + class OverloadExpr; + class ParenListExpr; + class ParmVarDecl; + class Preprocessor; + class PseudoDestructorTypeStorage; + class PseudoObjectExpr; + class QualType; + class StandardConversionSequence; + class Stmt; + class StringLiteral; + class SwitchStmt; + class TargetAttributesSema; + class TemplateArgument; + class TemplateArgumentList; + class TemplateArgumentLoc; + class TemplateDecl; + class TemplateParameterList; + class TemplatePartialOrderingContext; + class TemplateTemplateParmDecl; + class Token; + class TypeAliasDecl; + class TypedefDecl; + class TypedefNameDecl; + class TypeLoc; + class UnqualifiedId; + class UnresolvedLookupExpr; + class UnresolvedMemberExpr; + class UnresolvedSetImpl; + class UnresolvedSetIterator; + class UsingDecl; + class UsingShadowDecl; + class ValueDecl; + class VarDecl; + class VisibilityAttr; + class VisibleDeclConsumer; + class IndirectFieldDecl; + +namespace sema { + class AccessedEntity; + class BlockScopeInfo; + class CompoundScopeInfo; + class DelayedDiagnostic; + class FunctionScopeInfo; + class LambdaScopeInfo; + class PossiblyUnreachableDiag; + class TemplateDeductionInfo; +} + +// FIXME: No way to easily map from TemplateTypeParmTypes to +// TemplateTypeParmDecls, so we have this horrible PointerUnion. +typedef std::pair<llvm::PointerUnion<const TemplateTypeParmType*, NamedDecl*>, + SourceLocation> UnexpandedParameterPack; + +/// Sema - This implements semantic analysis and AST building for C. +class Sema { + Sema(const Sema&); // DO NOT IMPLEMENT + void operator=(const Sema&); // DO NOT IMPLEMENT + mutable const TargetAttributesSema* TheTargetAttributesSema; +public: + typedef OpaquePtr<DeclGroupRef> DeclGroupPtrTy; + typedef OpaquePtr<TemplateName> TemplateTy; + typedef OpaquePtr<QualType> TypeTy; + + OpenCLOptions OpenCLFeatures; + FPOptions FPFeatures; + + const LangOptions &LangOpts; + Preprocessor &PP; + ASTContext &Context; + ASTConsumer &Consumer; + DiagnosticsEngine &Diags; + SourceManager &SourceMgr; + + /// \brief Flag indicating whether or not to collect detailed statistics. + bool CollectStats; + + /// \brief Source of additional semantic information. + ExternalSemaSource *ExternalSource; + + /// \brief Code-completion consumer. + CodeCompleteConsumer *CodeCompleter; + + /// CurContext - This is the current declaration context of parsing. + DeclContext *CurContext; + + /// \brief Generally null except when we temporarily switch decl contexts, + /// like in \see ActOnObjCTemporaryExitContainerContext. + DeclContext *OriginalLexicalContext; + + /// VAListTagName - The declaration name corresponding to __va_list_tag. + /// This is used as part of a hack to omit that class from ADL results. + DeclarationName VAListTagName; + + /// PackContext - Manages the stack for #pragma pack. An alignment + /// of 0 indicates default alignment. + void *PackContext; // Really a "PragmaPackStack*" + + bool MSStructPragmaOn; // True when #pragma ms_struct on + + /// VisContext - Manages the stack for #pragma GCC visibility. + void *VisContext; // Really a "PragmaVisStack*" + + /// ExprNeedsCleanups - True if the current evaluation context + /// requires cleanups to be run at its conclusion. + bool ExprNeedsCleanups; + + /// ExprCleanupObjects - This is the stack of objects requiring + /// cleanup that are created by the current full expression. The + /// element type here is ExprWithCleanups::Object. + SmallVector<BlockDecl*, 8> ExprCleanupObjects; + + llvm::SmallPtrSet<Expr*, 8> MaybeODRUseExprs; + + /// \brief Stack containing information about each of the nested + /// function, block, and method scopes that are currently active. + /// + /// This array is never empty. Clients should ignore the first + /// element, which is used to cache a single FunctionScopeInfo + /// that's used to parse every top-level function. + SmallVector<sema::FunctionScopeInfo *, 4> FunctionScopes; + + typedef LazyVector<TypedefNameDecl *, ExternalSemaSource, + &ExternalSemaSource::ReadExtVectorDecls, 2, 2> + ExtVectorDeclsType; + + /// ExtVectorDecls - This is a list all the extended vector types. This allows + /// us to associate a raw vector type with one of the ext_vector type names. + /// This is only necessary for issuing pretty diagnostics. + ExtVectorDeclsType ExtVectorDecls; + + /// \brief The set of types for which we have already complained about the + /// definitions being hidden. + /// + /// This set is used to suppress redundant diagnostics. + llvm::SmallPtrSet<NamedDecl *, 4> HiddenDefinitions; + + /// FieldCollector - Collects CXXFieldDecls during parsing of C++ classes. + OwningPtr<CXXFieldCollector> FieldCollector; + + typedef llvm::SmallPtrSet<const CXXRecordDecl*, 8> RecordDeclSetTy; + + /// PureVirtualClassDiagSet - a set of class declarations which we have + /// emitted a list of pure virtual functions. Used to prevent emitting the + /// same list more than once. + OwningPtr<RecordDeclSetTy> PureVirtualClassDiagSet; + + /// ParsingInitForAutoVars - a set of declarations with auto types for which + /// we are currently parsing the initializer. + llvm::SmallPtrSet<const Decl*, 4> ParsingInitForAutoVars; + + /// \brief A mapping from external names to the most recent + /// locally-scoped external declaration with that name. + /// + /// This map contains external declarations introduced in local + /// scoped, e.g., + /// + /// \code + /// void f() { + /// void foo(int, int); + /// } + /// \endcode + /// + /// Here, the name "foo" will be associated with the declaration on + /// "foo" within f. This name is not visible outside of + /// "f". However, we still find it in two cases: + /// + /// - If we are declaring another external with the name "foo", we + /// can find "foo" as a previous declaration, so that the types + /// of this external declaration can be checked for + /// compatibility. + /// + /// - If we would implicitly declare "foo" (e.g., due to a call to + /// "foo" in C when no prototype or definition is visible), then + /// we find this declaration of "foo" and complain that it is + /// not visible. + llvm::DenseMap<DeclarationName, NamedDecl *> LocallyScopedExternalDecls; + + /// \brief Look for a locally scoped external declaration by the given name. + llvm::DenseMap<DeclarationName, NamedDecl *>::iterator + findLocallyScopedExternalDecl(DeclarationName Name); + + typedef LazyVector<VarDecl *, ExternalSemaSource, + &ExternalSemaSource::ReadTentativeDefinitions, 2, 2> + TentativeDefinitionsType; + + /// \brief All the tentative definitions encountered in the TU. + TentativeDefinitionsType TentativeDefinitions; + + typedef LazyVector<const DeclaratorDecl *, ExternalSemaSource, + &ExternalSemaSource::ReadUnusedFileScopedDecls, 2, 2> + UnusedFileScopedDeclsType; + + /// \brief The set of file scoped decls seen so far that have not been used + /// and must warn if not used. Only contains the first declaration. + UnusedFileScopedDeclsType UnusedFileScopedDecls; + + typedef LazyVector<CXXConstructorDecl *, ExternalSemaSource, + &ExternalSemaSource::ReadDelegatingConstructors, 2, 2> + DelegatingCtorDeclsType; + + /// \brief All the delegating constructors seen so far in the file, used for + /// cycle detection at the end of the TU. + DelegatingCtorDeclsType DelegatingCtorDecls; + + /// \brief All the destructors seen during a class definition that had their + /// exception spec computation delayed because it depended on an unparsed + /// exception spec. + SmallVector<CXXDestructorDecl*, 2> DelayedDestructorExceptionSpecs; + + /// \brief All the overriding destructors seen during a class definition + /// (there could be multiple due to nested classes) that had their exception + /// spec checks delayed, plus the overridden destructor. + SmallVector<std::pair<const CXXDestructorDecl*, + const CXXDestructorDecl*>, 2> + DelayedDestructorExceptionSpecChecks; + + /// \brief Callback to the parser to parse templated functions when needed. + typedef void LateTemplateParserCB(void *P, const FunctionDecl *FD); + LateTemplateParserCB *LateTemplateParser; + void *OpaqueParser; + + void SetLateTemplateParser(LateTemplateParserCB *LTP, void *P) { + LateTemplateParser = LTP; + OpaqueParser = P; + } + + class DelayedDiagnostics; + + class ParsingDeclState { + unsigned SavedStackSize; + friend class Sema::DelayedDiagnostics; + }; + + class ProcessingContextState { + unsigned SavedParsingDepth; + unsigned SavedActiveStackBase; + friend class Sema::DelayedDiagnostics; + }; + + /// A class which encapsulates the logic for delaying diagnostics + /// during parsing and other processing. + class DelayedDiagnostics { + /// \brief The stack of diagnostics that were delayed due to being + /// produced during the parsing of a declaration. + sema::DelayedDiagnostic *Stack; + + /// \brief The number of objects on the delayed-diagnostics stack. + unsigned StackSize; + + /// \brief The current capacity of the delayed-diagnostics stack. + unsigned StackCapacity; + + /// \brief The index of the first "active" delayed diagnostic in + /// the stack. When parsing class definitions, we ignore active + /// delayed diagnostics from the surrounding context. + unsigned ActiveStackBase; + + /// \brief The depth of the declarations we're currently parsing. + /// This gets saved and reset whenever we enter a class definition. + unsigned ParsingDepth; + + public: + DelayedDiagnostics() : Stack(0), StackSize(0), StackCapacity(0), + ActiveStackBase(0), ParsingDepth(0) {} + + ~DelayedDiagnostics() { + delete[] reinterpret_cast<char*>(Stack); + } + + /// Adds a delayed diagnostic. + void add(const sema::DelayedDiagnostic &diag); + + /// Determines whether diagnostics should be delayed. + bool shouldDelayDiagnostics() { return ParsingDepth > 0; } + + /// Observe that we've started parsing a declaration. Access and + /// deprecation diagnostics will be delayed; when the declaration + /// is completed, all active delayed diagnostics will be evaluated + /// in its context, and then active diagnostics stack will be + /// popped down to the saved depth. + ParsingDeclState pushParsingDecl() { + ParsingDepth++; + + ParsingDeclState state; + state.SavedStackSize = StackSize; + return state; + } + + /// Observe that we're completed parsing a declaration. + static void popParsingDecl(Sema &S, ParsingDeclState state, Decl *decl); + + /// Observe that we've started processing a different context, the + /// contents of which are semantically separate from the + /// declarations it may lexically appear in. This sets aside the + /// current stack of active diagnostics and starts afresh. + ProcessingContextState pushContext() { + assert(StackSize >= ActiveStackBase); + + ProcessingContextState state; + state.SavedParsingDepth = ParsingDepth; + state.SavedActiveStackBase = ActiveStackBase; + + ActiveStackBase = StackSize; + ParsingDepth = 0; + + return state; + } + + /// Observe that we've stopped processing a context. This + /// restores the previous stack of active diagnostics. + void popContext(ProcessingContextState state) { + assert(ActiveStackBase == StackSize); + assert(ParsingDepth == 0); + ActiveStackBase = state.SavedActiveStackBase; + ParsingDepth = state.SavedParsingDepth; + } + } DelayedDiagnostics; + + /// A RAII object to temporarily push a declaration context. + class ContextRAII { + private: + Sema &S; + DeclContext *SavedContext; + ProcessingContextState SavedContextState; + QualType SavedCXXThisTypeOverride; + + public: + ContextRAII(Sema &S, DeclContext *ContextToPush) + : S(S), SavedContext(S.CurContext), + SavedContextState(S.DelayedDiagnostics.pushContext()), + SavedCXXThisTypeOverride(S.CXXThisTypeOverride) + { + assert(ContextToPush && "pushing null context"); + S.CurContext = ContextToPush; + } + + void pop() { + if (!SavedContext) return; + S.CurContext = SavedContext; + S.DelayedDiagnostics.popContext(SavedContextState); + S.CXXThisTypeOverride = SavedCXXThisTypeOverride; + SavedContext = 0; + } + + ~ContextRAII() { + pop(); + } + }; + + /// WeakUndeclaredIdentifiers - Identifiers contained in + /// #pragma weak before declared. rare. may alias another + /// identifier, declared or undeclared + llvm::DenseMap<IdentifierInfo*,WeakInfo> WeakUndeclaredIdentifiers; + + /// ExtnameUndeclaredIdentifiers - Identifiers contained in + /// #pragma redefine_extname before declared. Used in Solaris system headers + /// to define functions that occur in multiple standards to call the version + /// in the currently selected standard. + llvm::DenseMap<IdentifierInfo*,AsmLabelAttr*> ExtnameUndeclaredIdentifiers; + + + /// \brief Load weak undeclared identifiers from the external source. + void LoadExternalWeakUndeclaredIdentifiers(); + + /// WeakTopLevelDecl - Translation-unit scoped declarations generated by + /// #pragma weak during processing of other Decls. + /// I couldn't figure out a clean way to generate these in-line, so + /// we store them here and handle separately -- which is a hack. + /// It would be best to refactor this. + SmallVector<Decl*,2> WeakTopLevelDecl; + + IdentifierResolver IdResolver; + + /// Translation Unit Scope - useful to Objective-C actions that need + /// to lookup file scope declarations in the "ordinary" C decl namespace. + /// For example, user-defined classes, built-in "id" type, etc. + Scope *TUScope; + + /// \brief The C++ "std" namespace, where the standard library resides. + LazyDeclPtr StdNamespace; + + /// \brief The C++ "std::bad_alloc" class, which is defined by the C++ + /// standard library. + LazyDeclPtr StdBadAlloc; + + /// \brief The C++ "std::initializer_list" template, which is defined in + /// <initializer_list>. + ClassTemplateDecl *StdInitializerList; + + /// \brief The C++ "type_info" declaration, which is defined in <typeinfo>. + RecordDecl *CXXTypeInfoDecl; + + /// \brief The MSVC "_GUID" struct, which is defined in MSVC header files. + RecordDecl *MSVCGuidDecl; + + /// \brief Caches identifiers/selectors for NSFoundation APIs. + llvm::OwningPtr<NSAPI> NSAPIObj; + + /// \brief The declaration of the Objective-C NSNumber class. + ObjCInterfaceDecl *NSNumberDecl; + + /// \brief The Objective-C NSNumber methods used to create NSNumber literals. + ObjCMethodDecl *NSNumberLiteralMethods[NSAPI::NumNSNumberLiteralMethods]; + + /// \brief The declaration of the Objective-C NSArray class. + ObjCInterfaceDecl *NSArrayDecl; + + /// \brief The declaration of the arrayWithObjects:count: method. + ObjCMethodDecl *ArrayWithObjectsMethod; + + /// \brief The declaration of the Objective-C NSDictionary class. + ObjCInterfaceDecl *NSDictionaryDecl; + + /// \brief The declaration of the dictionaryWithObjects:forKeys:count: method. + ObjCMethodDecl *DictionaryWithObjectsMethod; + + /// \brief id<NSCopying> type. + QualType QIDNSCopying; + + /// A flag to remember whether the implicit forms of operator new and delete + /// have been declared. + bool GlobalNewDeleteDeclared; + + /// A flag that is set when parsing a -dealloc method and no [super dealloc] + /// call was found yet. + bool ObjCShouldCallSuperDealloc; + /// A flag that is set when parsing a -finalize method and no [super finalize] + /// call was found yet. + bool ObjCShouldCallSuperFinalize; + + /// \brief Describes how the expressions currently being parsed are + /// evaluated at run-time, if at all. + enum ExpressionEvaluationContext { + /// \brief The current expression and its subexpressions occur within an + /// unevaluated operand (C++11 [expr]p7), such as the subexpression of + /// \c sizeof, where the type of the expression may be significant but + /// no code will be generated to evaluate the value of the expression at + /// run time. + Unevaluated, + + /// \brief The current context is "potentially evaluated" in C++11 terms, + /// but the expression is evaluated at compile-time (like the values of + /// cases in a switch statment). + ConstantEvaluated, + + /// \brief The current expression is potentially evaluated at run time, + /// which means that code may be generated to evaluate the value of the + /// expression at run time. + PotentiallyEvaluated, + + /// \brief The current expression is potentially evaluated, but any + /// declarations referenced inside that expression are only used if + /// in fact the current expression is used. + /// + /// This value is used when parsing default function arguments, for which + /// we would like to provide diagnostics (e.g., passing non-POD arguments + /// through varargs) but do not want to mark declarations as "referenced" + /// until the default argument is used. + PotentiallyEvaluatedIfUsed + }; + + /// \brief Data structure used to record current or nested + /// expression evaluation contexts. + struct ExpressionEvaluationContextRecord { + /// \brief The expression evaluation context. + ExpressionEvaluationContext Context; + + /// \brief Whether the enclosing context needed a cleanup. + bool ParentNeedsCleanups; + + /// \brief Whether we are in a decltype expression. + bool IsDecltype; + + /// \brief The number of active cleanup objects when we entered + /// this expression evaluation context. + unsigned NumCleanupObjects; + + llvm::SmallPtrSet<Expr*, 8> SavedMaybeODRUseExprs; + + /// \brief The lambdas that are present within this context, if it + /// is indeed an unevaluated context. + llvm::SmallVector<LambdaExpr *, 2> Lambdas; + + /// \brief The declaration that provides context for the lambda expression + /// if the normal declaration context does not suffice, e.g., in a + /// default function argument. + Decl *LambdaContextDecl; + + /// \brief The context information used to mangle lambda expressions + /// within this context. + /// + /// This mangling information is allocated lazily, since most contexts + /// do not have lambda expressions. + LambdaMangleContext *LambdaMangle; + + /// \brief If we are processing a decltype type, a set of call expressions + /// for which we have deferred checking the completeness of the return type. + llvm::SmallVector<CallExpr*, 8> DelayedDecltypeCalls; + + /// \brief If we are processing a decltype type, a set of temporary binding + /// expressions for which we have deferred checking the destructor. + llvm::SmallVector<CXXBindTemporaryExpr*, 8> DelayedDecltypeBinds; + + ExpressionEvaluationContextRecord(ExpressionEvaluationContext Context, + unsigned NumCleanupObjects, + bool ParentNeedsCleanups, + Decl *LambdaContextDecl, + bool IsDecltype) + : Context(Context), ParentNeedsCleanups(ParentNeedsCleanups), + IsDecltype(IsDecltype), NumCleanupObjects(NumCleanupObjects), + LambdaContextDecl(LambdaContextDecl), LambdaMangle() { } + + ~ExpressionEvaluationContextRecord() { + delete LambdaMangle; + } + + /// \brief Retrieve the mangling context for lambdas. + LambdaMangleContext &getLambdaMangleContext() { + assert(LambdaContextDecl && "Need to have a lambda context declaration"); + if (!LambdaMangle) + LambdaMangle = new LambdaMangleContext; + return *LambdaMangle; + } + }; + + /// A stack of expression evaluation contexts. + SmallVector<ExpressionEvaluationContextRecord, 8> ExprEvalContexts; + + /// SpecialMemberOverloadResult - The overloading result for a special member + /// function. + /// + /// This is basically a wrapper around PointerIntPair. The lowest bits of the + /// integer are used to determine whether overload resolution succeeded, and + /// whether, when looking up a copy constructor or assignment operator, we + /// found a potential copy constructor/assignment operator whose first + /// parameter is const-qualified. This is used for determining parameter types + /// of other objects and is utterly meaningless on other types of special + /// members. + class SpecialMemberOverloadResult : public llvm::FastFoldingSetNode { + public: + enum Kind { + NoMemberOrDeleted, + Ambiguous, + Success + }; + + private: + llvm::PointerIntPair<CXXMethodDecl*, 2> Pair; + + public: + SpecialMemberOverloadResult(const llvm::FoldingSetNodeID &ID) + : FastFoldingSetNode(ID) + {} + + CXXMethodDecl *getMethod() const { return Pair.getPointer(); } + void setMethod(CXXMethodDecl *MD) { Pair.setPointer(MD); } + + Kind getKind() const { return static_cast<Kind>(Pair.getInt()); } + void setKind(Kind K) { Pair.setInt(K); } + }; + + /// \brief A cache of special member function overload resolution results + /// for C++ records. + llvm::FoldingSet<SpecialMemberOverloadResult> SpecialMemberCache; + + /// \brief The kind of translation unit we are processing. + /// + /// When we're processing a complete translation unit, Sema will perform + /// end-of-translation-unit semantic tasks (such as creating + /// initializers for tentative definitions in C) once parsing has + /// completed. Modules and precompiled headers perform different kinds of + /// checks. + TranslationUnitKind TUKind; + + llvm::BumpPtrAllocator BumpAlloc; + + /// \brief The number of SFINAE diagnostics that have been trapped. + unsigned NumSFINAEErrors; + + typedef llvm::DenseMap<ParmVarDecl *, SmallVector<ParmVarDecl *, 1> > + UnparsedDefaultArgInstantiationsMap; + + /// \brief A mapping from parameters with unparsed default arguments to the + /// set of instantiations of each parameter. + /// + /// This mapping is a temporary data structure used when parsing + /// nested class templates or nested classes of class templates, + /// where we might end up instantiating an inner class before the + /// default arguments of its methods have been parsed. + UnparsedDefaultArgInstantiationsMap UnparsedDefaultArgInstantiations; + + // Contains the locations of the beginning of unparsed default + // argument locations. + llvm::DenseMap<ParmVarDecl *,SourceLocation> UnparsedDefaultArgLocs; + + /// UndefinedInternals - all the used, undefined objects with + /// internal linkage in this translation unit. + llvm::DenseMap<NamedDecl*, SourceLocation> UndefinedInternals; + + typedef std::pair<ObjCMethodList, ObjCMethodList> GlobalMethods; + typedef llvm::DenseMap<Selector, GlobalMethods> GlobalMethodPool; + + /// Method Pool - allows efficient lookup when typechecking messages to "id". + /// We need to maintain a list, since selectors can have differing signatures + /// across classes. In Cocoa, this happens to be extremely uncommon (only 1% + /// of selectors are "overloaded"). + GlobalMethodPool MethodPool; + + /// Method selectors used in a @selector expression. Used for implementation + /// of -Wselector. + llvm::DenseMap<Selector, SourceLocation> ReferencedSelectors; + + void ReadMethodPool(Selector Sel); + + /// Private Helper predicate to check for 'self'. + bool isSelfExpr(Expr *RExpr); + + /// \brief Cause the active diagnostic on the DiagosticsEngine to be + /// emitted. This is closely coupled to the SemaDiagnosticBuilder class and + /// should not be used elsewhere. + void EmitCurrentDiagnostic(unsigned DiagID); + +public: + Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, + TranslationUnitKind TUKind = TU_Complete, + CodeCompleteConsumer *CompletionConsumer = 0); + ~Sema(); + + /// \brief Perform initialization that occurs after the parser has been + /// initialized but before it parses anything. + void Initialize(); + + const LangOptions &getLangOpts() const { return LangOpts; } + OpenCLOptions &getOpenCLOptions() { return OpenCLFeatures; } + FPOptions &getFPOptions() { return FPFeatures; } + + DiagnosticsEngine &getDiagnostics() const { return Diags; } + SourceManager &getSourceManager() const { return SourceMgr; } + const TargetAttributesSema &getTargetAttributesSema() const; + Preprocessor &getPreprocessor() const { return PP; } + ASTContext &getASTContext() const { return Context; } + ASTConsumer &getASTConsumer() const { return Consumer; } + ASTMutationListener *getASTMutationListener() const; + + void PrintStats() const; + + /// \brief Helper class that creates diagnostics with optional + /// template instantiation stacks. + /// + /// This class provides a wrapper around the basic DiagnosticBuilder + /// class that emits diagnostics. SemaDiagnosticBuilder is + /// responsible for emitting the diagnostic (as DiagnosticBuilder + /// does) and, if the diagnostic comes from inside a template + /// instantiation, printing the template instantiation stack as + /// well. + class SemaDiagnosticBuilder : public DiagnosticBuilder { + Sema &SemaRef; + unsigned DiagID; + + public: + SemaDiagnosticBuilder(DiagnosticBuilder &DB, Sema &SemaRef, unsigned DiagID) + : DiagnosticBuilder(DB), SemaRef(SemaRef), DiagID(DiagID) { } + + ~SemaDiagnosticBuilder() { + // If we aren't active, there is nothing to do. + if (!isActive()) return; + + // Otherwise, we need to emit the diagnostic. First flush the underlying + // DiagnosticBuilder data, and clear the diagnostic builder itself so it + // won't emit the diagnostic in its own destructor. + // + // This seems wasteful, in that as written the DiagnosticBuilder dtor will + // do its own needless checks to see if the diagnostic needs to be + // emitted. However, because we take care to ensure that the builder + // objects never escape, a sufficiently smart compiler will be able to + // eliminate that code. + FlushCounts(); + Clear(); + + // Dispatch to Sema to emit the diagnostic. + SemaRef.EmitCurrentDiagnostic(DiagID); + } + }; + + /// \brief Emit a diagnostic. + SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) { + DiagnosticBuilder DB = Diags.Report(Loc, DiagID); + return SemaDiagnosticBuilder(DB, *this, DiagID); + } + + /// \brief Emit a partial diagnostic. + SemaDiagnosticBuilder Diag(SourceLocation Loc, const PartialDiagnostic& PD); + + /// \brief Build a partial diagnostic. + PartialDiagnostic PDiag(unsigned DiagID = 0); // in SemaInternal.h + + bool findMacroSpelling(SourceLocation &loc, StringRef name); + + /// \brief Get a string to suggest for zero-initialization of a type. + const char *getFixItZeroInitializerForType(QualType T) const; + + ExprResult Owned(Expr* E) { return E; } + ExprResult Owned(ExprResult R) { return R; } + StmtResult Owned(Stmt* S) { return S; } + + void ActOnEndOfTranslationUnit(); + + void CheckDelegatingCtorCycles(); + + Scope *getScopeForContext(DeclContext *Ctx); + + void PushFunctionScope(); + void PushBlockScope(Scope *BlockScope, BlockDecl *Block); + void PushLambdaScope(CXXRecordDecl *Lambda, CXXMethodDecl *CallOperator); + void PopFunctionScopeInfo(const sema::AnalysisBasedWarnings::Policy *WP =0, + const Decl *D = 0, const BlockExpr *blkExpr = 0); + + sema::FunctionScopeInfo *getCurFunction() const { + return FunctionScopes.back(); + } + + void PushCompoundScope(); + void PopCompoundScope(); + + sema::CompoundScopeInfo &getCurCompoundScope() const; + + bool hasAnyUnrecoverableErrorsInThisFunction() const; + + /// \brief Retrieve the current block, if any. + sema::BlockScopeInfo *getCurBlock(); + + /// \brief Retrieve the current lambda expression, if any. + sema::LambdaScopeInfo *getCurLambda(); + + /// WeakTopLevelDeclDecls - access to #pragma weak-generated Decls + SmallVector<Decl*,2> &WeakTopLevelDecls() { return WeakTopLevelDecl; } + + //===--------------------------------------------------------------------===// + // Type Analysis / Processing: SemaType.cpp. + // + + QualType BuildQualifiedType(QualType T, SourceLocation Loc, Qualifiers Qs); + QualType BuildQualifiedType(QualType T, SourceLocation Loc, unsigned CVR) { + return BuildQualifiedType(T, Loc, Qualifiers::fromCVRMask(CVR)); + } + QualType BuildPointerType(QualType T, + SourceLocation Loc, DeclarationName Entity); + QualType BuildReferenceType(QualType T, bool LValueRef, + SourceLocation Loc, DeclarationName Entity); + QualType BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, + Expr *ArraySize, unsigned Quals, + SourceRange Brackets, DeclarationName Entity); + QualType BuildExtVectorType(QualType T, Expr *ArraySize, + SourceLocation AttrLoc); + QualType BuildFunctionType(QualType T, + QualType *ParamTypes, unsigned NumParamTypes, + bool Variadic, bool HasTrailingReturn, + unsigned Quals, RefQualifierKind RefQualifier, + SourceLocation Loc, DeclarationName Entity, + FunctionType::ExtInfo Info); + QualType BuildMemberPointerType(QualType T, QualType Class, + SourceLocation Loc, + DeclarationName Entity); + QualType BuildBlockPointerType(QualType T, + SourceLocation Loc, DeclarationName Entity); + QualType BuildParenType(QualType T); + QualType BuildAtomicType(QualType T, SourceLocation Loc); + + TypeSourceInfo *GetTypeForDeclarator(Declarator &D, Scope *S); + TypeSourceInfo *GetTypeForDeclaratorCast(Declarator &D, QualType FromTy); + TypeSourceInfo *GetTypeSourceInfoForDeclarator(Declarator &D, QualType T, + TypeSourceInfo *ReturnTypeInfo); + + /// \brief Package the given type and TSI into a ParsedType. + ParsedType CreateParsedType(QualType T, TypeSourceInfo *TInfo); + DeclarationNameInfo GetNameForDeclarator(Declarator &D); + DeclarationNameInfo GetNameFromUnqualifiedId(const UnqualifiedId &Name); + static QualType GetTypeFromParser(ParsedType Ty, TypeSourceInfo **TInfo = 0); + CanThrowResult canThrow(const Expr *E); + const FunctionProtoType *ResolveExceptionSpec(SourceLocation Loc, + const FunctionProtoType *FPT); + bool CheckSpecifiedExceptionType(QualType T, const SourceRange &Range); + bool CheckDistantExceptionSpec(QualType T); + bool CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New); + bool CheckEquivalentExceptionSpec( + const FunctionProtoType *Old, SourceLocation OldLoc, + const FunctionProtoType *New, SourceLocation NewLoc); + bool CheckEquivalentExceptionSpec( + const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID, + const FunctionProtoType *Old, SourceLocation OldLoc, + const FunctionProtoType *New, SourceLocation NewLoc, + bool *MissingExceptionSpecification = 0, + bool *MissingEmptyExceptionSpecification = 0, + bool AllowNoexceptAllMatchWithNoSpec = false, + bool IsOperatorNew = false); + bool CheckExceptionSpecSubset( + const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID, + const FunctionProtoType *Superset, SourceLocation SuperLoc, + const FunctionProtoType *Subset, SourceLocation SubLoc); + bool CheckParamExceptionSpec(const PartialDiagnostic & NoteID, + const FunctionProtoType *Target, SourceLocation TargetLoc, + const FunctionProtoType *Source, SourceLocation SourceLoc); + + TypeResult ActOnTypeName(Scope *S, Declarator &D); + + /// \brief The parser has parsed the context-sensitive type 'instancetype' + /// in an Objective-C message declaration. Return the appropriate type. + ParsedType ActOnObjCInstanceType(SourceLocation Loc); + + bool RequireCompleteType(SourceLocation Loc, QualType T, + const PartialDiagnostic &PD, + std::pair<SourceLocation, PartialDiagnostic> Note); + bool RequireCompleteType(SourceLocation Loc, QualType T, + const PartialDiagnostic &PD); + bool RequireCompleteType(SourceLocation Loc, QualType T, + unsigned DiagID); + bool RequireCompleteExprType(Expr *E, const PartialDiagnostic &PD, + std::pair<SourceLocation, + PartialDiagnostic> Note); + + bool RequireLiteralType(SourceLocation Loc, QualType T, + const PartialDiagnostic &PD); + + QualType getElaboratedType(ElaboratedTypeKeyword Keyword, + const CXXScopeSpec &SS, QualType T); + + QualType BuildTypeofExprType(Expr *E, SourceLocation Loc); + QualType BuildDecltypeType(Expr *E, SourceLocation Loc); + QualType BuildUnaryTransformType(QualType BaseType, + UnaryTransformType::UTTKind UKind, + SourceLocation Loc); + + //===--------------------------------------------------------------------===// + // Symbol table / Decl tracking callbacks: SemaDecl.cpp. + // + + /// List of decls defined in a function prototype. This contains EnumConstants + /// that incorrectly end up in translation unit scope because there is no + /// function to pin them on. ActOnFunctionDeclarator reads this list and patches + /// them into the FunctionDecl. + std::vector<NamedDecl*> DeclsInPrototypeScope; + /// Nonzero if we are currently parsing a function declarator. This is a counter + /// as opposed to a boolean so we can deal with nested function declarators + /// such as: + /// void f(void (*g)(), ...) + unsigned InFunctionDeclarator; + + DeclGroupPtrTy ConvertDeclToDeclGroup(Decl *Ptr, Decl *OwnedType = 0); + + void DiagnoseUseOfUnimplementedSelectors(); + + ParsedType getTypeName(IdentifierInfo &II, SourceLocation NameLoc, + Scope *S, CXXScopeSpec *SS = 0, + bool isClassName = false, + bool HasTrailingDot = false, + ParsedType ObjectType = ParsedType(), + bool IsCtorOrDtorName = false, + bool WantNontrivialTypeSourceInfo = false, + IdentifierInfo **CorrectedII = 0); + TypeSpecifierType isTagName(IdentifierInfo &II, Scope *S); + bool isMicrosoftMissingTypename(const CXXScopeSpec *SS, Scope *S); + bool DiagnoseUnknownTypeName(const IdentifierInfo &II, + SourceLocation IILoc, + Scope *S, + CXXScopeSpec *SS, + ParsedType &SuggestedType); + + /// \brief Describes the result of the name lookup and resolution performed + /// by \c ClassifyName(). + enum NameClassificationKind { + NC_Unknown, + NC_Error, + NC_Keyword, + NC_Type, + NC_Expression, + NC_NestedNameSpecifier, + NC_TypeTemplate, + NC_FunctionTemplate + }; + + class NameClassification { + NameClassificationKind Kind; + ExprResult Expr; + TemplateName Template; + ParsedType Type; + const IdentifierInfo *Keyword; + + explicit NameClassification(NameClassificationKind Kind) : Kind(Kind) {} + + public: + NameClassification(ExprResult Expr) : Kind(NC_Expression), Expr(Expr) {} + + NameClassification(ParsedType Type) : Kind(NC_Type), Type(Type) {} + + NameClassification(const IdentifierInfo *Keyword) + : Kind(NC_Keyword), Keyword(Keyword) { } + + static NameClassification Error() { + return NameClassification(NC_Error); + } + + static NameClassification Unknown() { + return NameClassification(NC_Unknown); + } + + static NameClassification NestedNameSpecifier() { + return NameClassification(NC_NestedNameSpecifier); + } + + static NameClassification TypeTemplate(TemplateName Name) { + NameClassification Result(NC_TypeTemplate); + Result.Template = Name; + return Result; + } + + static NameClassification FunctionTemplate(TemplateName Name) { + NameClassification Result(NC_FunctionTemplate); + Result.Template = Name; + return Result; + } + + NameClassificationKind getKind() const { return Kind; } + + ParsedType getType() const { + assert(Kind == NC_Type); + return Type; + } + + ExprResult getExpression() const { + assert(Kind == NC_Expression); + return Expr; + } + + TemplateName getTemplateName() const { + assert(Kind == NC_TypeTemplate || Kind == NC_FunctionTemplate); + return Template; + } + + TemplateNameKind getTemplateNameKind() const { + assert(Kind == NC_TypeTemplate || Kind == NC_FunctionTemplate); + return Kind == NC_TypeTemplate? TNK_Type_template : TNK_Function_template; + } +}; + + /// \brief Perform name lookup on the given name, classifying it based on + /// the results of name lookup and the following token. + /// + /// This routine is used by the parser to resolve identifiers and help direct + /// parsing. When the identifier cannot be found, this routine will attempt + /// to correct the typo and classify based on the resulting name. + /// + /// \param S The scope in which we're performing name lookup. + /// + /// \param SS The nested-name-specifier that precedes the name. + /// + /// \param Name The identifier. If typo correction finds an alternative name, + /// this pointer parameter will be updated accordingly. + /// + /// \param NameLoc The location of the identifier. + /// + /// \param NextToken The token following the identifier. Used to help + /// disambiguate the name. + NameClassification ClassifyName(Scope *S, + CXXScopeSpec &SS, + IdentifierInfo *&Name, + SourceLocation NameLoc, + const Token &NextToken); + + Decl *ActOnDeclarator(Scope *S, Declarator &D); + + Decl *HandleDeclarator(Scope *S, Declarator &D, + MultiTemplateParamsArg TemplateParameterLists); + void RegisterLocallyScopedExternCDecl(NamedDecl *ND, + const LookupResult &Previous, + Scope *S); + bool DiagnoseClassNameShadow(DeclContext *DC, DeclarationNameInfo Info); + bool diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC, + DeclarationName Name, + SourceLocation Loc); + void DiagnoseFunctionSpecifiers(Declarator& D); + void CheckShadow(Scope *S, VarDecl *D, const LookupResult& R); + void CheckShadow(Scope *S, VarDecl *D); + void CheckCastAlign(Expr *Op, QualType T, SourceRange TRange); + void CheckTypedefForVariablyModifiedType(Scope *S, TypedefNameDecl *D); + NamedDecl* ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, + TypeSourceInfo *TInfo, + LookupResult &Previous); + NamedDecl* ActOnTypedefNameDecl(Scope* S, DeclContext* DC, TypedefNameDecl *D, + LookupResult &Previous, bool &Redeclaration); + NamedDecl* ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, + TypeSourceInfo *TInfo, + LookupResult &Previous, + MultiTemplateParamsArg TemplateParamLists); + // Returns true if the variable declaration is a redeclaration + bool CheckVariableDeclaration(VarDecl *NewVD, LookupResult &Previous); + void CheckCompleteVariableDeclaration(VarDecl *var); + void ActOnStartFunctionDeclarator(); + void ActOnEndFunctionDeclarator(); + NamedDecl* ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, + TypeSourceInfo *TInfo, + LookupResult &Previous, + MultiTemplateParamsArg TemplateParamLists, + bool &AddToScope); + bool AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD); + + bool CheckConstexprFunctionDecl(const FunctionDecl *FD); + bool CheckConstexprFunctionBody(const FunctionDecl *FD, Stmt *Body); + + void DiagnoseHiddenVirtualMethods(CXXRecordDecl *DC, CXXMethodDecl *MD); + // Returns true if the function declaration is a redeclaration + bool CheckFunctionDeclaration(Scope *S, + FunctionDecl *NewFD, LookupResult &Previous, + bool IsExplicitSpecialization); + void CheckMain(FunctionDecl *FD, const DeclSpec &D); + Decl *ActOnParamDeclarator(Scope *S, Declarator &D); + ParmVarDecl *BuildParmVarDeclForTypedef(DeclContext *DC, + SourceLocation Loc, + QualType T); + ParmVarDecl *CheckParameter(DeclContext *DC, SourceLocation StartLoc, + SourceLocation NameLoc, IdentifierInfo *Name, + QualType T, TypeSourceInfo *TSInfo, + StorageClass SC, StorageClass SCAsWritten); + void ActOnParamDefaultArgument(Decl *param, + SourceLocation EqualLoc, + Expr *defarg); + void ActOnParamUnparsedDefaultArgument(Decl *param, + SourceLocation EqualLoc, + SourceLocation ArgLoc); + void ActOnParamDefaultArgumentError(Decl *param); + bool SetParamDefaultArgument(ParmVarDecl *Param, Expr *DefaultArg, + SourceLocation EqualLoc); + + void CheckSelfReference(Decl *OrigDecl, Expr *E); + void AddInitializerToDecl(Decl *dcl, Expr *init, bool DirectInit, + bool TypeMayContainAuto); + void ActOnUninitializedDecl(Decl *dcl, bool TypeMayContainAuto); + void ActOnInitializerError(Decl *Dcl); + void ActOnCXXForRangeDecl(Decl *D); + void SetDeclDeleted(Decl *dcl, SourceLocation DelLoc); + void SetDeclDefaulted(Decl *dcl, SourceLocation DefaultLoc); + void FinalizeDeclaration(Decl *D); + DeclGroupPtrTy FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS, + Decl **Group, + unsigned NumDecls); + DeclGroupPtrTy BuildDeclaratorGroup(Decl **Group, unsigned NumDecls, + bool TypeMayContainAuto = true); + void ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D, + SourceLocation LocAfterDecls); + void CheckForFunctionRedefinition(FunctionDecl *FD); + Decl *ActOnStartOfFunctionDef(Scope *S, Declarator &D); + Decl *ActOnStartOfFunctionDef(Scope *S, Decl *D); + void ActOnStartOfObjCMethodDef(Scope *S, Decl *D); + + void computeNRVO(Stmt *Body, sema::FunctionScopeInfo *Scope); + Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body); + Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body, bool IsInstantiation); + + /// ActOnFinishDelayedAttribute - Invoked when we have finished parsing an + /// attribute for which parsing is delayed. + void ActOnFinishDelayedAttribute(Scope *S, Decl *D, ParsedAttributes &Attrs); + + /// \brief Diagnose any unused parameters in the given sequence of + /// ParmVarDecl pointers. + void DiagnoseUnusedParameters(ParmVarDecl * const *Begin, + ParmVarDecl * const *End); + + /// \brief Diagnose whether the size of parameters or return value of a + /// function or obj-c method definition is pass-by-value and larger than a + /// specified threshold. + void DiagnoseSizeOfParametersAndReturnValue(ParmVarDecl * const *Begin, + ParmVarDecl * const *End, + QualType ReturnTy, + NamedDecl *D); + + void DiagnoseInvalidJumps(Stmt *Body); + Decl *ActOnFileScopeAsmDecl(Expr *expr, + SourceLocation AsmLoc, + SourceLocation RParenLoc); + + /// \brief The parser has processed a module import declaration. + /// + /// \param AtLoc The location of the '@' symbol, if any. + /// + /// \param ImportLoc The location of the 'import' keyword. + /// + /// \param Path The module access path. + DeclResult ActOnModuleImport(SourceLocation AtLoc, SourceLocation ImportLoc, + ModuleIdPath Path); + + /// \brief Retrieve a suitable printing policy. + PrintingPolicy getPrintingPolicy() const { + return getPrintingPolicy(Context, PP); + } + + /// \brief Retrieve a suitable printing policy. + static PrintingPolicy getPrintingPolicy(const ASTContext &Ctx, + const Preprocessor &PP); + + /// Scope actions. + void ActOnPopScope(SourceLocation Loc, Scope *S); + void ActOnTranslationUnitScope(Scope *S); + + Decl *ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, + DeclSpec &DS); + Decl *ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, + DeclSpec &DS, + MultiTemplateParamsArg TemplateParams); + + Decl *BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, + AccessSpecifier AS, + RecordDecl *Record); + + Decl *BuildMicrosoftCAnonymousStruct(Scope *S, DeclSpec &DS, + RecordDecl *Record); + + bool isAcceptableTagRedeclaration(const TagDecl *Previous, + TagTypeKind NewTag, bool isDefinition, + SourceLocation NewTagLoc, + const IdentifierInfo &Name); + + enum TagUseKind { + TUK_Reference, // Reference to a tag: 'struct foo *X;' + TUK_Declaration, // Fwd decl of a tag: 'struct foo;' + TUK_Definition, // Definition of a tag: 'struct foo { int X; } Y;' + TUK_Friend // Friend declaration: 'friend struct foo;' + }; + + Decl *ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, + SourceLocation KWLoc, CXXScopeSpec &SS, + IdentifierInfo *Name, SourceLocation NameLoc, + AttributeList *Attr, AccessSpecifier AS, + SourceLocation ModulePrivateLoc, + MultiTemplateParamsArg TemplateParameterLists, + bool &OwnedDecl, bool &IsDependent, + SourceLocation ScopedEnumKWLoc, + bool ScopedEnumUsesClassTag, TypeResult UnderlyingType); + + Decl *ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, + unsigned TagSpec, SourceLocation TagLoc, + CXXScopeSpec &SS, + IdentifierInfo *Name, SourceLocation NameLoc, + AttributeList *Attr, + MultiTemplateParamsArg TempParamLists); + + TypeResult ActOnDependentTag(Scope *S, + unsigned TagSpec, + TagUseKind TUK, + const CXXScopeSpec &SS, + IdentifierInfo *Name, + SourceLocation TagLoc, + SourceLocation NameLoc); + + void ActOnDefs(Scope *S, Decl *TagD, SourceLocation DeclStart, + IdentifierInfo *ClassName, + SmallVectorImpl<Decl *> &Decls); + Decl *ActOnField(Scope *S, Decl *TagD, SourceLocation DeclStart, + Declarator &D, Expr *BitfieldWidth); + + FieldDecl *HandleField(Scope *S, RecordDecl *TagD, SourceLocation DeclStart, + Declarator &D, Expr *BitfieldWidth, bool HasInit, + AccessSpecifier AS); + + FieldDecl *CheckFieldDecl(DeclarationName Name, QualType T, + TypeSourceInfo *TInfo, + RecordDecl *Record, SourceLocation Loc, + bool Mutable, Expr *BitfieldWidth, bool HasInit, + SourceLocation TSSL, + AccessSpecifier AS, NamedDecl *PrevDecl, + Declarator *D = 0); + + enum CXXSpecialMember { + CXXDefaultConstructor, + CXXCopyConstructor, + CXXMoveConstructor, + CXXCopyAssignment, + CXXMoveAssignment, + CXXDestructor, + CXXInvalid + }; + bool CheckNontrivialField(FieldDecl *FD); + void DiagnoseNontrivial(const RecordType* Record, CXXSpecialMember mem); + CXXSpecialMember getSpecialMember(const CXXMethodDecl *MD); + void ActOnLastBitfield(SourceLocation DeclStart, + SmallVectorImpl<Decl *> &AllIvarDecls); + Decl *ActOnIvar(Scope *S, SourceLocation DeclStart, + Declarator &D, Expr *BitfieldWidth, + tok::ObjCKeywordKind visibility); + + // This is used for both record definitions and ObjC interface declarations. + void ActOnFields(Scope* S, SourceLocation RecLoc, Decl *TagDecl, + llvm::ArrayRef<Decl *> Fields, + SourceLocation LBrac, SourceLocation RBrac, + AttributeList *AttrList); + + /// ActOnTagStartDefinition - Invoked when we have entered the + /// scope of a tag's definition (e.g., for an enumeration, class, + /// struct, or union). + void ActOnTagStartDefinition(Scope *S, Decl *TagDecl); + + Decl *ActOnObjCContainerStartDefinition(Decl *IDecl); + + /// ActOnStartCXXMemberDeclarations - Invoked when we have parsed a + /// C++ record definition's base-specifiers clause and are starting its + /// member declarations. + void ActOnStartCXXMemberDeclarations(Scope *S, Decl *TagDecl, + SourceLocation FinalLoc, + SourceLocation LBraceLoc); + + /// ActOnTagFinishDefinition - Invoked once we have finished parsing + /// the definition of a tag (enumeration, class, struct, or union). + void ActOnTagFinishDefinition(Scope *S, Decl *TagDecl, + SourceLocation RBraceLoc); + + void ActOnObjCContainerFinishDefinition(); + + /// \brief Invoked when we must temporarily exit the objective-c container + /// scope for parsing/looking-up C constructs. + /// + /// Must be followed by a call to \see ActOnObjCReenterContainerContext + void ActOnObjCTemporaryExitContainerContext(DeclContext *DC); + void ActOnObjCReenterContainerContext(DeclContext *DC); + + /// ActOnTagDefinitionError - Invoked when there was an unrecoverable + /// error parsing the definition of a tag. + void ActOnTagDefinitionError(Scope *S, Decl *TagDecl); + + EnumConstantDecl *CheckEnumConstant(EnumDecl *Enum, + EnumConstantDecl *LastEnumConst, + SourceLocation IdLoc, + IdentifierInfo *Id, + Expr *val); + bool CheckEnumUnderlyingType(TypeSourceInfo *TI); + bool CheckEnumRedeclaration(SourceLocation EnumLoc, bool IsScoped, + QualType EnumUnderlyingTy, const EnumDecl *Prev); + + Decl *ActOnEnumConstant(Scope *S, Decl *EnumDecl, Decl *LastEnumConstant, + SourceLocation IdLoc, IdentifierInfo *Id, + AttributeList *Attrs, + SourceLocation EqualLoc, Expr *Val); + void ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, + SourceLocation RBraceLoc, Decl *EnumDecl, + Decl **Elements, unsigned NumElements, + Scope *S, AttributeList *Attr); + + DeclContext *getContainingDC(DeclContext *DC); + + /// Set the current declaration context until it gets popped. + void PushDeclContext(Scope *S, DeclContext *DC); + void PopDeclContext(); + + /// EnterDeclaratorContext - Used when we must lookup names in the context + /// of a declarator's nested name specifier. + void EnterDeclaratorContext(Scope *S, DeclContext *DC); + void ExitDeclaratorContext(Scope *S); + + /// Push the parameters of D, which must be a function, into scope. + void ActOnReenterFunctionContext(Scope* S, Decl* D); + void ActOnExitFunctionContext(); + + DeclContext *getFunctionLevelDeclContext(); + + /// getCurFunctionDecl - If inside of a function body, this returns a pointer + /// to the function decl for the function being parsed. If we're currently + /// in a 'block', this returns the containing context. + FunctionDecl *getCurFunctionDecl(); + + /// getCurMethodDecl - If inside of a method body, this returns a pointer to + /// the method decl for the method being parsed. If we're currently + /// in a 'block', this returns the containing context. + ObjCMethodDecl *getCurMethodDecl(); + + /// getCurFunctionOrMethodDecl - Return the Decl for the current ObjC method + /// or C function we're in, otherwise return null. If we're currently + /// in a 'block', this returns the containing context. + NamedDecl *getCurFunctionOrMethodDecl(); + + /// Add this decl to the scope shadowed decl chains. + void PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext = true); + + /// \brief Make the given externally-produced declaration visible at the + /// top level scope. + /// + /// \param D The externally-produced declaration to push. + /// + /// \param Name The name of the externally-produced declaration. + void pushExternalDeclIntoScope(NamedDecl *D, DeclarationName Name); + + /// isDeclInScope - If 'Ctx' is a function/method, isDeclInScope returns true + /// if 'D' is in Scope 'S', otherwise 'S' is ignored and isDeclInScope returns + /// true if 'D' belongs to the given declaration context. + /// + /// \param ExplicitInstantiationOrSpecialization When true, we are checking + /// whether the declaration is in scope for the purposes of explicit template + /// instantiation or specialization. The default is false. + bool isDeclInScope(NamedDecl *&D, DeclContext *Ctx, Scope *S = 0, + bool ExplicitInstantiationOrSpecialization = false); + + /// Finds the scope corresponding to the given decl context, if it + /// happens to be an enclosing scope. Otherwise return NULL. + static Scope *getScopeForDeclContext(Scope *S, DeclContext *DC); + + /// Subroutines of ActOnDeclarator(). + TypedefDecl *ParseTypedefDecl(Scope *S, Declarator &D, QualType T, + TypeSourceInfo *TInfo); + bool isIncompatibleTypedef(TypeDecl *Old, TypedefNameDecl *New); + void mergeDeclAttributes(Decl *New, Decl *Old, bool MergeDeprecation = true); + void MergeTypedefNameDecl(TypedefNameDecl *New, LookupResult &OldDecls); + bool MergeFunctionDecl(FunctionDecl *New, Decl *Old, Scope *S); + bool MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old, + Scope *S); + void mergeObjCMethodDecls(ObjCMethodDecl *New, ObjCMethodDecl *Old); + void MergeVarDecl(VarDecl *New, LookupResult &OldDecls); + void MergeVarDeclTypes(VarDecl *New, VarDecl *Old); + void MergeVarDeclExceptionSpecs(VarDecl *New, VarDecl *Old); + bool MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, Scope *S); + + // AssignmentAction - This is used by all the assignment diagnostic functions + // to represent what is actually causing the operation + enum AssignmentAction { + AA_Assigning, + AA_Passing, + AA_Returning, + AA_Converting, + AA_Initializing, + AA_Sending, + AA_Casting + }; + + /// C++ Overloading. + enum OverloadKind { + /// This is a legitimate overload: the existing declarations are + /// functions or function templates with different signatures. + Ovl_Overload, + + /// This is not an overload because the signature exactly matches + /// an existing declaration. + Ovl_Match, + + /// This is not an overload because the lookup results contain a + /// non-function. + Ovl_NonFunction + }; + OverloadKind CheckOverload(Scope *S, + FunctionDecl *New, + const LookupResult &OldDecls, + NamedDecl *&OldDecl, + bool IsForUsingDecl); + bool IsOverload(FunctionDecl *New, FunctionDecl *Old, bool IsForUsingDecl); + + /// \brief Checks availability of the function depending on the current + /// function context.Inside an unavailable function,unavailability is ignored. + /// + /// \returns true if \arg FD is unavailable and current context is inside + /// an available function, false otherwise. + bool isFunctionConsideredUnavailable(FunctionDecl *FD); + + ImplicitConversionSequence + TryImplicitConversion(Expr *From, QualType ToType, + bool SuppressUserConversions, + bool AllowExplicit, + bool InOverloadResolution, + bool CStyle, + bool AllowObjCWritebackConversion); + + bool IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType); + bool IsFloatingPointPromotion(QualType FromType, QualType ToType); + bool IsComplexPromotion(QualType FromType, QualType ToType); + bool IsPointerConversion(Expr *From, QualType FromType, QualType ToType, + bool InOverloadResolution, + QualType& ConvertedType, bool &IncompatibleObjC); + bool isObjCPointerConversion(QualType FromType, QualType ToType, + QualType& ConvertedType, bool &IncompatibleObjC); + bool isObjCWritebackConversion(QualType FromType, QualType ToType, + QualType &ConvertedType); + bool IsBlockPointerConversion(QualType FromType, QualType ToType, + QualType& ConvertedType); + bool FunctionArgTypesAreEqual(const FunctionProtoType *OldType, + const FunctionProtoType *NewType, + unsigned *ArgPos = 0); + void HandleFunctionTypeMismatch(PartialDiagnostic &PDiag, + QualType FromType, QualType ToType); + + CastKind PrepareCastToObjCObjectPointer(ExprResult &E); + bool CheckPointerConversion(Expr *From, QualType ToType, + CastKind &Kind, + CXXCastPath& BasePath, + bool IgnoreBaseAccess); + bool IsMemberPointerConversion(Expr *From, QualType FromType, QualType ToType, + bool InOverloadResolution, + QualType &ConvertedType); + bool CheckMemberPointerConversion(Expr *From, QualType ToType, + CastKind &Kind, + CXXCastPath &BasePath, + bool IgnoreBaseAccess); + bool IsQualificationConversion(QualType FromType, QualType ToType, + bool CStyle, bool &ObjCLifetimeConversion); + bool IsNoReturnConversion(QualType FromType, QualType ToType, + QualType &ResultTy); + bool DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType); + + + ExprResult PerformMoveOrCopyInitialization(const InitializedEntity &Entity, + const VarDecl *NRVOCandidate, + QualType ResultType, + Expr *Value, + bool AllowNRVO = true); + + bool CanPerformCopyInitialization(const InitializedEntity &Entity, + ExprResult Init); + ExprResult PerformCopyInitialization(const InitializedEntity &Entity, + SourceLocation EqualLoc, + ExprResult Init, + bool TopLevelOfInitList = false, + bool AllowExplicit = false); + ExprResult PerformObjectArgumentInitialization(Expr *From, + NestedNameSpecifier *Qualifier, + NamedDecl *FoundDecl, + CXXMethodDecl *Method); + + ExprResult PerformContextuallyConvertToBool(Expr *From); + ExprResult PerformContextuallyConvertToObjCPointer(Expr *From); + + /// Contexts in which a converted constant expression is required. + enum CCEKind { + CCEK_CaseValue, ///< Expression in a case label. + CCEK_Enumerator, ///< Enumerator value with fixed underlying type. + CCEK_TemplateArg ///< Value of a non-type template parameter. + }; + ExprResult CheckConvertedConstantExpression(Expr *From, QualType T, + llvm::APSInt &Value, CCEKind CCE); + + ExprResult + ConvertToIntegralOrEnumerationType(SourceLocation Loc, Expr *FromE, + const PartialDiagnostic &NotIntDiag, + const PartialDiagnostic &IncompleteDiag, + const PartialDiagnostic &ExplicitConvDiag, + const PartialDiagnostic &ExplicitConvNote, + const PartialDiagnostic &AmbigDiag, + const PartialDiagnostic &AmbigNote, + const PartialDiagnostic &ConvDiag, + bool AllowScopedEnumerations); + enum ObjCSubscriptKind { + OS_Array, + OS_Dictionary, + OS_Error + }; + ObjCSubscriptKind CheckSubscriptingKind(Expr *FromE); + + ExprResult PerformObjectMemberConversion(Expr *From, + NestedNameSpecifier *Qualifier, + NamedDecl *FoundDecl, + NamedDecl *Member); + + // Members have to be NamespaceDecl* or TranslationUnitDecl*. + // TODO: make this is a typesafe union. + typedef llvm::SmallPtrSet<DeclContext *, 16> AssociatedNamespaceSet; + typedef llvm::SmallPtrSet<CXXRecordDecl *, 16> AssociatedClassSet; + + void AddOverloadCandidate(FunctionDecl *Function, + DeclAccessPair FoundDecl, + llvm::ArrayRef<Expr *> Args, + OverloadCandidateSet& CandidateSet, + bool SuppressUserConversions = false, + bool PartialOverloading = false, + bool AllowExplicit = false); + void AddFunctionCandidates(const UnresolvedSetImpl &Functions, + llvm::ArrayRef<Expr *> Args, + OverloadCandidateSet& CandidateSet, + bool SuppressUserConversions = false, + TemplateArgumentListInfo *ExplicitTemplateArgs = 0); + void AddMethodCandidate(DeclAccessPair FoundDecl, + QualType ObjectType, + Expr::Classification ObjectClassification, + Expr **Args, unsigned NumArgs, + OverloadCandidateSet& CandidateSet, + bool SuppressUserConversion = false); + void AddMethodCandidate(CXXMethodDecl *Method, + DeclAccessPair FoundDecl, + CXXRecordDecl *ActingContext, QualType ObjectType, + Expr::Classification ObjectClassification, + llvm::ArrayRef<Expr *> Args, + OverloadCandidateSet& CandidateSet, + bool SuppressUserConversions = false); + void AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, + DeclAccessPair FoundDecl, + CXXRecordDecl *ActingContext, + TemplateArgumentListInfo *ExplicitTemplateArgs, + QualType ObjectType, + Expr::Classification ObjectClassification, + llvm::ArrayRef<Expr *> Args, + OverloadCandidateSet& CandidateSet, + bool SuppressUserConversions = false); + void AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, + DeclAccessPair FoundDecl, + TemplateArgumentListInfo *ExplicitTemplateArgs, + llvm::ArrayRef<Expr *> Args, + OverloadCandidateSet& CandidateSet, + bool SuppressUserConversions = false); + void AddConversionCandidate(CXXConversionDecl *Conversion, + DeclAccessPair FoundDecl, + CXXRecordDecl *ActingContext, + Expr *From, QualType ToType, + OverloadCandidateSet& CandidateSet); + void AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate, + DeclAccessPair FoundDecl, + CXXRecordDecl *ActingContext, + Expr *From, QualType ToType, + OverloadCandidateSet &CandidateSet); + void AddSurrogateCandidate(CXXConversionDecl *Conversion, + DeclAccessPair FoundDecl, + CXXRecordDecl *ActingContext, + const FunctionProtoType *Proto, + Expr *Object, llvm::ArrayRef<Expr*> Args, + OverloadCandidateSet& CandidateSet); + void AddMemberOperatorCandidates(OverloadedOperatorKind Op, + SourceLocation OpLoc, + Expr **Args, unsigned NumArgs, + OverloadCandidateSet& CandidateSet, + SourceRange OpRange = SourceRange()); + void AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys, + Expr **Args, unsigned NumArgs, + OverloadCandidateSet& CandidateSet, + bool IsAssignmentOperator = false, + unsigned NumContextualBoolArguments = 0); + void AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, + SourceLocation OpLoc, + Expr **Args, unsigned NumArgs, + OverloadCandidateSet& CandidateSet); + void AddArgumentDependentLookupCandidates(DeclarationName Name, + bool Operator, SourceLocation Loc, + llvm::ArrayRef<Expr *> Args, + TemplateArgumentListInfo *ExplicitTemplateArgs, + OverloadCandidateSet& CandidateSet, + bool PartialOverloading = false, + bool StdNamespaceIsAssociated = false); + + // Emit as a 'note' the specific overload candidate + void NoteOverloadCandidate(FunctionDecl *Fn, QualType DestType = QualType()); + + // Emit as a series of 'note's all template and non-templates + // identified by the expression Expr + void NoteAllOverloadCandidates(Expr* E, QualType DestType = QualType()); + + // [PossiblyAFunctionType] --> [Return] + // NonFunctionType --> NonFunctionType + // R (A) --> R(A) + // R (*)(A) --> R (A) + // R (&)(A) --> R (A) + // R (S::*)(A) --> R (A) + QualType ExtractUnqualifiedFunctionType(QualType PossiblyAFunctionType); + + FunctionDecl * + ResolveAddressOfOverloadedFunction(Expr *AddressOfExpr, + QualType TargetType, + bool Complain, + DeclAccessPair &Found, + bool *pHadMultipleCandidates = 0); + + FunctionDecl *ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl, + bool Complain = false, + DeclAccessPair* Found = 0); + + bool ResolveAndFixSingleFunctionTemplateSpecialization( + ExprResult &SrcExpr, + bool DoFunctionPointerConverion = false, + bool Complain = false, + const SourceRange& OpRangeForComplaining = SourceRange(), + QualType DestTypeForComplaining = QualType(), + unsigned DiagIDForComplaining = 0); + + + Expr *FixOverloadedFunctionReference(Expr *E, + DeclAccessPair FoundDecl, + FunctionDecl *Fn); + ExprResult FixOverloadedFunctionReference(ExprResult, + DeclAccessPair FoundDecl, + FunctionDecl *Fn); + + void AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE, + llvm::ArrayRef<Expr *> Args, + OverloadCandidateSet &CandidateSet, + bool PartialOverloading = false); + + ExprResult BuildOverloadedCallExpr(Scope *S, Expr *Fn, + UnresolvedLookupExpr *ULE, + SourceLocation LParenLoc, + Expr **Args, unsigned NumArgs, + SourceLocation RParenLoc, + Expr *ExecConfig, + bool AllowTypoCorrection=true); + + ExprResult CreateOverloadedUnaryOp(SourceLocation OpLoc, + unsigned Opc, + const UnresolvedSetImpl &Fns, + Expr *input); + + ExprResult CreateOverloadedBinOp(SourceLocation OpLoc, + unsigned Opc, + const UnresolvedSetImpl &Fns, + Expr *LHS, Expr *RHS); + + ExprResult CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, + SourceLocation RLoc, + Expr *Base,Expr *Idx); + + ExprResult + BuildCallToMemberFunction(Scope *S, Expr *MemExpr, + SourceLocation LParenLoc, Expr **Args, + unsigned NumArgs, SourceLocation RParenLoc); + ExprResult + BuildCallToObjectOfClassType(Scope *S, Expr *Object, SourceLocation LParenLoc, + Expr **Args, unsigned NumArgs, + SourceLocation RParenLoc); + + ExprResult BuildOverloadedArrowExpr(Scope *S, Expr *Base, + SourceLocation OpLoc); + + /// CheckCallReturnType - Checks that a call expression's return type is + /// complete. Returns true on failure. The location passed in is the location + /// that best represents the call. + bool CheckCallReturnType(QualType ReturnType, SourceLocation Loc, + CallExpr *CE, FunctionDecl *FD); + + /// Helpers for dealing with blocks and functions. + bool CheckParmsForFunctionDef(ParmVarDecl **Param, ParmVarDecl **ParamEnd, + bool CheckParameterNames); + void CheckCXXDefaultArguments(FunctionDecl *FD); + void CheckExtraCXXDefaultArguments(Declarator &D); + Scope *getNonFieldDeclScope(Scope *S); + + /// \name Name lookup + /// + /// These routines provide name lookup that is used during semantic + /// analysis to resolve the various kinds of names (identifiers, + /// overloaded operator names, constructor names, etc.) into zero or + /// more declarations within a particular scope. The major entry + /// points are LookupName, which performs unqualified name lookup, + /// and LookupQualifiedName, which performs qualified name lookup. + /// + /// All name lookup is performed based on some specific criteria, + /// which specify what names will be visible to name lookup and how + /// far name lookup should work. These criteria are important both + /// for capturing language semantics (certain lookups will ignore + /// certain names, for example) and for performance, since name + /// lookup is often a bottleneck in the compilation of C++. Name + /// lookup criteria is specified via the LookupCriteria enumeration. + /// + /// The results of name lookup can vary based on the kind of name + /// lookup performed, the current language, and the translation + /// unit. In C, for example, name lookup will either return nothing + /// (no entity found) or a single declaration. In C++, name lookup + /// can additionally refer to a set of overloaded functions or + /// result in an ambiguity. All of the possible results of name + /// lookup are captured by the LookupResult class, which provides + /// the ability to distinguish among them. + //@{ + + /// @brief Describes the kind of name lookup to perform. + enum LookupNameKind { + /// Ordinary name lookup, which finds ordinary names (functions, + /// variables, typedefs, etc.) in C and most kinds of names + /// (functions, variables, members, types, etc.) in C++. + LookupOrdinaryName = 0, + /// Tag name lookup, which finds the names of enums, classes, + /// structs, and unions. + LookupTagName, + /// Label name lookup. + LookupLabel, + /// Member name lookup, which finds the names of + /// class/struct/union members. + LookupMemberName, + /// Look up of an operator name (e.g., operator+) for use with + /// operator overloading. This lookup is similar to ordinary name + /// lookup, but will ignore any declarations that are class members. + LookupOperatorName, + /// Look up of a name that precedes the '::' scope resolution + /// operator in C++. This lookup completely ignores operator, object, + /// function, and enumerator names (C++ [basic.lookup.qual]p1). + LookupNestedNameSpecifierName, + /// Look up a namespace name within a C++ using directive or + /// namespace alias definition, ignoring non-namespace names (C++ + /// [basic.lookup.udir]p1). + LookupNamespaceName, + /// Look up all declarations in a scope with the given name, + /// including resolved using declarations. This is appropriate + /// for checking redeclarations for a using declaration. + LookupUsingDeclName, + /// Look up an ordinary name that is going to be redeclared as a + /// name with linkage. This lookup ignores any declarations that + /// are outside of the current scope unless they have linkage. See + /// C99 6.2.2p4-5 and C++ [basic.link]p6. + LookupRedeclarationWithLinkage, + /// Look up the name of an Objective-C protocol. + LookupObjCProtocolName, + /// Look up implicit 'self' parameter of an objective-c method. + LookupObjCImplicitSelfParam, + /// \brief Look up any declaration with any name. + LookupAnyName + }; + + /// \brief Specifies whether (or how) name lookup is being performed for a + /// redeclaration (vs. a reference). + enum RedeclarationKind { + /// \brief The lookup is a reference to this name that is not for the + /// purpose of redeclaring the name. + NotForRedeclaration = 0, + /// \brief The lookup results will be used for redeclaration of a name, + /// if an entity by that name already exists. + ForRedeclaration + }; + + /// \brief The possible outcomes of name lookup for a literal operator. + enum LiteralOperatorLookupResult { + /// \brief The lookup resulted in an error. + LOLR_Error, + /// \brief The lookup found a single 'cooked' literal operator, which + /// expects a normal literal to be built and passed to it. + LOLR_Cooked, + /// \brief The lookup found a single 'raw' literal operator, which expects + /// a string literal containing the spelling of the literal token. + LOLR_Raw, + /// \brief The lookup found an overload set of literal operator templates, + /// which expect the characters of the spelling of the literal token to be + /// passed as a non-type template argument pack. + LOLR_Template + }; + + SpecialMemberOverloadResult *LookupSpecialMember(CXXRecordDecl *D, + CXXSpecialMember SM, + bool ConstArg, + bool VolatileArg, + bool RValueThis, + bool ConstThis, + bool VolatileThis); + +private: + bool CppLookupName(LookupResult &R, Scope *S); + + // \brief The set of known/encountered (unique, canonicalized) NamespaceDecls. + // + // The boolean value will be true to indicate that the namespace was loaded + // from an AST/PCH file, or false otherwise. + llvm::DenseMap<NamespaceDecl*, bool> KnownNamespaces; + + /// \brief Whether we have already loaded known namespaces from an extenal + /// source. + bool LoadedExternalKnownNamespaces; + +public: + /// \brief Look up a name, looking for a single declaration. Return + /// null if the results were absent, ambiguous, or overloaded. + /// + /// It is preferable to use the elaborated form and explicitly handle + /// ambiguity and overloaded. + NamedDecl *LookupSingleName(Scope *S, DeclarationName Name, + SourceLocation Loc, + LookupNameKind NameKind, + RedeclarationKind Redecl + = NotForRedeclaration); + bool LookupName(LookupResult &R, Scope *S, + bool AllowBuiltinCreation = false); + bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, + bool InUnqualifiedLookup = false); + bool LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS, + bool AllowBuiltinCreation = false, + bool EnteringContext = false); + ObjCProtocolDecl *LookupProtocol(IdentifierInfo *II, SourceLocation IdLoc, + RedeclarationKind Redecl + = NotForRedeclaration); + + void LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S, + QualType T1, QualType T2, + UnresolvedSetImpl &Functions); + + LabelDecl *LookupOrCreateLabel(IdentifierInfo *II, SourceLocation IdentLoc, + SourceLocation GnuLabelLoc = SourceLocation()); + + DeclContextLookupResult LookupConstructors(CXXRecordDecl *Class); + CXXConstructorDecl *LookupDefaultConstructor(CXXRecordDecl *Class); + CXXConstructorDecl *LookupCopyingConstructor(CXXRecordDecl *Class, + unsigned Quals); + CXXMethodDecl *LookupCopyingAssignment(CXXRecordDecl *Class, unsigned Quals, + bool RValueThis, unsigned ThisQuals); + CXXConstructorDecl *LookupMovingConstructor(CXXRecordDecl *Class); + CXXMethodDecl *LookupMovingAssignment(CXXRecordDecl *Class, bool RValueThis, + unsigned ThisQuals); + CXXDestructorDecl *LookupDestructor(CXXRecordDecl *Class); + + LiteralOperatorLookupResult LookupLiteralOperator(Scope *S, LookupResult &R, + ArrayRef<QualType> ArgTys, + bool AllowRawAndTemplate); + + void ArgumentDependentLookup(DeclarationName Name, bool Operator, + SourceLocation Loc, + llvm::ArrayRef<Expr *> Args, + ADLResult &Functions, + bool StdNamespaceIsAssociated = false); + + void LookupVisibleDecls(Scope *S, LookupNameKind Kind, + VisibleDeclConsumer &Consumer, + bool IncludeGlobalScope = true); + void LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind, + VisibleDeclConsumer &Consumer, + bool IncludeGlobalScope = true); + + TypoCorrection CorrectTypo(const DeclarationNameInfo &Typo, + Sema::LookupNameKind LookupKind, + Scope *S, CXXScopeSpec *SS, + CorrectionCandidateCallback &CCC, + DeclContext *MemberContext = 0, + bool EnteringContext = false, + const ObjCObjectPointerType *OPT = 0); + + void FindAssociatedClassesAndNamespaces(llvm::ArrayRef<Expr *> Args, + AssociatedNamespaceSet &AssociatedNamespaces, + AssociatedClassSet &AssociatedClasses); + + void FilterLookupForScope(LookupResult &R, DeclContext *Ctx, Scope *S, + bool ConsiderLinkage, + bool ExplicitInstantiationOrSpecialization); + + bool DiagnoseAmbiguousLookup(LookupResult &Result); + //@} + + ObjCInterfaceDecl *getObjCInterfaceDecl(IdentifierInfo *&Id, + SourceLocation IdLoc, + bool TypoCorrection = false); + NamedDecl *LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID, + Scope *S, bool ForRedeclaration, + SourceLocation Loc); + NamedDecl *ImplicitlyDefineFunction(SourceLocation Loc, IdentifierInfo &II, + Scope *S); + void AddKnownFunctionAttributes(FunctionDecl *FD); + + // More parsing and symbol table subroutines. + + // Decl attributes - this routine is the top level dispatcher. + void ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD, + bool NonInheritable = true, bool Inheritable = true); + void ProcessDeclAttributeList(Scope *S, Decl *D, const AttributeList *AL, + bool NonInheritable = true, bool Inheritable = true); + bool ProcessAccessDeclAttributeList(AccessSpecDecl *ASDecl, + const AttributeList *AttrList); + + void checkUnusedDeclAttributes(Declarator &D); + + bool CheckRegparmAttr(const AttributeList &attr, unsigned &value); + bool CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC); + bool CheckNoReturnAttr(const AttributeList &attr); + + /// \brief Stmt attributes - this routine is the top level dispatcher. + StmtResult ProcessStmtAttributes(Stmt *Stmt, AttributeList *Attrs, + SourceRange Range); + + void WarnUndefinedMethod(SourceLocation ImpLoc, ObjCMethodDecl *method, + bool &IncompleteImpl, unsigned DiagID); + void WarnConflictingTypedMethods(ObjCMethodDecl *Method, + ObjCMethodDecl *MethodDecl, + bool IsProtocolMethodDecl); + + void CheckConflictingOverridingMethod(ObjCMethodDecl *Method, + ObjCMethodDecl *Overridden, + bool IsProtocolMethodDecl); + + /// WarnExactTypedMethods - This routine issues a warning if method + /// implementation declaration matches exactly that of its declaration. + void WarnExactTypedMethods(ObjCMethodDecl *Method, + ObjCMethodDecl *MethodDecl, + bool IsProtocolMethodDecl); + + bool isPropertyReadonly(ObjCPropertyDecl *PropertyDecl, + ObjCInterfaceDecl *IDecl); + + typedef llvm::DenseSet<Selector, llvm::DenseMapInfo<Selector> > SelectorSet; + typedef llvm::DenseMap<Selector, ObjCMethodDecl*> ProtocolsMethodsMap; + + /// CheckProtocolMethodDefs - This routine checks unimplemented + /// methods declared in protocol, and those referenced by it. + /// \param IDecl - Used for checking for methods which may have been + /// inherited. + void CheckProtocolMethodDefs(SourceLocation ImpLoc, + ObjCProtocolDecl *PDecl, + bool& IncompleteImpl, + const SelectorSet &InsMap, + const SelectorSet &ClsMap, + ObjCContainerDecl *CDecl); + + /// CheckImplementationIvars - This routine checks if the instance variables + /// listed in the implelementation match those listed in the interface. + void CheckImplementationIvars(ObjCImplementationDecl *ImpDecl, + ObjCIvarDecl **Fields, unsigned nIvars, + SourceLocation Loc); + + /// ImplMethodsVsClassMethods - This is main routine to warn if any method + /// remains unimplemented in the class or category @implementation. + void ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl, + ObjCContainerDecl* IDecl, + bool IncompleteImpl = false); + + /// DiagnoseUnimplementedProperties - This routine warns on those properties + /// which must be implemented by this implementation. + void DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl, + ObjCContainerDecl *CDecl, + const SelectorSet &InsMap); + + /// DefaultSynthesizeProperties - This routine default synthesizes all + /// properties which must be synthesized in class's @implementation. + void DefaultSynthesizeProperties (Scope *S, ObjCImplDecl* IMPDecl, + ObjCInterfaceDecl *IDecl); + void DefaultSynthesizeProperties(Scope *S, Decl *D); + + /// CollectImmediateProperties - This routine collects all properties in + /// the class and its conforming protocols; but not those it its super class. + void CollectImmediateProperties(ObjCContainerDecl *CDecl, + llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& PropMap, + llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& SuperPropMap); + + + /// LookupPropertyDecl - Looks up a property in the current class and all + /// its protocols. + ObjCPropertyDecl *LookupPropertyDecl(const ObjCContainerDecl *CDecl, + IdentifierInfo *II); + + /// Called by ActOnProperty to handle @property declarations in + //// class extensions. + Decl *HandlePropertyInClassExtension(Scope *S, + SourceLocation AtLoc, + SourceLocation LParenLoc, + FieldDeclarator &FD, + Selector GetterSel, + Selector SetterSel, + const bool isAssign, + const bool isReadWrite, + const unsigned Attributes, + const unsigned AttributesAsWritten, + bool *isOverridingProperty, + TypeSourceInfo *T, + tok::ObjCKeywordKind MethodImplKind); + + /// Called by ActOnProperty and HandlePropertyInClassExtension to + /// handle creating the ObjcPropertyDecl for a category or @interface. + ObjCPropertyDecl *CreatePropertyDecl(Scope *S, + ObjCContainerDecl *CDecl, + SourceLocation AtLoc, + SourceLocation LParenLoc, + FieldDeclarator &FD, + Selector GetterSel, + Selector SetterSel, + const bool isAssign, + const bool isReadWrite, + const unsigned Attributes, + const unsigned AttributesAsWritten, + TypeSourceInfo *T, + tok::ObjCKeywordKind MethodImplKind, + DeclContext *lexicalDC = 0); + + /// AtomicPropertySetterGetterRules - This routine enforces the rule (via + /// warning) when atomic property has one but not the other user-declared + /// setter or getter. + void AtomicPropertySetterGetterRules(ObjCImplDecl* IMPDecl, + ObjCContainerDecl* IDecl); + + void DiagnoseOwningPropertyGetterSynthesis(const ObjCImplementationDecl *D); + + void DiagnoseDuplicateIvars(ObjCInterfaceDecl *ID, ObjCInterfaceDecl *SID); + + enum MethodMatchStrategy { + MMS_loose, + MMS_strict + }; + + /// MatchTwoMethodDeclarations - Checks if two methods' type match and returns + /// true, or false, accordingly. + bool MatchTwoMethodDeclarations(const ObjCMethodDecl *Method, + const ObjCMethodDecl *PrevMethod, + MethodMatchStrategy strategy = MMS_strict); + + /// MatchAllMethodDeclarations - Check methods declaraed in interface or + /// or protocol against those declared in their implementations. + void MatchAllMethodDeclarations(const SelectorSet &InsMap, + const SelectorSet &ClsMap, + SelectorSet &InsMapSeen, + SelectorSet &ClsMapSeen, + ObjCImplDecl* IMPDecl, + ObjCContainerDecl* IDecl, + bool &IncompleteImpl, + bool ImmediateClass, + bool WarnCategoryMethodImpl=false); + + /// CheckCategoryVsClassMethodMatches - Checks that methods implemented in + /// category matches with those implemented in its primary class and + /// warns each time an exact match is found. + void CheckCategoryVsClassMethodMatches(ObjCCategoryImplDecl *CatIMP); + + /// \brief Add the given method to the list of globally-known methods. + void addMethodToGlobalList(ObjCMethodList *List, ObjCMethodDecl *Method); + +private: + /// AddMethodToGlobalPool - Add an instance or factory method to the global + /// pool. See descriptoin of AddInstanceMethodToGlobalPool. + void AddMethodToGlobalPool(ObjCMethodDecl *Method, bool impl, bool instance); + + /// LookupMethodInGlobalPool - Returns the instance or factory method and + /// optionally warns if there are multiple signatures. + ObjCMethodDecl *LookupMethodInGlobalPool(Selector Sel, SourceRange R, + bool receiverIdOrClass, + bool warn, bool instance); + +public: + /// AddInstanceMethodToGlobalPool - All instance methods in a translation + /// unit are added to a global pool. This allows us to efficiently associate + /// a selector with a method declaraation for purposes of typechecking + /// messages sent to "id" (where the class of the object is unknown). + void AddInstanceMethodToGlobalPool(ObjCMethodDecl *Method, bool impl=false) { + AddMethodToGlobalPool(Method, impl, /*instance*/true); + } + + /// AddFactoryMethodToGlobalPool - Same as above, but for factory methods. + void AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method, bool impl=false) { + AddMethodToGlobalPool(Method, impl, /*instance*/false); + } + + /// AddAnyMethodToGlobalPool - Add any method, instance or factory to global + /// pool. + void AddAnyMethodToGlobalPool(Decl *D); + + /// LookupInstanceMethodInGlobalPool - Returns the method and warns if + /// there are multiple signatures. + ObjCMethodDecl *LookupInstanceMethodInGlobalPool(Selector Sel, SourceRange R, + bool receiverIdOrClass=false, + bool warn=true) { + return LookupMethodInGlobalPool(Sel, R, receiverIdOrClass, + warn, /*instance*/true); + } + + /// LookupFactoryMethodInGlobalPool - Returns the method and warns if + /// there are multiple signatures. + ObjCMethodDecl *LookupFactoryMethodInGlobalPool(Selector Sel, SourceRange R, + bool receiverIdOrClass=false, + bool warn=true) { + return LookupMethodInGlobalPool(Sel, R, receiverIdOrClass, + warn, /*instance*/false); + } + + /// LookupImplementedMethodInGlobalPool - Returns the method which has an + /// implementation. + ObjCMethodDecl *LookupImplementedMethodInGlobalPool(Selector Sel); + + /// CollectIvarsToConstructOrDestruct - Collect those ivars which require + /// initialization. + void CollectIvarsToConstructOrDestruct(ObjCInterfaceDecl *OI, + SmallVectorImpl<ObjCIvarDecl*> &Ivars); + + //===--------------------------------------------------------------------===// + // Statement Parsing Callbacks: SemaStmt.cpp. +public: + class FullExprArg { + public: + FullExprArg(Sema &actions) : E(0) { } + + // FIXME: The const_cast here is ugly. RValue references would make this + // much nicer (or we could duplicate a bunch of the move semantics + // emulation code from Ownership.h). + FullExprArg(const FullExprArg& Other) : E(Other.E) {} + + ExprResult release() { + return move(E); + } + + Expr *get() const { return E; } + + Expr *operator->() { + return E; + } + + private: + // FIXME: No need to make the entire Sema class a friend when it's just + // Sema::MakeFullExpr that needs access to the constructor below. + friend class Sema; + + explicit FullExprArg(Expr *expr) : E(expr) {} + + Expr *E; + }; + + FullExprArg MakeFullExpr(Expr *Arg) { + return FullExprArg(ActOnFinishFullExpr(Arg).release()); + } + + StmtResult ActOnExprStmt(FullExprArg Expr); + + StmtResult ActOnNullStmt(SourceLocation SemiLoc, + bool HasLeadingEmptyMacro = false); + + void ActOnStartOfCompoundStmt(); + void ActOnFinishOfCompoundStmt(); + StmtResult ActOnCompoundStmt(SourceLocation L, SourceLocation R, + MultiStmtArg Elts, + bool isStmtExpr); + + /// \brief A RAII object to enter scope of a compound statement. + class CompoundScopeRAII { + public: + CompoundScopeRAII(Sema &S): S(S) { + S.ActOnStartOfCompoundStmt(); + } + + ~CompoundScopeRAII() { + S.ActOnFinishOfCompoundStmt(); + } + + private: + Sema &S; + }; + + StmtResult ActOnDeclStmt(DeclGroupPtrTy Decl, + SourceLocation StartLoc, + SourceLocation EndLoc); + void ActOnForEachDeclStmt(DeclGroupPtrTy Decl); + StmtResult ActOnForEachLValueExpr(Expr *E); + StmtResult ActOnCaseStmt(SourceLocation CaseLoc, Expr *LHSVal, + SourceLocation DotDotDotLoc, Expr *RHSVal, + SourceLocation ColonLoc); + void ActOnCaseStmtBody(Stmt *CaseStmt, Stmt *SubStmt); + + StmtResult ActOnDefaultStmt(SourceLocation DefaultLoc, + SourceLocation ColonLoc, + Stmt *SubStmt, Scope *CurScope); + StmtResult ActOnLabelStmt(SourceLocation IdentLoc, LabelDecl *TheDecl, + SourceLocation ColonLoc, Stmt *SubStmt); + + StmtResult ActOnAttributedStmt(SourceLocation AttrLoc, const AttrVec &Attrs, + Stmt *SubStmt); + + StmtResult ActOnIfStmt(SourceLocation IfLoc, + FullExprArg CondVal, Decl *CondVar, + Stmt *ThenVal, + SourceLocation ElseLoc, Stmt *ElseVal); + StmtResult ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, + Expr *Cond, + Decl *CondVar); + StmtResult ActOnFinishSwitchStmt(SourceLocation SwitchLoc, + Stmt *Switch, Stmt *Body); + StmtResult ActOnWhileStmt(SourceLocation WhileLoc, + FullExprArg Cond, + Decl *CondVar, Stmt *Body); + StmtResult ActOnDoStmt(SourceLocation DoLoc, Stmt *Body, + SourceLocation WhileLoc, + SourceLocation CondLParen, Expr *Cond, + SourceLocation CondRParen); + + StmtResult ActOnForStmt(SourceLocation ForLoc, + SourceLocation LParenLoc, + Stmt *First, FullExprArg Second, + Decl *SecondVar, + FullExprArg Third, + SourceLocation RParenLoc, + Stmt *Body); + ExprResult ActOnObjCForCollectionOperand(SourceLocation forLoc, + Expr *collection); + StmtResult ActOnObjCForCollectionStmt(SourceLocation ForColLoc, + SourceLocation LParenLoc, + Stmt *First, Expr *Second, + SourceLocation RParenLoc, Stmt *Body); + StmtResult ActOnCXXForRangeStmt(SourceLocation ForLoc, + SourceLocation LParenLoc, Stmt *LoopVar, + SourceLocation ColonLoc, Expr *Collection, + SourceLocation RParenLoc); + StmtResult BuildCXXForRangeStmt(SourceLocation ForLoc, + SourceLocation ColonLoc, + Stmt *RangeDecl, Stmt *BeginEndDecl, + Expr *Cond, Expr *Inc, + Stmt *LoopVarDecl, + SourceLocation RParenLoc); + StmtResult FinishCXXForRangeStmt(Stmt *ForRange, Stmt *Body); + + StmtResult ActOnGotoStmt(SourceLocation GotoLoc, + SourceLocation LabelLoc, + LabelDecl *TheDecl); + StmtResult ActOnIndirectGotoStmt(SourceLocation GotoLoc, + SourceLocation StarLoc, + Expr *DestExp); + StmtResult ActOnContinueStmt(SourceLocation ContinueLoc, Scope *CurScope); + StmtResult ActOnBreakStmt(SourceLocation GotoLoc, Scope *CurScope); + + const VarDecl *getCopyElisionCandidate(QualType ReturnType, Expr *E, + bool AllowFunctionParameters); + + StmtResult ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp); + StmtResult ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp); + + StmtResult ActOnAsmStmt(SourceLocation AsmLoc, + bool IsSimple, bool IsVolatile, + unsigned NumOutputs, unsigned NumInputs, + IdentifierInfo **Names, + MultiExprArg Constraints, + MultiExprArg Exprs, + Expr *AsmString, + MultiExprArg Clobbers, + SourceLocation RParenLoc, + bool MSAsm = false); + + + VarDecl *BuildObjCExceptionDecl(TypeSourceInfo *TInfo, QualType ExceptionType, + SourceLocation StartLoc, + SourceLocation IdLoc, IdentifierInfo *Id, + bool Invalid = false); + + Decl *ActOnObjCExceptionDecl(Scope *S, Declarator &D); + + StmtResult ActOnObjCAtCatchStmt(SourceLocation AtLoc, SourceLocation RParen, + Decl *Parm, Stmt *Body); + + StmtResult ActOnObjCAtFinallyStmt(SourceLocation AtLoc, Stmt *Body); + + StmtResult ActOnObjCAtTryStmt(SourceLocation AtLoc, Stmt *Try, + MultiStmtArg Catch, Stmt *Finally); + + StmtResult BuildObjCAtThrowStmt(SourceLocation AtLoc, Expr *Throw); + StmtResult ActOnObjCAtThrowStmt(SourceLocation AtLoc, Expr *Throw, + Scope *CurScope); + ExprResult ActOnObjCAtSynchronizedOperand(SourceLocation atLoc, + Expr *operand); + StmtResult ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, + Expr *SynchExpr, + Stmt *SynchBody); + + StmtResult ActOnObjCAutoreleasePoolStmt(SourceLocation AtLoc, Stmt *Body); + + VarDecl *BuildExceptionDeclaration(Scope *S, TypeSourceInfo *TInfo, + SourceLocation StartLoc, + SourceLocation IdLoc, + IdentifierInfo *Id); + + Decl *ActOnExceptionDeclarator(Scope *S, Declarator &D); + + StmtResult ActOnCXXCatchBlock(SourceLocation CatchLoc, + Decl *ExDecl, Stmt *HandlerBlock); + StmtResult ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock, + MultiStmtArg Handlers); + + StmtResult ActOnSEHTryBlock(bool IsCXXTry, // try (true) or __try (false) ? + SourceLocation TryLoc, + Stmt *TryBlock, + Stmt *Handler); + + StmtResult ActOnSEHExceptBlock(SourceLocation Loc, + Expr *FilterExpr, + Stmt *Block); + + StmtResult ActOnSEHFinallyBlock(SourceLocation Loc, + Stmt *Block); + + void DiagnoseReturnInConstructorExceptionHandler(CXXTryStmt *TryBlock); + + bool ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const; + + /// \brief If it's a file scoped decl that must warn if not used, keep track + /// of it. + void MarkUnusedFileScopedDecl(const DeclaratorDecl *D); + + /// DiagnoseUnusedExprResult - If the statement passed in is an expression + /// whose result is unused, warn. + void DiagnoseUnusedExprResult(const Stmt *S); + void DiagnoseUnusedDecl(const NamedDecl *ND); + + /// Emit \p DiagID if statement located on \p StmtLoc has a suspicious null + /// statement as a \p Body, and it is located on the same line. + /// + /// This helps prevent bugs due to typos, such as: + /// if (condition); + /// do_stuff(); + void DiagnoseEmptyStmtBody(SourceLocation StmtLoc, + const Stmt *Body, + unsigned DiagID); + + /// Warn if a for/while loop statement \p S, which is followed by + /// \p PossibleBody, has a suspicious null statement as a body. + void DiagnoseEmptyLoopBody(const Stmt *S, + const Stmt *PossibleBody); + + ParsingDeclState PushParsingDeclaration() { + return DelayedDiagnostics.pushParsingDecl(); + } + void PopParsingDeclaration(ParsingDeclState state, Decl *decl) { + DelayedDiagnostics::popParsingDecl(*this, state, decl); + } + + typedef ProcessingContextState ParsingClassState; + ParsingClassState PushParsingClass() { + return DelayedDiagnostics.pushContext(); + } + void PopParsingClass(ParsingClassState state) { + DelayedDiagnostics.popContext(state); + } + + void EmitDeprecationWarning(NamedDecl *D, StringRef Message, + SourceLocation Loc, + const ObjCInterfaceDecl *UnknownObjCClass=0); + + void HandleDelayedDeprecationCheck(sema::DelayedDiagnostic &DD, Decl *Ctx); + + bool makeUnavailableInSystemHeader(SourceLocation loc, + StringRef message); + + //===--------------------------------------------------------------------===// + // Expression Parsing Callbacks: SemaExpr.cpp. + + bool CanUseDecl(NamedDecl *D); + bool DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, + const ObjCInterfaceDecl *UnknownObjCClass=0); + void NoteDeletedFunction(FunctionDecl *FD); + std::string getDeletedOrUnavailableSuffix(const FunctionDecl *FD); + bool DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *PD, + ObjCMethodDecl *Getter, + SourceLocation Loc); + void DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc, + Expr **Args, unsigned NumArgs); + + void PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext, + Decl *LambdaContextDecl = 0, + bool IsDecltype = false); + + void PopExpressionEvaluationContext(); + + void DiscardCleanupsInEvaluationContext(); + + ExprResult TranformToPotentiallyEvaluated(Expr *E); + ExprResult HandleExprEvaluationContextForTypeof(Expr *E); + + ExprResult ActOnConstantExpression(ExprResult Res); + + // Functions for marking a declaration referenced. These functions also + // contain the relevant logic for marking if a reference to a function or + // variable is an odr-use (in the C++11 sense). There are separate variants + // for expressions referring to a decl; these exist because odr-use marking + // needs to be delayed for some constant variables when we build one of the + // named expressions. + void MarkAnyDeclReferenced(SourceLocation Loc, Decl *D); + void MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func); + void MarkVariableReferenced(SourceLocation Loc, VarDecl *Var); + void MarkDeclRefReferenced(DeclRefExpr *E); + void MarkMemberReferenced(MemberExpr *E); + + void UpdateMarkingForLValueToRValue(Expr *E); + void CleanupVarDeclMarking(); + + enum TryCaptureKind { + TryCapture_Implicit, TryCapture_ExplicitByVal, TryCapture_ExplicitByRef + }; + + /// \brief Try to capture the given variable. + /// + /// \param Var The variable to capture. + /// + /// \param Loc The location at which the capture occurs. + /// + /// \param Kind The kind of capture, which may be implicit (for either a + /// block or a lambda), or explicit by-value or by-reference (for a lambda). + /// + /// \param EllipsisLoc The location of the ellipsis, if one is provided in + /// an explicit lambda capture. + /// + /// \param BuildAndDiagnose Whether we are actually supposed to add the + /// captures or diagnose errors. If false, this routine merely check whether + /// the capture can occur without performing the capture itself or complaining + /// if the variable cannot be captured. + /// + /// \param CaptureType Will be set to the type of the field used to capture + /// this variable in the innermost block or lambda. Only valid when the + /// variable can be captured. + /// + /// \param DeclRefType Will be set to the type of a refernce to the capture + /// from within the current scope. Only valid when the variable can be + /// captured. + /// + /// \returns true if an error occurred (i.e., the variable cannot be + /// captured) and false if the capture succeeded. + bool tryCaptureVariable(VarDecl *Var, SourceLocation Loc, TryCaptureKind Kind, + SourceLocation EllipsisLoc, bool BuildAndDiagnose, + QualType &CaptureType, + QualType &DeclRefType); + + /// \brief Try to capture the given variable. + bool tryCaptureVariable(VarDecl *Var, SourceLocation Loc, + TryCaptureKind Kind = TryCapture_Implicit, + SourceLocation EllipsisLoc = SourceLocation()); + + /// \brief Given a variable, determine the type that a reference to that + /// variable will have in the given scope. + QualType getCapturedDeclRefType(VarDecl *Var, SourceLocation Loc); + + void MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T); + void MarkDeclarationsReferencedInExpr(Expr *E, + bool SkipLocalVariables = false); + + /// \brief Try to recover by turning the given expression into a + /// call. Returns true if recovery was attempted or an error was + /// emitted; this may also leave the ExprResult invalid. + bool tryToRecoverWithCall(ExprResult &E, const PartialDiagnostic &PD, + bool ForceComplain = false, + bool (*IsPlausibleResult)(QualType) = 0); + + /// \brief Figure out if an expression could be turned into a call. + bool isExprCallable(const Expr &E, QualType &ZeroArgCallReturnTy, + UnresolvedSetImpl &NonTemplateOverloads); + + /// \brief Conditionally issue a diagnostic based on the current + /// evaluation context. + /// + /// \param stmt - If stmt is non-null, delay reporting the diagnostic until + /// the function body is parsed, and then do a basic reachability analysis to + /// determine if the statement is reachable. If it is unreachable, the + /// diagnostic will not be emitted. + bool DiagRuntimeBehavior(SourceLocation Loc, const Stmt *Statement, + const PartialDiagnostic &PD); + + // Primary Expressions. + SourceRange getExprRange(Expr *E) const; + + ExprResult ActOnIdExpression(Scope *S, CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, + UnqualifiedId &Id, + bool HasTrailingLParen, bool IsAddressOfOperand, + CorrectionCandidateCallback *CCC = 0); + + void DecomposeUnqualifiedId(const UnqualifiedId &Id, + TemplateArgumentListInfo &Buffer, + DeclarationNameInfo &NameInfo, + const TemplateArgumentListInfo *&TemplateArgs); + + bool DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, + CorrectionCandidateCallback &CCC, + TemplateArgumentListInfo *ExplicitTemplateArgs = 0, + llvm::ArrayRef<Expr *> Args = llvm::ArrayRef<Expr *>()); + + ExprResult LookupInObjCMethod(LookupResult &LookUp, Scope *S, + IdentifierInfo *II, + bool AllowBuiltinCreation=false); + + ExprResult ActOnDependentIdExpression(const CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, + const DeclarationNameInfo &NameInfo, + bool isAddressOfOperand, + const TemplateArgumentListInfo *TemplateArgs); + + ExprResult BuildDeclRefExpr(ValueDecl *D, QualType Ty, + ExprValueKind VK, + SourceLocation Loc, + const CXXScopeSpec *SS = 0); + ExprResult BuildDeclRefExpr(ValueDecl *D, QualType Ty, + ExprValueKind VK, + const DeclarationNameInfo &NameInfo, + const CXXScopeSpec *SS = 0); + ExprResult + BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS, + SourceLocation nameLoc, + IndirectFieldDecl *indirectField, + Expr *baseObjectExpr = 0, + SourceLocation opLoc = SourceLocation()); + ExprResult BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, + LookupResult &R, + const TemplateArgumentListInfo *TemplateArgs); + ExprResult BuildImplicitMemberExpr(const CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, + LookupResult &R, + const TemplateArgumentListInfo *TemplateArgs, + bool IsDefiniteInstance); + bool UseArgumentDependentLookup(const CXXScopeSpec &SS, + const LookupResult &R, + bool HasTrailingLParen); + + ExprResult BuildQualifiedDeclarationNameExpr(CXXScopeSpec &SS, + const DeclarationNameInfo &NameInfo); + ExprResult BuildDependentDeclRefExpr(const CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, + const DeclarationNameInfo &NameInfo, + const TemplateArgumentListInfo *TemplateArgs); + + ExprResult BuildDeclarationNameExpr(const CXXScopeSpec &SS, + LookupResult &R, + bool NeedsADL); + ExprResult BuildDeclarationNameExpr(const CXXScopeSpec &SS, + const DeclarationNameInfo &NameInfo, + NamedDecl *D); + + ExprResult BuildLiteralOperatorCall(LookupResult &R, + DeclarationNameInfo &SuffixInfo, + ArrayRef<Expr*> Args, + SourceLocation LitEndLoc, + TemplateArgumentListInfo *ExplicitTemplateArgs = 0); + + ExprResult ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind); + ExprResult ActOnIntegerConstant(SourceLocation Loc, uint64_t Val); + ExprResult ActOnNumericConstant(const Token &Tok, Scope *UDLScope = 0); + ExprResult ActOnCharacterConstant(const Token &Tok, Scope *UDLScope = 0); + ExprResult ActOnParenExpr(SourceLocation L, SourceLocation R, Expr *E); + ExprResult ActOnParenListExpr(SourceLocation L, + SourceLocation R, + MultiExprArg Val); + + /// ActOnStringLiteral - The specified tokens were lexed as pasted string + /// fragments (e.g. "foo" "bar" L"baz"). + ExprResult ActOnStringLiteral(const Token *StringToks, unsigned NumStringToks, + Scope *UDLScope = 0); + + ExprResult ActOnGenericSelectionExpr(SourceLocation KeyLoc, + SourceLocation DefaultLoc, + SourceLocation RParenLoc, + Expr *ControllingExpr, + MultiTypeArg ArgTypes, + MultiExprArg ArgExprs); + ExprResult CreateGenericSelectionExpr(SourceLocation KeyLoc, + SourceLocation DefaultLoc, + SourceLocation RParenLoc, + Expr *ControllingExpr, + TypeSourceInfo **Types, + Expr **Exprs, + unsigned NumAssocs); + + // Binary/Unary Operators. 'Tok' is the token for the operator. + ExprResult CreateBuiltinUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc, + Expr *InputExpr); + ExprResult BuildUnaryOp(Scope *S, SourceLocation OpLoc, + UnaryOperatorKind Opc, Expr *Input); + ExprResult ActOnUnaryOp(Scope *S, SourceLocation OpLoc, + tok::TokenKind Op, Expr *Input); + + ExprResult CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo, + SourceLocation OpLoc, + UnaryExprOrTypeTrait ExprKind, + SourceRange R); + ExprResult CreateUnaryExprOrTypeTraitExpr(Expr *E, SourceLocation OpLoc, + UnaryExprOrTypeTrait ExprKind); + ExprResult + ActOnUnaryExprOrTypeTraitExpr(SourceLocation OpLoc, + UnaryExprOrTypeTrait ExprKind, + bool IsType, void *TyOrEx, + const SourceRange &ArgRange); + + ExprResult CheckPlaceholderExpr(Expr *E); + bool CheckVecStepExpr(Expr *E); + + bool CheckUnaryExprOrTypeTraitOperand(Expr *E, UnaryExprOrTypeTrait ExprKind); + bool CheckUnaryExprOrTypeTraitOperand(QualType ExprType, SourceLocation OpLoc, + SourceRange ExprRange, + UnaryExprOrTypeTrait ExprKind); + ExprResult ActOnSizeofParameterPackExpr(Scope *S, + SourceLocation OpLoc, + IdentifierInfo &Name, + SourceLocation NameLoc, + SourceLocation RParenLoc); + ExprResult ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc, + tok::TokenKind Kind, Expr *Input); + + ExprResult ActOnArraySubscriptExpr(Scope *S, Expr *Base, SourceLocation LLoc, + Expr *Idx, SourceLocation RLoc); + ExprResult CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, + Expr *Idx, SourceLocation RLoc); + + ExprResult BuildMemberReferenceExpr(Expr *Base, QualType BaseType, + SourceLocation OpLoc, bool IsArrow, + CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, + NamedDecl *FirstQualifierInScope, + const DeclarationNameInfo &NameInfo, + const TemplateArgumentListInfo *TemplateArgs); + + ExprResult BuildMemberReferenceExpr(Expr *Base, QualType BaseType, + SourceLocation OpLoc, bool IsArrow, + const CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, + NamedDecl *FirstQualifierInScope, + LookupResult &R, + const TemplateArgumentListInfo *TemplateArgs, + bool SuppressQualifierCheck = false); + + ExprResult PerformMemberExprBaseConversion(Expr *Base, bool IsArrow); + ExprResult LookupMemberExpr(LookupResult &R, ExprResult &Base, + bool &IsArrow, SourceLocation OpLoc, + CXXScopeSpec &SS, + Decl *ObjCImpDecl, + bool HasTemplateArgs); + + bool CheckQualifiedMemberReference(Expr *BaseExpr, QualType BaseType, + const CXXScopeSpec &SS, + const LookupResult &R); + + ExprResult ActOnDependentMemberExpr(Expr *Base, QualType BaseType, + bool IsArrow, SourceLocation OpLoc, + const CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, + NamedDecl *FirstQualifierInScope, + const DeclarationNameInfo &NameInfo, + const TemplateArgumentListInfo *TemplateArgs); + + ExprResult ActOnMemberAccessExpr(Scope *S, Expr *Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, + UnqualifiedId &Member, + Decl *ObjCImpDecl, + bool HasTrailingLParen); + + void ActOnDefaultCtorInitializers(Decl *CDtorDecl); + bool ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, + FunctionDecl *FDecl, + const FunctionProtoType *Proto, + Expr **Args, unsigned NumArgs, + SourceLocation RParenLoc, + bool ExecConfig = false); + void CheckStaticArrayArgument(SourceLocation CallLoc, + ParmVarDecl *Param, + const Expr *ArgExpr); + + /// ActOnCallExpr - Handle a call to Fn with the specified array of arguments. + /// This provides the location of the left/right parens and a list of comma + /// locations. + ExprResult ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, + MultiExprArg ArgExprs, SourceLocation RParenLoc, + Expr *ExecConfig = 0, bool IsExecConfig = false); + ExprResult BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, + SourceLocation LParenLoc, + Expr **Args, unsigned NumArgs, + SourceLocation RParenLoc, + Expr *Config = 0, + bool IsExecConfig = false); + + ExprResult ActOnCUDAExecConfigExpr(Scope *S, SourceLocation LLLLoc, + MultiExprArg ExecConfig, + SourceLocation GGGLoc); + + ExprResult ActOnCastExpr(Scope *S, SourceLocation LParenLoc, + Declarator &D, ParsedType &Ty, + SourceLocation RParenLoc, Expr *CastExpr); + ExprResult BuildCStyleCastExpr(SourceLocation LParenLoc, + TypeSourceInfo *Ty, + SourceLocation RParenLoc, + Expr *Op); + CastKind PrepareScalarCast(ExprResult &src, QualType destType); + + /// \brief Build an altivec or OpenCL literal. + ExprResult BuildVectorLiteral(SourceLocation LParenLoc, + SourceLocation RParenLoc, Expr *E, + TypeSourceInfo *TInfo); + + ExprResult MaybeConvertParenListExprToParenExpr(Scope *S, Expr *ME); + + ExprResult ActOnCompoundLiteral(SourceLocation LParenLoc, + ParsedType Ty, + SourceLocation RParenLoc, + Expr *InitExpr); + + ExprResult BuildCompoundLiteralExpr(SourceLocation LParenLoc, + TypeSourceInfo *TInfo, + SourceLocation RParenLoc, + Expr *LiteralExpr); + + ExprResult ActOnInitList(SourceLocation LBraceLoc, + MultiExprArg InitArgList, + SourceLocation RBraceLoc); + + ExprResult ActOnDesignatedInitializer(Designation &Desig, + SourceLocation Loc, + bool GNUSyntax, + ExprResult Init); + + ExprResult ActOnBinOp(Scope *S, SourceLocation TokLoc, + tok::TokenKind Kind, Expr *LHSExpr, Expr *RHSExpr); + ExprResult BuildBinOp(Scope *S, SourceLocation OpLoc, + BinaryOperatorKind Opc, Expr *LHSExpr, Expr *RHSExpr); + ExprResult CreateBuiltinBinOp(SourceLocation OpLoc, BinaryOperatorKind Opc, + Expr *LHSExpr, Expr *RHSExpr); + + /// ActOnConditionalOp - Parse a ?: operation. Note that 'LHS' may be null + /// in the case of a the GNU conditional expr extension. + ExprResult ActOnConditionalOp(SourceLocation QuestionLoc, + SourceLocation ColonLoc, + Expr *CondExpr, Expr *LHSExpr, Expr *RHSExpr); + + /// ActOnAddrLabel - Parse the GNU address of label extension: "&&foo". + ExprResult ActOnAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc, + LabelDecl *TheDecl); + + void ActOnStartStmtExpr(); + ExprResult ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt, + SourceLocation RPLoc); // "({..})" + void ActOnStmtExprError(); + + // __builtin_offsetof(type, identifier(.identifier|[expr])*) + struct OffsetOfComponent { + SourceLocation LocStart, LocEnd; + bool isBrackets; // true if [expr], false if .ident + union { + IdentifierInfo *IdentInfo; + Expr *E; + } U; + }; + + /// __builtin_offsetof(type, a.b[123][456].c) + ExprResult BuildBuiltinOffsetOf(SourceLocation BuiltinLoc, + TypeSourceInfo *TInfo, + OffsetOfComponent *CompPtr, + unsigned NumComponents, + SourceLocation RParenLoc); + ExprResult ActOnBuiltinOffsetOf(Scope *S, + SourceLocation BuiltinLoc, + SourceLocation TypeLoc, + ParsedType ParsedArgTy, + OffsetOfComponent *CompPtr, + unsigned NumComponents, + SourceLocation RParenLoc); + + // __builtin_choose_expr(constExpr, expr1, expr2) + ExprResult ActOnChooseExpr(SourceLocation BuiltinLoc, + Expr *CondExpr, Expr *LHSExpr, + Expr *RHSExpr, SourceLocation RPLoc); + + // __builtin_va_arg(expr, type) + ExprResult ActOnVAArg(SourceLocation BuiltinLoc, Expr *E, ParsedType Ty, + SourceLocation RPLoc); + ExprResult BuildVAArgExpr(SourceLocation BuiltinLoc, Expr *E, + TypeSourceInfo *TInfo, SourceLocation RPLoc); + + // __null + ExprResult ActOnGNUNullExpr(SourceLocation TokenLoc); + + bool CheckCaseExpression(Expr *E); + + /// \brief Describes the result of an "if-exists" condition check. + enum IfExistsResult { + /// \brief The symbol exists. + IER_Exists, + + /// \brief The symbol does not exist. + IER_DoesNotExist, + + /// \brief The name is a dependent name, so the results will differ + /// from one instantiation to the next. + IER_Dependent, + + /// \brief An error occurred. + IER_Error + }; + + IfExistsResult + CheckMicrosoftIfExistsSymbol(Scope *S, CXXScopeSpec &SS, + const DeclarationNameInfo &TargetNameInfo); + + IfExistsResult + CheckMicrosoftIfExistsSymbol(Scope *S, SourceLocation KeywordLoc, + bool IsIfExists, CXXScopeSpec &SS, + UnqualifiedId &Name); + + StmtResult BuildMSDependentExistsStmt(SourceLocation KeywordLoc, + bool IsIfExists, + NestedNameSpecifierLoc QualifierLoc, + DeclarationNameInfo NameInfo, + Stmt *Nested); + StmtResult ActOnMSDependentExistsStmt(SourceLocation KeywordLoc, + bool IsIfExists, + CXXScopeSpec &SS, UnqualifiedId &Name, + Stmt *Nested); + + //===------------------------- "Block" Extension ------------------------===// + + /// ActOnBlockStart - This callback is invoked when a block literal is + /// started. + void ActOnBlockStart(SourceLocation CaretLoc, Scope *CurScope); + + /// ActOnBlockArguments - This callback allows processing of block arguments. + /// If there are no arguments, this is still invoked. + void ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope); + + /// ActOnBlockError - If there is an error parsing a block, this callback + /// is invoked to pop the information about the block from the action impl. + void ActOnBlockError(SourceLocation CaretLoc, Scope *CurScope); + + /// ActOnBlockStmtExpr - This is called when the body of a block statement + /// literal was successfully completed. ^(int x){...} + ExprResult ActOnBlockStmtExpr(SourceLocation CaretLoc, Stmt *Body, + Scope *CurScope); + + //===---------------------------- OpenCL Features -----------------------===// + + /// __builtin_astype(...) + ExprResult ActOnAsTypeExpr(Expr *E, ParsedType ParsedDestTy, + SourceLocation BuiltinLoc, + SourceLocation RParenLoc); + + //===---------------------------- C++ Features --------------------------===// + + // Act on C++ namespaces + Decl *ActOnStartNamespaceDef(Scope *S, SourceLocation InlineLoc, + SourceLocation NamespaceLoc, + SourceLocation IdentLoc, + IdentifierInfo *Ident, + SourceLocation LBrace, + AttributeList *AttrList); + void ActOnFinishNamespaceDef(Decl *Dcl, SourceLocation RBrace); + + NamespaceDecl *getStdNamespace() const; + NamespaceDecl *getOrCreateStdNamespace(); + + CXXRecordDecl *getStdBadAlloc() const; + + /// \brief Tests whether Ty is an instance of std::initializer_list and, if + /// it is and Element is not NULL, assigns the element type to Element. + bool isStdInitializerList(QualType Ty, QualType *Element); + + /// \brief Looks for the std::initializer_list template and instantiates it + /// with Element, or emits an error if it's not found. + /// + /// \returns The instantiated template, or null on error. + QualType BuildStdInitializerList(QualType Element, SourceLocation Loc); + + /// \brief Determine whether Ctor is an initializer-list constructor, as + /// defined in [dcl.init.list]p2. + bool isInitListConstructor(const CXXConstructorDecl *Ctor); + + Decl *ActOnUsingDirective(Scope *CurScope, + SourceLocation UsingLoc, + SourceLocation NamespcLoc, + CXXScopeSpec &SS, + SourceLocation IdentLoc, + IdentifierInfo *NamespcName, + AttributeList *AttrList); + + void PushUsingDirective(Scope *S, UsingDirectiveDecl *UDir); + + Decl *ActOnNamespaceAliasDef(Scope *CurScope, + SourceLocation NamespaceLoc, + SourceLocation AliasLoc, + IdentifierInfo *Alias, + CXXScopeSpec &SS, + SourceLocation IdentLoc, + IdentifierInfo *Ident); + + void HideUsingShadowDecl(Scope *S, UsingShadowDecl *Shadow); + bool CheckUsingShadowDecl(UsingDecl *UD, NamedDecl *Target, + const LookupResult &PreviousDecls); + UsingShadowDecl *BuildUsingShadowDecl(Scope *S, UsingDecl *UD, + NamedDecl *Target); + + bool CheckUsingDeclRedeclaration(SourceLocation UsingLoc, + bool isTypeName, + const CXXScopeSpec &SS, + SourceLocation NameLoc, + const LookupResult &Previous); + bool CheckUsingDeclQualifier(SourceLocation UsingLoc, + const CXXScopeSpec &SS, + SourceLocation NameLoc); + + NamedDecl *BuildUsingDeclaration(Scope *S, AccessSpecifier AS, + SourceLocation UsingLoc, + CXXScopeSpec &SS, + const DeclarationNameInfo &NameInfo, + AttributeList *AttrList, + bool IsInstantiation, + bool IsTypeName, + SourceLocation TypenameLoc); + + bool CheckInheritingConstructorUsingDecl(UsingDecl *UD); + + Decl *ActOnUsingDeclaration(Scope *CurScope, + AccessSpecifier AS, + bool HasUsingKeyword, + SourceLocation UsingLoc, + CXXScopeSpec &SS, + UnqualifiedId &Name, + AttributeList *AttrList, + bool IsTypeName, + SourceLocation TypenameLoc); + Decl *ActOnAliasDeclaration(Scope *CurScope, + AccessSpecifier AS, + MultiTemplateParamsArg TemplateParams, + SourceLocation UsingLoc, + UnqualifiedId &Name, + TypeResult Type); + + /// InitializeVarWithConstructor - Creates an CXXConstructExpr + /// and sets it as the initializer for the the passed in VarDecl. + bool InitializeVarWithConstructor(VarDecl *VD, + CXXConstructorDecl *Constructor, + MultiExprArg Exprs, + bool HadMultipleCandidates); + + /// BuildCXXConstructExpr - Creates a complete call to a constructor, + /// including handling of its default argument expressions. + /// + /// \param ConstructKind - a CXXConstructExpr::ConstructionKind + ExprResult + BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, + CXXConstructorDecl *Constructor, MultiExprArg Exprs, + bool HadMultipleCandidates, bool RequiresZeroInit, + unsigned ConstructKind, SourceRange ParenRange); + + // FIXME: Can re remove this and have the above BuildCXXConstructExpr check if + // the constructor can be elidable? + ExprResult + BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, + CXXConstructorDecl *Constructor, bool Elidable, + MultiExprArg Exprs, bool HadMultipleCandidates, + bool RequiresZeroInit, unsigned ConstructKind, + SourceRange ParenRange); + + /// BuildCXXDefaultArgExpr - Creates a CXXDefaultArgExpr, instantiating + /// the default expr if needed. + ExprResult BuildCXXDefaultArgExpr(SourceLocation CallLoc, + FunctionDecl *FD, + ParmVarDecl *Param); + + /// FinalizeVarWithDestructor - Prepare for calling destructor on the + /// constructed variable. + void FinalizeVarWithDestructor(VarDecl *VD, const RecordType *DeclInitType); + + /// \brief Helper class that collects exception specifications for + /// implicitly-declared special member functions. + class ImplicitExceptionSpecification { + // Pointer to allow copying + Sema *Self; + // We order exception specifications thus: + // noexcept is the most restrictive, but is only used in C++0x. + // throw() comes next. + // Then a throw(collected exceptions) + // Finally no specification. + // throw(...) is used instead if any called function uses it. + // + // If this exception specification cannot be known yet (for instance, + // because this is the exception specification for a defaulted default + // constructor and we haven't finished parsing the deferred parts of the + // class yet), the C++0x standard does not specify how to behave. We + // record this as an 'unknown' exception specification, which overrules + // any other specification (even 'none', to keep this rule simple). + ExceptionSpecificationType ComputedEST; + llvm::SmallPtrSet<CanQualType, 4> ExceptionsSeen; + SmallVector<QualType, 4> Exceptions; + + void ClearExceptions() { + ExceptionsSeen.clear(); + Exceptions.clear(); + } + + public: + explicit ImplicitExceptionSpecification(Sema &Self) + : Self(&Self), ComputedEST(EST_BasicNoexcept) { + if (!Self.Context.getLangOpts().CPlusPlus0x) + ComputedEST = EST_DynamicNone; + } + + /// \brief Get the computed exception specification type. + ExceptionSpecificationType getExceptionSpecType() const { + assert(ComputedEST != EST_ComputedNoexcept && + "noexcept(expr) should not be a possible result"); + return ComputedEST; + } + + /// \brief The number of exceptions in the exception specification. + unsigned size() const { return Exceptions.size(); } + + /// \brief The set of exceptions in the exception specification. + const QualType *data() const { return Exceptions.data(); } + + /// \brief Integrate another called method into the collected data. + void CalledDecl(SourceLocation CallLoc, CXXMethodDecl *Method); + + /// \brief Integrate an invoked expression into the collected data. + void CalledExpr(Expr *E); + + /// \brief Specify that the exception specification can't be detemined yet. + void SetDelayed() { + ClearExceptions(); + ComputedEST = EST_Delayed; + } + + FunctionProtoType::ExtProtoInfo getEPI() const { + FunctionProtoType::ExtProtoInfo EPI; + EPI.ExceptionSpecType = getExceptionSpecType(); + EPI.NumExceptions = size(); + EPI.Exceptions = data(); + return EPI; + } + }; + + /// \brief Determine what sort of exception specification a defaulted + /// copy constructor of a class will have. + ImplicitExceptionSpecification + ComputeDefaultedDefaultCtorExceptionSpec(CXXRecordDecl *ClassDecl); + + /// \brief Determine what sort of exception specification a defaulted + /// default constructor of a class will have, and whether the parameter + /// will be const. + std::pair<ImplicitExceptionSpecification, bool> + ComputeDefaultedCopyCtorExceptionSpecAndConst(CXXRecordDecl *ClassDecl); + + /// \brief Determine what sort of exception specification a defautled + /// copy assignment operator of a class will have, and whether the + /// parameter will be const. + std::pair<ImplicitExceptionSpecification, bool> + ComputeDefaultedCopyAssignmentExceptionSpecAndConst(CXXRecordDecl *ClassDecl); + + /// \brief Determine what sort of exception specification a defaulted move + /// constructor of a class will have. + ImplicitExceptionSpecification + ComputeDefaultedMoveCtorExceptionSpec(CXXRecordDecl *ClassDecl); + + /// \brief Determine what sort of exception specification a defaulted move + /// assignment operator of a class will have. + ImplicitExceptionSpecification + ComputeDefaultedMoveAssignmentExceptionSpec(CXXRecordDecl *ClassDecl); + + /// \brief Determine what sort of exception specification a defaulted + /// destructor of a class will have. + ImplicitExceptionSpecification + ComputeDefaultedDtorExceptionSpec(CXXRecordDecl *ClassDecl); + + /// \brief Check the given exception-specification and update the + /// extended prototype information with the results. + void checkExceptionSpecification(ExceptionSpecificationType EST, + ArrayRef<ParsedType> DynamicExceptions, + ArrayRef<SourceRange> DynamicExceptionRanges, + Expr *NoexceptExpr, + llvm::SmallVectorImpl<QualType> &Exceptions, + FunctionProtoType::ExtProtoInfo &EPI); + + /// \brief Determine if a special member function should have a deleted + /// definition when it is defaulted. + bool ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM, + bool Diagnose = false); + + /// \brief Declare the implicit default constructor for the given class. + /// + /// \param ClassDecl The class declaration into which the implicit + /// default constructor will be added. + /// + /// \returns The implicitly-declared default constructor. + CXXConstructorDecl *DeclareImplicitDefaultConstructor( + CXXRecordDecl *ClassDecl); + + /// DefineImplicitDefaultConstructor - Checks for feasibility of + /// defining this constructor as the default constructor. + void DefineImplicitDefaultConstructor(SourceLocation CurrentLocation, + CXXConstructorDecl *Constructor); + + /// \brief Declare the implicit destructor for the given class. + /// + /// \param ClassDecl The class declaration into which the implicit + /// destructor will be added. + /// + /// \returns The implicitly-declared destructor. + CXXDestructorDecl *DeclareImplicitDestructor(CXXRecordDecl *ClassDecl); + + /// DefineImplicitDestructor - Checks for feasibility of + /// defining this destructor as the default destructor. + void DefineImplicitDestructor(SourceLocation CurrentLocation, + CXXDestructorDecl *Destructor); + + /// \brief Build an exception spec for destructors that don't have one. + /// + /// C++11 says that user-defined destructors with no exception spec get one + /// that looks as if the destructor was implicitly declared. + void AdjustDestructorExceptionSpec(CXXRecordDecl *ClassDecl, + CXXDestructorDecl *Destructor, + bool WasDelayed = false); + + /// \brief Declare all inherited constructors for the given class. + /// + /// \param ClassDecl The class declaration into which the inherited + /// constructors will be added. + void DeclareInheritedConstructors(CXXRecordDecl *ClassDecl); + + /// \brief Declare the implicit copy constructor for the given class. + /// + /// \param ClassDecl The class declaration into which the implicit + /// copy constructor will be added. + /// + /// \returns The implicitly-declared copy constructor. + CXXConstructorDecl *DeclareImplicitCopyConstructor(CXXRecordDecl *ClassDecl); + + /// DefineImplicitCopyConstructor - Checks for feasibility of + /// defining this constructor as the copy constructor. + void DefineImplicitCopyConstructor(SourceLocation CurrentLocation, + CXXConstructorDecl *Constructor); + + /// \brief Declare the implicit move constructor for the given class. + /// + /// \param ClassDecl The Class declaration into which the implicit + /// move constructor will be added. + /// + /// \returns The implicitly-declared move constructor, or NULL if it wasn't + /// declared. + CXXConstructorDecl *DeclareImplicitMoveConstructor(CXXRecordDecl *ClassDecl); + + /// DefineImplicitMoveConstructor - Checks for feasibility of + /// defining this constructor as the move constructor. + void DefineImplicitMoveConstructor(SourceLocation CurrentLocation, + CXXConstructorDecl *Constructor); + + /// \brief Declare the implicit copy assignment operator for the given class. + /// + /// \param ClassDecl The class declaration into which the implicit + /// copy assignment operator will be added. + /// + /// \returns The implicitly-declared copy assignment operator. + CXXMethodDecl *DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl); + + /// \brief Defines an implicitly-declared copy assignment operator. + void DefineImplicitCopyAssignment(SourceLocation CurrentLocation, + CXXMethodDecl *MethodDecl); + + /// \brief Declare the implicit move assignment operator for the given class. + /// + /// \param ClassDecl The Class declaration into which the implicit + /// move assignment operator will be added. + /// + /// \returns The implicitly-declared move assignment operator, or NULL if it + /// wasn't declared. + CXXMethodDecl *DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl); + + /// \brief Defines an implicitly-declared move assignment operator. + void DefineImplicitMoveAssignment(SourceLocation CurrentLocation, + CXXMethodDecl *MethodDecl); + + /// \brief Force the declaration of any implicitly-declared members of this + /// class. + void ForceDeclarationOfImplicitMembers(CXXRecordDecl *Class); + + /// \brief Determine whether the given function is an implicitly-deleted + /// special member function. + bool isImplicitlyDeleted(FunctionDecl *FD); + + /// \brief Check whether 'this' shows up in the type of a static member + /// function after the (naturally empty) cv-qualifier-seq would be. + /// + /// \returns true if an error occurred. + bool checkThisInStaticMemberFunctionType(CXXMethodDecl *Method); + + /// \brief Whether this' shows up in the exception specification of a static + /// member function. + bool checkThisInStaticMemberFunctionExceptionSpec(CXXMethodDecl *Method); + + /// \brief Check whether 'this' shows up in the attributes of the given + /// static member function. + /// + /// \returns true if an error occurred. + bool checkThisInStaticMemberFunctionAttributes(CXXMethodDecl *Method); + + /// MaybeBindToTemporary - If the passed in expression has a record type with + /// a non-trivial destructor, this will return CXXBindTemporaryExpr. Otherwise + /// it simply returns the passed in expression. + ExprResult MaybeBindToTemporary(Expr *E); + + bool CompleteConstructorCall(CXXConstructorDecl *Constructor, + MultiExprArg ArgsPtr, + SourceLocation Loc, + ASTOwningVector<Expr*> &ConvertedArgs, + bool AllowExplicit = false); + + ParsedType getDestructorName(SourceLocation TildeLoc, + IdentifierInfo &II, SourceLocation NameLoc, + Scope *S, CXXScopeSpec &SS, + ParsedType ObjectType, + bool EnteringContext); + + ParsedType getDestructorType(const DeclSpec& DS, ParsedType ObjectType); + + // Checks that reinterpret casts don't have undefined behavior. + void CheckCompatibleReinterpretCast(QualType SrcType, QualType DestType, + bool IsDereference, SourceRange Range); + + /// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's. + ExprResult ActOnCXXNamedCast(SourceLocation OpLoc, + tok::TokenKind Kind, + SourceLocation LAngleBracketLoc, + Declarator &D, + SourceLocation RAngleBracketLoc, + SourceLocation LParenLoc, + Expr *E, + SourceLocation RParenLoc); + + ExprResult BuildCXXNamedCast(SourceLocation OpLoc, + tok::TokenKind Kind, + TypeSourceInfo *Ty, + Expr *E, + SourceRange AngleBrackets, + SourceRange Parens); + + ExprResult BuildCXXTypeId(QualType TypeInfoType, + SourceLocation TypeidLoc, + TypeSourceInfo *Operand, + SourceLocation RParenLoc); + ExprResult BuildCXXTypeId(QualType TypeInfoType, + SourceLocation TypeidLoc, + Expr *Operand, + SourceLocation RParenLoc); + + /// ActOnCXXTypeid - Parse typeid( something ). + ExprResult ActOnCXXTypeid(SourceLocation OpLoc, + SourceLocation LParenLoc, bool isType, + void *TyOrExpr, + SourceLocation RParenLoc); + + ExprResult BuildCXXUuidof(QualType TypeInfoType, + SourceLocation TypeidLoc, + TypeSourceInfo *Operand, + SourceLocation RParenLoc); + ExprResult BuildCXXUuidof(QualType TypeInfoType, + SourceLocation TypeidLoc, + Expr *Operand, + SourceLocation RParenLoc); + + /// ActOnCXXUuidof - Parse __uuidof( something ). + ExprResult ActOnCXXUuidof(SourceLocation OpLoc, + SourceLocation LParenLoc, bool isType, + void *TyOrExpr, + SourceLocation RParenLoc); + + + //// ActOnCXXThis - Parse 'this' pointer. + ExprResult ActOnCXXThis(SourceLocation loc); + + /// \brief Try to retrieve the type of the 'this' pointer. + /// + /// \param Capture If true, capture 'this' in this context. + /// + /// \returns The type of 'this', if possible. Otherwise, returns a NULL type. + QualType getCurrentThisType(); + + /// \brief When non-NULL, the C++ 'this' expression is allowed despite the + /// current context not being a non-static member function. In such cases, + /// this provides the type used for 'this'. + QualType CXXThisTypeOverride; + + /// \brief RAII object used to temporarily allow the C++ 'this' expression + /// to be used, with the given qualifiers on the current class type. + class CXXThisScopeRAII { + Sema &S; + QualType OldCXXThisTypeOverride; + bool Enabled; + + public: + /// \brief Introduce a new scope where 'this' may be allowed (when enabled), + /// using the given declaration (which is either a class template or a + /// class) along with the given qualifiers. + /// along with the qualifiers placed on '*this'. + CXXThisScopeRAII(Sema &S, Decl *ContextDecl, unsigned CXXThisTypeQuals, + bool Enabled = true); + + ~CXXThisScopeRAII(); + }; + + /// \brief Make sure the value of 'this' is actually available in the current + /// context, if it is a potentially evaluated context. + /// + /// \param Loc The location at which the capture of 'this' occurs. + /// + /// \param Explicit Whether 'this' is explicitly captured in a lambda + /// capture list. + void CheckCXXThisCapture(SourceLocation Loc, bool Explicit = false); + + /// \brief Determine whether the given type is the type of *this that is used + /// outside of the body of a member function for a type that is currently + /// being defined. + bool isThisOutsideMemberFunctionBody(QualType BaseType); + + /// ActOnCXXBoolLiteral - Parse {true,false} literals. + ExprResult ActOnCXXBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind); + + + /// ActOnObjCBoolLiteral - Parse {__objc_yes,__objc_no} literals. + ExprResult ActOnObjCBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind); + + /// ActOnCXXNullPtrLiteral - Parse 'nullptr'. + ExprResult ActOnCXXNullPtrLiteral(SourceLocation Loc); + + //// ActOnCXXThrow - Parse throw expressions. + ExprResult ActOnCXXThrow(Scope *S, SourceLocation OpLoc, Expr *expr); + ExprResult BuildCXXThrow(SourceLocation OpLoc, Expr *Ex, + bool IsThrownVarInScope); + ExprResult CheckCXXThrowOperand(SourceLocation ThrowLoc, Expr *E, + bool IsThrownVarInScope); + + /// ActOnCXXTypeConstructExpr - Parse construction of a specified type. + /// Can be interpreted either as function-style casting ("int(x)") + /// or class type construction ("ClassType(x,y,z)") + /// or creation of a value-initialized type ("int()"). + ExprResult ActOnCXXTypeConstructExpr(ParsedType TypeRep, + SourceLocation LParenLoc, + MultiExprArg Exprs, + SourceLocation RParenLoc); + + ExprResult BuildCXXTypeConstructExpr(TypeSourceInfo *Type, + SourceLocation LParenLoc, + MultiExprArg Exprs, + SourceLocation RParenLoc); + + /// ActOnCXXNew - Parsed a C++ 'new' expression. + ExprResult ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, + SourceLocation PlacementLParen, + MultiExprArg PlacementArgs, + SourceLocation PlacementRParen, + SourceRange TypeIdParens, Declarator &D, + Expr *Initializer); + ExprResult BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, + SourceLocation PlacementLParen, + MultiExprArg PlacementArgs, + SourceLocation PlacementRParen, + SourceRange TypeIdParens, + QualType AllocType, + TypeSourceInfo *AllocTypeInfo, + Expr *ArraySize, + SourceRange DirectInitRange, + Expr *Initializer, + bool TypeMayContainAuto = true); + + bool CheckAllocatedType(QualType AllocType, SourceLocation Loc, + SourceRange R); + bool FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, + bool UseGlobal, QualType AllocType, bool IsArray, + Expr **PlaceArgs, unsigned NumPlaceArgs, + FunctionDecl *&OperatorNew, + FunctionDecl *&OperatorDelete); + bool FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, + DeclarationName Name, Expr** Args, + unsigned NumArgs, DeclContext *Ctx, + bool AllowMissing, FunctionDecl *&Operator, + bool Diagnose = true); + void DeclareGlobalNewDelete(); + void DeclareGlobalAllocationFunction(DeclarationName Name, QualType Return, + QualType Argument, + bool addMallocAttr = false); + + bool FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, + DeclarationName Name, FunctionDecl* &Operator, + bool Diagnose = true); + + /// ActOnCXXDelete - Parsed a C++ 'delete' expression + ExprResult ActOnCXXDelete(SourceLocation StartLoc, + bool UseGlobal, bool ArrayForm, + Expr *Operand); + + DeclResult ActOnCXXConditionDeclaration(Scope *S, Declarator &D); + ExprResult CheckConditionVariable(VarDecl *ConditionVar, + SourceLocation StmtLoc, + bool ConvertToBoolean); + + ExprResult ActOnNoexceptExpr(SourceLocation KeyLoc, SourceLocation LParen, + Expr *Operand, SourceLocation RParen); + ExprResult BuildCXXNoexceptExpr(SourceLocation KeyLoc, Expr *Operand, + SourceLocation RParen); + + /// ActOnUnaryTypeTrait - Parsed one of the unary type trait support + /// pseudo-functions. + ExprResult ActOnUnaryTypeTrait(UnaryTypeTrait OTT, + SourceLocation KWLoc, + ParsedType Ty, + SourceLocation RParen); + + ExprResult BuildUnaryTypeTrait(UnaryTypeTrait OTT, + SourceLocation KWLoc, + TypeSourceInfo *T, + SourceLocation RParen); + + /// ActOnBinaryTypeTrait - Parsed one of the bianry type trait support + /// pseudo-functions. + ExprResult ActOnBinaryTypeTrait(BinaryTypeTrait OTT, + SourceLocation KWLoc, + ParsedType LhsTy, + ParsedType RhsTy, + SourceLocation RParen); + + ExprResult BuildBinaryTypeTrait(BinaryTypeTrait BTT, + SourceLocation KWLoc, + TypeSourceInfo *LhsT, + TypeSourceInfo *RhsT, + SourceLocation RParen); + + /// \brief Parsed one of the type trait support pseudo-functions. + ExprResult ActOnTypeTrait(TypeTrait Kind, SourceLocation KWLoc, + ArrayRef<ParsedType> Args, + SourceLocation RParenLoc); + ExprResult BuildTypeTrait(TypeTrait Kind, SourceLocation KWLoc, + ArrayRef<TypeSourceInfo *> Args, + SourceLocation RParenLoc); + + /// ActOnArrayTypeTrait - Parsed one of the bianry type trait support + /// pseudo-functions. + ExprResult ActOnArrayTypeTrait(ArrayTypeTrait ATT, + SourceLocation KWLoc, + ParsedType LhsTy, + Expr *DimExpr, + SourceLocation RParen); + + ExprResult BuildArrayTypeTrait(ArrayTypeTrait ATT, + SourceLocation KWLoc, + TypeSourceInfo *TSInfo, + Expr *DimExpr, + SourceLocation RParen); + + /// ActOnExpressionTrait - Parsed one of the unary type trait support + /// pseudo-functions. + ExprResult ActOnExpressionTrait(ExpressionTrait OET, + SourceLocation KWLoc, + Expr *Queried, + SourceLocation RParen); + + ExprResult BuildExpressionTrait(ExpressionTrait OET, + SourceLocation KWLoc, + Expr *Queried, + SourceLocation RParen); + + ExprResult ActOnStartCXXMemberReference(Scope *S, + Expr *Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + ParsedType &ObjectType, + bool &MayBePseudoDestructor); + + ExprResult DiagnoseDtorReference(SourceLocation NameLoc, Expr *MemExpr); + + ExprResult BuildPseudoDestructorExpr(Expr *Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + const CXXScopeSpec &SS, + TypeSourceInfo *ScopeType, + SourceLocation CCLoc, + SourceLocation TildeLoc, + PseudoDestructorTypeStorage DestroyedType, + bool HasTrailingLParen); + + ExprResult ActOnPseudoDestructorExpr(Scope *S, Expr *Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + CXXScopeSpec &SS, + UnqualifiedId &FirstTypeName, + SourceLocation CCLoc, + SourceLocation TildeLoc, + UnqualifiedId &SecondTypeName, + bool HasTrailingLParen); + + ExprResult ActOnPseudoDestructorExpr(Scope *S, Expr *Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + SourceLocation TildeLoc, + const DeclSpec& DS, + bool HasTrailingLParen); + + /// MaybeCreateExprWithCleanups - If the current full-expression + /// requires any cleanups, surround it with a ExprWithCleanups node. + /// Otherwise, just returns the passed-in expression. + Expr *MaybeCreateExprWithCleanups(Expr *SubExpr); + Stmt *MaybeCreateStmtWithCleanups(Stmt *SubStmt); + ExprResult MaybeCreateExprWithCleanups(ExprResult SubExpr); + + ExprResult ActOnFinishFullExpr(Expr *Expr); + StmtResult ActOnFinishFullStmt(Stmt *Stmt); + + // Marks SS invalid if it represents an incomplete type. + bool RequireCompleteDeclContext(CXXScopeSpec &SS, DeclContext *DC); + + DeclContext *computeDeclContext(QualType T); + DeclContext *computeDeclContext(const CXXScopeSpec &SS, + bool EnteringContext = false); + bool isDependentScopeSpecifier(const CXXScopeSpec &SS); + CXXRecordDecl *getCurrentInstantiationOf(NestedNameSpecifier *NNS); + bool isUnknownSpecialization(const CXXScopeSpec &SS); + + /// \brief The parser has parsed a global nested-name-specifier '::'. + /// + /// \param S The scope in which this nested-name-specifier occurs. + /// + /// \param CCLoc The location of the '::'. + /// + /// \param SS The nested-name-specifier, which will be updated in-place + /// to reflect the parsed nested-name-specifier. + /// + /// \returns true if an error occurred, false otherwise. + bool ActOnCXXGlobalScopeSpecifier(Scope *S, SourceLocation CCLoc, + CXXScopeSpec &SS); + + bool isAcceptableNestedNameSpecifier(NamedDecl *SD); + NamedDecl *FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS); + + bool isNonTypeNestedNameSpecifier(Scope *S, CXXScopeSpec &SS, + SourceLocation IdLoc, + IdentifierInfo &II, + ParsedType ObjectType); + + bool BuildCXXNestedNameSpecifier(Scope *S, + IdentifierInfo &Identifier, + SourceLocation IdentifierLoc, + SourceLocation CCLoc, + QualType ObjectType, + bool EnteringContext, + CXXScopeSpec &SS, + NamedDecl *ScopeLookupResult, + bool ErrorRecoveryLookup); + + /// \brief The parser has parsed a nested-name-specifier 'identifier::'. + /// + /// \param S The scope in which this nested-name-specifier occurs. + /// + /// \param Identifier The identifier preceding the '::'. + /// + /// \param IdentifierLoc The location of the identifier. + /// + /// \param CCLoc The location of the '::'. + /// + /// \param ObjectType The type of the object, if we're parsing + /// nested-name-specifier in a member access expression. + /// + /// \param EnteringContext Whether we're entering the context nominated by + /// this nested-name-specifier. + /// + /// \param SS The nested-name-specifier, which is both an input + /// parameter (the nested-name-specifier before this type) and an + /// output parameter (containing the full nested-name-specifier, + /// including this new type). + /// + /// \returns true if an error occurred, false otherwise. + bool ActOnCXXNestedNameSpecifier(Scope *S, + IdentifierInfo &Identifier, + SourceLocation IdentifierLoc, + SourceLocation CCLoc, + ParsedType ObjectType, + bool EnteringContext, + CXXScopeSpec &SS); + + ExprResult ActOnDecltypeExpression(Expr *E); + + bool ActOnCXXNestedNameSpecifierDecltype(CXXScopeSpec &SS, + const DeclSpec &DS, + SourceLocation ColonColonLoc); + + bool IsInvalidUnlessNestedName(Scope *S, CXXScopeSpec &SS, + IdentifierInfo &Identifier, + SourceLocation IdentifierLoc, + SourceLocation ColonLoc, + ParsedType ObjectType, + bool EnteringContext); + + /// \brief The parser has parsed a nested-name-specifier + /// 'template[opt] template-name < template-args >::'. + /// + /// \param S The scope in which this nested-name-specifier occurs. + /// + /// \param SS The nested-name-specifier, which is both an input + /// parameter (the nested-name-specifier before this type) and an + /// output parameter (containing the full nested-name-specifier, + /// including this new type). + /// + /// \param TemplateKWLoc the location of the 'template' keyword, if any. + /// \param TemplateName The template name. + /// \param TemplateNameLoc The location of the template name. + /// \param LAngleLoc The location of the opening angle bracket ('<'). + /// \param TemplateArgs The template arguments. + /// \param RAngleLoc The location of the closing angle bracket ('>'). + /// \param CCLoc The location of the '::'. + /// + /// \param EnteringContext Whether we're entering the context of the + /// nested-name-specifier. + /// + /// + /// \returns true if an error occurred, false otherwise. + bool ActOnCXXNestedNameSpecifier(Scope *S, + CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, + TemplateTy Template, + SourceLocation TemplateNameLoc, + SourceLocation LAngleLoc, + ASTTemplateArgsPtr TemplateArgs, + SourceLocation RAngleLoc, + SourceLocation CCLoc, + bool EnteringContext); + + /// \brief Given a C++ nested-name-specifier, produce an annotation value + /// that the parser can use later to reconstruct the given + /// nested-name-specifier. + /// + /// \param SS A nested-name-specifier. + /// + /// \returns A pointer containing all of the information in the + /// nested-name-specifier \p SS. + void *SaveNestedNameSpecifierAnnotation(CXXScopeSpec &SS); + + /// \brief Given an annotation pointer for a nested-name-specifier, restore + /// the nested-name-specifier structure. + /// + /// \param Annotation The annotation pointer, produced by + /// \c SaveNestedNameSpecifierAnnotation(). + /// + /// \param AnnotationRange The source range corresponding to the annotation. + /// + /// \param SS The nested-name-specifier that will be updated with the contents + /// of the annotation pointer. + void RestoreNestedNameSpecifierAnnotation(void *Annotation, + SourceRange AnnotationRange, + CXXScopeSpec &SS); + + bool ShouldEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS); + + /// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global + /// scope or nested-name-specifier) is parsed, part of a declarator-id. + /// After this method is called, according to [C++ 3.4.3p3], names should be + /// looked up in the declarator-id's scope, until the declarator is parsed and + /// ActOnCXXExitDeclaratorScope is called. + /// The 'SS' should be a non-empty valid CXXScopeSpec. + bool ActOnCXXEnterDeclaratorScope(Scope *S, CXXScopeSpec &SS); + + /// ActOnCXXExitDeclaratorScope - Called when a declarator that previously + /// invoked ActOnCXXEnterDeclaratorScope(), is finished. 'SS' is the same + /// CXXScopeSpec that was passed to ActOnCXXEnterDeclaratorScope as well. + /// Used to indicate that names should revert to being looked up in the + /// defining scope. + void ActOnCXXExitDeclaratorScope(Scope *S, const CXXScopeSpec &SS); + + /// ActOnCXXEnterDeclInitializer - Invoked when we are about to parse an + /// initializer for the declaration 'Dcl'. + /// After this method is called, according to [C++ 3.4.1p13], if 'Dcl' is a + /// static data member of class X, names should be looked up in the scope of + /// class X. + void ActOnCXXEnterDeclInitializer(Scope *S, Decl *Dcl); + + /// ActOnCXXExitDeclInitializer - Invoked after we are finished parsing an + /// initializer for the declaration 'Dcl'. + void ActOnCXXExitDeclInitializer(Scope *S, Decl *Dcl); + + /// \brief Create a new lambda closure type. + CXXRecordDecl *createLambdaClosureType(SourceRange IntroducerRange, + bool KnownDependent = false); + + /// \brief Start the definition of a lambda expression. + CXXMethodDecl *startLambdaDefinition(CXXRecordDecl *Class, + SourceRange IntroducerRange, + TypeSourceInfo *MethodType, + SourceLocation EndLoc, + llvm::ArrayRef<ParmVarDecl *> Params, + llvm::Optional<unsigned> ManglingNumber + = llvm::Optional<unsigned>(), + Decl *ContextDecl = 0); + + /// \brief Introduce the scope for a lambda expression. + sema::LambdaScopeInfo *enterLambdaScope(CXXMethodDecl *CallOperator, + SourceRange IntroducerRange, + LambdaCaptureDefault CaptureDefault, + bool ExplicitParams, + bool ExplicitResultType, + bool Mutable); + + /// \brief Note that we have finished the explicit captures for the + /// given lambda. + void finishLambdaExplicitCaptures(sema::LambdaScopeInfo *LSI); + + /// \brief Introduce the lambda parameters into scope. + void addLambdaParameters(CXXMethodDecl *CallOperator, Scope *CurScope); + + /// ActOnStartOfLambdaDefinition - This is called just before we start + /// parsing the body of a lambda; it analyzes the explicit captures and + /// arguments, and sets up various data-structures for the body of the + /// lambda. + void ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, + Declarator &ParamInfo, Scope *CurScope); + + /// ActOnLambdaError - If there is an error parsing a lambda, this callback + /// is invoked to pop the information about the lambda. + void ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope, + bool IsInstantiation = false); + + /// ActOnLambdaExpr - This is called when the body of a lambda expression + /// was successfully completed. + ExprResult ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, + Scope *CurScope, + bool IsInstantiation = false); + + /// \brief Define the "body" of the conversion from a lambda object to a + /// function pointer. + /// + /// This routine doesn't actually define a sensible body; rather, it fills + /// in the initialization expression needed to copy the lambda object into + /// the block, and IR generation actually generates the real body of the + /// block pointer conversion. + void DefineImplicitLambdaToFunctionPointerConversion( + SourceLocation CurrentLoc, CXXConversionDecl *Conv); + + /// \brief Define the "body" of the conversion from a lambda object to a + /// block pointer. + /// + /// This routine doesn't actually define a sensible body; rather, it fills + /// in the initialization expression needed to copy the lambda object into + /// the block, and IR generation actually generates the real body of the + /// block pointer conversion. + void DefineImplicitLambdaToBlockPointerConversion(SourceLocation CurrentLoc, + CXXConversionDecl *Conv); + + ExprResult BuildBlockForLambdaConversion(SourceLocation CurrentLocation, + SourceLocation ConvLocation, + CXXConversionDecl *Conv, + Expr *Src); + + // ParseObjCStringLiteral - Parse Objective-C string literals. + ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs, + Expr **Strings, + unsigned NumStrings); + + ExprResult BuildObjCStringLiteral(SourceLocation AtLoc, StringLiteral *S); + + /// BuildObjCNumericLiteral - builds an ObjCNumericLiteral AST node for the + /// numeric literal expression. Type of the expression will be "NSNumber *" + /// or "id" if NSNumber is unavailable. + ExprResult BuildObjCNumericLiteral(SourceLocation AtLoc, Expr *Number); + ExprResult ActOnObjCBoolLiteral(SourceLocation AtLoc, SourceLocation ValueLoc, + bool Value); + ExprResult BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements); + + ExprResult BuildObjCSubscriptExpression(SourceLocation RB, Expr *BaseExpr, + Expr *IndexExpr, + ObjCMethodDecl *getterMethod, + ObjCMethodDecl *setterMethod); + + ExprResult BuildObjCDictionaryLiteral(SourceRange SR, + ObjCDictionaryElement *Elements, + unsigned NumElements); + + ExprResult BuildObjCEncodeExpression(SourceLocation AtLoc, + TypeSourceInfo *EncodedTypeInfo, + SourceLocation RParenLoc); + ExprResult BuildCXXMemberCallExpr(Expr *Exp, NamedDecl *FoundDecl, + CXXConversionDecl *Method, + bool HadMultipleCandidates); + + ExprResult ParseObjCEncodeExpression(SourceLocation AtLoc, + SourceLocation EncodeLoc, + SourceLocation LParenLoc, + ParsedType Ty, + SourceLocation RParenLoc); + + // ParseObjCSelectorExpression - Build selector expression for @selector + ExprResult ParseObjCSelectorExpression(Selector Sel, + SourceLocation AtLoc, + SourceLocation SelLoc, + SourceLocation LParenLoc, + SourceLocation RParenLoc); + + // ParseObjCProtocolExpression - Build protocol expression for @protocol + ExprResult ParseObjCProtocolExpression(IdentifierInfo * ProtocolName, + SourceLocation AtLoc, + SourceLocation ProtoLoc, + SourceLocation LParenLoc, + SourceLocation RParenLoc); + + //===--------------------------------------------------------------------===// + // C++ Declarations + // + Decl *ActOnStartLinkageSpecification(Scope *S, + SourceLocation ExternLoc, + SourceLocation LangLoc, + StringRef Lang, + SourceLocation LBraceLoc); + Decl *ActOnFinishLinkageSpecification(Scope *S, + Decl *LinkageSpec, + SourceLocation RBraceLoc); + + + //===--------------------------------------------------------------------===// + // C++ Classes + // + bool isCurrentClassName(const IdentifierInfo &II, Scope *S, + const CXXScopeSpec *SS = 0); + + bool ActOnAccessSpecifier(AccessSpecifier Access, + SourceLocation ASLoc, + SourceLocation ColonLoc, + AttributeList *Attrs = 0); + + Decl *ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, + Declarator &D, + MultiTemplateParamsArg TemplateParameterLists, + Expr *BitfieldWidth, const VirtSpecifiers &VS, + bool HasDeferredInit); + void ActOnCXXInClassMemberInitializer(Decl *VarDecl, SourceLocation EqualLoc, + Expr *Init); + + MemInitResult ActOnMemInitializer(Decl *ConstructorD, + Scope *S, + CXXScopeSpec &SS, + IdentifierInfo *MemberOrBase, + ParsedType TemplateTypeTy, + const DeclSpec &DS, + SourceLocation IdLoc, + SourceLocation LParenLoc, + Expr **Args, unsigned NumArgs, + SourceLocation RParenLoc, + SourceLocation EllipsisLoc); + + MemInitResult ActOnMemInitializer(Decl *ConstructorD, + Scope *S, + CXXScopeSpec &SS, + IdentifierInfo *MemberOrBase, + ParsedType TemplateTypeTy, + const DeclSpec &DS, + SourceLocation IdLoc, + Expr *InitList, + SourceLocation EllipsisLoc); + + MemInitResult BuildMemInitializer(Decl *ConstructorD, + Scope *S, + CXXScopeSpec &SS, + IdentifierInfo *MemberOrBase, + ParsedType TemplateTypeTy, + const DeclSpec &DS, + SourceLocation IdLoc, + Expr *Init, + SourceLocation EllipsisLoc); + + MemInitResult BuildMemberInitializer(ValueDecl *Member, + Expr *Init, + SourceLocation IdLoc); + + MemInitResult BuildBaseInitializer(QualType BaseType, + TypeSourceInfo *BaseTInfo, + Expr *Init, + CXXRecordDecl *ClassDecl, + SourceLocation EllipsisLoc); + + MemInitResult BuildDelegatingInitializer(TypeSourceInfo *TInfo, + Expr *Init, + CXXRecordDecl *ClassDecl); + + bool SetDelegatingInitializer(CXXConstructorDecl *Constructor, + CXXCtorInitializer *Initializer); + + bool SetCtorInitializers(CXXConstructorDecl *Constructor, + CXXCtorInitializer **Initializers, + unsigned NumInitializers, bool AnyErrors); + + void SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation); + + + /// MarkBaseAndMemberDestructorsReferenced - Given a record decl, + /// mark all the non-trivial destructors of its members and bases as + /// referenced. + void MarkBaseAndMemberDestructorsReferenced(SourceLocation Loc, + CXXRecordDecl *Record); + + /// \brief The list of classes whose vtables have been used within + /// this translation unit, and the source locations at which the + /// first use occurred. + typedef std::pair<CXXRecordDecl*, SourceLocation> VTableUse; + + /// \brief The list of vtables that are required but have not yet been + /// materialized. + SmallVector<VTableUse, 16> VTableUses; + + /// \brief The set of classes whose vtables have been used within + /// this translation unit, and a bit that will be true if the vtable is + /// required to be emitted (otherwise, it should be emitted only if needed + /// by code generation). + llvm::DenseMap<CXXRecordDecl *, bool> VTablesUsed; + + /// \brief Load any externally-stored vtable uses. + void LoadExternalVTableUses(); + + typedef LazyVector<CXXRecordDecl *, ExternalSemaSource, + &ExternalSemaSource::ReadDynamicClasses, 2, 2> + DynamicClassesType; + + /// \brief A list of all of the dynamic classes in this translation + /// unit. + DynamicClassesType DynamicClasses; + + /// \brief Note that the vtable for the given class was used at the + /// given location. + void MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class, + bool DefinitionRequired = false); + + /// MarkVirtualMembersReferenced - Will mark all members of the given + /// CXXRecordDecl referenced. + void MarkVirtualMembersReferenced(SourceLocation Loc, + const CXXRecordDecl *RD); + + /// \brief Define all of the vtables that have been used in this + /// translation unit and reference any virtual members used by those + /// vtables. + /// + /// \returns true if any work was done, false otherwise. + bool DefineUsedVTables(); + + void AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl); + + void ActOnMemInitializers(Decl *ConstructorDecl, + SourceLocation ColonLoc, + CXXCtorInitializer **MemInits, + unsigned NumMemInits, + bool AnyErrors); + + void CheckCompletedCXXClass(CXXRecordDecl *Record); + void ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, + Decl *TagDecl, + SourceLocation LBrac, + SourceLocation RBrac, + AttributeList *AttrList); + void ActOnFinishCXXMemberDecls(); + + void ActOnReenterTemplateScope(Scope *S, Decl *Template); + void ActOnReenterDeclaratorTemplateScope(Scope *S, DeclaratorDecl *D); + void ActOnStartDelayedMemberDeclarations(Scope *S, Decl *Record); + void ActOnStartDelayedCXXMethodDeclaration(Scope *S, Decl *Method); + void ActOnDelayedCXXMethodParameter(Scope *S, Decl *Param); + void ActOnFinishDelayedMemberDeclarations(Scope *S, Decl *Record); + void ActOnFinishDelayedCXXMethodDeclaration(Scope *S, Decl *Method); + void ActOnFinishDelayedMemberInitializers(Decl *Record); + void MarkAsLateParsedTemplate(FunctionDecl *FD, bool Flag = true); + bool IsInsideALocalClassWithinATemplateFunction(); + + Decl *ActOnStaticAssertDeclaration(SourceLocation StaticAssertLoc, + Expr *AssertExpr, + Expr *AssertMessageExpr, + SourceLocation RParenLoc); + + FriendDecl *CheckFriendTypeDecl(SourceLocation Loc, + SourceLocation FriendLoc, + TypeSourceInfo *TSInfo); + Decl *ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, + MultiTemplateParamsArg TemplateParams); + Decl *ActOnFriendFunctionDecl(Scope *S, Declarator &D, + MultiTemplateParamsArg TemplateParams); + + QualType CheckConstructorDeclarator(Declarator &D, QualType R, + StorageClass& SC); + void CheckConstructor(CXXConstructorDecl *Constructor); + QualType CheckDestructorDeclarator(Declarator &D, QualType R, + StorageClass& SC); + bool CheckDestructor(CXXDestructorDecl *Destructor); + void CheckConversionDeclarator(Declarator &D, QualType &R, + StorageClass& SC); + Decl *ActOnConversionDeclarator(CXXConversionDecl *Conversion); + + void CheckExplicitlyDefaultedMethods(CXXRecordDecl *Record); + void CheckExplicitlyDefaultedDefaultConstructor(CXXConstructorDecl *Ctor); + void CheckExplicitlyDefaultedCopyConstructor(CXXConstructorDecl *Ctor); + void CheckExplicitlyDefaultedCopyAssignment(CXXMethodDecl *Method); + void CheckExplicitlyDefaultedMoveConstructor(CXXConstructorDecl *Ctor); + void CheckExplicitlyDefaultedMoveAssignment(CXXMethodDecl *Method); + void CheckExplicitlyDefaultedDestructor(CXXDestructorDecl *Dtor); + + //===--------------------------------------------------------------------===// + // C++ Derived Classes + // + + /// ActOnBaseSpecifier - Parsed a base specifier + CXXBaseSpecifier *CheckBaseSpecifier(CXXRecordDecl *Class, + SourceRange SpecifierRange, + bool Virtual, AccessSpecifier Access, + TypeSourceInfo *TInfo, + SourceLocation EllipsisLoc); + + BaseResult ActOnBaseSpecifier(Decl *classdecl, + SourceRange SpecifierRange, + bool Virtual, AccessSpecifier Access, + ParsedType basetype, + SourceLocation BaseLoc, + SourceLocation EllipsisLoc); + + bool AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases, + unsigned NumBases); + void ActOnBaseSpecifiers(Decl *ClassDecl, CXXBaseSpecifier **Bases, + unsigned NumBases); + + bool IsDerivedFrom(QualType Derived, QualType Base); + bool IsDerivedFrom(QualType Derived, QualType Base, CXXBasePaths &Paths); + + // FIXME: I don't like this name. + void BuildBasePathArray(const CXXBasePaths &Paths, CXXCastPath &BasePath); + + bool BasePathInvolvesVirtualBase(const CXXCastPath &BasePath); + + bool CheckDerivedToBaseConversion(QualType Derived, QualType Base, + SourceLocation Loc, SourceRange Range, + CXXCastPath *BasePath = 0, + bool IgnoreAccess = false); + bool CheckDerivedToBaseConversion(QualType Derived, QualType Base, + unsigned InaccessibleBaseID, + unsigned AmbigiousBaseConvID, + SourceLocation Loc, SourceRange Range, + DeclarationName Name, + CXXCastPath *BasePath); + + std::string getAmbiguousPathsDisplayString(CXXBasePaths &Paths); + + /// CheckOverridingFunctionReturnType - Checks whether the return types are + /// covariant, according to C++ [class.virtual]p5. + bool CheckOverridingFunctionReturnType(const CXXMethodDecl *New, + const CXXMethodDecl *Old); + + /// CheckOverridingFunctionExceptionSpec - Checks whether the exception + /// spec is a subset of base spec. + bool CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New, + const CXXMethodDecl *Old); + + bool CheckPureMethod(CXXMethodDecl *Method, SourceRange InitRange); + + /// CheckOverrideControl - Check C++0x override control semantics. + void CheckOverrideControl(const Decl *D); + + /// CheckForFunctionMarkedFinal - Checks whether a virtual member function + /// overrides a virtual member function marked 'final', according to + /// C++0x [class.virtual]p3. + bool CheckIfOverriddenFunctionIsMarkedFinal(const CXXMethodDecl *New, + const CXXMethodDecl *Old); + + + //===--------------------------------------------------------------------===// + // C++ Access Control + // + + enum AccessResult { + AR_accessible, + AR_inaccessible, + AR_dependent, + AR_delayed + }; + + bool SetMemberAccessSpecifier(NamedDecl *MemberDecl, + NamedDecl *PrevMemberDecl, + AccessSpecifier LexicalAS); + + AccessResult CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E, + DeclAccessPair FoundDecl); + AccessResult CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E, + DeclAccessPair FoundDecl); + AccessResult CheckAllocationAccess(SourceLocation OperatorLoc, + SourceRange PlacementRange, + CXXRecordDecl *NamingClass, + DeclAccessPair FoundDecl, + bool Diagnose = true); + AccessResult CheckConstructorAccess(SourceLocation Loc, + CXXConstructorDecl *D, + const InitializedEntity &Entity, + AccessSpecifier Access, + bool IsCopyBindingRefToTemp = false); + AccessResult CheckConstructorAccess(SourceLocation Loc, + CXXConstructorDecl *D, + const InitializedEntity &Entity, + AccessSpecifier Access, + const PartialDiagnostic &PDiag); + AccessResult CheckDestructorAccess(SourceLocation Loc, + CXXDestructorDecl *Dtor, + const PartialDiagnostic &PDiag, + QualType objectType = QualType()); + AccessResult CheckDirectMemberAccess(SourceLocation Loc, + NamedDecl *D, + const PartialDiagnostic &PDiag); + AccessResult CheckMemberOperatorAccess(SourceLocation Loc, + Expr *ObjectExpr, + Expr *ArgExpr, + DeclAccessPair FoundDecl); + AccessResult CheckAddressOfMemberAccess(Expr *OvlExpr, + DeclAccessPair FoundDecl); + AccessResult CheckBaseClassAccess(SourceLocation AccessLoc, + QualType Base, QualType Derived, + const CXXBasePath &Path, + unsigned DiagID, + bool ForceCheck = false, + bool ForceUnprivileged = false); + void CheckLookupAccess(const LookupResult &R); + bool IsSimplyAccessible(NamedDecl *decl, DeclContext *Ctx); + bool isSpecialMemberAccessibleForDeletion(CXXMethodDecl *decl, + AccessSpecifier access, + QualType objectType); + + void HandleDependentAccessCheck(const DependentDiagnostic &DD, + const MultiLevelTemplateArgumentList &TemplateArgs); + void PerformDependentDiagnostics(const DeclContext *Pattern, + const MultiLevelTemplateArgumentList &TemplateArgs); + + void HandleDelayedAccessCheck(sema::DelayedDiagnostic &DD, Decl *Ctx); + + /// A flag to suppress access checking. + bool SuppressAccessChecking; + + /// \brief When true, access checking violations are treated as SFINAE + /// failures rather than hard errors. + bool AccessCheckingSFINAE; + + /// \brief RAII object used to temporarily suppress access checking. + class SuppressAccessChecksRAII { + Sema &S; + bool SuppressingAccess; + + public: + SuppressAccessChecksRAII(Sema &S, bool Suppress) + : S(S), SuppressingAccess(Suppress) { + if (Suppress) S.ActOnStartSuppressingAccessChecks(); + } + ~SuppressAccessChecksRAII() { + done(); + } + void done() { + if (!SuppressingAccess) return; + S.ActOnStopSuppressingAccessChecks(); + SuppressingAccess = false; + } + }; + + void ActOnStartSuppressingAccessChecks(); + void ActOnStopSuppressingAccessChecks(); + + enum AbstractDiagSelID { + AbstractNone = -1, + AbstractReturnType, + AbstractParamType, + AbstractVariableType, + AbstractFieldType, + AbstractArrayType + }; + + bool RequireNonAbstractType(SourceLocation Loc, QualType T, + const PartialDiagnostic &PD); + void DiagnoseAbstractType(const CXXRecordDecl *RD); + + bool RequireNonAbstractType(SourceLocation Loc, QualType T, unsigned DiagID, + AbstractDiagSelID SelID = AbstractNone); + + //===--------------------------------------------------------------------===// + // C++ Overloaded Operators [C++ 13.5] + // + + bool CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl); + + bool CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl); + + //===--------------------------------------------------------------------===// + // C++ Templates [C++ 14] + // + void FilterAcceptableTemplateNames(LookupResult &R, + bool AllowFunctionTemplates = true); + bool hasAnyAcceptableTemplateNames(LookupResult &R, + bool AllowFunctionTemplates = true); + + void LookupTemplateName(LookupResult &R, Scope *S, CXXScopeSpec &SS, + QualType ObjectType, bool EnteringContext, + bool &MemberOfUnknownSpecialization); + + TemplateNameKind isTemplateName(Scope *S, + CXXScopeSpec &SS, + bool hasTemplateKeyword, + UnqualifiedId &Name, + ParsedType ObjectType, + bool EnteringContext, + TemplateTy &Template, + bool &MemberOfUnknownSpecialization); + + bool DiagnoseUnknownTemplateName(const IdentifierInfo &II, + SourceLocation IILoc, + Scope *S, + const CXXScopeSpec *SS, + TemplateTy &SuggestedTemplate, + TemplateNameKind &SuggestedKind); + + void DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl); + TemplateDecl *AdjustDeclIfTemplate(Decl *&Decl); + + Decl *ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis, + SourceLocation EllipsisLoc, + SourceLocation KeyLoc, + IdentifierInfo *ParamName, + SourceLocation ParamNameLoc, + unsigned Depth, unsigned Position, + SourceLocation EqualLoc, + ParsedType DefaultArg); + + QualType CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc); + Decl *ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, + unsigned Depth, + unsigned Position, + SourceLocation EqualLoc, + Expr *DefaultArg); + Decl *ActOnTemplateTemplateParameter(Scope *S, + SourceLocation TmpLoc, + TemplateParameterList *Params, + SourceLocation EllipsisLoc, + IdentifierInfo *ParamName, + SourceLocation ParamNameLoc, + unsigned Depth, + unsigned Position, + SourceLocation EqualLoc, + ParsedTemplateArgument DefaultArg); + + TemplateParameterList * + ActOnTemplateParameterList(unsigned Depth, + SourceLocation ExportLoc, + SourceLocation TemplateLoc, + SourceLocation LAngleLoc, + Decl **Params, unsigned NumParams, + SourceLocation RAngleLoc); + + /// \brief The context in which we are checking a template parameter + /// list. + enum TemplateParamListContext { + TPC_ClassTemplate, + TPC_FunctionTemplate, + TPC_ClassTemplateMember, + TPC_FriendFunctionTemplate, + TPC_FriendFunctionTemplateDefinition, + TPC_TypeAliasTemplate + }; + + bool CheckTemplateParameterList(TemplateParameterList *NewParams, + TemplateParameterList *OldParams, + TemplateParamListContext TPC); + TemplateParameterList * + MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, + SourceLocation DeclLoc, + const CXXScopeSpec &SS, + TemplateParameterList **ParamLists, + unsigned NumParamLists, + bool IsFriend, + bool &IsExplicitSpecialization, + bool &Invalid); + + DeclResult CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, + SourceLocation KWLoc, CXXScopeSpec &SS, + IdentifierInfo *Name, SourceLocation NameLoc, + AttributeList *Attr, + TemplateParameterList *TemplateParams, + AccessSpecifier AS, + SourceLocation ModulePrivateLoc, + unsigned NumOuterTemplateParamLists, + TemplateParameterList **OuterTemplateParamLists); + + void translateTemplateArguments(const ASTTemplateArgsPtr &In, + TemplateArgumentListInfo &Out); + + void NoteAllFoundTemplates(TemplateName Name); + + QualType CheckTemplateIdType(TemplateName Template, + SourceLocation TemplateLoc, + TemplateArgumentListInfo &TemplateArgs); + + TypeResult + ActOnTemplateIdType(CXXScopeSpec &SS, SourceLocation TemplateKWLoc, + TemplateTy Template, SourceLocation TemplateLoc, + SourceLocation LAngleLoc, + ASTTemplateArgsPtr TemplateArgs, + SourceLocation RAngleLoc, + bool IsCtorOrDtorName = false); + + /// \brief Parsed an elaborated-type-specifier that refers to a template-id, + /// such as \c class T::template apply<U>. + /// + /// \param TUK + TypeResult ActOnTagTemplateIdType(TagUseKind TUK, + TypeSpecifierType TagSpec, + SourceLocation TagLoc, + CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, + TemplateTy TemplateD, + SourceLocation TemplateLoc, + SourceLocation LAngleLoc, + ASTTemplateArgsPtr TemplateArgsIn, + SourceLocation RAngleLoc); + + + ExprResult BuildTemplateIdExpr(const CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, + LookupResult &R, + bool RequiresADL, + const TemplateArgumentListInfo *TemplateArgs); + + ExprResult BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, + const DeclarationNameInfo &NameInfo, + const TemplateArgumentListInfo *TemplateArgs); + + TemplateNameKind ActOnDependentTemplateName(Scope *S, + CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, + UnqualifiedId &Name, + ParsedType ObjectType, + bool EnteringContext, + TemplateTy &Template); + + DeclResult + ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagUseKind TUK, + SourceLocation KWLoc, + SourceLocation ModulePrivateLoc, + CXXScopeSpec &SS, + TemplateTy Template, + SourceLocation TemplateNameLoc, + SourceLocation LAngleLoc, + ASTTemplateArgsPtr TemplateArgs, + SourceLocation RAngleLoc, + AttributeList *Attr, + MultiTemplateParamsArg TemplateParameterLists); + + Decl *ActOnTemplateDeclarator(Scope *S, + MultiTemplateParamsArg TemplateParameterLists, + Declarator &D); + + Decl *ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope, + MultiTemplateParamsArg TemplateParameterLists, + Declarator &D); + + bool + CheckSpecializationInstantiationRedecl(SourceLocation NewLoc, + TemplateSpecializationKind NewTSK, + NamedDecl *PrevDecl, + TemplateSpecializationKind PrevTSK, + SourceLocation PrevPtOfInstantiation, + bool &SuppressNew); + + bool CheckDependentFunctionTemplateSpecialization(FunctionDecl *FD, + const TemplateArgumentListInfo &ExplicitTemplateArgs, + LookupResult &Previous); + + bool CheckFunctionTemplateSpecialization(FunctionDecl *FD, + TemplateArgumentListInfo *ExplicitTemplateArgs, + LookupResult &Previous); + bool CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous); + + DeclResult + ActOnExplicitInstantiation(Scope *S, + SourceLocation ExternLoc, + SourceLocation TemplateLoc, + unsigned TagSpec, + SourceLocation KWLoc, + const CXXScopeSpec &SS, + TemplateTy Template, + SourceLocation TemplateNameLoc, + SourceLocation LAngleLoc, + ASTTemplateArgsPtr TemplateArgs, + SourceLocation RAngleLoc, + AttributeList *Attr); + + DeclResult + ActOnExplicitInstantiation(Scope *S, + SourceLocation ExternLoc, + SourceLocation TemplateLoc, + unsigned TagSpec, + SourceLocation KWLoc, + CXXScopeSpec &SS, + IdentifierInfo *Name, + SourceLocation NameLoc, + AttributeList *Attr); + + DeclResult ActOnExplicitInstantiation(Scope *S, + SourceLocation ExternLoc, + SourceLocation TemplateLoc, + Declarator &D); + + TemplateArgumentLoc + SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template, + SourceLocation TemplateLoc, + SourceLocation RAngleLoc, + Decl *Param, + SmallVectorImpl<TemplateArgument> &Converted); + + /// \brief Specifies the context in which a particular template + /// argument is being checked. + enum CheckTemplateArgumentKind { + /// \brief The template argument was specified in the code or was + /// instantiated with some deduced template arguments. + CTAK_Specified, + + /// \brief The template argument was deduced via template argument + /// deduction. + CTAK_Deduced, + + /// \brief The template argument was deduced from an array bound + /// via template argument deduction. + CTAK_DeducedFromArrayBound + }; + + bool CheckTemplateArgument(NamedDecl *Param, + const TemplateArgumentLoc &Arg, + NamedDecl *Template, + SourceLocation TemplateLoc, + SourceLocation RAngleLoc, + unsigned ArgumentPackIndex, + SmallVectorImpl<TemplateArgument> &Converted, + CheckTemplateArgumentKind CTAK = CTAK_Specified); + + /// \brief Check that the given template arguments can be be provided to + /// the given template, converting the arguments along the way. + /// + /// \param Template The template to which the template arguments are being + /// provided. + /// + /// \param TemplateLoc The location of the template name in the source. + /// + /// \param TemplateArgs The list of template arguments. If the template is + /// a template template parameter, this function may extend the set of + /// template arguments to also include substituted, defaulted template + /// arguments. + /// + /// \param PartialTemplateArgs True if the list of template arguments is + /// intentionally partial, e.g., because we're checking just the initial + /// set of template arguments. + /// + /// \param Converted Will receive the converted, canonicalized template + /// arguments. + /// + /// + /// \param ExpansionIntoFixedList If non-NULL, will be set true to indicate + /// when the template arguments contain a pack expansion that is being + /// expanded into a fixed parameter list. + /// + /// \returns True if an error occurred, false otherwise. + bool CheckTemplateArgumentList(TemplateDecl *Template, + SourceLocation TemplateLoc, + TemplateArgumentListInfo &TemplateArgs, + bool PartialTemplateArgs, + SmallVectorImpl<TemplateArgument> &Converted, + bool *ExpansionIntoFixedList = 0); + + bool CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, + const TemplateArgumentLoc &Arg, + SmallVectorImpl<TemplateArgument> &Converted); + + bool CheckTemplateArgument(TemplateTypeParmDecl *Param, + TypeSourceInfo *Arg); + ExprResult CheckTemplateArgument(NonTypeTemplateParmDecl *Param, + QualType InstantiatedParamType, Expr *Arg, + TemplateArgument &Converted, + CheckTemplateArgumentKind CTAK = CTAK_Specified); + bool CheckTemplateArgument(TemplateTemplateParmDecl *Param, + const TemplateArgumentLoc &Arg); + + ExprResult + BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg, + QualType ParamType, + SourceLocation Loc); + ExprResult + BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg, + SourceLocation Loc); + + /// \brief Enumeration describing how template parameter lists are compared + /// for equality. + enum TemplateParameterListEqualKind { + /// \brief We are matching the template parameter lists of two templates + /// that might be redeclarations. + /// + /// \code + /// template<typename T> struct X; + /// template<typename T> struct X; + /// \endcode + TPL_TemplateMatch, + + /// \brief We are matching the template parameter lists of two template + /// template parameters as part of matching the template parameter lists + /// of two templates that might be redeclarations. + /// + /// \code + /// template<template<int I> class TT> struct X; + /// template<template<int Value> class Other> struct X; + /// \endcode + TPL_TemplateTemplateParmMatch, + + /// \brief We are matching the template parameter lists of a template + /// template argument against the template parameter lists of a template + /// template parameter. + /// + /// \code + /// template<template<int Value> class Metafun> struct X; + /// template<int Value> struct integer_c; + /// X<integer_c> xic; + /// \endcode + TPL_TemplateTemplateArgumentMatch + }; + + bool TemplateParameterListsAreEqual(TemplateParameterList *New, + TemplateParameterList *Old, + bool Complain, + TemplateParameterListEqualKind Kind, + SourceLocation TemplateArgLoc + = SourceLocation()); + + bool CheckTemplateDeclScope(Scope *S, TemplateParameterList *TemplateParams); + + /// \brief Called when the parser has parsed a C++ typename + /// specifier, e.g., "typename T::type". + /// + /// \param S The scope in which this typename type occurs. + /// \param TypenameLoc the location of the 'typename' keyword + /// \param SS the nested-name-specifier following the typename (e.g., 'T::'). + /// \param II the identifier we're retrieving (e.g., 'type' in the example). + /// \param IdLoc the location of the identifier. + TypeResult + ActOnTypenameType(Scope *S, SourceLocation TypenameLoc, + const CXXScopeSpec &SS, const IdentifierInfo &II, + SourceLocation IdLoc); + + /// \brief Called when the parser has parsed a C++ typename + /// specifier that ends in a template-id, e.g., + /// "typename MetaFun::template apply<T1, T2>". + /// + /// \param S The scope in which this typename type occurs. + /// \param TypenameLoc the location of the 'typename' keyword + /// \param SS the nested-name-specifier following the typename (e.g., 'T::'). + /// \param TemplateLoc the location of the 'template' keyword, if any. + /// \param TemplateName The template name. + /// \param TemplateNameLoc The location of the template name. + /// \param LAngleLoc The location of the opening angle bracket ('<'). + /// \param TemplateArgs The template arguments. + /// \param RAngleLoc The location of the closing angle bracket ('>'). + TypeResult + ActOnTypenameType(Scope *S, SourceLocation TypenameLoc, + const CXXScopeSpec &SS, + SourceLocation TemplateLoc, + TemplateTy Template, + SourceLocation TemplateNameLoc, + SourceLocation LAngleLoc, + ASTTemplateArgsPtr TemplateArgs, + SourceLocation RAngleLoc); + + QualType CheckTypenameType(ElaboratedTypeKeyword Keyword, + SourceLocation KeywordLoc, + NestedNameSpecifierLoc QualifierLoc, + const IdentifierInfo &II, + SourceLocation IILoc); + + TypeSourceInfo *RebuildTypeInCurrentInstantiation(TypeSourceInfo *T, + SourceLocation Loc, + DeclarationName Name); + bool RebuildNestedNameSpecifierInCurrentInstantiation(CXXScopeSpec &SS); + + ExprResult RebuildExprInCurrentInstantiation(Expr *E); + bool RebuildTemplateParamsInCurrentInstantiation( + TemplateParameterList *Params); + + std::string + getTemplateArgumentBindingsText(const TemplateParameterList *Params, + const TemplateArgumentList &Args); + + std::string + getTemplateArgumentBindingsText(const TemplateParameterList *Params, + const TemplateArgument *Args, + unsigned NumArgs); + + //===--------------------------------------------------------------------===// + // C++ Variadic Templates (C++0x [temp.variadic]) + //===--------------------------------------------------------------------===// + + /// \brief The context in which an unexpanded parameter pack is + /// being diagnosed. + /// + /// Note that the values of this enumeration line up with the first + /// argument to the \c err_unexpanded_parameter_pack diagnostic. + enum UnexpandedParameterPackContext { + /// \brief An arbitrary expression. + UPPC_Expression = 0, + + /// \brief The base type of a class type. + UPPC_BaseType, + + /// \brief The type of an arbitrary declaration. + UPPC_DeclarationType, + + /// \brief The type of a data member. + UPPC_DataMemberType, + + /// \brief The size of a bit-field. + UPPC_BitFieldWidth, + + /// \brief The expression in a static assertion. + UPPC_StaticAssertExpression, + + /// \brief The fixed underlying type of an enumeration. + UPPC_FixedUnderlyingType, + + /// \brief The enumerator value. + UPPC_EnumeratorValue, + + /// \brief A using declaration. + UPPC_UsingDeclaration, + + /// \brief A friend declaration. + UPPC_FriendDeclaration, + + /// \brief A declaration qualifier. + UPPC_DeclarationQualifier, + + /// \brief An initializer. + UPPC_Initializer, + + /// \brief A default argument. + UPPC_DefaultArgument, + + /// \brief The type of a non-type template parameter. + UPPC_NonTypeTemplateParameterType, + + /// \brief The type of an exception. + UPPC_ExceptionType, + + /// \brief Partial specialization. + UPPC_PartialSpecialization, + + /// \brief Microsoft __if_exists. + UPPC_IfExists, + + /// \brief Microsoft __if_not_exists. + UPPC_IfNotExists +}; + + /// \brief Diagnose unexpanded parameter packs. + /// + /// \param Loc The location at which we should emit the diagnostic. + /// + /// \param UPPC The context in which we are diagnosing unexpanded + /// parameter packs. + /// + /// \param Unexpanded the set of unexpanded parameter packs. + void DiagnoseUnexpandedParameterPacks(SourceLocation Loc, + UnexpandedParameterPackContext UPPC, + ArrayRef<UnexpandedParameterPack> Unexpanded); + + /// \brief If the given type contains an unexpanded parameter pack, + /// diagnose the error. + /// + /// \param Loc The source location where a diagnostc should be emitted. + /// + /// \param T The type that is being checked for unexpanded parameter + /// packs. + /// + /// \returns true if an error occurred, false otherwise. + bool DiagnoseUnexpandedParameterPack(SourceLocation Loc, TypeSourceInfo *T, + UnexpandedParameterPackContext UPPC); + + /// \brief If the given expression contains an unexpanded parameter + /// pack, diagnose the error. + /// + /// \param E The expression that is being checked for unexpanded + /// parameter packs. + /// + /// \returns true if an error occurred, false otherwise. + bool DiagnoseUnexpandedParameterPack(Expr *E, + UnexpandedParameterPackContext UPPC = UPPC_Expression); + + /// \brief If the given nested-name-specifier contains an unexpanded + /// parameter pack, diagnose the error. + /// + /// \param SS The nested-name-specifier that is being checked for + /// unexpanded parameter packs. + /// + /// \returns true if an error occurred, false otherwise. + bool DiagnoseUnexpandedParameterPack(const CXXScopeSpec &SS, + UnexpandedParameterPackContext UPPC); + + /// \brief If the given name contains an unexpanded parameter pack, + /// diagnose the error. + /// + /// \param NameInfo The name (with source location information) that + /// is being checked for unexpanded parameter packs. + /// + /// \returns true if an error occurred, false otherwise. + bool DiagnoseUnexpandedParameterPack(const DeclarationNameInfo &NameInfo, + UnexpandedParameterPackContext UPPC); + + /// \brief If the given template name contains an unexpanded parameter pack, + /// diagnose the error. + /// + /// \param Loc The location of the template name. + /// + /// \param Template The template name that is being checked for unexpanded + /// parameter packs. + /// + /// \returns true if an error occurred, false otherwise. + bool DiagnoseUnexpandedParameterPack(SourceLocation Loc, + TemplateName Template, + UnexpandedParameterPackContext UPPC); + + /// \brief If the given template argument contains an unexpanded parameter + /// pack, diagnose the error. + /// + /// \param Arg The template argument that is being checked for unexpanded + /// parameter packs. + /// + /// \returns true if an error occurred, false otherwise. + bool DiagnoseUnexpandedParameterPack(TemplateArgumentLoc Arg, + UnexpandedParameterPackContext UPPC); + + /// \brief Collect the set of unexpanded parameter packs within the given + /// template argument. + /// + /// \param Arg The template argument that will be traversed to find + /// unexpanded parameter packs. + void collectUnexpandedParameterPacks(TemplateArgument Arg, + SmallVectorImpl<UnexpandedParameterPack> &Unexpanded); + + /// \brief Collect the set of unexpanded parameter packs within the given + /// template argument. + /// + /// \param Arg The template argument that will be traversed to find + /// unexpanded parameter packs. + void collectUnexpandedParameterPacks(TemplateArgumentLoc Arg, + SmallVectorImpl<UnexpandedParameterPack> &Unexpanded); + + /// \brief Collect the set of unexpanded parameter packs within the given + /// type. + /// + /// \param T The type that will be traversed to find + /// unexpanded parameter packs. + void collectUnexpandedParameterPacks(QualType T, + SmallVectorImpl<UnexpandedParameterPack> &Unexpanded); + + /// \brief Collect the set of unexpanded parameter packs within the given + /// type. + /// + /// \param TL The type that will be traversed to find + /// unexpanded parameter packs. + void collectUnexpandedParameterPacks(TypeLoc TL, + SmallVectorImpl<UnexpandedParameterPack> &Unexpanded); + + /// \brief Collect the set of unexpanded parameter packs within the given + /// nested-name-specifier. + /// + /// \param SS The nested-name-specifier that will be traversed to find + /// unexpanded parameter packs. + void collectUnexpandedParameterPacks(CXXScopeSpec &SS, + SmallVectorImpl<UnexpandedParameterPack> &Unexpanded); + + /// \brief Collect the set of unexpanded parameter packs within the given + /// name. + /// + /// \param NameInfo The name that will be traversed to find + /// unexpanded parameter packs. + void collectUnexpandedParameterPacks(const DeclarationNameInfo &NameInfo, + SmallVectorImpl<UnexpandedParameterPack> &Unexpanded); + + /// \brief Invoked when parsing a template argument followed by an + /// ellipsis, which creates a pack expansion. + /// + /// \param Arg The template argument preceding the ellipsis, which + /// may already be invalid. + /// + /// \param EllipsisLoc The location of the ellipsis. + ParsedTemplateArgument ActOnPackExpansion(const ParsedTemplateArgument &Arg, + SourceLocation EllipsisLoc); + + /// \brief Invoked when parsing a type followed by an ellipsis, which + /// creates a pack expansion. + /// + /// \param Type The type preceding the ellipsis, which will become + /// the pattern of the pack expansion. + /// + /// \param EllipsisLoc The location of the ellipsis. + TypeResult ActOnPackExpansion(ParsedType Type, SourceLocation EllipsisLoc); + + /// \brief Construct a pack expansion type from the pattern of the pack + /// expansion. + TypeSourceInfo *CheckPackExpansion(TypeSourceInfo *Pattern, + SourceLocation EllipsisLoc, + llvm::Optional<unsigned> NumExpansions); + + /// \brief Construct a pack expansion type from the pattern of the pack + /// expansion. + QualType CheckPackExpansion(QualType Pattern, + SourceRange PatternRange, + SourceLocation EllipsisLoc, + llvm::Optional<unsigned> NumExpansions); + + /// \brief Invoked when parsing an expression followed by an ellipsis, which + /// creates a pack expansion. + /// + /// \param Pattern The expression preceding the ellipsis, which will become + /// the pattern of the pack expansion. + /// + /// \param EllipsisLoc The location of the ellipsis. + ExprResult ActOnPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc); + + /// \brief Invoked when parsing an expression followed by an ellipsis, which + /// creates a pack expansion. + /// + /// \param Pattern The expression preceding the ellipsis, which will become + /// the pattern of the pack expansion. + /// + /// \param EllipsisLoc The location of the ellipsis. + ExprResult CheckPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc, + llvm::Optional<unsigned> NumExpansions); + + /// \brief Determine whether we could expand a pack expansion with the + /// given set of parameter packs into separate arguments by repeatedly + /// transforming the pattern. + /// + /// \param EllipsisLoc The location of the ellipsis that identifies the + /// pack expansion. + /// + /// \param PatternRange The source range that covers the entire pattern of + /// the pack expansion. + /// + /// \param Unexpanded The set of unexpanded parameter packs within the + /// pattern. + /// + /// \param NumUnexpanded The number of unexpanded parameter packs in + /// \p Unexpanded. + /// + /// \param ShouldExpand Will be set to \c true if the transformer should + /// expand the corresponding pack expansions into separate arguments. When + /// set, \c NumExpansions must also be set. + /// + /// \param RetainExpansion Whether the caller should add an unexpanded + /// pack expansion after all of the expanded arguments. This is used + /// when extending explicitly-specified template argument packs per + /// C++0x [temp.arg.explicit]p9. + /// + /// \param NumExpansions The number of separate arguments that will be in + /// the expanded form of the corresponding pack expansion. This is both an + /// input and an output parameter, which can be set by the caller if the + /// number of expansions is known a priori (e.g., due to a prior substitution) + /// and will be set by the callee when the number of expansions is known. + /// The callee must set this value when \c ShouldExpand is \c true; it may + /// set this value in other cases. + /// + /// \returns true if an error occurred (e.g., because the parameter packs + /// are to be instantiated with arguments of different lengths), false + /// otherwise. If false, \c ShouldExpand (and possibly \c NumExpansions) + /// must be set. + bool CheckParameterPacksForExpansion(SourceLocation EllipsisLoc, + SourceRange PatternRange, + llvm::ArrayRef<UnexpandedParameterPack> Unexpanded, + const MultiLevelTemplateArgumentList &TemplateArgs, + bool &ShouldExpand, + bool &RetainExpansion, + llvm::Optional<unsigned> &NumExpansions); + + /// \brief Determine the number of arguments in the given pack expansion + /// type. + /// + /// This routine already assumes that the pack expansion type can be + /// expanded and that the number of arguments in the expansion is + /// consistent across all of the unexpanded parameter packs in its pattern. + unsigned getNumArgumentsInExpansion(QualType T, + const MultiLevelTemplateArgumentList &TemplateArgs); + + /// \brief Determine whether the given declarator contains any unexpanded + /// parameter packs. + /// + /// This routine is used by the parser to disambiguate function declarators + /// with an ellipsis prior to the ')', e.g., + /// + /// \code + /// void f(T...); + /// \endcode + /// + /// To determine whether we have an (unnamed) function parameter pack or + /// a variadic function. + /// + /// \returns true if the declarator contains any unexpanded parameter packs, + /// false otherwise. + bool containsUnexpandedParameterPacks(Declarator &D); + + //===--------------------------------------------------------------------===// + // C++ Template Argument Deduction (C++ [temp.deduct]) + //===--------------------------------------------------------------------===// + + /// \brief Describes the result of template argument deduction. + /// + /// The TemplateDeductionResult enumeration describes the result of + /// template argument deduction, as returned from + /// DeduceTemplateArguments(). The separate TemplateDeductionInfo + /// structure provides additional information about the results of + /// template argument deduction, e.g., the deduced template argument + /// list (if successful) or the specific template parameters or + /// deduced arguments that were involved in the failure. + enum TemplateDeductionResult { + /// \brief Template argument deduction was successful. + TDK_Success = 0, + /// \brief Template argument deduction exceeded the maximum template + /// instantiation depth (which has already been diagnosed). + TDK_InstantiationDepth, + /// \brief Template argument deduction did not deduce a value + /// for every template parameter. + TDK_Incomplete, + /// \brief Template argument deduction produced inconsistent + /// deduced values for the given template parameter. + TDK_Inconsistent, + /// \brief Template argument deduction failed due to inconsistent + /// cv-qualifiers on a template parameter type that would + /// otherwise be deduced, e.g., we tried to deduce T in "const T" + /// but were given a non-const "X". + TDK_Underqualified, + /// \brief Substitution of the deduced template argument values + /// resulted in an error. + TDK_SubstitutionFailure, + /// \brief Substitution of the deduced template argument values + /// into a non-deduced context produced a type or value that + /// produces a type that does not match the original template + /// arguments provided. + TDK_NonDeducedMismatch, + /// \brief When performing template argument deduction for a function + /// template, there were too many call arguments. + TDK_TooManyArguments, + /// \brief When performing template argument deduction for a function + /// template, there were too few call arguments. + TDK_TooFewArguments, + /// \brief The explicitly-specified template arguments were not valid + /// template arguments for the given template. + TDK_InvalidExplicitArguments, + /// \brief The arguments included an overloaded function name that could + /// not be resolved to a suitable function. + TDK_FailedOverloadResolution + }; + + TemplateDeductionResult + DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, + const TemplateArgumentList &TemplateArgs, + sema::TemplateDeductionInfo &Info); + + TemplateDeductionResult + SubstituteExplicitTemplateArguments(FunctionTemplateDecl *FunctionTemplate, + TemplateArgumentListInfo &ExplicitTemplateArgs, + SmallVectorImpl<DeducedTemplateArgument> &Deduced, + SmallVectorImpl<QualType> &ParamTypes, + QualType *FunctionType, + sema::TemplateDeductionInfo &Info); + + /// brief A function argument from which we performed template argument + // deduction for a call. + struct OriginalCallArg { + OriginalCallArg(QualType OriginalParamType, + unsigned ArgIdx, + QualType OriginalArgType) + : OriginalParamType(OriginalParamType), ArgIdx(ArgIdx), + OriginalArgType(OriginalArgType) { } + + QualType OriginalParamType; + unsigned ArgIdx; + QualType OriginalArgType; + }; + + TemplateDeductionResult + FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, + SmallVectorImpl<DeducedTemplateArgument> &Deduced, + unsigned NumExplicitlySpecified, + FunctionDecl *&Specialization, + sema::TemplateDeductionInfo &Info, + SmallVectorImpl<OriginalCallArg> const *OriginalCallArgs = 0); + + TemplateDeductionResult + DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, + TemplateArgumentListInfo *ExplicitTemplateArgs, + llvm::ArrayRef<Expr *> Args, + FunctionDecl *&Specialization, + sema::TemplateDeductionInfo &Info); + + TemplateDeductionResult + DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, + TemplateArgumentListInfo *ExplicitTemplateArgs, + QualType ArgFunctionType, + FunctionDecl *&Specialization, + sema::TemplateDeductionInfo &Info); + + TemplateDeductionResult + DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, + QualType ToType, + CXXConversionDecl *&Specialization, + sema::TemplateDeductionInfo &Info); + + TemplateDeductionResult + DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, + TemplateArgumentListInfo *ExplicitTemplateArgs, + FunctionDecl *&Specialization, + sema::TemplateDeductionInfo &Info); + + /// \brief Result type of DeduceAutoType. + enum DeduceAutoResult { + DAR_Succeeded, + DAR_Failed, + DAR_FailedAlreadyDiagnosed + }; + + DeduceAutoResult DeduceAutoType(TypeSourceInfo *AutoType, Expr *&Initializer, + TypeSourceInfo *&Result); + void DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init); + + FunctionTemplateDecl *getMoreSpecializedTemplate(FunctionTemplateDecl *FT1, + FunctionTemplateDecl *FT2, + SourceLocation Loc, + TemplatePartialOrderingContext TPOC, + unsigned NumCallArguments); + UnresolvedSetIterator getMostSpecialized(UnresolvedSetIterator SBegin, + UnresolvedSetIterator SEnd, + TemplatePartialOrderingContext TPOC, + unsigned NumCallArguments, + SourceLocation Loc, + const PartialDiagnostic &NoneDiag, + const PartialDiagnostic &AmbigDiag, + const PartialDiagnostic &CandidateDiag, + bool Complain = true, + QualType TargetType = QualType()); + + ClassTemplatePartialSpecializationDecl * + getMoreSpecializedPartialSpecialization( + ClassTemplatePartialSpecializationDecl *PS1, + ClassTemplatePartialSpecializationDecl *PS2, + SourceLocation Loc); + + void MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs, + bool OnlyDeduced, + unsigned Depth, + llvm::SmallBitVector &Used); + void MarkDeducedTemplateParameters(FunctionTemplateDecl *FunctionTemplate, + llvm::SmallBitVector &Deduced) { + return MarkDeducedTemplateParameters(Context, FunctionTemplate, Deduced); + } + static void MarkDeducedTemplateParameters(ASTContext &Ctx, + FunctionTemplateDecl *FunctionTemplate, + llvm::SmallBitVector &Deduced); + + //===--------------------------------------------------------------------===// + // C++ Template Instantiation + // + + MultiLevelTemplateArgumentList getTemplateInstantiationArgs(NamedDecl *D, + const TemplateArgumentList *Innermost = 0, + bool RelativeToPrimary = false, + const FunctionDecl *Pattern = 0); + + /// \brief A template instantiation that is currently in progress. + struct ActiveTemplateInstantiation { + /// \brief The kind of template instantiation we are performing + enum InstantiationKind { + /// We are instantiating a template declaration. The entity is + /// the declaration we're instantiating (e.g., a CXXRecordDecl). + TemplateInstantiation, + + /// We are instantiating a default argument for a template + /// parameter. The Entity is the template, and + /// TemplateArgs/NumTemplateArguments provides the template + /// arguments as specified. + /// FIXME: Use a TemplateArgumentList + DefaultTemplateArgumentInstantiation, + + /// We are instantiating a default argument for a function. + /// The Entity is the ParmVarDecl, and TemplateArgs/NumTemplateArgs + /// provides the template arguments as specified. + DefaultFunctionArgumentInstantiation, + + /// We are substituting explicit template arguments provided for + /// a function template. The entity is a FunctionTemplateDecl. + ExplicitTemplateArgumentSubstitution, + + /// We are substituting template argument determined as part of + /// template argument deduction for either a class template + /// partial specialization or a function template. The + /// Entity is either a ClassTemplatePartialSpecializationDecl or + /// a FunctionTemplateDecl. + DeducedTemplateArgumentSubstitution, + + /// We are substituting prior template arguments into a new + /// template parameter. The template parameter itself is either a + /// NonTypeTemplateParmDecl or a TemplateTemplateParmDecl. + PriorTemplateArgumentSubstitution, + + /// We are checking the validity of a default template argument that + /// has been used when naming a template-id. + DefaultTemplateArgumentChecking, + + /// We are instantiating the exception specification for a function + /// template which was deferred until it was needed. + ExceptionSpecInstantiation + } Kind; + + /// \brief The point of instantiation within the source code. + SourceLocation PointOfInstantiation; + + /// \brief The template (or partial specialization) in which we are + /// performing the instantiation, for substitutions of prior template + /// arguments. + NamedDecl *Template; + + /// \brief The entity that is being instantiated. + uintptr_t Entity; + + /// \brief The list of template arguments we are substituting, if they + /// are not part of the entity. + const TemplateArgument *TemplateArgs; + + /// \brief The number of template arguments in TemplateArgs. + unsigned NumTemplateArgs; + + /// \brief The template deduction info object associated with the + /// substitution or checking of explicit or deduced template arguments. + sema::TemplateDeductionInfo *DeductionInfo; + + /// \brief The source range that covers the construct that cause + /// the instantiation, e.g., the template-id that causes a class + /// template instantiation. + SourceRange InstantiationRange; + + ActiveTemplateInstantiation() + : Kind(TemplateInstantiation), Template(0), Entity(0), TemplateArgs(0), + NumTemplateArgs(0), DeductionInfo(0) {} + + /// \brief Determines whether this template is an actual instantiation + /// that should be counted toward the maximum instantiation depth. + bool isInstantiationRecord() const; + + friend bool operator==(const ActiveTemplateInstantiation &X, + const ActiveTemplateInstantiation &Y) { + if (X.Kind != Y.Kind) + return false; + + if (X.Entity != Y.Entity) + return false; + + switch (X.Kind) { + case TemplateInstantiation: + case ExceptionSpecInstantiation: + return true; + + case PriorTemplateArgumentSubstitution: + case DefaultTemplateArgumentChecking: + if (X.Template != Y.Template) + return false; + + // Fall through + + case DefaultTemplateArgumentInstantiation: + case ExplicitTemplateArgumentSubstitution: + case DeducedTemplateArgumentSubstitution: + case DefaultFunctionArgumentInstantiation: + return X.TemplateArgs == Y.TemplateArgs; + + } + + llvm_unreachable("Invalid InstantiationKind!"); + } + + friend bool operator!=(const ActiveTemplateInstantiation &X, + const ActiveTemplateInstantiation &Y) { + return !(X == Y); + } + }; + + /// \brief List of active template instantiations. + /// + /// This vector is treated as a stack. As one template instantiation + /// requires another template instantiation, additional + /// instantiations are pushed onto the stack up to a + /// user-configurable limit LangOptions::InstantiationDepth. + SmallVector<ActiveTemplateInstantiation, 16> + ActiveTemplateInstantiations; + + /// \brief Whether we are in a SFINAE context that is not associated with + /// template instantiation. + /// + /// This is used when setting up a SFINAE trap (\c see SFINAETrap) outside + /// of a template instantiation or template argument deduction. + bool InNonInstantiationSFINAEContext; + + /// \brief The number of ActiveTemplateInstantiation entries in + /// \c ActiveTemplateInstantiations that are not actual instantiations and, + /// therefore, should not be counted as part of the instantiation depth. + unsigned NonInstantiationEntries; + + /// \brief The last template from which a template instantiation + /// error or warning was produced. + /// + /// This value is used to suppress printing of redundant template + /// instantiation backtraces when there are multiple errors in the + /// same instantiation. FIXME: Does this belong in Sema? It's tough + /// to implement it anywhere else. + ActiveTemplateInstantiation LastTemplateInstantiationErrorContext; + + /// \brief The current index into pack expansion arguments that will be + /// used for substitution of parameter packs. + /// + /// The pack expansion index will be -1 to indicate that parameter packs + /// should be instantiated as themselves. Otherwise, the index specifies + /// which argument within the parameter pack will be used for substitution. + int ArgumentPackSubstitutionIndex; + + /// \brief RAII object used to change the argument pack substitution index + /// within a \c Sema object. + /// + /// See \c ArgumentPackSubstitutionIndex for more information. + class ArgumentPackSubstitutionIndexRAII { + Sema &Self; + int OldSubstitutionIndex; + + public: + ArgumentPackSubstitutionIndexRAII(Sema &Self, int NewSubstitutionIndex) + : Self(Self), OldSubstitutionIndex(Self.ArgumentPackSubstitutionIndex) { + Self.ArgumentPackSubstitutionIndex = NewSubstitutionIndex; + } + + ~ArgumentPackSubstitutionIndexRAII() { + Self.ArgumentPackSubstitutionIndex = OldSubstitutionIndex; + } + }; + + friend class ArgumentPackSubstitutionRAII; + + /// \brief The stack of calls expression undergoing template instantiation. + /// + /// The top of this stack is used by a fixit instantiating unresolved + /// function calls to fix the AST to match the textual change it prints. + SmallVector<CallExpr *, 8> CallsUndergoingInstantiation; + + /// \brief For each declaration that involved template argument deduction, the + /// set of diagnostics that were suppressed during that template argument + /// deduction. + /// + /// FIXME: Serialize this structure to the AST file. + llvm::DenseMap<Decl *, SmallVector<PartialDiagnosticAt, 1> > + SuppressedDiagnostics; + + /// \brief A stack object to be created when performing template + /// instantiation. + /// + /// Construction of an object of type \c InstantiatingTemplate + /// pushes the current instantiation onto the stack of active + /// instantiations. If the size of this stack exceeds the maximum + /// number of recursive template instantiations, construction + /// produces an error and evaluates true. + /// + /// Destruction of this object will pop the named instantiation off + /// the stack. + struct InstantiatingTemplate { + /// \brief Note that we are instantiating a class template, + /// function template, or a member thereof. + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + Decl *Entity, + SourceRange InstantiationRange = SourceRange()); + + struct ExceptionSpecification {}; + /// \brief Note that we are instantiating an exception specification + /// of a function template. + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + FunctionDecl *Entity, ExceptionSpecification, + SourceRange InstantiationRange = SourceRange()); + + /// \brief Note that we are instantiating a default argument in a + /// template-id. + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + TemplateDecl *Template, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, + SourceRange InstantiationRange = SourceRange()); + + /// \brief Note that we are instantiating a default argument in a + /// template-id. + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + FunctionTemplateDecl *FunctionTemplate, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, + ActiveTemplateInstantiation::InstantiationKind Kind, + sema::TemplateDeductionInfo &DeductionInfo, + SourceRange InstantiationRange = SourceRange()); + + /// \brief Note that we are instantiating as part of template + /// argument deduction for a class template partial + /// specialization. + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + ClassTemplatePartialSpecializationDecl *PartialSpec, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, + sema::TemplateDeductionInfo &DeductionInfo, + SourceRange InstantiationRange = SourceRange()); + + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + ParmVarDecl *Param, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, + SourceRange InstantiationRange = SourceRange()); + + /// \brief Note that we are substituting prior template arguments into a + /// non-type or template template parameter. + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + NamedDecl *Template, + NonTypeTemplateParmDecl *Param, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, + SourceRange InstantiationRange); + + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + NamedDecl *Template, + TemplateTemplateParmDecl *Param, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, + SourceRange InstantiationRange); + + /// \brief Note that we are checking the default template argument + /// against the template parameter for a given template-id. + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + TemplateDecl *Template, + NamedDecl *Param, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, + SourceRange InstantiationRange); + + + /// \brief Note that we have finished instantiating this template. + void Clear(); + + ~InstantiatingTemplate() { Clear(); } + + /// \brief Determines whether we have exceeded the maximum + /// recursive template instantiations. + operator bool() const { return Invalid; } + + private: + Sema &SemaRef; + bool Invalid; + bool SavedInNonInstantiationSFINAEContext; + bool CheckInstantiationDepth(SourceLocation PointOfInstantiation, + SourceRange InstantiationRange); + + InstantiatingTemplate(const InstantiatingTemplate&); // not implemented + + InstantiatingTemplate& + operator=(const InstantiatingTemplate&); // not implemented + }; + + void PrintInstantiationStack(); + + /// \brief Determines whether we are currently in a context where + /// template argument substitution failures are not considered + /// errors. + /// + /// \returns An empty \c llvm::Optional if we're not in a SFINAE context. + /// Otherwise, contains a pointer that, if non-NULL, contains the nearest + /// template-deduction context object, which can be used to capture + /// diagnostics that will be suppressed. + llvm::Optional<sema::TemplateDeductionInfo *> isSFINAEContext() const; + + /// \brief RAII class used to determine whether SFINAE has + /// trapped any errors that occur during template argument + /// deduction.` + class SFINAETrap { + Sema &SemaRef; + unsigned PrevSFINAEErrors; + bool PrevInNonInstantiationSFINAEContext; + bool PrevAccessCheckingSFINAE; + + public: + explicit SFINAETrap(Sema &SemaRef, bool AccessCheckingSFINAE = false) + : SemaRef(SemaRef), PrevSFINAEErrors(SemaRef.NumSFINAEErrors), + PrevInNonInstantiationSFINAEContext( + SemaRef.InNonInstantiationSFINAEContext), + PrevAccessCheckingSFINAE(SemaRef.AccessCheckingSFINAE) + { + if (!SemaRef.isSFINAEContext()) + SemaRef.InNonInstantiationSFINAEContext = true; + SemaRef.AccessCheckingSFINAE = AccessCheckingSFINAE; + } + + ~SFINAETrap() { + SemaRef.NumSFINAEErrors = PrevSFINAEErrors; + SemaRef.InNonInstantiationSFINAEContext + = PrevInNonInstantiationSFINAEContext; + SemaRef.AccessCheckingSFINAE = PrevAccessCheckingSFINAE; + } + + /// \brief Determine whether any SFINAE errors have been trapped. + bool hasErrorOccurred() const { + return SemaRef.NumSFINAEErrors > PrevSFINAEErrors; + } + }; + + /// \brief The current instantiation scope used to store local + /// variables. + LocalInstantiationScope *CurrentInstantiationScope; + + /// \brief The number of typos corrected by CorrectTypo. + unsigned TyposCorrected; + + typedef llvm::DenseMap<IdentifierInfo *, TypoCorrection> + UnqualifiedTyposCorrectedMap; + + /// \brief A cache containing the results of typo correction for unqualified + /// name lookup. + /// + /// The string is the string that we corrected to (which may be empty, if + /// there was no correction), while the boolean will be true when the + /// string represents a keyword. + UnqualifiedTyposCorrectedMap UnqualifiedTyposCorrected; + + /// \brief Worker object for performing CFG-based warnings. + sema::AnalysisBasedWarnings AnalysisWarnings; + + /// \brief An entity for which implicit template instantiation is required. + /// + /// The source location associated with the declaration is the first place in + /// the source code where the declaration was "used". It is not necessarily + /// the point of instantiation (which will be either before or after the + /// namespace-scope declaration that triggered this implicit instantiation), + /// However, it is the location that diagnostics should generally refer to, + /// because users will need to know what code triggered the instantiation. + typedef std::pair<ValueDecl *, SourceLocation> PendingImplicitInstantiation; + + /// \brief The queue of implicit template instantiations that are required + /// but have not yet been performed. + std::deque<PendingImplicitInstantiation> PendingInstantiations; + + /// \brief The queue of implicit template instantiations that are required + /// and must be performed within the current local scope. + /// + /// This queue is only used for member functions of local classes in + /// templates, which must be instantiated in the same scope as their + /// enclosing function, so that they can reference function-local + /// types, static variables, enumerators, etc. + std::deque<PendingImplicitInstantiation> PendingLocalImplicitInstantiations; + + void PerformPendingInstantiations(bool LocalOnly = false); + + TypeSourceInfo *SubstType(TypeSourceInfo *T, + const MultiLevelTemplateArgumentList &TemplateArgs, + SourceLocation Loc, DeclarationName Entity); + + QualType SubstType(QualType T, + const MultiLevelTemplateArgumentList &TemplateArgs, + SourceLocation Loc, DeclarationName Entity); + + TypeSourceInfo *SubstType(TypeLoc TL, + const MultiLevelTemplateArgumentList &TemplateArgs, + SourceLocation Loc, DeclarationName Entity); + + TypeSourceInfo *SubstFunctionDeclType(TypeSourceInfo *T, + const MultiLevelTemplateArgumentList &TemplateArgs, + SourceLocation Loc, + DeclarationName Entity, + CXXRecordDecl *ThisContext, + unsigned ThisTypeQuals); + ParmVarDecl *SubstParmVarDecl(ParmVarDecl *D, + const MultiLevelTemplateArgumentList &TemplateArgs, + int indexAdjustment, + llvm::Optional<unsigned> NumExpansions, + bool ExpectParameterPack); + bool SubstParmTypes(SourceLocation Loc, + ParmVarDecl **Params, unsigned NumParams, + const MultiLevelTemplateArgumentList &TemplateArgs, + SmallVectorImpl<QualType> &ParamTypes, + SmallVectorImpl<ParmVarDecl *> *OutParams = 0); + ExprResult SubstExpr(Expr *E, + const MultiLevelTemplateArgumentList &TemplateArgs); + + /// \brief Substitute the given template arguments into a list of + /// expressions, expanding pack expansions if required. + /// + /// \param Exprs The list of expressions to substitute into. + /// + /// \param NumExprs The number of expressions in \p Exprs. + /// + /// \param IsCall Whether this is some form of call, in which case + /// default arguments will be dropped. + /// + /// \param TemplateArgs The set of template arguments to substitute. + /// + /// \param Outputs Will receive all of the substituted arguments. + /// + /// \returns true if an error occurred, false otherwise. + bool SubstExprs(Expr **Exprs, unsigned NumExprs, bool IsCall, + const MultiLevelTemplateArgumentList &TemplateArgs, + SmallVectorImpl<Expr *> &Outputs); + + StmtResult SubstStmt(Stmt *S, + const MultiLevelTemplateArgumentList &TemplateArgs); + + Decl *SubstDecl(Decl *D, DeclContext *Owner, + const MultiLevelTemplateArgumentList &TemplateArgs); + + ExprResult SubstInitializer(Expr *E, + const MultiLevelTemplateArgumentList &TemplateArgs, + bool CXXDirectInit); + + bool + SubstBaseSpecifiers(CXXRecordDecl *Instantiation, + CXXRecordDecl *Pattern, + const MultiLevelTemplateArgumentList &TemplateArgs); + + bool + InstantiateClass(SourceLocation PointOfInstantiation, + CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern, + const MultiLevelTemplateArgumentList &TemplateArgs, + TemplateSpecializationKind TSK, + bool Complain = true); + + bool InstantiateEnum(SourceLocation PointOfInstantiation, + EnumDecl *Instantiation, EnumDecl *Pattern, + const MultiLevelTemplateArgumentList &TemplateArgs, + TemplateSpecializationKind TSK); + + struct LateInstantiatedAttribute { + const Attr *TmplAttr; + LocalInstantiationScope *Scope; + Decl *NewDecl; + + LateInstantiatedAttribute(const Attr *A, LocalInstantiationScope *S, + Decl *D) + : TmplAttr(A), Scope(S), NewDecl(D) + { } + }; + typedef SmallVector<LateInstantiatedAttribute, 16> LateInstantiatedAttrVec; + + void InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, + const Decl *Pattern, Decl *Inst, + LateInstantiatedAttrVec *LateAttrs = 0, + LocalInstantiationScope *OuterMostScope = 0); + + bool + InstantiateClassTemplateSpecialization(SourceLocation PointOfInstantiation, + ClassTemplateSpecializationDecl *ClassTemplateSpec, + TemplateSpecializationKind TSK, + bool Complain = true); + + void InstantiateClassMembers(SourceLocation PointOfInstantiation, + CXXRecordDecl *Instantiation, + const MultiLevelTemplateArgumentList &TemplateArgs, + TemplateSpecializationKind TSK); + + void InstantiateClassTemplateSpecializationMembers( + SourceLocation PointOfInstantiation, + ClassTemplateSpecializationDecl *ClassTemplateSpec, + TemplateSpecializationKind TSK); + + NestedNameSpecifierLoc + SubstNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS, + const MultiLevelTemplateArgumentList &TemplateArgs); + + DeclarationNameInfo + SubstDeclarationNameInfo(const DeclarationNameInfo &NameInfo, + const MultiLevelTemplateArgumentList &TemplateArgs); + TemplateName + SubstTemplateName(NestedNameSpecifierLoc QualifierLoc, TemplateName Name, + SourceLocation Loc, + const MultiLevelTemplateArgumentList &TemplateArgs); + bool Subst(const TemplateArgumentLoc *Args, unsigned NumArgs, + TemplateArgumentListInfo &Result, + const MultiLevelTemplateArgumentList &TemplateArgs); + + void InstantiateExceptionSpec(SourceLocation PointOfInstantiation, + FunctionDecl *Function); + void InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, + FunctionDecl *Function, + bool Recursive = false, + bool DefinitionRequired = false); + void InstantiateStaticDataMemberDefinition( + SourceLocation PointOfInstantiation, + VarDecl *Var, + bool Recursive = false, + bool DefinitionRequired = false); + + void InstantiateMemInitializers(CXXConstructorDecl *New, + const CXXConstructorDecl *Tmpl, + const MultiLevelTemplateArgumentList &TemplateArgs); + + NamedDecl *FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, + const MultiLevelTemplateArgumentList &TemplateArgs); + DeclContext *FindInstantiatedContext(SourceLocation Loc, DeclContext *DC, + const MultiLevelTemplateArgumentList &TemplateArgs); + + // Objective-C declarations. + enum ObjCContainerKind { + OCK_None = -1, + OCK_Interface = 0, + OCK_Protocol, + OCK_Category, + OCK_ClassExtension, + OCK_Implementation, + OCK_CategoryImplementation + }; + ObjCContainerKind getObjCContainerKind() const; + + Decl *ActOnStartClassInterface(SourceLocation AtInterfaceLoc, + IdentifierInfo *ClassName, + SourceLocation ClassLoc, + IdentifierInfo *SuperName, + SourceLocation SuperLoc, + Decl * const *ProtoRefs, + unsigned NumProtoRefs, + const SourceLocation *ProtoLocs, + SourceLocation EndProtoLoc, + AttributeList *AttrList); + + Decl *ActOnCompatiblityAlias( + SourceLocation AtCompatibilityAliasLoc, + IdentifierInfo *AliasName, SourceLocation AliasLocation, + IdentifierInfo *ClassName, SourceLocation ClassLocation); + + bool CheckForwardProtocolDeclarationForCircularDependency( + IdentifierInfo *PName, + SourceLocation &PLoc, SourceLocation PrevLoc, + const ObjCList<ObjCProtocolDecl> &PList); + + Decl *ActOnStartProtocolInterface( + SourceLocation AtProtoInterfaceLoc, + IdentifierInfo *ProtocolName, SourceLocation ProtocolLoc, + Decl * const *ProtoRefNames, unsigned NumProtoRefs, + const SourceLocation *ProtoLocs, + SourceLocation EndProtoLoc, + AttributeList *AttrList); + + Decl *ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, + IdentifierInfo *ClassName, + SourceLocation ClassLoc, + IdentifierInfo *CategoryName, + SourceLocation CategoryLoc, + Decl * const *ProtoRefs, + unsigned NumProtoRefs, + const SourceLocation *ProtoLocs, + SourceLocation EndProtoLoc); + + Decl *ActOnStartClassImplementation( + SourceLocation AtClassImplLoc, + IdentifierInfo *ClassName, SourceLocation ClassLoc, + IdentifierInfo *SuperClassname, + SourceLocation SuperClassLoc); + + Decl *ActOnStartCategoryImplementation(SourceLocation AtCatImplLoc, + IdentifierInfo *ClassName, + SourceLocation ClassLoc, + IdentifierInfo *CatName, + SourceLocation CatLoc); + + DeclGroupPtrTy ActOnFinishObjCImplementation(Decl *ObjCImpDecl, + ArrayRef<Decl *> Decls); + + DeclGroupPtrTy ActOnForwardClassDeclaration(SourceLocation Loc, + IdentifierInfo **IdentList, + SourceLocation *IdentLocs, + unsigned NumElts); + + DeclGroupPtrTy ActOnForwardProtocolDeclaration(SourceLocation AtProtoclLoc, + const IdentifierLocPair *IdentList, + unsigned NumElts, + AttributeList *attrList); + + void FindProtocolDeclaration(bool WarnOnDeclarations, + const IdentifierLocPair *ProtocolId, + unsigned NumProtocols, + SmallVectorImpl<Decl *> &Protocols); + + /// Ensure attributes are consistent with type. + /// \param [in, out] Attributes The attributes to check; they will + /// be modified to be consistent with \arg PropertyTy. + void CheckObjCPropertyAttributes(Decl *PropertyPtrTy, + SourceLocation Loc, + unsigned &Attributes); + + /// Process the specified property declaration and create decls for the + /// setters and getters as needed. + /// \param property The property declaration being processed + /// \param DC The semantic container for the property + /// \param redeclaredProperty Declaration for property if redeclared + /// in class extension. + /// \param lexicalDC Container for redeclaredProperty. + void ProcessPropertyDecl(ObjCPropertyDecl *property, + ObjCContainerDecl *DC, + ObjCPropertyDecl *redeclaredProperty = 0, + ObjCContainerDecl *lexicalDC = 0); + + void DiagnosePropertyMismatch(ObjCPropertyDecl *Property, + ObjCPropertyDecl *SuperProperty, + const IdentifierInfo *Name); + void ComparePropertiesInBaseAndSuper(ObjCInterfaceDecl *IDecl); + + void CompareMethodParamsInBaseAndSuper(Decl *IDecl, + ObjCMethodDecl *MethodDecl, + bool IsInstance); + + void CompareProperties(Decl *CDecl, Decl *MergeProtocols); + + void DiagnoseClassExtensionDupMethods(ObjCCategoryDecl *CAT, + ObjCInterfaceDecl *ID); + + void MatchOneProtocolPropertiesInClass(Decl *CDecl, + ObjCProtocolDecl *PDecl); + + Decl *ActOnAtEnd(Scope *S, SourceRange AtEnd, + Decl **allMethods = 0, unsigned allNum = 0, + Decl **allProperties = 0, unsigned pNum = 0, + DeclGroupPtrTy *allTUVars = 0, unsigned tuvNum = 0); + + Decl *ActOnProperty(Scope *S, SourceLocation AtLoc, + SourceLocation LParenLoc, + FieldDeclarator &FD, ObjCDeclSpec &ODS, + Selector GetterSel, Selector SetterSel, + bool *OverridingProperty, + tok::ObjCKeywordKind MethodImplKind, + DeclContext *lexicalDC = 0); + + Decl *ActOnPropertyImplDecl(Scope *S, + SourceLocation AtLoc, + SourceLocation PropertyLoc, + bool ImplKind, + IdentifierInfo *PropertyId, + IdentifierInfo *PropertyIvar, + SourceLocation PropertyIvarLoc); + + enum ObjCSpecialMethodKind { + OSMK_None, + OSMK_Alloc, + OSMK_New, + OSMK_Copy, + OSMK_RetainingInit, + OSMK_NonRetainingInit + }; + + struct ObjCArgInfo { + IdentifierInfo *Name; + SourceLocation NameLoc; + // The Type is null if no type was specified, and the DeclSpec is invalid + // in this case. + ParsedType Type; + ObjCDeclSpec DeclSpec; + + /// ArgAttrs - Attribute list for this argument. + AttributeList *ArgAttrs; + }; + + Decl *ActOnMethodDeclaration( + Scope *S, + SourceLocation BeginLoc, // location of the + or -. + SourceLocation EndLoc, // location of the ; or {. + tok::TokenKind MethodType, + ObjCDeclSpec &ReturnQT, ParsedType ReturnType, + ArrayRef<SourceLocation> SelectorLocs, Selector Sel, + // optional arguments. The number of types/arguments is obtained + // from the Sel.getNumArgs(). + ObjCArgInfo *ArgInfo, + DeclaratorChunk::ParamInfo *CParamInfo, unsigned CNumArgs, // c-style args + AttributeList *AttrList, tok::ObjCKeywordKind MethodImplKind, + bool isVariadic, bool MethodDefinition); + + // Helper method for ActOnClassMethod/ActOnInstanceMethod. + // Will search "local" class/category implementations for a method decl. + // Will also search in class's root looking for instance method. + // Returns 0 if no method is found. + ObjCMethodDecl *LookupPrivateClassMethod(Selector Sel, + ObjCInterfaceDecl *CDecl); + ObjCMethodDecl *LookupPrivateInstanceMethod(Selector Sel, + ObjCInterfaceDecl *ClassDecl); + ObjCMethodDecl *LookupMethodInQualifiedType(Selector Sel, + const ObjCObjectPointerType *OPT, + bool IsInstance); + ObjCMethodDecl *LookupMethodInObjectType(Selector Sel, QualType Ty, + bool IsInstance); + + bool inferObjCARCLifetime(ValueDecl *decl); + + ExprResult + HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, + Expr *BaseExpr, + SourceLocation OpLoc, + DeclarationName MemberName, + SourceLocation MemberLoc, + SourceLocation SuperLoc, QualType SuperType, + bool Super); + + ExprResult + ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, + IdentifierInfo &propertyName, + SourceLocation receiverNameLoc, + SourceLocation propertyNameLoc); + + ObjCMethodDecl *tryCaptureObjCSelf(SourceLocation Loc); + + /// \brief Describes the kind of message expression indicated by a message + /// send that starts with an identifier. + enum ObjCMessageKind { + /// \brief The message is sent to 'super'. + ObjCSuperMessage, + /// \brief The message is an instance message. + ObjCInstanceMessage, + /// \brief The message is a class message, and the identifier is a type + /// name. + ObjCClassMessage + }; + + ObjCMessageKind getObjCMessageKind(Scope *S, + IdentifierInfo *Name, + SourceLocation NameLoc, + bool IsSuper, + bool HasTrailingDot, + ParsedType &ReceiverType); + + ExprResult ActOnSuperMessage(Scope *S, SourceLocation SuperLoc, + Selector Sel, + SourceLocation LBracLoc, + ArrayRef<SourceLocation> SelectorLocs, + SourceLocation RBracLoc, + MultiExprArg Args); + + ExprResult BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, + QualType ReceiverType, + SourceLocation SuperLoc, + Selector Sel, + ObjCMethodDecl *Method, + SourceLocation LBracLoc, + ArrayRef<SourceLocation> SelectorLocs, + SourceLocation RBracLoc, + MultiExprArg Args, + bool isImplicit = false); + + ExprResult BuildClassMessageImplicit(QualType ReceiverType, + bool isSuperReceiver, + SourceLocation Loc, + Selector Sel, + ObjCMethodDecl *Method, + MultiExprArg Args); + + ExprResult ActOnClassMessage(Scope *S, + ParsedType Receiver, + Selector Sel, + SourceLocation LBracLoc, + ArrayRef<SourceLocation> SelectorLocs, + SourceLocation RBracLoc, + MultiExprArg Args); + + ExprResult BuildInstanceMessage(Expr *Receiver, + QualType ReceiverType, + SourceLocation SuperLoc, + Selector Sel, + ObjCMethodDecl *Method, + SourceLocation LBracLoc, + ArrayRef<SourceLocation> SelectorLocs, + SourceLocation RBracLoc, + MultiExprArg Args, + bool isImplicit = false); + + ExprResult BuildInstanceMessageImplicit(Expr *Receiver, + QualType ReceiverType, + SourceLocation Loc, + Selector Sel, + ObjCMethodDecl *Method, + MultiExprArg Args); + + ExprResult ActOnInstanceMessage(Scope *S, + Expr *Receiver, + Selector Sel, + SourceLocation LBracLoc, + ArrayRef<SourceLocation> SelectorLocs, + SourceLocation RBracLoc, + MultiExprArg Args); + + ExprResult BuildObjCBridgedCast(SourceLocation LParenLoc, + ObjCBridgeCastKind Kind, + SourceLocation BridgeKeywordLoc, + TypeSourceInfo *TSInfo, + Expr *SubExpr); + + ExprResult ActOnObjCBridgedCast(Scope *S, + SourceLocation LParenLoc, + ObjCBridgeCastKind Kind, + SourceLocation BridgeKeywordLoc, + ParsedType Type, + SourceLocation RParenLoc, + Expr *SubExpr); + + bool checkInitMethod(ObjCMethodDecl *method, QualType receiverTypeIfCall); + + /// \brief Check whether the given new method is a valid override of the + /// given overridden method, and set any properties that should be inherited. + void CheckObjCMethodOverride(ObjCMethodDecl *NewMethod, + const ObjCMethodDecl *Overridden, + bool IsImplementation); + + /// \brief Check whether the given method overrides any methods in its class, + /// calling \c CheckObjCMethodOverride for each overridden method. + bool CheckObjCMethodOverrides(ObjCMethodDecl *NewMethod, DeclContext *DC); + + enum PragmaOptionsAlignKind { + POAK_Native, // #pragma options align=native + POAK_Natural, // #pragma options align=natural + POAK_Packed, // #pragma options align=packed + POAK_Power, // #pragma options align=power + POAK_Mac68k, // #pragma options align=mac68k + POAK_Reset // #pragma options align=reset + }; + + /// ActOnPragmaOptionsAlign - Called on well formed #pragma options align. + void ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind, + SourceLocation PragmaLoc, + SourceLocation KindLoc); + + enum PragmaPackKind { + PPK_Default, // #pragma pack([n]) + PPK_Show, // #pragma pack(show), only supported by MSVC. + PPK_Push, // #pragma pack(push, [identifier], [n]) + PPK_Pop // #pragma pack(pop, [identifier], [n]) + }; + + enum PragmaMSStructKind { + PMSST_OFF, // #pragms ms_struct off + PMSST_ON // #pragms ms_struct on + }; + + /// ActOnPragmaPack - Called on well formed #pragma pack(...). + void ActOnPragmaPack(PragmaPackKind Kind, + IdentifierInfo *Name, + Expr *Alignment, + SourceLocation PragmaLoc, + SourceLocation LParenLoc, + SourceLocation RParenLoc); + + /// ActOnPragmaMSStruct - Called on well formed #pragms ms_struct [on|off]. + void ActOnPragmaMSStruct(PragmaMSStructKind Kind); + + /// ActOnPragmaUnused - Called on well-formed '#pragma unused'. + void ActOnPragmaUnused(const Token &Identifier, + Scope *curScope, + SourceLocation PragmaLoc); + + /// ActOnPragmaVisibility - Called on well formed #pragma GCC visibility... . + void ActOnPragmaVisibility(const IdentifierInfo* VisType, + SourceLocation PragmaLoc); + + NamedDecl *DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II, + SourceLocation Loc); + void DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, WeakInfo &W); + + /// ActOnPragmaWeakID - Called on well formed #pragma weak ident. + void ActOnPragmaWeakID(IdentifierInfo* WeakName, + SourceLocation PragmaLoc, + SourceLocation WeakNameLoc); + + /// ActOnPragmaRedefineExtname - Called on well formed + /// #pragma redefine_extname oldname newname. + void ActOnPragmaRedefineExtname(IdentifierInfo* WeakName, + IdentifierInfo* AliasName, + SourceLocation PragmaLoc, + SourceLocation WeakNameLoc, + SourceLocation AliasNameLoc); + + /// ActOnPragmaWeakAlias - Called on well formed #pragma weak ident = ident. + void ActOnPragmaWeakAlias(IdentifierInfo* WeakName, + IdentifierInfo* AliasName, + SourceLocation PragmaLoc, + SourceLocation WeakNameLoc, + SourceLocation AliasNameLoc); + + /// ActOnPragmaFPContract - Called on well formed + /// #pragma {STDC,OPENCL} FP_CONTRACT + void ActOnPragmaFPContract(tok::OnOffSwitch OOS); + + /// AddAlignmentAttributesForRecord - Adds any needed alignment attributes to + /// a the record decl, to handle '#pragma pack' and '#pragma options align'. + void AddAlignmentAttributesForRecord(RecordDecl *RD); + + /// AddMsStructLayoutForRecord - Adds ms_struct layout attribute to record. + void AddMsStructLayoutForRecord(RecordDecl *RD); + + /// FreePackedContext - Deallocate and null out PackContext. + void FreePackedContext(); + + /// PushNamespaceVisibilityAttr - Note that we've entered a + /// namespace with a visibility attribute. + void PushNamespaceVisibilityAttr(const VisibilityAttr *Attr, + SourceLocation Loc); + + /// AddPushedVisibilityAttribute - If '#pragma GCC visibility' was used, + /// add an appropriate visibility attribute. + void AddPushedVisibilityAttribute(Decl *RD); + + /// PopPragmaVisibility - Pop the top element of the visibility stack; used + /// for '#pragma GCC visibility' and visibility attributes on namespaces. + void PopPragmaVisibility(bool IsNamespaceEnd, SourceLocation EndLoc); + + /// FreeVisContext - Deallocate and null out VisContext. + void FreeVisContext(); + + /// AddCFAuditedAttribute - Check whether we're currently within + /// '#pragma clang arc_cf_code_audited' and, if so, consider adding + /// the appropriate attribute. + void AddCFAuditedAttribute(Decl *D); + + /// AddAlignedAttr - Adds an aligned attribute to a particular declaration. + void AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E); + void AddAlignedAttr(SourceRange AttrRange, Decl *D, TypeSourceInfo *T); + + /// \brief The kind of conversion being performed. + enum CheckedConversionKind { + /// \brief An implicit conversion. + CCK_ImplicitConversion, + /// \brief A C-style cast. + CCK_CStyleCast, + /// \brief A functional-style cast. + CCK_FunctionalCast, + /// \brief A cast other than a C-style cast. + CCK_OtherCast + }; + + /// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit + /// cast. If there is already an implicit cast, merge into the existing one. + /// If isLvalue, the result of the cast is an lvalue. + ExprResult ImpCastExprToType(Expr *E, QualType Type, CastKind CK, + ExprValueKind VK = VK_RValue, + const CXXCastPath *BasePath = 0, + CheckedConversionKind CCK + = CCK_ImplicitConversion); + + /// ScalarTypeToBooleanCastKind - Returns the cast kind corresponding + /// to the conversion from scalar type ScalarTy to the Boolean type. + static CastKind ScalarTypeToBooleanCastKind(QualType ScalarTy); + + /// IgnoredValueConversions - Given that an expression's result is + /// syntactically ignored, perform any conversions that are + /// required. + ExprResult IgnoredValueConversions(Expr *E); + + // UsualUnaryConversions - promotes integers (C99 6.3.1.1p2) and converts + // functions and arrays to their respective pointers (C99 6.3.2.1). + ExprResult UsualUnaryConversions(Expr *E); + + // DefaultFunctionArrayConversion - converts functions and arrays + // to their respective pointers (C99 6.3.2.1). + ExprResult DefaultFunctionArrayConversion(Expr *E); + + // DefaultFunctionArrayLvalueConversion - converts functions and + // arrays to their respective pointers and performs the + // lvalue-to-rvalue conversion. + ExprResult DefaultFunctionArrayLvalueConversion(Expr *E); + + // DefaultLvalueConversion - performs lvalue-to-rvalue conversion on + // the operand. This is DefaultFunctionArrayLvalueConversion, + // except that it assumes the operand isn't of function or array + // type. + ExprResult DefaultLvalueConversion(Expr *E); + + // DefaultArgumentPromotion (C99 6.5.2.2p6). Used for function calls that + // do not have a prototype. Integer promotions are performed on each + // argument, and arguments that have type float are promoted to double. + ExprResult DefaultArgumentPromotion(Expr *E); + + // Used for emitting the right warning by DefaultVariadicArgumentPromotion + enum VariadicCallType { + VariadicFunction, + VariadicBlock, + VariadicMethod, + VariadicConstructor, + VariadicDoesNotApply + }; + + /// GatherArgumentsForCall - Collector argument expressions for various + /// form of call prototypes. + bool GatherArgumentsForCall(SourceLocation CallLoc, + FunctionDecl *FDecl, + const FunctionProtoType *Proto, + unsigned FirstProtoArg, + Expr **Args, unsigned NumArgs, + SmallVector<Expr *, 8> &AllArgs, + VariadicCallType CallType = VariadicDoesNotApply, + bool AllowExplicit = false); + + // DefaultVariadicArgumentPromotion - Like DefaultArgumentPromotion, but + // will warn if the resulting type is not a POD type. + ExprResult DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT, + FunctionDecl *FDecl); + + // UsualArithmeticConversions - performs the UsualUnaryConversions on it's + // operands and then handles various conversions that are common to binary + // operators (C99 6.3.1.8). If both operands aren't arithmetic, this + // routine returns the first non-arithmetic type found. The client is + // responsible for emitting appropriate error diagnostics. + QualType UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS, + bool IsCompAssign = false); + + /// AssignConvertType - All of the 'assignment' semantic checks return this + /// enum to indicate whether the assignment was allowed. These checks are + /// done for simple assignments, as well as initialization, return from + /// function, argument passing, etc. The query is phrased in terms of a + /// source and destination type. + enum AssignConvertType { + /// Compatible - the types are compatible according to the standard. + Compatible, + + /// PointerToInt - The assignment converts a pointer to an int, which we + /// accept as an extension. + PointerToInt, + + /// IntToPointer - The assignment converts an int to a pointer, which we + /// accept as an extension. + IntToPointer, + + /// FunctionVoidPointer - The assignment is between a function pointer and + /// void*, which the standard doesn't allow, but we accept as an extension. + FunctionVoidPointer, + + /// IncompatiblePointer - The assignment is between two pointers types that + /// are not compatible, but we accept them as an extension. + IncompatiblePointer, + + /// IncompatiblePointer - The assignment is between two pointers types which + /// point to integers which have a different sign, but are otherwise + /// identical. This is a subset of the above, but broken out because it's by + /// far the most common case of incompatible pointers. + IncompatiblePointerSign, + + /// CompatiblePointerDiscardsQualifiers - The assignment discards + /// c/v/r qualifiers, which we accept as an extension. + CompatiblePointerDiscardsQualifiers, + + /// IncompatiblePointerDiscardsQualifiers - The assignment + /// discards qualifiers that we don't permit to be discarded, + /// like address spaces. + IncompatiblePointerDiscardsQualifiers, + + /// IncompatibleNestedPointerQualifiers - The assignment is between two + /// nested pointer types, and the qualifiers other than the first two + /// levels differ e.g. char ** -> const char **, but we accept them as an + /// extension. + IncompatibleNestedPointerQualifiers, + + /// IncompatibleVectors - The assignment is between two vector types that + /// have the same size, which we accept as an extension. + IncompatibleVectors, + + /// IntToBlockPointer - The assignment converts an int to a block + /// pointer. We disallow this. + IntToBlockPointer, + + /// IncompatibleBlockPointer - The assignment is between two block + /// pointers types that are not compatible. + IncompatibleBlockPointer, + + /// IncompatibleObjCQualifiedId - The assignment is between a qualified + /// id type and something else (that is incompatible with it). For example, + /// "id <XXX>" = "Foo *", where "Foo *" doesn't implement the XXX protocol. + IncompatibleObjCQualifiedId, + + /// IncompatibleObjCWeakRef - Assigning a weak-unavailable object to an + /// object with __weak qualifier. + IncompatibleObjCWeakRef, + + /// Incompatible - We reject this conversion outright, it is invalid to + /// represent it in the AST. + Incompatible + }; + + /// DiagnoseAssignmentResult - Emit a diagnostic, if required, for the + /// assignment conversion type specified by ConvTy. This returns true if the + /// conversion was invalid or false if the conversion was accepted. + bool DiagnoseAssignmentResult(AssignConvertType ConvTy, + SourceLocation Loc, + QualType DstType, QualType SrcType, + Expr *SrcExpr, AssignmentAction Action, + bool *Complained = 0); + + /// CheckAssignmentConstraints - Perform type checking for assignment, + /// argument passing, variable initialization, and function return values. + /// C99 6.5.16. + AssignConvertType CheckAssignmentConstraints(SourceLocation Loc, + QualType LHSType, + QualType RHSType); + + /// Check assignment constraints and prepare for a conversion of the + /// RHS to the LHS type. + AssignConvertType CheckAssignmentConstraints(QualType LHSType, + ExprResult &RHS, + CastKind &Kind); + + // CheckSingleAssignmentConstraints - Currently used by + // CheckAssignmentOperands, and ActOnReturnStmt. Prior to type checking, + // this routine performs the default function/array converions. + AssignConvertType CheckSingleAssignmentConstraints(QualType LHSType, + ExprResult &RHS, + bool Diagnose = true); + + // \brief If the lhs type is a transparent union, check whether we + // can initialize the transparent union with the given expression. + AssignConvertType CheckTransparentUnionArgumentConstraints(QualType ArgType, + ExprResult &RHS); + + bool IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType); + + bool CheckExceptionSpecCompatibility(Expr *From, QualType ToType); + + ExprResult PerformImplicitConversion(Expr *From, QualType ToType, + AssignmentAction Action, + bool AllowExplicit = false); + ExprResult PerformImplicitConversion(Expr *From, QualType ToType, + AssignmentAction Action, + bool AllowExplicit, + ImplicitConversionSequence& ICS); + ExprResult PerformImplicitConversion(Expr *From, QualType ToType, + const ImplicitConversionSequence& ICS, + AssignmentAction Action, + CheckedConversionKind CCK + = CCK_ImplicitConversion); + ExprResult PerformImplicitConversion(Expr *From, QualType ToType, + const StandardConversionSequence& SCS, + AssignmentAction Action, + CheckedConversionKind CCK); + + /// the following "Check" methods will return a valid/converted QualType + /// or a null QualType (indicating an error diagnostic was issued). + + /// type checking binary operators (subroutines of CreateBuiltinBinOp). + QualType InvalidOperands(SourceLocation Loc, ExprResult &LHS, + ExprResult &RHS); + QualType CheckPointerToMemberOperands( // C++ 5.5 + ExprResult &LHS, ExprResult &RHS, ExprValueKind &VK, + SourceLocation OpLoc, bool isIndirect); + QualType CheckMultiplyDivideOperands( // C99 6.5.5 + ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsCompAssign, + bool IsDivide); + QualType CheckRemainderOperands( // C99 6.5.5 + ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, + bool IsCompAssign = false); + QualType CheckAdditionOperands( // C99 6.5.6 + ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, unsigned Opc, + QualType* CompLHSTy = 0); + QualType CheckSubtractionOperands( // C99 6.5.6 + ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, + QualType* CompLHSTy = 0); + QualType CheckShiftOperands( // C99 6.5.7 + ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, unsigned Opc, + bool IsCompAssign = false); + QualType CheckCompareOperands( // C99 6.5.8/9 + ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, unsigned OpaqueOpc, + bool isRelational); + QualType CheckBitwiseOperands( // C99 6.5.[10...12] + ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, + bool IsCompAssign = false); + QualType CheckLogicalOperands( // C99 6.5.[13,14] + ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, unsigned Opc); + // CheckAssignmentOperands is used for both simple and compound assignment. + // For simple assignment, pass both expressions and a null converted type. + // For compound assignment, pass both expressions and the converted type. + QualType CheckAssignmentOperands( // C99 6.5.16.[1,2] + Expr *LHSExpr, ExprResult &RHS, SourceLocation Loc, QualType CompoundType); + + ExprResult checkPseudoObjectIncDec(Scope *S, SourceLocation OpLoc, + UnaryOperatorKind Opcode, Expr *Op); + ExprResult checkPseudoObjectAssignment(Scope *S, SourceLocation OpLoc, + BinaryOperatorKind Opcode, + Expr *LHS, Expr *RHS); + ExprResult checkPseudoObjectRValue(Expr *E); + Expr *recreateSyntacticForm(PseudoObjectExpr *E); + + QualType CheckConditionalOperands( // C99 6.5.15 + ExprResult &Cond, ExprResult &LHS, ExprResult &RHS, + ExprValueKind &VK, ExprObjectKind &OK, SourceLocation QuestionLoc); + QualType CXXCheckConditionalOperands( // C++ 5.16 + ExprResult &cond, ExprResult &lhs, ExprResult &rhs, + ExprValueKind &VK, ExprObjectKind &OK, SourceLocation questionLoc); + QualType FindCompositePointerType(SourceLocation Loc, Expr *&E1, Expr *&E2, + bool *NonStandardCompositeType = 0); + QualType FindCompositePointerType(SourceLocation Loc, + ExprResult &E1, ExprResult &E2, + bool *NonStandardCompositeType = 0) { + Expr *E1Tmp = E1.take(), *E2Tmp = E2.take(); + QualType Composite = FindCompositePointerType(Loc, E1Tmp, E2Tmp, + NonStandardCompositeType); + E1 = Owned(E1Tmp); + E2 = Owned(E2Tmp); + return Composite; + } + + QualType FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS, + SourceLocation QuestionLoc); + + bool DiagnoseConditionalForNull(Expr *LHSExpr, Expr *RHSExpr, + SourceLocation QuestionLoc); + + /// type checking for vector binary operators. + QualType CheckVectorOperands(ExprResult &LHS, ExprResult &RHS, + SourceLocation Loc, bool IsCompAssign); + QualType GetSignedVectorType(QualType V); + QualType CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS, + SourceLocation Loc, bool isRelational); + QualType CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS, + SourceLocation Loc); + + /// type checking declaration initializers (C99 6.7.8) + bool CheckForConstantInitializer(Expr *e, QualType t); + + // type checking C++ declaration initializers (C++ [dcl.init]). + + /// ReferenceCompareResult - Expresses the result of comparing two + /// types (cv1 T1 and cv2 T2) to determine their compatibility for the + /// purposes of initialization by reference (C++ [dcl.init.ref]p4). + enum ReferenceCompareResult { + /// Ref_Incompatible - The two types are incompatible, so direct + /// reference binding is not possible. + Ref_Incompatible = 0, + /// Ref_Related - The two types are reference-related, which means + /// that their unqualified forms (T1 and T2) are either the same + /// or T1 is a base class of T2. + Ref_Related, + /// Ref_Compatible_With_Added_Qualification - The two types are + /// reference-compatible with added qualification, meaning that + /// they are reference-compatible and the qualifiers on T1 (cv1) + /// are greater than the qualifiers on T2 (cv2). + Ref_Compatible_With_Added_Qualification, + /// Ref_Compatible - The two types are reference-compatible and + /// have equivalent qualifiers (cv1 == cv2). + Ref_Compatible + }; + + ReferenceCompareResult CompareReferenceRelationship(SourceLocation Loc, + QualType T1, QualType T2, + bool &DerivedToBase, + bool &ObjCConversion, + bool &ObjCLifetimeConversion); + + ExprResult checkUnknownAnyCast(SourceRange TypeRange, QualType CastType, + Expr *CastExpr, CastKind &CastKind, + ExprValueKind &VK, CXXCastPath &Path); + + /// \brief Force an expression with unknown-type to an expression of the + /// given type. + ExprResult forceUnknownAnyToType(Expr *E, QualType ToType); + + // CheckVectorCast - check type constraints for vectors. + // Since vectors are an extension, there are no C standard reference for this. + // We allow casting between vectors and integer datatypes of the same size. + // returns true if the cast is invalid + bool CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty, + CastKind &Kind); + + // CheckExtVectorCast - check type constraints for extended vectors. + // Since vectors are an extension, there are no C standard reference for this. + // We allow casting between vectors and integer datatypes of the same size, + // or vectors and the element type of that vector. + // returns the cast expr + ExprResult CheckExtVectorCast(SourceRange R, QualType DestTy, Expr *CastExpr, + CastKind &Kind); + + ExprResult BuildCXXFunctionalCastExpr(TypeSourceInfo *TInfo, + SourceLocation LParenLoc, + Expr *CastExpr, + SourceLocation RParenLoc); + + enum ARCConversionResult { ACR_okay, ACR_unbridged }; + + /// \brief Checks for invalid conversions and casts between + /// retainable pointers and other pointer kinds. + ARCConversionResult CheckObjCARCConversion(SourceRange castRange, + QualType castType, Expr *&op, + CheckedConversionKind CCK); + + Expr *stripARCUnbridgedCast(Expr *e); + void diagnoseARCUnbridgedCast(Expr *e); + + bool CheckObjCARCUnavailableWeakConversion(QualType castType, + QualType ExprType); + + /// checkRetainCycles - Check whether an Objective-C message send + /// might create an obvious retain cycle. + void checkRetainCycles(ObjCMessageExpr *msg); + void checkRetainCycles(Expr *receiver, Expr *argument); + + /// checkUnsafeAssigns - Check whether +1 expr is being assigned + /// to weak/__unsafe_unretained type. + bool checkUnsafeAssigns(SourceLocation Loc, QualType LHS, Expr *RHS); + + /// checkUnsafeExprAssigns - Check whether +1 expr is being assigned + /// to weak/__unsafe_unretained expression. + void checkUnsafeExprAssigns(SourceLocation Loc, Expr *LHS, Expr *RHS); + + /// CheckMessageArgumentTypes - Check types in an Obj-C message send. + /// \param Method - May be null. + /// \param [out] ReturnType - The return type of the send. + /// \return true iff there were any incompatible types. + bool CheckMessageArgumentTypes(QualType ReceiverType, + Expr **Args, unsigned NumArgs, Selector Sel, + ObjCMethodDecl *Method, bool isClassMessage, + bool isSuperMessage, + SourceLocation lbrac, SourceLocation rbrac, + QualType &ReturnType, ExprValueKind &VK); + + /// \brief Determine the result of a message send expression based on + /// the type of the receiver, the method expected to receive the message, + /// and the form of the message send. + QualType getMessageSendResultType(QualType ReceiverType, + ObjCMethodDecl *Method, + bool isClassMessage, bool isSuperMessage); + + /// \brief If the given expression involves a message send to a method + /// with a related result type, emit a note describing what happened. + void EmitRelatedResultTypeNote(const Expr *E); + + /// CheckBooleanCondition - Diagnose problems involving the use of + /// the given expression as a boolean condition (e.g. in an if + /// statement). Also performs the standard function and array + /// decays, possibly changing the input variable. + /// + /// \param Loc - A location associated with the condition, e.g. the + /// 'if' keyword. + /// \return true iff there were any errors + ExprResult CheckBooleanCondition(Expr *E, SourceLocation Loc); + + ExprResult ActOnBooleanCondition(Scope *S, SourceLocation Loc, + Expr *SubExpr); + + /// DiagnoseAssignmentAsCondition - Given that an expression is + /// being used as a boolean condition, warn if it's an assignment. + void DiagnoseAssignmentAsCondition(Expr *E); + + /// \brief Redundant parentheses over an equality comparison can indicate + /// that the user intended an assignment used as condition. + void DiagnoseEqualityWithExtraParens(ParenExpr *ParenE); + + /// CheckCXXBooleanCondition - Returns true if conversion to bool is invalid. + ExprResult CheckCXXBooleanCondition(Expr *CondExpr); + + /// ConvertIntegerToTypeWarnOnOverflow - Convert the specified APInt to have + /// the specified width and sign. If an overflow occurs, detect it and emit + /// the specified diagnostic. + void ConvertIntegerToTypeWarnOnOverflow(llvm::APSInt &OldVal, + unsigned NewWidth, bool NewSign, + SourceLocation Loc, unsigned DiagID); + + /// Checks that the Objective-C declaration is declared in the global scope. + /// Emits an error and marks the declaration as invalid if it's not declared + /// in the global scope. + bool CheckObjCDeclScope(Decl *D); + + /// VerifyIntegerConstantExpression - Verifies that an expression is an ICE, + /// and reports the appropriate diagnostics. Returns false on success. + /// Can optionally return the value of the expression. + ExprResult VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result, + const PartialDiagnostic &Diag, + bool AllowFold, + const PartialDiagnostic &FoldDiag); + ExprResult VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result, + const PartialDiagnostic &Diag, + bool AllowFold = true) { + return VerifyIntegerConstantExpression(E, Result, Diag, AllowFold, + PDiag(0)); + } + ExprResult VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result = 0); + + /// VerifyBitField - verifies that a bit field expression is an ICE and has + /// the correct width, and that the field type is valid. + /// Returns false on success. + /// Can optionally return whether the bit-field is of width 0 + ExprResult VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName, + QualType FieldTy, Expr *BitWidth, + bool *ZeroWidth = 0); + + enum CUDAFunctionTarget { + CFT_Device, + CFT_Global, + CFT_Host, + CFT_HostDevice + }; + + CUDAFunctionTarget IdentifyCUDATarget(const FunctionDecl *D); + + bool CheckCUDATarget(CUDAFunctionTarget CallerTarget, + CUDAFunctionTarget CalleeTarget); + + bool CheckCUDATarget(const FunctionDecl *Caller, const FunctionDecl *Callee) { + return CheckCUDATarget(IdentifyCUDATarget(Caller), + IdentifyCUDATarget(Callee)); + } + + /// \name Code completion + //@{ + /// \brief Describes the context in which code completion occurs. + enum ParserCompletionContext { + /// \brief Code completion occurs at top-level or namespace context. + PCC_Namespace, + /// \brief Code completion occurs within a class, struct, or union. + PCC_Class, + /// \brief Code completion occurs within an Objective-C interface, protocol, + /// or category. + PCC_ObjCInterface, + /// \brief Code completion occurs within an Objective-C implementation or + /// category implementation + PCC_ObjCImplementation, + /// \brief Code completion occurs within the list of instance variables + /// in an Objective-C interface, protocol, category, or implementation. + PCC_ObjCInstanceVariableList, + /// \brief Code completion occurs following one or more template + /// headers. + PCC_Template, + /// \brief Code completion occurs following one or more template + /// headers within a class. + PCC_MemberTemplate, + /// \brief Code completion occurs within an expression. + PCC_Expression, + /// \brief Code completion occurs within a statement, which may + /// also be an expression or a declaration. + PCC_Statement, + /// \brief Code completion occurs at the beginning of the + /// initialization statement (or expression) in a for loop. + PCC_ForInit, + /// \brief Code completion occurs within the condition of an if, + /// while, switch, or for statement. + PCC_Condition, + /// \brief Code completion occurs within the body of a function on a + /// recovery path, where we do not have a specific handle on our position + /// in the grammar. + PCC_RecoveryInFunction, + /// \brief Code completion occurs where only a type is permitted. + PCC_Type, + /// \brief Code completion occurs in a parenthesized expression, which + /// might also be a type cast. + PCC_ParenthesizedExpression, + /// \brief Code completion occurs within a sequence of declaration + /// specifiers within a function, method, or block. + PCC_LocalDeclarationSpecifiers + }; + + void CodeCompleteModuleImport(SourceLocation ImportLoc, ModuleIdPath Path); + void CodeCompleteOrdinaryName(Scope *S, + ParserCompletionContext CompletionContext); + void CodeCompleteDeclSpec(Scope *S, DeclSpec &DS, + bool AllowNonIdentifiers, + bool AllowNestedNameSpecifiers); + + struct CodeCompleteExpressionData; + void CodeCompleteExpression(Scope *S, + const CodeCompleteExpressionData &Data); + void CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base, + SourceLocation OpLoc, + bool IsArrow); + void CodeCompletePostfixExpression(Scope *S, ExprResult LHS); + void CodeCompleteTag(Scope *S, unsigned TagSpec); + void CodeCompleteTypeQualifiers(DeclSpec &DS); + void CodeCompleteCase(Scope *S); + void CodeCompleteCall(Scope *S, Expr *Fn, llvm::ArrayRef<Expr *> Args); + void CodeCompleteInitializer(Scope *S, Decl *D); + void CodeCompleteReturn(Scope *S); + void CodeCompleteAfterIf(Scope *S); + void CodeCompleteAssignmentRHS(Scope *S, Expr *LHS); + + void CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS, + bool EnteringContext); + void CodeCompleteUsing(Scope *S); + void CodeCompleteUsingDirective(Scope *S); + void CodeCompleteNamespaceDecl(Scope *S); + void CodeCompleteNamespaceAliasDecl(Scope *S); + void CodeCompleteOperatorName(Scope *S); + void CodeCompleteConstructorInitializer(Decl *Constructor, + CXXCtorInitializer** Initializers, + unsigned NumInitializers); + void CodeCompleteLambdaIntroducer(Scope *S, LambdaIntroducer &Intro, + bool AfterAmpersand); + + void CodeCompleteObjCAtDirective(Scope *S); + void CodeCompleteObjCAtVisibility(Scope *S); + void CodeCompleteObjCAtStatement(Scope *S); + void CodeCompleteObjCAtExpression(Scope *S); + void CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS); + void CodeCompleteObjCPropertyGetter(Scope *S); + void CodeCompleteObjCPropertySetter(Scope *S); + void CodeCompleteObjCPassingType(Scope *S, ObjCDeclSpec &DS, + bool IsParameter); + void CodeCompleteObjCMessageReceiver(Scope *S); + void CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc, + IdentifierInfo **SelIdents, + unsigned NumSelIdents, + bool AtArgumentExpression); + void CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver, + IdentifierInfo **SelIdents, + unsigned NumSelIdents, + bool AtArgumentExpression, + bool IsSuper = false); + void CodeCompleteObjCInstanceMessage(Scope *S, Expr *Receiver, + IdentifierInfo **SelIdents, + unsigned NumSelIdents, + bool AtArgumentExpression, + ObjCInterfaceDecl *Super = 0); + void CodeCompleteObjCForCollection(Scope *S, + DeclGroupPtrTy IterationVar); + void CodeCompleteObjCSelector(Scope *S, + IdentifierInfo **SelIdents, + unsigned NumSelIdents); + void CodeCompleteObjCProtocolReferences(IdentifierLocPair *Protocols, + unsigned NumProtocols); + void CodeCompleteObjCProtocolDecl(Scope *S); + void CodeCompleteObjCInterfaceDecl(Scope *S); + void CodeCompleteObjCSuperclass(Scope *S, + IdentifierInfo *ClassName, + SourceLocation ClassNameLoc); + void CodeCompleteObjCImplementationDecl(Scope *S); + void CodeCompleteObjCInterfaceCategory(Scope *S, + IdentifierInfo *ClassName, + SourceLocation ClassNameLoc); + void CodeCompleteObjCImplementationCategory(Scope *S, + IdentifierInfo *ClassName, + SourceLocation ClassNameLoc); + void CodeCompleteObjCPropertyDefinition(Scope *S); + void CodeCompleteObjCPropertySynthesizeIvar(Scope *S, + IdentifierInfo *PropertyName); + void CodeCompleteObjCMethodDecl(Scope *S, + bool IsInstanceMethod, + ParsedType ReturnType); + void CodeCompleteObjCMethodDeclSelector(Scope *S, + bool IsInstanceMethod, + bool AtParameterName, + ParsedType ReturnType, + IdentifierInfo **SelIdents, + unsigned NumSelIdents); + void CodeCompletePreprocessorDirective(bool InConditional); + void CodeCompleteInPreprocessorConditionalExclusion(Scope *S); + void CodeCompletePreprocessorMacroName(bool IsDefinition); + void CodeCompletePreprocessorExpression(); + void CodeCompletePreprocessorMacroArgument(Scope *S, + IdentifierInfo *Macro, + MacroInfo *MacroInfo, + unsigned Argument); + void CodeCompleteNaturalLanguage(); + void GatherGlobalCodeCompletions(CodeCompletionAllocator &Allocator, + CodeCompletionTUInfo &CCTUInfo, + SmallVectorImpl<CodeCompletionResult> &Results); + //@} + + //===--------------------------------------------------------------------===// + // Extra semantic analysis beyond the C type system + +public: + SourceLocation getLocationOfStringLiteralByte(const StringLiteral *SL, + unsigned ByteNo) const; + +private: + void CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr, + const ArraySubscriptExpr *ASE=0, + bool AllowOnePastEnd=true, bool IndexNegated=false); + void CheckArrayAccess(const Expr *E); + bool CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall); + bool CheckObjCMethodCall(ObjCMethodDecl *Method, SourceLocation loc, + Expr **Args, unsigned NumArgs); + bool CheckBlockCall(NamedDecl *NDecl, CallExpr *TheCall); + + bool CheckObjCString(Expr *Arg); + + ExprResult CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); + bool CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); + + bool SemaBuiltinVAStart(CallExpr *TheCall); + bool SemaBuiltinUnorderedCompare(CallExpr *TheCall); + bool SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs); + +public: + // Used by C++ template instantiation. + ExprResult SemaBuiltinShuffleVector(CallExpr *TheCall); + +private: + bool SemaBuiltinPrefetch(CallExpr *TheCall); + bool SemaBuiltinObjectSize(CallExpr *TheCall); + bool SemaBuiltinLongjmp(CallExpr *TheCall); + ExprResult SemaBuiltinAtomicOverloaded(ExprResult TheCallResult); + ExprResult SemaAtomicOpsOverloaded(ExprResult TheCallResult, + AtomicExpr::AtomicOp Op); + bool SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum, + llvm::APSInt &Result); + + enum FormatStringType { + FST_Scanf, + FST_Printf, + FST_NSString, + FST_Strftime, + FST_Strfmon, + FST_Kprintf, + FST_Unknown + }; + static FormatStringType GetFormatStringType(const FormatAttr *Format); + bool SemaCheckStringLiteral(const Expr *E, Expr **Args, unsigned NumArgs, + bool HasVAListArg, unsigned format_idx, + unsigned firstDataArg, FormatStringType Type, + bool inFunctionCall = true); + + void CheckFormatString(const StringLiteral *FExpr, const Expr *OrigFormatExpr, + Expr **Args, unsigned NumArgs, bool HasVAListArg, + unsigned format_idx, unsigned firstDataArg, + FormatStringType Type, bool inFunctionCall); + + void CheckFormatArguments(const FormatAttr *Format, CallExpr *TheCall); + void CheckFormatArguments(const FormatAttr *Format, Expr **Args, + unsigned NumArgs, bool IsCXXMember, + SourceLocation Loc, SourceRange Range); + void CheckFormatArguments(Expr **Args, unsigned NumArgs, + bool HasVAListArg, unsigned format_idx, + unsigned firstDataArg, FormatStringType Type, + SourceLocation Loc, SourceRange range); + + void CheckNonNullArguments(const NonNullAttr *NonNull, + const Expr * const *ExprArgs, + SourceLocation CallSiteLoc); + + void CheckMemaccessArguments(const CallExpr *Call, + unsigned BId, + IdentifierInfo *FnName); + + void CheckStrlcpycatArguments(const CallExpr *Call, + IdentifierInfo *FnName); + + void CheckStrncatArguments(const CallExpr *Call, + IdentifierInfo *FnName); + + void CheckReturnStackAddr(Expr *RetValExp, QualType lhsType, + SourceLocation ReturnLoc); + void CheckFloatComparison(SourceLocation Loc, Expr* LHS, Expr* RHS); + void CheckImplicitConversions(Expr *E, SourceLocation CC = SourceLocation()); + + void CheckBitFieldInitialization(SourceLocation InitLoc, FieldDecl *Field, + Expr *Init); + + /// \brief The parser's current scope. + /// + /// The parser maintains this state here. + Scope *CurScope; + +protected: + friend class Parser; + friend class InitializationSequence; + friend class ASTReader; + friend class ASTWriter; + +public: + /// \brief Retrieve the parser's current scope. + /// + /// This routine must only be used when it is certain that semantic analysis + /// and the parser are in precisely the same context, which is not the case + /// when, e.g., we are performing any kind of template instantiation. + /// Therefore, the only safe places to use this scope are in the parser + /// itself and in routines directly invoked from the parser and *never* from + /// template substitution or instantiation. + Scope *getCurScope() const { return CurScope; } + + Decl *getObjCDeclContext() const; + + DeclContext *getCurLexicalContext() const { + return OriginalLexicalContext ? OriginalLexicalContext : CurContext; + } + + AvailabilityResult getCurContextAvailability() const; +}; + +/// \brief RAII object that enters a new expression evaluation context. +class EnterExpressionEvaluationContext { + Sema &Actions; + +public: + EnterExpressionEvaluationContext(Sema &Actions, + Sema::ExpressionEvaluationContext NewContext, + Decl *LambdaContextDecl = 0, + bool IsDecltype = false) + : Actions(Actions) { + Actions.PushExpressionEvaluationContext(NewContext, LambdaContextDecl, + IsDecltype); + } + + ~EnterExpressionEvaluationContext() { + Actions.PopExpressionEvaluationContext(); + } +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Sema/SemaConsumer.h b/clang/include/clang/Sema/SemaConsumer.h new file mode 100644 index 0000000..139cce8 --- /dev/null +++ b/clang/include/clang/Sema/SemaConsumer.h @@ -0,0 +1,49 @@ +//===--- SemaConsumer.h - Abstract interface for AST semantics --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the SemaConsumer class, a subclass of +// ASTConsumer that is used by AST clients that also require +// additional semantic analysis. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_SEMA_SEMACONSUMER_H +#define LLVM_CLANG_SEMA_SEMACONSUMER_H + +#include "clang/AST/ASTConsumer.h" + +namespace clang { + class Sema; + + /// \brief An abstract interface that should be implemented by + /// clients that read ASTs and then require further semantic + /// analysis of the entities in those ASTs. + class SemaConsumer : public ASTConsumer { + virtual void anchor(); + public: + SemaConsumer() { + ASTConsumer::SemaConsumer = true; + } + + /// \brief Initialize the semantic consumer with the Sema instance + /// being used to perform semantic analysis on the abstract syntax + /// tree. + virtual void InitializeSema(Sema &S) {} + + /// \brief Inform the semantic consumer that Sema is no longer available. + virtual void ForgetSema() {} + + // isa/cast/dyn_cast support + static bool classof(const ASTConsumer *Consumer) { + return Consumer->SemaConsumer; + } + static bool classof(const SemaConsumer *) { return true; } + }; +} + +#endif diff --git a/clang/include/clang/Sema/SemaDiagnostic.h b/clang/include/clang/Sema/SemaDiagnostic.h new file mode 100644 index 0000000..9605bf8 --- /dev/null +++ b/clang/include/clang/Sema/SemaDiagnostic.h @@ -0,0 +1,28 @@ +//===--- DiagnosticSema.h - Diagnostics for libsema -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_DIAGNOSTICSEMA_H +#define LLVM_CLANG_DIAGNOSTICSEMA_H + +#include "clang/Basic/Diagnostic.h" + +namespace clang { + namespace diag { + enum { +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\ + SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM, +#define SEMASTART +#include "clang/Basic/DiagnosticSemaKinds.inc" +#undef DIAG + NUM_BUILTIN_SEMA_DIAGNOSTICS + }; + } // end namespace diag +} // end namespace clang + +#endif diff --git a/clang/include/clang/Sema/SemaFixItUtils.h b/clang/include/clang/Sema/SemaFixItUtils.h new file mode 100644 index 0000000..fffca67 --- /dev/null +++ b/clang/include/clang/Sema/SemaFixItUtils.h @@ -0,0 +1,91 @@ +//===--- SemaFixItUtils.h - Sema FixIts -----------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines helper classes for generation of Sema FixItHints. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_SEMA_FIXITUTILS_H +#define LLVM_CLANG_SEMA_FIXITUTILS_H + +#include "clang/AST/Expr.h" + +namespace clang { + +enum OverloadFixItKind { + OFIK_Undefined = 0, + OFIK_Dereference, + OFIK_TakeAddress, + OFIK_RemoveDereference, + OFIK_RemoveTakeAddress +}; + +class Sema; + +/// The class facilities generation and storage of conversion FixIts. Hints for +/// new conversions are added using TryToFixConversion method. The default type +/// conversion checker can be reset. +struct ConversionFixItGenerator { + /// Performs a simple check to see if From type can be converted to To type. + static bool compareTypesSimple(CanQualType From, + CanQualType To, + Sema &S, + SourceLocation Loc, + ExprValueKind FromVK); + + /// The list of Hints generated so far. + std::vector<FixItHint> Hints; + + /// The number of Conversions fixed. This can be different from the size + /// of the Hints vector since we allow multiple FixIts per conversion. + unsigned NumConversionsFixed; + + /// The type of fix applied. If multiple conversions are fixed, corresponds + /// to the kid of the very first conversion. + OverloadFixItKind Kind; + + typedef bool (*TypeComparisonFuncTy) (const CanQualType FromTy, + const CanQualType ToTy, + Sema &S, + SourceLocation Loc, + ExprValueKind FromVK); + /// The type comparison function used to decide if expression FromExpr of + /// type FromTy can be converted to ToTy. For example, one could check if + /// an implicit conversion exists. Returns true if comparison exists. + TypeComparisonFuncTy CompareTypes; + + ConversionFixItGenerator(TypeComparisonFuncTy Foo): NumConversionsFixed(0), + Kind(OFIK_Undefined), + CompareTypes(Foo) {} + + ConversionFixItGenerator(): NumConversionsFixed(0), + Kind(OFIK_Undefined), + CompareTypes(compareTypesSimple) {} + + /// Resets the default conversion checker method. + void setConversionChecker(TypeComparisonFuncTy Foo) { + CompareTypes = Foo; + } + + /// If possible, generates and stores a fix for the given conversion. + bool tryToFixConversion(const Expr *FromExpr, + const QualType FromQTy, const QualType ToQTy, + Sema &S); + + void clear() { + Hints.clear(); + NumConversionsFixed = 0; + } + + bool isNull() { + return (NumConversionsFixed == 0); + } +}; + +} // endof namespace clang +#endif // LLVM_CLANG_SEMA_FIXITUTILS_H diff --git a/clang/include/clang/Sema/SemaInternal.h b/clang/include/clang/Sema/SemaInternal.h new file mode 100644 index 0000000..64b83e3 --- /dev/null +++ b/clang/include/clang/Sema/SemaInternal.h @@ -0,0 +1,30 @@ +//===--- SemaInternal.h - Internal Sema Interfaces --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides common API and #includes for the internal +// implementation of Sema. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_SEMA_INTERNAL_H +#define LLVM_CLANG_SEMA_SEMA_INTERNAL_H + +#include "clang/Sema/Sema.h" +#include "clang/Sema/SemaDiagnostic.h" +#include "clang/AST/ASTContext.h" + +namespace clang { + +inline PartialDiagnostic Sema::PDiag(unsigned DiagID) { + return PartialDiagnostic(DiagID, Context.getDiagAllocator()); +} + +} + +#endif diff --git a/clang/include/clang/Sema/Template.h b/clang/include/clang/Sema/Template.h new file mode 100644 index 0000000..c16823a --- /dev/null +++ b/clang/include/clang/Sema/Template.h @@ -0,0 +1,491 @@ +//===------- SemaTemplate.h - C++ Templates ---------------------*- C++ -*-===/ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +//===----------------------------------------------------------------------===/ +// +// This file provides types used in the semantic analysis of C++ templates. +// +//===----------------------------------------------------------------------===/ +#ifndef LLVM_CLANG_SEMA_TEMPLATE_H +#define LLVM_CLANG_SEMA_TEMPLATE_H + +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/DeclVisitor.h" +#include "llvm/ADT/SmallVector.h" +#include <cassert> +#include <utility> + +namespace clang { + /// \brief Data structure that captures multiple levels of template argument + /// lists for use in template instantiation. + /// + /// Multiple levels of template arguments occur when instantiating the + /// definitions of member templates. For example: + /// + /// \code + /// template<typename T> + /// struct X { + /// template<T Value> + /// struct Y { + /// void f(); + /// }; + /// }; + /// \endcode + /// + /// When instantiating X<int>::Y<17>::f, the multi-level template argument + /// list will contain a template argument list (int) at depth 0 and a + /// template argument list (17) at depth 1. + class MultiLevelTemplateArgumentList { + public: + typedef std::pair<const TemplateArgument *, unsigned> ArgList; + + private: + /// \brief The template argument lists, stored from the innermost template + /// argument list (first) to the outermost template argument list (last). + SmallVector<ArgList, 4> TemplateArgumentLists; + + public: + /// \brief Construct an empty set of template argument lists. + MultiLevelTemplateArgumentList() { } + + /// \brief Construct a single-level template argument list. + explicit + MultiLevelTemplateArgumentList(const TemplateArgumentList &TemplateArgs) { + addOuterTemplateArguments(&TemplateArgs); + } + + /// \brief Determine the number of levels in this template argument + /// list. + unsigned getNumLevels() const { return TemplateArgumentLists.size(); } + + /// \brief Retrieve the template argument at a given depth and index. + const TemplateArgument &operator()(unsigned Depth, unsigned Index) const { + assert(Depth < TemplateArgumentLists.size()); + assert(Index < TemplateArgumentLists[getNumLevels() - Depth - 1].second); + return TemplateArgumentLists[getNumLevels() - Depth - 1].first[Index]; + } + + /// \brief Determine whether there is a non-NULL template argument at the + /// given depth and index. + /// + /// There must exist a template argument list at the given depth. + bool hasTemplateArgument(unsigned Depth, unsigned Index) const { + assert(Depth < TemplateArgumentLists.size()); + + if (Index >= TemplateArgumentLists[getNumLevels() - Depth - 1].second) + return false; + + return !(*this)(Depth, Index).isNull(); + } + + /// \brief Clear out a specific template argument. + void setArgument(unsigned Depth, unsigned Index, + TemplateArgument Arg) { + assert(Depth < TemplateArgumentLists.size()); + assert(Index < TemplateArgumentLists[getNumLevels() - Depth - 1].second); + const_cast<TemplateArgument&>( + TemplateArgumentLists[getNumLevels() - Depth - 1].first[Index]) + = Arg; + } + + /// \brief Add a new outermost level to the multi-level template argument + /// list. + void addOuterTemplateArguments(const TemplateArgumentList *TemplateArgs) { + TemplateArgumentLists.push_back(ArgList(TemplateArgs->data(), + TemplateArgs->size())); + } + + /// \brief Add a new outmost level to the multi-level template argument + /// list. + void addOuterTemplateArguments(const TemplateArgument *Args, + unsigned NumArgs) { + TemplateArgumentLists.push_back(ArgList(Args, NumArgs)); + } + + /// \brief Retrieve the innermost template argument list. + const ArgList &getInnermost() const { + return TemplateArgumentLists.front(); + } + }; + + /// \brief The context in which partial ordering of function templates occurs. + enum TPOC { + /// \brief Partial ordering of function templates for a function call. + TPOC_Call, + /// \brief Partial ordering of function templates for a call to a + /// conversion function. + TPOC_Conversion, + /// \brief Partial ordering of function templates in other contexts, e.g., + /// taking the address of a function template or matching a function + /// template specialization to a function template. + TPOC_Other + }; + + // This is lame but unavoidable in a world without forward + // declarations of enums. The alternatives are to either pollute + // Sema.h (by including this file) or sacrifice type safety (by + // making Sema.h declare things as enums). + class TemplatePartialOrderingContext { + TPOC Value; + public: + TemplatePartialOrderingContext(TPOC Value) : Value(Value) {} + operator TPOC() const { return Value; } + }; + + /// \brief Captures a template argument whose value has been deduced + /// via c++ template argument deduction. + class DeducedTemplateArgument : public TemplateArgument { + /// \brief For a non-type template argument, whether the value was + /// deduced from an array bound. + bool DeducedFromArrayBound; + + public: + DeducedTemplateArgument() + : TemplateArgument(), DeducedFromArrayBound(false) { } + + DeducedTemplateArgument(const TemplateArgument &Arg, + bool DeducedFromArrayBound = false) + : TemplateArgument(Arg), DeducedFromArrayBound(DeducedFromArrayBound) { } + + /// \brief Construct an integral non-type template argument that + /// has been deduced, possibly from an array bound. + DeducedTemplateArgument(const llvm::APSInt &Value, + QualType ValueType, + bool DeducedFromArrayBound) + : TemplateArgument(Value, ValueType), + DeducedFromArrayBound(DeducedFromArrayBound) { } + + /// \brief For a non-type template argument, determine whether the + /// template argument was deduced from an array bound. + bool wasDeducedFromArrayBound() const { return DeducedFromArrayBound; } + + /// \brief Specify whether the given non-type template argument + /// was deduced from an array bound. + void setDeducedFromArrayBound(bool Deduced) { + DeducedFromArrayBound = Deduced; + } + }; + + /// \brief A stack-allocated class that identifies which local + /// variable declaration instantiations are present in this scope. + /// + /// A new instance of this class type will be created whenever we + /// instantiate a new function declaration, which will have its own + /// set of parameter declarations. + class LocalInstantiationScope { + public: + /// \brief A set of declarations. + typedef SmallVector<Decl *, 4> DeclArgumentPack; + + private: + /// \brief Reference to the semantic analysis that is performing + /// this template instantiation. + Sema &SemaRef; + + typedef llvm::DenseMap<const Decl *, + llvm::PointerUnion<Decl *, DeclArgumentPack *> > + LocalDeclsMap; + + /// \brief A mapping from local declarations that occur + /// within a template to their instantiations. + /// + /// This mapping is used during instantiation to keep track of, + /// e.g., function parameter and variable declarations. For example, + /// given: + /// + /// \code + /// template<typename T> T add(T x, T y) { return x + y; } + /// \endcode + /// + /// when we instantiate add<int>, we will introduce a mapping from + /// the ParmVarDecl for 'x' that occurs in the template to the + /// instantiated ParmVarDecl for 'x'. + /// + /// For a parameter pack, the local instantiation scope may contain a + /// set of instantiated parameters. This is stored as a DeclArgumentPack + /// pointer. + LocalDeclsMap LocalDecls; + + /// \brief The set of argument packs we've allocated. + SmallVector<DeclArgumentPack *, 1> ArgumentPacks; + + /// \brief The outer scope, which contains local variable + /// definitions from some other instantiation (that may not be + /// relevant to this particular scope). + LocalInstantiationScope *Outer; + + /// \brief Whether we have already exited this scope. + bool Exited; + + /// \brief Whether to combine this scope with the outer scope, such that + /// lookup will search our outer scope. + bool CombineWithOuterScope; + + /// \brief If non-NULL, the template parameter pack that has been + /// partially substituted per C++0x [temp.arg.explicit]p9. + NamedDecl *PartiallySubstitutedPack; + + /// \brief If \c PartiallySubstitutedPack is non-null, the set of + /// explicitly-specified template arguments in that pack. + const TemplateArgument *ArgsInPartiallySubstitutedPack; + + /// \brief If \c PartiallySubstitutedPack, the number of + /// explicitly-specified template arguments in + /// ArgsInPartiallySubstitutedPack. + unsigned NumArgsInPartiallySubstitutedPack; + + // This class is non-copyable + LocalInstantiationScope(const LocalInstantiationScope &); + LocalInstantiationScope &operator=(const LocalInstantiationScope &); + + public: + LocalInstantiationScope(Sema &SemaRef, bool CombineWithOuterScope = false) + : SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope), + Exited(false), CombineWithOuterScope(CombineWithOuterScope), + PartiallySubstitutedPack(0) + { + SemaRef.CurrentInstantiationScope = this; + } + + ~LocalInstantiationScope() { + Exit(); + } + + const Sema &getSema() const { return SemaRef; } + + /// \brief Exit this local instantiation scope early. + void Exit() { + if (Exited) + return; + + for (unsigned I = 0, N = ArgumentPacks.size(); I != N; ++I) + delete ArgumentPacks[I]; + + SemaRef.CurrentInstantiationScope = Outer; + Exited = true; + } + + /// \brief Clone this scope, and all outer scopes, down to the given + /// outermost scope. + LocalInstantiationScope *cloneScopes(LocalInstantiationScope *Outermost) { + if (this == Outermost) return this; + LocalInstantiationScope *newScope = + new LocalInstantiationScope(SemaRef, CombineWithOuterScope); + + newScope->Outer = 0; + if (Outer) + newScope->Outer = Outer->cloneScopes(Outermost); + + newScope->PartiallySubstitutedPack = PartiallySubstitutedPack; + newScope->ArgsInPartiallySubstitutedPack = ArgsInPartiallySubstitutedPack; + newScope->NumArgsInPartiallySubstitutedPack = + NumArgsInPartiallySubstitutedPack; + + for (LocalDeclsMap::iterator I = LocalDecls.begin(), E = LocalDecls.end(); + I != E; ++I) { + const Decl *D = I->first; + llvm::PointerUnion<Decl *, DeclArgumentPack *> &Stored = + newScope->LocalDecls[D]; + if (I->second.is<Decl *>()) { + Stored = I->second.get<Decl *>(); + } else { + DeclArgumentPack *OldPack = I->second.get<DeclArgumentPack *>(); + DeclArgumentPack *NewPack = new DeclArgumentPack(*OldPack); + Stored = NewPack; + newScope->ArgumentPacks.push_back(NewPack); + } + } + return newScope; + } + + /// \brief deletes the given scope, and all otuer scopes, down to the + /// given outermost scope. + static void deleteScopes(LocalInstantiationScope *Scope, + LocalInstantiationScope *Outermost) { + while (Scope && Scope != Outermost) { + LocalInstantiationScope *Out = Scope->Outer; + delete Scope; + Scope = Out; + } + } + + /// \brief Find the instantiation of the declaration D within the current + /// instantiation scope. + /// + /// \param D The declaration whose instantiation we are searching for. + /// + /// \returns A pointer to the declaration or argument pack of declarations + /// to which the declaration \c D is instantiataed, if found. Otherwise, + /// returns NULL. + llvm::PointerUnion<Decl *, DeclArgumentPack *> * + findInstantiationOf(const Decl *D); + + void InstantiatedLocal(const Decl *D, Decl *Inst); + void InstantiatedLocalPackArg(const Decl *D, Decl *Inst); + void MakeInstantiatedLocalArgPack(const Decl *D); + + /// \brief Note that the given parameter pack has been partially substituted + /// via explicit specification of template arguments + /// (C++0x [temp.arg.explicit]p9). + /// + /// \param Pack The parameter pack, which will always be a template + /// parameter pack. + /// + /// \param ExplicitArgs The explicitly-specified template arguments provided + /// for this parameter pack. + /// + /// \param NumExplicitArgs The number of explicitly-specified template + /// arguments provided for this parameter pack. + void SetPartiallySubstitutedPack(NamedDecl *Pack, + const TemplateArgument *ExplicitArgs, + unsigned NumExplicitArgs); + + /// \brief Retrieve the partially-substitued template parameter pack. + /// + /// If there is no partially-substituted parameter pack, returns NULL. + NamedDecl *getPartiallySubstitutedPack( + const TemplateArgument **ExplicitArgs = 0, + unsigned *NumExplicitArgs = 0) const; + }; + + class TemplateDeclInstantiator + : public DeclVisitor<TemplateDeclInstantiator, Decl *> + { + Sema &SemaRef; + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex; + DeclContext *Owner; + const MultiLevelTemplateArgumentList &TemplateArgs; + Sema::LateInstantiatedAttrVec* LateAttrs; + LocalInstantiationScope *StartingScope; + + /// \brief A list of out-of-line class template partial + /// specializations that will need to be instantiated after the + /// enclosing class's instantiation is complete. + SmallVector<std::pair<ClassTemplateDecl *, + ClassTemplatePartialSpecializationDecl *>, 4> + OutOfLinePartialSpecs; + + public: + TemplateDeclInstantiator(Sema &SemaRef, DeclContext *Owner, + const MultiLevelTemplateArgumentList &TemplateArgs) + : SemaRef(SemaRef), SubstIndex(SemaRef, -1), Owner(Owner), + TemplateArgs(TemplateArgs), LateAttrs(0), StartingScope(0) { } + + // FIXME: Once we get closer to completion, replace these manually-written + // declarations with automatically-generated ones from + // clang/AST/DeclNodes.inc. + Decl *VisitTranslationUnitDecl(TranslationUnitDecl *D); + Decl *VisitLabelDecl(LabelDecl *D); + Decl *VisitNamespaceDecl(NamespaceDecl *D); + Decl *VisitNamespaceAliasDecl(NamespaceAliasDecl *D); + Decl *VisitTypedefDecl(TypedefDecl *D); + Decl *VisitTypeAliasDecl(TypeAliasDecl *D); + Decl *VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D); + Decl *VisitVarDecl(VarDecl *D); + Decl *VisitAccessSpecDecl(AccessSpecDecl *D); + Decl *VisitFieldDecl(FieldDecl *D); + Decl *VisitIndirectFieldDecl(IndirectFieldDecl *D); + Decl *VisitStaticAssertDecl(StaticAssertDecl *D); + Decl *VisitEnumDecl(EnumDecl *D); + Decl *VisitEnumConstantDecl(EnumConstantDecl *D); + Decl *VisitFriendDecl(FriendDecl *D); + Decl *VisitFunctionDecl(FunctionDecl *D, + TemplateParameterList *TemplateParams = 0); + Decl *VisitCXXRecordDecl(CXXRecordDecl *D); + Decl *VisitCXXMethodDecl(CXXMethodDecl *D, + TemplateParameterList *TemplateParams = 0, + bool IsClassScopeSpecialization = false); + Decl *VisitCXXConstructorDecl(CXXConstructorDecl *D); + Decl *VisitCXXDestructorDecl(CXXDestructorDecl *D); + Decl *VisitCXXConversionDecl(CXXConversionDecl *D); + ParmVarDecl *VisitParmVarDecl(ParmVarDecl *D); + Decl *VisitClassTemplateDecl(ClassTemplateDecl *D); + Decl *VisitClassTemplatePartialSpecializationDecl( + ClassTemplatePartialSpecializationDecl *D); + Decl *VisitFunctionTemplateDecl(FunctionTemplateDecl *D); + Decl *VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D); + Decl *VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D); + Decl *VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D); + Decl *VisitUsingDirectiveDecl(UsingDirectiveDecl *D); + Decl *VisitUsingDecl(UsingDecl *D); + Decl *VisitUsingShadowDecl(UsingShadowDecl *D); + Decl *VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D); + Decl *VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D); + Decl *VisitClassScopeFunctionSpecializationDecl( + ClassScopeFunctionSpecializationDecl *D); + + // Base case. FIXME: Remove once we can instantiate everything. + Decl *VisitDecl(Decl *D) { + unsigned DiagID = SemaRef.getDiagnostics().getCustomDiagID( + DiagnosticsEngine::Error, + "cannot instantiate %0 yet"); + SemaRef.Diag(D->getLocation(), DiagID) + << D->getDeclKindName(); + + return 0; + } + + // Enable late instantiation of attributes. Late instantiated attributes + // will be stored in LA. + void enableLateAttributeInstantiation(Sema::LateInstantiatedAttrVec *LA) { + LateAttrs = LA; + StartingScope = SemaRef.CurrentInstantiationScope; + } + + // Disable late instantiation of attributes. + void disableLateAttributeInstantiation() { + LateAttrs = 0; + StartingScope = 0; + } + + LocalInstantiationScope *getStartingScope() const { return StartingScope; } + + typedef + SmallVectorImpl<std::pair<ClassTemplateDecl *, + ClassTemplatePartialSpecializationDecl *> > + ::iterator + delayed_partial_spec_iterator; + + /// \brief Return an iterator to the beginning of the set of + /// "delayed" partial specializations, which must be passed to + /// InstantiateClassTemplatePartialSpecialization once the class + /// definition has been completed. + delayed_partial_spec_iterator delayed_partial_spec_begin() { + return OutOfLinePartialSpecs.begin(); + } + + /// \brief Return an iterator to the end of the set of + /// "delayed" partial specializations, which must be passed to + /// InstantiateClassTemplatePartialSpecialization once the class + /// definition has been completed. + delayed_partial_spec_iterator delayed_partial_spec_end() { + return OutOfLinePartialSpecs.end(); + } + + // Helper functions for instantiating methods. + TypeSourceInfo *SubstFunctionType(FunctionDecl *D, + SmallVectorImpl<ParmVarDecl *> &Params); + bool InitFunctionInstantiation(FunctionDecl *New, FunctionDecl *Tmpl); + bool InitMethodInstantiation(CXXMethodDecl *New, CXXMethodDecl *Tmpl); + + TemplateParameterList * + SubstTemplateParams(TemplateParameterList *List); + + bool SubstQualifier(const DeclaratorDecl *OldDecl, + DeclaratorDecl *NewDecl); + bool SubstQualifier(const TagDecl *OldDecl, + TagDecl *NewDecl); + + Decl *InstantiateTypedefNameDecl(TypedefNameDecl *D, bool IsTypeAlias); + ClassTemplatePartialSpecializationDecl * + InstantiateClassTemplatePartialSpecialization( + ClassTemplateDecl *ClassTemplate, + ClassTemplatePartialSpecializationDecl *PartialSpec); + void InstantiateEnumDefinition(EnumDecl *Enum, EnumDecl *Pattern); + }; +} + +#endif // LLVM_CLANG_SEMA_TEMPLATE_H diff --git a/clang/include/clang/Sema/TemplateDeduction.h b/clang/include/clang/Sema/TemplateDeduction.h new file mode 100644 index 0000000..100d56e --- /dev/null +++ b/clang/include/clang/Sema/TemplateDeduction.h @@ -0,0 +1,135 @@ +//===- TemplateDeduction.h - C++ template argument deduction ----*- C++ -*-===/ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +//===----------------------------------------------------------------------===/ +// +// This file provides types used with Sema's template argument deduction +// routines. +// +//===----------------------------------------------------------------------===/ +#ifndef LLVM_CLANG_SEMA_TEMPLATE_DEDUCTION_H +#define LLVM_CLANG_SEMA_TEMPLATE_DEDUCTION_H + +#include "clang/Basic/PartialDiagnostic.h" +#include "clang/AST/DeclTemplate.h" +#include "llvm/ADT/SmallVector.h" + +namespace clang { + +class ASTContext; +class TemplateArgumentList; + +namespace sema { + +/// \brief Provides information about an attempted template argument +/// deduction, whose success or failure was described by a +/// TemplateDeductionResult value. +class TemplateDeductionInfo { + /// \brief The context in which the template arguments are stored. + ASTContext &Context; + + /// \brief The deduced template argument list. + /// + TemplateArgumentList *Deduced; + + /// \brief The source location at which template argument + /// deduction is occurring. + SourceLocation Loc; + + /// \brief Warnings (and follow-on notes) that were suppressed due to + /// SFINAE while performing template argument deduction. + SmallVector<PartialDiagnosticAt, 4> SuppressedDiagnostics; + + // do not implement these + TemplateDeductionInfo(const TemplateDeductionInfo&); + TemplateDeductionInfo &operator=(const TemplateDeductionInfo&); + +public: + TemplateDeductionInfo(ASTContext &Context, SourceLocation Loc) + : Context(Context), Deduced(0), Loc(Loc) { } + + ~TemplateDeductionInfo() { + // FIXME: if (Deduced) Deduced->Destroy(Context); + } + + /// \brief Returns the location at which template argument is + /// occurring. + SourceLocation getLocation() const { + return Loc; + } + + /// \brief Take ownership of the deduced template argument list. + TemplateArgumentList *take() { + TemplateArgumentList *Result = Deduced; + Deduced = 0; + return Result; + } + + /// \brief Provide a new template argument list that contains the + /// results of template argument deduction. + void reset(TemplateArgumentList *NewDeduced) { + // FIXME: if (Deduced) Deduced->Destroy(Context); + Deduced = NewDeduced; + } + + /// \brief Add a new diagnostic to the set of diagnostics + void addSuppressedDiagnostic(SourceLocation Loc, + const PartialDiagnostic &PD) { + SuppressedDiagnostics.push_back(std::make_pair(Loc, PD)); + } + + /// \brief Iterator over the set of suppressed diagnostics. + typedef SmallVectorImpl<PartialDiagnosticAt>::const_iterator + diag_iterator; + + /// \brief Returns an iterator at the beginning of the sequence of suppressed + /// diagnostics. + diag_iterator diag_begin() const { return SuppressedDiagnostics.begin(); } + + /// \brief Returns an iterator at the end of the sequence of suppressed + /// diagnostics. + diag_iterator diag_end() const { return SuppressedDiagnostics.end(); } + + /// \brief The template parameter to which a template argument + /// deduction failure refers. + /// + /// Depending on the result of template argument deduction, this + /// template parameter may have different meanings: + /// + /// TDK_Incomplete: this is the first template parameter whose + /// corresponding template argument was not deduced. + /// + /// TDK_Inconsistent: this is the template parameter for which + /// two different template argument values were deduced. + TemplateParameter Param; + + /// \brief The first template argument to which the template + /// argument deduction failure refers. + /// + /// Depending on the result of the template argument deduction, + /// this template argument may have different meanings: + /// + /// TDK_Inconsistent: this argument is the first value deduced + /// for the corresponding template parameter. + /// + /// TDK_SubstitutionFailure: this argument is the template + /// argument we were instantiating when we encountered an error. + /// + /// TDK_NonDeducedMismatch: this is the template argument + /// provided in the source code. + TemplateArgument FirstArg; + + /// \brief The second template argument to which the template + /// argument deduction failure refers. + /// + /// FIXME: Finish documenting this. + TemplateArgument SecondArg; +}; + +} +} + +#endif diff --git a/clang/include/clang/Sema/TypoCorrection.h b/clang/include/clang/Sema/TypoCorrection.h new file mode 100644 index 0000000..a8f6e11 --- /dev/null +++ b/clang/include/clang/Sema/TypoCorrection.h @@ -0,0 +1,256 @@ +//===--- TypoCorrection.h - Class for typo correction results ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the TypoCorrection class, which stores the results of +// Sema's typo correction (Sema::CorrectTypo). +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_TYPOCORRECTION_H +#define LLVM_CLANG_SEMA_TYPOCORRECTION_H + +#include "clang/AST/DeclCXX.h" +#include "llvm/ADT/SmallVector.h" + +namespace clang { + +/// @brief Simple class containing the result of Sema::CorrectTypo +class TypoCorrection { +public: + // "Distance" for unusable corrections + static const unsigned InvalidDistance = ~0U; + // The largest distance still considered valid (larger edit distances are + // mapped to InvalidDistance by getEditDistance). + static const unsigned MaximumDistance = 10000U; + + // Relative weightings of the "edit distance" components. The higher the + // weight, the more of a penalty to fitness the component will give (higher + // weights mean greater contribution to the total edit distance, with the + // best correction candidates having the lowest edit distance). + static const unsigned CharDistanceWeight = 100U; + static const unsigned QualifierDistanceWeight = 110U; + static const unsigned CallbackDistanceWeight = 150U; + + TypoCorrection(const DeclarationName &Name, NamedDecl *NameDecl, + NestedNameSpecifier *NNS=0, unsigned CharDistance=0, + unsigned QualifierDistance=0) + : CorrectionName(Name), CorrectionNameSpec(NNS), + CharDistance(CharDistance), QualifierDistance(QualifierDistance), + CallbackDistance(0) { + if (NameDecl) + CorrectionDecls.push_back(NameDecl); + } + + TypoCorrection(NamedDecl *Name, NestedNameSpecifier *NNS=0, + unsigned CharDistance=0) + : CorrectionName(Name->getDeclName()), CorrectionNameSpec(NNS), + CharDistance(CharDistance), QualifierDistance(0), CallbackDistance(0) { + if (Name) + CorrectionDecls.push_back(Name); + } + + TypoCorrection(DeclarationName Name, NestedNameSpecifier *NNS=0, + unsigned CharDistance=0) + : CorrectionName(Name), CorrectionNameSpec(NNS), + CharDistance(CharDistance), QualifierDistance(0), CallbackDistance(0) {} + + TypoCorrection() + : CorrectionNameSpec(0), CharDistance(0), QualifierDistance(0), + CallbackDistance(0) {} + + /// \brief Gets the DeclarationName of the typo correction + DeclarationName getCorrection() const { return CorrectionName; } + IdentifierInfo* getCorrectionAsIdentifierInfo() const { + return CorrectionName.getAsIdentifierInfo(); + } + + /// \brief Gets the NestedNameSpecifier needed to use the typo correction + NestedNameSpecifier* getCorrectionSpecifier() const { + return CorrectionNameSpec; + } + void setCorrectionSpecifier(NestedNameSpecifier* NNS) { + CorrectionNameSpec = NNS; + } + + void setQualifierDistance(unsigned ED) { + QualifierDistance = ED; + } + + void setCallbackDistance(unsigned ED) { + CallbackDistance = ED; + } + + // Convert the given weighted edit distance to a roughly equivalent number of + // single-character edits (typically for comparison to the length of the + // string being edited). + static unsigned NormalizeEditDistance(unsigned ED) { + if (ED > MaximumDistance) + return InvalidDistance; + return (ED + CharDistanceWeight / 2) / CharDistanceWeight; + } + + /// \brief Gets the "edit distance" of the typo correction from the typo. + /// If Normalized is true, scale the distance down by the CharDistanceWeight + /// to return the edit distance in terms of single-character edits. + unsigned getEditDistance(bool Normalized = true) const { + if (CharDistance > MaximumDistance || QualifierDistance > MaximumDistance || + CallbackDistance > MaximumDistance) + return InvalidDistance; + unsigned ED = + CharDistance * CharDistanceWeight + + QualifierDistance * QualifierDistanceWeight + + CallbackDistance * CallbackDistanceWeight; + if (ED > MaximumDistance) + return InvalidDistance; + // Half the CharDistanceWeight is added to ED to simulate rounding since + // integer division truncates the value (i.e. round-to-nearest-int instead + // of round-to-zero). + return Normalized ? NormalizeEditDistance(ED) : ED; + } + + /// \brief Gets the pointer to the declaration of the typo correction + NamedDecl* getCorrectionDecl() const { + return hasCorrectionDecl() ? *(CorrectionDecls.begin()) : 0; + } + template <class DeclClass> + DeclClass *getCorrectionDeclAs() const { + return dyn_cast_or_null<DeclClass>(getCorrectionDecl()); + } + + /// \brief Clears the list of NamedDecls before adding the new one. + void setCorrectionDecl(NamedDecl *CDecl) { + CorrectionDecls.clear(); + addCorrectionDecl(CDecl); + } + + /// \brief Add the given NamedDecl to the list of NamedDecls that are the + /// declarations associated with the DeclarationName of this TypoCorrection + void addCorrectionDecl(NamedDecl *CDecl); + + std::string getAsString(const LangOptions &LO) const; + std::string getQuoted(const LangOptions &LO) const { + return "'" + getAsString(LO) + "'"; + } + + /// \brief Returns whether this TypoCorrection has a non-empty DeclarationName + operator bool() const { return bool(CorrectionName); } + + /// \brief Mark this TypoCorrection as being a keyword. + /// Since addCorrectionDeclsand setCorrectionDecl don't allow NULL to be + /// added to the list of the correction's NamedDecl pointers, NULL is added + /// as the only element in the list to mark this TypoCorrection as a keyword. + void makeKeyword() { + CorrectionDecls.clear(); + CorrectionDecls.push_back(0); + } + + // Check if this TypoCorrection is a keyword by checking if the first + // item in CorrectionDecls is NULL. + bool isKeyword() const { + return !CorrectionDecls.empty() && + CorrectionDecls.front() == 0; + } + + // Check if this TypoCorrection is the given keyword. + template<std::size_t StrLen> + bool isKeyword(const char (&Str)[StrLen]) const { + return isKeyword() && getCorrectionAsIdentifierInfo()->isStr(Str); + } + + // Returns true if the correction either is a keyword or has a known decl. + bool isResolved() const { return !CorrectionDecls.empty(); } + + bool isOverloaded() const { + return CorrectionDecls.size() > 1; + } + + typedef llvm::SmallVector<NamedDecl*, 1>::iterator decl_iterator; + decl_iterator begin() { + return isKeyword() ? CorrectionDecls.end() : CorrectionDecls.begin(); + } + decl_iterator end() { return CorrectionDecls.end(); } + typedef llvm::SmallVector<NamedDecl*, 1>::const_iterator const_decl_iterator; + const_decl_iterator begin() const { + return isKeyword() ? CorrectionDecls.end() : CorrectionDecls.begin(); + } + const_decl_iterator end() const { return CorrectionDecls.end(); } + +private: + bool hasCorrectionDecl() const { + return (!isKeyword() && !CorrectionDecls.empty()); + } + + // Results. + DeclarationName CorrectionName; + NestedNameSpecifier *CorrectionNameSpec; + llvm::SmallVector<NamedDecl*, 1> CorrectionDecls; + unsigned CharDistance; + unsigned QualifierDistance; + unsigned CallbackDistance; +}; + +/// @brief Base class for callback objects used by Sema::CorrectTypo to check +/// the validity of a potential typo correction. +class CorrectionCandidateCallback { + public: + static const unsigned InvalidDistance = TypoCorrection::InvalidDistance; + + CorrectionCandidateCallback() + : WantTypeSpecifiers(true), WantExpressionKeywords(true), + WantCXXNamedCasts(true), WantRemainingKeywords(true), + WantObjCSuper(false), + IsObjCIvarLookup(false) {} + + virtual ~CorrectionCandidateCallback() {} + + /// \brief Simple predicate used by the default RankCandidate to + /// determine whether to return an edit distance of 0 or InvalidDistance. + /// This can be overrided by validators that only need to determine if a + /// candidate is viable, without ranking potentially viable candidates. + /// Only ValidateCandidate or RankCandidate need to be overriden by a + /// callback wishing to check the viability of correction candidates. + virtual bool ValidateCandidate(const TypoCorrection &candidate) { + return true; + } + + /// \brief Method used by Sema::CorrectTypo to assign an "edit distance" rank + /// to a candidate (where a lower value represents a better candidate), or + /// returning InvalidDistance if the candidate is not at all viable. For + /// validation callbacks that only need to determine if a candidate is viable, + /// the default RankCandidate returns either 0 or InvalidDistance depending + /// whether ValidateCandidate returns true or false. + virtual unsigned RankCandidate(const TypoCorrection &candidate) { + return ValidateCandidate(candidate) ? 0 : InvalidDistance; + } + + // Flags for context-dependent keywords. + // TODO: Expand these to apply to non-keywords or possibly remove them. + bool WantTypeSpecifiers; + bool WantExpressionKeywords; + bool WantCXXNamedCasts; + bool WantRemainingKeywords; + bool WantObjCSuper; + // Temporary hack for the one case where a CorrectTypoContext enum is used + // when looking up results. + bool IsObjCIvarLookup; +}; + +/// @brief Simple template class for restricting typo correction candidates +/// to ones having a single Decl* of the given type. +template <class C> +class DeclFilterCCC : public CorrectionCandidateCallback { + public: + virtual bool ValidateCandidate(const TypoCorrection &candidate) { + return candidate.getCorrectionDeclAs<C>(); + } +}; + +} + +#endif diff --git a/clang/include/clang/Sema/Weak.h b/clang/include/clang/Sema/Weak.h new file mode 100644 index 0000000..d36b970 --- /dev/null +++ b/clang/include/clang/Sema/Weak.h @@ -0,0 +1,46 @@ +//===-- UnresolvedSet.h - Unresolved sets of declarations ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the WeakInfo class, which is used to store +// information about the target of a #pragma weak directive. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_WEAK_H +#define LLVM_CLANG_SEMA_WEAK_H + +#include "clang/Basic/SourceLocation.h" + +namespace clang { + +class IdentifierInfo; + +/// \brief Captures information about a #pragma weak directive. +class WeakInfo { + IdentifierInfo *alias; // alias (optional) + SourceLocation loc; // for diagnostics + bool used; // identifier later declared? +public: + WeakInfo() + : alias(0), loc(SourceLocation()), used(false) {} + WeakInfo(IdentifierInfo *Alias, SourceLocation Loc) + : alias(Alias), loc(Loc), used(false) {} + inline IdentifierInfo * getAlias() const { return alias; } + inline SourceLocation getLocation() const { return loc; } + void setUsed(bool Used=true) { used = Used; } + inline bool getUsed() { return used; } + bool operator==(WeakInfo RHS) const { + return alias == RHS.getAlias() && loc == RHS.getLocation(); + } + bool operator!=(WeakInfo RHS) const { return !(*this == RHS); } +}; + +} // end namespace clang + +#endif // LLVM_CLANG_SEMA_WEAK_H diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h new file mode 100644 index 0000000..f9bb892 --- /dev/null +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -0,0 +1,1279 @@ +//===- ASTBitCodes.h - Enum values for the PCH bitcode format ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This header defines Bitcode enum values for Clang serialized AST files. +// +// The enum values defined in this file should be considered permanent. If +// new features are added, they should have values added at the end of the +// respective lists. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_FRONTEND_PCHBITCODES_H +#define LLVM_CLANG_FRONTEND_PCHBITCODES_H + +#include "clang/AST/Type.h" +#include "llvm/Bitcode/BitCodes.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/ADT/DenseMap.h" + +namespace clang { + namespace serialization { + /// \brief AST file major version number supported by this version of + /// Clang. + /// + /// Whenever the AST file format changes in a way that makes it + /// incompatible with previous versions (such that a reader + /// designed for the previous version could not support reading + /// the new version), this number should be increased. + /// + /// Version 4 of AST files also requires that the version control branch and + /// revision match exactly, since there is no backward compatibility of + /// AST files at this time. + const unsigned VERSION_MAJOR = 4; + + /// \brief AST file minor version number supported by this version of + /// Clang. + /// + /// Whenever the AST format changes in a way that is still + /// compatible with previous versions (such that a reader designed + /// for the previous version could still support reading the new + /// version by ignoring new kinds of subblocks), this number + /// should be increased. + const unsigned VERSION_MINOR = 0; + + /// \brief An ID number that refers to an identifier in an AST file. + /// + /// The ID numbers of identifiers are consecutive (in order of discovery) + /// and start at 1. 0 is reserved for NULL. + typedef uint32_t IdentifierID; + + /// \brief An ID number that refers to a declaration in an AST file. + /// + /// The ID numbers of declarations are consecutive (in order of + /// discovery), with values below NUM_PREDEF_DECL_IDS being reserved. + /// At the start of a chain of precompiled headers, declaration ID 1 is + /// used for the translation unit declaration. + typedef uint32_t DeclID; + + /// \brief a Decl::Kind/DeclID pair. + typedef std::pair<uint32_t, DeclID> KindDeclIDPair; + + // FIXME: Turn these into classes so we can have some type safety when + // we go from local ID to global and vice-versa. + typedef DeclID LocalDeclID; + typedef DeclID GlobalDeclID; + + /// \brief An ID number that refers to a type in an AST file. + /// + /// The ID of a type is partitioned into two parts: the lower + /// three bits are used to store the const/volatile/restrict + /// qualifiers (as with QualType) and the upper bits provide a + /// type index. The type index values are partitioned into two + /// sets. The values below NUM_PREDEF_TYPE_IDs are predefined type + /// IDs (based on the PREDEF_TYPE_*_ID constants), with 0 as a + /// placeholder for "no type". Values from NUM_PREDEF_TYPE_IDs are + /// other types that have serialized representations. + typedef uint32_t TypeID; + + /// \brief A type index; the type ID with the qualifier bits removed. + class TypeIdx { + uint32_t Idx; + public: + TypeIdx() : Idx(0) { } + explicit TypeIdx(uint32_t index) : Idx(index) { } + + uint32_t getIndex() const { return Idx; } + TypeID asTypeID(unsigned FastQuals) const { + if (Idx == uint32_t(-1)) + return TypeID(-1); + + return (Idx << Qualifiers::FastWidth) | FastQuals; + } + static TypeIdx fromTypeID(TypeID ID) { + if (ID == TypeID(-1)) + return TypeIdx(-1); + + return TypeIdx(ID >> Qualifiers::FastWidth); + } + }; + + /// A structure for putting "fast"-unqualified QualTypes into a + /// DenseMap. This uses the standard pointer hash function. + struct UnsafeQualTypeDenseMapInfo { + static inline bool isEqual(QualType A, QualType B) { return A == B; } + static inline QualType getEmptyKey() { + return QualType::getFromOpaquePtr((void*) 1); + } + static inline QualType getTombstoneKey() { + return QualType::getFromOpaquePtr((void*) 2); + } + static inline unsigned getHashValue(QualType T) { + assert(!T.getLocalFastQualifiers() && + "hash invalid for types with fast quals"); + uintptr_t v = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr()); + return (unsigned(v) >> 4) ^ (unsigned(v) >> 9); + } + }; + + /// \brief An ID number that refers to an identifier in an AST file. + typedef uint32_t IdentID; + + /// \brief The number of predefined identifier IDs. + const unsigned int NUM_PREDEF_IDENT_IDS = 1; + + /// \brief An ID number that refers to an ObjC selector in an AST file. + typedef uint32_t SelectorID; + + /// \brief The number of predefined selector IDs. + const unsigned int NUM_PREDEF_SELECTOR_IDS = 1; + + /// \brief An ID number that refers to a set of CXXBaseSpecifiers in an + /// AST file. + typedef uint32_t CXXBaseSpecifiersID; + + /// \brief An ID number that refers to an entity in the detailed + /// preprocessing record. + typedef uint32_t PreprocessedEntityID; + + /// \brief An ID number that refers to a submodule in a module file. + typedef uint32_t SubmoduleID; + + /// \brief The number of predefined submodule IDs. + const unsigned int NUM_PREDEF_SUBMODULE_IDS = 1; + + /// \brief Source range/offset of a preprocessed entity. + struct PPEntityOffset { + /// \brief Raw source location of beginning of range. + unsigned Begin; + /// \brief Raw source location of end of range. + unsigned End; + /// \brief Offset in the AST file. + uint32_t BitOffset; + + PPEntityOffset(SourceRange R, uint32_t BitOffset) + : Begin(R.getBegin().getRawEncoding()), + End(R.getEnd().getRawEncoding()), + BitOffset(BitOffset) { } + }; + + /// \brief Source range/offset of a preprocessed entity. + struct DeclOffset { + /// \brief Raw source location. + unsigned Loc; + /// \brief Offset in the AST file. + uint32_t BitOffset; + + DeclOffset() : Loc(0), BitOffset(0) { } + DeclOffset(SourceLocation Loc, uint32_t BitOffset) + : Loc(Loc.getRawEncoding()), + BitOffset(BitOffset) { } + void setLocation(SourceLocation L) { + Loc = L.getRawEncoding(); + } + }; + + /// \brief The number of predefined preprocessed entity IDs. + const unsigned int NUM_PREDEF_PP_ENTITY_IDS = 1; + + /// \brief Describes the various kinds of blocks that occur within + /// an AST file. + enum BlockIDs { + /// \brief The AST block, which acts as a container around the + /// full AST block. + AST_BLOCK_ID = llvm::bitc::FIRST_APPLICATION_BLOCKID, + + /// \brief The block containing information about the source + /// manager. + SOURCE_MANAGER_BLOCK_ID, + + /// \brief The block containing information about the + /// preprocessor. + PREPROCESSOR_BLOCK_ID, + + /// \brief The block containing the definitions of all of the + /// types and decls used within the AST file. + DECLTYPES_BLOCK_ID, + + /// \brief The block containing DECL_UPDATES records. + DECL_UPDATES_BLOCK_ID, + + /// \brief The block containing the detailed preprocessing record. + PREPROCESSOR_DETAIL_BLOCK_ID, + + /// \brief The block containing the submodule structure. + SUBMODULE_BLOCK_ID + }; + + /// \brief Record types that occur within the AST block itself. + enum ASTRecordTypes { + /// \brief Record code for the offsets of each type. + /// + /// The TYPE_OFFSET constant describes the record that occurs + /// within the AST block. The record itself is an array of offsets that + /// point into the declarations and types block (identified by + /// DECLTYPES_BLOCK_ID). The index into the array is based on the ID + /// of a type. For a given type ID @c T, the lower three bits of + /// @c T are its qualifiers (const, volatile, restrict), as in + /// the QualType class. The upper bits, after being shifted and + /// subtracting NUM_PREDEF_TYPE_IDS, are used to index into the + /// TYPE_OFFSET block to determine the offset of that type's + /// corresponding record within the DECLTYPES_BLOCK_ID block. + TYPE_OFFSET = 1, + + /// \brief Record code for the offsets of each decl. + /// + /// The DECL_OFFSET constant describes the record that occurs + /// within the block identified by DECL_OFFSETS_BLOCK_ID within + /// the AST block. The record itself is an array of offsets that + /// point into the declarations and types block (identified by + /// DECLTYPES_BLOCK_ID). The declaration ID is an index into this + /// record, after subtracting one to account for the use of + /// declaration ID 0 for a NULL declaration pointer. Index 0 is + /// reserved for the translation unit declaration. + DECL_OFFSET = 2, + + /// \brief Record code for the language options table. + /// + /// The record with this code contains the contents of the + /// LangOptions structure. We serialize the entire contents of + /// the structure, and let the reader decide which options are + /// actually important to check. + LANGUAGE_OPTIONS = 3, + + /// \brief AST file metadata, including the AST file version number + /// and the target triple used to build the AST file. + METADATA = 4, + + /// \brief Record code for the table of offsets of each + /// identifier ID. + /// + /// The offset table contains offsets into the blob stored in + /// the IDENTIFIER_TABLE record. Each offset points to the + /// NULL-terminated string that corresponds to that identifier. + IDENTIFIER_OFFSET = 5, + + /// \brief Record code for the identifier table. + /// + /// The identifier table is a simple blob that contains + /// NULL-terminated strings for all of the identifiers + /// referenced by the AST file. The IDENTIFIER_OFFSET table + /// contains the mapping from identifier IDs to the characters + /// in this blob. Note that the starting offsets of all of the + /// identifiers are odd, so that, when the identifier offset + /// table is loaded in, we can use the low bit to distinguish + /// between offsets (for unresolved identifier IDs) and + /// IdentifierInfo pointers (for already-resolved identifier + /// IDs). + IDENTIFIER_TABLE = 6, + + /// \brief Record code for the array of external definitions. + /// + /// The AST file contains a list of all of the unnamed external + /// definitions present within the parsed headers, stored as an + /// array of declaration IDs. These external definitions will be + /// reported to the AST consumer after the AST file has been + /// read, since their presence can affect the semantics of the + /// program (e.g., for code generation). + EXTERNAL_DEFINITIONS = 7, + + /// \brief Record code for the set of non-builtin, special + /// types. + /// + /// This record contains the type IDs for the various type nodes + /// that are constructed during semantic analysis (e.g., + /// __builtin_va_list). The SPECIAL_TYPE_* constants provide + /// offsets into this record. + SPECIAL_TYPES = 8, + + /// \brief Record code for the extra statistics we gather while + /// generating an AST file. + STATISTICS = 9, + + /// \brief Record code for the array of tentative definitions. + TENTATIVE_DEFINITIONS = 10, + + /// \brief Record code for the array of locally-scoped external + /// declarations. + LOCALLY_SCOPED_EXTERNAL_DECLS = 11, + + /// \brief Record code for the table of offsets into the + /// Objective-C method pool. + SELECTOR_OFFSETS = 12, + + /// \brief Record code for the Objective-C method pool, + METHOD_POOL = 13, + + /// \brief The value of the next __COUNTER__ to dispense. + /// [PP_COUNTER_VALUE, Val] + PP_COUNTER_VALUE = 14, + + /// \brief Record code for the table of offsets into the block + /// of source-location information. + SOURCE_LOCATION_OFFSETS = 15, + + /// \brief Record code for the set of source location entries + /// that need to be preloaded by the AST reader. + /// + /// This set contains the source location entry for the + /// predefines buffer and for any file entries that need to be + /// preloaded. + SOURCE_LOCATION_PRELOADS = 16, + + /// \brief Record code for the stat() cache. + STAT_CACHE = 17, + + /// \brief Record code for the set of ext_vector type names. + EXT_VECTOR_DECLS = 18, + + /// \brief Record code for the original file that was used to + /// generate the AST file. + ORIGINAL_FILE_NAME = 19, + + /// \brief Record code for the file ID of the original file used to + /// generate the AST file. + ORIGINAL_FILE_ID = 20, + + /// \brief Record code for the version control branch and revision + /// information of the compiler used to build this AST file. + VERSION_CONTROL_BRANCH_REVISION = 21, + + /// \brief Record code for the array of unused file scoped decls. + UNUSED_FILESCOPED_DECLS = 22, + + /// \brief Record code for the table of offsets to entries in the + /// preprocessing record. + PPD_ENTITIES_OFFSETS = 23, + + /// \brief Record code for the array of VTable uses. + VTABLE_USES = 24, + + /// \brief Record code for the array of dynamic classes. + DYNAMIC_CLASSES = 25, + + /// \brief Record code for the list of other AST files imported by + /// this AST file. + IMPORTS = 26, + + /// \brief Record code for referenced selector pool. + REFERENCED_SELECTOR_POOL = 27, + + /// \brief Record code for an update to the TU's lexically contained + /// declarations. + TU_UPDATE_LEXICAL = 28, + + /// \brief Record code for the array describing the locations (in the + /// LOCAL_REDECLARATIONS record) of the redeclaration chains, indexed by + /// the first known ID. + LOCAL_REDECLARATIONS_MAP = 29, + + /// \brief Record code for declarations that Sema keeps references of. + SEMA_DECL_REFS = 30, + + /// \brief Record code for weak undeclared identifiers. + WEAK_UNDECLARED_IDENTIFIERS = 31, + + /// \brief Record code for pending implicit instantiations. + PENDING_IMPLICIT_INSTANTIATIONS = 32, + + /// \brief Record code for a decl replacement block. + /// + /// If a declaration is modified after having been deserialized, and then + /// written to a dependent AST file, its ID and offset must be added to + /// the replacement block. + DECL_REPLACEMENTS = 33, + + /// \brief Record code for an update to a decl context's lookup table. + /// + /// In practice, this should only be used for the TU and namespaces. + UPDATE_VISIBLE = 34, + + /// \brief Record for offsets of DECL_UPDATES records for declarations + /// that were modified after being deserialized and need updates. + DECL_UPDATE_OFFSETS = 35, + + /// \brief Record of updates for a declaration that was modified after + /// being deserialized. + DECL_UPDATES = 36, + + /// \brief Record code for the table of offsets to CXXBaseSpecifier + /// sets. + CXX_BASE_SPECIFIER_OFFSETS = 37, + + /// \brief Record code for #pragma diagnostic mappings. + DIAG_PRAGMA_MAPPINGS = 38, + + /// \brief Record code for special CUDA declarations. + CUDA_SPECIAL_DECL_REFS = 39, + + /// \brief Record code for header search information. + HEADER_SEARCH_TABLE = 40, + + /// \brief The directory that the PCH was originally created in. + ORIGINAL_PCH_DIR = 41, + + /// \brief Record code for floating point #pragma options. + FP_PRAGMA_OPTIONS = 42, + + /// \brief Record code for enabled OpenCL extensions. + OPENCL_EXTENSIONS = 43, + + /// \brief The list of delegating constructor declarations. + DELEGATING_CTORS = 44, + + /// \brief Record code for the table of offsets into the block + /// of file source-location information. + FILE_SOURCE_LOCATION_OFFSETS = 45, + + /// \brief Record code for the set of known namespaces, which are used + /// for typo correction. + KNOWN_NAMESPACES = 46, + + /// \brief Record code for the remapping information used to relate + /// loaded modules to the various offsets and IDs(e.g., source location + /// offests, declaration and type IDs) that are used in that module to + /// refer to other modules. + MODULE_OFFSET_MAP = 47, + + /// \brief Record code for the source manager line table information, + /// which stores information about #line directives. + SOURCE_MANAGER_LINE_TABLE = 48, + + /// \brief Record code for map of Objective-C class definition IDs to the + /// ObjC categories in a module that are attached to that class. + OBJC_CATEGORIES_MAP = 49, + + /// \brief Record code for a file sorted array of DeclIDs in a module. + FILE_SORTED_DECLS = 50, + + /// \brief Record code for an array of all of the (sub)modules that were + /// imported by the AST file. + IMPORTED_MODULES = 51, + + /// \brief Record code for the set of merged declarations in an AST file. + MERGED_DECLARATIONS = 52, + + /// \brief Record code for the array of redeclaration chains. + /// + /// This array can only be interpreted properly using the local + /// redeclarations map. + LOCAL_REDECLARATIONS = 53, + + /// \brief Record code for the array of Objective-C categories (including + /// extensions). + /// + /// This array can only be interpreted properly using the Objective-C + /// categories map. + OBJC_CATEGORIES + }; + + /// \brief Record types used within a source manager block. + enum SourceManagerRecordTypes { + /// \brief Describes a source location entry (SLocEntry) for a + /// file. + SM_SLOC_FILE_ENTRY = 1, + /// \brief Describes a source location entry (SLocEntry) for a + /// buffer. + SM_SLOC_BUFFER_ENTRY = 2, + /// \brief Describes a blob that contains the data for a buffer + /// entry. This kind of record always directly follows a + /// SM_SLOC_BUFFER_ENTRY record or a SM_SLOC_FILE_ENTRY with an + /// overridden buffer. + SM_SLOC_BUFFER_BLOB = 3, + /// \brief Describes a source location entry (SLocEntry) for a + /// macro expansion. + SM_SLOC_EXPANSION_ENTRY = 4 + }; + + /// \brief Record types used within a preprocessor block. + enum PreprocessorRecordTypes { + // The macros in the PP section are a PP_MACRO_* instance followed by a + // list of PP_TOKEN instances for each token in the definition. + + /// \brief An object-like macro definition. + /// [PP_MACRO_OBJECT_LIKE, IdentInfoID, SLoc, IsUsed] + PP_MACRO_OBJECT_LIKE = 1, + + /// \brief A function-like macro definition. + /// [PP_MACRO_FUNCTION_LIKE, <ObjectLikeStuff>, IsC99Varargs, IsGNUVarars, + /// NumArgs, ArgIdentInfoID* ] + PP_MACRO_FUNCTION_LIKE = 2, + + /// \brief Describes one token. + /// [PP_TOKEN, SLoc, Length, IdentInfoID, Kind, Flags] + PP_TOKEN = 3 + }; + + /// \brief Record types used within a preprocessor detail block. + enum PreprocessorDetailRecordTypes { + /// \brief Describes a macro expansion within the preprocessing record. + PPD_MACRO_EXPANSION = 0, + + /// \brief Describes a macro definition within the preprocessing record. + PPD_MACRO_DEFINITION = 1, + + /// \brief Describes an inclusion directive within the preprocessing + /// record. + PPD_INCLUSION_DIRECTIVE = 2 + }; + + /// \brief Record types used within a submodule description block. + enum SubmoduleRecordTypes { + /// \brief Metadata for submodules as a whole. + SUBMODULE_METADATA = 0, + /// \brief Defines the major attributes of a submodule, including its + /// name and parent. + SUBMODULE_DEFINITION = 1, + /// \brief Specifies the umbrella header used to create this module, + /// if any. + SUBMODULE_UMBRELLA_HEADER = 2, + /// \brief Specifies a header that falls into this (sub)module. + SUBMODULE_HEADER = 3, + /// \brief Specifies an umbrella directory. + SUBMODULE_UMBRELLA_DIR = 4, + /// \brief Specifies the submodules that are imported by this + /// submodule. + SUBMODULE_IMPORTS = 5, + /// \brief Specifies the submodules that are re-exported from this + /// submodule. + SUBMODULE_EXPORTS = 6, + /// \brief Specifies a required feature. + SUBMODULE_REQUIRES = 7 + }; + + /// \defgroup ASTAST AST file AST constants + /// + /// The constants in this group describe various components of the + /// abstract syntax tree within an AST file. + /// + /// @{ + + /// \brief Predefined type IDs. + /// + /// These type IDs correspond to predefined types in the AST + /// context, such as built-in types (int) and special place-holder + /// types (the <overload> and <dependent> type markers). Such + /// types are never actually serialized, since they will be built + /// by the AST context when it is created. + enum PredefinedTypeIDs { + /// \brief The NULL type. + PREDEF_TYPE_NULL_ID = 0, + /// \brief The void type. + PREDEF_TYPE_VOID_ID = 1, + /// \brief The 'bool' or '_Bool' type. + PREDEF_TYPE_BOOL_ID = 2, + /// \brief The 'char' type, when it is unsigned. + PREDEF_TYPE_CHAR_U_ID = 3, + /// \brief The 'unsigned char' type. + PREDEF_TYPE_UCHAR_ID = 4, + /// \brief The 'unsigned short' type. + PREDEF_TYPE_USHORT_ID = 5, + /// \brief The 'unsigned int' type. + PREDEF_TYPE_UINT_ID = 6, + /// \brief The 'unsigned long' type. + PREDEF_TYPE_ULONG_ID = 7, + /// \brief The 'unsigned long long' type. + PREDEF_TYPE_ULONGLONG_ID = 8, + /// \brief The 'char' type, when it is signed. + PREDEF_TYPE_CHAR_S_ID = 9, + /// \brief The 'signed char' type. + PREDEF_TYPE_SCHAR_ID = 10, + /// \brief The C++ 'wchar_t' type. + PREDEF_TYPE_WCHAR_ID = 11, + /// \brief The (signed) 'short' type. + PREDEF_TYPE_SHORT_ID = 12, + /// \brief The (signed) 'int' type. + PREDEF_TYPE_INT_ID = 13, + /// \brief The (signed) 'long' type. + PREDEF_TYPE_LONG_ID = 14, + /// \brief The (signed) 'long long' type. + PREDEF_TYPE_LONGLONG_ID = 15, + /// \brief The 'float' type. + PREDEF_TYPE_FLOAT_ID = 16, + /// \brief The 'double' type. + PREDEF_TYPE_DOUBLE_ID = 17, + /// \brief The 'long double' type. + PREDEF_TYPE_LONGDOUBLE_ID = 18, + /// \brief The placeholder type for overloaded function sets. + PREDEF_TYPE_OVERLOAD_ID = 19, + /// \brief The placeholder type for dependent types. + PREDEF_TYPE_DEPENDENT_ID = 20, + /// \brief The '__uint128_t' type. + PREDEF_TYPE_UINT128_ID = 21, + /// \brief The '__int128_t' type. + PREDEF_TYPE_INT128_ID = 22, + /// \brief The type of 'nullptr'. + PREDEF_TYPE_NULLPTR_ID = 23, + /// \brief The C++ 'char16_t' type. + PREDEF_TYPE_CHAR16_ID = 24, + /// \brief The C++ 'char32_t' type. + PREDEF_TYPE_CHAR32_ID = 25, + /// \brief The ObjC 'id' type. + PREDEF_TYPE_OBJC_ID = 26, + /// \brief The ObjC 'Class' type. + PREDEF_TYPE_OBJC_CLASS = 27, + /// \brief The ObjC 'SEL' type. + PREDEF_TYPE_OBJC_SEL = 28, + /// \brief The 'unknown any' placeholder type. + PREDEF_TYPE_UNKNOWN_ANY = 29, + /// \brief The placeholder type for bound member functions. + PREDEF_TYPE_BOUND_MEMBER = 30, + /// \brief The "auto" deduction type. + PREDEF_TYPE_AUTO_DEDUCT = 31, + /// \brief The "auto &&" deduction type. + PREDEF_TYPE_AUTO_RREF_DEDUCT = 32, + /// \brief The OpenCL 'half' / ARM NEON __fp16 type. + PREDEF_TYPE_HALF_ID = 33, + /// \brief ARC's unbridged-cast placeholder type. + PREDEF_TYPE_ARC_UNBRIDGED_CAST = 34, + /// \brief The pseudo-object placeholder type. + PREDEF_TYPE_PSEUDO_OBJECT = 35 + }; + + /// \brief The number of predefined type IDs that are reserved for + /// the PREDEF_TYPE_* constants. + /// + /// Type IDs for non-predefined types will start at + /// NUM_PREDEF_TYPE_IDs. + const unsigned NUM_PREDEF_TYPE_IDS = 100; + + /// \brief The number of allowed abbreviations in bits + const unsigned NUM_ALLOWED_ABBREVS_SIZE = 4; + + /// \brief Record codes for each kind of type. + /// + /// These constants describe the type records that can occur within a + /// block identified by DECLTYPES_BLOCK_ID in the AST file. Each + /// constant describes a record for a specific type class in the + /// AST. + enum TypeCode { + /// \brief An ExtQualType record. + TYPE_EXT_QUAL = 1, + /// \brief A ComplexType record. + TYPE_COMPLEX = 3, + /// \brief A PointerType record. + TYPE_POINTER = 4, + /// \brief A BlockPointerType record. + TYPE_BLOCK_POINTER = 5, + /// \brief An LValueReferenceType record. + TYPE_LVALUE_REFERENCE = 6, + /// \brief An RValueReferenceType record. + TYPE_RVALUE_REFERENCE = 7, + /// \brief A MemberPointerType record. + TYPE_MEMBER_POINTER = 8, + /// \brief A ConstantArrayType record. + TYPE_CONSTANT_ARRAY = 9, + /// \brief An IncompleteArrayType record. + TYPE_INCOMPLETE_ARRAY = 10, + /// \brief A VariableArrayType record. + TYPE_VARIABLE_ARRAY = 11, + /// \brief A VectorType record. + TYPE_VECTOR = 12, + /// \brief An ExtVectorType record. + TYPE_EXT_VECTOR = 13, + /// \brief A FunctionNoProtoType record. + TYPE_FUNCTION_NO_PROTO = 14, + /// \brief A FunctionProtoType record. + TYPE_FUNCTION_PROTO = 15, + /// \brief A TypedefType record. + TYPE_TYPEDEF = 16, + /// \brief A TypeOfExprType record. + TYPE_TYPEOF_EXPR = 17, + /// \brief A TypeOfType record. + TYPE_TYPEOF = 18, + /// \brief A RecordType record. + TYPE_RECORD = 19, + /// \brief An EnumType record. + TYPE_ENUM = 20, + /// \brief An ObjCInterfaceType record. + TYPE_OBJC_INTERFACE = 21, + /// \brief An ObjCObjectPointerType record. + TYPE_OBJC_OBJECT_POINTER = 22, + /// \brief a DecltypeType record. + TYPE_DECLTYPE = 23, + /// \brief An ElaboratedType record. + TYPE_ELABORATED = 24, + /// \brief A SubstTemplateTypeParmType record. + TYPE_SUBST_TEMPLATE_TYPE_PARM = 25, + /// \brief An UnresolvedUsingType record. + TYPE_UNRESOLVED_USING = 26, + /// \brief An InjectedClassNameType record. + TYPE_INJECTED_CLASS_NAME = 27, + /// \brief An ObjCObjectType record. + TYPE_OBJC_OBJECT = 28, + /// \brief An TemplateTypeParmType record. + TYPE_TEMPLATE_TYPE_PARM = 29, + /// \brief An TemplateSpecializationType record. + TYPE_TEMPLATE_SPECIALIZATION = 30, + /// \brief A DependentNameType record. + TYPE_DEPENDENT_NAME = 31, + /// \brief A DependentTemplateSpecializationType record. + TYPE_DEPENDENT_TEMPLATE_SPECIALIZATION = 32, + /// \brief A DependentSizedArrayType record. + TYPE_DEPENDENT_SIZED_ARRAY = 33, + /// \brief A ParenType record. + TYPE_PAREN = 34, + /// \brief A PackExpansionType record. + TYPE_PACK_EXPANSION = 35, + /// \brief An AttributedType record. + TYPE_ATTRIBUTED = 36, + /// \brief A SubstTemplateTypeParmPackType record. + TYPE_SUBST_TEMPLATE_TYPE_PARM_PACK = 37, + /// \brief A AutoType record. + TYPE_AUTO = 38, + /// \brief A UnaryTransformType record. + TYPE_UNARY_TRANSFORM = 39, + /// \brief An AtomicType record. + TYPE_ATOMIC = 40 + }; + + /// \brief The type IDs for special types constructed by semantic + /// analysis. + /// + /// The constants in this enumeration are indices into the + /// SPECIAL_TYPES record. + enum SpecialTypeIDs { + /// \brief __builtin_va_list + SPECIAL_TYPE_BUILTIN_VA_LIST = 0, + /// \brief CFConstantString type + SPECIAL_TYPE_CF_CONSTANT_STRING = 1, + /// \brief C FILE typedef type + SPECIAL_TYPE_FILE = 2, + /// \brief C jmp_buf typedef type + SPECIAL_TYPE_JMP_BUF = 3, + /// \brief C sigjmp_buf typedef type + SPECIAL_TYPE_SIGJMP_BUF = 4, + /// \brief Objective-C "id" redefinition type + SPECIAL_TYPE_OBJC_ID_REDEFINITION = 5, + /// \brief Objective-C "Class" redefinition type + SPECIAL_TYPE_OBJC_CLASS_REDEFINITION = 6, + /// \brief Objective-C "SEL" redefinition type + SPECIAL_TYPE_OBJC_SEL_REDEFINITION = 7, + /// \brief C ucontext_t typedef type + SPECIAL_TYPE_UCONTEXT_T = 8 + }; + + /// \brief The number of special type IDs. + const unsigned NumSpecialTypeIDs = 9; + + /// \brief Predefined declaration IDs. + /// + /// These declaration IDs correspond to predefined declarations in the AST + /// context, such as the NULL declaration ID. Such declarations are never + /// actually serialized, since they will be built by the AST context when + /// it is created. + enum PredefinedDeclIDs { + /// \brief The NULL declaration. + PREDEF_DECL_NULL_ID = 0, + + /// \brief The translation unit. + PREDEF_DECL_TRANSLATION_UNIT_ID = 1, + + /// \brief The Objective-C 'id' type. + PREDEF_DECL_OBJC_ID_ID = 2, + + /// \brief The Objective-C 'SEL' type. + PREDEF_DECL_OBJC_SEL_ID = 3, + + /// \brief The Objective-C 'Class' type. + PREDEF_DECL_OBJC_CLASS_ID = 4, + + /// \brief The Objective-C 'Protocol' type. + PREDEF_DECL_OBJC_PROTOCOL_ID = 5, + + /// \brief The signed 128-bit integer type. + PREDEF_DECL_INT_128_ID = 6, + + /// \brief The unsigned 128-bit integer type. + PREDEF_DECL_UNSIGNED_INT_128_ID = 7, + + /// \brief The internal 'instancetype' typedef. + PREDEF_DECL_OBJC_INSTANCETYPE_ID = 8 + }; + + /// \brief The number of declaration IDs that are predefined. + /// + /// For more information about predefined declarations, see the + /// \c PredefinedDeclIDs type and the PREDEF_DECL_*_ID constants. + const unsigned int NUM_PREDEF_DECL_IDS = 9; + + /// \brief Record codes for each kind of declaration. + /// + /// These constants describe the declaration records that can occur within + /// a declarations block (identified by DECLS_BLOCK_ID). Each + /// constant describes a record for a specific declaration class + /// in the AST. + enum DeclCode { + /// \brief A TypedefDecl record. + DECL_TYPEDEF = 51, + /// \brief A TypeAliasDecl record. + DECL_TYPEALIAS, + /// \brief An EnumDecl record. + DECL_ENUM, + /// \brief A RecordDecl record. + DECL_RECORD, + /// \brief An EnumConstantDecl record. + DECL_ENUM_CONSTANT, + /// \brief A FunctionDecl record. + DECL_FUNCTION, + /// \brief A ObjCMethodDecl record. + DECL_OBJC_METHOD, + /// \brief A ObjCInterfaceDecl record. + DECL_OBJC_INTERFACE, + /// \brief A ObjCProtocolDecl record. + DECL_OBJC_PROTOCOL, + /// \brief A ObjCIvarDecl record. + DECL_OBJC_IVAR, + /// \brief A ObjCAtDefsFieldDecl record. + DECL_OBJC_AT_DEFS_FIELD, + /// \brief A ObjCCategoryDecl record. + DECL_OBJC_CATEGORY, + /// \brief A ObjCCategoryImplDecl record. + DECL_OBJC_CATEGORY_IMPL, + /// \brief A ObjCImplementationDecl record. + DECL_OBJC_IMPLEMENTATION, + /// \brief A ObjCCompatibleAliasDecl record. + DECL_OBJC_COMPATIBLE_ALIAS, + /// \brief A ObjCPropertyDecl record. + DECL_OBJC_PROPERTY, + /// \brief A ObjCPropertyImplDecl record. + DECL_OBJC_PROPERTY_IMPL, + /// \brief A FieldDecl record. + DECL_FIELD, + /// \brief A VarDecl record. + DECL_VAR, + /// \brief An ImplicitParamDecl record. + DECL_IMPLICIT_PARAM, + /// \brief A ParmVarDecl record. + DECL_PARM_VAR, + /// \brief A FileScopeAsmDecl record. + DECL_FILE_SCOPE_ASM, + /// \brief A BlockDecl record. + DECL_BLOCK, + /// \brief A record that stores the set of declarations that are + /// lexically stored within a given DeclContext. + /// + /// The record itself is a blob that is an array of declaration IDs, + /// in the order in which those declarations were added to the + /// declaration context. This data is used when iterating over + /// the contents of a DeclContext, e.g., via + /// DeclContext::decls_begin()/DeclContext::decls_end(). + DECL_CONTEXT_LEXICAL, + /// \brief A record that stores the set of declarations that are + /// visible from a given DeclContext. + /// + /// The record itself stores a set of mappings, each of which + /// associates a declaration name with one or more declaration + /// IDs. This data is used when performing qualified name lookup + /// into a DeclContext via DeclContext::lookup. + DECL_CONTEXT_VISIBLE, + /// \brief A LabelDecl record. + DECL_LABEL, + /// \brief A NamespaceDecl record. + DECL_NAMESPACE, + /// \brief A NamespaceAliasDecl record. + DECL_NAMESPACE_ALIAS, + /// \brief A UsingDecl record. + DECL_USING, + /// \brief A UsingShadowDecl record. + DECL_USING_SHADOW, + /// \brief A UsingDirecitveDecl record. + DECL_USING_DIRECTIVE, + /// \brief An UnresolvedUsingValueDecl record. + DECL_UNRESOLVED_USING_VALUE, + /// \brief An UnresolvedUsingTypenameDecl record. + DECL_UNRESOLVED_USING_TYPENAME, + /// \brief A LinkageSpecDecl record. + DECL_LINKAGE_SPEC, + /// \brief A CXXRecordDecl record. + DECL_CXX_RECORD, + /// \brief A CXXMethodDecl record. + DECL_CXX_METHOD, + /// \brief A CXXConstructorDecl record. + DECL_CXX_CONSTRUCTOR, + /// \brief A CXXDestructorDecl record. + DECL_CXX_DESTRUCTOR, + /// \brief A CXXConversionDecl record. + DECL_CXX_CONVERSION, + /// \brief An AccessSpecDecl record. + DECL_ACCESS_SPEC, + + /// \brief A FriendDecl record. + DECL_FRIEND, + /// \brief A FriendTemplateDecl record. + DECL_FRIEND_TEMPLATE, + /// \brief A ClassTemplateDecl record. + DECL_CLASS_TEMPLATE, + /// \brief A ClassTemplateSpecializationDecl record. + DECL_CLASS_TEMPLATE_SPECIALIZATION, + /// \brief A ClassTemplatePartialSpecializationDecl record. + DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION, + /// \brief A FunctionTemplateDecl record. + DECL_FUNCTION_TEMPLATE, + /// \brief A TemplateTypeParmDecl record. + DECL_TEMPLATE_TYPE_PARM, + /// \brief A NonTypeTemplateParmDecl record. + DECL_NON_TYPE_TEMPLATE_PARM, + /// \brief A TemplateTemplateParmDecl record. + DECL_TEMPLATE_TEMPLATE_PARM, + /// \brief A TypeAliasTemplateDecl record. + DECL_TYPE_ALIAS_TEMPLATE, + /// \brief A StaticAssertDecl record. + DECL_STATIC_ASSERT, + /// \brief A record containing CXXBaseSpecifiers. + DECL_CXX_BASE_SPECIFIERS, + /// \brief A IndirectFieldDecl record. + DECL_INDIRECTFIELD, + /// \brief A NonTypeTemplateParmDecl record that stores an expanded + /// non-type template parameter pack. + DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK, + /// \brief A ClassScopeFunctionSpecializationDecl record a class scope + /// function specialization. (Microsoft extension). + DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION, + /// \brief An ImportDecl recording a module import. + DECL_IMPORT + }; + + /// \brief Record codes for each kind of statement or expression. + /// + /// These constants describe the records that describe statements + /// or expressions. These records occur within type and declarations + /// block, so they begin with record values of 100. Each constant + /// describes a record for a specific statement or expression class in the + /// AST. + enum StmtCode { + /// \brief A marker record that indicates that we are at the end + /// of an expression. + STMT_STOP = 100, + /// \brief A NULL expression. + STMT_NULL_PTR, + /// \brief A reference to a previously [de]serialized Stmt record. + STMT_REF_PTR, + /// \brief A NullStmt record. + STMT_NULL, + /// \brief A CompoundStmt record. + STMT_COMPOUND, + /// \brief A CaseStmt record. + STMT_CASE, + /// \brief A DefaultStmt record. + STMT_DEFAULT, + /// \brief A LabelStmt record. + STMT_LABEL, + /// \brief An AttributedStmt record. + STMT_ATTRIBUTED, + /// \brief An IfStmt record. + STMT_IF, + /// \brief A SwitchStmt record. + STMT_SWITCH, + /// \brief A WhileStmt record. + STMT_WHILE, + /// \brief A DoStmt record. + STMT_DO, + /// \brief A ForStmt record. + STMT_FOR, + /// \brief A GotoStmt record. + STMT_GOTO, + /// \brief An IndirectGotoStmt record. + STMT_INDIRECT_GOTO, + /// \brief A ContinueStmt record. + STMT_CONTINUE, + /// \brief A BreakStmt record. + STMT_BREAK, + /// \brief A ReturnStmt record. + STMT_RETURN, + /// \brief A DeclStmt record. + STMT_DECL, + /// \brief An AsmStmt record. + STMT_ASM, + /// \brief A PredefinedExpr record. + EXPR_PREDEFINED, + /// \brief A DeclRefExpr record. + EXPR_DECL_REF, + /// \brief An IntegerLiteral record. + EXPR_INTEGER_LITERAL, + /// \brief A FloatingLiteral record. + EXPR_FLOATING_LITERAL, + /// \brief An ImaginaryLiteral record. + EXPR_IMAGINARY_LITERAL, + /// \brief A StringLiteral record. + EXPR_STRING_LITERAL, + /// \brief A CharacterLiteral record. + EXPR_CHARACTER_LITERAL, + /// \brief A ParenExpr record. + EXPR_PAREN, + /// \brief A ParenListExpr record. + EXPR_PAREN_LIST, + /// \brief A UnaryOperator record. + EXPR_UNARY_OPERATOR, + /// \brief An OffsetOfExpr record. + EXPR_OFFSETOF, + /// \brief A SizefAlignOfExpr record. + EXPR_SIZEOF_ALIGN_OF, + /// \brief An ArraySubscriptExpr record. + EXPR_ARRAY_SUBSCRIPT, + /// \brief A CallExpr record. + EXPR_CALL, + /// \brief A MemberExpr record. + EXPR_MEMBER, + /// \brief A BinaryOperator record. + EXPR_BINARY_OPERATOR, + /// \brief A CompoundAssignOperator record. + EXPR_COMPOUND_ASSIGN_OPERATOR, + /// \brief A ConditionOperator record. + EXPR_CONDITIONAL_OPERATOR, + /// \brief An ImplicitCastExpr record. + EXPR_IMPLICIT_CAST, + /// \brief A CStyleCastExpr record. + EXPR_CSTYLE_CAST, + /// \brief A CompoundLiteralExpr record. + EXPR_COMPOUND_LITERAL, + /// \brief An ExtVectorElementExpr record. + EXPR_EXT_VECTOR_ELEMENT, + /// \brief An InitListExpr record. + EXPR_INIT_LIST, + /// \brief A DesignatedInitExpr record. + EXPR_DESIGNATED_INIT, + /// \brief An ImplicitValueInitExpr record. + EXPR_IMPLICIT_VALUE_INIT, + /// \brief A VAArgExpr record. + EXPR_VA_ARG, + /// \brief An AddrLabelExpr record. + EXPR_ADDR_LABEL, + /// \brief A StmtExpr record. + EXPR_STMT, + /// \brief A ChooseExpr record. + EXPR_CHOOSE, + /// \brief A GNUNullExpr record. + EXPR_GNU_NULL, + /// \brief A ShuffleVectorExpr record. + EXPR_SHUFFLE_VECTOR, + /// \brief BlockExpr + EXPR_BLOCK, + /// \brief A GenericSelectionExpr record. + EXPR_GENERIC_SELECTION, + /// \brief A PseudoObjectExpr record. + EXPR_PSEUDO_OBJECT, + /// \brief An AtomicExpr record. + EXPR_ATOMIC, + + // Objective-C + + /// \brief An ObjCStringLiteral record. + EXPR_OBJC_STRING_LITERAL, + + EXPR_OBJC_NUMERIC_LITERAL, + EXPR_OBJC_ARRAY_LITERAL, + EXPR_OBJC_DICTIONARY_LITERAL, + + + /// \brief An ObjCEncodeExpr record. + EXPR_OBJC_ENCODE, + /// \brief An ObjCSelectorExpr record. + EXPR_OBJC_SELECTOR_EXPR, + /// \brief An ObjCProtocolExpr record. + EXPR_OBJC_PROTOCOL_EXPR, + /// \brief An ObjCIvarRefExpr record. + EXPR_OBJC_IVAR_REF_EXPR, + /// \brief An ObjCPropertyRefExpr record. + EXPR_OBJC_PROPERTY_REF_EXPR, + /// \brief An ObjCSubscriptRefExpr record. + EXPR_OBJC_SUBSCRIPT_REF_EXPR, + /// \brief UNUSED + EXPR_OBJC_KVC_REF_EXPR, + /// \brief An ObjCMessageExpr record. + EXPR_OBJC_MESSAGE_EXPR, + /// \brief An ObjCIsa Expr record. + EXPR_OBJC_ISA, + /// \breif An ObjCIndirectCopyRestoreExpr record. + EXPR_OBJC_INDIRECT_COPY_RESTORE, + + /// \brief An ObjCForCollectionStmt record. + STMT_OBJC_FOR_COLLECTION, + /// \brief An ObjCAtCatchStmt record. + STMT_OBJC_CATCH, + /// \brief An ObjCAtFinallyStmt record. + STMT_OBJC_FINALLY, + /// \brief An ObjCAtTryStmt record. + STMT_OBJC_AT_TRY, + /// \brief An ObjCAtSynchronizedStmt record. + STMT_OBJC_AT_SYNCHRONIZED, + /// \brief An ObjCAtThrowStmt record. + STMT_OBJC_AT_THROW, + /// \brief An ObjCAutoreleasePoolStmt record. + STMT_OBJC_AUTORELEASE_POOL, + /// \brief A ObjCBoolLiteralExpr record. + EXPR_OBJC_BOOL_LITERAL, + + // C++ + + /// \brief A CXXCatchStmt record. + STMT_CXX_CATCH, + /// \brief A CXXTryStmt record. + STMT_CXX_TRY, + /// \brief A CXXForRangeStmt record. + STMT_CXX_FOR_RANGE, + + /// \brief A CXXOperatorCallExpr record. + EXPR_CXX_OPERATOR_CALL, + /// \brief A CXXMemberCallExpr record. + EXPR_CXX_MEMBER_CALL, + /// \brief A CXXConstructExpr record. + EXPR_CXX_CONSTRUCT, + /// \brief A CXXTemporaryObjectExpr record. + EXPR_CXX_TEMPORARY_OBJECT, + /// \brief A CXXStaticCastExpr record. + EXPR_CXX_STATIC_CAST, + /// \brief A CXXDynamicCastExpr record. + EXPR_CXX_DYNAMIC_CAST, + /// \brief A CXXReinterpretCastExpr record. + EXPR_CXX_REINTERPRET_CAST, + /// \brief A CXXConstCastExpr record. + EXPR_CXX_CONST_CAST, + /// \brief A CXXFunctionalCastExpr record. + EXPR_CXX_FUNCTIONAL_CAST, + /// \brief A UserDefinedLiteral record. + EXPR_USER_DEFINED_LITERAL, + /// \brief A CXXBoolLiteralExpr record. + EXPR_CXX_BOOL_LITERAL, + EXPR_CXX_NULL_PTR_LITERAL, // CXXNullPtrLiteralExpr + EXPR_CXX_TYPEID_EXPR, // CXXTypeidExpr (of expr). + EXPR_CXX_TYPEID_TYPE, // CXXTypeidExpr (of type). + EXPR_CXX_THIS, // CXXThisExpr + EXPR_CXX_THROW, // CXXThrowExpr + EXPR_CXX_DEFAULT_ARG, // CXXDefaultArgExpr + EXPR_CXX_BIND_TEMPORARY, // CXXBindTemporaryExpr + + EXPR_CXX_SCALAR_VALUE_INIT, // CXXScalarValueInitExpr + EXPR_CXX_NEW, // CXXNewExpr + EXPR_CXX_DELETE, // CXXDeleteExpr + EXPR_CXX_PSEUDO_DESTRUCTOR, // CXXPseudoDestructorExpr + + EXPR_EXPR_WITH_CLEANUPS, // ExprWithCleanups + + EXPR_CXX_DEPENDENT_SCOPE_MEMBER, // CXXDependentScopeMemberExpr + EXPR_CXX_DEPENDENT_SCOPE_DECL_REF, // DependentScopeDeclRefExpr + EXPR_CXX_UNRESOLVED_CONSTRUCT, // CXXUnresolvedConstructExpr + EXPR_CXX_UNRESOLVED_MEMBER, // UnresolvedMemberExpr + EXPR_CXX_UNRESOLVED_LOOKUP, // UnresolvedLookupExpr + + EXPR_CXX_UNARY_TYPE_TRAIT, // UnaryTypeTraitExpr + EXPR_CXX_EXPRESSION_TRAIT, // ExpressionTraitExpr + EXPR_CXX_NOEXCEPT, // CXXNoexceptExpr + + EXPR_OPAQUE_VALUE, // OpaqueValueExpr + EXPR_BINARY_CONDITIONAL_OPERATOR, // BinaryConditionalOperator + EXPR_BINARY_TYPE_TRAIT, // BinaryTypeTraitExpr + EXPR_TYPE_TRAIT, // TypeTraitExpr + EXPR_ARRAY_TYPE_TRAIT, // ArrayTypeTraitIntExpr + + EXPR_PACK_EXPANSION, // PackExpansionExpr + EXPR_SIZEOF_PACK, // SizeOfPackExpr + EXPR_SUBST_NON_TYPE_TEMPLATE_PARM, // SubstNonTypeTemplateParmExpr + EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK,// SubstNonTypeTemplateParmPackExpr + EXPR_MATERIALIZE_TEMPORARY, // MaterializeTemporaryExpr + + // CUDA + EXPR_CUDA_KERNEL_CALL, // CUDAKernelCallExpr + + // OpenCL + EXPR_ASTYPE, // AsTypeExpr + + // Microsoft + EXPR_CXX_UUIDOF_EXPR, // CXXUuidofExpr (of expr). + EXPR_CXX_UUIDOF_TYPE, // CXXUuidofExpr (of type). + STMT_SEH_EXCEPT, // SEHExceptStmt + STMT_SEH_FINALLY, // SEHFinallyStmt + STMT_SEH_TRY, // SEHTryStmt + + // ARC + EXPR_OBJC_BRIDGED_CAST, // ObjCBridgedCastExpr + + STMT_MS_DEPENDENT_EXISTS, // MSDependentExistsStmt + EXPR_LAMBDA // LambdaExpr + }; + + /// \brief The kinds of designators that can occur in a + /// DesignatedInitExpr. + enum DesignatorTypes { + /// \brief Field designator where only the field name is known. + DESIG_FIELD_NAME = 0, + /// \brief Field designator where the field has been resolved to + /// a declaration. + DESIG_FIELD_DECL = 1, + /// \brief Array designator. + DESIG_ARRAY = 2, + /// \brief GNU array range designator. + DESIG_ARRAY_RANGE = 3 + }; + + /// \brief The different kinds of data that can occur in a + /// CtorInitializer. + enum CtorInitializerType { + CTOR_INITIALIZER_BASE, + CTOR_INITIALIZER_DELEGATING, + CTOR_INITIALIZER_MEMBER, + CTOR_INITIALIZER_INDIRECT_MEMBER + }; + + /// \brief Describes the redeclarations of a declaration. + struct LocalRedeclarationsInfo { + DeclID FirstID; // The ID of the first declaration + unsigned Offset; // Offset into the array of redeclaration chains. + + friend bool operator<(const LocalRedeclarationsInfo &X, + const LocalRedeclarationsInfo &Y) { + return X.FirstID < Y.FirstID; + } + + friend bool operator>(const LocalRedeclarationsInfo &X, + const LocalRedeclarationsInfo &Y) { + return X.FirstID > Y.FirstID; + } + + friend bool operator<=(const LocalRedeclarationsInfo &X, + const LocalRedeclarationsInfo &Y) { + return X.FirstID <= Y.FirstID; + } + + friend bool operator>=(const LocalRedeclarationsInfo &X, + const LocalRedeclarationsInfo &Y) { + return X.FirstID >= Y.FirstID; + } + }; + + /// \brief Describes the categories of an Objective-C class. + struct ObjCCategoriesInfo { + DeclID DefinitionID; // The ID of the definition + unsigned Offset; // Offset into the array of category lists. + + friend bool operator<(const ObjCCategoriesInfo &X, + const ObjCCategoriesInfo &Y) { + return X.DefinitionID < Y.DefinitionID; + } + + friend bool operator>(const ObjCCategoriesInfo &X, + const ObjCCategoriesInfo &Y) { + return X.DefinitionID > Y.DefinitionID; + } + + friend bool operator<=(const ObjCCategoriesInfo &X, + const ObjCCategoriesInfo &Y) { + return X.DefinitionID <= Y.DefinitionID; + } + + friend bool operator>=(const ObjCCategoriesInfo &X, + const ObjCCategoriesInfo &Y) { + return X.DefinitionID >= Y.DefinitionID; + } + }; + + /// @} + } +} // end namespace clang + +#endif diff --git a/clang/include/clang/Serialization/ASTDeserializationListener.h b/clang/include/clang/Serialization/ASTDeserializationListener.h new file mode 100644 index 0000000..ab0d313 --- /dev/null +++ b/clang/include/clang/Serialization/ASTDeserializationListener.h @@ -0,0 +1,60 @@ +//===- ASTDeserializationListener.h - Decl/Type PCH Read Events -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ASTDeserializationListener class, which is notified +// by the ASTReader whenever a type or declaration is deserialized. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_AST_DESERIALIZATION_LISTENER_H +#define LLVM_CLANG_FRONTEND_AST_DESERIALIZATION_LISTENER_H + +#include "clang/Serialization/ASTBitCodes.h" + +namespace clang { + +class Decl; +class ASTReader; +class QualType; +class MacroDefinition; +class Module; + +class ASTDeserializationListener { +protected: + virtual ~ASTDeserializationListener(); + +public: + + /// \brief The ASTReader was initialized. + virtual void ReaderInitialized(ASTReader *Reader) { } + + /// \brief An identifier was deserialized from the AST file. + virtual void IdentifierRead(serialization::IdentID ID, + IdentifierInfo *II) { } + /// \brief A type was deserialized from the AST file. The ID here has the + /// qualifier bits already removed, and T is guaranteed to be locally + /// unqualified. + virtual void TypeRead(serialization::TypeIdx Idx, QualType T) { } + /// \brief A decl was deserialized from the AST file. + virtual void DeclRead(serialization::DeclID ID, const Decl *D) { } + /// \brief A selector was read from the AST file. + virtual void SelectorRead(serialization::SelectorID iD, Selector Sel) { } + /// \brief A macro definition was read from the AST file. + virtual void MacroDefinitionRead(serialization::PreprocessedEntityID, + MacroDefinition *MD) { } + /// \brief A macro definition that had previously been deserialized + /// (and removed via IdentifierRead) has now been made visible. + virtual void MacroVisible(IdentifierInfo *II) { } + /// \brief A module definition was read from the AST file. + virtual void ModuleRead(serialization::SubmoduleID ID, Module *Mod) { } +}; + +} + +#endif diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h new file mode 100644 index 0000000..a9d0fc3 --- /dev/null +++ b/clang/include/clang/Serialization/ASTReader.h @@ -0,0 +1,1524 @@ +//===--- ASTReader.h - AST File Reader --------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ASTReader class, which reads AST files. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_AST_READER_H +#define LLVM_CLANG_FRONTEND_AST_READER_H + +#include "clang/Serialization/ASTBitCodes.h" +#include "clang/Serialization/ContinuousRangeMap.h" +#include "clang/Serialization/Module.h" +#include "clang/Serialization/ModuleManager.h" +#include "clang/Sema/ExternalSemaSource.h" +#include "clang/AST/DeclarationName.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/TemplateBase.h" +#include "clang/Lex/ExternalPreprocessorSource.h" +#include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/PreprocessingRecord.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/FileSystemOptions.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/SourceManager.h" +#include "llvm/ADT/APFloat.h" +#include "llvm/ADT/APInt.h" +#include "llvm/ADT/APSInt.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/Bitcode/BitstreamReader.h" +#include "llvm/Support/DataTypes.h" +#include <deque> +#include <map> +#include <string> +#include <utility> +#include <vector> + +namespace llvm { + class MemoryBuffer; +} + +namespace clang { + +class AddrLabelExpr; +class ASTConsumer; +class ASTContext; +class ASTIdentifierIterator; +class ASTUnit; // FIXME: Layering violation and egregious hack. +class Attr; +class Decl; +class DeclContext; +class NestedNameSpecifier; +class CXXBaseSpecifier; +class CXXConstructorDecl; +class CXXCtorInitializer; +class GotoStmt; +class MacroDefinition; +class NamedDecl; +class OpaqueValueExpr; +class Preprocessor; +class Sema; +class SwitchCase; +class ASTDeserializationListener; +class ASTWriter; +class ASTReader; +class ASTDeclReader; +class ASTStmtReader; +class TypeLocReader; +struct HeaderFileInfo; +class VersionTuple; + +struct PCHPredefinesBlock { + /// \brief The file ID for this predefines buffer in a PCH file. + FileID BufferID; + + /// \brief This predefines buffer in a PCH file. + StringRef Data; +}; +typedef SmallVector<PCHPredefinesBlock, 2> PCHPredefinesBlocks; + +/// \brief Abstract interface for callback invocations by the ASTReader. +/// +/// While reading an AST file, the ASTReader will call the methods of the +/// listener to pass on specific information. Some of the listener methods can +/// return true to indicate to the ASTReader that the information (and +/// consequently the AST file) is invalid. +class ASTReaderListener { +public: + virtual ~ASTReaderListener(); + + /// \brief Receives the language options. + /// + /// \returns true to indicate the options are invalid or false otherwise. + virtual bool ReadLanguageOptions(const LangOptions &LangOpts) { + return false; + } + + /// \brief Receives the target triple. + /// + /// \returns true to indicate the target triple is invalid or false otherwise. + virtual bool ReadTargetTriple(StringRef Triple) { + return false; + } + + /// \brief Receives the contents of the predefines buffer. + /// + /// \param Buffers Information about the predefines buffers. + /// + /// \param OriginalFileName The original file name for the AST file, which + /// will appear as an entry in the predefines buffer. + /// + /// \param SuggestedPredefines If necessary, additional definitions are added + /// here. + /// + /// \returns true to indicate the predefines are invalid or false otherwise. + virtual bool ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers, + StringRef OriginalFileName, + std::string &SuggestedPredefines, + FileManager &FileMgr) { + return false; + } + + /// \brief Receives a HeaderFileInfo entry. + virtual void ReadHeaderFileInfo(const HeaderFileInfo &HFI, unsigned ID) {} + + /// \brief Receives __COUNTER__ value. + virtual void ReadCounter(unsigned Value) {} +}; + +/// \brief ASTReaderListener implementation to validate the information of +/// the PCH file against an initialized Preprocessor. +class PCHValidator : public ASTReaderListener { + Preprocessor &PP; + ASTReader &Reader; + + unsigned NumHeaderInfos; + +public: + PCHValidator(Preprocessor &PP, ASTReader &Reader) + : PP(PP), Reader(Reader), NumHeaderInfos(0) {} + + virtual bool ReadLanguageOptions(const LangOptions &LangOpts); + virtual bool ReadTargetTriple(StringRef Triple); + virtual bool ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers, + StringRef OriginalFileName, + std::string &SuggestedPredefines, + FileManager &FileMgr); + virtual void ReadHeaderFileInfo(const HeaderFileInfo &HFI, unsigned ID); + virtual void ReadCounter(unsigned Value); + +private: + void Error(const char *Msg); +}; + +namespace serialization { + +class ReadMethodPoolVisitor; + +namespace reader { + class ASTIdentifierLookupTrait; + /// \brief The on-disk hash table used for the DeclContext's Name lookup table. + typedef OnDiskChainedHashTable<ASTDeclContextNameLookupTrait> + ASTDeclContextNameLookupTable; +} + +} // end namespace serialization + +/// \brief Reads an AST files chain containing the contents of a translation +/// unit. +/// +/// The ASTReader class reads bitstreams (produced by the ASTWriter +/// class) containing the serialized representation of a given +/// abstract syntax tree and its supporting data structures. An +/// instance of the ASTReader can be attached to an ASTContext object, +/// which will provide access to the contents of the AST files. +/// +/// The AST reader provides lazy de-serialization of declarations, as +/// required when traversing the AST. Only those AST nodes that are +/// actually required will be de-serialized. +class ASTReader + : public ExternalPreprocessorSource, + public ExternalPreprocessingRecordSource, + public ExternalHeaderFileInfoSource, + public ExternalSemaSource, + public IdentifierInfoLookup, + public ExternalIdentifierLookup, + public ExternalSLocEntrySource +{ +public: + enum ASTReadResult { Success, Failure, IgnorePCH }; + /// \brief Types of AST files. + friend class PCHValidator; + friend class ASTDeclReader; + friend class ASTStmtReader; + friend class ASTIdentifierIterator; + friend class serialization::reader::ASTIdentifierLookupTrait; + friend class TypeLocReader; + friend class ASTWriter; + friend class ASTUnit; // ASTUnit needs to remap source locations. + friend class serialization::ReadMethodPoolVisitor; + + typedef serialization::ModuleFile ModuleFile; + typedef serialization::ModuleKind ModuleKind; + typedef serialization::ModuleManager ModuleManager; + + typedef ModuleManager::ModuleIterator ModuleIterator; + typedef ModuleManager::ModuleConstIterator ModuleConstIterator; + typedef ModuleManager::ModuleReverseIterator ModuleReverseIterator; + +private: + /// \brief The receiver of some callbacks invoked by ASTReader. + OwningPtr<ASTReaderListener> Listener; + + /// \brief The receiver of deserialization events. + ASTDeserializationListener *DeserializationListener; + + SourceManager &SourceMgr; + FileManager &FileMgr; + DiagnosticsEngine &Diags; + + /// \brief The semantic analysis object that will be processing the + /// AST files and the translation unit that uses it. + Sema *SemaObj; + + /// \brief The preprocessor that will be loading the source file. + Preprocessor &PP; + + /// \brief The AST context into which we'll read the AST files. + ASTContext &Context; + + /// \brief The AST consumer. + ASTConsumer *Consumer; + + /// \brief The module manager which manages modules and their dependencies + ModuleManager ModuleMgr; + + /// \brief A map of global bit offsets to the module that stores entities + /// at those bit offsets. + ContinuousRangeMap<uint64_t, ModuleFile*, 4> GlobalBitOffsetsMap; + + /// \brief A map of negated SLocEntryIDs to the modules containing them. + ContinuousRangeMap<unsigned, ModuleFile*, 64> GlobalSLocEntryMap; + + typedef ContinuousRangeMap<unsigned, ModuleFile*, 64> GlobalSLocOffsetMapType; + + /// \brief A map of reversed (SourceManager::MaxLoadedOffset - SLocOffset) + /// SourceLocation offsets to the modules containing them. + GlobalSLocOffsetMapType GlobalSLocOffsetMap; + + /// \brief Types that have already been loaded from the chain. + /// + /// When the pointer at index I is non-NULL, the type with + /// ID = (I + 1) << FastQual::Width has already been loaded + std::vector<QualType> TypesLoaded; + + typedef ContinuousRangeMap<serialization::TypeID, ModuleFile *, 4> + GlobalTypeMapType; + + /// \brief Mapping from global type IDs to the module in which the + /// type resides along with the offset that should be added to the + /// global type ID to produce a local ID. + GlobalTypeMapType GlobalTypeMap; + + /// \brief Declarations that have already been loaded from the chain. + /// + /// When the pointer at index I is non-NULL, the declaration with ID + /// = I + 1 has already been loaded. + std::vector<Decl *> DeclsLoaded; + + typedef ContinuousRangeMap<serialization::DeclID, ModuleFile *, 4> + GlobalDeclMapType; + + /// \brief Mapping from global declaration IDs to the module in which the + /// declaration resides. + GlobalDeclMapType GlobalDeclMap; + + typedef std::pair<ModuleFile *, uint64_t> FileOffset; + typedef SmallVector<FileOffset, 2> FileOffsetsTy; + typedef llvm::DenseMap<serialization::DeclID, FileOffsetsTy> + DeclUpdateOffsetsMap; + + /// \brief Declarations that have modifications residing in a later file + /// in the chain. + DeclUpdateOffsetsMap DeclUpdateOffsets; + + struct ReplacedDeclInfo { + ModuleFile *Mod; + uint64_t Offset; + unsigned RawLoc; + + ReplacedDeclInfo() : Mod(0), Offset(0), RawLoc(0) {} + ReplacedDeclInfo(ModuleFile *Mod, uint64_t Offset, unsigned RawLoc) + : Mod(Mod), Offset(Offset), RawLoc(RawLoc) {} + }; + + typedef llvm::DenseMap<serialization::DeclID, ReplacedDeclInfo> + DeclReplacementMap; + /// \brief Declarations that have been replaced in a later file in the chain. + DeclReplacementMap ReplacedDecls; + + struct FileDeclsInfo { + ModuleFile *Mod; + ArrayRef<serialization::LocalDeclID> Decls; + + FileDeclsInfo() : Mod(0) {} + FileDeclsInfo(ModuleFile *Mod, ArrayRef<serialization::LocalDeclID> Decls) + : Mod(Mod), Decls(Decls) {} + }; + + /// \brief Map from a FileID to the file-level declarations that it contains. + llvm::DenseMap<FileID, FileDeclsInfo> FileDeclIDs; + + // Updates for visible decls can occur for other contexts than just the + // TU, and when we read those update records, the actual context will not + // be available yet (unless it's the TU), so have this pending map using the + // ID as a key. It will be realized when the context is actually loaded. + typedef + SmallVector<std::pair<serialization::reader::ASTDeclContextNameLookupTable *, + ModuleFile*>, 1> DeclContextVisibleUpdates; + typedef llvm::DenseMap<serialization::DeclID, DeclContextVisibleUpdates> + DeclContextVisibleUpdatesPending; + + /// \brief Updates to the visible declarations of declaration contexts that + /// haven't been loaded yet. + DeclContextVisibleUpdatesPending PendingVisibleUpdates; + + /// \brief The set of C++ or Objective-C classes that have forward + /// declarations that have not yet been linked to their definitions. + llvm::SmallPtrSet<Decl *, 4> PendingDefinitions; + + /// \brief Read the records that describe the contents of declcontexts. + bool ReadDeclContextStorage(ModuleFile &M, + llvm::BitstreamCursor &Cursor, + const std::pair<uint64_t, uint64_t> &Offsets, + serialization::DeclContextInfo &Info); + + /// \brief A vector containing identifiers that have already been + /// loaded. + /// + /// If the pointer at index I is non-NULL, then it refers to the + /// IdentifierInfo for the identifier with ID=I+1 that has already + /// been loaded. + std::vector<IdentifierInfo *> IdentifiersLoaded; + + typedef ContinuousRangeMap<serialization::IdentID, ModuleFile *, 4> + GlobalIdentifierMapType; + + /// \brief Mapping from global identifer IDs to the module in which the + /// identifier resides along with the offset that should be added to the + /// global identifier ID to produce a local ID. + GlobalIdentifierMapType GlobalIdentifierMap; + + /// \brief A vector containing submodules that have already been loaded. + /// + /// This vector is indexed by the Submodule ID (-1). NULL submodule entries + /// indicate that the particular submodule ID has not yet been loaded. + SmallVector<Module *, 2> SubmodulesLoaded; + + typedef ContinuousRangeMap<serialization::SubmoduleID, ModuleFile *, 4> + GlobalSubmoduleMapType; + + /// \brief Mapping from global submodule IDs to the module file in which the + /// submodule resides along with the offset that should be added to the + /// global submodule ID to produce a local ID. + GlobalSubmoduleMapType GlobalSubmoduleMap; + + /// \brief A set of hidden declarations. + typedef llvm::SmallVector<llvm::PointerUnion<Decl *, IdentifierInfo *>, 2> + HiddenNames; + + typedef llvm::DenseMap<Module *, HiddenNames> HiddenNamesMapType; + + /// \brief A mapping from each of the hidden submodules to the deserialized + /// declarations in that submodule that could be made visible. + HiddenNamesMapType HiddenNamesMap; + + + /// \brief A module import or export that hasn't yet been resolved. + struct UnresolvedModuleImportExport { + /// \brief The file in which this module resides. + ModuleFile *File; + + /// \brief The module that is importing or exporting. + Module *Mod; + + /// \brief The local ID of the module that is being exported. + unsigned ID; + + /// \brief Whether this is an import (vs. an export). + unsigned IsImport : 1; + + /// \brief Whether this is a wildcard export. + unsigned IsWildcard : 1; + }; + + /// \brief The set of module imports and exports that still need to be + /// resolved. + llvm::SmallVector<UnresolvedModuleImportExport, 2> + UnresolvedModuleImportExports; + + /// \brief A vector containing selectors that have already been loaded. + /// + /// This vector is indexed by the Selector ID (-1). NULL selector + /// entries indicate that the particular selector ID has not yet + /// been loaded. + SmallVector<Selector, 16> SelectorsLoaded; + + typedef ContinuousRangeMap<serialization::SelectorID, ModuleFile *, 4> + GlobalSelectorMapType; + + /// \brief Mapping from global selector IDs to the module in which the + /// selector resides along with the offset that should be added to the + /// global selector ID to produce a local ID. + GlobalSelectorMapType GlobalSelectorMap; + + /// \brief The generation number of the last time we loaded data from the + /// global method pool for this selector. + llvm::DenseMap<Selector, unsigned> SelectorGeneration; + + /// \brief Mapping from identifiers that represent macros whose definitions + /// have not yet been deserialized to the global offset where the macro + /// record resides. + llvm::DenseMap<IdentifierInfo *, uint64_t> UnreadMacroRecordOffsets; + + typedef ContinuousRangeMap<unsigned, ModuleFile *, 4> + GlobalPreprocessedEntityMapType; + + /// \brief Mapping from global preprocessing entity IDs to the module in + /// which the preprocessed entity resides along with the offset that should be + /// added to the global preprocessing entitiy ID to produce a local ID. + GlobalPreprocessedEntityMapType GlobalPreprocessedEntityMap; + + /// \name CodeGen-relevant special data + /// \brief Fields containing data that is relevant to CodeGen. + //@{ + + /// \brief The IDs of all declarations that fulfill the criteria of + /// "interesting" decls. + /// + /// This contains the data loaded from all EXTERNAL_DEFINITIONS blocks in the + /// chain. The referenced declarations are deserialized and passed to the + /// consumer eagerly. + SmallVector<uint64_t, 16> ExternalDefinitions; + + /// \brief The IDs of all tentative definitions stored in the the chain. + /// + /// Sema keeps track of all tentative definitions in a TU because it has to + /// complete them and pass them on to CodeGen. Thus, tentative definitions in + /// the PCH chain must be eagerly deserialized. + SmallVector<uint64_t, 16> TentativeDefinitions; + + /// \brief The IDs of all CXXRecordDecls stored in the chain whose VTables are + /// used. + /// + /// CodeGen has to emit VTables for these records, so they have to be eagerly + /// deserialized. + SmallVector<uint64_t, 64> VTableUses; + + /// \brief A snapshot of the pending instantiations in the chain. + /// + /// This record tracks the instantiations that Sema has to perform at the + /// end of the TU. It consists of a pair of values for every pending + /// instantiation where the first value is the ID of the decl and the second + /// is the instantiation location. + SmallVector<uint64_t, 64> PendingInstantiations; + + //@} + + /// \name DiagnosticsEngine-relevant special data + /// \brief Fields containing data that is used for generating diagnostics + //@{ + + /// \brief A snapshot of Sema's unused file-scoped variable tracking, for + /// generating warnings. + SmallVector<uint64_t, 16> UnusedFileScopedDecls; + + /// \brief A list of all the delegating constructors we've seen, to diagnose + /// cycles. + SmallVector<uint64_t, 4> DelegatingCtorDecls; + + /// \brief Method selectors used in a @selector expression. Used for + /// implementation of -Wselector. + SmallVector<uint64_t, 64> ReferencedSelectorsData; + + /// \brief A snapshot of Sema's weak undeclared identifier tracking, for + /// generating warnings. + SmallVector<uint64_t, 64> WeakUndeclaredIdentifiers; + + /// \brief The IDs of type aliases for ext_vectors that exist in the chain. + /// + /// Used by Sema for finding sugared names for ext_vectors in diagnostics. + SmallVector<uint64_t, 4> ExtVectorDecls; + + //@} + + /// \name Sema-relevant special data + /// \brief Fields containing data that is used for semantic analysis + //@{ + + /// \brief The IDs of all locally scoped external decls in the chain. + /// + /// Sema tracks these to validate that the types are consistent across all + /// local external declarations. + SmallVector<uint64_t, 16> LocallyScopedExternalDecls; + + /// \brief The IDs of all dynamic class declarations in the chain. + /// + /// Sema tracks these because it checks for the key functions being defined + /// at the end of the TU, in which case it directs CodeGen to emit the VTable. + SmallVector<uint64_t, 16> DynamicClasses; + + /// \brief The IDs of the declarations Sema stores directly. + /// + /// Sema tracks a few important decls, such as namespace std, directly. + SmallVector<uint64_t, 4> SemaDeclRefs; + + /// \brief The IDs of the types ASTContext stores directly. + /// + /// The AST context tracks a few important types, such as va_list, directly. + SmallVector<uint64_t, 16> SpecialTypes; + + /// \brief The IDs of CUDA-specific declarations ASTContext stores directly. + /// + /// The AST context tracks a few important decls, currently cudaConfigureCall, + /// directly. + SmallVector<uint64_t, 2> CUDASpecialDeclRefs; + + /// \brief The floating point pragma option settings. + SmallVector<uint64_t, 1> FPPragmaOptions; + + /// \brief The OpenCL extension settings. + SmallVector<uint64_t, 1> OpenCLExtensions; + + /// \brief A list of the namespaces we've seen. + SmallVector<uint64_t, 4> KnownNamespaces; + + /// \brief A list of modules that were imported by precompiled headers or + /// any other non-module AST file. + SmallVector<serialization::SubmoduleID, 2> ImportedModules; + //@} + + /// \brief The original file name that was used to build the primary AST file, + /// which may have been modified for relocatable-pch support. + std::string OriginalFileName; + + /// \brief The actual original file name that was used to build the primary + /// AST file. + std::string ActualOriginalFileName; + + /// \brief The file ID for the original file that was used to build the + /// primary AST file. + FileID OriginalFileID; + + /// \brief The directory that the PCH was originally created in. Used to + /// allow resolving headers even after headers+PCH was moved to a new path. + std::string OriginalDir; + + /// \brief The directory that the PCH we are reading is stored in. + std::string CurrentDir; + + /// \brief Whether this precompiled header is a relocatable PCH file. + bool RelocatablePCH; + + /// \brief The system include root to be used when loading the + /// precompiled header. + std::string isysroot; + + /// \brief Whether to disable the normal validation performed on precompiled + /// headers when they are loaded. + bool DisableValidation; + + /// \brief Whether to disable the use of stat caches in AST files. + bool DisableStatCache; + + /// \brief Whether to accept an AST file with compiler errors. + bool AllowASTWithCompilerErrors; + + /// \brief The current "generation" of the module file import stack, which + /// indicates how many separate module file load operations have occurred. + unsigned CurrentGeneration; + + /// \brief Mapping from switch-case IDs in the chain to switch-case statements + /// + /// Statements usually don't have IDs, but switch cases need them, so that the + /// switch statement can refer to them. + std::map<unsigned, SwitchCase *> SwitchCaseStmts; + + /// \brief The number of stat() calls that hit/missed the stat + /// cache. + unsigned NumStatHits, NumStatMisses; + + /// \brief The number of source location entries de-serialized from + /// the PCH file. + unsigned NumSLocEntriesRead; + + /// \brief The number of source location entries in the chain. + unsigned TotalNumSLocEntries; + + /// \brief The number of statements (and expressions) de-serialized + /// from the chain. + unsigned NumStatementsRead; + + /// \brief The total number of statements (and expressions) stored + /// in the chain. + unsigned TotalNumStatements; + + /// \brief The number of macros de-serialized from the chain. + unsigned NumMacrosRead; + + /// \brief The total number of macros stored in the chain. + unsigned TotalNumMacros; + + /// \brief The number of selectors that have been read. + unsigned NumSelectorsRead; + + /// \brief The number of method pool entries that have been read. + unsigned NumMethodPoolEntriesRead; + + /// \brief The number of times we have looked up a selector in the method + /// pool and not found anything interesting. + unsigned NumMethodPoolMisses; + + /// \brief The total number of method pool entries in the selector table. + unsigned TotalNumMethodPoolEntries; + + /// Number of lexical decl contexts read/total. + unsigned NumLexicalDeclContextsRead, TotalLexicalDeclContexts; + + /// Number of visible decl contexts read/total. + unsigned NumVisibleDeclContextsRead, TotalVisibleDeclContexts; + + /// Total size of modules, in bits, currently loaded + uint64_t TotalModulesSizeInBits; + + /// \brief Number of Decl/types that are currently deserializing. + unsigned NumCurrentElementsDeserializing; + + /// \brief Set true while we are in the process of passing deserialized + /// "interesting" decls to consumer inside FinishedDeserializing(). + /// This is used as a guard to avoid recursively repeating the process of + /// passing decls to consumer. + bool PassingDeclsToConsumer; + + /// Number of CXX base specifiers currently loaded + unsigned NumCXXBaseSpecifiersLoaded; + + /// \brief An IdentifierInfo that has been loaded but whose top-level + /// declarations of the same name have not (yet) been loaded. + struct PendingIdentifierInfo { + IdentifierInfo *II; + SmallVector<uint32_t, 4> DeclIDs; + }; + + /// \brief The set of identifiers that were read while the AST reader was + /// (recursively) loading declarations. + /// + /// The declarations on the identifier chain for these identifiers will be + /// loaded once the recursive loading has completed. + std::deque<PendingIdentifierInfo> PendingIdentifierInfos; + + /// \brief The generation number of each identifier, which keeps track of + /// the last time we loaded information about this identifier. + llvm::DenseMap<IdentifierInfo *, unsigned> IdentifierGeneration; + + /// \brief Contains declarations and definitions that will be + /// "interesting" to the ASTConsumer, when we get that AST consumer. + /// + /// "Interesting" declarations are those that have data that may + /// need to be emitted, such as inline function definitions or + /// Objective-C protocols. + std::deque<Decl *> InterestingDecls; + + /// \brief The set of redeclarable declaraations that have been deserialized + /// since the last time the declaration chains were linked. + llvm::SmallPtrSet<Decl *, 16> RedeclsDeserialized; + + /// \brief The list of redeclaration chains that still need to be + /// reconstructed. + /// + /// Each element is the global declaration ID of the first declaration in + /// the chain. Elements in this vector should be unique; use + /// PendingDeclChainsKnown to ensure uniqueness. + llvm::SmallVector<serialization::DeclID, 16> PendingDeclChains; + + /// \brief Keeps track of the elements added to PendingDeclChains. + llvm::SmallSet<serialization::DeclID, 16> PendingDeclChainsKnown; + + /// \brief The set of Objective-C categories that have been deserialized + /// since the last time the declaration chains were linked. + llvm::SmallPtrSet<ObjCCategoryDecl *, 16> CategoriesDeserialized; + + /// \brief The set of Objective-C class definitions that have already been + /// loaded, for which we will need to check for categories whenever a new + /// module is loaded. + llvm::SmallVector<ObjCInterfaceDecl *, 16> ObjCClassesLoaded; + + typedef llvm::DenseMap<Decl *, llvm::SmallVector<serialization::DeclID, 2> > + MergedDeclsMap; + + /// \brief A mapping from canonical declarations to the set of additional + /// (global, previously-canonical) declaration IDs that have been merged with + /// that canonical declaration. + MergedDeclsMap MergedDecls; + + typedef llvm::DenseMap<serialization::GlobalDeclID, + llvm::SmallVector<serialization::DeclID, 2> > + StoredMergedDeclsMap; + + /// \brief A mapping from canonical declaration IDs to the set of additional + /// declaration IDs that have been merged with that canonical declaration. + /// + /// This is the deserialized representation of the entries in MergedDecls. + /// When we query entries in MergedDecls, they will be augmented with entries + /// from StoredMergedDecls. + StoredMergedDeclsMap StoredMergedDecls; + + /// \brief Combine the stored merged declarations for the given canonical + /// declaration into the set of merged declarations. + /// + /// \returns An iterator into MergedDecls that corresponds to the position of + /// the given canonical declaration. + MergedDeclsMap::iterator + combineStoredMergedDecls(Decl *Canon, serialization::GlobalDeclID CanonID); + + /// \brief Ready to load the previous declaration of the given Decl. + void loadAndAttachPreviousDecl(Decl *D, serialization::DeclID ID); + + /// \brief When reading a Stmt tree, Stmt operands are placed in this stack. + SmallVector<Stmt *, 16> StmtStack; + + /// \brief What kind of records we are reading. + enum ReadingKind { + Read_Decl, Read_Type, Read_Stmt + }; + + /// \brief What kind of records we are reading. + ReadingKind ReadingKind; + + /// \brief RAII object to change the reading kind. + class ReadingKindTracker { + ASTReader &Reader; + enum ReadingKind PrevKind; + + ReadingKindTracker(const ReadingKindTracker&); // do not implement + ReadingKindTracker &operator=(const ReadingKindTracker&);// do not implement + + public: + ReadingKindTracker(enum ReadingKind newKind, ASTReader &reader) + : Reader(reader), PrevKind(Reader.ReadingKind) { + Reader.ReadingKind = newKind; + } + + ~ReadingKindTracker() { Reader.ReadingKind = PrevKind; } + }; + + /// \brief All predefines buffers in the chain, to be treated as if + /// concatenated. + PCHPredefinesBlocks PCHPredefinesBuffers; + + /// \brief Suggested contents of the predefines buffer, after this + /// PCH file has been processed. + /// + /// In most cases, this string will be empty, because the predefines + /// buffer computed to build the PCH file will be identical to the + /// predefines buffer computed from the command line. However, when + /// there are differences that the PCH reader can work around, this + /// predefines buffer may contain additional definitions. + std::string SuggestedPredefines; + + /// \brief Reads a statement from the specified cursor. + Stmt *ReadStmtFromStream(ModuleFile &F); + + /// \brief Get a FileEntry out of stored-in-PCH filename, making sure we take + /// into account all the necessary relocations. + const FileEntry *getFileEntry(StringRef filename); + + void MaybeAddSystemRootToFilename(std::string &Filename); + + ASTReadResult ReadASTCore(StringRef FileName, ModuleKind Type, + ModuleFile *ImportedBy); + ASTReadResult ReadASTBlock(ModuleFile &F); + bool CheckPredefinesBuffers(); + bool ParseLineTable(ModuleFile &F, SmallVectorImpl<uint64_t> &Record); + ASTReadResult ReadSourceManagerBlock(ModuleFile &F); + ASTReadResult ReadSLocEntryRecord(int ID); + llvm::BitstreamCursor &SLocCursorForID(int ID); + SourceLocation getImportLocation(ModuleFile *F); + ASTReadResult ReadSubmoduleBlock(ModuleFile &F); + bool ParseLanguageOptions(const SmallVectorImpl<uint64_t> &Record); + + struct RecordLocation { + RecordLocation(ModuleFile *M, uint64_t O) + : F(M), Offset(O) {} + ModuleFile *F; + uint64_t Offset; + }; + + QualType readTypeRecord(unsigned Index); + RecordLocation TypeCursorForIndex(unsigned Index); + void LoadedDecl(unsigned Index, Decl *D); + Decl *ReadDeclRecord(serialization::DeclID ID); + RecordLocation DeclCursorForID(serialization::DeclID ID, + unsigned &RawLocation); + void loadDeclUpdateRecords(serialization::DeclID ID, Decl *D); + void loadPendingDeclChain(serialization::GlobalDeclID ID); + void loadObjCCategories(serialization::GlobalDeclID ID, ObjCInterfaceDecl *D, + unsigned PreviousGeneration = 0); + + RecordLocation getLocalBitOffset(uint64_t GlobalOffset); + uint64_t getGlobalBitOffset(ModuleFile &M, uint32_t LocalOffset); + + /// \brief Returns the first preprocessed entity ID that ends after \arg BLoc. + serialization::PreprocessedEntityID + findBeginPreprocessedEntity(SourceLocation BLoc) const; + + /// \brief Returns the first preprocessed entity ID that begins after \arg + /// ELoc. + serialization::PreprocessedEntityID + findEndPreprocessedEntity(SourceLocation ELoc) const; + + /// \brief \arg SLocMapI points at a chunk of a module that contains no + /// preprocessed entities or the entities it contains are not the ones we are + /// looking for. Find the next module that contains entities and return the ID + /// of the first entry. + serialization::PreprocessedEntityID + findNextPreprocessedEntity( + GlobalSLocOffsetMapType::const_iterator SLocMapI) const; + + /// \brief Returns (ModuleFile, Local index) pair for \arg GlobalIndex of a + /// preprocessed entity. + std::pair<ModuleFile *, unsigned> + getModulePreprocessedEntity(unsigned GlobalIndex); + + void PassInterestingDeclsToConsumer(); + void PassInterestingDeclToConsumer(Decl *D); + + void finishPendingActions(); + + /// \brief Produce an error diagnostic and return true. + /// + /// This routine should only be used for fatal errors that have to + /// do with non-routine failures (e.g., corrupted AST file). + void Error(StringRef Msg); + void Error(unsigned DiagID, StringRef Arg1 = StringRef(), + StringRef Arg2 = StringRef()); + + ASTReader(const ASTReader&); // do not implement + ASTReader &operator=(const ASTReader &); // do not implement +public: + typedef SmallVector<uint64_t, 64> RecordData; + + /// \brief Load the AST file and validate its contents against the given + /// Preprocessor. + /// + /// \param PP the preprocessor associated with the context in which this + /// precompiled header will be loaded. + /// + /// \param Context the AST context that this precompiled header will be + /// loaded into. + /// + /// \param isysroot If non-NULL, the system include path specified by the + /// user. This is only used with relocatable PCH files. If non-NULL, + /// a relocatable PCH file will use the default path "/". + /// + /// \param DisableValidation If true, the AST reader will suppress most + /// of its regular consistency checking, allowing the use of precompiled + /// headers that cannot be determined to be compatible. + /// + /// \param DisableStatCache If true, the AST reader will ignore the + /// stat cache in the AST files. This performance pessimization can + /// help when an AST file is being used in cases where the + /// underlying files in the file system may have changed, but + /// parsing should still continue. + /// + /// \param AllowASTWithCompilerErrors If true, the AST reader will accept an + /// AST file the was created out of an AST with compiler errors, + /// otherwise it will reject it. + ASTReader(Preprocessor &PP, ASTContext &Context, StringRef isysroot = "", + bool DisableValidation = false, bool DisableStatCache = false, + bool AllowASTWithCompilerErrors = false); + + ~ASTReader(); + + SourceManager &getSourceManager() const { return SourceMgr; } + + /// \brief Load the AST file designated by the given file name. + ASTReadResult ReadAST(const std::string &FileName, ModuleKind Type); + + /// \brief Checks that no file that is stored in PCH is out-of-sync with + /// the actual file in the file system. + ASTReadResult validateFileEntries(ModuleFile &M); + + /// \brief Make the entities in the given module and any of its (non-explicit) + /// submodules visible to name lookup. + /// + /// \param Mod The module whose names should be made visible. + /// + /// \param Visibility The level of visibility to give the names in the module. + /// Visibility can only be increased over time. + void makeModuleVisible(Module *Mod, + Module::NameVisibilityKind NameVisibility); + + /// \brief Make the names within this set of hidden names visible. + void makeNamesVisible(const HiddenNames &Names); + + /// \brief Set the AST callbacks listener. + void setListener(ASTReaderListener *listener) { + Listener.reset(listener); + } + + /// \brief Set the AST deserialization listener. + void setDeserializationListener(ASTDeserializationListener *Listener); + + /// \brief Initializes the ASTContext + void InitializeContext(); + + /// \brief Add in-memory (virtual file) buffer. + void addInMemoryBuffer(StringRef &FileName, llvm::MemoryBuffer *Buffer) { + ModuleMgr.addInMemoryBuffer(FileName, Buffer); + } + + /// \brief Finalizes the AST reader's state before writing an AST file to + /// disk. + /// + /// This operation may undo temporary state in the AST that should not be + /// emitted. + void finalizeForWriting(); + + /// \brief Retrieve the module manager. + ModuleManager &getModuleManager() { return ModuleMgr; } + + /// \brief Retrieve the preprocessor. + Preprocessor &getPreprocessor() const { return PP; } + + /// \brief Retrieve the name of the original source file name + const std::string &getOriginalSourceFile() { return OriginalFileName; } + + /// \brief Retrieve the name of the original source file name directly from + /// the AST file, without actually loading the AST file. + static std::string getOriginalSourceFile(const std::string &ASTFileName, + FileManager &FileMgr, + DiagnosticsEngine &Diags); + + /// \brief Returns the suggested contents of the predefines buffer, + /// which contains a (typically-empty) subset of the predefines + /// build prior to including the precompiled header. + const std::string &getSuggestedPredefines() { return SuggestedPredefines; } + + /// \brief Read a preallocated preprocessed entity from the external source. + /// + /// \returns null if an error occurred that prevented the preprocessed + /// entity from being loaded. + virtual PreprocessedEntity *ReadPreprocessedEntity(unsigned Index); + + /// \brief Returns a pair of [Begin, End) indices of preallocated + /// preprocessed entities that \arg Range encompasses. + virtual std::pair<unsigned, unsigned> + findPreprocessedEntitiesInRange(SourceRange Range); + + /// \brief Optionally returns true or false if the preallocated preprocessed + /// entity with index \arg Index came from file \arg FID. + virtual llvm::Optional<bool> isPreprocessedEntityInFileID(unsigned Index, + FileID FID); + + /// \brief Read the header file information for the given file entry. + virtual HeaderFileInfo GetHeaderFileInfo(const FileEntry *FE); + + void ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag); + + /// \brief Returns the number of source locations found in the chain. + unsigned getTotalNumSLocs() const { + return TotalNumSLocEntries; + } + + /// \brief Returns the number of identifiers found in the chain. + unsigned getTotalNumIdentifiers() const { + return static_cast<unsigned>(IdentifiersLoaded.size()); + } + + /// \brief Returns the number of types found in the chain. + unsigned getTotalNumTypes() const { + return static_cast<unsigned>(TypesLoaded.size()); + } + + /// \brief Returns the number of declarations found in the chain. + unsigned getTotalNumDecls() const { + return static_cast<unsigned>(DeclsLoaded.size()); + } + + /// \brief Returns the number of submodules known. + unsigned getTotalNumSubmodules() const { + return static_cast<unsigned>(SubmodulesLoaded.size()); + } + + /// \brief Returns the number of selectors found in the chain. + unsigned getTotalNumSelectors() const { + return static_cast<unsigned>(SelectorsLoaded.size()); + } + + /// \brief Returns the number of preprocessed entities known to the AST + /// reader. + unsigned getTotalNumPreprocessedEntities() const { + unsigned Result = 0; + for (ModuleConstIterator I = ModuleMgr.begin(), + E = ModuleMgr.end(); I != E; ++I) { + Result += (*I)->NumPreprocessedEntities; + } + + return Result; + } + + /// \brief Returns the number of C++ base specifiers found in the chain. + unsigned getTotalNumCXXBaseSpecifiers() const { + return NumCXXBaseSpecifiersLoaded; + } + + /// \brief Reads a TemplateArgumentLocInfo appropriate for the + /// given TemplateArgument kind. + TemplateArgumentLocInfo + GetTemplateArgumentLocInfo(ModuleFile &F, TemplateArgument::ArgKind Kind, + const RecordData &Record, unsigned &Idx); + + /// \brief Reads a TemplateArgumentLoc. + TemplateArgumentLoc + ReadTemplateArgumentLoc(ModuleFile &F, + const RecordData &Record, unsigned &Idx); + + /// \brief Reads a declarator info from the given record. + TypeSourceInfo *GetTypeSourceInfo(ModuleFile &F, + const RecordData &Record, unsigned &Idx); + + /// \brief Resolve a type ID into a type, potentially building a new + /// type. + QualType GetType(serialization::TypeID ID); + + /// \brief Resolve a local type ID within a given AST file into a type. + QualType getLocalType(ModuleFile &F, unsigned LocalID); + + /// \brief Map a local type ID within a given AST file into a global type ID. + serialization::TypeID getGlobalTypeID(ModuleFile &F, unsigned LocalID) const; + + /// \brief Read a type from the current position in the given record, which + /// was read from the given AST file. + QualType readType(ModuleFile &F, const RecordData &Record, unsigned &Idx) { + if (Idx >= Record.size()) + return QualType(); + + return getLocalType(F, Record[Idx++]); + } + + /// \brief Map from a local declaration ID within a given module to a + /// global declaration ID. + serialization::DeclID getGlobalDeclID(ModuleFile &F, unsigned LocalID) const; + + /// \brief Returns true if global DeclID \arg ID originated from module + /// \arg M. + bool isDeclIDFromModule(serialization::GlobalDeclID ID, ModuleFile &M) const; + + /// \brief Retrieve the module file that owns the given declaration, or NULL + /// if the declaration is not from a module file. + ModuleFile *getOwningModuleFile(Decl *D); + + /// \brief Returns the source location for the decl \arg ID. + SourceLocation getSourceLocationForDeclID(serialization::GlobalDeclID ID); + + /// \brief Resolve a declaration ID into a declaration, potentially + /// building a new declaration. + Decl *GetDecl(serialization::DeclID ID); + virtual Decl *GetExternalDecl(uint32_t ID); + + /// \brief Reads a declaration with the given local ID in the given module. + Decl *GetLocalDecl(ModuleFile &F, uint32_t LocalID) { + return GetDecl(getGlobalDeclID(F, LocalID)); + } + + /// \brief Reads a declaration with the given local ID in the given module. + /// + /// \returns The requested declaration, casted to the given return type. + template<typename T> + T *GetLocalDeclAs(ModuleFile &F, uint32_t LocalID) { + return cast_or_null<T>(GetLocalDecl(F, LocalID)); + } + + /// \brief Map a global declaration ID into the declaration ID used to + /// refer to this declaration within the given module fule. + /// + /// \returns the global ID of the given declaration as known in the given + /// module file. + serialization::DeclID + mapGlobalIDToModuleFileGlobalID(ModuleFile &M, + serialization::DeclID GlobalID); + + /// \brief Reads a declaration ID from the given position in a record in the + /// given module. + /// + /// \returns The declaration ID read from the record, adjusted to a global ID. + serialization::DeclID ReadDeclID(ModuleFile &F, const RecordData &Record, + unsigned &Idx); + + /// \brief Reads a declaration from the given position in a record in the + /// given module. + Decl *ReadDecl(ModuleFile &F, const RecordData &R, unsigned &I) { + return GetDecl(ReadDeclID(F, R, I)); + } + + /// \brief Reads a declaration from the given position in a record in the + /// given module. + /// + /// \returns The declaration read from this location, casted to the given + /// result type. + template<typename T> + T *ReadDeclAs(ModuleFile &F, const RecordData &R, unsigned &I) { + return cast_or_null<T>(GetDecl(ReadDeclID(F, R, I))); + } + + /// \brief Read a CXXBaseSpecifiers ID form the given record and + /// return its global bit offset. + uint64_t readCXXBaseSpecifiers(ModuleFile &M, const RecordData &Record, + unsigned &Idx); + + virtual CXXBaseSpecifier *GetExternalCXXBaseSpecifiers(uint64_t Offset); + + /// \brief Resolve the offset of a statement into a statement. + /// + /// This operation will read a new statement from the external + /// source each time it is called, and is meant to be used via a + /// LazyOffsetPtr (which is used by Decls for the body of functions, etc). + virtual Stmt *GetExternalDeclStmt(uint64_t Offset); + + /// ReadBlockAbbrevs - Enter a subblock of the specified BlockID with the + /// specified cursor. Read the abbreviations that are at the top of the block + /// and then leave the cursor pointing into the block. + bool ReadBlockAbbrevs(llvm::BitstreamCursor &Cursor, unsigned BlockID); + + /// \brief Finds all the visible declarations with a given name. + /// The current implementation of this method just loads the entire + /// lookup table as unmaterialized references. + virtual DeclContext::lookup_result + FindExternalVisibleDeclsByName(const DeclContext *DC, + DeclarationName Name); + + /// \brief Read all of the declarations lexically stored in a + /// declaration context. + /// + /// \param DC The declaration context whose declarations will be + /// read. + /// + /// \param Decls Vector that will contain the declarations loaded + /// from the external source. The caller is responsible for merging + /// these declarations with any declarations already stored in the + /// declaration context. + /// + /// \returns true if there was an error while reading the + /// declarations for this declaration context. + virtual ExternalLoadResult FindExternalLexicalDecls(const DeclContext *DC, + bool (*isKindWeWant)(Decl::Kind), + SmallVectorImpl<Decl*> &Decls); + + /// \brief Get the decls that are contained in a file in the Offset/Length + /// range. \arg Length can be 0 to indicate a point at \arg Offset instead of + /// a range. + virtual void FindFileRegionDecls(FileID File, unsigned Offset,unsigned Length, + SmallVectorImpl<Decl *> &Decls); + + /// \brief Notify ASTReader that we started deserialization of + /// a decl or type so until FinishedDeserializing is called there may be + /// decls that are initializing. Must be paired with FinishedDeserializing. + virtual void StartedDeserializing() { ++NumCurrentElementsDeserializing; } + + /// \brief Notify ASTReader that we finished the deserialization of + /// a decl or type. Must be paired with StartedDeserializing. + virtual void FinishedDeserializing(); + + /// \brief Function that will be invoked when we begin parsing a new + /// translation unit involving this external AST source. + /// + /// This function will provide all of the external definitions to + /// the ASTConsumer. + virtual void StartTranslationUnit(ASTConsumer *Consumer); + + /// \brief Print some statistics about AST usage. + virtual void PrintStats(); + + /// \brief Dump information about the AST reader to standard error. + void dump(); + + /// Return the amount of memory used by memory buffers, breaking down + /// by heap-backed versus mmap'ed memory. + virtual void getMemoryBufferSizes(MemoryBufferSizes &sizes) const; + + /// \brief Initialize the semantic source with the Sema instance + /// being used to perform semantic analysis on the abstract syntax + /// tree. + virtual void InitializeSema(Sema &S); + + /// \brief Inform the semantic consumer that Sema is no longer available. + virtual void ForgetSema() { SemaObj = 0; } + + /// \brief Retrieve the IdentifierInfo for the named identifier. + /// + /// This routine builds a new IdentifierInfo for the given identifier. If any + /// declarations with this name are visible from translation unit scope, their + /// declarations will be deserialized and introduced into the declaration + /// chain of the identifier. + virtual IdentifierInfo *get(const char *NameStart, const char *NameEnd); + IdentifierInfo *get(StringRef Name) { + return get(Name.begin(), Name.end()); + } + + /// \brief Retrieve an iterator into the set of all identifiers + /// in all loaded AST files. + virtual IdentifierIterator *getIdentifiers() const; + + /// \brief Load the contents of the global method pool for a given + /// selector. + virtual void ReadMethodPool(Selector Sel); + + /// \brief Load the set of namespaces that are known to the external source, + /// which will be used during typo correction. + virtual void ReadKnownNamespaces( + SmallVectorImpl<NamespaceDecl *> &Namespaces); + + virtual void ReadTentativeDefinitions( + SmallVectorImpl<VarDecl *> &TentativeDefs); + + virtual void ReadUnusedFileScopedDecls( + SmallVectorImpl<const DeclaratorDecl *> &Decls); + + virtual void ReadDelegatingConstructors( + SmallVectorImpl<CXXConstructorDecl *> &Decls); + + virtual void ReadExtVectorDecls(SmallVectorImpl<TypedefNameDecl *> &Decls); + + virtual void ReadDynamicClasses(SmallVectorImpl<CXXRecordDecl *> &Decls); + + virtual void ReadLocallyScopedExternalDecls( + SmallVectorImpl<NamedDecl *> &Decls); + + virtual void ReadReferencedSelectors( + SmallVectorImpl<std::pair<Selector, SourceLocation> > &Sels); + + virtual void ReadWeakUndeclaredIdentifiers( + SmallVectorImpl<std::pair<IdentifierInfo *, WeakInfo> > &WI); + + virtual void ReadUsedVTables(SmallVectorImpl<ExternalVTableUse> &VTables); + + virtual void ReadPendingInstantiations( + SmallVectorImpl<std::pair<ValueDecl *, + SourceLocation> > &Pending); + + /// \brief Load a selector from disk, registering its ID if it exists. + void LoadSelector(Selector Sel); + + void SetIdentifierInfo(unsigned ID, IdentifierInfo *II); + void SetGloballyVisibleDecls(IdentifierInfo *II, + const SmallVectorImpl<uint32_t> &DeclIDs, + bool Nonrecursive = false); + + /// \brief Report a diagnostic. + DiagnosticBuilder Diag(unsigned DiagID); + + /// \brief Report a diagnostic. + DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID); + + IdentifierInfo *DecodeIdentifierInfo(serialization::IdentifierID ID); + + IdentifierInfo *GetIdentifierInfo(ModuleFile &M, const RecordData &Record, + unsigned &Idx) { + return DecodeIdentifierInfo(getGlobalIdentifierID(M, Record[Idx++])); + } + + virtual IdentifierInfo *GetIdentifier(serialization::IdentifierID ID) { + return DecodeIdentifierInfo(ID); + } + + IdentifierInfo *getLocalIdentifier(ModuleFile &M, unsigned LocalID); + + serialization::IdentifierID getGlobalIdentifierID(ModuleFile &M, + unsigned LocalID); + + /// \brief Read the source location entry with index ID. + virtual bool ReadSLocEntry(int ID); + + /// \brief Retrieve the global submodule ID given a module and its local ID + /// number. + serialization::SubmoduleID + getGlobalSubmoduleID(ModuleFile &M, unsigned LocalID); + + /// \brief Retrieve the submodule that corresponds to a global submodule ID. + /// + Module *getSubmodule(serialization::SubmoduleID GlobalID); + + /// \brief Retrieve a selector from the given module with its local ID + /// number. + Selector getLocalSelector(ModuleFile &M, unsigned LocalID); + + Selector DecodeSelector(serialization::SelectorID Idx); + + virtual Selector GetExternalSelector(serialization::SelectorID ID); + uint32_t GetNumExternalSelectors(); + + Selector ReadSelector(ModuleFile &M, const RecordData &Record, unsigned &Idx) { + return getLocalSelector(M, Record[Idx++]); + } + + /// \brief Retrieve the global selector ID that corresponds to this + /// the local selector ID in a given module. + serialization::SelectorID getGlobalSelectorID(ModuleFile &F, + unsigned LocalID) const; + + /// \brief Read a declaration name. + DeclarationName ReadDeclarationName(ModuleFile &F, + const RecordData &Record, unsigned &Idx); + void ReadDeclarationNameLoc(ModuleFile &F, + DeclarationNameLoc &DNLoc, DeclarationName Name, + const RecordData &Record, unsigned &Idx); + void ReadDeclarationNameInfo(ModuleFile &F, DeclarationNameInfo &NameInfo, + const RecordData &Record, unsigned &Idx); + + void ReadQualifierInfo(ModuleFile &F, QualifierInfo &Info, + const RecordData &Record, unsigned &Idx); + + NestedNameSpecifier *ReadNestedNameSpecifier(ModuleFile &F, + const RecordData &Record, + unsigned &Idx); + + NestedNameSpecifierLoc ReadNestedNameSpecifierLoc(ModuleFile &F, + const RecordData &Record, + unsigned &Idx); + + /// \brief Read a template name. + TemplateName ReadTemplateName(ModuleFile &F, const RecordData &Record, + unsigned &Idx); + + /// \brief Read a template argument. + TemplateArgument ReadTemplateArgument(ModuleFile &F, + const RecordData &Record,unsigned &Idx); + + /// \brief Read a template parameter list. + TemplateParameterList *ReadTemplateParameterList(ModuleFile &F, + const RecordData &Record, + unsigned &Idx); + + /// \brief Read a template argument array. + void + ReadTemplateArgumentList(SmallVector<TemplateArgument, 8> &TemplArgs, + ModuleFile &F, const RecordData &Record, + unsigned &Idx); + + /// \brief Read a UnresolvedSet structure. + void ReadUnresolvedSet(ModuleFile &F, UnresolvedSetImpl &Set, + const RecordData &Record, unsigned &Idx); + + /// \brief Read a C++ base specifier. + CXXBaseSpecifier ReadCXXBaseSpecifier(ModuleFile &F, + const RecordData &Record,unsigned &Idx); + + /// \brief Read a CXXCtorInitializer array. + std::pair<CXXCtorInitializer **, unsigned> + ReadCXXCtorInitializers(ModuleFile &F, const RecordData &Record, + unsigned &Idx); + + /// \brief Read a source location from raw form. + SourceLocation ReadSourceLocation(ModuleFile &ModuleFile, unsigned Raw) const { + SourceLocation Loc = SourceLocation::getFromRawEncoding(Raw); + assert(ModuleFile.SLocRemap.find(Loc.getOffset()) != ModuleFile.SLocRemap.end() && + "Cannot find offset to remap."); + int Remap = ModuleFile.SLocRemap.find(Loc.getOffset())->second; + return Loc.getLocWithOffset(Remap); + } + + /// \brief Read a source location. + SourceLocation ReadSourceLocation(ModuleFile &ModuleFile, + const RecordData &Record, unsigned& Idx) { + return ReadSourceLocation(ModuleFile, Record[Idx++]); + } + + /// \brief Read a source range. + SourceRange ReadSourceRange(ModuleFile &F, + const RecordData &Record, unsigned& Idx); + + /// \brief Read an integral value + llvm::APInt ReadAPInt(const RecordData &Record, unsigned &Idx); + + /// \brief Read a signed integral value + llvm::APSInt ReadAPSInt(const RecordData &Record, unsigned &Idx); + + /// \brief Read a floating-point value + llvm::APFloat ReadAPFloat(const RecordData &Record, unsigned &Idx); + + // \brief Read a string + std::string ReadString(const RecordData &Record, unsigned &Idx); + + /// \brief Read a version tuple. + VersionTuple ReadVersionTuple(const RecordData &Record, unsigned &Idx); + + CXXTemporary *ReadCXXTemporary(ModuleFile &F, const RecordData &Record, + unsigned &Idx); + + /// \brief Reads attributes from the current stream position. + void ReadAttributes(ModuleFile &F, AttrVec &Attrs, + const RecordData &Record, unsigned &Idx); + + /// \brief Reads a statement. + Stmt *ReadStmt(ModuleFile &F); + + /// \brief Reads an expression. + Expr *ReadExpr(ModuleFile &F); + + /// \brief Reads a sub-statement operand during statement reading. + Stmt *ReadSubStmt() { + assert(ReadingKind == Read_Stmt && + "Should be called only during statement reading!"); + // Subexpressions are stored from last to first, so the next Stmt we need + // is at the back of the stack. + assert(!StmtStack.empty() && "Read too many sub statements!"); + return StmtStack.pop_back_val(); + } + + /// \brief Reads a sub-expression operand during statement reading. + Expr *ReadSubExpr(); + + /// \brief Reads the macro record located at the given offset. + void ReadMacroRecord(ModuleFile &F, uint64_t Offset); + + /// \brief Determine the global preprocessed entity ID that corresponds to + /// the given local ID within the given module. + serialization::PreprocessedEntityID + getGlobalPreprocessedEntityID(ModuleFile &M, unsigned LocalID) const; + + /// \brief Note that the identifier is a macro whose record will be loaded + /// from the given AST file at the given (file-local) offset. + /// + /// \param II The name of the macro. + /// + /// \param F The module file from which the macro definition was deserialized. + /// + /// \param Offset The offset into the module file at which the macro + /// definition is located. + /// + /// \param Visible Whether the macro should be made visible. + void setIdentifierIsMacro(IdentifierInfo *II, ModuleFile &F, + uint64_t Offset, bool Visible); + + /// \brief Read the set of macros defined by this external macro source. + virtual void ReadDefinedMacros(); + + /// \brief Read the macro definition for this identifier. + virtual void LoadMacroDefinition(IdentifierInfo *II); + + /// \brief Update an out-of-date identifier. + virtual void updateOutOfDateIdentifier(IdentifierInfo &II); + + /// \brief Note that this identifier is up-to-date. + void markIdentifierUpToDate(IdentifierInfo *II); + + /// \brief Read the macro definition corresponding to this iterator + /// into the unread macro record offsets table. + void LoadMacroDefinition( + llvm::DenseMap<IdentifierInfo *, uint64_t>::iterator Pos); + + /// \brief Load all external visible decls in the given DeclContext. + void completeVisibleDeclsMap(const DeclContext *DC); + + /// \brief Retrieve the AST context that this AST reader supplements. + ASTContext &getContext() { return Context; } + + // \brief Contains declarations that were loaded before we have + // access to a Sema object. + SmallVector<NamedDecl *, 16> PreloadedDecls; + + /// \brief Retrieve the semantic analysis object used to analyze the + /// translation unit in which the precompiled header is being + /// imported. + Sema *getSema() { return SemaObj; } + + /// \brief Retrieve the identifier table associated with the + /// preprocessor. + IdentifierTable &getIdentifierTable(); + + /// \brief Record that the given ID maps to the given switch-case + /// statement. + void RecordSwitchCaseID(SwitchCase *SC, unsigned ID); + + /// \brief Retrieve the switch-case statement with the given ID. + SwitchCase *getSwitchCaseWithID(unsigned ID); + + void ClearSwitchCaseIDs(); +}; + +/// \brief Helper class that saves the current stream position and +/// then restores it when destroyed. +struct SavedStreamPosition { + explicit SavedStreamPosition(llvm::BitstreamCursor &Cursor) + : Cursor(Cursor), Offset(Cursor.GetCurrentBitNo()) { } + + ~SavedStreamPosition() { + Cursor.JumpToBit(Offset); + } + +private: + llvm::BitstreamCursor &Cursor; + uint64_t Offset; +}; + +inline void PCHValidator::Error(const char *Msg) { + Reader.Error(Msg); +} + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Serialization/ASTWriter.h b/clang/include/clang/Serialization/ASTWriter.h new file mode 100644 index 0000000..e693f17 --- /dev/null +++ b/clang/include/clang/Serialization/ASTWriter.h @@ -0,0 +1,738 @@ +//===--- ASTWriter.h - AST File Writer --------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ASTWriter class, which writes an AST file +// containing a serialized representation of a translation unit. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_FRONTEND_AST_WRITER_H +#define LLVM_CLANG_FRONTEND_AST_WRITER_H + +#include "clang/AST/Decl.h" +#include "clang/AST/DeclarationName.h" +#include "clang/AST/TemplateBase.h" +#include "clang/AST/ASTMutationListener.h" +#include "clang/Serialization/ASTBitCodes.h" +#include "clang/Serialization/ASTDeserializationListener.h" +#include "clang/Sema/SemaConsumer.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/Bitcode/BitstreamWriter.h" +#include <map> +#include <queue> +#include <vector> + +namespace llvm { + class APFloat; + class APInt; + class BitstreamWriter; +} + +namespace clang { + +class ASTContext; +class NestedNameSpecifier; +class CXXBaseSpecifier; +class CXXCtorInitializer; +class FPOptions; +class HeaderSearch; +class IdentifierResolver; +class MacroDefinition; +class MemorizeStatCalls; +class OpaqueValueExpr; +class OpenCLOptions; +class ASTReader; +class Module; +class PreprocessedEntity; +class PreprocessingRecord; +class Preprocessor; +class Sema; +class SourceManager; +class SwitchCase; +class TargetInfo; +class VersionTuple; + +namespace SrcMgr { class SLocEntry; } + +/// \brief Writes an AST file containing the contents of a translation unit. +/// +/// The ASTWriter class produces a bitstream containing the serialized +/// representation of a given abstract syntax tree and its supporting +/// data structures. This bitstream can be de-serialized via an +/// instance of the ASTReader class. +class ASTWriter : public ASTDeserializationListener, + public ASTMutationListener { +public: + typedef SmallVector<uint64_t, 64> RecordData; + typedef SmallVectorImpl<uint64_t> RecordDataImpl; + + friend class ASTDeclWriter; + friend class ASTStmtWriter; +private: + /// \brief Map that provides the ID numbers of each type within the + /// output stream, plus those deserialized from a chained PCH. + /// + /// The ID numbers of types are consecutive (in order of discovery) + /// and start at 1. 0 is reserved for NULL. When types are actually + /// stored in the stream, the ID number is shifted by 2 bits to + /// allow for the const/volatile qualifiers. + /// + /// Keys in the map never have const/volatile qualifiers. + typedef llvm::DenseMap<QualType, serialization::TypeIdx, + serialization::UnsafeQualTypeDenseMapInfo> + TypeIdxMap; + + /// \brief The bitstream writer used to emit this precompiled header. + llvm::BitstreamWriter &Stream; + + /// \brief The ASTContext we're writing. + ASTContext *Context; + + /// \brief The preprocessor we're writing. + Preprocessor *PP; + + /// \brief The reader of existing AST files, if we're chaining. + ASTReader *Chain; + + /// \brief The module we're currently writing, if any. + Module *WritingModule; + + /// \brief Indicates when the AST writing is actively performing + /// serialization, rather than just queueing updates. + bool WritingAST; + + /// \brief Indicates that the AST contained compiler errors. + bool ASTHasCompilerErrors; + + /// \brief Stores a declaration or a type to be written to the AST file. + class DeclOrType { + public: + DeclOrType(Decl *D) : Stored(D), IsType(false) { } + DeclOrType(QualType T) : Stored(T.getAsOpaquePtr()), IsType(true) { } + + bool isType() const { return IsType; } + bool isDecl() const { return !IsType; } + + QualType getType() const { + assert(isType() && "Not a type!"); + return QualType::getFromOpaquePtr(Stored); + } + + Decl *getDecl() const { + assert(isDecl() && "Not a decl!"); + return static_cast<Decl *>(Stored); + } + + private: + void *Stored; + bool IsType; + }; + + /// \brief The declarations and types to emit. + std::queue<DeclOrType> DeclTypesToEmit; + + /// \brief The first ID number we can use for our own declarations. + serialization::DeclID FirstDeclID; + + /// \brief The decl ID that will be assigned to the next new decl. + serialization::DeclID NextDeclID; + + /// \brief Map that provides the ID numbers of each declaration within + /// the output stream, as well as those deserialized from a chained PCH. + /// + /// The ID numbers of declarations are consecutive (in order of + /// discovery) and start at 2. 1 is reserved for the translation + /// unit, while 0 is reserved for NULL. + llvm::DenseMap<const Decl *, serialization::DeclID> DeclIDs; + + /// \brief Offset of each declaration in the bitstream, indexed by + /// the declaration's ID. + std::vector<serialization::DeclOffset> DeclOffsets; + + /// \brief Sorted (by file offset) vector of pairs of file offset/DeclID. + typedef SmallVector<std::pair<unsigned, serialization::DeclID>, 64> + LocDeclIDsTy; + struct DeclIDInFileInfo { + LocDeclIDsTy DeclIDs; + /// \brief Set when the DeclIDs vectors from all files are joined, this + /// indicates the index that this particular vector has in the global one. + unsigned FirstDeclIndex; + }; + typedef llvm::DenseMap<const SrcMgr::SLocEntry *, + DeclIDInFileInfo *> FileDeclIDsTy; + + /// \brief Map from file SLocEntries to info about the file-level declarations + /// that it contains. + FileDeclIDsTy FileDeclIDs; + + void associateDeclWithFile(const Decl *D, serialization::DeclID); + + /// \brief The first ID number we can use for our own types. + serialization::TypeID FirstTypeID; + + /// \brief The type ID that will be assigned to the next new type. + serialization::TypeID NextTypeID; + + /// \brief Map that provides the ID numbers of each type within the + /// output stream, plus those deserialized from a chained PCH. + /// + /// The ID numbers of types are consecutive (in order of discovery) + /// and start at 1. 0 is reserved for NULL. When types are actually + /// stored in the stream, the ID number is shifted by 2 bits to + /// allow for the const/volatile qualifiers. + /// + /// Keys in the map never have const/volatile qualifiers. + TypeIdxMap TypeIdxs; + + /// \brief Offset of each type in the bitstream, indexed by + /// the type's ID. + std::vector<uint32_t> TypeOffsets; + + /// \brief The first ID number we can use for our own identifiers. + serialization::IdentID FirstIdentID; + + /// \brief The identifier ID that will be assigned to the next new identifier. + serialization::IdentID NextIdentID; + + /// \brief Map that provides the ID numbers of each identifier in + /// the output stream. + /// + /// The ID numbers for identifiers are consecutive (in order of + /// discovery), starting at 1. An ID of zero refers to a NULL + /// IdentifierInfo. + llvm::DenseMap<const IdentifierInfo *, serialization::IdentID> IdentifierIDs; + + /// @name FlushStmt Caches + /// @{ + + /// \brief Set of parent Stmts for the currently serializing sub stmt. + llvm::DenseSet<Stmt *> ParentStmts; + + /// \brief Offsets of sub stmts already serialized. The offset points + /// just after the stmt record. + llvm::DenseMap<Stmt *, uint64_t> SubStmtEntries; + + /// @} + + /// \brief Offsets of each of the identifier IDs into the identifier + /// table. + std::vector<uint32_t> IdentifierOffsets; + + /// \brief The first ID number we can use for our own submodules. + serialization::SubmoduleID FirstSubmoduleID; + + /// \brief The submodule ID that will be assigned to the next new submodule. + serialization::SubmoduleID NextSubmoduleID; + + /// \brief The first ID number we can use for our own selectors. + serialization::SelectorID FirstSelectorID; + + /// \brief The selector ID that will be assigned to the next new selector. + serialization::SelectorID NextSelectorID; + + /// \brief Map that provides the ID numbers of each Selector. + llvm::DenseMap<Selector, serialization::SelectorID> SelectorIDs; + + /// \brief Offset of each selector within the method pool/selector + /// table, indexed by the Selector ID (-1). + std::vector<uint32_t> SelectorOffsets; + + /// \brief Offsets of each of the macro identifiers into the + /// bitstream. + /// + /// For each identifier that is associated with a macro, this map + /// provides the offset into the bitstream where that macro is + /// defined. + llvm::DenseMap<const IdentifierInfo *, uint64_t> MacroOffsets; + + /// \brief The set of identifiers that had macro definitions at some point. + std::vector<const IdentifierInfo *> DeserializedMacroNames; + + /// \brief Mapping from macro definitions (as they occur in the preprocessing + /// record) to the macro IDs. + llvm::DenseMap<const MacroDefinition *, serialization::PreprocessedEntityID> + MacroDefinitions; + + typedef SmallVector<uint64_t, 2> UpdateRecord; + typedef llvm::DenseMap<const Decl *, UpdateRecord> DeclUpdateMap; + /// \brief Mapping from declarations that came from a chained PCH to the + /// record containing modifications to them. + DeclUpdateMap DeclUpdates; + + typedef llvm::DenseMap<Decl *, Decl *> FirstLatestDeclMap; + /// \brief Map of first declarations from a chained PCH that point to the + /// most recent declarations in another PCH. + FirstLatestDeclMap FirstLatestDecls; + + /// \brief Declarations encountered that might be external + /// definitions. + /// + /// We keep track of external definitions (as well as tentative + /// definitions) as we are emitting declarations to the AST + /// file. The AST file contains a separate record for these external + /// definitions, which are provided to the AST consumer by the AST + /// reader. This is behavior is required to properly cope with, + /// e.g., tentative variable definitions that occur within + /// headers. The declarations themselves are stored as declaration + /// IDs, since they will be written out to an EXTERNAL_DEFINITIONS + /// record. + SmallVector<uint64_t, 16> ExternalDefinitions; + + /// \brief DeclContexts that have received extensions since their serialized + /// form. + /// + /// For namespaces, when we're chaining and encountering a namespace, we check + /// if its primary namespace comes from the chain. If it does, we add the + /// primary to this set, so that we can write out lexical content updates for + /// it. + llvm::SmallPtrSet<const DeclContext *, 16> UpdatedDeclContexts; + + typedef llvm::SmallPtrSet<const Decl *, 16> DeclsToRewriteTy; + /// \brief Decls that will be replaced in the current dependent AST file. + DeclsToRewriteTy DeclsToRewrite; + + /// \brief The set of Objective-C class that have categories we + /// should serialize. + llvm::SetVector<ObjCInterfaceDecl *> ObjCClassesWithCategories; + + struct ReplacedDeclInfo { + serialization::DeclID ID; + uint64_t Offset; + unsigned Loc; + + ReplacedDeclInfo() : ID(0), Offset(0), Loc(0) {} + ReplacedDeclInfo(serialization::DeclID ID, uint64_t Offset, + SourceLocation Loc) + : ID(ID), Offset(Offset), Loc(Loc.getRawEncoding()) {} + }; + + /// \brief Decls that have been replaced in the current dependent AST file. + /// + /// When a decl changes fundamentally after being deserialized (this shouldn't + /// happen, but the ObjC AST nodes are designed this way), it will be + /// serialized again. In this case, it is registered here, so that the reader + /// knows to read the updated version. + SmallVector<ReplacedDeclInfo, 16> ReplacedDecls; + + /// \brief The set of declarations that may have redeclaration chains that + /// need to be serialized. + llvm::SetVector<Decl *, llvm::SmallVector<Decl *, 4>, + llvm::SmallPtrSet<Decl *, 4> > Redeclarations; + + /// \brief Statements that we've encountered while serializing a + /// declaration or type. + SmallVector<Stmt *, 16> StmtsToEmit; + + /// \brief Statements collection to use for ASTWriter::AddStmt(). + /// It will point to StmtsToEmit unless it is overriden. + SmallVector<Stmt *, 16> *CollectedStmts; + + /// \brief Mapping from SwitchCase statements to IDs. + std::map<SwitchCase *, unsigned> SwitchCaseIDs; + + /// \brief The number of statements written to the AST file. + unsigned NumStatements; + + /// \brief The number of macros written to the AST file. + unsigned NumMacros; + + /// \brief The number of lexical declcontexts written to the AST + /// file. + unsigned NumLexicalDeclContexts; + + /// \brief The number of visible declcontexts written to the AST + /// file. + unsigned NumVisibleDeclContexts; + + /// \brief The offset of each CXXBaseSpecifier set within the AST. + SmallVector<uint32_t, 4> CXXBaseSpecifiersOffsets; + + /// \brief The first ID number we can use for our own base specifiers. + serialization::CXXBaseSpecifiersID FirstCXXBaseSpecifiersID; + + /// \brief The base specifiers ID that will be assigned to the next new + /// set of C++ base specifiers. + serialization::CXXBaseSpecifiersID NextCXXBaseSpecifiersID; + + /// \brief A set of C++ base specifiers that is queued to be written into the + /// AST file. + struct QueuedCXXBaseSpecifiers { + QueuedCXXBaseSpecifiers() : ID(), Bases(), BasesEnd() { } + + QueuedCXXBaseSpecifiers(serialization::CXXBaseSpecifiersID ID, + CXXBaseSpecifier const *Bases, + CXXBaseSpecifier const *BasesEnd) + : ID(ID), Bases(Bases), BasesEnd(BasesEnd) { } + + serialization::CXXBaseSpecifiersID ID; + CXXBaseSpecifier const * Bases; + CXXBaseSpecifier const * BasesEnd; + }; + + /// \brief Queue of C++ base specifiers to be written to the AST file, + /// in the order they should be written. + SmallVector<QueuedCXXBaseSpecifiers, 2> CXXBaseSpecifiersToWrite; + + /// \brief A mapping from each known submodule to its ID number, which will + /// be a positive integer. + llvm::DenseMap<Module *, unsigned> SubmoduleIDs; + + /// \brief Retrieve or create a submodule ID for this module. + unsigned getSubmoduleID(Module *Mod); + + /// \brief Write the given subexpression to the bitstream. + void WriteSubStmt(Stmt *S, + llvm::DenseMap<Stmt *, uint64_t> &SubStmtEntries, + llvm::DenseSet<Stmt *> &ParentStmts); + + void WriteBlockInfoBlock(); + void WriteMetadata(ASTContext &Context, StringRef isysroot, + const std::string &OutputFile); + void WriteLanguageOptions(const LangOptions &LangOpts); + void WriteStatCache(MemorizeStatCalls &StatCalls); + void WriteSourceManagerBlock(SourceManager &SourceMgr, + const Preprocessor &PP, + StringRef isysroot); + void WritePreprocessor(const Preprocessor &PP, bool IsModule); + void WriteHeaderSearch(const HeaderSearch &HS, StringRef isysroot); + void WritePreprocessorDetail(PreprocessingRecord &PPRec); + void WriteSubmodules(Module *WritingModule); + + void WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag); + void WriteCXXBaseSpecifiersOffsets(); + void WriteType(QualType T); + uint64_t WriteDeclContextLexicalBlock(ASTContext &Context, DeclContext *DC); + uint64_t WriteDeclContextVisibleBlock(ASTContext &Context, DeclContext *DC); + void WriteTypeDeclOffsets(); + void WriteFileDeclIDsMap(); + void WriteSelectors(Sema &SemaRef); + void WriteReferencedSelectorsPool(Sema &SemaRef); + void WriteIdentifierTable(Preprocessor &PP, IdentifierResolver &IdResolver, + bool IsModule); + void WriteAttributes(const AttrVec &Attrs, RecordDataImpl &Record); + void ResolveDeclUpdatesBlocks(); + void WriteDeclUpdatesBlocks(); + void WriteDeclReplacementsBlock(); + void WriteDeclContextVisibleUpdate(const DeclContext *DC); + void WriteFPPragmaOptions(const FPOptions &Opts); + void WriteOpenCLExtensions(Sema &SemaRef); + void WriteObjCCategories(); + void WriteRedeclarations(); + void WriteMergedDecls(); + + unsigned DeclParmVarAbbrev; + unsigned DeclContextLexicalAbbrev; + unsigned DeclContextVisibleLookupAbbrev; + unsigned UpdateVisibleAbbrev; + unsigned DeclRefExprAbbrev; + unsigned CharacterLiteralAbbrev; + unsigned DeclRecordAbbrev; + unsigned IntegerLiteralAbbrev; + unsigned DeclTypedefAbbrev; + unsigned DeclVarAbbrev; + unsigned DeclFieldAbbrev; + unsigned DeclEnumAbbrev; + unsigned DeclObjCIvarAbbrev; + + void WriteDeclsBlockAbbrevs(); + void WriteDecl(ASTContext &Context, Decl *D); + + void WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls, + StringRef isysroot, const std::string &OutputFile, + Module *WritingModule); + +public: + /// \brief Create a new precompiled header writer that outputs to + /// the given bitstream. + ASTWriter(llvm::BitstreamWriter &Stream); + ~ASTWriter(); + + /// \brief Write a precompiled header for the given semantic analysis. + /// + /// \param SemaRef a reference to the semantic analysis object that processed + /// the AST to be written into the precompiled header. + /// + /// \param StatCalls the object that cached all of the stat() calls made while + /// searching for source files and headers. + /// + /// \param WritingModule The module that we are writing. If null, we are + /// writing a precompiled header. + /// + /// \param isysroot if non-empty, write a relocatable file whose headers + /// are relative to the given system root. + void WriteAST(Sema &SemaRef, MemorizeStatCalls *StatCalls, + const std::string &OutputFile, + Module *WritingModule, StringRef isysroot, + bool hasErrors = false); + + /// \brief Emit a source location. + void AddSourceLocation(SourceLocation Loc, RecordDataImpl &Record); + + /// \brief Emit a source range. + void AddSourceRange(SourceRange Range, RecordDataImpl &Record); + + /// \brief Emit an integral value. + void AddAPInt(const llvm::APInt &Value, RecordDataImpl &Record); + + /// \brief Emit a signed integral value. + void AddAPSInt(const llvm::APSInt &Value, RecordDataImpl &Record); + + /// \brief Emit a floating-point value. + void AddAPFloat(const llvm::APFloat &Value, RecordDataImpl &Record); + + /// \brief Emit a reference to an identifier. + void AddIdentifierRef(const IdentifierInfo *II, RecordDataImpl &Record); + + /// \brief Emit a Selector (which is a smart pointer reference). + void AddSelectorRef(Selector, RecordDataImpl &Record); + + /// \brief Emit a CXXTemporary. + void AddCXXTemporary(const CXXTemporary *Temp, RecordDataImpl &Record); + + /// \brief Emit a set of C++ base specifiers to the record. + void AddCXXBaseSpecifiersRef(CXXBaseSpecifier const *Bases, + CXXBaseSpecifier const *BasesEnd, + RecordDataImpl &Record); + + /// \brief Get the unique number used to refer to the given selector. + serialization::SelectorID getSelectorRef(Selector Sel); + + /// \brief Get the unique number used to refer to the given identifier. + serialization::IdentID getIdentifierRef(const IdentifierInfo *II); + + /// \brief Retrieve the offset of the macro definition for the given + /// identifier. + /// + /// The identifier must refer to a macro. + uint64_t getMacroOffset(const IdentifierInfo *II) { + assert(MacroOffsets.find(II) != MacroOffsets.end() && + "Identifier does not name a macro"); + return MacroOffsets[II]; + } + + /// \brief Emit a reference to a type. + void AddTypeRef(QualType T, RecordDataImpl &Record); + + /// \brief Force a type to be emitted and get its ID. + serialization::TypeID GetOrCreateTypeID(QualType T); + + /// \brief Determine the type ID of an already-emitted type. + serialization::TypeID getTypeID(QualType T) const; + + /// \brief Force a type to be emitted and get its index. + serialization::TypeIdx GetOrCreateTypeIdx( QualType T); + + /// \brief Determine the type index of an already-emitted type. + serialization::TypeIdx getTypeIdx(QualType T) const; + + /// \brief Emits a reference to a declarator info. + void AddTypeSourceInfo(TypeSourceInfo *TInfo, RecordDataImpl &Record); + + /// \brief Emits a type with source-location information. + void AddTypeLoc(TypeLoc TL, RecordDataImpl &Record); + + /// \brief Emits a template argument location info. + void AddTemplateArgumentLocInfo(TemplateArgument::ArgKind Kind, + const TemplateArgumentLocInfo &Arg, + RecordDataImpl &Record); + + /// \brief Emits a template argument location. + void AddTemplateArgumentLoc(const TemplateArgumentLoc &Arg, + RecordDataImpl &Record); + + /// \brief Emit a reference to a declaration. + void AddDeclRef(const Decl *D, RecordDataImpl &Record); + + + /// \brief Force a declaration to be emitted and get its ID. + serialization::DeclID GetDeclRef(const Decl *D); + + /// \brief Determine the declaration ID of an already-emitted + /// declaration. + serialization::DeclID getDeclID(const Decl *D); + + /// \brief Emit a declaration name. + void AddDeclarationName(DeclarationName Name, RecordDataImpl &Record); + void AddDeclarationNameLoc(const DeclarationNameLoc &DNLoc, + DeclarationName Name, RecordDataImpl &Record); + void AddDeclarationNameInfo(const DeclarationNameInfo &NameInfo, + RecordDataImpl &Record); + + void AddQualifierInfo(const QualifierInfo &Info, RecordDataImpl &Record); + + /// \brief Emit a nested name specifier. + void AddNestedNameSpecifier(NestedNameSpecifier *NNS, RecordDataImpl &Record); + + /// \brief Emit a nested name specifier with source-location information. + void AddNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS, + RecordDataImpl &Record); + + /// \brief Emit a template name. + void AddTemplateName(TemplateName Name, RecordDataImpl &Record); + + /// \brief Emit a template argument. + void AddTemplateArgument(const TemplateArgument &Arg, RecordDataImpl &Record); + + /// \brief Emit a template parameter list. + void AddTemplateParameterList(const TemplateParameterList *TemplateParams, + RecordDataImpl &Record); + + /// \brief Emit a template argument list. + void AddTemplateArgumentList(const TemplateArgumentList *TemplateArgs, + RecordDataImpl &Record); + + /// \brief Emit a UnresolvedSet structure. + void AddUnresolvedSet(const UnresolvedSetImpl &Set, RecordDataImpl &Record); + + /// \brief Emit a C++ base specifier. + void AddCXXBaseSpecifier(const CXXBaseSpecifier &Base, + RecordDataImpl &Record); + + /// \brief Emit a CXXCtorInitializer array. + void AddCXXCtorInitializers( + const CXXCtorInitializer * const *CtorInitializers, + unsigned NumCtorInitializers, + RecordDataImpl &Record); + + void AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Record); + + /// \brief Add a string to the given record. + void AddString(StringRef Str, RecordDataImpl &Record); + + /// \brief Add a version tuple to the given record + void AddVersionTuple(const VersionTuple &Version, RecordDataImpl &Record); + + /// \brief Mark a declaration context as needing an update. + void AddUpdatedDeclContext(const DeclContext *DC) { + UpdatedDeclContexts.insert(DC); + } + + void RewriteDecl(const Decl *D) { + DeclsToRewrite.insert(D); + } + + bool isRewritten(const Decl *D) const { + return DeclsToRewrite.count(D); + } + + /// \brief Infer the submodule ID that contains an entity at the given + /// source location. + serialization::SubmoduleID inferSubmoduleIDFromLocation(SourceLocation Loc); + + /// \brief Note that the identifier II occurs at the given offset + /// within the identifier table. + void SetIdentifierOffset(const IdentifierInfo *II, uint32_t Offset); + + /// \brief Note that the selector Sel occurs at the given offset + /// within the method pool/selector table. + void SetSelectorOffset(Selector Sel, uint32_t Offset); + + /// \brief Add the given statement or expression to the queue of + /// statements to emit. + /// + /// This routine should be used when emitting types and declarations + /// that have expressions as part of their formulation. Once the + /// type or declaration has been written, call FlushStmts() to write + /// the corresponding statements just after the type or + /// declaration. + void AddStmt(Stmt *S) { + CollectedStmts->push_back(S); + } + + /// \brief Flush all of the statements and expressions that have + /// been added to the queue via AddStmt(). + void FlushStmts(); + + /// \brief Flush all of the C++ base specifier sets that have been added + /// via \c AddCXXBaseSpecifiersRef(). + void FlushCXXBaseSpecifiers(); + + /// \brief Record an ID for the given switch-case statement. + unsigned RecordSwitchCaseID(SwitchCase *S); + + /// \brief Retrieve the ID for the given switch-case statement. + unsigned getSwitchCaseID(SwitchCase *S); + + void ClearSwitchCaseIDs(); + + unsigned getDeclParmVarAbbrev() const { return DeclParmVarAbbrev; } + unsigned getDeclRefExprAbbrev() const { return DeclRefExprAbbrev; } + unsigned getCharacterLiteralAbbrev() const { return CharacterLiteralAbbrev; } + unsigned getDeclRecordAbbrev() const { return DeclRecordAbbrev; } + unsigned getIntegerLiteralAbbrev() const { return IntegerLiteralAbbrev; } + unsigned getDeclTypedefAbbrev() const { return DeclTypedefAbbrev; } + unsigned getDeclVarAbbrev() const { return DeclVarAbbrev; } + unsigned getDeclFieldAbbrev() const { return DeclFieldAbbrev; } + unsigned getDeclEnumAbbrev() const { return DeclEnumAbbrev; } + unsigned getDeclObjCIvarAbbrev() const { return DeclObjCIvarAbbrev; } + + bool hasChain() const { return Chain; } + + // ASTDeserializationListener implementation + void ReaderInitialized(ASTReader *Reader); + void IdentifierRead(serialization::IdentID ID, IdentifierInfo *II); + void TypeRead(serialization::TypeIdx Idx, QualType T); + void SelectorRead(serialization::SelectorID ID, Selector Sel); + void MacroDefinitionRead(serialization::PreprocessedEntityID ID, + MacroDefinition *MD); + void MacroVisible(IdentifierInfo *II); + void ModuleRead(serialization::SubmoduleID ID, Module *Mod); + + // ASTMutationListener implementation. + virtual void CompletedTagDefinition(const TagDecl *D); + virtual void AddedVisibleDecl(const DeclContext *DC, const Decl *D); + virtual void AddedCXXImplicitMember(const CXXRecordDecl *RD, const Decl *D); + virtual void AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD, + const ClassTemplateSpecializationDecl *D); + virtual void AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD, + const FunctionDecl *D); + virtual void CompletedImplicitDefinition(const FunctionDecl *D); + virtual void StaticDataMemberInstantiated(const VarDecl *D); + virtual void AddedObjCCategoryToInterface(const ObjCCategoryDecl *CatD, + const ObjCInterfaceDecl *IFD); + virtual void AddedObjCPropertyInClassExtension(const ObjCPropertyDecl *Prop, + const ObjCPropertyDecl *OrigProp, + const ObjCCategoryDecl *ClassExt); +}; + +/// \brief AST and semantic-analysis consumer that generates a +/// precompiled header from the parsed source code. +class PCHGenerator : public SemaConsumer { + const Preprocessor &PP; + std::string OutputFile; + clang::Module *Module; + std::string isysroot; + raw_ostream *Out; + Sema *SemaPtr; + MemorizeStatCalls *StatCalls; // owned by the FileManager + llvm::SmallVector<char, 128> Buffer; + llvm::BitstreamWriter Stream; + ASTWriter Writer; + +protected: + ASTWriter &getWriter() { return Writer; } + const ASTWriter &getWriter() const { return Writer; } + +public: + PCHGenerator(const Preprocessor &PP, StringRef OutputFile, + clang::Module *Module, + StringRef isysroot, raw_ostream *Out); + ~PCHGenerator(); + virtual void InitializeSema(Sema &S) { SemaPtr = &S; } + virtual void HandleTranslationUnit(ASTContext &Ctx); + virtual ASTMutationListener *GetASTMutationListener(); + virtual ASTDeserializationListener *GetASTDeserializationListener(); +}; + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Serialization/CMakeLists.txt b/clang/include/clang/Serialization/CMakeLists.txt new file mode 100644 index 0000000..d91513d --- /dev/null +++ b/clang/include/clang/Serialization/CMakeLists.txt @@ -0,0 +1,9 @@ +clang_tablegen(AttrPCHRead.inc -gen-clang-attr-pch-read + -I ${CMAKE_CURRENT_SOURCE_DIR}/../../ + SOURCE ../Basic/Attr.td + TARGET ClangAttrPCHRead) + +clang_tablegen(AttrPCHWrite.inc -gen-clang-attr-pch-write + -I ${CMAKE_CURRENT_SOURCE_DIR}/../../ + SOURCE ../Basic/Attr.td + TARGET ClangAttrPCHWrite) diff --git a/clang/include/clang/Serialization/ContinuousRangeMap.h b/clang/include/clang/Serialization/ContinuousRangeMap.h new file mode 100644 index 0000000..f368a80 --- /dev/null +++ b/clang/include/clang/Serialization/ContinuousRangeMap.h @@ -0,0 +1,130 @@ +//===--- ContinuousRangeMap.h - Map with int range as key -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ContinuousRangeMap class, which is a highly +// specialized container used by serialization. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SERIALIZATION_CONTINUOUS_RANGE_MAP_H +#define LLVM_CLANG_SERIALIZATION_CONTINUOUS_RANGE_MAP_H + +#include "llvm/ADT/SmallVector.h" +#include <algorithm> +#include <utility> + +namespace clang { + +/// \brief A map from continuous integer ranges to some value, with a very +/// specialized interface. +/// +/// CRM maps from integer ranges to values. The ranges are continuous, i.e. +/// where one ends, the next one begins. So if the map contains the stops I0-3, +/// the first range is from I0 to I1, the second from I1 to I2, the third from +/// I2 to I3 and the last from I3 to infinity. +/// +/// Ranges must be inserted in order. Inserting a new stop I4 into the map will +/// shrink the fourth range to I3 to I4 and add the new range I4 to inf. +template <typename Int, typename V, unsigned InitialCapacity> +class ContinuousRangeMap { +public: + typedef std::pair<Int, V> value_type; + typedef value_type &reference; + typedef const value_type &const_reference; + typedef value_type *pointer; + typedef const value_type *const_pointer; + +private: + typedef SmallVector<value_type, InitialCapacity> Representation; + Representation Rep; + + struct Compare { + bool operator ()(const_reference L, Int R) const { + return L.first < R; + } + bool operator ()(Int L, const_reference R) const { + return L < R.first; + } + bool operator ()(Int L, Int R) const { + return L < R; + } + bool operator ()(const_reference L, const_reference R) const { + return L.first < R.first; + } + }; + +public: + void insert(const value_type &Val) { + if (!Rep.empty() && Rep.back() == Val) + return; + + assert((Rep.empty() || Rep.back().first < Val.first) && + "Must insert keys in order."); + Rep.push_back(Val); + } + + void insertOrReplace(const value_type &Val) { + iterator I = std::lower_bound(Rep.begin(), Rep.end(), Val, Compare()); + if (I != Rep.end() && I->first == Val.first) { + I->second = Val.second; + return; + } + + Rep.insert(I, Val); + } + + typedef typename Representation::iterator iterator; + typedef typename Representation::const_iterator const_iterator; + + iterator begin() { return Rep.begin(); } + iterator end() { return Rep.end(); } + const_iterator begin() const { return Rep.begin(); } + const_iterator end() const { return Rep.end(); } + + iterator find(Int K) { + iterator I = std::upper_bound(Rep.begin(), Rep.end(), K, Compare()); + // I points to the first entry with a key > K, which is the range that + // follows the one containing K. + if (I == Rep.begin()) + return Rep.end(); + --I; + return I; + } + const_iterator find(Int K) const { + return const_cast<ContinuousRangeMap*>(this)->find(K); + } + + reference back() { return Rep.back(); } + const_reference back() const { return Rep.back(); } + + /// \brief An object that helps properly build a continuous range map + /// from a set of values. + class Builder { + ContinuousRangeMap &Self; + + Builder(const Builder&); // DO NOT IMPLEMENT + Builder &operator=(const Builder&); // DO NOT IMPLEMENT + + public: + explicit Builder(ContinuousRangeMap &Self) : Self(Self) { } + + ~Builder() { + std::sort(Self.Rep.begin(), Self.Rep.end(), Compare()); + } + + void insert(const value_type &Val) { + Self.Rep.push_back(Val); + } + }; + friend class Builder; +}; + +} + +#endif diff --git a/clang/include/clang/Serialization/Makefile b/clang/include/clang/Serialization/Makefile new file mode 100644 index 0000000..386f453 --- /dev/null +++ b/clang/include/clang/Serialization/Makefile @@ -0,0 +1,19 @@ +CLANG_LEVEL := ../../.. +TD_SRC_DIR = $(PROJ_SRC_DIR)/../Basic +BUILT_SOURCES = AttrPCHRead.inc AttrPCHWrite.inc + +TABLEGEN_INC_FILES_COMMON = 1 + +include $(CLANG_LEVEL)/Makefile + +$(ObjDir)/AttrPCHRead.inc.tmp : $(TD_SRC_DIR)/Attr.td $(CLANG_TBLGEN) \ + $(ObjDir)/.dir + $(Echo) "Building Clang PCH reader with tblgen" + $(Verb) $(ClangTableGen) -gen-clang-attr-pch-read -o $(call SYSPATH, $@) \ + -I $(PROJ_SRC_DIR)/../../ $< + +$(ObjDir)/AttrPCHWrite.inc.tmp : $(TD_SRC_DIR)/Attr.td $(CLANG_TBLGEN) \ + $(ObjDir)/.dir + $(Echo) "Building Clang PCH writer with tblgen" + $(Verb) $(ClangTableGen) -gen-clang-attr-pch-write -o $(call SYSPATH, $@) \ + -I $(PROJ_SRC_DIR)/../../ $< diff --git a/clang/include/clang/Serialization/Module.h b/clang/include/clang/Serialization/Module.h new file mode 100644 index 0000000..786ecd3 --- /dev/null +++ b/clang/include/clang/Serialization/Module.h @@ -0,0 +1,364 @@ +//===--- Module.h - Module description --------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Module class, which describes a module that has +// been loaded from an AST file. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SERIALIZATION_MODULE_H +#define LLVM_CLANG_SERIALIZATION_MODULE_H + +#include "clang/Serialization/ASTBitCodes.h" +#include "clang/Serialization/ContinuousRangeMap.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/Bitcode/BitstreamReader.h" +#include <string> + +namespace clang { + +class DeclContext; +class Module; +template<typename Info> class OnDiskChainedHashTable; + +namespace serialization { + +namespace reader { + class ASTDeclContextNameLookupTrait; +} + +/// \brief Specifies the kind of module that has been loaded. +enum ModuleKind { + MK_Module, ///< File is a module proper. + MK_PCH, ///< File is a PCH file treated as such. + MK_Preamble, ///< File is a PCH file treated as the preamble. + MK_MainFile ///< File is a PCH file treated as the actual main file. +}; + +/// \brief Information about the contents of a DeclContext. +struct DeclContextInfo { + DeclContextInfo() + : NameLookupTableData(), LexicalDecls(), NumLexicalDecls() {} + + OnDiskChainedHashTable<reader::ASTDeclContextNameLookupTrait> + *NameLookupTableData; // an ASTDeclContextNameLookupTable. + const KindDeclIDPair *LexicalDecls; + unsigned NumLexicalDecls; +}; + +/// \brief Information about a module that has been loaded by the ASTReader. +/// +/// Each instance of the Module class corresponds to a single AST file, which +/// may be a precompiled header, precompiled preamble, a module, or an AST file +/// of some sort loaded as the main file, all of which are specific formulations +/// of the general notion of a "module". A module may depend on any number of +/// other modules. +class ModuleFile { +public: + ModuleFile(ModuleKind Kind, unsigned Generation); + ~ModuleFile(); + + // === General information === + + /// \brief The type of this module. + ModuleKind Kind; + + /// \brief The file name of the module file. + std::string FileName; + + /// \brief Whether this module has been directly imported by the + /// user. + bool DirectlyImported; + + /// \brief The generation of which this module file is a part. + unsigned Generation; + + /// \brief The memory buffer that stores the data associated with + /// this AST file. + OwningPtr<llvm::MemoryBuffer> Buffer; + + /// \brief The size of this file, in bits. + uint64_t SizeInBits; + + /// \brief The global bit offset (or base) of this module + uint64_t GlobalBitOffset; + + /// \brief The bitstream reader from which we'll read the AST file. + llvm::BitstreamReader StreamFile; + + /// \brief The main bitstream cursor for the main block. + llvm::BitstreamCursor Stream; + + /// \brief The source location where this module was first imported. + SourceLocation ImportLoc; + + /// \brief The first source location in this module. + SourceLocation FirstLoc; + + // === Source Locations === + + /// \brief Cursor used to read source location entries. + llvm::BitstreamCursor SLocEntryCursor; + + /// \brief The number of source location entries in this AST file. + unsigned LocalNumSLocEntries; + + /// \brief The base ID in the source manager's view of this module. + int SLocEntryBaseID; + + /// \brief The base offset in the source manager's view of this module. + unsigned SLocEntryBaseOffset; + + /// \brief Offsets for all of the source location entries in the + /// AST file. + const uint32_t *SLocEntryOffsets; + + /// \brief SLocEntries that we're going to preload. + SmallVector<uint64_t, 4> PreloadSLocEntries; + + /// \brief The number of source location file entries in this AST file. + unsigned LocalNumSLocFileEntries; + + /// \brief Offsets for all of the source location file entries in the + /// AST file. + const uint32_t *SLocFileOffsets; + + /// \brief Remapping table for source locations in this module. + ContinuousRangeMap<uint32_t, int, 2> SLocRemap; + + // === Identifiers === + + /// \brief The number of identifiers in this AST file. + unsigned LocalNumIdentifiers; + + /// \brief Offsets into the identifier table data. + /// + /// This array is indexed by the identifier ID (-1), and provides + /// the offset into IdentifierTableData where the string data is + /// stored. + const uint32_t *IdentifierOffsets; + + /// \brief Base identifier ID for identifiers local to this module. + serialization::IdentID BaseIdentifierID; + + /// \brief Remapping table for identifier IDs in this module. + ContinuousRangeMap<uint32_t, int, 2> IdentifierRemap; + + /// \brief Actual data for the on-disk hash table of identifiers. + /// + /// This pointer points into a memory buffer, where the on-disk hash + /// table for identifiers actually lives. + const char *IdentifierTableData; + + /// \brief A pointer to an on-disk hash table of opaque type + /// IdentifierHashTable. + void *IdentifierLookupTable; + + // === Macros === + + /// \brief The cursor to the start of the preprocessor block, which stores + /// all of the macro definitions. + llvm::BitstreamCursor MacroCursor; + + /// \brief The offset of the start of the set of defined macros. + uint64_t MacroStartOffset; + + // === Detailed PreprocessingRecord === + + /// \brief The cursor to the start of the (optional) detailed preprocessing + /// record block. + llvm::BitstreamCursor PreprocessorDetailCursor; + + /// \brief The offset of the start of the preprocessor detail cursor. + uint64_t PreprocessorDetailStartOffset; + + /// \brief Base preprocessed entity ID for preprocessed entities local to + /// this module. + serialization::PreprocessedEntityID BasePreprocessedEntityID; + + /// \brief Remapping table for preprocessed entity IDs in this module. + ContinuousRangeMap<uint32_t, int, 2> PreprocessedEntityRemap; + + const PPEntityOffset *PreprocessedEntityOffsets; + unsigned NumPreprocessedEntities; + + // === Header search information === + + /// \brief The number of local HeaderFileInfo structures. + unsigned LocalNumHeaderFileInfos; + + /// \brief Actual data for the on-disk hash table of header file + /// information. + /// + /// This pointer points into a memory buffer, where the on-disk hash + /// table for header file information actually lives. + const char *HeaderFileInfoTableData; + + /// \brief The on-disk hash table that contains information about each of + /// the header files. + void *HeaderFileInfoTable; + + /// \brief Actual data for the list of framework names used in the header + /// search information. + const char *HeaderFileFrameworkStrings; + + // === Submodule information === + /// \brief The number of submodules in this module. + unsigned LocalNumSubmodules; + + /// \brief Base submodule ID for submodules local to this module. + serialization::SubmoduleID BaseSubmoduleID; + + /// \brief Remapping table for submodule IDs in this module. + ContinuousRangeMap<uint32_t, int, 2> SubmoduleRemap; + + // === Selectors === + + /// \brief The number of selectors new to this file. + /// + /// This is the number of entries in SelectorOffsets. + unsigned LocalNumSelectors; + + /// \brief Offsets into the selector lookup table's data array + /// where each selector resides. + const uint32_t *SelectorOffsets; + + /// \brief Base selector ID for selectors local to this module. + serialization::SelectorID BaseSelectorID; + + /// \brief Remapping table for selector IDs in this module. + ContinuousRangeMap<uint32_t, int, 2> SelectorRemap; + + /// \brief A pointer to the character data that comprises the selector table + /// + /// The SelectorOffsets table refers into this memory. + const unsigned char *SelectorLookupTableData; + + /// \brief A pointer to an on-disk hash table of opaque type + /// ASTSelectorLookupTable. + /// + /// This hash table provides the IDs of all selectors, and the associated + /// instance and factory methods. + void *SelectorLookupTable; + + // === Declarations === + + /// DeclsCursor - This is a cursor to the start of the DECLS_BLOCK block. It + /// has read all the abbreviations at the start of the block and is ready to + /// jump around with these in context. + llvm::BitstreamCursor DeclsCursor; + + /// \brief The number of declarations in this AST file. + unsigned LocalNumDecls; + + /// \brief Offset of each declaration within the bitstream, indexed + /// by the declaration ID (-1). + const DeclOffset *DeclOffsets; + + /// \brief Base declaration ID for declarations local to this module. + serialization::DeclID BaseDeclID; + + /// \brief Remapping table for declaration IDs in this module. + ContinuousRangeMap<uint32_t, int, 2> DeclRemap; + + /// \brief Mapping from the module files that this module file depends on + /// to the base declaration ID for that module as it is understood within this + /// module. + /// + /// This is effectively a reverse global-to-local mapping for declaration + /// IDs, so that we can interpret a true global ID (for this translation unit) + /// as a local ID (for this module file). + llvm::DenseMap<ModuleFile *, serialization::DeclID> GlobalToLocalDeclIDs; + + /// \brief The number of C++ base specifier sets in this AST file. + unsigned LocalNumCXXBaseSpecifiers; + + /// \brief Offset of each C++ base specifier set within the bitstream, + /// indexed by the C++ base specifier set ID (-1). + const uint32_t *CXXBaseSpecifiersOffsets; + + typedef llvm::DenseMap<const DeclContext *, DeclContextInfo> + DeclContextInfosMap; + + /// \brief Information about the lexical and visible declarations + /// for each DeclContext. + DeclContextInfosMap DeclContextInfos; + + /// \brief Array of file-level DeclIDs sorted by file. + const serialization::DeclID *FileSortedDecls; + + /// \brief Array of redeclaration chain location information within this + /// module file, sorted by the first declaration ID. + const serialization::LocalRedeclarationsInfo *RedeclarationsMap; + + /// \brief The number of redeclaration info entries in RedeclarationsMap. + unsigned LocalNumRedeclarationsInMap; + + /// \brief The redeclaration chains for declarations local to this + /// module file. + SmallVector<uint64_t, 1> RedeclarationChains; + + /// \brief Array of category list location information within this + /// module file, sorted by the definition ID. + const serialization::ObjCCategoriesInfo *ObjCCategoriesMap; + + /// \brief The number of redeclaration info entries in ObjCCategoriesMap. + unsigned LocalNumObjCCategoriesInMap; + + /// \brief The Objective-C category lists for categories known to this + /// module. + SmallVector<uint64_t, 1> ObjCCategories; + + // === Types === + + /// \brief The number of types in this AST file. + unsigned LocalNumTypes; + + /// \brief Offset of each type within the bitstream, indexed by the + /// type ID, or the representation of a Type*. + const uint32_t *TypeOffsets; + + /// \brief Base type ID for types local to this module as represented in + /// the global type ID space. + serialization::TypeID BaseTypeIndex; + + /// \brief Remapping table for type IDs in this module. + ContinuousRangeMap<uint32_t, int, 2> TypeRemap; + + // === Miscellaneous === + + /// \brief Diagnostic IDs and their mappings that the user changed. + SmallVector<uint64_t, 8> PragmaDiagMappings; + + /// \brief The AST stat cache installed for this file, if any. + /// + /// The dynamic type of this stat cache is always ASTStatCache + void *StatCache; + + /// \brief List of modules which depend on this module + llvm::SetVector<ModuleFile *> ImportedBy; + + /// \brief List of modules which this module depends on + llvm::SetVector<ModuleFile *> Imports; + + /// \brief Determine whether this module was directly imported at + /// any point during translation. + bool isDirectlyImported() const { return DirectlyImported; } + + /// \brief Dump debugging output for this module. + void dump(); +}; + +} // end namespace serialization + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Serialization/ModuleManager.h b/clang/include/clang/Serialization/ModuleManager.h new file mode 100644 index 0000000..6ff0640 --- /dev/null +++ b/clang/include/clang/Serialization/ModuleManager.h @@ -0,0 +1,158 @@ +//===--- ModuleManager.cpp - Module Manager ---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ModuleManager class, which manages a set of loaded +// modules for the ASTReader. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SERIALIZATION_MODULE_MANAGER_H +#define LLVM_CLANG_SERIALIZATION_MODULE_MANAGER_H + +#include "clang/Serialization/Module.h" +#include "clang/Basic/FileManager.h" +#include "llvm/ADT/DenseMap.h" + +namespace clang { + +namespace serialization { + +/// \brief Manages the set of modules loaded by an AST reader. +class ModuleManager { + /// \brief The chain of AST files. The first entry is the one named by the + /// user, the last one is the one that doesn't depend on anything further. + llvm::SmallVector<ModuleFile*, 2> Chain; + + /// \brief All loaded modules, indexed by name. + llvm::DenseMap<const FileEntry *, ModuleFile *> Modules; + + /// \brief FileManager that handles translating between filenames and + /// FileEntry *. + FileManager FileMgr; + + /// \brief A lookup of in-memory (virtual file) buffers + llvm::DenseMap<const FileEntry *, llvm::MemoryBuffer *> InMemoryBuffers; + +public: + typedef SmallVector<ModuleFile*, 2>::iterator ModuleIterator; + typedef SmallVector<ModuleFile*, 2>::const_iterator ModuleConstIterator; + typedef SmallVector<ModuleFile*, 2>::reverse_iterator ModuleReverseIterator; + typedef std::pair<uint32_t, StringRef> ModuleOffset; + + ModuleManager(const FileSystemOptions &FSO); + ~ModuleManager(); + + /// \brief Forward iterator to traverse all loaded modules. This is reverse + /// source-order. + ModuleIterator begin() { return Chain.begin(); } + /// \brief Forward iterator end-point to traverse all loaded modules + ModuleIterator end() { return Chain.end(); } + + /// \brief Const forward iterator to traverse all loaded modules. This is + /// in reverse source-order. + ModuleConstIterator begin() const { return Chain.begin(); } + /// \brief Const forward iterator end-point to traverse all loaded modules + ModuleConstIterator end() const { return Chain.end(); } + + /// \brief Reverse iterator to traverse all loaded modules. This is in + /// source order. + ModuleReverseIterator rbegin() { return Chain.rbegin(); } + /// \brief Reverse iterator end-point to traverse all loaded modules. + ModuleReverseIterator rend() { return Chain.rend(); } + + /// \brief Returns the primary module associated with the manager, that is, + /// the first module loaded + ModuleFile &getPrimaryModule() { return *Chain[0]; } + + /// \brief Returns the primary module associated with the manager, that is, + /// the first module loaded. + ModuleFile &getPrimaryModule() const { return *Chain[0]; } + + /// \brief Returns the module associated with the given index + ModuleFile &operator[](unsigned Index) const { return *Chain[Index]; } + + /// \brief Returns the module associated with the given name + ModuleFile *lookup(StringRef Name); + + /// \brief Returns the in-memory (virtual file) buffer with the given name + llvm::MemoryBuffer *lookupBuffer(StringRef Name); + + /// \brief Number of modules loaded + unsigned size() const { return Chain.size(); } + /// \brief Attempts to create a new module and add it to the list of known + /// modules. + /// + /// \param FileName The file name of the module to be loaded. + /// + /// \param Type The kind of module being loaded. + /// + /// \param ImportedBy The module that is importing this module, or NULL if + /// this module is imported directly by the user. + /// + /// \param Generation The generation in which this module was loaded. + /// + /// \param ErrorStr Will be set to a non-empty string if any errors occurred + /// while trying to load the module. + /// + /// \return A pointer to the module that corresponds to this file name, + /// and a boolean indicating whether the module was newly added. + std::pair<ModuleFile *, bool> + addModule(StringRef FileName, ModuleKind Type, ModuleFile *ImportedBy, + unsigned Generation, std::string &ErrorStr); + + /// \brief Add an in-memory buffer the list of known buffers + void addInMemoryBuffer(StringRef FileName, llvm::MemoryBuffer *Buffer); + + /// \brief Visit each of the modules. + /// + /// This routine visits each of the modules, starting with the + /// "root" modules that no other loaded modules depend on, and + /// proceeding to the leaf modules, visiting each module only once + /// during the traversal. + /// + /// This traversal is intended to support various "lookup" + /// operations that can find data in any of the loaded modules. + /// + /// \param Visitor A visitor function that will be invoked with each + /// module and the given user data pointer. The return value must be + /// convertible to bool; when false, the visitation continues to + /// modules that the current module depends on. When true, the + /// visitation skips any modules that the current module depends on. + /// + /// \param UserData User data associated with the visitor object, which + /// will be passed along to the visitor. + void visit(bool (*Visitor)(ModuleFile &M, void *UserData), void *UserData); + + /// \brief Visit each of the modules with a depth-first traversal. + /// + /// This routine visits each of the modules known to the module + /// manager using a depth-first search, starting with the first + /// loaded module. The traversal invokes the callback both before + /// traversing the children (preorder traversal) and after + /// traversing the children (postorder traversal). + /// + /// \param Visitor A visitor function that will be invoked with each + /// module and given a \c Preorder flag that indicates whether we're + /// visiting the module before or after visiting its children. The + /// visitor may return true at any time to abort the depth-first + /// visitation. + /// + /// \param UserData User data ssociated with the visitor object, + /// which will be passed along to the user. + void visitDepthFirst(bool (*Visitor)(ModuleFile &M, bool Preorder, + void *UserData), + void *UserData); + + /// \brief View the graphviz representation of the module graph. + void viewGraph(); +}; + +} } // end namespace clang::serialization + +#endif diff --git a/clang/include/clang/Serialization/SerializationDiagnostic.h b/clang/include/clang/Serialization/SerializationDiagnostic.h new file mode 100644 index 0000000..e63f814 --- /dev/null +++ b/clang/include/clang/Serialization/SerializationDiagnostic.h @@ -0,0 +1,28 @@ +//===--- SerializationDiagnostic.h - Serialization Diagnostics -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SERIALIZATIONDIAGNOSTIC_H +#define LLVM_CLANG_SERIALIZATIONDIAGNOSTIC_H + +#include "clang/Basic/Diagnostic.h" + +namespace clang { + namespace diag { + enum { +#define DIAG(ENUM,FLAGS,DEFAULT_MAPPING,DESC,GROUP,\ + SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,CATEGORY) ENUM, +#define SERIALIZATIONSTART +#include "clang/Basic/DiagnosticSerializationKinds.inc" +#undef DIAG + NUM_BUILTIN_SERIALIZATION_DIAGNOSTICS + }; + } // end namespace diag +} // end namespace clang + +#endif diff --git a/clang/include/clang/StaticAnalyzer/Checkers/CheckerBase.td b/clang/include/clang/StaticAnalyzer/Checkers/CheckerBase.td new file mode 100644 index 0000000..11f1e5d --- /dev/null +++ b/clang/include/clang/StaticAnalyzer/Checkers/CheckerBase.td @@ -0,0 +1,39 @@ +//===--- CheckerBase.td - Checker TableGen classes ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the TableGen core definitions for checkers +// +//===----------------------------------------------------------------------===// + +class CheckerGroup<string name> { + string GroupName = name; +} +class InGroup<CheckerGroup G> { CheckerGroup Group = G; } + +class Package<string name> { + string PackageName = name; + bit Hidden = 0; + Package ParentPackage; + CheckerGroup Group; +} +class InPackage<Package P> { Package ParentPackage = P; } + +// All checkers are an indirect subclass of this. +class Checker<string name = ""> { + string CheckerName = name; + string DescFile; + string HelpText; + bit Hidden = 0; + Package ParentPackage; + CheckerGroup Group; +} + +class DescFile<string filename> { string DescFile = filename; } +class HelpText<string text> { string HelpText = text; } +class Hidden { bit Hidden = 1; } diff --git a/clang/include/clang/StaticAnalyzer/Checkers/ClangCheckers.h b/clang/include/clang/StaticAnalyzer/Checkers/ClangCheckers.h new file mode 100644 index 0000000..cf0a30a --- /dev/null +++ b/clang/include/clang/StaticAnalyzer/Checkers/ClangCheckers.h @@ -0,0 +1,22 @@ +//===--- ClangCheckers.h - Provides builtin checkers ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_CHECKERS_CLANGCHECKERS_H +#define LLVM_CLANG_STATICANALYZER_CHECKERS_CLANGCHECKERS_H + +namespace clang { +namespace ento { +class CheckerRegistry; + +void registerBuiltinCheckers(CheckerRegistry ®istry); + +} // end namespace ento +} // end namespace clang + +#endif diff --git a/clang/include/clang/StaticAnalyzer/Checkers/CommonBugCategories.h b/clang/include/clang/StaticAnalyzer/Checkers/CommonBugCategories.h new file mode 100644 index 0000000..9d4251b --- /dev/null +++ b/clang/include/clang/StaticAnalyzer/Checkers/CommonBugCategories.h @@ -0,0 +1,24 @@ +//=--- CommonBugCategories.h - Provides common issue categories -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATIC_ANALYZER_CHECKER_CATEGORIES_H +#define LLVM_CLANG_STATIC_ANALYZER_CHECKER_CATEGORIES_H + +// Common strings used for the "category" of many static analyzer issues. +namespace clang { + namespace ento { + namespace categories { + extern const char *CoreFoundationObjectiveC; + extern const char *MemoryCoreFoundationObjectiveC; + extern const char *UnixAPI; + } + } +} +#endif + diff --git a/clang/include/clang/StaticAnalyzer/Checkers/DereferenceChecker.h b/clang/include/clang/StaticAnalyzer/Checkers/DereferenceChecker.h new file mode 100644 index 0000000..f9cce9c --- /dev/null +++ b/clang/include/clang/StaticAnalyzer/Checkers/DereferenceChecker.h @@ -0,0 +1,35 @@ +//== NullDerefChecker.h - Null dereference checker --------------*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This defines NullDerefChecker and UndefDerefChecker, two builtin checks +// in ExprEngine that check for null and undefined pointers at loads +// and stores. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_GR_DEREFCHECKER +#define LLVM_CLANG_GR_DEREFCHECKER + +#include <utility> + +namespace clang { + +namespace ento { + +class ExprEngine; +class ExplodedNode; + +std::pair<ExplodedNode * const *, ExplodedNode * const *> +GetImplicitNullDereferences(ExprEngine &Eng); + +} // end GR namespace + +} // end clang namespace + +#endif diff --git a/clang/include/clang/StaticAnalyzer/Checkers/LocalCheckers.h b/clang/include/clang/StaticAnalyzer/Checkers/LocalCheckers.h new file mode 100644 index 0000000..eee38e9 --- /dev/null +++ b/clang/include/clang/StaticAnalyzer/Checkers/LocalCheckers.h @@ -0,0 +1,28 @@ +//==- LocalCheckers.h - Intra-Procedural+Flow-Sensitive Checkers -*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the interface to call a set of intra-procedural (local) +// checkers that use flow/path-sensitive analyses to find bugs. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_GR_LOCALCHECKERS_H +#define LLVM_CLANG_GR_LOCALCHECKERS_H + +namespace clang { +namespace ento { + +class ExprEngine; + +void RegisterCallInliner(ExprEngine &Eng); + +} // end namespace ento +} // end namespace clang + +#endif diff --git a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h new file mode 100644 index 0000000..2b699a8 --- /dev/null +++ b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h @@ -0,0 +1,453 @@ +//===--- BugReporter.h - Generate PathDiagnostics --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines BugReporter, a utility class for generating +// PathDiagnostics for analyses based on ProgramState. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_GR_BUGREPORTER +#define LLVM_CLANG_GR_BUGREPORTER + +#include "clang/Basic/SourceLocation.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h" +#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/ilist.h" +#include "llvm/ADT/ilist_node.h" +#include "llvm/ADT/ImmutableSet.h" +#include "llvm/ADT/DenseSet.h" + +namespace clang { + +class ASTContext; +class DiagnosticsEngine; +class Stmt; +class ParentMap; + +namespace ento { + +class PathDiagnostic; +class ExplodedNode; +class ExplodedGraph; +class BugReport; +class BugReporter; +class BugReporterContext; +class ExprEngine; +class BugType; + +//===----------------------------------------------------------------------===// +// Interface for individual bug reports. +//===----------------------------------------------------------------------===// + +/// This class provides an interface through which checkers can create +/// individual bug reports. +class BugReport : public llvm::ilist_node<BugReport> { +public: + class NodeResolver { + virtual void anchor(); + public: + virtual ~NodeResolver() {} + virtual const ExplodedNode* + getOriginalNode(const ExplodedNode *N) = 0; + }; + + typedef const SourceRange *ranges_iterator; + typedef SmallVector<BugReporterVisitor *, 8> VisitorList; + typedef VisitorList::iterator visitor_iterator; + typedef SmallVector<StringRef, 2> ExtraTextList; + +protected: + friend class BugReporter; + friend class BugReportEquivClass; + + BugType& BT; + const Decl *DeclWithIssue; + std::string ShortDescription; + std::string Description; + PathDiagnosticLocation Location; + PathDiagnosticLocation UniqueingLocation; + const ExplodedNode *ErrorNode; + SmallVector<SourceRange, 4> Ranges; + ExtraTextList ExtraText; + + typedef llvm::DenseSet<SymbolRef> Symbols; + typedef llvm::DenseSet<const MemRegion *> Regions; + + /// A set of symbols that are registered with this report as being + /// "interesting", and thus used to help decide which diagnostics + /// to include when constructing the final path diagnostic. + Symbols interestingSymbols; + + /// A set of regions that are registered with this report as being + /// "interesting", and thus used to help decide which diagnostics + /// to include when constructing the final path diagnostic. + Regions interestingRegions; + + /// A set of custom visitors which generate "event" diagnostics at + /// interesting points in the path. + VisitorList Callbacks; + + /// Used for ensuring the visitors are only added once. + llvm::FoldingSet<BugReporterVisitor> CallbacksSet; + + /// Used for clients to tell if the report's configuration has changed + /// since the last time they checked. + unsigned ConfigurationChangeToken; + +public: + BugReport(BugType& bt, StringRef desc, const ExplodedNode *errornode) + : BT(bt), DeclWithIssue(0), Description(desc), ErrorNode(errornode), + ConfigurationChangeToken(0) {} + + BugReport(BugType& bt, StringRef shortDesc, StringRef desc, + const ExplodedNode *errornode) + : BT(bt), DeclWithIssue(0), ShortDescription(shortDesc), Description(desc), + ErrorNode(errornode), ConfigurationChangeToken(0) {} + + BugReport(BugType& bt, StringRef desc, PathDiagnosticLocation l) + : BT(bt), DeclWithIssue(0), Description(desc), Location(l), ErrorNode(0), + ConfigurationChangeToken(0) {} + + /// \brief Create a BugReport with a custom uniqueing location. + /// + /// The reports that have the same report location, description, bug type, and + /// ranges are uniqued - only one of the equivalent reports will be presented + /// to the user. This method allows to rest the location which should be used + /// for uniquing reports. For example, memory leaks checker, could set this to + /// the allocation site, rather then the location where the bug is reported. + BugReport(BugType& bt, StringRef desc, const ExplodedNode *errornode, + PathDiagnosticLocation LocationToUnique) + : BT(bt), DeclWithIssue(0), Description(desc), + UniqueingLocation(LocationToUnique), + ErrorNode(errornode), ConfigurationChangeToken(0) {} + + virtual ~BugReport(); + + const BugType& getBugType() const { return BT; } + BugType& getBugType() { return BT; } + + const ExplodedNode *getErrorNode() const { return ErrorNode; } + + const StringRef getDescription() const { return Description; } + + const StringRef getShortDescription() const { + return ShortDescription.empty() ? Description : ShortDescription; + } + + void markInteresting(SymbolRef sym); + void markInteresting(const MemRegion *R); + void markInteresting(SVal V); + + bool isInteresting(SymbolRef sym) const; + bool isInteresting(const MemRegion *R) const; + bool isInteresting(SVal V) const; + + unsigned getConfigurationChangeToken() const { + return ConfigurationChangeToken; + } + + /// Return the canonical declaration, be it a method or class, where + /// this issue semantically occurred. + const Decl *getDeclWithIssue() const; + + /// Specifically set the Decl where an issue occurred. This isn't necessary + /// for BugReports that cover a path as it will be automatically inferred. + void setDeclWithIssue(const Decl *declWithIssue) { + DeclWithIssue = declWithIssue; + } + + /// \brief This allows for addition of meta data to the diagnostic. + /// + /// Currently, only the HTMLDiagnosticClient knows how to display it. + void addExtraText(StringRef S) { + ExtraText.push_back(S); + } + + virtual const ExtraTextList &getExtraText() { + return ExtraText; + } + + /// \brief Return the "definitive" location of the reported bug. + /// + /// While a bug can span an entire path, usually there is a specific + /// location that can be used to identify where the key issue occurred. + /// This location is used by clients rendering diagnostics. + virtual PathDiagnosticLocation getLocation(const SourceManager &SM) const; + + const Stmt *getStmt() const; + + /// \brief Add a range to a bug report. + /// + /// Ranges are used to highlight regions of interest in the source code. + /// They should be at the same source code line as the BugReport location. + /// By default, the source range of the statement corresponding to the error + /// node will be used; add a single invalid range to specify absence of + /// ranges. + void addRange(SourceRange R) { + assert((R.isValid() || Ranges.empty()) && "Invalid range can only be used " + "to specify that the report does not have a range."); + Ranges.push_back(R); + } + + /// \brief Get the SourceRanges associated with the report. + virtual std::pair<ranges_iterator, ranges_iterator> getRanges(); + + /// \brief Add custom or predefined bug report visitors to this report. + /// + /// The visitors should be used when the default trace is not sufficient. + /// For example, they allow constructing a more elaborate trace. + /// \sa registerConditionVisitor(), registerTrackNullOrUndefValue(), + /// registerFindLastStore(), registerNilReceiverVisitor(), and + /// registerVarDeclsLastStore(). + void addVisitor(BugReporterVisitor *visitor); + + /// Iterators through the custom diagnostic visitors. + visitor_iterator visitor_begin() { return Callbacks.begin(); } + visitor_iterator visitor_end() { return Callbacks.end(); } + + /// Profile to identify equivalent bug reports for error report coalescing. + /// Reports are uniqued to ensure that we do not emit multiple diagnostics + /// for each bug. + virtual void Profile(llvm::FoldingSetNodeID& hash) const; +}; + +} // end ento namespace +} // end clang namespace + +namespace llvm { + template<> struct ilist_traits<clang::ento::BugReport> + : public ilist_default_traits<clang::ento::BugReport> { + clang::ento::BugReport *createSentinel() const { + return static_cast<clang::ento::BugReport *>(&Sentinel); + } + void destroySentinel(clang::ento::BugReport *) const {} + + clang::ento::BugReport *provideInitialHead() const { + return createSentinel(); + } + clang::ento::BugReport *ensureHead(clang::ento::BugReport *) const { + return createSentinel(); + } + private: + mutable ilist_half_node<clang::ento::BugReport> Sentinel; + }; +} + +namespace clang { +namespace ento { + +//===----------------------------------------------------------------------===// +// BugTypes (collections of related reports). +//===----------------------------------------------------------------------===// + +class BugReportEquivClass : public llvm::FoldingSetNode { + /// List of *owned* BugReport objects. + llvm::ilist<BugReport> Reports; + + friend class BugReporter; + void AddReport(BugReport* R) { Reports.push_back(R); } +public: + BugReportEquivClass(BugReport* R) { Reports.push_back(R); } + ~BugReportEquivClass(); + + void Profile(llvm::FoldingSetNodeID& ID) const { + assert(!Reports.empty()); + Reports.front().Profile(ID); + } + + typedef llvm::ilist<BugReport>::iterator iterator; + typedef llvm::ilist<BugReport>::const_iterator const_iterator; + + iterator begin() { return Reports.begin(); } + iterator end() { return Reports.end(); } + + const_iterator begin() const { return Reports.begin(); } + const_iterator end() const { return Reports.end(); } +}; + +//===----------------------------------------------------------------------===// +// BugReporter and friends. +//===----------------------------------------------------------------------===// + +class BugReporterData { +public: + virtual ~BugReporterData(); + virtual DiagnosticsEngine& getDiagnostic() = 0; + virtual PathDiagnosticConsumer* getPathDiagnosticConsumer() = 0; + virtual ASTContext &getASTContext() = 0; + virtual SourceManager& getSourceManager() = 0; +}; + +/// BugReporter is a utility class for generating PathDiagnostics for analysis. +/// It collects the BugReports and BugTypes and knows how to generate +/// and flush the corresponding diagnostics. +class BugReporter { +public: + enum Kind { BaseBRKind, GRBugReporterKind }; + +private: + typedef llvm::ImmutableSet<BugType*> BugTypesTy; + BugTypesTy::Factory F; + BugTypesTy BugTypes; + + const Kind kind; + BugReporterData& D; + + /// Generate and flush the diagnostics for the given bug report. + void FlushReport(BugReportEquivClass& EQ); + + /// The set of bug reports tracked by the BugReporter. + llvm::FoldingSet<BugReportEquivClass> EQClasses; + /// A vector of BugReports for tracking the allocated pointers and cleanup. + std::vector<BugReportEquivClass *> EQClassesVector; + +protected: + BugReporter(BugReporterData& d, Kind k) : BugTypes(F.getEmptySet()), kind(k), + D(d) {} + +public: + BugReporter(BugReporterData& d) : BugTypes(F.getEmptySet()), kind(BaseBRKind), + D(d) {} + virtual ~BugReporter(); + + /// \brief Generate and flush diagnostics for all bug reports. + void FlushReports(); + + Kind getKind() const { return kind; } + + DiagnosticsEngine& getDiagnostic() { + return D.getDiagnostic(); + } + + PathDiagnosticConsumer* getPathDiagnosticConsumer() { + return D.getPathDiagnosticConsumer(); + } + + /// \brief Iterator over the set of BugTypes tracked by the BugReporter. + typedef BugTypesTy::iterator iterator; + iterator begin() { return BugTypes.begin(); } + iterator end() { return BugTypes.end(); } + + /// \brief Iterator over the set of BugReports tracked by the BugReporter. + typedef llvm::FoldingSet<BugReportEquivClass>::iterator EQClasses_iterator; + EQClasses_iterator EQClasses_begin() { return EQClasses.begin(); } + EQClasses_iterator EQClasses_end() { return EQClasses.end(); } + + ASTContext &getContext() { return D.getASTContext(); } + + SourceManager& getSourceManager() { return D.getSourceManager(); } + + virtual void GeneratePathDiagnostic(PathDiagnostic& pathDiagnostic, + SmallVectorImpl<BugReport *> &bugReports) {} + + void Register(BugType *BT); + + /// \brief Add the given report to the set of reports tracked by BugReporter. + /// + /// The reports are usually generated by the checkers. Further, they are + /// folded based on the profile value, which is done to coalesce similar + /// reports. + void EmitReport(BugReport *R); + + void EmitBasicReport(const Decl *DeclWithIssue, + StringRef BugName, StringRef BugCategory, + StringRef BugStr, PathDiagnosticLocation Loc, + SourceRange* RangeBeg, unsigned NumRanges); + + void EmitBasicReport(const Decl *DeclWithIssue, + StringRef BugName, StringRef BugCategory, + StringRef BugStr, PathDiagnosticLocation Loc) { + EmitBasicReport(DeclWithIssue, BugName, BugCategory, BugStr, Loc, 0, 0); + } + + void EmitBasicReport(const Decl *DeclWithIssue, + StringRef BugName, StringRef Category, + StringRef BugStr, PathDiagnosticLocation Loc, + SourceRange R) { + EmitBasicReport(DeclWithIssue, BugName, Category, BugStr, Loc, &R, 1); + } + + static bool classof(const BugReporter* R) { return true; } + +private: + llvm::StringMap<BugType *> StrBugTypes; + + /// \brief Returns a BugType that is associated with the given name and + /// category. + BugType *getBugTypeForName(StringRef name, StringRef category); +}; + +// FIXME: Get rid of GRBugReporter. It's the wrong abstraction. +class GRBugReporter : public BugReporter { + ExprEngine& Eng; +public: + GRBugReporter(BugReporterData& d, ExprEngine& eng) + : BugReporter(d, GRBugReporterKind), Eng(eng) {} + + virtual ~GRBugReporter(); + + /// getEngine - Return the analysis engine used to analyze a given + /// function or method. + ExprEngine &getEngine() { return Eng; } + + /// getGraph - Get the exploded graph created by the analysis engine + /// for the analyzed method or function. + ExplodedGraph &getGraph(); + + /// getStateManager - Return the state manager used by the analysis + /// engine. + ProgramStateManager &getStateManager(); + + virtual void GeneratePathDiagnostic(PathDiagnostic &pathDiagnostic, + SmallVectorImpl<BugReport*> &bugReports); + + /// classof - Used by isa<>, cast<>, and dyn_cast<>. + static bool classof(const BugReporter* R) { + return R->getKind() == GRBugReporterKind; + } +}; + +class BugReporterContext { + virtual void anchor(); + GRBugReporter &BR; +public: + BugReporterContext(GRBugReporter& br) : BR(br) {} + + virtual ~BugReporterContext() {} + + GRBugReporter& getBugReporter() { return BR; } + + ExplodedGraph &getGraph() { return BR.getGraph(); } + + ProgramStateManager& getStateManager() { + return BR.getStateManager(); + } + + SValBuilder& getSValBuilder() { + return getStateManager().getSValBuilder(); + } + + ASTContext &getASTContext() { + return BR.getContext(); + } + + SourceManager& getSourceManager() { + return BR.getSourceManager(); + } + + virtual BugReport::NodeResolver& getNodeResolver() = 0; +}; + +} // end GR namespace + +} // end clang namespace + +#endif diff --git a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h new file mode 100644 index 0000000..7e665ce --- /dev/null +++ b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitor.h @@ -0,0 +1,243 @@ +//===--- BugReporterVisitor.h - Generate PathDiagnostics -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares BugReporterVisitors, which are used to generate enhanced +// diagnostic traces. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_GR_BUGREPORTERVISITOR +#define LLVM_CLANG_GR_BUGREPORTERVISITOR + +#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" +#include "llvm/ADT/FoldingSet.h" + +namespace clang { + +namespace ento { + +class BugReport; +class BugReporterContext; +class ExplodedNode; +class MemRegion; +class PathDiagnosticPiece; + +/// \brief BugReporterVisitors are used to add custom diagnostics along a path. +/// +/// Custom visitors should subclass the BugReporterVisitorImpl class for a +/// default implementation of the clone() method. +/// (Warning: if you have a deep subclass of BugReporterVisitorImpl, the +/// default implementation of clone() will NOT do the right thing, and you +/// will have to provide your own implementation.) +class BugReporterVisitor : public llvm::FoldingSetNode { +public: + virtual ~BugReporterVisitor(); + + /// \brief Returns a copy of this BugReporter. + /// + /// Custom BugReporterVisitors should not override this method directly. + /// Instead, they should inherit from BugReporterVisitorImpl and provide + /// a protected or public copy constructor. + /// + /// (Warning: if you have a deep subclass of BugReporterVisitorImpl, the + /// default implementation of clone() will NOT do the right thing, and you + /// will have to provide your own implementation.) + virtual BugReporterVisitor *clone() const = 0; + + /// \brief Return a diagnostic piece which should be associated with the + /// given node. + /// + /// The last parameter can be used to register a new visitor with the given + /// BugReport while processing a node. + virtual PathDiagnosticPiece *VisitNode(const ExplodedNode *N, + const ExplodedNode *PrevN, + BugReporterContext &BRC, + BugReport &BR) = 0; + + /// \brief Provide custom definition for the final diagnostic piece on the + /// path - the piece, which is displayed before the path is expanded. + /// + /// If returns NULL the default implementation will be used. + /// Also note that at most one visitor of a BugReport should generate a + /// non-NULL end of path diagnostic piece. + virtual PathDiagnosticPiece *getEndPath(BugReporterContext &BRC, + const ExplodedNode *N, + BugReport &BR); + + virtual void Profile(llvm::FoldingSetNodeID &ID) const = 0; + + /// \brief Generates the default final diagnostic piece. + static PathDiagnosticPiece *getDefaultEndPath(BugReporterContext &BRC, + const ExplodedNode *N, + BugReport &BR); + +}; + +/// This class provides a convenience implementation for clone() using the +/// Curiously-Recurring Template Pattern. If you are implementing a custom +/// BugReporterVisitor, subclass BugReporterVisitorImpl and provide a public +/// or protected copy constructor. +/// +/// (Warning: if you have a deep subclass of BugReporterVisitorImpl, the +/// default implementation of clone() will NOT do the right thing, and you +/// will have to provide your own implementation.) +template <class DERIVED> +class BugReporterVisitorImpl : public BugReporterVisitor { + virtual BugReporterVisitor *clone() const { + return new DERIVED(*static_cast<const DERIVED *>(this)); + } +}; + +class FindLastStoreBRVisitor + : public BugReporterVisitorImpl<FindLastStoreBRVisitor> +{ + const MemRegion *R; + SVal V; + bool satisfied; + const ExplodedNode *StoreSite; + +public: + /// \brief Convenience method to create a visitor given only the MemRegion. + /// Returns NULL if the visitor cannot be created. For example, when the + /// corresponding value is unknown. + static BugReporterVisitor *createVisitorObject(const ExplodedNode *N, + const MemRegion *R); + + /// Creates a visitor for every VarDecl inside a Stmt and registers it with + /// the BugReport. + static void registerStatementVarDecls(BugReport &BR, const Stmt *S); + + FindLastStoreBRVisitor(SVal v, const MemRegion *r) + : R(r), V(v), satisfied(false), StoreSite(0) { + assert (!V.isUnknown() && "Cannot track unknown value."); + + // TODO: Does it make sense to allow undef values here? + // (If not, also see UndefCapturedBlockVarChecker)? + } + + void Profile(llvm::FoldingSetNodeID &ID) const; + + PathDiagnosticPiece *VisitNode(const ExplodedNode *N, + const ExplodedNode *PrevN, + BugReporterContext &BRC, + BugReport &BR); +}; + +class TrackConstraintBRVisitor + : public BugReporterVisitorImpl<TrackConstraintBRVisitor> +{ + DefinedSVal Constraint; + const bool Assumption; + bool isSatisfied; + +public: + TrackConstraintBRVisitor(DefinedSVal constraint, bool assumption) + : Constraint(constraint), Assumption(assumption), isSatisfied(false) {} + + void Profile(llvm::FoldingSetNodeID &ID) const; + + PathDiagnosticPiece *VisitNode(const ExplodedNode *N, + const ExplodedNode *PrevN, + BugReporterContext &BRC, + BugReport &BR); +}; + +class NilReceiverBRVisitor + : public BugReporterVisitorImpl<NilReceiverBRVisitor> +{ +public: + void Profile(llvm::FoldingSetNodeID &ID) const { + static int x = 0; + ID.AddPointer(&x); + } + + PathDiagnosticPiece *VisitNode(const ExplodedNode *N, + const ExplodedNode *PrevN, + BugReporterContext &BRC, + BugReport &BR); +}; + +/// Visitor that tries to report interesting diagnostics from conditions. +class ConditionBRVisitor : public BugReporterVisitorImpl<ConditionBRVisitor> { +public: + void Profile(llvm::FoldingSetNodeID &ID) const { + static int x = 0; + ID.AddPointer(&x); + } + + + virtual PathDiagnosticPiece *VisitNode(const ExplodedNode *N, + const ExplodedNode *Prev, + BugReporterContext &BRC, + BugReport &BR); + + PathDiagnosticPiece *VisitNodeImpl(const ExplodedNode *N, + const ExplodedNode *Prev, + BugReporterContext &BRC, + BugReport &BR); + + PathDiagnosticPiece *VisitTerminator(const Stmt *Term, + const ExplodedNode *N, + const CFGBlock *srcBlk, + const CFGBlock *dstBlk, + BugReport &R, + BugReporterContext &BRC); + + PathDiagnosticPiece *VisitTrueTest(const Expr *Cond, + bool tookTrue, + BugReporterContext &BRC, + BugReport &R, + const ExplodedNode *N); + + PathDiagnosticPiece *VisitTrueTest(const Expr *Cond, + const DeclRefExpr *DR, + const bool tookTrue, + BugReporterContext &BRC, + BugReport &R, + const ExplodedNode *N); + + PathDiagnosticPiece *VisitTrueTest(const Expr *Cond, + const BinaryOperator *BExpr, + const bool tookTrue, + BugReporterContext &BRC, + BugReport &R, + const ExplodedNode *N); + + PathDiagnosticPiece *VisitConditionVariable(StringRef LhsString, + const Expr *CondVarExpr, + const bool tookTrue, + BugReporterContext &BRC, + BugReport &R, + const ExplodedNode *N); + + bool patternMatch(const Expr *Ex, + llvm::raw_ostream &Out, + BugReporterContext &BRC, + BugReport &R, + const ExplodedNode *N, + llvm::Optional<bool> &prunable); +}; + +namespace bugreporter { + +BugReporterVisitor *getTrackNullOrUndefValueVisitor(const ExplodedNode *N, + const Stmt *S, + BugReport *R); + +const Stmt *GetDerefExpr(const ExplodedNode *N); +const Stmt *GetDenomExpr(const ExplodedNode *N); +const Stmt *GetCalleeExpr(const ExplodedNode *N); +const Stmt *GetRetValExpr(const ExplodedNode *N); + +} // end namespace clang +} // end namespace ento +} // end namespace bugreporter + + +#endif //LLVM_CLANG_GR__BUGREPORTERVISITOR diff --git a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h new file mode 100644 index 0000000..cb49122 --- /dev/null +++ b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h @@ -0,0 +1,67 @@ +//===--- BugType.h - Bug Information Desciption ----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines BugType, a class representing a bug type. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_BUGTYPE +#define LLVM_CLANG_ANALYSIS_BUGTYPE + +#include "llvm/ADT/FoldingSet.h" +#include <string> + +namespace clang { + +namespace ento { + +class BugReporter; +class ExplodedNode; +class ExprEngine; + +class BugType { +private: + const std::string Name; + const std::string Category; + bool SuppressonSink; +public: + BugType(StringRef name, StringRef cat) + : Name(name), Category(cat), SuppressonSink(false) {} + virtual ~BugType(); + + // FIXME: Should these be made strings as well? + StringRef getName() const { return Name; } + StringRef getCategory() const { return Category; } + + /// isSuppressOnSink - Returns true if bug reports associated with this bug + /// type should be suppressed if the end node of the report is post-dominated + /// by a sink node. + bool isSuppressOnSink() const { return SuppressonSink; } + void setSuppressOnSink(bool x) { SuppressonSink = x; } + + virtual void FlushReports(BugReporter& BR); +}; + +class BuiltinBug : public BugType { + virtual void anchor(); + const std::string desc; +public: + BuiltinBug(const char *name, const char *description) + : BugType(name, "Logic error"), desc(description) {} + + BuiltinBug(const char *name) + : BugType(name, "Logic error"), desc(name) {} + + StringRef getDescription() const { return desc; } +}; + +} // end GR namespace + +} // end clang namespace +#endif diff --git a/clang/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h b/clang/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h new file mode 100644 index 0000000..5a8a1c7 --- /dev/null +++ b/clang/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h @@ -0,0 +1,679 @@ +//===--- PathDiagnostic.h - Path-Specific Diagnostic Handling ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the PathDiagnostic-related interfaces. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_PATH_DIAGNOSTIC_H +#define LLVM_CLANG_PATH_DIAGNOSTIC_H + +#include "clang/Basic/SourceLocation.h" +#include "clang/Analysis/ProgramPoint.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/Optional.h" +#include <deque> +#include <iterator> +#include <string> +#include <vector> + +namespace clang { + +class AnalysisDeclContext; +class BinaryOperator; +class CompoundStmt; +class Decl; +class LocationContext; +class MemberExpr; +class ParentMap; +class ProgramPoint; +class SourceManager; +class Stmt; + +namespace ento { + +class ExplodedNode; +class SymExpr; +typedef const SymExpr* SymbolRef; + +//===----------------------------------------------------------------------===// +// High-level interface for handlers of path-sensitive diagnostics. +//===----------------------------------------------------------------------===// + +class PathDiagnostic; + +class PathDiagnosticConsumer { + virtual void anchor(); +public: + PathDiagnosticConsumer() : flushed(false) {} + virtual ~PathDiagnosticConsumer(); + + void FlushDiagnostics(SmallVectorImpl<std::string> *FilesMade); + + virtual void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags, + SmallVectorImpl<std::string> *FilesMade) + = 0; + + virtual StringRef getName() const = 0; + + void HandlePathDiagnostic(PathDiagnostic *D); + + enum PathGenerationScheme { Minimal, Extensive }; + virtual PathGenerationScheme getGenerationScheme() const { return Minimal; } + virtual bool supportsLogicalOpControlFlow() const { return false; } + virtual bool supportsAllBlockEdges() const { return false; } + virtual bool useVerboseDescription() const { return true; } + + /// Return true if the PathDiagnosticConsumer supports individual + /// PathDiagnostics that span multiple files. + virtual bool supportsCrossFileDiagnostics() const { return false; } + +protected: + bool flushed; + llvm::FoldingSet<PathDiagnostic> Diags; +}; + +//===----------------------------------------------------------------------===// +// Path-sensitive diagnostics. +//===----------------------------------------------------------------------===// + +class PathDiagnosticRange : public SourceRange { +public: + bool isPoint; + + PathDiagnosticRange(const SourceRange &R, bool isP = false) + : SourceRange(R), isPoint(isP) {} + + PathDiagnosticRange() : isPoint(false) {} +}; + +typedef llvm::PointerUnion<const LocationContext*, AnalysisDeclContext*> + LocationOrAnalysisDeclContext; + +class PathDiagnosticLocation { +private: + enum Kind { RangeK, SingleLocK, StmtK, DeclK } K; + const Stmt *S; + const Decl *D; + const SourceManager *SM; + FullSourceLoc Loc; + PathDiagnosticRange Range; + + PathDiagnosticLocation(SourceLocation L, const SourceManager &sm, + Kind kind) + : K(kind), S(0), D(0), SM(&sm), + Loc(genLocation(L)), Range(genRange()) { + assert(Loc.isValid()); + assert(Range.isValid()); + } + + FullSourceLoc + genLocation(SourceLocation L = SourceLocation(), + LocationOrAnalysisDeclContext LAC = (AnalysisDeclContext*)0) const; + + PathDiagnosticRange + genRange(LocationOrAnalysisDeclContext LAC = (AnalysisDeclContext*)0) const; + +public: + /// Create an invalid location. + PathDiagnosticLocation() + : K(SingleLocK), S(0), D(0), SM(0) {} + + /// Create a location corresponding to the given statement. + PathDiagnosticLocation(const Stmt *s, + const SourceManager &sm, + LocationOrAnalysisDeclContext lac) + : K(StmtK), S(s), D(0), SM(&sm), + Loc(genLocation(SourceLocation(), lac)), + Range(genRange(lac)) { + assert(S); + assert(Loc.isValid()); + assert(Range.isValid()); + } + + /// Create a location corresponding to the given declaration. + PathDiagnosticLocation(const Decl *d, const SourceManager &sm) + : K(DeclK), S(0), D(d), SM(&sm), + Loc(genLocation()), Range(genRange()) { + assert(D); + assert(Loc.isValid()); + assert(Range.isValid()); + } + + /// Create a location corresponding to the given declaration. + static PathDiagnosticLocation create(const Decl *D, + const SourceManager &SM) { + return PathDiagnosticLocation(D, SM); + } + + /// Create a location for the beginning of the declaration. + static PathDiagnosticLocation createBegin(const Decl *D, + const SourceManager &SM); + + /// Create a location for the beginning of the statement. + static PathDiagnosticLocation createBegin(const Stmt *S, + const SourceManager &SM, + const LocationOrAnalysisDeclContext LAC); + + /// Create the location for the operator of the binary expression. + /// Assumes the statement has a valid location. + static PathDiagnosticLocation createOperatorLoc(const BinaryOperator *BO, + const SourceManager &SM); + + /// For member expressions, return the location of the '.' or '->'. + /// Assumes the statement has a valid location. + static PathDiagnosticLocation createMemberLoc(const MemberExpr *ME, + const SourceManager &SM); + + /// Create a location for the beginning of the compound statement. + /// Assumes the statement has a valid location. + static PathDiagnosticLocation createBeginBrace(const CompoundStmt *CS, + const SourceManager &SM); + + /// Create a location for the end of the compound statement. + /// Assumes the statement has a valid location. + static PathDiagnosticLocation createEndBrace(const CompoundStmt *CS, + const SourceManager &SM); + + /// Create a location for the beginning of the enclosing declaration body. + /// Defaults to the beginning of the first statement in the declaration body. + static PathDiagnosticLocation createDeclBegin(const LocationContext *LC, + const SourceManager &SM); + + /// Constructs a location for the end of the enclosing declaration body. + /// Defaults to the end of brace. + static PathDiagnosticLocation createDeclEnd(const LocationContext *LC, + const SourceManager &SM); + + /// Create a location corresponding to the given valid ExplodedNode. + static PathDiagnosticLocation create(const ProgramPoint& P, + const SourceManager &SMng); + + /// Create a location corresponding to the next valid ExplodedNode as end + /// of path location. + static PathDiagnosticLocation createEndOfPath(const ExplodedNode* N, + const SourceManager &SM); + + /// Convert the given location into a single kind location. + static PathDiagnosticLocation createSingleLocation( + const PathDiagnosticLocation &PDL); + + bool operator==(const PathDiagnosticLocation &X) const { + return K == X.K && Loc == X.Loc && Range == X.Range; + } + + bool operator!=(const PathDiagnosticLocation &X) const { + return !(*this == X); + } + + bool isValid() const { + return SM != 0; + } + + FullSourceLoc asLocation() const { + return Loc; + } + + PathDiagnosticRange asRange() const { + return Range; + } + + const Stmt *asStmt() const { assert(isValid()); return S; } + const Decl *asDecl() const { assert(isValid()); return D; } + + bool hasRange() const { return K == StmtK || K == RangeK || K == DeclK; } + + void invalidate() { + *this = PathDiagnosticLocation(); + } + + void flatten(); + + const SourceManager& getManager() const { assert(isValid()); return *SM; } + + void Profile(llvm::FoldingSetNodeID &ID) const; +}; + +class PathDiagnosticLocationPair { +private: + PathDiagnosticLocation Start, End; +public: + PathDiagnosticLocationPair(const PathDiagnosticLocation &start, + const PathDiagnosticLocation &end) + : Start(start), End(end) {} + + const PathDiagnosticLocation &getStart() const { return Start; } + const PathDiagnosticLocation &getEnd() const { return End; } + + void flatten() { + Start.flatten(); + End.flatten(); + } + + void Profile(llvm::FoldingSetNodeID &ID) const { + Start.Profile(ID); + End.Profile(ID); + } +}; + +//===----------------------------------------------------------------------===// +// Path "pieces" for path-sensitive diagnostics. +//===----------------------------------------------------------------------===// + +class PathDiagnosticPiece : public RefCountedBaseVPTR { +public: + enum Kind { ControlFlow, Event, Macro, Call }; + enum DisplayHint { Above, Below }; + +private: + const std::string str; + const Kind kind; + const DisplayHint Hint; + std::vector<SourceRange> ranges; + + // Do not implement: + PathDiagnosticPiece(); + PathDiagnosticPiece(const PathDiagnosticPiece &P); + PathDiagnosticPiece& operator=(const PathDiagnosticPiece &P); + +protected: + PathDiagnosticPiece(StringRef s, Kind k, DisplayHint hint = Below); + + PathDiagnosticPiece(Kind k, DisplayHint hint = Below); + +public: + virtual ~PathDiagnosticPiece(); + + const std::string& getString() const { return str; } + + /// getDisplayHint - Return a hint indicating where the diagnostic should + /// be displayed by the PathDiagnosticConsumer. + DisplayHint getDisplayHint() const { return Hint; } + + virtual PathDiagnosticLocation getLocation() const = 0; + virtual void flattenLocations() = 0; + + Kind getKind() const { return kind; } + + void addRange(SourceRange R) { + if (!R.isValid()) + return; + ranges.push_back(R); + } + + void addRange(SourceLocation B, SourceLocation E) { + if (!B.isValid() || !E.isValid()) + return; + ranges.push_back(SourceRange(B,E)); + } + + typedef const SourceRange* range_iterator; + + range_iterator ranges_begin() const { + return ranges.empty() ? NULL : &ranges[0]; + } + + range_iterator ranges_end() const { + return ranges_begin() + ranges.size(); + } + + static inline bool classof(const PathDiagnosticPiece *P) { + return true; + } + + virtual void Profile(llvm::FoldingSetNodeID &ID) const; +}; + + +class PathPieces : + public std::deque<IntrusiveRefCntPtr<PathDiagnosticPiece> > { +public: + ~PathPieces(); +}; + +class PathDiagnosticSpotPiece : public PathDiagnosticPiece { +private: + PathDiagnosticLocation Pos; +public: + PathDiagnosticSpotPiece(const PathDiagnosticLocation &pos, + StringRef s, + PathDiagnosticPiece::Kind k, + bool addPosRange = true) + : PathDiagnosticPiece(s, k), Pos(pos) { + assert(Pos.isValid() && Pos.asLocation().isValid() && + "PathDiagnosticSpotPiece's must have a valid location."); + if (addPosRange && Pos.hasRange()) addRange(Pos.asRange()); + } + + PathDiagnosticLocation getLocation() const { return Pos; } + virtual void flattenLocations() { Pos.flatten(); } + + virtual void Profile(llvm::FoldingSetNodeID &ID) const; +}; + +/// \brief Interface for classes constructing Stack hints. +/// +/// If a PathDiagnosticEvent occurs in a different frame than the final +/// diagnostic the hints can be used to summarise the effect of the call. +class StackHintGenerator { +public: + virtual ~StackHintGenerator() = 0; + + /// \brief Construct the Diagnostic message for the given ExplodedNode. + virtual std::string getMessage(const ExplodedNode *N) = 0; +}; + +/// \brief Constructs a Stack hint for the given symbol. +/// +/// The class knows how to construct the stack hint message based on +/// traversing the CallExpr associated with the call and checking if the given +/// symbol is returned or is one of the arguments. +/// The hint can be customized by redefining 'getMessageForX()' methods. +class StackHintGeneratorForSymbol : public StackHintGenerator { +private: + SymbolRef Sym; + std::string Msg; + +public: + StackHintGeneratorForSymbol(SymbolRef S, StringRef M) : Sym(S), Msg(M) {} + virtual ~StackHintGeneratorForSymbol() {} + + /// \brief Search the call expression for the symbol Sym and dispatch the + /// 'getMessageForX()' methods to construct a specific message. + virtual std::string getMessage(const ExplodedNode *N); + + /// Prints the ordinal form of the given integer, + /// only valid for ValNo : ValNo > 0. + void printOrdinal(unsigned ValNo, llvm::raw_svector_ostream &Out); + + /// Produces the message of the following form: + /// 'Msg via Nth parameter' + virtual std::string getMessageForArg(const Expr *ArgE, unsigned ArgIndex); + virtual std::string getMessageForReturn(const CallExpr *CallExpr) { + return Msg; + } + virtual std::string getMessageForSymbolNotFound() { + return Msg; + } +}; + +class PathDiagnosticEventPiece : public PathDiagnosticSpotPiece { + llvm::Optional<bool> IsPrunable; + + /// If the event occurs in a different frame than the final diagnostic, + /// supply a message that will be used to construct an extra hint on the + /// returns from all the calls on the stack from this event to the final + /// diagnostic. + llvm::OwningPtr<StackHintGenerator> CallStackHint; + +public: + PathDiagnosticEventPiece(const PathDiagnosticLocation &pos, + StringRef s, bool addPosRange = true, + StackHintGenerator *stackHint = 0) + : PathDiagnosticSpotPiece(pos, s, Event, addPosRange), + CallStackHint(stackHint) {} + + ~PathDiagnosticEventPiece(); + + /// Mark the diagnostic piece as being potentially prunable. This + /// flag may have been previously set, at which point it will not + /// be reset unless one specifies to do so. + void setPrunable(bool isPrunable, bool override = false) { + if (IsPrunable.hasValue() && !override) + return; + IsPrunable = isPrunable; + } + + /// Return true if the diagnostic piece is prunable. + bool isPrunable() const { + return IsPrunable.hasValue() ? IsPrunable.getValue() : false; + } + + bool hasCallStackHint() { + return (CallStackHint != 0); + } + + /// Produce the hint for the given node. The node contains + /// information about the call for which the diagnostic can be generated. + std::string getCallStackMessage(const ExplodedNode *N) { + if (CallStackHint) + return CallStackHint->getMessage(N); + return ""; + } + + static inline bool classof(const PathDiagnosticPiece *P) { + return P->getKind() == Event; + } +}; + +class PathDiagnosticCallPiece : public PathDiagnosticPiece { + PathDiagnosticCallPiece(const Decl *callerD, + const PathDiagnosticLocation &callReturnPos) + : PathDiagnosticPiece(Call), Caller(callerD), Callee(0), + NoExit(false), callReturn(callReturnPos) {} + + PathDiagnosticCallPiece(PathPieces &oldPath, const Decl *caller) + : PathDiagnosticPiece(Call), Caller(caller), Callee(0), + NoExit(true), path(oldPath) {} + + const Decl *Caller; + const Decl *Callee; + + // Flag signifying that this diagnostic has only call enter and no matching + // call exit. + bool NoExit; + + // The custom string, which should appear after the call Return Diagnostic. + // TODO: Should we allow multiple diagnostics? + std::string CallStackMessage; + +public: + PathDiagnosticLocation callEnter; + PathDiagnosticLocation callEnterWithin; + PathDiagnosticLocation callReturn; + PathPieces path; + + virtual ~PathDiagnosticCallPiece(); + + const Decl *getCaller() const { return Caller; } + + const Decl *getCallee() const { return Callee; } + void setCallee(const CallEnter &CE, const SourceManager &SM); + + bool hasCallStackMessage() { return !CallStackMessage.empty(); } + void setCallStackMessage(StringRef st) { + CallStackMessage = st; + } + + virtual PathDiagnosticLocation getLocation() const { + return callEnter; + } + + IntrusiveRefCntPtr<PathDiagnosticEventPiece> getCallEnterEvent() const; + IntrusiveRefCntPtr<PathDiagnosticEventPiece> + getCallEnterWithinCallerEvent() const; + IntrusiveRefCntPtr<PathDiagnosticEventPiece> getCallExitEvent() const; + + virtual void flattenLocations() { + callEnter.flatten(); + callReturn.flatten(); + for (PathPieces::iterator I = path.begin(), + E = path.end(); I != E; ++I) (*I)->flattenLocations(); + } + + static PathDiagnosticCallPiece *construct(const ExplodedNode *N, + const CallExit &CE, + const SourceManager &SM); + + static PathDiagnosticCallPiece *construct(PathPieces &pieces, + const Decl *caller); + + virtual void Profile(llvm::FoldingSetNodeID &ID) const; + + static inline bool classof(const PathDiagnosticPiece *P) { + return P->getKind() == Call; + } +}; + +class PathDiagnosticControlFlowPiece : public PathDiagnosticPiece { + std::vector<PathDiagnosticLocationPair> LPairs; +public: + PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos, + const PathDiagnosticLocation &endPos, + StringRef s) + : PathDiagnosticPiece(s, ControlFlow) { + LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos)); + } + + PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos, + const PathDiagnosticLocation &endPos) + : PathDiagnosticPiece(ControlFlow) { + LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos)); + } + + ~PathDiagnosticControlFlowPiece(); + + PathDiagnosticLocation getStartLocation() const { + assert(!LPairs.empty() && + "PathDiagnosticControlFlowPiece needs at least one location."); + return LPairs[0].getStart(); + } + + PathDiagnosticLocation getEndLocation() const { + assert(!LPairs.empty() && + "PathDiagnosticControlFlowPiece needs at least one location."); + return LPairs[0].getEnd(); + } + + void push_back(const PathDiagnosticLocationPair &X) { LPairs.push_back(X); } + + virtual PathDiagnosticLocation getLocation() const { + return getStartLocation(); + } + + typedef std::vector<PathDiagnosticLocationPair>::iterator iterator; + iterator begin() { return LPairs.begin(); } + iterator end() { return LPairs.end(); } + + virtual void flattenLocations() { + for (iterator I=begin(), E=end(); I!=E; ++I) I->flatten(); + } + + typedef std::vector<PathDiagnosticLocationPair>::const_iterator + const_iterator; + const_iterator begin() const { return LPairs.begin(); } + const_iterator end() const { return LPairs.end(); } + + static inline bool classof(const PathDiagnosticPiece *P) { + return P->getKind() == ControlFlow; + } + + virtual void Profile(llvm::FoldingSetNodeID &ID) const; +}; + +class PathDiagnosticMacroPiece : public PathDiagnosticSpotPiece { +public: + PathDiagnosticMacroPiece(const PathDiagnosticLocation &pos) + : PathDiagnosticSpotPiece(pos, "", Macro) {} + + ~PathDiagnosticMacroPiece(); + + PathPieces subPieces; + + bool containsEvent() const; + + virtual void flattenLocations() { + PathDiagnosticSpotPiece::flattenLocations(); + for (PathPieces::iterator I = subPieces.begin(), + E = subPieces.end(); I != E; ++I) (*I)->flattenLocations(); + } + + static inline bool classof(const PathDiagnosticPiece *P) { + return P->getKind() == Macro; + } + + virtual void Profile(llvm::FoldingSetNodeID &ID) const; +}; + +/// PathDiagnostic - PathDiagnostic objects represent a single path-sensitive +/// diagnostic. It represents an ordered-collection of PathDiagnosticPieces, +/// each which represent the pieces of the path. +class PathDiagnostic : public llvm::FoldingSetNode { + const Decl *DeclWithIssue; + std::string BugType; + std::string Desc; + std::string Category; + std::deque<std::string> OtherDesc; + PathPieces pathImpl; + llvm::SmallVector<PathPieces *, 3> pathStack; + + PathDiagnostic(); // Do not implement. +public: + const PathPieces &path; + + /// Return the path currently used by builders for constructing the + /// PathDiagnostic. + PathPieces &getActivePath() { + if (pathStack.empty()) + return pathImpl; + return *pathStack.back(); + } + + /// Return a mutable version of 'path'. + PathPieces &getMutablePieces() { + return pathImpl; + } + + /// Return the unrolled size of the path. + unsigned full_size(); + + void pushActivePath(PathPieces *p) { pathStack.push_back(p); } + void popActivePath() { if (!pathStack.empty()) pathStack.pop_back(); } + + // PathDiagnostic(); + PathDiagnostic(const Decl *DeclWithIssue, + StringRef bugtype, + StringRef desc, + StringRef category); + + ~PathDiagnostic(); + + StringRef getDescription() const { return Desc; } + StringRef getBugType() const { return BugType; } + StringRef getCategory() const { return Category; } + + /// Return the semantic context where an issue occurred. If the + /// issue occurs along a path, this represents the "central" area + /// where the bug manifests. + const Decl *getDeclWithIssue() const { return DeclWithIssue; } + + typedef std::deque<std::string>::const_iterator meta_iterator; + meta_iterator meta_begin() const { return OtherDesc.begin(); } + meta_iterator meta_end() const { return OtherDesc.end(); } + void addMeta(StringRef s) { OtherDesc.push_back(s); } + + PathDiagnosticLocation getLocation() const; + + void flattenLocations() { + for (PathPieces::iterator I = pathImpl.begin(), E = pathImpl.end(); + I != E; ++I) (*I)->flattenLocations(); + } + + void Profile(llvm::FoldingSetNodeID &ID) const; + + void FullProfile(llvm::FoldingSetNodeID &ID) const; +}; + +} // end GR namespace + +} //end clang namespace + +#endif diff --git a/clang/include/clang/StaticAnalyzer/Core/Checker.h b/clang/include/clang/StaticAnalyzer/Core/Checker.h new file mode 100644 index 0000000..76d8c15 --- /dev/null +++ b/clang/include/clang/StaticAnalyzer/Core/Checker.h @@ -0,0 +1,441 @@ +//== Checker.h - Registration mechanism for checkers -------------*- C++ -*--=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines Checker, used to create and register checkers. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SA_CORE_CHECKER +#define LLVM_CLANG_SA_CORE_CHECKER + +#include "clang/Analysis/ProgramPoint.h" +#include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" +#include "llvm/Support/Casting.h" + +namespace clang { +namespace ento { + class BugReporter; + +namespace check { + +struct _VoidCheck { + static void _register(void *checker, CheckerManager &mgr) { } +}; + +template <typename DECL> +class ASTDecl { + template <typename CHECKER> + static void _checkDecl(void *checker, const Decl *D, AnalysisManager& mgr, + BugReporter &BR) { + ((const CHECKER *)checker)->checkASTDecl(llvm::cast<DECL>(D), mgr, BR); + } + + static bool _handlesDecl(const Decl *D) { + return llvm::isa<DECL>(D); + } +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForDecl(CheckerManager::CheckDeclFunc(checker, + _checkDecl<CHECKER>), + _handlesDecl); + } +}; + +class ASTCodeBody { + template <typename CHECKER> + static void _checkBody(void *checker, const Decl *D, AnalysisManager& mgr, + BugReporter &BR) { + ((const CHECKER *)checker)->checkASTCodeBody(D, mgr, BR); + } + +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForBody(CheckerManager::CheckDeclFunc(checker, + _checkBody<CHECKER>)); + } +}; + +class EndOfTranslationUnit { + template <typename CHECKER> + static void _checkEndOfTranslationUnit(void *checker, + const TranslationUnitDecl *TU, + AnalysisManager& mgr, + BugReporter &BR) { + ((const CHECKER *)checker)->checkEndOfTranslationUnit(TU, mgr, BR); + } + +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr){ + mgr._registerForEndOfTranslationUnit( + CheckerManager::CheckEndOfTranslationUnit(checker, + _checkEndOfTranslationUnit<CHECKER>)); + } +}; + +template <typename STMT> +class PreStmt { + template <typename CHECKER> + static void _checkStmt(void *checker, const Stmt *S, CheckerContext &C) { + ((const CHECKER *)checker)->checkPreStmt(llvm::cast<STMT>(S), C); + } + + static bool _handlesStmt(const Stmt *S) { + return llvm::isa<STMT>(S); + } +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForPreStmt(CheckerManager::CheckStmtFunc(checker, + _checkStmt<CHECKER>), + _handlesStmt); + } +}; + +template <typename STMT> +class PostStmt { + template <typename CHECKER> + static void _checkStmt(void *checker, const Stmt *S, CheckerContext &C) { + ((const CHECKER *)checker)->checkPostStmt(llvm::cast<STMT>(S), C); + } + + static bool _handlesStmt(const Stmt *S) { + return llvm::isa<STMT>(S); + } +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForPostStmt(CheckerManager::CheckStmtFunc(checker, + _checkStmt<CHECKER>), + _handlesStmt); + } +}; + +class PreObjCMessage { + template <typename CHECKER> + static void _checkObjCMessage(void *checker, const ObjCMessage &msg, + CheckerContext &C) { + ((const CHECKER *)checker)->checkPreObjCMessage(msg, C); + } + +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForPreObjCMessage( + CheckerManager::CheckObjCMessageFunc(checker, _checkObjCMessage<CHECKER>)); + } +}; + +class PostObjCMessage { + template <typename CHECKER> + static void _checkObjCMessage(void *checker, const ObjCMessage &msg, + CheckerContext &C) { + ((const CHECKER *)checker)->checkPostObjCMessage(msg, C); + } + +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForPostObjCMessage( + CheckerManager::CheckObjCMessageFunc(checker, _checkObjCMessage<CHECKER>)); + } +}; + +class Location { + template <typename CHECKER> + static void _checkLocation(void *checker, + const SVal &location, bool isLoad, const Stmt *S, + CheckerContext &C) { + ((const CHECKER *)checker)->checkLocation(location, isLoad, S, C); + } + +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForLocation( + CheckerManager::CheckLocationFunc(checker, _checkLocation<CHECKER>)); + } +}; + +class Bind { + template <typename CHECKER> + static void _checkBind(void *checker, + const SVal &location, const SVal &val, const Stmt *S, + CheckerContext &C) { + ((const CHECKER *)checker)->checkBind(location, val, S, C); + } + +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForBind( + CheckerManager::CheckBindFunc(checker, _checkBind<CHECKER>)); + } +}; + +class EndAnalysis { + template <typename CHECKER> + static void _checkEndAnalysis(void *checker, ExplodedGraph &G, + BugReporter &BR, ExprEngine &Eng) { + ((const CHECKER *)checker)->checkEndAnalysis(G, BR, Eng); + } + +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForEndAnalysis( + CheckerManager::CheckEndAnalysisFunc(checker, _checkEndAnalysis<CHECKER>)); + } +}; + +class EndPath { + template <typename CHECKER> + static void _checkEndPath(void *checker, + CheckerContext &C) { + ((const CHECKER *)checker)->checkEndPath(C); + } + +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForEndPath( + CheckerManager::CheckEndPathFunc(checker, _checkEndPath<CHECKER>)); + } +}; + +class BranchCondition { + template <typename CHECKER> + static void _checkBranchCondition(void *checker, const Stmt *Condition, + CheckerContext & C) { + ((const CHECKER *)checker)->checkBranchCondition(Condition, C); + } + +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForBranchCondition( + CheckerManager::CheckBranchConditionFunc(checker, + _checkBranchCondition<CHECKER>)); + } +}; + +class LiveSymbols { + template <typename CHECKER> + static void _checkLiveSymbols(void *checker, ProgramStateRef state, + SymbolReaper &SR) { + ((const CHECKER *)checker)->checkLiveSymbols(state, SR); + } + +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForLiveSymbols( + CheckerManager::CheckLiveSymbolsFunc(checker, _checkLiveSymbols<CHECKER>)); + } +}; + +class DeadSymbols { + template <typename CHECKER> + static void _checkDeadSymbols(void *checker, + SymbolReaper &SR, CheckerContext &C) { + ((const CHECKER *)checker)->checkDeadSymbols(SR, C); + } + +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForDeadSymbols( + CheckerManager::CheckDeadSymbolsFunc(checker, _checkDeadSymbols<CHECKER>)); + } +}; + +class RegionChanges { + template <typename CHECKER> + static ProgramStateRef + _checkRegionChanges(void *checker, + ProgramStateRef state, + const StoreManager::InvalidatedSymbols *invalidated, + ArrayRef<const MemRegion *> Explicits, + ArrayRef<const MemRegion *> Regions, + const CallOrObjCMessage *Call) { + return ((const CHECKER *)checker)->checkRegionChanges(state, invalidated, + Explicits, Regions, Call); + } + template <typename CHECKER> + static bool _wantsRegionChangeUpdate(void *checker, + ProgramStateRef state) { + return ((const CHECKER *)checker)->wantsRegionChangeUpdate(state); + } + +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForRegionChanges( + CheckerManager::CheckRegionChangesFunc(checker, + _checkRegionChanges<CHECKER>), + CheckerManager::WantsRegionChangeUpdateFunc(checker, + _wantsRegionChangeUpdate<CHECKER>)); + } +}; + +template <typename EVENT> +class Event { + template <typename CHECKER> + static void _checkEvent(void *checker, const void *event) { + ((const CHECKER *)checker)->checkEvent(*(const EVENT *)event); + } +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerListenerForEvent<EVENT>( + CheckerManager::CheckEventFunc(checker, _checkEvent<CHECKER>)); + } +}; + +} // end check namespace + +namespace eval { + +class Assume { + template <typename CHECKER> + static ProgramStateRef _evalAssume(void *checker, + ProgramStateRef state, + const SVal &cond, + bool assumption) { + return ((const CHECKER *)checker)->evalAssume(state, cond, assumption); + } + +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForEvalAssume( + CheckerManager::EvalAssumeFunc(checker, _evalAssume<CHECKER>)); + } +}; + +class Call { + template <typename CHECKER> + static bool _evalCall(void *checker, const CallExpr *CE, CheckerContext &C) { + return ((const CHECKER *)checker)->evalCall(CE, C); + } + +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForEvalCall( + CheckerManager::EvalCallFunc(checker, _evalCall<CHECKER>)); + } +}; + +class InlineCall { + template <typename CHECKER> + static bool _inlineCall(void *checker, const CallExpr *CE, + ExprEngine &Eng, + ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + return ((const CHECKER *)checker)->inlineCall(CE, Eng, Pred, Dst); + } + +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForInlineCall( + CheckerManager::InlineCallFunc(checker, _inlineCall<CHECKER>)); + } +}; + +} // end eval namespace + +class CheckerBase : public ProgramPointTag { +public: + StringRef getTagDescription() const; + + /// See CheckerManager::runCheckersForPrintState. + virtual void printState(raw_ostream &Out, ProgramStateRef State, + const char *NL, const char *Sep) const { } +}; + +template <typename CHECK1, typename CHECK2=check::_VoidCheck, + typename CHECK3=check::_VoidCheck, typename CHECK4=check::_VoidCheck, + typename CHECK5=check::_VoidCheck, typename CHECK6=check::_VoidCheck, + typename CHECK7=check::_VoidCheck, typename CHECK8=check::_VoidCheck, + typename CHECK9=check::_VoidCheck, typename CHECK10=check::_VoidCheck, + typename CHECK11=check::_VoidCheck,typename CHECK12=check::_VoidCheck, + typename CHECK13=check::_VoidCheck,typename CHECK14=check::_VoidCheck, + typename CHECK15=check::_VoidCheck,typename CHECK16=check::_VoidCheck, + typename CHECK17=check::_VoidCheck,typename CHECK18=check::_VoidCheck> +class Checker; + +template <> +class Checker<check::_VoidCheck, check::_VoidCheck, check::_VoidCheck, + check::_VoidCheck, check::_VoidCheck, check::_VoidCheck, + check::_VoidCheck, check::_VoidCheck, check::_VoidCheck, + check::_VoidCheck, check::_VoidCheck, check::_VoidCheck, + check::_VoidCheck, check::_VoidCheck, check::_VoidCheck, + check::_VoidCheck, check::_VoidCheck, check::_VoidCheck> + : public CheckerBase +{ + virtual void anchor(); +public: + static void _register(void *checker, CheckerManager &mgr) { } +}; + +template <typename CHECK1, typename CHECK2, typename CHECK3, typename CHECK4, + typename CHECK5, typename CHECK6, typename CHECK7, typename CHECK8, + typename CHECK9, typename CHECK10,typename CHECK11,typename CHECK12, + typename CHECK13,typename CHECK14,typename CHECK15,typename CHECK16, + typename CHECK17,typename CHECK18> +class Checker + : public CHECK1, + public Checker<CHECK2, CHECK3, CHECK4, CHECK5, CHECK6, CHECK7, CHECK8, + CHECK9, CHECK10,CHECK11,CHECK12,CHECK13,CHECK14,CHECK15, + CHECK16,CHECK17,CHECK18> { +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + CHECK1::_register(checker, mgr); + Checker<CHECK2, CHECK3, CHECK4, CHECK5, CHECK6, CHECK7, CHECK8, + CHECK9, CHECK10,CHECK11,CHECK12,CHECK13,CHECK14,CHECK15, + CHECK16,CHECK17,CHECK18>::_register(checker, mgr); + } +}; + +template <typename EVENT> +class EventDispatcher { + CheckerManager *Mgr; +public: + EventDispatcher() : Mgr(0) { } + + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerDispatcherForEvent<EVENT>(); + static_cast<EventDispatcher<EVENT> *>(checker)->Mgr = &mgr; + } + + void dispatchEvent(const EVENT &event) const { + Mgr->_dispatchEvent(event); + } +}; + +/// \brief We dereferenced a location that may be null. +struct ImplicitNullDerefEvent { + SVal Location; + bool IsLoad; + ExplodedNode *SinkNode; + BugReporter *BR; +}; + +} // end ento namespace + +} // end clang namespace + +#endif diff --git a/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h b/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h new file mode 100644 index 0000000..d215f99 --- /dev/null +++ b/clang/include/clang/StaticAnalyzer/Core/CheckerManager.h @@ -0,0 +1,594 @@ +//===--- CheckerManager.h - Static Analyzer Checker Manager -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Defines the Static Analyzer Checker Manager. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SA_CORE_CHECKERMANAGER_H +#define LLVM_CLANG_SA_CORE_CHECKERMANAGER_H + +#include "clang/Basic/LangOptions.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/FoldingSet.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h" +#include "clang/Analysis/ProgramPoint.h" +#include <vector> + +namespace clang { + class Decl; + class Stmt; + class CallExpr; + +namespace ento { + class CheckerBase; + class ExprEngine; + class AnalysisManager; + class BugReporter; + class CheckerContext; + class ObjCMessage; + class SVal; + class ExplodedNode; + class ExplodedNodeSet; + class ExplodedGraph; + class ProgramState; + class NodeBuilder; + struct NodeBuilderContext; + class MemRegion; + class SymbolReaper; + +class GraphExpander { +public: + virtual ~GraphExpander(); + virtual void expandGraph(ExplodedNodeSet &Dst, ExplodedNode *Pred) = 0; +}; + +template <typename T> class CheckerFn; + +template <typename RET, typename P1, typename P2, typename P3, typename P4, + typename P5> +class CheckerFn<RET(P1, P2, P3, P4, P5)> { + typedef RET (*Func)(void *, P1, P2, P3, P4, P5); + Func Fn; +public: + CheckerBase *Checker; + CheckerFn(CheckerBase *checker, Func fn) : Fn(fn), Checker(checker) { } + RET operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) const { + return Fn(Checker, p1, p2, p3, p4, p5); + } +}; + +template <typename RET, typename P1, typename P2, typename P3, typename P4> +class CheckerFn<RET(P1, P2, P3, P4)> { + typedef RET (*Func)(void *, P1, P2, P3, P4); + Func Fn; +public: + CheckerBase *Checker; + CheckerFn(CheckerBase *checker, Func fn) : Fn(fn), Checker(checker) { } + RET operator()(P1 p1, P2 p2, P3 p3, P4 p4) const { + return Fn(Checker, p1, p2, p3, p4); + } +}; + +template <typename RET, typename P1, typename P2, typename P3> +class CheckerFn<RET(P1, P2, P3)> { + typedef RET (*Func)(void *, P1, P2, P3); + Func Fn; +public: + CheckerBase *Checker; + CheckerFn(CheckerBase *checker, Func fn) : Fn(fn), Checker(checker) { } + RET operator()(P1 p1, P2 p2, P3 p3) const { return Fn(Checker, p1, p2, p3); } +}; + +template <typename RET, typename P1, typename P2> +class CheckerFn<RET(P1, P2)> { + typedef RET (*Func)(void *, P1, P2); + Func Fn; +public: + CheckerBase *Checker; + CheckerFn(CheckerBase *checker, Func fn) : Fn(fn), Checker(checker) { } + RET operator()(P1 p1, P2 p2) const { return Fn(Checker, p1, p2); } +}; + +template <typename RET, typename P1> +class CheckerFn<RET(P1)> { + typedef RET (*Func)(void *, P1); + Func Fn; +public: + CheckerBase *Checker; + CheckerFn(CheckerBase *checker, Func fn) : Fn(fn), Checker(checker) { } + RET operator()(P1 p1) const { return Fn(Checker, p1); } +}; + +template <typename RET> +class CheckerFn<RET()> { + typedef RET (*Func)(void *); + Func Fn; +public: + CheckerBase *Checker; + CheckerFn(CheckerBase *checker, Func fn) : Fn(fn), Checker(checker) { } + RET operator()() const { return Fn(Checker); } +}; + +class CheckerManager { + const LangOptions LangOpts; + +public: + CheckerManager(const LangOptions &langOpts) : LangOpts(langOpts) { } + ~CheckerManager(); + + bool hasPathSensitiveCheckers() const; + + void finishedCheckerRegistration(); + + const LangOptions &getLangOpts() const { return LangOpts; } + + typedef CheckerBase *CheckerRef; + typedef const void *CheckerTag; + typedef CheckerFn<void ()> CheckerDtor; + +//===----------------------------------------------------------------------===// +// registerChecker +//===----------------------------------------------------------------------===// + + /// \brief Used to register checkers. + /// + /// \returns a pointer to the checker object. + template <typename CHECKER> + CHECKER *registerChecker() { + CheckerTag tag = getTag<CHECKER>(); + CheckerRef &ref = CheckerTags[tag]; + if (ref) + return static_cast<CHECKER *>(ref); // already registered. + + CHECKER *checker = new CHECKER(); + CheckerDtors.push_back(CheckerDtor(checker, destruct<CHECKER>)); + CHECKER::_register(checker, *this); + ref = checker; + return checker; + } + +//===----------------------------------------------------------------------===// +// Functions for running checkers for AST traversing.. +//===----------------------------------------------------------------------===// + + /// \brief Run checkers handling Decls. + void runCheckersOnASTDecl(const Decl *D, AnalysisManager& mgr, + BugReporter &BR); + + /// \brief Run checkers handling Decls containing a Stmt body. + void runCheckersOnASTBody(const Decl *D, AnalysisManager& mgr, + BugReporter &BR); + +//===----------------------------------------------------------------------===// +// Functions for running checkers for path-sensitive checking. +//===----------------------------------------------------------------------===// + + /// \brief Run checkers for pre-visiting Stmts. + /// + /// The notification is performed for every explored CFGElement, which does + /// not include the control flow statements such as IfStmt. + /// + /// \sa runCheckersForBranchCondition, runCheckersForPostStmt + void runCheckersForPreStmt(ExplodedNodeSet &Dst, + const ExplodedNodeSet &Src, + const Stmt *S, + ExprEngine &Eng) { + runCheckersForStmt(/*isPreVisit=*/true, Dst, Src, S, Eng); + } + + /// \brief Run checkers for post-visiting Stmts. + /// + /// The notification is performed for every explored CFGElement, which does + /// not include the control flow statements such as IfStmt. + /// + /// \sa runCheckersForBranchCondition, runCheckersForPreStmt + void runCheckersForPostStmt(ExplodedNodeSet &Dst, + const ExplodedNodeSet &Src, + const Stmt *S, + ExprEngine &Eng, + bool wasInlined = false) { + runCheckersForStmt(/*isPreVisit=*/false, Dst, Src, S, Eng, wasInlined); + } + + /// \brief Run checkers for visiting Stmts. + void runCheckersForStmt(bool isPreVisit, + ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, + const Stmt *S, ExprEngine &Eng, + bool wasInlined = false); + + /// \brief Run checkers for pre-visiting obj-c messages. + void runCheckersForPreObjCMessage(ExplodedNodeSet &Dst, + const ExplodedNodeSet &Src, + const ObjCMessage &msg, + ExprEngine &Eng) { + runCheckersForObjCMessage(/*isPreVisit=*/true, Dst, Src, msg, Eng); + } + + /// \brief Run checkers for post-visiting obj-c messages. + void runCheckersForPostObjCMessage(ExplodedNodeSet &Dst, + const ExplodedNodeSet &Src, + const ObjCMessage &msg, + ExprEngine &Eng) { + runCheckersForObjCMessage(/*isPreVisit=*/false, Dst, Src, msg, Eng); + } + + /// \brief Run checkers for visiting obj-c messages. + void runCheckersForObjCMessage(bool isPreVisit, + ExplodedNodeSet &Dst, + const ExplodedNodeSet &Src, + const ObjCMessage &msg, ExprEngine &Eng); + + /// \brief Run checkers for load/store of a location. + void runCheckersForLocation(ExplodedNodeSet &Dst, + const ExplodedNodeSet &Src, + SVal location, + bool isLoad, + const Stmt *NodeEx, + const Stmt *BoundEx, + ExprEngine &Eng); + + /// \brief Run checkers for binding of a value to a location. + void runCheckersForBind(ExplodedNodeSet &Dst, + const ExplodedNodeSet &Src, + SVal location, SVal val, + const Stmt *S, ExprEngine &Eng, + ProgramPoint::Kind PointKind); + + /// \brief Run checkers for end of analysis. + void runCheckersForEndAnalysis(ExplodedGraph &G, BugReporter &BR, + ExprEngine &Eng); + + /// \brief Run checkers for end of path. + void runCheckersForEndPath(NodeBuilderContext &BC, + ExplodedNodeSet &Dst, + ExprEngine &Eng); + + /// \brief Run checkers for branch condition. + void runCheckersForBranchCondition(const Stmt *condition, + ExplodedNodeSet &Dst, ExplodedNode *Pred, + ExprEngine &Eng); + + /// \brief Run checkers for live symbols. + /// + /// Allows modifying SymbolReaper object. For example, checkers can explicitly + /// register symbols of interest as live. These symbols will not be marked + /// dead and removed. + void runCheckersForLiveSymbols(ProgramStateRef state, + SymbolReaper &SymReaper); + + /// \brief Run checkers for dead symbols. + /// + /// Notifies checkers when symbols become dead. For example, this allows + /// checkers to aggressively clean up/reduce the checker state and produce + /// precise diagnostics. + void runCheckersForDeadSymbols(ExplodedNodeSet &Dst, + const ExplodedNodeSet &Src, + SymbolReaper &SymReaper, const Stmt *S, + ExprEngine &Eng); + + /// \brief True if at least one checker wants to check region changes. + bool wantsRegionChangeUpdate(ProgramStateRef state); + + /// \brief Run checkers for region changes. + /// + /// This corresponds to the check::RegionChanges callback. + /// \param state The current program state. + /// \param invalidated A set of all symbols potentially touched by the change. + /// \param ExplicitRegions The regions explicitly requested for invalidation. + /// For example, in the case of a function call, these would be arguments. + /// \param Regions The transitive closure of accessible regions, + /// i.e. all regions that may have been touched by this change. + /// \param The call expression wrapper if the regions are invalidated by a + /// call. + ProgramStateRef + runCheckersForRegionChanges(ProgramStateRef state, + const StoreManager::InvalidatedSymbols *invalidated, + ArrayRef<const MemRegion *> ExplicitRegions, + ArrayRef<const MemRegion *> Regions, + const CallOrObjCMessage *Call); + + /// \brief Run checkers for handling assumptions on symbolic values. + ProgramStateRef runCheckersForEvalAssume(ProgramStateRef state, + SVal Cond, bool Assumption); + + /// \brief Run checkers for evaluating a call. + void runCheckersForEvalCall(ExplodedNodeSet &Dst, + const ExplodedNodeSet &Src, + const CallExpr *CE, ExprEngine &Eng, + GraphExpander *defaultEval = 0); + + /// \brief Run checkers for the entire Translation Unit. + void runCheckersOnEndOfTranslationUnit(const TranslationUnitDecl *TU, + AnalysisManager &mgr, + BugReporter &BR); + + /// \brief Run checkers for debug-printing a ProgramState. + /// + /// Unlike most other callbacks, any checker can simply implement the virtual + /// method CheckerBase::printState if it has custom data to print. + /// \param Out The output stream + /// \param State The state being printed + /// \param NL The preferred representation of a newline. + /// \param Sep The preferred separator between different kinds of data. + void runCheckersForPrintState(raw_ostream &Out, ProgramStateRef State, + const char *NL, const char *Sep); + +//===----------------------------------------------------------------------===// +// Internal registration functions for AST traversing. +//===----------------------------------------------------------------------===// + + // Functions used by the registration mechanism, checkers should not touch + // these directly. + + typedef CheckerFn<void (const Decl *, AnalysisManager&, BugReporter &)> + CheckDeclFunc; + + typedef bool (*HandlesDeclFunc)(const Decl *D); + void _registerForDecl(CheckDeclFunc checkfn, HandlesDeclFunc isForDeclFn); + + void _registerForBody(CheckDeclFunc checkfn); + +//===----------------------------------------------------------------------===// +// Internal registration functions for path-sensitive checking. +//===----------------------------------------------------------------------===// + + typedef CheckerFn<void (const Stmt *, CheckerContext &)> CheckStmtFunc; + + typedef CheckerFn<void (const ObjCMessage &, CheckerContext &)> + CheckObjCMessageFunc; + + typedef CheckerFn<void (const SVal &location, bool isLoad, + const Stmt *S, + CheckerContext &)> + CheckLocationFunc; + + typedef CheckerFn<void (const SVal &location, const SVal &val, + const Stmt *S, CheckerContext &)> + CheckBindFunc; + + typedef CheckerFn<void (ExplodedGraph &, BugReporter &, ExprEngine &)> + CheckEndAnalysisFunc; + + typedef CheckerFn<void (CheckerContext &)> + CheckEndPathFunc; + + typedef CheckerFn<void (const Stmt *, CheckerContext &)> + CheckBranchConditionFunc; + + typedef CheckerFn<void (SymbolReaper &, CheckerContext &)> + CheckDeadSymbolsFunc; + + typedef CheckerFn<void (ProgramStateRef,SymbolReaper &)> CheckLiveSymbolsFunc; + + typedef CheckerFn<ProgramStateRef (ProgramStateRef, + const StoreManager::InvalidatedSymbols *symbols, + ArrayRef<const MemRegion *> ExplicitRegions, + ArrayRef<const MemRegion *> Regions, + const CallOrObjCMessage *Call)> + CheckRegionChangesFunc; + + typedef CheckerFn<bool (ProgramStateRef)> WantsRegionChangeUpdateFunc; + + typedef CheckerFn<ProgramStateRef (ProgramStateRef, + const SVal &cond, bool assumption)> + EvalAssumeFunc; + + typedef CheckerFn<bool (const CallExpr *, CheckerContext &)> + EvalCallFunc; + + typedef CheckerFn<bool (const CallExpr *, ExprEngine &Eng, + ExplodedNode *Pred, + ExplodedNodeSet &Dst)> + InlineCallFunc; + + typedef CheckerFn<void (const TranslationUnitDecl *, + AnalysisManager&, BugReporter &)> + CheckEndOfTranslationUnit; + + typedef bool (*HandlesStmtFunc)(const Stmt *D); + void _registerForPreStmt(CheckStmtFunc checkfn, + HandlesStmtFunc isForStmtFn); + void _registerForPostStmt(CheckStmtFunc checkfn, + HandlesStmtFunc isForStmtFn); + + void _registerForPreObjCMessage(CheckObjCMessageFunc checkfn); + void _registerForPostObjCMessage(CheckObjCMessageFunc checkfn); + + void _registerForLocation(CheckLocationFunc checkfn); + + void _registerForBind(CheckBindFunc checkfn); + + void _registerForEndAnalysis(CheckEndAnalysisFunc checkfn); + + void _registerForEndPath(CheckEndPathFunc checkfn); + + void _registerForBranchCondition(CheckBranchConditionFunc checkfn); + + void _registerForLiveSymbols(CheckLiveSymbolsFunc checkfn); + + void _registerForDeadSymbols(CheckDeadSymbolsFunc checkfn); + + void _registerForRegionChanges(CheckRegionChangesFunc checkfn, + WantsRegionChangeUpdateFunc wantUpdateFn); + + void _registerForEvalAssume(EvalAssumeFunc checkfn); + + void _registerForEvalCall(EvalCallFunc checkfn); + + void _registerForInlineCall(InlineCallFunc checkfn); + + void _registerForEndOfTranslationUnit(CheckEndOfTranslationUnit checkfn); + +//===----------------------------------------------------------------------===// +// Internal registration functions for events. +//===----------------------------------------------------------------------===// + + typedef void *EventTag; + typedef CheckerFn<void (const void *event)> CheckEventFunc; + + template <typename EVENT> + void _registerListenerForEvent(CheckEventFunc checkfn) { + EventInfo &info = Events[getTag<EVENT>()]; + info.Checkers.push_back(checkfn); + } + + template <typename EVENT> + void _registerDispatcherForEvent() { + EventInfo &info = Events[getTag<EVENT>()]; + info.HasDispatcher = true; + } + + template <typename EVENT> + void _dispatchEvent(const EVENT &event) const { + EventsTy::const_iterator I = Events.find(getTag<EVENT>()); + if (I == Events.end()) + return; + const EventInfo &info = I->second; + for (unsigned i = 0, e = info.Checkers.size(); i != e; ++i) + info.Checkers[i](&event); + } + +//===----------------------------------------------------------------------===// +// Implementation details. +//===----------------------------------------------------------------------===// + +private: + template <typename CHECKER> + static void destruct(void *obj) { delete static_cast<CHECKER *>(obj); } + + template <typename T> + static void *getTag() { static int tag; return &tag; } + + llvm::DenseMap<CheckerTag, CheckerRef> CheckerTags; + + std::vector<CheckerDtor> CheckerDtors; + + struct DeclCheckerInfo { + CheckDeclFunc CheckFn; + HandlesDeclFunc IsForDeclFn; + }; + std::vector<DeclCheckerInfo> DeclCheckers; + + std::vector<CheckDeclFunc> BodyCheckers; + + typedef SmallVector<CheckDeclFunc, 4> CachedDeclCheckers; + typedef llvm::DenseMap<unsigned, CachedDeclCheckers> CachedDeclCheckersMapTy; + CachedDeclCheckersMapTy CachedDeclCheckersMap; + + struct StmtCheckerInfo { + CheckStmtFunc CheckFn; + HandlesStmtFunc IsForStmtFn; + bool IsPreVisit; + }; + std::vector<StmtCheckerInfo> StmtCheckers; + + struct CachedStmtCheckersKey { + unsigned StmtKind; + bool IsPreVisit; + + CachedStmtCheckersKey() : StmtKind(0), IsPreVisit(0) { } + CachedStmtCheckersKey(unsigned stmtKind, bool isPreVisit) + : StmtKind(stmtKind), IsPreVisit(isPreVisit) { } + + static CachedStmtCheckersKey getSentinel() { + return CachedStmtCheckersKey(~0U, 0); + } + unsigned getHashValue() const { + llvm::FoldingSetNodeID ID; + ID.AddInteger(StmtKind); + ID.AddBoolean(IsPreVisit); + return ID.ComputeHash(); + } + bool operator==(const CachedStmtCheckersKey &RHS) const { + return StmtKind == RHS.StmtKind && IsPreVisit == RHS.IsPreVisit; + } + }; + friend struct llvm::DenseMapInfo<CachedStmtCheckersKey>; + + typedef SmallVector<CheckStmtFunc, 4> CachedStmtCheckers; + typedef llvm::DenseMap<CachedStmtCheckersKey, CachedStmtCheckers> + CachedStmtCheckersMapTy; + CachedStmtCheckersMapTy CachedStmtCheckersMap; + + CachedStmtCheckers *getCachedStmtCheckersFor(const Stmt *S, bool isPreVisit); + + std::vector<CheckObjCMessageFunc> PreObjCMessageCheckers; + std::vector<CheckObjCMessageFunc> PostObjCMessageCheckers; + + std::vector<CheckLocationFunc> LocationCheckers; + + std::vector<CheckBindFunc> BindCheckers; + + std::vector<CheckEndAnalysisFunc> EndAnalysisCheckers; + + std::vector<CheckEndPathFunc> EndPathCheckers; + + std::vector<CheckBranchConditionFunc> BranchConditionCheckers; + + std::vector<CheckLiveSymbolsFunc> LiveSymbolsCheckers; + + std::vector<CheckDeadSymbolsFunc> DeadSymbolsCheckers; + + struct RegionChangesCheckerInfo { + CheckRegionChangesFunc CheckFn; + WantsRegionChangeUpdateFunc WantUpdateFn; + }; + std::vector<RegionChangesCheckerInfo> RegionChangesCheckers; + + std::vector<EvalAssumeFunc> EvalAssumeCheckers; + + std::vector<EvalCallFunc> EvalCallCheckers; + + std::vector<InlineCallFunc> InlineCallCheckers; + + std::vector<CheckEndOfTranslationUnit> EndOfTranslationUnitCheckers; + + struct EventInfo { + SmallVector<CheckEventFunc, 4> Checkers; + bool HasDispatcher; + EventInfo() : HasDispatcher(false) { } + }; + + typedef llvm::DenseMap<EventTag, EventInfo> EventsTy; + EventsTy Events; +}; + +} // end ento namespace + +} // end clang namespace + +namespace llvm { + /// Define DenseMapInfo so that CachedStmtCheckersKey can be used as key + /// in DenseMap and DenseSets. + template <> + struct DenseMapInfo<clang::ento::CheckerManager::CachedStmtCheckersKey> { + static inline clang::ento::CheckerManager::CachedStmtCheckersKey + getEmptyKey() { + return clang::ento::CheckerManager::CachedStmtCheckersKey(); + } + static inline clang::ento::CheckerManager::CachedStmtCheckersKey + getTombstoneKey() { + return clang::ento::CheckerManager::CachedStmtCheckersKey::getSentinel(); + } + + static unsigned + getHashValue(clang::ento::CheckerManager::CachedStmtCheckersKey S) { + return S.getHashValue(); + } + + static bool isEqual(clang::ento::CheckerManager::CachedStmtCheckersKey LHS, + clang::ento::CheckerManager::CachedStmtCheckersKey RHS) { + return LHS == RHS; + } + }; +} // end namespace llvm + +#endif diff --git a/clang/include/clang/StaticAnalyzer/Core/CheckerOptInfo.h b/clang/include/clang/StaticAnalyzer/Core/CheckerOptInfo.h new file mode 100644 index 0000000..6ce5b3c --- /dev/null +++ b/clang/include/clang/StaticAnalyzer/Core/CheckerOptInfo.h @@ -0,0 +1,43 @@ +//===--- CheckerOptInfo.h - Specifies which checkers to use -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_CORE_CHECKEROPTINFO_H +#define LLVM_CLANG_STATICANALYZER_CORE_CHECKEROPTINFO_H + +#include "clang/Basic/LLVM.h" + +namespace clang { +namespace ento { + +/// Represents a request to include or exclude a checker or package from a +/// specific analysis run. +/// +/// \sa CheckerRegistry::initializeManager +class CheckerOptInfo { + StringRef Name; + bool Enable; + bool Claimed; + +public: + CheckerOptInfo(StringRef name, bool enable) + : Name(name), Enable(enable), Claimed(false) { } + + StringRef getName() const { return Name; } + bool isEnabled() const { return Enable; } + bool isDisabled() const { return !isEnabled(); } + + bool isClaimed() const { return Claimed; } + bool isUnclaimed() const { return !isClaimed(); } + void claim() { Claimed = true; } +}; + +} // end namespace ento +} // end namespace clang + +#endif diff --git a/clang/include/clang/StaticAnalyzer/Core/CheckerRegistry.h b/clang/include/clang/StaticAnalyzer/Core/CheckerRegistry.h new file mode 100644 index 0000000..1452d45 --- /dev/null +++ b/clang/include/clang/StaticAnalyzer/Core/CheckerRegistry.h @@ -0,0 +1,134 @@ +//===--- CheckerRegistry.h - Maintains all available checkers ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_CORE_CHECKERREGISTRY_H +#define LLVM_CLANG_STATICANALYZER_CORE_CHECKERREGISTRY_H + +#include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/Basic/LLVM.h" +#include <vector> + +// FIXME: move this information to an HTML file in docs/. +// At the very least, a checker plugin is a dynamic library that exports +// clang_analyzerAPIVersionString. This should be defined as follows: +// +// extern "C" +// const char clang_analyzerAPIVersionString[] = +// CLANG_ANALYZER_API_VERSION_STRING; +// +// This is used to check whether the current version of the analyzer is known to +// be incompatible with a plugin. Plugins with incompatible version strings, +// or without a version string at all, will not be loaded. +// +// To add a custom checker to the analyzer, the plugin must also define the +// function clang_registerCheckers. For example: +// +// extern "C" +// void clang_registerCheckers (CheckerRegistry ®istry) { +// registry.addChecker<MainCallChecker>("example.MainCallChecker", +// "Disallows calls to functions called main"); +// } +// +// The first method argument is the full name of the checker, including its +// enclosing package. By convention, the registered name of a checker is the +// name of the associated class (the template argument). +// The second method argument is a short human-readable description of the +// checker. +// +// The clang_registerCheckers function may add any number of checkers to the +// registry. If any checkers require additional initialization, use the three- +// argument form of CheckerRegistry::addChecker. +// +// To load a checker plugin, specify the full path to the dynamic library as +// the argument to the -load option in the cc1 frontend. You can then enable +// your custom checker using the -analyzer-checker: +// +// clang -cc1 -load </path/to/plugin.dylib> -analyze +// -analyzer-checker=<example.MainCallChecker> +// +// For a complete working example, see examples/analyzer-plugin. + + +namespace clang { +namespace ento { + +#ifndef CLANG_ANALYZER_API_VERSION_STRING +// FIXME: The Clang version string is not particularly granular; +// the analyzer infrastructure can change a lot between releases. +// Unfortunately, this string has to be statically embedded in each plugin, +// so we can't just use the functions defined in Version.h. +#include "clang/Basic/Version.h" +#define CLANG_ANALYZER_API_VERSION_STRING CLANG_VERSION_STRING +#endif + +class CheckerOptInfo; + +/// Manages a set of available checkers for running a static analysis. +/// The checkers are organized into packages by full name, where including +/// a package will recursively include all subpackages and checkers within it. +/// For example, the checker "core.builtin.NoReturnFunctionChecker" will be +/// included if initializeManager() is called with an option of "core", +/// "core.builtin", or the full name "core.builtin.NoReturnFunctionChecker". +class CheckerRegistry { +public: + /// Initialization functions perform any necessary setup for a checker. + /// They should include a call to CheckerManager::registerChecker. + typedef void (*InitializationFunction)(CheckerManager &); + struct CheckerInfo { + InitializationFunction Initialize; + StringRef FullName; + StringRef Desc; + + CheckerInfo(InitializationFunction fn, StringRef name, StringRef desc) + : Initialize(fn), FullName(name), Desc(desc) {} + }; + + typedef std::vector<CheckerInfo> CheckerInfoList; + +private: + template <typename T> + static void initializeManager(CheckerManager &mgr) { + mgr.registerChecker<T>(); + } + +public: + /// Adds a checker to the registry. Use this non-templated overload when your + /// checker requires custom initialization. + void addChecker(InitializationFunction fn, StringRef fullName, + StringRef desc); + + /// Adds a checker to the registry. Use this templated overload when your + /// checker does not require any custom initialization. + template <class T> + void addChecker(StringRef fullName, StringRef desc) { + // Avoid MSVC's Compiler Error C2276: + // http://msdn.microsoft.com/en-us/library/850cstw1(v=VS.80).aspx + addChecker(&CheckerRegistry::initializeManager<T>, fullName, desc); + } + + /// Initializes a CheckerManager by calling the initialization functions for + /// all checkers specified by the given CheckerOptInfo list. The order of this + /// list is significant; later options can be used to reverse earlier ones. + /// This can be used to exclude certain checkers in an included package. + void initializeManager(CheckerManager &mgr, + SmallVectorImpl<CheckerOptInfo> &opts) const; + + /// Prints the name and description of all checkers in this registry. + /// This output is not intended to be machine-parseable. + void printHelp(raw_ostream &out, size_t maxNameChars = 30) const ; + +private: + mutable CheckerInfoList Checkers; + mutable llvm::StringMap<size_t> Packages; +}; + +} // end namespace ento +} // end namespace clang + +#endif diff --git a/clang/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h b/clang/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h new file mode 100644 index 0000000..65be3a4 --- /dev/null +++ b/clang/include/clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h @@ -0,0 +1,46 @@ +//===--- PathDiagnosticClients.h - Path Diagnostic Clients ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the interface to create different path diagostic clients. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_GR_PATH_DIAGNOSTIC_CLIENTS_H +#define LLVM_CLANG_GR_PATH_DIAGNOSTIC_CLIENTS_H + +#include <string> + +namespace clang { + +class Preprocessor; + +namespace ento { + +class PathDiagnosticConsumer; + +PathDiagnosticConsumer* +createHTMLDiagnosticConsumer(const std::string& prefix, const Preprocessor &PP); + +PathDiagnosticConsumer* +createPlistDiagnosticConsumer(const std::string& prefix, const Preprocessor &PP, + PathDiagnosticConsumer *SubPD = 0); + +PathDiagnosticConsumer* +createPlistMultiFileDiagnosticConsumer(const std::string& prefix, + const Preprocessor &PP); + +PathDiagnosticConsumer* +createTextPathDiagnosticConsumer(const std::string& prefix, + const Preprocessor &PP); + +} // end GR namespace + +} // end clang namespace + +#endif diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/.#CheckerContext_flymake.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/.#CheckerContext_flymake.h new file mode 120000 index 0000000..235903b --- /dev/null +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/.#CheckerContext_flymake.h @@ -0,0 +1 @@ +carlo@pc-4w14-0.cs.usyd.edu.au.1585:1347012043
\ No newline at end of file diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h new file mode 100644 index 0000000..d01644b --- /dev/null +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h @@ -0,0 +1,203 @@ +//== AnalysisManager.h - Path sensitive analysis data manager ------*- C++ -*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the AnalysisManager class that manages the data and policy +// for path sensitive analysis. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_GR_ANALYSISMANAGER_H +#define LLVM_CLANG_GR_ANALYSISMANAGER_H + +#include "clang/Analysis/AnalysisContext.h" +#include "clang/Frontend/AnalyzerOptions.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" +#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" + +namespace clang { + +namespace ento { + class CheckerManager; + +class AnalysisManager : public BugReporterData { + virtual void anchor(); + AnalysisDeclContextManager AnaCtxMgr; + + ASTContext &Ctx; + DiagnosticsEngine &Diags; + const LangOptions &LangOpts; + + OwningPtr<PathDiagnosticConsumer> PD; + + // Configurable components creators. + StoreManagerCreator CreateStoreMgr; + ConstraintManagerCreator CreateConstraintMgr; + + CheckerManager *CheckerMgr; + + enum AnalysisScope { ScopeTU, ScopeDecl } AScope; + + /// \brief The maximum number of exploded nodes the analyzer will generate. + unsigned MaxNodes; + + /// \brief The maximum number of times the analyzer visits a block. + unsigned MaxVisit; + + bool VisualizeEGDot; + bool VisualizeEGUbi; + AnalysisPurgeMode PurgeDead; + + /// \brief The flag regulates if we should eagerly assume evaluations of + /// conditionals, thus, bifurcating the path. + /// + /// EagerlyAssume - A flag indicating how the engine should handle + /// expressions such as: 'x = (y != 0)'. When this flag is true then + /// the subexpression 'y != 0' will be eagerly assumed to be true or false, + /// thus evaluating it to the integers 0 or 1 respectively. The upside + /// is that this can increase analysis precision until we have a better way + /// to lazily evaluate such logic. The downside is that it eagerly + /// bifurcates paths. + bool EagerlyAssume; + bool TrimGraph; + bool EagerlyTrimEGraph; + +public: + // \brief inter-procedural analysis mode. + AnalysisIPAMode IPAMode; + + // Settings for inlining tuning. + /// \brief The inlining stack depth limit. + unsigned InlineMaxStackDepth; + /// \brief The max number of basic blocks in a function being inlined. + unsigned InlineMaxFunctionSize; + /// \brief The mode of function selection used during inlining. + AnalysisInliningMode InliningMode; + + /// \brief Do not re-analyze paths leading to exhausted nodes with a different + /// strategy. We get better code coverage when retry is enabled. + bool NoRetryExhausted; + +public: + AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags, + const LangOptions &lang, PathDiagnosticConsumer *pd, + StoreManagerCreator storemgr, + ConstraintManagerCreator constraintmgr, + CheckerManager *checkerMgr, + unsigned maxnodes, unsigned maxvisit, + bool vizdot, bool vizubi, AnalysisPurgeMode purge, + bool eager, bool trim, + bool useUnoptimizedCFG, + bool addImplicitDtors, bool addInitializers, + bool eagerlyTrimEGraph, + AnalysisIPAMode ipa, + unsigned inlineMaxStack, + unsigned inlineMaxFunctionSize, + AnalysisInliningMode inliningMode, + bool NoRetry); + + /// Construct a clone of the given AnalysisManager with the given ASTContext + /// and DiagnosticsEngine. + AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags, + AnalysisManager &ParentAM); + + ~AnalysisManager() { FlushDiagnostics(); } + + void ClearContexts() { + AnaCtxMgr.clear(); + } + + AnalysisDeclContextManager& getAnalysisDeclContextManager() { + return AnaCtxMgr; + } + + StoreManagerCreator getStoreManagerCreator() { + return CreateStoreMgr; + } + + ConstraintManagerCreator getConstraintManagerCreator() { + return CreateConstraintMgr; + } + + CheckerManager *getCheckerManager() const { return CheckerMgr; } + + virtual ASTContext &getASTContext() { + return Ctx; + } + + virtual SourceManager &getSourceManager() { + return getASTContext().getSourceManager(); + } + + virtual DiagnosticsEngine &getDiagnostic() { + return Diags; + } + + const LangOptions &getLangOpts() const { + return LangOpts; + } + + virtual PathDiagnosticConsumer *getPathDiagnosticConsumer() { + return PD.get(); + } + + void FlushDiagnostics() { + if (PD.get()) + PD->FlushDiagnostics(0); + } + + unsigned getMaxNodes() const { return MaxNodes; } + + unsigned getMaxVisit() const { return MaxVisit; } + + bool shouldVisualizeGraphviz() const { return VisualizeEGDot; } + + bool shouldVisualizeUbigraph() const { return VisualizeEGUbi; } + + bool shouldVisualize() const { + return VisualizeEGDot || VisualizeEGUbi; + } + + bool shouldEagerlyTrimExplodedGraph() const { return EagerlyTrimEGraph; } + + bool shouldTrimGraph() const { return TrimGraph; } + + AnalysisPurgeMode getPurgeMode() const { return PurgeDead; } + + bool shouldEagerlyAssume() const { return EagerlyAssume; } + + bool shouldInlineCall() const { return (IPAMode == Inlining); } + + CFG *getCFG(Decl const *D) { + return AnaCtxMgr.getContext(D)->getCFG(); + } + + template <typename T> + T *getAnalysis(Decl const *D) { + return AnaCtxMgr.getContext(D)->getAnalysis<T>(); + } + + ParentMap &getParentMap(Decl const *D) { + return AnaCtxMgr.getContext(D)->getParentMap(); + } + + AnalysisDeclContext *getAnalysisDeclContext(const Decl *D) { + return AnaCtxMgr.getContext(D); + } + + AnalysisDeclContext *getAnalysisDeclContext(const Decl *D, idx::TranslationUnit *TU) { + return AnaCtxMgr.getContext(D, TU); + } + +}; + +} // enAnaCtxMgrspace + +} // end clang namespace + +#endif diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h new file mode 100644 index 0000000..9a699f9 --- /dev/null +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h @@ -0,0 +1,199 @@ +//=== BasicValueFactory.h - Basic values for Path Sens analysis --*- C++ -*---// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines BasicValueFactory, a class that manages the lifetime +// of APSInt objects and symbolic constraints used by ExprEngine +// and related classes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_GR_BASICVALUEFACTORY_H +#define LLVM_CLANG_GR_BASICVALUEFACTORY_H + +#include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" + +namespace clang { +namespace ento { + +class CompoundValData : public llvm::FoldingSetNode { + QualType T; + llvm::ImmutableList<SVal> L; + +public: + CompoundValData(QualType t, llvm::ImmutableList<SVal> l) + : T(t), L(l) {} + + typedef llvm::ImmutableList<SVal>::iterator iterator; + iterator begin() const { return L.begin(); } + iterator end() const { return L.end(); } + + static void Profile(llvm::FoldingSetNodeID& ID, QualType T, + llvm::ImmutableList<SVal> L); + + void Profile(llvm::FoldingSetNodeID& ID) { Profile(ID, T, L); } +}; + +class LazyCompoundValData : public llvm::FoldingSetNode { + StoreRef store; + const TypedValueRegion *region; +public: + LazyCompoundValData(const StoreRef &st, const TypedValueRegion *r) + : store(st), region(r) {} + + const void *getStore() const { return store.getStore(); } + const TypedValueRegion *getRegion() const { return region; } + + static void Profile(llvm::FoldingSetNodeID& ID, + const StoreRef &store, + const TypedValueRegion *region); + + void Profile(llvm::FoldingSetNodeID& ID) { Profile(ID, store, region); } +}; + +class BasicValueFactory { + typedef llvm::FoldingSet<llvm::FoldingSetNodeWrapper<llvm::APSInt> > + APSIntSetTy; + + ASTContext &Ctx; + llvm::BumpPtrAllocator& BPAlloc; + + APSIntSetTy APSIntSet; + void * PersistentSVals; + void * PersistentSValPairs; + + llvm::ImmutableList<SVal>::Factory SValListFactory; + llvm::FoldingSet<CompoundValData> CompoundValDataSet; + llvm::FoldingSet<LazyCompoundValData> LazyCompoundValDataSet; + +public: + BasicValueFactory(ASTContext &ctx, llvm::BumpPtrAllocator& Alloc) + : Ctx(ctx), BPAlloc(Alloc), PersistentSVals(0), PersistentSValPairs(0), + SValListFactory(Alloc) {} + + ~BasicValueFactory(); + + ASTContext &getContext() const { return Ctx; } + + const llvm::APSInt& getValue(const llvm::APSInt& X); + const llvm::APSInt& getValue(const llvm::APInt& X, bool isUnsigned); + const llvm::APSInt& getValue(uint64_t X, unsigned BitWidth, bool isUnsigned); + const llvm::APSInt& getValue(uint64_t X, QualType T); + + /// Convert - Create a new persistent APSInt with the same value as 'From' + /// but with the bitwidth and signedness of 'To'. + const llvm::APSInt &Convert(const llvm::APSInt& To, + const llvm::APSInt& From) { + + if (To.isUnsigned() == From.isUnsigned() && + To.getBitWidth() == From.getBitWidth()) + return From; + + return getValue(From.getSExtValue(), To.getBitWidth(), To.isUnsigned()); + } + + const llvm::APSInt &Convert(QualType T, const llvm::APSInt &From) { + assert(T->isIntegerType() || Loc::isLocType(T)); + unsigned bitwidth = Ctx.getTypeSize(T); + bool isUnsigned + = T->isUnsignedIntegerOrEnumerationType() || Loc::isLocType(T); + + if (isUnsigned == From.isUnsigned() && bitwidth == From.getBitWidth()) + return From; + + return getValue(From.getSExtValue(), bitwidth, isUnsigned); + } + + const llvm::APSInt& getIntValue(uint64_t X, bool isUnsigned) { + QualType T = isUnsigned ? Ctx.UnsignedIntTy : Ctx.IntTy; + return getValue(X, T); + } + + inline const llvm::APSInt& getMaxValue(const llvm::APSInt &v) { + return getValue(llvm::APSInt::getMaxValue(v.getBitWidth(), v.isUnsigned())); + } + + inline const llvm::APSInt& getMinValue(const llvm::APSInt &v) { + return getValue(llvm::APSInt::getMinValue(v.getBitWidth(), v.isUnsigned())); + } + + inline const llvm::APSInt& getMaxValue(QualType T) { + assert(T->isIntegerType() || Loc::isLocType(T)); + bool isUnsigned + = T->isUnsignedIntegerOrEnumerationType() || Loc::isLocType(T); + return getValue(llvm::APSInt::getMaxValue(Ctx.getTypeSize(T), isUnsigned)); + } + + inline const llvm::APSInt& getMinValue(QualType T) { + assert(T->isIntegerType() || Loc::isLocType(T)); + bool isUnsigned + = T->isUnsignedIntegerOrEnumerationType() || Loc::isLocType(T); + return getValue(llvm::APSInt::getMinValue(Ctx.getTypeSize(T), isUnsigned)); + } + + inline const llvm::APSInt& Add1(const llvm::APSInt& V) { + llvm::APSInt X = V; + ++X; + return getValue(X); + } + + inline const llvm::APSInt& Sub1(const llvm::APSInt& V) { + llvm::APSInt X = V; + --X; + return getValue(X); + } + + inline const llvm::APSInt& getZeroWithPtrWidth(bool isUnsigned = true) { + return getValue(0, Ctx.getTypeSize(Ctx.VoidPtrTy), isUnsigned); + } + + inline const llvm::APSInt &getIntWithPtrWidth(uint64_t X, bool isUnsigned) { + return getValue(X, Ctx.getTypeSize(Ctx.VoidPtrTy), isUnsigned); + } + + inline const llvm::APSInt& getTruthValue(bool b, QualType T) { + return getValue(b ? 1 : 0, Ctx.getTypeSize(T), false); + } + + inline const llvm::APSInt& getTruthValue(bool b) { + return getTruthValue(b, Ctx.getLogicalOperationType()); + } + + const CompoundValData *getCompoundValData(QualType T, + llvm::ImmutableList<SVal> Vals); + + const LazyCompoundValData *getLazyCompoundValData(const StoreRef &store, + const TypedValueRegion *region); + + llvm::ImmutableList<SVal> getEmptySValList() { + return SValListFactory.getEmptyList(); + } + + llvm::ImmutableList<SVal> consVals(SVal X, llvm::ImmutableList<SVal> L) { + return SValListFactory.add(X, L); + } + + const llvm::APSInt* evalAPSInt(BinaryOperator::Opcode Op, + const llvm::APSInt& V1, + const llvm::APSInt& V2); + + const std::pair<SVal, uintptr_t>& + getPersistentSValWithData(const SVal& V, uintptr_t Data); + + const std::pair<SVal, SVal>& + getPersistentSValPair(const SVal& V1, const SVal& V2); + + const SVal* getPersistentSVal(SVal X); +}; + +} // end GR namespace + +} // end clang namespace + +#endif diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h new file mode 100644 index 0000000..2483a79 --- /dev/null +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h @@ -0,0 +1,62 @@ +//==- BlockCounter.h - ADT for counting block visits ---------------*- C++ -*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines BlockCounter, an abstract data type used to count +// the number of times a given block has been visited along a path +// analyzed by CoreEngine. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_GR_BLOCKCOUNTER +#define LLVM_CLANG_GR_BLOCKCOUNTER + +namespace llvm { + class BumpPtrAllocator; +} + +namespace clang { + +class StackFrameContext; + +namespace ento { + +/// \class BlockCounter +/// \brief An abstract data type used to count the number of times a given +/// block has been visited along a path analyzed by CoreEngine. +class BlockCounter { + void *Data; + + BlockCounter(void *D) : Data(D) {} + +public: + BlockCounter() : Data(0) {} + + unsigned getNumVisited(const StackFrameContext *CallSite, + unsigned BlockID) const; + + class Factory { + void *F; + public: + Factory(llvm::BumpPtrAllocator& Alloc); + ~Factory(); + + BlockCounter GetEmptyCounter(); + BlockCounter IncrementCount(BlockCounter BC, + const StackFrameContext *CallSite, + unsigned BlockID); + }; + + friend class Factory; +}; + +} // end GR namespace + +} // end clang namespace + +#endif diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h new file mode 100644 index 0000000..b051d33 --- /dev/null +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h @@ -0,0 +1,239 @@ +//== CheckerContext.h - Context info for path-sensitive checkers--*- C++ -*--=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines CheckerContext that provides contextual info for +// path-sensitive checkers. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SA_CORE_PATHSENSITIVE_CHECKERCONTEXT +#define LLVM_CLANG_SA_CORE_PATHSENSITIVE_CHECKERCONTEXT + +#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" + +namespace clang { +namespace ento { + +class CheckerContext { + ExprEngine &Eng; + /// The current exploded(symbolic execution) graph node. + ExplodedNode *Pred; + /// The flag is true if the (state of the execution) has been modified + /// by the checker using this context. For example, a new transition has been + /// added or a bug report issued. + bool Changed; + /// The tagged location, which is used to generate all new nodes. + const ProgramPoint Location; + NodeBuilder &NB; + +public: + /// If we are post visiting a call, this flag will be set if the + /// call was inlined. In all other cases it will be false. + const bool wasInlined; + + CheckerContext(NodeBuilder &builder, + ExprEngine &eng, + ExplodedNode *pred, + const ProgramPoint &loc, + bool wasInlined = false) + : Eng(eng), + Pred(pred), + Changed(false), + Location(loc), + NB(builder), + wasInlined(wasInlined) { + assert(Pred->getState() && + "We should not call the checkers on an empty state."); + } + + AnalysisManager &getAnalysisManager() { + return Eng.getAnalysisManager(); + } + + ConstraintManager &getConstraintManager() { + return Eng.getConstraintManager(); + } + + StoreManager &getStoreManager() { + return Eng.getStoreManager(); + } + + /// \brief Returns the previous node in the exploded graph, which includes + /// the state of the program before the checker ran. Note, checkers should + /// not retain the node in their state since the nodes might get invalidated. + ExplodedNode *getPredecessor() { return Pred; } + ProgramStateRef getState() const { return Pred->getState(); } + + /// \brief Check if the checker changed the state of the execution; ex: added + /// a new transition or a bug report. + bool isDifferent() { return Changed; } + + /// \brief Returns the number of times the current block has been visited + /// along the analyzed path. + unsigned getCurrentBlockCount() const { + return NB.getContext().getCurrentBlockCount(); + } + + ASTContext &getASTContext() { + return Eng.getContext(); + } + + const LangOptions &getLangOpts() const { + return Eng.getContext().getLangOpts(); + } + + const LocationContext *getLocationContext() const { + return Pred->getLocationContext(); + } + + BugReporter &getBugReporter() { + return Eng.getBugReporter(); + } + + SourceManager &getSourceManager() { + return getBugReporter().getSourceManager(); + } + + SValBuilder &getSValBuilder() { + return Eng.getSValBuilder(); + } + + SymbolManager &getSymbolManager() { + return getSValBuilder().getSymbolManager(); + } + + bool isObjCGCEnabled() const { + return Eng.isObjCGCEnabled(); + } + + ProgramStateManager &getStateManager() { + return Eng.getStateManager(); + } + + AnalysisDeclContext *getCurrentAnalysisDeclContext() const { + return Pred->getLocationContext()->getAnalysisDeclContext(); + } + + /// \brief If the given node corresponds to a PostStore program point, retrieve + /// the location region as it was uttered in the code. + /// + /// This utility can be useful for generating extensive diagnostics, for + /// example, for finding variables that the given symbol was assigned to. + static const MemRegion *getLocationRegionIfPostStore(const ExplodedNode *N) { + ProgramPoint L = N->getLocation(); + if (const PostStore *PSL = dyn_cast<PostStore>(&L)) + return reinterpret_cast<const MemRegion*>(PSL->getLocationValue()); + return 0; + } + + /// \brief Generates a new transition in the program state graph + /// (ExplodedGraph). Uses the default CheckerContext predecessor node. + /// + /// @param State The state of the generated node. + /// @param Tag The tag is used to uniquely identify the creation site. If no + /// tag is specified, a default tag, unique to the given checker, + /// will be used. Tags are used to prevent states generated at + /// different sites from caching out. + ExplodedNode *addTransition(ProgramStateRef State, + const ProgramPointTag *Tag = 0) { + return addTransitionImpl(State, false, 0, Tag); + } + + /// \brief Generates a default transition (containing checker tag but no + /// checker state changes). + ExplodedNode *addTransition() { + return addTransition(getState()); + } + + /// \brief Generates a new transition with the given predecessor. + /// Allows checkers to generate a chain of nodes. + /// + /// @param State The state of the generated node. + /// @param Pred The transition will be generated from the specified Pred node + /// to the newly generated node. + /// @param Tag The tag to uniquely identify the creation site. + /// @param IsSink Mark the new node as sink, which will stop exploration of + /// the given path. + ExplodedNode *addTransition(ProgramStateRef State, + ExplodedNode *Pred, + const ProgramPointTag *Tag = 0, + bool IsSink = false) { + return addTransitionImpl(State, IsSink, Pred, Tag); + } + + /// \brief Generate a sink node. Generating sink stops exploration of the + /// given path. + ExplodedNode *generateSink(ProgramStateRef state = 0) { + return addTransitionImpl(state ? state : getState(), true); + } + + /// \brief Emit the diagnostics report. + void EmitReport(BugReport *R) { + Changed = true; + Eng.getBugReporter().EmitReport(R); + } + + /// \brief Get the declaration of the called function (path-sensitive). + const FunctionDecl *getCalleeDecl(const CallExpr *CE) const; + + /// \brief Get the name of the called function (path-sensitive). + StringRef getCalleeName(const FunctionDecl *FunDecl) const; + + /// \brief Get the name of the called function (path-sensitive). + StringRef getCalleeName(const CallExpr *CE) const { + const FunctionDecl *FunDecl = getCalleeDecl(CE); + return getCalleeName(FunDecl); + } + + /// Given a function declaration and a name checks if this is a C lib + /// function with the given name. + bool isCLibraryFunction(const FunctionDecl *FD, StringRef Name); + static bool isCLibraryFunction(const FunctionDecl *FD, StringRef Name, + ASTContext &Context); + + /// \brief Depending on wither the location corresponds to a macro, return + /// either the macro name or the token spelling. + /// + /// This could be useful when checkers' logic depends on whether a function + /// is called with a given macro argument. For example: + /// s = socket(AF_INET,..) + /// If AF_INET is a macro, the result should be treated as a source of taint. + /// + /// \sa clang::Lexer::getSpelling(), clang::Lexer::getImmediateMacroName(). + StringRef getMacroNameOrSpelling(SourceLocation &Loc); + +private: + ExplodedNode *addTransitionImpl(ProgramStateRef State, + bool MarkAsSink, + ExplodedNode *P = 0, + const ProgramPointTag *Tag = 0) { + if (!State || (State == Pred->getState() && !Tag && !MarkAsSink)) + return Pred; + + Changed = true; + ExplodedNode *node = NB.generateNode(Tag ? Location.withTag(Tag) : Location, + State, + P ? P : Pred, MarkAsSink); + return node; + } +}; + +/// \brief A helper class which wraps a boolean value set to false by default. +struct DefaultBool { + bool Val; + DefaultBool() : Val(false) {} + operator bool() const { return Val; } + DefaultBool &operator=(bool b) { Val = b; return *this; } +}; + +} // end GR namespace + +} // end clang namespace + +#endif diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h new file mode 100644 index 0000000..12547e0 --- /dev/null +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h @@ -0,0 +1,43 @@ +//== CheckerHelpers.h - Helper functions for checkers ------------*- C++ -*--=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines CheckerVisitor. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_GR_PATHSENSITIVE_CHECKERHELPERS +#define LLVM_CLANG_GR_PATHSENSITIVE_CHECKERHELPERS + +#include "clang/AST/Stmt.h" + +namespace clang { + +namespace ento { + +bool containsMacro(const Stmt *S); +bool containsEnum(const Stmt *S); +bool containsStaticLocal(const Stmt *S); +bool containsBuiltinOffsetOf(const Stmt *S); +template <class T> bool containsStmt(const Stmt *S) { + if (isa<T>(S)) + return true; + + for (Stmt::const_child_range I = S->children(); I; ++I) + if (const Stmt *child = *I) + if (containsStmt<T>(child)) + return true; + + return false; +} + +} // end GR namespace + +} // end clang namespace + +#endif diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h new file mode 100644 index 0000000..4051cfc --- /dev/null +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h @@ -0,0 +1,83 @@ +//== ConstraintManager.h - Constraints on symbolic values.-------*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defined the interface to manage constraints on symbolic values. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_GR_CONSTRAINT_MANAGER_H +#define LLVM_CLANG_GR_CONSTRAINT_MANAGER_H + +#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" + +namespace llvm { +class APSInt; +} + +namespace clang { +namespace ento { + +class SubEngine; + +class ConstraintManager { +public: + virtual ~ConstraintManager(); + virtual ProgramStateRef assume(ProgramStateRef state, + DefinedSVal Cond, + bool Assumption) = 0; + + std::pair<ProgramStateRef, ProgramStateRef > + assumeDual(ProgramStateRef state, DefinedSVal Cond) + { + std::pair<ProgramStateRef, ProgramStateRef > res = + std::make_pair(assume(state, Cond, true), assume(state, Cond, false)); + + assert(!(!res.first && !res.second) && "System is over constrained."); + return res; + } + + virtual const llvm::APSInt* getSymVal(ProgramStateRef state, + SymbolRef sym) const = 0; + + virtual bool isEqual(ProgramStateRef state, + SymbolRef sym, + const llvm::APSInt& V) const = 0; + + virtual ProgramStateRef removeDeadBindings(ProgramStateRef state, + SymbolReaper& SymReaper) = 0; + + virtual void print(ProgramStateRef state, + raw_ostream &Out, + const char* nl, + const char *sep) = 0; + + virtual void EndPath(ProgramStateRef state) {} + +protected: + /// canReasonAbout - Not all ConstraintManagers can accurately reason about + /// all SVal values. This method returns true if the ConstraintManager can + /// reasonably handle a given SVal value. This is typically queried by + /// ExprEngine to determine if the value should be replaced with a + /// conjured symbolic value in order to recover some precision. + virtual bool canReasonAbout(SVal X) const = 0; +}; + +ConstraintManager* CreateBasicConstraintManager(ProgramStateManager& statemgr, + SubEngine &subengine); +ConstraintManager* CreateRangeConstraintManager(ProgramStateManager& statemgr, + SubEngine &subengine); +ConstraintManager* CreateIntervalConstraintManager(ProgramStateManager& statemgr, + SubEngine &subengine); + +} // end GR namespace + +} // end clang namespace + +#endif diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h new file mode 100644 index 0000000..59136fc --- /dev/null +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h @@ -0,0 +1,541 @@ +//==- CoreEngine.h - Path-Sensitive Dataflow Engine ----------------*- C++ -*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines a generic engine for intraprocedural, path-sensitive, +// dataflow analysis via graph reachability. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_GR_COREENGINE +#define LLVM_CLANG_GR_COREENGINE + +#include "clang/AST/Expr.h" +#include "clang/Analysis/AnalysisContext.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/WorkList.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h" +#include "llvm/ADT/OwningPtr.h" + +namespace clang { + +class ProgramPointTag; + +namespace ento { + +class NodeBuilder; + +//===----------------------------------------------------------------------===// +/// CoreEngine - Implements the core logic of the graph-reachability +/// analysis. It traverses the CFG and generates the ExplodedGraph. +/// Program "states" are treated as opaque void pointers. +/// The template class CoreEngine (which subclasses CoreEngine) +/// provides the matching component to the engine that knows the actual types +/// for states. Note that this engine only dispatches to transfer functions +/// at the statement and block-level. The analyses themselves must implement +/// any transfer function logic and the sub-expression level (if any). +class CoreEngine { + friend struct NodeBuilderContext; + friend class NodeBuilder; + friend class ExprEngine; + friend class CommonNodeBuilder; + friend class IndirectGotoNodeBuilder; + friend class SwitchNodeBuilder; + friend class EndOfFunctionNodeBuilder; +public: + typedef std::vector<std::pair<BlockEdge, const ExplodedNode*> > + BlocksExhausted; + + typedef std::vector<std::pair<const CFGBlock*, const ExplodedNode*> > + BlocksAborted; + +private: + + SubEngine& SubEng; + + /// G - The simulation graph. Each node is a (location,state) pair. + OwningPtr<ExplodedGraph> G; + + /// WList - A set of queued nodes that need to be processed by the + /// worklist algorithm. It is up to the implementation of WList to decide + /// the order that nodes are processed. + WorkList* WList; + + /// BCounterFactory - A factory object for created BlockCounter objects. + /// These are used to record for key nodes in the ExplodedGraph the + /// number of times different CFGBlocks have been visited along a path. + BlockCounter::Factory BCounterFactory; + + /// The locations where we stopped doing work because we visited a location + /// too many times. + BlocksExhausted blocksExhausted; + + /// The locations where we stopped because the engine aborted analysis, + /// usually because it could not reason about something. + BlocksAborted blocksAborted; + + /// The functions which have been analyzed through inlining. This is owned by + /// AnalysisConsumer. It can be null. + SetOfConstDecls *AnalyzedCallees; + + /// The information about functions shared by the whole translation unit. + /// (This data is owned by AnalysisConsumer.) + FunctionSummariesTy *FunctionSummaries; + + void generateNode(const ProgramPoint &Loc, + ProgramStateRef State, + ExplodedNode *Pred); + + void HandleBlockEdge(const BlockEdge &E, ExplodedNode *Pred); + void HandleBlockEntrance(const BlockEntrance &E, ExplodedNode *Pred); + void HandleBlockExit(const CFGBlock *B, ExplodedNode *Pred); + void HandlePostStmt(const CFGBlock *B, unsigned StmtIdx, ExplodedNode *Pred); + + void HandleBranch(const Stmt *Cond, const Stmt *Term, const CFGBlock *B, + ExplodedNode *Pred); + +private: + CoreEngine(const CoreEngine&); // Do not implement. + CoreEngine& operator=(const CoreEngine&); + + ExplodedNode *generateCallExitNode(ExplodedNode *N); + +public: + /// Construct a CoreEngine object to analyze the provided CFG using + /// a DFS exploration of the exploded graph. + CoreEngine(SubEngine& subengine, SetOfConstDecls *VisitedCallees, + FunctionSummariesTy *FS) + : SubEng(subengine), G(new ExplodedGraph()), + WList(WorkList::makeBFS()), + BCounterFactory(G->getAllocator()), + AnalyzedCallees(VisitedCallees), + FunctionSummaries(FS){} + + ~CoreEngine() { + delete WList; + } + + /// getGraph - Returns the exploded graph. + ExplodedGraph& getGraph() { return *G.get(); } + + /// takeGraph - Returns the exploded graph. Ownership of the graph is + /// transferred to the caller. + ExplodedGraph* takeGraph() { return G.take(); } + + /// ExecuteWorkList - Run the worklist algorithm for a maximum number of + /// steps. Returns true if there is still simulation state on the worklist. + bool ExecuteWorkList(const LocationContext *L, unsigned Steps, + ProgramStateRef InitState); + /// Returns true if there is still simulation state on the worklist. + bool ExecuteWorkListWithInitialState(const LocationContext *L, + unsigned Steps, + ProgramStateRef InitState, + ExplodedNodeSet &Dst); + + /// Dispatch the work list item based on the given location information. + /// Use Pred parameter as the predecessor state. + void dispatchWorkItem(ExplodedNode* Pred, ProgramPoint Loc, + const WorkListUnit& WU); + + // Functions for external checking of whether we have unfinished work + bool wasBlockAborted() const { return !blocksAborted.empty(); } + bool wasBlocksExhausted() const { return !blocksExhausted.empty(); } + bool hasWorkRemaining() const { return wasBlocksExhausted() || + WList->hasWork() || + wasBlockAborted(); } + + /// Inform the CoreEngine that a basic block was aborted because + /// it could not be completely analyzed. + void addAbortedBlock(const ExplodedNode *node, const CFGBlock *block) { + blocksAborted.push_back(std::make_pair(block, node)); + } + + WorkList *getWorkList() const { return WList; } + + BlocksExhausted::const_iterator blocks_exhausted_begin() const { + return blocksExhausted.begin(); + } + BlocksExhausted::const_iterator blocks_exhausted_end() const { + return blocksExhausted.end(); + } + BlocksAborted::const_iterator blocks_aborted_begin() const { + return blocksAborted.begin(); + } + BlocksAborted::const_iterator blocks_aborted_end() const { + return blocksAborted.end(); + } + + /// \brief Enqueue the given set of nodes onto the work list. + void enqueue(ExplodedNodeSet &Set); + + /// \brief Enqueue nodes that were created as a result of processing + /// a statement onto the work list. + void enqueue(ExplodedNodeSet &Set, const CFGBlock *Block, unsigned Idx); + + /// \brief enqueue the nodes corresponding to the end of function onto the + /// end of path / work list. + void enqueueEndOfFunction(ExplodedNodeSet &Set); + + /// \brief Enqueue a single node created as a result of statement processing. + void enqueueStmtNode(ExplodedNode *N, const CFGBlock *Block, unsigned Idx); +}; + +// TODO: Turn into a calss. +struct NodeBuilderContext { + CoreEngine &Eng; + const CFGBlock *Block; + ExplodedNode *Pred; + NodeBuilderContext(CoreEngine &E, const CFGBlock *B, ExplodedNode *N) + : Eng(E), Block(B), Pred(N) { assert(B); assert(!N->isSink()); } + + ExplodedNode *getPred() const { return Pred; } + + /// \brief Return the CFGBlock associated with this builder. + const CFGBlock *getBlock() const { return Block; } + + /// \brief Returns the number of times the current basic block has been + /// visited on the exploded graph path. + unsigned getCurrentBlockCount() const { + return Eng.WList->getBlockCounter().getNumVisited( + Pred->getLocationContext()->getCurrentStackFrame(), + Block->getBlockID()); + } +}; + +/// \class NodeBuilder +/// \brief This is the simplest builder which generates nodes in the +/// ExplodedGraph. +/// +/// The main benefit of the builder is that it automatically tracks the +/// frontier nodes (or destination set). This is the set of nodes which should +/// be propagated to the next step / builder. They are the nodes which have been +/// added to the builder (either as the input node set or as the newly +/// constructed nodes) but did not have any outgoing transitions added. +class NodeBuilder { + virtual void anchor(); +protected: + const NodeBuilderContext &C; + + /// Specifies if the builder results have been finalized. For example, if it + /// is set to false, autotransitions are yet to be generated. + bool Finalized; + bool HasGeneratedNodes; + /// \brief The frontier set - a set of nodes which need to be propagated after + /// the builder dies. + ExplodedNodeSet &Frontier; + + /// Checkes if the results are ready. + virtual bool checkResults() { + if (!Finalized) + return false; + return true; + } + + bool hasNoSinksInFrontier() { + for (iterator I = Frontier.begin(), E = Frontier.end(); I != E; ++I) { + if ((*I)->isSink()) + return false; + } + return true; + } + + /// Allow subclasses to finalize results before result_begin() is executed. + virtual void finalizeResults() {} + + ExplodedNode *generateNodeImpl(const ProgramPoint &PP, + ProgramStateRef State, + ExplodedNode *Pred, + bool MarkAsSink = false); + +public: + NodeBuilder(ExplodedNode *SrcNode, ExplodedNodeSet &DstSet, + const NodeBuilderContext &Ctx, bool F = true) + : C(Ctx), Finalized(F), HasGeneratedNodes(false), Frontier(DstSet) { + Frontier.Add(SrcNode); + } + + NodeBuilder(const ExplodedNodeSet &SrcSet, ExplodedNodeSet &DstSet, + const NodeBuilderContext &Ctx, bool F = true) + : C(Ctx), Finalized(F), HasGeneratedNodes(false), Frontier(DstSet) { + Frontier.insert(SrcSet); + assert(hasNoSinksInFrontier()); + } + + virtual ~NodeBuilder() {} + + /// \brief Generates a node in the ExplodedGraph. + /// + /// When a node is marked as sink, the exploration from the node is stopped - + /// the node becomes the last node on the path. + ExplodedNode *generateNode(const ProgramPoint &PP, + ProgramStateRef State, + ExplodedNode *Pred, + bool MarkAsSink = false) { + return generateNodeImpl(PP, State, Pred, MarkAsSink); + } + + const ExplodedNodeSet &getResults() { + finalizeResults(); + assert(checkResults()); + return Frontier; + } + + typedef ExplodedNodeSet::iterator iterator; + /// \brief Iterators through the results frontier. + inline iterator begin() { + finalizeResults(); + assert(checkResults()); + return Frontier.begin(); + } + inline iterator end() { + finalizeResults(); + return Frontier.end(); + } + + const NodeBuilderContext &getContext() { return C; } + bool hasGeneratedNodes() { return HasGeneratedNodes; } + + void takeNodes(const ExplodedNodeSet &S) { + for (ExplodedNodeSet::iterator I = S.begin(), E = S.end(); I != E; ++I ) + Frontier.erase(*I); + } + void takeNodes(ExplodedNode *N) { Frontier.erase(N); } + void addNodes(const ExplodedNodeSet &S) { Frontier.insert(S); } + void addNodes(ExplodedNode *N) { Frontier.Add(N); } +}; + +/// \class NodeBuilderWithSinks +/// \brief This node builder keeps track of the generated sink nodes. +class NodeBuilderWithSinks: public NodeBuilder { + virtual void anchor(); +protected: + SmallVector<ExplodedNode*, 2> sinksGenerated; + ProgramPoint &Location; + +public: + NodeBuilderWithSinks(ExplodedNode *Pred, ExplodedNodeSet &DstSet, + const NodeBuilderContext &Ctx, ProgramPoint &L) + : NodeBuilder(Pred, DstSet, Ctx), Location(L) {} + ExplodedNode *generateNode(ProgramStateRef State, + ExplodedNode *Pred, + const ProgramPointTag *Tag = 0, + bool MarkAsSink = false) { + ProgramPoint LocalLoc = (Tag ? Location.withTag(Tag): Location); + + ExplodedNode *N = generateNodeImpl(LocalLoc, State, Pred, MarkAsSink); + if (N && N->isSink()) + sinksGenerated.push_back(N); + return N; + } + + const SmallVectorImpl<ExplodedNode*> &getSinks() const { + return sinksGenerated; + } +}; + +/// \class StmtNodeBuilder +/// \brief This builder class is useful for generating nodes that resulted from +/// visiting a statement. The main difference from it's parent NodeBuilder is +/// that it creates a statement specific ProgramPoint. +class StmtNodeBuilder: public NodeBuilder { + NodeBuilder *EnclosingBldr; +public: + + /// \brief Constructs a StmtNodeBuilder. If the builder is going to process + /// nodes currently owned by another builder(with larger scope), use + /// Enclosing builder to transfer ownership. + StmtNodeBuilder(ExplodedNode *SrcNode, ExplodedNodeSet &DstSet, + const NodeBuilderContext &Ctx, NodeBuilder *Enclosing = 0) + : NodeBuilder(SrcNode, DstSet, Ctx), EnclosingBldr(Enclosing) { + if (EnclosingBldr) + EnclosingBldr->takeNodes(SrcNode); + } + + StmtNodeBuilder(ExplodedNodeSet &SrcSet, ExplodedNodeSet &DstSet, + const NodeBuilderContext &Ctx, NodeBuilder *Enclosing = 0) + : NodeBuilder(SrcSet, DstSet, Ctx), EnclosingBldr(Enclosing) { + if (EnclosingBldr) + for (ExplodedNodeSet::iterator I = SrcSet.begin(), + E = SrcSet.end(); I != E; ++I ) + EnclosingBldr->takeNodes(*I); + } + + virtual ~StmtNodeBuilder(); + + ExplodedNode *generateNode(const Stmt *S, + ExplodedNode *Pred, + ProgramStateRef St, + bool MarkAsSink = false, + const ProgramPointTag *tag = 0, + ProgramPoint::Kind K = ProgramPoint::PostStmtKind){ + const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K, + Pred->getLocationContext(), tag); + return generateNodeImpl(L, St, Pred, MarkAsSink); + } + + ExplodedNode *generateNode(const ProgramPoint &PP, + ExplodedNode *Pred, + ProgramStateRef State, + bool MarkAsSink = false) { + return generateNodeImpl(PP, State, Pred, MarkAsSink); + } +}; + +/// \brief BranchNodeBuilder is responsible for constructing the nodes +/// corresponding to the two branches of the if statement - true and false. +class BranchNodeBuilder: public NodeBuilder { + virtual void anchor(); + const CFGBlock *DstT; + const CFGBlock *DstF; + + bool InFeasibleTrue; + bool InFeasibleFalse; + +public: + BranchNodeBuilder(ExplodedNode *SrcNode, ExplodedNodeSet &DstSet, + const NodeBuilderContext &C, + const CFGBlock *dstT, const CFGBlock *dstF) + : NodeBuilder(SrcNode, DstSet, C), DstT(dstT), DstF(dstF), + InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) { + // The branch node builder does not generate autotransitions. + // If there are no successors it means that both branches are infeasible. + takeNodes(SrcNode); + } + + BranchNodeBuilder(const ExplodedNodeSet &SrcSet, ExplodedNodeSet &DstSet, + const NodeBuilderContext &C, + const CFGBlock *dstT, const CFGBlock *dstF) + : NodeBuilder(SrcSet, DstSet, C), DstT(dstT), DstF(dstF), + InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) { + takeNodes(SrcSet); + } + + ExplodedNode *generateNode(ProgramStateRef State, bool branch, + ExplodedNode *Pred); + + const CFGBlock *getTargetBlock(bool branch) const { + return branch ? DstT : DstF; + } + + void markInfeasible(bool branch) { + if (branch) + InFeasibleTrue = true; + else + InFeasibleFalse = true; + } + + bool isFeasible(bool branch) { + return branch ? !InFeasibleTrue : !InFeasibleFalse; + } +}; + +class IndirectGotoNodeBuilder { + CoreEngine& Eng; + const CFGBlock *Src; + const CFGBlock &DispatchBlock; + const Expr *E; + ExplodedNode *Pred; + +public: + IndirectGotoNodeBuilder(ExplodedNode *pred, const CFGBlock *src, + const Expr *e, const CFGBlock *dispatch, CoreEngine* eng) + : Eng(*eng), Src(src), DispatchBlock(*dispatch), E(e), Pred(pred) {} + + class iterator { + CFGBlock::const_succ_iterator I; + + friend class IndirectGotoNodeBuilder; + iterator(CFGBlock::const_succ_iterator i) : I(i) {} + public: + + iterator &operator++() { ++I; return *this; } + bool operator!=(const iterator &X) const { return I != X.I; } + + const LabelDecl *getLabel() const { + return llvm::cast<LabelStmt>((*I)->getLabel())->getDecl(); + } + + const CFGBlock *getBlock() const { + return *I; + } + }; + + iterator begin() { return iterator(DispatchBlock.succ_begin()); } + iterator end() { return iterator(DispatchBlock.succ_end()); } + + ExplodedNode *generateNode(const iterator &I, + ProgramStateRef State, + bool isSink = false); + + const Expr *getTarget() const { return E; } + + ProgramStateRef getState() const { return Pred->State; } + + const LocationContext *getLocationContext() const { + return Pred->getLocationContext(); + } +}; + +class SwitchNodeBuilder { + CoreEngine& Eng; + const CFGBlock *Src; + const Expr *Condition; + ExplodedNode *Pred; + +public: + SwitchNodeBuilder(ExplodedNode *pred, const CFGBlock *src, + const Expr *condition, CoreEngine* eng) + : Eng(*eng), Src(src), Condition(condition), Pred(pred) {} + + class iterator { + CFGBlock::const_succ_reverse_iterator I; + + friend class SwitchNodeBuilder; + iterator(CFGBlock::const_succ_reverse_iterator i) : I(i) {} + + public: + iterator &operator++() { ++I; return *this; } + bool operator!=(const iterator &X) const { return I != X.I; } + bool operator==(const iterator &X) const { return I == X.I; } + + const CaseStmt *getCase() const { + return llvm::cast<CaseStmt>((*I)->getLabel()); + } + + const CFGBlock *getBlock() const { + return *I; + } + }; + + iterator begin() { return iterator(Src->succ_rbegin()+1); } + iterator end() { return iterator(Src->succ_rend()); } + + const SwitchStmt *getSwitch() const { + return llvm::cast<SwitchStmt>(Src->getTerminator()); + } + + ExplodedNode *generateCaseStmtNode(const iterator &I, + ProgramStateRef State); + + ExplodedNode *generateDefaultCaseNode(ProgramStateRef State, + bool isSink = false); + + const Expr *getCondition() const { return Condition; } + + ProgramStateRef getState() const { return Pred->State; } + + const LocationContext *getLocationContext() const { + return Pred->getLocationContext(); + } +}; + +} // end ento namespace +} // end clang namespace + +#endif diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h new file mode 100644 index 0000000..b80213e --- /dev/null +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Environment.h @@ -0,0 +1,139 @@ +//== Environment.h - Map from Stmt* to Locations/Values ---------*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defined the Environment and EnvironmentManager classes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_GR_ENVIRONMENT_H +#define LLVM_CLANG_GR_ENVIRONMENT_H + +#include "clang/Analysis/AnalysisContext.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" +#include "llvm/ADT/ImmutableMap.h" + +namespace clang { + +class LiveVariables; + +namespace ento { + +class EnvironmentManager; +class SValBuilder; + +/// An entry in the environment consists of a Stmt and an LocationContext. +/// This allows the environment to manage context-sensitive bindings, +/// which is essentially for modeling recursive function analysis, among +/// other things. +class EnvironmentEntry : public std::pair<const Stmt*, + const StackFrameContext *> { +public: + EnvironmentEntry(const Stmt *s, const LocationContext *L) + : std::pair<const Stmt*, + const StackFrameContext*>(s, L ? L->getCurrentStackFrame():0) {} + + const Stmt *getStmt() const { return first; } + const LocationContext *getLocationContext() const { return second; } + + /// Profile an EnvironmentEntry for inclusion in a FoldingSet. + static void Profile(llvm::FoldingSetNodeID &ID, + const EnvironmentEntry &E) { + ID.AddPointer(E.getStmt()); + ID.AddPointer(E.getLocationContext()); + } + + void Profile(llvm::FoldingSetNodeID &ID) const { + Profile(ID, *this); + } +}; + +/// An immutable map from EnvironemntEntries to SVals. +class Environment { +private: + friend class EnvironmentManager; + + // Type definitions. + typedef llvm::ImmutableMap<EnvironmentEntry, SVal> BindingsTy; + + // Data. + BindingsTy ExprBindings; + + Environment(BindingsTy eb) + : ExprBindings(eb) {} + + SVal lookupExpr(const EnvironmentEntry &E) const; + +public: + typedef BindingsTy::iterator iterator; + iterator begin() const { return ExprBindings.begin(); } + iterator end() const { return ExprBindings.end(); } + + /// Fetches the current binding of the expression in the + /// Environment. + SVal getSVal(const EnvironmentEntry &E, + SValBuilder &svalBuilder, + bool useOnlyDirectBindings = false) const; + + /// Profile - Profile the contents of an Environment object for use + /// in a FoldingSet. + static void Profile(llvm::FoldingSetNodeID& ID, const Environment* env) { + env->ExprBindings.Profile(ID); + } + + /// Profile - Used to profile the contents of this object for inclusion + /// in a FoldingSet. + void Profile(llvm::FoldingSetNodeID& ID) const { + Profile(ID, this); + } + + bool operator==(const Environment& RHS) const { + return ExprBindings == RHS.ExprBindings; + } + + void print(raw_ostream &Out, const char *NL, const char *Sep) const; + +private: + void printAux(raw_ostream &Out, bool printLocations, + const char *NL, const char *Sep) const; +}; + +class EnvironmentManager { +private: + typedef Environment::BindingsTy::Factory FactoryTy; + FactoryTy F; + +public: + EnvironmentManager(llvm::BumpPtrAllocator& Allocator) : F(Allocator) {} + ~EnvironmentManager() {} + + Environment getInitialEnvironment() { + return Environment(F.getEmptyMap()); + } + + /// Bind a symbolic value to the given environment entry. + Environment bindExpr(Environment Env, const EnvironmentEntry &E, SVal V, + bool Invalidate); + + /// Bind the location 'location' and value 'V' to the specified + /// environment entry. + Environment bindExprAndLocation(Environment Env, + const EnvironmentEntry &E, + SVal location, + SVal V); + + Environment removeDeadBindings(Environment Env, + SymbolReaper &SymReaper, + ProgramStateRef state); +}; + +} // end GR namespace + +} // end clang namespace + +#endif diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h new file mode 100644 index 0000000..46fbb88 --- /dev/null +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h @@ -0,0 +1,480 @@ +//=-- ExplodedGraph.h - Local, Path-Sens. "Exploded Graph" -*- C++ -*-------==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the template classes ExplodedNode and ExplodedGraph, +// which represent a path-sensitive, intra-procedural "exploded graph." +// See "Precise interprocedural dataflow analysis via graph reachability" +// by Reps, Horwitz, and Sagiv +// (http://portal.acm.org/citation.cfm?id=199462) for the definition of an +// exploded graph. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_GR_EXPLODEDGRAPH +#define LLVM_CLANG_GR_EXPLODEDGRAPH + +#include "clang/Analysis/ProgramPoint.h" +#include "clang/Analysis/AnalysisContext.h" +#include "clang/AST/Decl.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/Support/Allocator.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/GraphTraits.h" +#include "llvm/ADT/DepthFirstIterator.h" +#include "llvm/Support/Casting.h" +#include "clang/Analysis/Support/BumpVector.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" +#include <vector> + +namespace clang { + +class CFG; + +namespace ento { + +class ExplodedGraph; + +//===----------------------------------------------------------------------===// +// ExplodedGraph "implementation" classes. These classes are not typed to +// contain a specific kind of state. Typed-specialized versions are defined +// on top of these classes. +//===----------------------------------------------------------------------===// + +// ExplodedNode is not constified all over the engine because we need to add +// successors to it at any time after creating it. + +class ExplodedNode : public llvm::FoldingSetNode { + friend class ExplodedGraph; + friend class CoreEngine; + friend class NodeBuilder; + friend class BranchNodeBuilder; + friend class IndirectGotoNodeBuilder; + friend class SwitchNodeBuilder; + friend class EndOfFunctionNodeBuilder; + + class NodeGroup { + enum { Size1 = 0x0, SizeOther = 0x1, AuxFlag = 0x2, Mask = 0x3 }; + uintptr_t P; + + unsigned getKind() const { + return P & 0x1; + } + + void *getPtr() const { + assert (!getFlag()); + return reinterpret_cast<void*>(P & ~Mask); + } + + ExplodedNode *getNode() const { + return reinterpret_cast<ExplodedNode*>(getPtr()); + } + + public: + NodeGroup() : P(0) {} + + ExplodedNode **begin() const; + + ExplodedNode **end() const; + + unsigned size() const; + + bool empty() const { return (P & ~Mask) == 0; } + + void addNode(ExplodedNode *N, ExplodedGraph &G); + + void replaceNode(ExplodedNode *node); + + void setFlag() { + assert(P == 0); + P = AuxFlag; + } + + bool getFlag() const { + return P & AuxFlag ? true : false; + } + }; + + /// Location - The program location (within a function body) associated + /// with this node. + const ProgramPoint Location; + + /// State - The state associated with this node. + ProgramStateRef State; + + /// Preds - The predecessors of this node. + NodeGroup Preds; + + /// Succs - The successors of this node. + NodeGroup Succs; + +public: + + explicit ExplodedNode(const ProgramPoint &loc, ProgramStateRef state, + bool IsSink) + : Location(loc), State(state) { + if (IsSink) + Succs.setFlag(); + } + + ~ExplodedNode() {} + + /// getLocation - Returns the edge associated with the given node. + ProgramPoint getLocation() const { return Location; } + + const LocationContext *getLocationContext() const { + return getLocation().getLocationContext(); + } + + const Decl &getCodeDecl() const { return *getLocationContext()->getDecl(); } + + CFG &getCFG() const { return *getLocationContext()->getCFG(); } + + ParentMap &getParentMap() const {return getLocationContext()->getParentMap();} + + template <typename T> + T &getAnalysis() const { + return *getLocationContext()->getAnalysis<T>(); + } + + ProgramStateRef getState() const { return State; } + + template <typename T> + const T* getLocationAs() const { return llvm::dyn_cast<T>(&Location); } + + static void Profile(llvm::FoldingSetNodeID &ID, + const ProgramPoint &Loc, + ProgramStateRef state, + bool IsSink) { + ID.Add(Loc); + ID.AddPointer(state.getPtr()); + ID.AddBoolean(IsSink); + } + + void Profile(llvm::FoldingSetNodeID& ID) const { + Profile(ID, getLocation(), getState(), isSink()); + } + + /// addPredeccessor - Adds a predecessor to the current node, and + /// in tandem add this node as a successor of the other node. + void addPredecessor(ExplodedNode *V, ExplodedGraph &G); + + unsigned succ_size() const { return Succs.size(); } + unsigned pred_size() const { return Preds.size(); } + bool succ_empty() const { return Succs.empty(); } + bool pred_empty() const { return Preds.empty(); } + + bool isSink() const { return Succs.getFlag(); } + + bool hasSinglePred() const { + return (pred_size() == 1); + } + + ExplodedNode *getFirstPred() { + return pred_empty() ? NULL : *(pred_begin()); + } + + const ExplodedNode *getFirstPred() const { + return const_cast<ExplodedNode*>(this)->getFirstPred(); + } + + // Iterators over successor and predecessor vertices. + typedef ExplodedNode** succ_iterator; + typedef const ExplodedNode* const * const_succ_iterator; + typedef ExplodedNode** pred_iterator; + typedef const ExplodedNode* const * const_pred_iterator; + + pred_iterator pred_begin() { return Preds.begin(); } + pred_iterator pred_end() { return Preds.end(); } + + const_pred_iterator pred_begin() const { + return const_cast<ExplodedNode*>(this)->pred_begin(); + } + const_pred_iterator pred_end() const { + return const_cast<ExplodedNode*>(this)->pred_end(); + } + + succ_iterator succ_begin() { return Succs.begin(); } + succ_iterator succ_end() { return Succs.end(); } + + const_succ_iterator succ_begin() const { + return const_cast<ExplodedNode*>(this)->succ_begin(); + } + const_succ_iterator succ_end() const { + return const_cast<ExplodedNode*>(this)->succ_end(); + } + + // For debugging. + +public: + + class Auditor { + public: + virtual ~Auditor(); + virtual void AddEdge(ExplodedNode *Src, ExplodedNode *Dst) = 0; + }; + + static void SetAuditor(Auditor* A); + +private: + void replaceSuccessor(ExplodedNode *node) { Succs.replaceNode(node); } + void replacePredecessor(ExplodedNode *node) { Preds.replaceNode(node); } +}; + +// FIXME: Is this class necessary? +class InterExplodedGraphMap { + virtual void anchor(); + llvm::DenseMap<const ExplodedNode*, ExplodedNode*> M; + friend class ExplodedGraph; + +public: + ExplodedNode *getMappedNode(const ExplodedNode *N) const; + + InterExplodedGraphMap() {} + virtual ~InterExplodedGraphMap() {} +}; + +class ExplodedGraph { +protected: + friend class CoreEngine; + + // Type definitions. + typedef std::vector<ExplodedNode *> NodeVector; + + /// The roots of the simulation graph. Usually there will be only + /// one, but clients are free to establish multiple subgraphs within a single + /// SimulGraph. Moreover, these subgraphs can often merge when paths from + /// different roots reach the same state at the same program location. + NodeVector Roots; + + /// The nodes in the simulation graph which have been + /// specially marked as the endpoint of an abstract simulation path. + NodeVector EndNodes; + + /// Nodes - The nodes in the graph. + llvm::FoldingSet<ExplodedNode> Nodes; + + /// BVC - Allocator and context for allocating nodes and their predecessor + /// and successor groups. + BumpVectorContext BVC; + + /// NumNodes - The number of nodes in the graph. + unsigned NumNodes; + + /// A list of recently allocated nodes that can potentially be recycled. + NodeVector ChangedNodes; + + /// A list of nodes that can be reused. + NodeVector FreeNodes; + + /// A flag that indicates whether nodes should be recycled. + bool reclaimNodes; + + /// Counter to determine when to reclaim nodes. + unsigned reclaimCounter; + +public: + + /// \brief Retrieve the node associated with a (Location,State) pair, + /// where the 'Location' is a ProgramPoint in the CFG. If no node for + /// this pair exists, it is created. IsNew is set to true if + /// the node was freshly created. + ExplodedNode *getNode(const ProgramPoint &L, ProgramStateRef State, + bool IsSink = false, + bool* IsNew = 0); + + ExplodedGraph* MakeEmptyGraph() const { + return new ExplodedGraph(); + } + + /// addRoot - Add an untyped node to the set of roots. + ExplodedNode *addRoot(ExplodedNode *V) { + Roots.push_back(V); + return V; + } + + /// addEndOfPath - Add an untyped node to the set of EOP nodes. + ExplodedNode *addEndOfPath(ExplodedNode *V) { + EndNodes.push_back(V); + return V; + } + + ExplodedGraph(); + + ~ExplodedGraph(); + + unsigned num_roots() const { return Roots.size(); } + unsigned num_eops() const { return EndNodes.size(); } + + bool empty() const { return NumNodes == 0; } + unsigned size() const { return NumNodes; } + + // Iterators. + typedef ExplodedNode NodeTy; + typedef llvm::FoldingSet<ExplodedNode> AllNodesTy; + typedef NodeVector::iterator roots_iterator; + typedef NodeVector::const_iterator const_roots_iterator; + typedef NodeVector::iterator eop_iterator; + typedef NodeVector::const_iterator const_eop_iterator; + typedef AllNodesTy::iterator node_iterator; + typedef AllNodesTy::const_iterator const_node_iterator; + + node_iterator nodes_begin() { return Nodes.begin(); } + + node_iterator nodes_end() { return Nodes.end(); } + + const_node_iterator nodes_begin() const { return Nodes.begin(); } + + const_node_iterator nodes_end() const { return Nodes.end(); } + + roots_iterator roots_begin() { return Roots.begin(); } + + roots_iterator roots_end() { return Roots.end(); } + + const_roots_iterator roots_begin() const { return Roots.begin(); } + + const_roots_iterator roots_end() const { return Roots.end(); } + + eop_iterator eop_begin() { return EndNodes.begin(); } + + eop_iterator eop_end() { return EndNodes.end(); } + + const_eop_iterator eop_begin() const { return EndNodes.begin(); } + + const_eop_iterator eop_end() const { return EndNodes.end(); } + + llvm::BumpPtrAllocator & getAllocator() { return BVC.getAllocator(); } + BumpVectorContext &getNodeAllocator() { return BVC; } + + typedef llvm::DenseMap<const ExplodedNode*, ExplodedNode*> NodeMap; + + std::pair<ExplodedGraph*, InterExplodedGraphMap*> + Trim(const NodeTy* const* NBeg, const NodeTy* const* NEnd, + llvm::DenseMap<const void*, const void*> *InverseMap = 0) const; + + ExplodedGraph* TrimInternal(const ExplodedNode* const * NBeg, + const ExplodedNode* const * NEnd, + InterExplodedGraphMap *M, + llvm::DenseMap<const void*, const void*> *InverseMap) const; + + /// Enable tracking of recently allocated nodes for potential reclamation + /// when calling reclaimRecentlyAllocatedNodes(). + void enableNodeReclamation() { reclaimNodes = true; } + + /// Reclaim "uninteresting" nodes created since the last time this method + /// was called. + void reclaimRecentlyAllocatedNodes(); + +private: + bool shouldCollect(const ExplodedNode *node); + void collectNode(ExplodedNode *node); +}; + +class ExplodedNodeSet { + typedef llvm::SmallPtrSet<ExplodedNode*,5> ImplTy; + ImplTy Impl; + +public: + ExplodedNodeSet(ExplodedNode *N) { + assert (N && !static_cast<ExplodedNode*>(N)->isSink()); + Impl.insert(N); + } + + ExplodedNodeSet() {} + + inline void Add(ExplodedNode *N) { + if (N && !static_cast<ExplodedNode*>(N)->isSink()) Impl.insert(N); + } + + typedef ImplTy::iterator iterator; + typedef ImplTy::const_iterator const_iterator; + + unsigned size() const { return Impl.size(); } + bool empty() const { return Impl.empty(); } + bool erase(ExplodedNode *N) { return Impl.erase(N); } + + void clear() { Impl.clear(); } + void insert(const ExplodedNodeSet &S) { + assert(&S != this); + if (empty()) + Impl = S.Impl; + else + Impl.insert(S.begin(), S.end()); + } + + inline iterator begin() { return Impl.begin(); } + inline iterator end() { return Impl.end(); } + + inline const_iterator begin() const { return Impl.begin(); } + inline const_iterator end() const { return Impl.end(); } +}; + +} // end GR namespace + +} // end clang namespace + +// GraphTraits + +namespace llvm { + template<> struct GraphTraits<clang::ento::ExplodedNode*> { + typedef clang::ento::ExplodedNode NodeType; + typedef NodeType::succ_iterator ChildIteratorType; + typedef llvm::df_iterator<NodeType*> nodes_iterator; + + static inline NodeType* getEntryNode(NodeType* N) { + return N; + } + + static inline ChildIteratorType child_begin(NodeType* N) { + return N->succ_begin(); + } + + static inline ChildIteratorType child_end(NodeType* N) { + return N->succ_end(); + } + + static inline nodes_iterator nodes_begin(NodeType* N) { + return df_begin(N); + } + + static inline nodes_iterator nodes_end(NodeType* N) { + return df_end(N); + } + }; + + template<> struct GraphTraits<const clang::ento::ExplodedNode*> { + typedef const clang::ento::ExplodedNode NodeType; + typedef NodeType::const_succ_iterator ChildIteratorType; + typedef llvm::df_iterator<NodeType*> nodes_iterator; + + static inline NodeType* getEntryNode(NodeType* N) { + return N; + } + + static inline ChildIteratorType child_begin(NodeType* N) { + return N->succ_begin(); + } + + static inline ChildIteratorType child_end(NodeType* N) { + return N->succ_end(); + } + + static inline nodes_iterator nodes_begin(NodeType* N) { + return df_begin(N); + } + + static inline nodes_iterator nodes_end(NodeType* N) { + return df_end(N); + } + }; + +} // end llvm namespace + +#endif diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h new file mode 100644 index 0000000..2a21a03 --- /dev/null +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -0,0 +1,496 @@ +//===-- ExprEngine.h - Path-Sensitive Expression-Level Dataflow ---*- C++ -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines a meta-engine for path-sensitive dataflow analysis that +// is built on CoreEngine, but provides the boilerplate to execute transfer +// functions and build the ExplodedGraph at the expression level. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_GR_EXPRENGINE +#define LLVM_CLANG_GR_EXPRENGINE + +#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" +#include "clang/AST/Expr.h" +#include "clang/AST/Type.h" + +namespace clang { + +class AnalysisDeclContextManager; +class CXXCatchStmt; +class CXXConstructExpr; +class CXXDeleteExpr; +class CXXNewExpr; +class CXXTemporaryObjectExpr; +class CXXThisExpr; +class MaterializeTemporaryExpr; +class ObjCAtSynchronizedStmt; +class ObjCForCollectionStmt; + +namespace ento { + +class AnalysisManager; +class CallOrObjCMessage; +class ObjCMessage; + +class ExprEngine : public SubEngine { + AnalysisManager &AMgr; + + AnalysisDeclContextManager &AnalysisDeclContexts; + + CoreEngine Engine; + + /// G - the simulation graph. + ExplodedGraph& G; + + /// StateMgr - Object that manages the data for all created states. + ProgramStateManager StateMgr; + + /// SymMgr - Object that manages the symbol information. + SymbolManager& SymMgr; + + /// svalBuilder - SValBuilder object that creates SVals from expressions. + SValBuilder &svalBuilder; + + /// EntryNode - The immediate predecessor node. + ExplodedNode *EntryNode; + + /// CleanedState - The state for EntryNode "cleaned" of all dead + /// variables and symbols (as determined by a liveness analysis). + ProgramStateRef CleanedState; + + /// currentStmt - The current block-level statement. + const Stmt *currentStmt; + unsigned int currentStmtIdx; + const NodeBuilderContext *currentBuilderContext; + + /// Obj-C Class Identifiers. + IdentifierInfo* NSExceptionII; + + /// Obj-C Selectors. + Selector* NSExceptionInstanceRaiseSelectors; + Selector RaiseSel; + + /// Whether or not GC is enabled in this analysis. + bool ObjCGCEnabled; + + /// The BugReporter associated with this engine. It is important that + /// this object be placed at the very end of member variables so that its + /// destructor is called before the rest of the ExprEngine is destroyed. + GRBugReporter BR; + +public: + ExprEngine(AnalysisManager &mgr, bool gcEnabled, + SetOfConstDecls *VisitedCallees, + FunctionSummariesTy *FS); + + ~ExprEngine(); + + /// Returns true if there is still simulation state on the worklist. + bool ExecuteWorkList(const LocationContext *L, unsigned Steps = 150000) { + return Engine.ExecuteWorkList(L, Steps, 0); + } + + /// Execute the work list with an initial state. Nodes that reaches the exit + /// of the function are added into the Dst set, which represent the exit + /// state of the function call. Returns true if there is still simulation + /// state on the worklist. + bool ExecuteWorkListWithInitialState(const LocationContext *L, unsigned Steps, + ProgramStateRef InitState, + ExplodedNodeSet &Dst) { + return Engine.ExecuteWorkListWithInitialState(L, Steps, InitState, Dst); + } + + /// getContext - Return the ASTContext associated with this analysis. + ASTContext &getContext() const { return AMgr.getASTContext(); } + + virtual AnalysisManager &getAnalysisManager() { return AMgr; } + + CheckerManager &getCheckerManager() const { + return *AMgr.getCheckerManager(); + } + + SValBuilder &getSValBuilder() { return svalBuilder; } + + BugReporter& getBugReporter() { return BR; } + + const NodeBuilderContext &getBuilderContext() { + assert(currentBuilderContext); + return *currentBuilderContext; + } + + bool isObjCGCEnabled() { return ObjCGCEnabled; } + + const Stmt *getStmt() const; + + void GenerateAutoTransition(ExplodedNode *N); + void enqueueEndOfPath(ExplodedNodeSet &S); + void GenerateCallExitNode(ExplodedNode *N); + + /// ViewGraph - Visualize the ExplodedGraph created by executing the + /// simulation. + void ViewGraph(bool trim = false); + + void ViewGraph(ExplodedNode** Beg, ExplodedNode** End); + + /// getInitialState - Return the initial state used for the root vertex + /// in the ExplodedGraph. + ProgramStateRef getInitialState(const LocationContext *InitLoc); + + ExplodedGraph& getGraph() { return G; } + const ExplodedGraph& getGraph() const { return G; } + + /// processCFGElement - Called by CoreEngine. Used to generate new successor + /// nodes by processing the 'effects' of a CFG element. + void processCFGElement(const CFGElement E, ExplodedNode *Pred, + unsigned StmtIdx, NodeBuilderContext *Ctx); + + void ProcessStmt(const CFGStmt S, ExplodedNode *Pred); + + void ProcessInitializer(const CFGInitializer I, ExplodedNode *Pred); + + void ProcessImplicitDtor(const CFGImplicitDtor D, ExplodedNode *Pred); + + void ProcessAutomaticObjDtor(const CFGAutomaticObjDtor D, + ExplodedNode *Pred, ExplodedNodeSet &Dst); + void ProcessBaseDtor(const CFGBaseDtor D, + ExplodedNode *Pred, ExplodedNodeSet &Dst); + void ProcessMemberDtor(const CFGMemberDtor D, + ExplodedNode *Pred, ExplodedNodeSet &Dst); + void ProcessTemporaryDtor(const CFGTemporaryDtor D, + ExplodedNode *Pred, ExplodedNodeSet &Dst); + + /// Called by CoreEngine when processing the entrance of a CFGBlock. + virtual void processCFGBlockEntrance(const BlockEdge &L, + NodeBuilderWithSinks &nodeBuilder); + + /// ProcessBranch - Called by CoreEngine. Used to generate successor + /// nodes by processing the 'effects' of a branch condition. + void processBranch(const Stmt *Condition, const Stmt *Term, + NodeBuilderContext& BuilderCtx, + ExplodedNode *Pred, + ExplodedNodeSet &Dst, + const CFGBlock *DstT, + const CFGBlock *DstF); + + /// processIndirectGoto - Called by CoreEngine. Used to generate successor + /// nodes by processing the 'effects' of a computed goto jump. + void processIndirectGoto(IndirectGotoNodeBuilder& builder); + + /// ProcessSwitch - Called by CoreEngine. Used to generate successor + /// nodes by processing the 'effects' of a switch statement. + void processSwitch(SwitchNodeBuilder& builder); + + /// ProcessEndPath - Called by CoreEngine. Used to generate end-of-path + /// nodes when the control reaches the end of a function. + void processEndOfFunction(NodeBuilderContext& BC); + + /// Generate the entry node of the callee. + void processCallEnter(CallEnter CE, ExplodedNode *Pred); + + /// Generate the first post callsite node. + void processCallExit(ExplodedNode *Pred); + + /// Called by CoreEngine when the analysis worklist has terminated. + void processEndWorklist(bool hasWorkRemaining); + + /// evalAssume - Callback function invoked by the ConstraintManager when + /// making assumptions about state values. + ProgramStateRef processAssume(ProgramStateRef state, SVal cond,bool assumption); + + /// wantsRegionChangeUpdate - Called by ProgramStateManager to determine if a + /// region change should trigger a processRegionChanges update. + bool wantsRegionChangeUpdate(ProgramStateRef state); + + /// processRegionChanges - Called by ProgramStateManager whenever a change is made + /// to the store. Used to update checkers that track region values. + ProgramStateRef + processRegionChanges(ProgramStateRef state, + const StoreManager::InvalidatedSymbols *invalidated, + ArrayRef<const MemRegion *> ExplicitRegions, + ArrayRef<const MemRegion *> Regions, + const CallOrObjCMessage *Call); + + /// printState - Called by ProgramStateManager to print checker-specific data. + void printState(raw_ostream &Out, ProgramStateRef State, + const char *NL, const char *Sep); + + virtual ProgramStateManager& getStateManager() { return StateMgr; } + + StoreManager& getStoreManager() { return StateMgr.getStoreManager(); } + + ConstraintManager& getConstraintManager() { + return StateMgr.getConstraintManager(); + } + + // FIXME: Remove when we migrate over to just using SValBuilder. + BasicValueFactory& getBasicVals() { + return StateMgr.getBasicVals(); + } + const BasicValueFactory& getBasicVals() const { + return StateMgr.getBasicVals(); + } + + // FIXME: Remove when we migrate over to just using ValueManager. + SymbolManager& getSymbolManager() { return SymMgr; } + const SymbolManager& getSymbolManager() const { return SymMgr; } + + // Functions for external checking of whether we have unfinished work + bool wasBlocksExhausted() const { return Engine.wasBlocksExhausted(); } + bool hasEmptyWorkList() const { return !Engine.getWorkList()->hasWork(); } + bool hasWorkRemaining() const { return Engine.hasWorkRemaining(); } + + const CoreEngine &getCoreEngine() const { return Engine; } + +public: + /// Visit - Transfer function logic for all statements. Dispatches to + /// other functions that handle specific kinds of statements. + void Visit(const Stmt *S, ExplodedNode *Pred, ExplodedNodeSet &Dst); + + /// VisitArraySubscriptExpr - Transfer function for array accesses. + void VisitLvalArraySubscriptExpr(const ArraySubscriptExpr *Ex, + ExplodedNode *Pred, + ExplodedNodeSet &Dst); + + /// VisitAsmStmt - Transfer function logic for inline asm. + void VisitAsmStmt(const AsmStmt *A, ExplodedNode *Pred, ExplodedNodeSet &Dst); + + /// VisitBlockExpr - Transfer function logic for BlockExprs. + void VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred, + ExplodedNodeSet &Dst); + + /// VisitBinaryOperator - Transfer function logic for binary operators. + void VisitBinaryOperator(const BinaryOperator* B, ExplodedNode *Pred, + ExplodedNodeSet &Dst); + + + /// VisitCall - Transfer function for function calls. + void VisitCallExpr(const CallExpr *CE, ExplodedNode *Pred, + ExplodedNodeSet &Dst); + + /// VisitCast - Transfer function logic for all casts (implicit and explicit). + void VisitCast(const CastExpr *CastE, const Expr *Ex, ExplodedNode *Pred, + ExplodedNodeSet &Dst); + + /// VisitCompoundLiteralExpr - Transfer function logic for compound literals. + void VisitCompoundLiteralExpr(const CompoundLiteralExpr *CL, + ExplodedNode *Pred, ExplodedNodeSet &Dst); + + /// Transfer function logic for DeclRefExprs and BlockDeclRefExprs. + void VisitCommonDeclRefExpr(const Expr *DR, const NamedDecl *D, + ExplodedNode *Pred, ExplodedNodeSet &Dst); + + /// VisitDeclStmt - Transfer function logic for DeclStmts. + void VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred, + ExplodedNodeSet &Dst); + + /// VisitGuardedExpr - Transfer function logic for ?, __builtin_choose + void VisitGuardedExpr(const Expr *Ex, const Expr *L, const Expr *R, + ExplodedNode *Pred, ExplodedNodeSet &Dst); + + void VisitInitListExpr(const InitListExpr *E, ExplodedNode *Pred, + ExplodedNodeSet &Dst); + + /// VisitLogicalExpr - Transfer function logic for '&&', '||' + void VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred, + ExplodedNodeSet &Dst); + + /// VisitMemberExpr - Transfer function for member expressions. + void VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred, + ExplodedNodeSet &Dst); + + /// Transfer function logic for ObjCAtSynchronizedStmts. + void VisitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt *S, + ExplodedNode *Pred, ExplodedNodeSet &Dst); + + /// Transfer function logic for computing the lvalue of an Objective-C ivar. + void VisitLvalObjCIvarRefExpr(const ObjCIvarRefExpr *DR, ExplodedNode *Pred, + ExplodedNodeSet &Dst); + + /// VisitObjCForCollectionStmt - Transfer function logic for + /// ObjCForCollectionStmt. + void VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S, + ExplodedNode *Pred, ExplodedNodeSet &Dst); + + void VisitObjCMessage(const ObjCMessage &msg, ExplodedNode *Pred, + ExplodedNodeSet &Dst); + + /// VisitReturnStmt - Transfer function logic for return statements. + void VisitReturnStmt(const ReturnStmt *R, ExplodedNode *Pred, + ExplodedNodeSet &Dst); + + /// VisitOffsetOfExpr - Transfer function for offsetof. + void VisitOffsetOfExpr(const OffsetOfExpr *Ex, ExplodedNode *Pred, + ExplodedNodeSet &Dst); + + /// VisitUnaryExprOrTypeTraitExpr - Transfer function for sizeof. + void VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex, + ExplodedNode *Pred, ExplodedNodeSet &Dst); + + /// VisitUnaryOperator - Transfer function logic for unary operators. + void VisitUnaryOperator(const UnaryOperator* B, ExplodedNode *Pred, + ExplodedNodeSet &Dst); + + /// Handle ++ and -- (both pre- and post-increment). + void VisitIncrementDecrementOperator(const UnaryOperator* U, + ExplodedNode *Pred, + ExplodedNodeSet &Dst); + + void VisitCXXCatchStmt(const CXXCatchStmt *CS, ExplodedNode *Pred, + ExplodedNodeSet &Dst); + + void VisitCXXThisExpr(const CXXThisExpr *TE, ExplodedNode *Pred, + ExplodedNodeSet & Dst); + + void VisitCXXTemporaryObjectExpr(const CXXTemporaryObjectExpr *expr, + ExplodedNode *Pred, ExplodedNodeSet &Dst); + + void VisitCXXConstructExpr(const CXXConstructExpr *E, const MemRegion *Dest, + ExplodedNode *Pred, ExplodedNodeSet &Dst); + + void VisitCXXDestructor(const CXXDestructorDecl *DD, + const MemRegion *Dest, const Stmt *S, + ExplodedNode *Pred, ExplodedNodeSet &Dst); + + void VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, + ExplodedNodeSet &Dst); + + void VisitCXXDeleteExpr(const CXXDeleteExpr *CDE, ExplodedNode *Pred, + ExplodedNodeSet &Dst); + + /// Create a C++ temporary object for an rvalue. + void CreateCXXTemporaryObject(const MaterializeTemporaryExpr *ME, + ExplodedNode *Pred, + ExplodedNodeSet &Dst); + + /// Synthesize CXXThisRegion. + const CXXThisRegion *getCXXThisRegion(const CXXRecordDecl *RD, + const StackFrameContext *SFC); + + const CXXThisRegion *getCXXThisRegion(const CXXMethodDecl *decl, + const StackFrameContext *frameCtx); + + /// evalEagerlyAssume - Given the nodes in 'Src', eagerly assume symbolic + /// expressions of the form 'x != 0' and generate new nodes (stored in Dst) + /// with those assumptions. + void evalEagerlyAssume(ExplodedNodeSet &Dst, ExplodedNodeSet &Src, + const Expr *Ex); + + std::pair<const ProgramPointTag *, const ProgramPointTag*> + getEagerlyAssumeTags(); + + SVal evalMinus(SVal X) { + return X.isValid() ? svalBuilder.evalMinus(cast<NonLoc>(X)) : X; + } + + SVal evalComplement(SVal X) { + return X.isValid() ? svalBuilder.evalComplement(cast<NonLoc>(X)) : X; + } + +public: + + SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op, + NonLoc L, NonLoc R, QualType T) { + return svalBuilder.evalBinOpNN(state, op, L, R, T); + } + + SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op, + NonLoc L, SVal R, QualType T) { + return R.isValid() ? svalBuilder.evalBinOpNN(state,op,L, cast<NonLoc>(R), T) : R; + } + + SVal evalBinOp(ProgramStateRef ST, BinaryOperator::Opcode Op, + SVal LHS, SVal RHS, QualType T) { + return svalBuilder.evalBinOp(ST, Op, LHS, RHS, T); + } + +protected: + void evalObjCMessage(StmtNodeBuilder &Bldr, const ObjCMessage &msg, + ExplodedNode *Pred, ProgramStateRef state, + bool GenSink); + + ProgramStateRef invalidateArguments(ProgramStateRef State, + const CallOrObjCMessage &Call, + const LocationContext *LC); + + ProgramStateRef MarkBranch(ProgramStateRef state, + const Stmt *Terminator, + const LocationContext *LCtx, + bool branchTaken); + + /// evalBind - Handle the semantics of binding a value to a specific location. + /// This method is used by evalStore, VisitDeclStmt, and others. + void evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE, ExplodedNode *Pred, + SVal location, SVal Val, bool atDeclInit = false); + +public: + // FIXME: 'tag' should be removed, and a LocationContext should be used + // instead. + // FIXME: Comment on the meaning of the arguments, when 'St' may not + // be the same as Pred->state, and when 'location' may not be the + // same as state->getLValue(Ex). + /// Simulate a read of the result of Ex. + void evalLoad(ExplodedNodeSet &Dst, + const Expr *NodeEx, /* Eventually will be a CFGStmt */ + const Expr *BoundExpr, + ExplodedNode *Pred, + ProgramStateRef St, + SVal location, + const ProgramPointTag *tag = 0, + QualType LoadTy = QualType()); + + // FIXME: 'tag' should be removed, and a LocationContext should be used + // instead. + void evalStore(ExplodedNodeSet &Dst, const Expr *AssignE, const Expr *StoreE, + ExplodedNode *Pred, ProgramStateRef St, SVal TargetLV, SVal Val, + const ProgramPointTag *tag = 0); +private: + void evalLoadCommon(ExplodedNodeSet &Dst, + const Expr *NodeEx, /* Eventually will be a CFGStmt */ + const Expr *BoundEx, + ExplodedNode *Pred, + ProgramStateRef St, + SVal location, + const ProgramPointTag *tag, + QualType LoadTy); + + // FIXME: 'tag' should be removed, and a LocationContext should be used + // instead. + void evalLocation(ExplodedNodeSet &Dst, + const Stmt *NodeEx, /* This will eventually be a CFGStmt */ + const Stmt *BoundEx, + ExplodedNode *Pred, + ProgramStateRef St, SVal location, + const ProgramPointTag *tag, bool isLoad); + + bool shouldInlineDecl(const FunctionDecl *FD, ExplodedNode *Pred); + bool InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE, ExplodedNode *Pred); + + bool replayWithoutInlining(ExplodedNode *P, const LocationContext *CalleeLC); +}; + +/// Traits for storing the call processing policy inside GDM. +/// The GDM stores the corresponding CallExpr pointer. +struct ReplayWithoutInlining{}; +template <> +struct ProgramStateTrait<ReplayWithoutInlining> : + public ProgramStatePartialTrait<void*> { + static void *GDMIndex() { static int index = 0; return &index; } +}; + +} // end ento namespace + +} // end clang namespace + +#endif diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h new file mode 100644 index 0000000..42adff3 --- /dev/null +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h @@ -0,0 +1,107 @@ +//== FunctionSummary.h - Stores summaries of functions. ------------*- C++ -*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines a summary of a function gathered/used by static analyzes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_GR_FUNCTIONSUMMARY_H +#define LLVM_CLANG_GR_FUNCTIONSUMMARY_H + +#include "clang/AST/Decl.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/BitVector.h" + +namespace clang { +namespace ento { +typedef llvm::SmallPtrSet<Decl*, 24> SetOfDecls; +typedef llvm::SmallPtrSet<const Decl*, 24> SetOfConstDecls; + +class FunctionSummariesTy { + struct FunctionSummary { + /// True if this function has reached a max block count while inlined from + /// at least one call site. + bool MayReachMaxBlockCount; + + /// Total number of blocks in the function. + unsigned TotalBasicBlocks; + + /// Marks the IDs of the basic blocks visited during the analyzes. + llvm::BitVector VisitedBasicBlocks; + + FunctionSummary() : + MayReachMaxBlockCount(false), + TotalBasicBlocks(0), + VisitedBasicBlocks(0) {} + }; + + typedef llvm::DenseMap<const Decl*, FunctionSummary*> MapTy; + MapTy Map; + +public: + ~FunctionSummariesTy(); + + MapTy::iterator findOrInsertSummary(const Decl *D) { + MapTy::iterator I = Map.find(D); + if (I != Map.end()) + return I; + FunctionSummary *DS = new FunctionSummary(); + I = Map.insert(std::pair<const Decl*, FunctionSummary*>(D, DS)).first; + assert(I != Map.end()); + return I; + } + + void markReachedMaxBlockCount(const Decl* D) { + MapTy::iterator I = findOrInsertSummary(D); + I->second->MayReachMaxBlockCount = true; + } + + bool hasReachedMaxBlockCount(const Decl* D) { + MapTy::const_iterator I = Map.find(D); + if (I != Map.end()) + return I->second->MayReachMaxBlockCount; + return false; + } + + void markVisitedBasicBlock(unsigned ID, const Decl* D, unsigned TotalIDs) { + MapTy::iterator I = findOrInsertSummary(D); + llvm::BitVector &Blocks = I->second->VisitedBasicBlocks; + assert(ID < TotalIDs); + if (TotalIDs > Blocks.size()) { + Blocks.resize(TotalIDs); + I->second->TotalBasicBlocks = TotalIDs; + } + Blocks[ID] = true; + } + + unsigned getNumVisitedBasicBlocks(const Decl* D) { + MapTy::const_iterator I = Map.find(D); + if (I != Map.end()) + return I->second->VisitedBasicBlocks.count(); + return 0; + } + + /// Get the percentage of the reachable blocks. + unsigned getPercentBlocksReachable(const Decl *D) { + MapTy::const_iterator I = Map.find(D); + if (I != Map.end()) + return ((I->second->VisitedBasicBlocks.count() * 100) / + I->second->TotalBasicBlocks); + return 0; + } + + unsigned getTotalNumBasicBlocks(); + unsigned getTotalNumVisitedBasicBlocks(); + +}; + +}} // end clang ento namespaces + +#endif diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h new file mode 100644 index 0000000..87bc0df --- /dev/null +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h @@ -0,0 +1,1230 @@ +//== MemRegion.h - Abstract memory regions for static analysis --*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines MemRegion and its subclasses. MemRegion defines a +// partially-typed abstraction of memory useful for path-sensitive dataflow +// analyses. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_GR_MEMREGION_H +#define LLVM_CLANG_GR_MEMREGION_H + +#include "clang/AST/CharUnits.h" +#include "clang/AST/Decl.h" +#include "clang/AST/ExprObjC.h" +#include "clang/Basic/LLVM.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/ADT/FoldingSet.h" +#include <string> + +namespace llvm { +class BumpPtrAllocator; +} + +namespace clang { + +class LocationContext; +class StackFrameContext; + +namespace ento { + +class MemRegionManager; +class MemSpaceRegion; +class SValBuilder; +class VarRegion; +class CodeTextRegion; + +/// Represent a region's offset within the top level base region. +class RegionOffset { + /// The base region. + const MemRegion *R; + + /// The bit offset within the base region. It shouldn't be negative. + int64_t Offset; + +public: + RegionOffset(const MemRegion *r) : R(r), Offset(0) {} + RegionOffset(const MemRegion *r, int64_t off) : R(r), Offset(off) {} + + const MemRegion *getRegion() const { return R; } + int64_t getOffset() const { return Offset; } +}; + +//===----------------------------------------------------------------------===// +// Base region classes. +//===----------------------------------------------------------------------===// + +/// MemRegion - The root abstract class for all memory regions. +class MemRegion : public llvm::FoldingSetNode { + friend class MemRegionManager; +public: + enum Kind { + // Memory spaces. + GenericMemSpaceRegionKind, + StackLocalsSpaceRegionKind, + StackArgumentsSpaceRegionKind, + HeapSpaceRegionKind, + UnknownSpaceRegionKind, + StaticGlobalSpaceRegionKind, + GlobalInternalSpaceRegionKind, + GlobalSystemSpaceRegionKind, + GlobalImmutableSpaceRegionKind, + BEG_NON_STATIC_GLOBAL_MEMSPACES = GlobalInternalSpaceRegionKind, + END_NON_STATIC_GLOBAL_MEMSPACES = GlobalImmutableSpaceRegionKind, + BEG_GLOBAL_MEMSPACES = StaticGlobalSpaceRegionKind, + END_GLOBAL_MEMSPACES = GlobalImmutableSpaceRegionKind, + BEG_MEMSPACES = GenericMemSpaceRegionKind, + END_MEMSPACES = GlobalImmutableSpaceRegionKind, + // Untyped regions. + SymbolicRegionKind, + AllocaRegionKind, + BlockDataRegionKind, + // Typed regions. + BEG_TYPED_REGIONS, + FunctionTextRegionKind = BEG_TYPED_REGIONS, + BlockTextRegionKind, + BEG_TYPED_VALUE_REGIONS, + CompoundLiteralRegionKind = BEG_TYPED_VALUE_REGIONS, + CXXThisRegionKind, + StringRegionKind, + ObjCStringRegionKind, + ElementRegionKind, + // Decl Regions. + BEG_DECL_REGIONS, + VarRegionKind = BEG_DECL_REGIONS, + FieldRegionKind, + ObjCIvarRegionKind, + END_DECL_REGIONS = ObjCIvarRegionKind, + CXXTempObjectRegionKind, + CXXBaseObjectRegionKind, + END_TYPED_VALUE_REGIONS = CXXBaseObjectRegionKind, + END_TYPED_REGIONS = CXXBaseObjectRegionKind + }; + +private: + const Kind kind; + +protected: + MemRegion(Kind k) : kind(k) {} + virtual ~MemRegion(); + +public: + ASTContext &getContext() const; + + virtual void Profile(llvm::FoldingSetNodeID& ID) const = 0; + + virtual MemRegionManager* getMemRegionManager() const = 0; + + const MemSpaceRegion *getMemorySpace() const; + + const MemRegion *getBaseRegion() const; + + const MemRegion *StripCasts() const; + + bool hasGlobalsOrParametersStorage() const; + + bool hasStackStorage() const; + + bool hasStackNonParametersStorage() const; + + bool hasStackParametersStorage() const; + + /// Compute the offset within the top level memory object. + RegionOffset getAsOffset() const; + + /// \brief Get a string representation of a region for debug use. + std::string getString() const; + + virtual void dumpToStream(raw_ostream &os) const; + + void dump() const; + + /// \brief Print the region for use in diagnostics. + virtual void dumpPretty(raw_ostream &os) const; + + Kind getKind() const { return kind; } + + template<typename RegionTy> const RegionTy* getAs() const; + + virtual bool isBoundable() const { return false; } + + static bool classof(const MemRegion*) { return true; } +}; + +/// MemSpaceRegion - A memory region that represents a "memory space"; +/// for example, the set of global variables, the stack frame, etc. +class MemSpaceRegion : public MemRegion { +protected: + friend class MemRegionManager; + + MemRegionManager *Mgr; + + MemSpaceRegion(MemRegionManager *mgr, Kind k = GenericMemSpaceRegionKind) + : MemRegion(k), Mgr(mgr) { + assert(classof(this)); + } + + MemRegionManager* getMemRegionManager() const { return Mgr; } + +public: + bool isBoundable() const { return false; } + + void Profile(llvm::FoldingSetNodeID &ID) const; + + static bool classof(const MemRegion *R) { + Kind k = R->getKind(); + return k >= BEG_MEMSPACES && k <= END_MEMSPACES; + } +}; + +class GlobalsSpaceRegion : public MemSpaceRegion { + virtual void anchor(); +protected: + GlobalsSpaceRegion(MemRegionManager *mgr, Kind k) + : MemSpaceRegion(mgr, k) {} +public: + static bool classof(const MemRegion *R) { + Kind k = R->getKind(); + return k >= BEG_GLOBAL_MEMSPACES && k <= END_GLOBAL_MEMSPACES; + } +}; + +/// \class The region of the static variables within the current CodeTextRegion +/// scope. +/// Currently, only the static locals are placed there, so we know that these +/// variables do not get invalidated by calls to other functions. +class StaticGlobalSpaceRegion : public GlobalsSpaceRegion { + friend class MemRegionManager; + + const CodeTextRegion *CR; + + StaticGlobalSpaceRegion(MemRegionManager *mgr, const CodeTextRegion *cr) + : GlobalsSpaceRegion(mgr, StaticGlobalSpaceRegionKind), CR(cr) {} + +public: + void Profile(llvm::FoldingSetNodeID &ID) const; + + void dumpToStream(raw_ostream &os) const; + + const CodeTextRegion *getCodeRegion() const { return CR; } + + static bool classof(const MemRegion *R) { + return R->getKind() == StaticGlobalSpaceRegionKind; + } +}; + +/// \class The region for all the non-static global variables. +/// +/// This class is further split into subclasses for efficient implementation of +/// invalidating a set of related global values as is done in +/// RegionStoreManager::invalidateRegions (instead of finding all the dependent +/// globals, we invalidate the whole parent region). +class NonStaticGlobalSpaceRegion : public GlobalsSpaceRegion { + friend class MemRegionManager; + +protected: + NonStaticGlobalSpaceRegion(MemRegionManager *mgr, Kind k) + : GlobalsSpaceRegion(mgr, k) {} + +public: + + void dumpToStream(raw_ostream &os) const; + + static bool classof(const MemRegion *R) { + Kind k = R->getKind(); + return k >= BEG_NON_STATIC_GLOBAL_MEMSPACES && + k <= END_NON_STATIC_GLOBAL_MEMSPACES; + } +}; + +/// \class The region containing globals which are defined in system/external +/// headers and are considered modifiable by system calls (ex: errno). +class GlobalSystemSpaceRegion : public NonStaticGlobalSpaceRegion { + friend class MemRegionManager; + + GlobalSystemSpaceRegion(MemRegionManager *mgr) + : NonStaticGlobalSpaceRegion(mgr, GlobalSystemSpaceRegionKind) {} + +public: + + void dumpToStream(raw_ostream &os) const; + + static bool classof(const MemRegion *R) { + return R->getKind() == GlobalSystemSpaceRegionKind; + } +}; + +/// \class The region containing globals which are considered not to be modified +/// or point to data which could be modified as a result of a function call +/// (system or internal). Ex: Const global scalars would be modeled as part of +/// this region. This region also includes most system globals since they have +/// low chance of being modified. +class GlobalImmutableSpaceRegion : public NonStaticGlobalSpaceRegion { + friend class MemRegionManager; + + GlobalImmutableSpaceRegion(MemRegionManager *mgr) + : NonStaticGlobalSpaceRegion(mgr, GlobalImmutableSpaceRegionKind) {} + +public: + + void dumpToStream(raw_ostream &os) const; + + static bool classof(const MemRegion *R) { + return R->getKind() == GlobalImmutableSpaceRegionKind; + } +}; + +/// \class The region containing globals which can be modified by calls to +/// "internally" defined functions - (for now just) functions other then system +/// calls. +class GlobalInternalSpaceRegion : public NonStaticGlobalSpaceRegion { + friend class MemRegionManager; + + GlobalInternalSpaceRegion(MemRegionManager *mgr) + : NonStaticGlobalSpaceRegion(mgr, GlobalInternalSpaceRegionKind) {} + +public: + + void dumpToStream(raw_ostream &os) const; + + static bool classof(const MemRegion *R) { + return R->getKind() == GlobalInternalSpaceRegionKind; + } +}; + +class HeapSpaceRegion : public MemSpaceRegion { + virtual void anchor(); + friend class MemRegionManager; + + HeapSpaceRegion(MemRegionManager *mgr) + : MemSpaceRegion(mgr, HeapSpaceRegionKind) {} +public: + static bool classof(const MemRegion *R) { + return R->getKind() == HeapSpaceRegionKind; + } +}; + +class UnknownSpaceRegion : public MemSpaceRegion { + virtual void anchor(); + friend class MemRegionManager; + UnknownSpaceRegion(MemRegionManager *mgr) + : MemSpaceRegion(mgr, UnknownSpaceRegionKind) {} +public: + static bool classof(const MemRegion *R) { + return R->getKind() == UnknownSpaceRegionKind; + } +}; + +class StackSpaceRegion : public MemSpaceRegion { +private: + const StackFrameContext *SFC; + +protected: + StackSpaceRegion(MemRegionManager *mgr, Kind k, const StackFrameContext *sfc) + : MemSpaceRegion(mgr, k), SFC(sfc) { + assert(classof(this)); + } + +public: + const StackFrameContext *getStackFrame() const { return SFC; } + + void Profile(llvm::FoldingSetNodeID &ID) const; + + static bool classof(const MemRegion *R) { + Kind k = R->getKind(); + return k >= StackLocalsSpaceRegionKind && + k <= StackArgumentsSpaceRegionKind; + } +}; + +class StackLocalsSpaceRegion : public StackSpaceRegion { + virtual void anchor(); + friend class MemRegionManager; + StackLocalsSpaceRegion(MemRegionManager *mgr, const StackFrameContext *sfc) + : StackSpaceRegion(mgr, StackLocalsSpaceRegionKind, sfc) {} +public: + static bool classof(const MemRegion *R) { + return R->getKind() == StackLocalsSpaceRegionKind; + } +}; + +class StackArgumentsSpaceRegion : public StackSpaceRegion { +private: + virtual void anchor(); + friend class MemRegionManager; + StackArgumentsSpaceRegion(MemRegionManager *mgr, const StackFrameContext *sfc) + : StackSpaceRegion(mgr, StackArgumentsSpaceRegionKind, sfc) {} +public: + static bool classof(const MemRegion *R) { + return R->getKind() == StackArgumentsSpaceRegionKind; + } +}; + + +/// SubRegion - A region that subsets another larger region. Most regions +/// are subclasses of SubRegion. +class SubRegion : public MemRegion { +private: + virtual void anchor(); +protected: + const MemRegion* superRegion; + SubRegion(const MemRegion* sReg, Kind k) : MemRegion(k), superRegion(sReg) {} +public: + const MemRegion* getSuperRegion() const { + return superRegion; + } + + /// getExtent - Returns the size of the region in bytes. + virtual DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const { + return UnknownVal(); + } + + MemRegionManager* getMemRegionManager() const; + + bool isSubRegionOf(const MemRegion* R) const; + + static bool classof(const MemRegion* R) { + return R->getKind() > END_MEMSPACES; + } +}; + +//===----------------------------------------------------------------------===// +// MemRegion subclasses. +//===----------------------------------------------------------------------===// + +/// AllocaRegion - A region that represents an untyped blob of bytes created +/// by a call to 'alloca'. +class AllocaRegion : public SubRegion { + friend class MemRegionManager; +protected: + unsigned Cnt; // Block counter. Used to distinguish different pieces of + // memory allocated by alloca at the same call site. + const Expr *Ex; + + AllocaRegion(const Expr *ex, unsigned cnt, const MemRegion *superRegion) + : SubRegion(superRegion, AllocaRegionKind), Cnt(cnt), Ex(ex) {} + +public: + + const Expr *getExpr() const { return Ex; } + + bool isBoundable() const { return true; } + + DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const; + + void Profile(llvm::FoldingSetNodeID& ID) const; + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Expr *Ex, + unsigned Cnt, const MemRegion *superRegion); + + void dumpToStream(raw_ostream &os) const; + + static bool classof(const MemRegion* R) { + return R->getKind() == AllocaRegionKind; + } +}; + +/// TypedRegion - An abstract class representing regions that are typed. +class TypedRegion : public SubRegion { +public: + virtual void anchor(); +protected: + TypedRegion(const MemRegion* sReg, Kind k) : SubRegion(sReg, k) {} + +public: + virtual QualType getLocationType() const = 0; + + QualType getDesugaredLocationType(ASTContext &Context) const { + return getLocationType().getDesugaredType(Context); + } + + bool isBoundable() const { return true; } + + static bool classof(const MemRegion* R) { + unsigned k = R->getKind(); + return k >= BEG_TYPED_REGIONS && k <= END_TYPED_REGIONS; + } +}; + +/// TypedValueRegion - An abstract class representing regions having a typed value. +class TypedValueRegion : public TypedRegion { +public: + virtual void anchor(); +protected: + TypedValueRegion(const MemRegion* sReg, Kind k) : TypedRegion(sReg, k) {} + +public: + virtual QualType getValueType() const = 0; + + virtual QualType getLocationType() const { + // FIXME: We can possibly optimize this later to cache this value. + QualType T = getValueType(); + ASTContext &ctx = getContext(); + if (T->getAs<ObjCObjectType>()) + return ctx.getObjCObjectPointerType(T); + return ctx.getPointerType(getValueType()); + } + + QualType getDesugaredValueType(ASTContext &Context) const { + QualType T = getValueType(); + return T.getTypePtrOrNull() ? T.getDesugaredType(Context) : T; + } + + static bool classof(const MemRegion* R) { + unsigned k = R->getKind(); + return k >= BEG_TYPED_VALUE_REGIONS && k <= END_TYPED_VALUE_REGIONS; + } +}; + + +class CodeTextRegion : public TypedRegion { +public: + virtual void anchor(); +protected: + CodeTextRegion(const MemRegion *sreg, Kind k) : TypedRegion(sreg, k) {} +public: + bool isBoundable() const { return false; } + + static bool classof(const MemRegion* R) { + Kind k = R->getKind(); + return k >= FunctionTextRegionKind && k <= BlockTextRegionKind; + } +}; + +/// FunctionTextRegion - A region that represents code texts of function. +class FunctionTextRegion : public CodeTextRegion { + const FunctionDecl *FD; +public: + FunctionTextRegion(const FunctionDecl *fd, const MemRegion* sreg) + : CodeTextRegion(sreg, FunctionTextRegionKind), FD(fd) {} + + QualType getLocationType() const { + return getContext().getPointerType(FD->getType()); + } + + const FunctionDecl *getDecl() const { + return FD; + } + + virtual void dumpToStream(raw_ostream &os) const; + + void Profile(llvm::FoldingSetNodeID& ID) const; + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, const FunctionDecl *FD, + const MemRegion*); + + static bool classof(const MemRegion* R) { + return R->getKind() == FunctionTextRegionKind; + } +}; + + +/// BlockTextRegion - A region that represents code texts of blocks (closures). +/// Blocks are represented with two kinds of regions. BlockTextRegions +/// represent the "code", while BlockDataRegions represent instances of blocks, +/// which correspond to "code+data". The distinction is important, because +/// like a closure a block captures the values of externally referenced +/// variables. +class BlockTextRegion : public CodeTextRegion { + friend class MemRegionManager; + + const BlockDecl *BD; + AnalysisDeclContext *AC; + CanQualType locTy; + + BlockTextRegion(const BlockDecl *bd, CanQualType lTy, + AnalysisDeclContext *ac, const MemRegion* sreg) + : CodeTextRegion(sreg, BlockTextRegionKind), BD(bd), AC(ac), locTy(lTy) {} + +public: + QualType getLocationType() const { + return locTy; + } + + const BlockDecl *getDecl() const { + return BD; + } + + AnalysisDeclContext *getAnalysisDeclContext() const { return AC; } + + virtual void dumpToStream(raw_ostream &os) const; + + void Profile(llvm::FoldingSetNodeID& ID) const; + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, const BlockDecl *BD, + CanQualType, const AnalysisDeclContext*, + const MemRegion*); + + static bool classof(const MemRegion* R) { + return R->getKind() == BlockTextRegionKind; + } +}; + +/// BlockDataRegion - A region that represents a block instance. +/// Blocks are represented with two kinds of regions. BlockTextRegions +/// represent the "code", while BlockDataRegions represent instances of blocks, +/// which correspond to "code+data". The distinction is important, because +/// like a closure a block captures the values of externally referenced +/// variables. +class BlockDataRegion : public SubRegion { + friend class MemRegionManager; + const BlockTextRegion *BC; + const LocationContext *LC; // Can be null */ + void *ReferencedVars; + + BlockDataRegion(const BlockTextRegion *bc, const LocationContext *lc, + const MemRegion *sreg) + : SubRegion(sreg, BlockDataRegionKind), BC(bc), LC(lc), ReferencedVars(0) {} + +public: + const BlockTextRegion *getCodeRegion() const { return BC; } + + const BlockDecl *getDecl() const { return BC->getDecl(); } + + class referenced_vars_iterator { + const MemRegion * const *R; + public: + explicit referenced_vars_iterator(const MemRegion * const *r) : R(r) {} + + operator const MemRegion * const *() const { + return R; + } + + const VarRegion* operator*() const { + return cast<VarRegion>(*R); + } + + bool operator==(const referenced_vars_iterator &I) const { + return I.R == R; + } + bool operator!=(const referenced_vars_iterator &I) const { + return I.R != R; + } + referenced_vars_iterator &operator++() { + ++R; + return *this; + } + }; + + referenced_vars_iterator referenced_vars_begin() const; + referenced_vars_iterator referenced_vars_end() const; + + virtual void dumpToStream(raw_ostream &os) const; + + void Profile(llvm::FoldingSetNodeID& ID) const; + + static void ProfileRegion(llvm::FoldingSetNodeID&, const BlockTextRegion *, + const LocationContext *, const MemRegion *); + + static bool classof(const MemRegion* R) { + return R->getKind() == BlockDataRegionKind; + } +private: + void LazyInitializeReferencedVars(); +}; + +/// SymbolicRegion - A special, "non-concrete" region. Unlike other region +/// clases, SymbolicRegion represents a region that serves as an alias for +/// either a real region, a NULL pointer, etc. It essentially is used to +/// map the concept of symbolic values into the domain of regions. Symbolic +/// regions do not need to be typed. +class SymbolicRegion : public SubRegion { +protected: + const SymbolRef sym; + +public: + SymbolicRegion(const SymbolRef s, const MemRegion* sreg) + : SubRegion(sreg, SymbolicRegionKind), sym(s) {} + + SymbolRef getSymbol() const { + return sym; + } + + bool isBoundable() const { return true; } + + DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const; + + void Profile(llvm::FoldingSetNodeID& ID) const; + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, + SymbolRef sym, + const MemRegion* superRegion); + + void dumpToStream(raw_ostream &os) const; + + static bool classof(const MemRegion* R) { + return R->getKind() == SymbolicRegionKind; + } +}; + +/// StringRegion - Region associated with a StringLiteral. +class StringRegion : public TypedValueRegion { + friend class MemRegionManager; + const StringLiteral* Str; +protected: + + StringRegion(const StringLiteral* str, const MemRegion* sreg) + : TypedValueRegion(sreg, StringRegionKind), Str(str) {} + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, + const StringLiteral* Str, + const MemRegion* superRegion); + +public: + + const StringLiteral* getStringLiteral() const { return Str; } + + QualType getValueType() const { + return Str->getType(); + } + + DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const; + + bool isBoundable() const { return false; } + + void Profile(llvm::FoldingSetNodeID& ID) const { + ProfileRegion(ID, Str, superRegion); + } + + void dumpToStream(raw_ostream &os) const; + + static bool classof(const MemRegion* R) { + return R->getKind() == StringRegionKind; + } +}; + +/// The region associated with an ObjCStringLiteral. +class ObjCStringRegion : public TypedValueRegion { + friend class MemRegionManager; + const ObjCStringLiteral* Str; +protected: + + ObjCStringRegion(const ObjCStringLiteral* str, const MemRegion* sreg) + : TypedValueRegion(sreg, ObjCStringRegionKind), Str(str) {} + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, + const ObjCStringLiteral* Str, + const MemRegion* superRegion); + +public: + + const ObjCStringLiteral* getObjCStringLiteral() const { return Str; } + + QualType getValueType() const { + return Str->getType(); + } + + bool isBoundable() const { return false; } + + void Profile(llvm::FoldingSetNodeID& ID) const { + ProfileRegion(ID, Str, superRegion); + } + + void dumpToStream(raw_ostream &os) const; + + static bool classof(const MemRegion* R) { + return R->getKind() == ObjCStringRegionKind; + } +}; + +/// CompoundLiteralRegion - A memory region representing a compound literal. +/// Compound literals are essentially temporaries that are stack allocated +/// or in the global constant pool. +class CompoundLiteralRegion : public TypedValueRegion { +private: + friend class MemRegionManager; + const CompoundLiteralExpr *CL; + + CompoundLiteralRegion(const CompoundLiteralExpr *cl, const MemRegion* sReg) + : TypedValueRegion(sReg, CompoundLiteralRegionKind), CL(cl) {} + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, + const CompoundLiteralExpr *CL, + const MemRegion* superRegion); +public: + QualType getValueType() const { + return CL->getType(); + } + + bool isBoundable() const { return !CL->isFileScope(); } + + void Profile(llvm::FoldingSetNodeID& ID) const; + + void dumpToStream(raw_ostream &os) const; + + const CompoundLiteralExpr *getLiteralExpr() const { return CL; } + + static bool classof(const MemRegion* R) { + return R->getKind() == CompoundLiteralRegionKind; + } +}; + +class DeclRegion : public TypedValueRegion { +protected: + const Decl *D; + + DeclRegion(const Decl *d, const MemRegion* sReg, Kind k) + : TypedValueRegion(sReg, k), D(d) {} + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Decl *D, + const MemRegion* superRegion, Kind k); + +public: + const Decl *getDecl() const { return D; } + void Profile(llvm::FoldingSetNodeID& ID) const; + + DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const; + + static bool classof(const MemRegion* R) { + unsigned k = R->getKind(); + return k >= BEG_DECL_REGIONS && k <= END_DECL_REGIONS; + } +}; + +class VarRegion : public DeclRegion { + friend class MemRegionManager; + + // Constructors and private methods. + VarRegion(const VarDecl *vd, const MemRegion* sReg) + : DeclRegion(vd, sReg, VarRegionKind) {} + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, const VarDecl *VD, + const MemRegion *superRegion) { + DeclRegion::ProfileRegion(ID, VD, superRegion, VarRegionKind); + } + + void Profile(llvm::FoldingSetNodeID& ID) const; + +public: + const VarDecl *getDecl() const { return cast<VarDecl>(D); } + + const StackFrameContext *getStackFrame() const; + + QualType getValueType() const { + // FIXME: We can cache this if needed. + return getDecl()->getType(); + } + + void dumpToStream(raw_ostream &os) const; + + static bool classof(const MemRegion* R) { + return R->getKind() == VarRegionKind; + } + + void dumpPretty(raw_ostream &os) const; +}; + +/// CXXThisRegion - Represents the region for the implicit 'this' parameter +/// in a call to a C++ method. This region doesn't represent the object +/// referred to by 'this', but rather 'this' itself. +class CXXThisRegion : public TypedValueRegion { + friend class MemRegionManager; + CXXThisRegion(const PointerType *thisPointerTy, + const MemRegion *sReg) + : TypedValueRegion(sReg, CXXThisRegionKind), ThisPointerTy(thisPointerTy) {} + + static void ProfileRegion(llvm::FoldingSetNodeID &ID, + const PointerType *PT, + const MemRegion *sReg); + + void Profile(llvm::FoldingSetNodeID &ID) const; + +public: + QualType getValueType() const { + return QualType(ThisPointerTy, 0); + } + + void dumpToStream(raw_ostream &os) const; + + static bool classof(const MemRegion* R) { + return R->getKind() == CXXThisRegionKind; + } + +private: + const PointerType *ThisPointerTy; +}; + +class FieldRegion : public DeclRegion { + friend class MemRegionManager; + + FieldRegion(const FieldDecl *fd, const MemRegion* sReg) + : DeclRegion(fd, sReg, FieldRegionKind) {} + +public: + const FieldDecl *getDecl() const { return cast<FieldDecl>(D); } + + QualType getValueType() const { + // FIXME: We can cache this if needed. + return getDecl()->getType(); + } + + DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const; + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, const FieldDecl *FD, + const MemRegion* superRegion) { + DeclRegion::ProfileRegion(ID, FD, superRegion, FieldRegionKind); + } + + static bool classof(const MemRegion* R) { + return R->getKind() == FieldRegionKind; + } + + void dumpToStream(raw_ostream &os) const; + void dumpPretty(raw_ostream &os) const; +}; + +class ObjCIvarRegion : public DeclRegion { + + friend class MemRegionManager; + + ObjCIvarRegion(const ObjCIvarDecl *ivd, const MemRegion* sReg); + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, const ObjCIvarDecl *ivd, + const MemRegion* superRegion); + +public: + const ObjCIvarDecl *getDecl() const; + QualType getValueType() const; + + void dumpToStream(raw_ostream &os) const; + + static bool classof(const MemRegion* R) { + return R->getKind() == ObjCIvarRegionKind; + } +}; +//===----------------------------------------------------------------------===// +// Auxiliary data classes for use with MemRegions. +//===----------------------------------------------------------------------===// + +class ElementRegion; + +class RegionRawOffset { +private: + friend class ElementRegion; + + const MemRegion *Region; + CharUnits Offset; + + RegionRawOffset(const MemRegion* reg, CharUnits offset = CharUnits::Zero()) + : Region(reg), Offset(offset) {} + +public: + // FIXME: Eventually support symbolic offsets. + CharUnits getOffset() const { return Offset; } + const MemRegion *getRegion() const { return Region; } + + void dumpToStream(raw_ostream &os) const; + void dump() const; +}; + +/// \brief ElementRegin is used to represent both array elements and casts. +class ElementRegion : public TypedValueRegion { + friend class MemRegionManager; + + QualType ElementType; + NonLoc Index; + + ElementRegion(QualType elementType, NonLoc Idx, const MemRegion* sReg) + : TypedValueRegion(sReg, ElementRegionKind), + ElementType(elementType), Index(Idx) { + assert((!isa<nonloc::ConcreteInt>(&Idx) || + cast<nonloc::ConcreteInt>(&Idx)->getValue().isSigned()) && + "The index must be signed"); + } + + static void ProfileRegion(llvm::FoldingSetNodeID& ID, QualType elementType, + SVal Idx, const MemRegion* superRegion); + +public: + + NonLoc getIndex() const { return Index; } + + QualType getValueType() const { + return ElementType; + } + + QualType getElementType() const { + return ElementType; + } + /// Compute the offset within the array. The array might also be a subobject. + RegionRawOffset getAsArrayOffset() const; + + void dumpToStream(raw_ostream &os) const; + + void Profile(llvm::FoldingSetNodeID& ID) const; + + static bool classof(const MemRegion* R) { + return R->getKind() == ElementRegionKind; + } +}; + +// C++ temporary object associated with an expression. +class CXXTempObjectRegion : public TypedValueRegion { + friend class MemRegionManager; + + Expr const *Ex; + + CXXTempObjectRegion(Expr const *E, MemRegion const *sReg) + : TypedValueRegion(sReg, CXXTempObjectRegionKind), Ex(E) {} + + static void ProfileRegion(llvm::FoldingSetNodeID &ID, + Expr const *E, const MemRegion *sReg); + +public: + const Expr *getExpr() const { return Ex; } + + QualType getValueType() const { + return Ex->getType(); + } + + void dumpToStream(raw_ostream &os) const; + + void Profile(llvm::FoldingSetNodeID &ID) const; + + static bool classof(const MemRegion* R) { + return R->getKind() == CXXTempObjectRegionKind; + } +}; + +// CXXBaseObjectRegion represents a base object within a C++ object. It is +// identified by the base class declaration and the region of its parent object. +class CXXBaseObjectRegion : public TypedValueRegion { + friend class MemRegionManager; + + const CXXRecordDecl *decl; + + CXXBaseObjectRegion(const CXXRecordDecl *d, const MemRegion *sReg) + : TypedValueRegion(sReg, CXXBaseObjectRegionKind), decl(d) {} + + static void ProfileRegion(llvm::FoldingSetNodeID &ID, + const CXXRecordDecl *decl, const MemRegion *sReg); + +public: + const CXXRecordDecl *getDecl() const { return decl; } + + QualType getValueType() const; + + void dumpToStream(raw_ostream &os) const; + + void Profile(llvm::FoldingSetNodeID &ID) const; + + static bool classof(const MemRegion *region) { + return region->getKind() == CXXBaseObjectRegionKind; + } +}; + +template<typename RegionTy> +const RegionTy* MemRegion::getAs() const { + if (const RegionTy* RT = dyn_cast<RegionTy>(this)) + return RT; + + return NULL; +} + +//===----------------------------------------------------------------------===// +// MemRegionManager - Factory object for creating regions. +//===----------------------------------------------------------------------===// + +class MemRegionManager { + ASTContext &C; + llvm::BumpPtrAllocator& A; + llvm::FoldingSet<MemRegion> Regions; + + GlobalInternalSpaceRegion *InternalGlobals; + GlobalSystemSpaceRegion *SystemGlobals; + GlobalImmutableSpaceRegion *ImmutableGlobals; + + + llvm::DenseMap<const StackFrameContext *, StackLocalsSpaceRegion *> + StackLocalsSpaceRegions; + llvm::DenseMap<const StackFrameContext *, StackArgumentsSpaceRegion *> + StackArgumentsSpaceRegions; + llvm::DenseMap<const CodeTextRegion *, StaticGlobalSpaceRegion *> + StaticsGlobalSpaceRegions; + + HeapSpaceRegion *heap; + UnknownSpaceRegion *unknown; + MemSpaceRegion *code; + +public: + MemRegionManager(ASTContext &c, llvm::BumpPtrAllocator& a) + : C(c), A(a), InternalGlobals(0), SystemGlobals(0), ImmutableGlobals(0), + heap(0), unknown(0), code(0) {} + + ~MemRegionManager(); + + ASTContext &getContext() { return C; } + + llvm::BumpPtrAllocator &getAllocator() { return A; } + + /// getStackLocalsRegion - Retrieve the memory region associated with the + /// specified stack frame. + const StackLocalsSpaceRegion * + getStackLocalsRegion(const StackFrameContext *STC); + + /// getStackArgumentsRegion - Retrieve the memory region associated with + /// function/method arguments of the specified stack frame. + const StackArgumentsSpaceRegion * + getStackArgumentsRegion(const StackFrameContext *STC); + + /// getGlobalsRegion - Retrieve the memory region associated with + /// global variables. + const GlobalsSpaceRegion *getGlobalsRegion( + MemRegion::Kind K = MemRegion::GlobalInternalSpaceRegionKind, + const CodeTextRegion *R = 0); + + /// getHeapRegion - Retrieve the memory region associated with the + /// generic "heap". + const HeapSpaceRegion *getHeapRegion(); + + /// getUnknownRegion - Retrieve the memory region associated with unknown + /// memory space. + const MemSpaceRegion *getUnknownRegion(); + + const MemSpaceRegion *getCodeRegion(); + + /// getAllocaRegion - Retrieve a region associated with a call to alloca(). + const AllocaRegion *getAllocaRegion(const Expr *Ex, unsigned Cnt, + const LocationContext *LC); + + /// getCompoundLiteralRegion - Retrieve the region associated with a + /// given CompoundLiteral. + const CompoundLiteralRegion* + getCompoundLiteralRegion(const CompoundLiteralExpr *CL, + const LocationContext *LC); + + /// getCXXThisRegion - Retrieve the [artificial] region associated with the + /// parameter 'this'. + const CXXThisRegion *getCXXThisRegion(QualType thisPointerTy, + const LocationContext *LC); + + /// getSymbolicRegion - Retrieve or create a "symbolic" memory region. + const SymbolicRegion* getSymbolicRegion(SymbolRef sym); + + const StringRegion *getStringRegion(const StringLiteral* Str); + + const ObjCStringRegion *getObjCStringRegion(const ObjCStringLiteral *Str); + + /// getVarRegion - Retrieve or create the memory region associated with + /// a specified VarDecl and LocationContext. + const VarRegion* getVarRegion(const VarDecl *D, const LocationContext *LC); + + /// getVarRegion - Retrieve or create the memory region associated with + /// a specified VarDecl and super region. + const VarRegion* getVarRegion(const VarDecl *D, const MemRegion *superR); + + /// getElementRegion - Retrieve the memory region associated with the + /// associated element type, index, and super region. + const ElementRegion *getElementRegion(QualType elementType, NonLoc Idx, + const MemRegion *superRegion, + ASTContext &Ctx); + + const ElementRegion *getElementRegionWithSuper(const ElementRegion *ER, + const MemRegion *superRegion) { + return getElementRegion(ER->getElementType(), ER->getIndex(), + superRegion, ER->getContext()); + } + + /// getFieldRegion - Retrieve or create the memory region associated with + /// a specified FieldDecl. 'superRegion' corresponds to the containing + /// memory region (which typically represents the memory representing + /// a structure or class). + const FieldRegion *getFieldRegion(const FieldDecl *fd, + const MemRegion* superRegion); + + const FieldRegion *getFieldRegionWithSuper(const FieldRegion *FR, + const MemRegion *superRegion) { + return getFieldRegion(FR->getDecl(), superRegion); + } + + /// getObjCIvarRegion - Retrieve or create the memory region associated with + /// a specified Objective-c instance variable. 'superRegion' corresponds + /// to the containing region (which typically represents the Objective-C + /// object). + const ObjCIvarRegion *getObjCIvarRegion(const ObjCIvarDecl *ivd, + const MemRegion* superRegion); + + const CXXTempObjectRegion *getCXXTempObjectRegion(Expr const *Ex, + LocationContext const *LC); + + const CXXBaseObjectRegion *getCXXBaseObjectRegion(const CXXRecordDecl *decl, + const MemRegion *superRegion); + + /// Create a CXXBaseObjectRegion with the same CXXRecordDecl but a different + /// super region. + const CXXBaseObjectRegion * + getCXXBaseObjectRegionWithSuper(const CXXBaseObjectRegion *baseReg, + const MemRegion *superRegion) { + return getCXXBaseObjectRegion(baseReg->getDecl(), superRegion); + } + + const FunctionTextRegion *getFunctionTextRegion(const FunctionDecl *FD); + const BlockTextRegion *getBlockTextRegion(const BlockDecl *BD, + CanQualType locTy, + AnalysisDeclContext *AC); + + /// getBlockDataRegion - Get the memory region associated with an instance + /// of a block. Unlike many other MemRegions, the LocationContext* + /// argument is allowed to be NULL for cases where we have no known + /// context. + const BlockDataRegion *getBlockDataRegion(const BlockTextRegion *bc, + const LocationContext *lc = NULL); + +private: + template <typename RegionTy, typename A1> + RegionTy* getRegion(const A1 a1); + + template <typename RegionTy, typename A1> + RegionTy* getSubRegion(const A1 a1, const MemRegion* superRegion); + + template <typename RegionTy, typename A1, typename A2> + RegionTy* getRegion(const A1 a1, const A2 a2); + + template <typename RegionTy, typename A1, typename A2> + RegionTy* getSubRegion(const A1 a1, const A2 a2, + const MemRegion* superRegion); + + template <typename RegionTy, typename A1, typename A2, typename A3> + RegionTy* getSubRegion(const A1 a1, const A2 a2, const A3 a3, + const MemRegion* superRegion); + + template <typename REG> + const REG* LazyAllocate(REG*& region); + + template <typename REG, typename ARG> + const REG* LazyAllocate(REG*& region, ARG a); +}; + +//===----------------------------------------------------------------------===// +// Out-of-line member definitions. +//===----------------------------------------------------------------------===// + +inline ASTContext &MemRegion::getContext() const { + return getMemRegionManager()->getContext(); +} + +} // end GR namespace + +} // end clang namespace + +//===----------------------------------------------------------------------===// +// Pretty-printing regions. +//===----------------------------------------------------------------------===// + +namespace llvm { +static inline raw_ostream &operator<<(raw_ostream &os, + const clang::ento::MemRegion* R) { + R->dumpToStream(os); + return os; +} +} // end llvm namespace + +#endif diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h new file mode 100644 index 0000000..d8aec09 --- /dev/null +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h @@ -0,0 +1,293 @@ +//===- ObjCMessage.h - Wrapper for ObjC messages and dot syntax ---*- C++ -*--// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines ObjCMessage which serves as a common wrapper for ObjC +// message expressions or implicit messages for loading/storing ObjC properties. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_STATICANALYZER_PATHSENSITIVE_OBJCMESSAGE +#define LLVM_CLANG_STATICANALYZER_PATHSENSITIVE_OBJCMESSAGE + +#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" +#include "clang/AST/ExprObjC.h" +#include "clang/AST/ExprCXX.h" +#include "clang/Basic/SourceManager.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/Compiler.h" + +namespace clang { +namespace ento { +using llvm::StrInStrNoCase; + +/// \brief Represents both explicit ObjC message expressions and implicit +/// messages that are sent for handling properties in dot syntax. +class ObjCMessage { + const ObjCMessageExpr *Msg; + const ObjCPropertyRefExpr *PE; + const bool IsPropSetter; +public: + ObjCMessage() : Msg(0), PE(0), IsPropSetter(false) {} + + ObjCMessage(const ObjCMessageExpr *E, const ObjCPropertyRefExpr *pe = 0, + bool isSetter = false) + : Msg(E), PE(pe), IsPropSetter(isSetter) { + assert(E && "should not be initialized with null expression"); + } + + bool isValid() const { return Msg; } + + bool isPureMessageExpr() const { return !PE; } + + bool isPropertyGetter() const { return PE && !IsPropSetter; } + + bool isPropertySetter() const { + return IsPropSetter; + } + + const Expr *getMessageExpr() const { + return Msg; + } + + QualType getType(ASTContext &ctx) const { + return Msg->getType(); + } + + QualType getResultType(ASTContext &ctx) const { + if (const ObjCMethodDecl *MD = Msg->getMethodDecl()) + return MD->getResultType(); + return getType(ctx); + } + + ObjCMethodFamily getMethodFamily() const { + return Msg->getMethodFamily(); + } + + Selector getSelector() const { + return Msg->getSelector(); + } + + const Expr *getInstanceReceiver() const { + return Msg->getInstanceReceiver(); + } + + SVal getInstanceReceiverSVal(ProgramStateRef State, + const LocationContext *LC) const { + if (!isInstanceMessage()) + return UndefinedVal(); + if (const Expr *Ex = getInstanceReceiver()) + return State->getSValAsScalarOrLoc(Ex, LC); + + // An instance message with no expression means we are sending to super. + // In this case the object reference is the same as 'self'. + const ImplicitParamDecl *SelfDecl = LC->getSelfDecl(); + assert(SelfDecl && "No message receiver Expr, but not in an ObjC method"); + return State->getSVal(State->getRegion(SelfDecl, LC)); + } + + bool isInstanceMessage() const { + return Msg->isInstanceMessage(); + } + + const ObjCMethodDecl *getMethodDecl() const { + return Msg->getMethodDecl(); + } + + const ObjCInterfaceDecl *getReceiverInterface() const { + return Msg->getReceiverInterface(); + } + + SourceLocation getSuperLoc() const { + if (PE) + return PE->getReceiverLocation(); + return Msg->getSuperLoc(); + } + + SourceRange getSourceRange() const LLVM_READONLY { + if (PE) + return PE->getSourceRange(); + return Msg->getSourceRange(); + } + + unsigned getNumArgs() const { + return Msg->getNumArgs(); + } + + SVal getArgSVal(unsigned i, + const LocationContext *LCtx, + ProgramStateRef state) const { + assert(i < getNumArgs() && "Invalid index for argument"); + return state->getSVal(Msg->getArg(i), LCtx); + } + + QualType getArgType(unsigned i) const { + assert(i < getNumArgs() && "Invalid index for argument"); + return Msg->getArg(i)->getType(); + } + + const Expr *getArgExpr(unsigned i) const { + assert(i < getNumArgs() && "Invalid index for argument"); + return Msg->getArg(i); + } + + SourceRange getArgSourceRange(unsigned i) const { + const Expr *argE = getArgExpr(i); + return argE->getSourceRange(); + } + + SourceRange getReceiverSourceRange() const { + if (PE) { + if (PE->isObjectReceiver()) + return PE->getBase()->getSourceRange(); + } + else { + return Msg->getReceiverRange(); + } + + // FIXME: This isn't a range. + return PE->getReceiverLocation(); + } +}; + +/// \brief Common wrapper for a call expression, ObjC message, or C++ +/// constructor, mainly to provide a common interface for their arguments. +class CallOrObjCMessage { + llvm::PointerUnion<const CallExpr *, const CXXConstructExpr *> CallE; + ObjCMessage Msg; + ProgramStateRef State; + const LocationContext *LCtx; +public: + CallOrObjCMessage(const CallExpr *callE, ProgramStateRef state, + const LocationContext *lctx) + : CallE(callE), State(state), LCtx(lctx) {} + CallOrObjCMessage(const CXXConstructExpr *consE, ProgramStateRef state, + const LocationContext *lctx) + : CallE(consE), State(state), LCtx(lctx) {} + CallOrObjCMessage(const ObjCMessage &msg, ProgramStateRef state, + const LocationContext *lctx) + : CallE((CallExpr *)0), Msg(msg), State(state), LCtx(lctx) {} + + QualType getResultType(ASTContext &ctx) const; + + bool isFunctionCall() const { + return CallE && CallE.is<const CallExpr *>(); + } + + bool isCXXConstructExpr() const { + return CallE && CallE.is<const CXXConstructExpr *>(); + } + + bool isObjCMessage() const { + return !CallE; + } + + bool isCXXCall() const { + const CallExpr *ActualCallE = CallE.dyn_cast<const CallExpr *>(); + return ActualCallE && isa<CXXMemberCallExpr>(ActualCallE); + } + + /// Check if the callee is declared in the system header. + bool isInSystemHeader() const { + if (const Decl *FD = getDecl()) { + const SourceManager &SM = + State->getStateManager().getContext().getSourceManager(); + return SM.isInSystemHeader(FD->getLocation()); + } + return false; + } + + const Expr *getOriginExpr() const { + if (!CallE) + return Msg.getMessageExpr(); + if (const CXXConstructExpr *Ctor = + CallE.dyn_cast<const CXXConstructExpr *>()) + return Ctor; + return CallE.get<const CallExpr *>(); + } + + SVal getFunctionCallee() const; + SVal getCXXCallee() const; + SVal getInstanceMessageReceiver(const LocationContext *LC) const; + + /// Get the declaration of the function or method. + const Decl *getDecl() const; + + unsigned getNumArgs() const { + if (!CallE) + return Msg.getNumArgs(); + if (const CXXConstructExpr *Ctor = + CallE.dyn_cast<const CXXConstructExpr *>()) + return Ctor->getNumArgs(); + return CallE.get<const CallExpr *>()->getNumArgs(); + } + + SVal getArgSVal(unsigned i) const { + assert(i < getNumArgs()); + if (!CallE) + return Msg.getArgSVal(i, LCtx, State); + return State->getSVal(getArg(i), LCtx); + } + + const Expr *getArg(unsigned i) const { + assert(i < getNumArgs()); + if (!CallE) + return Msg.getArgExpr(i); + if (const CXXConstructExpr *Ctor = + CallE.dyn_cast<const CXXConstructExpr *>()) + return Ctor->getArg(i); + return CallE.get<const CallExpr *>()->getArg(i); + } + + SourceRange getArgSourceRange(unsigned i) const { + assert(i < getNumArgs()); + if (CallE) + return getArg(i)->getSourceRange(); + return Msg.getArgSourceRange(i); + } + + SourceRange getReceiverSourceRange() const { + assert(isObjCMessage()); + return Msg.getReceiverSourceRange(); + } + + /// \brief Check if the name corresponds to a CoreFoundation or CoreGraphics + /// function that allows objects to escape. + /// + /// Many methods allow a tracked object to escape. For example: + /// + /// CFMutableDictionaryRef x = CFDictionaryCreateMutable(..., customDeallocator); + /// CFDictionaryAddValue(y, key, x); + /// + /// We handle this and similar cases with the following heuristic. If the + /// function name contains "InsertValue", "SetValue", "AddValue", + /// "AppendValue", or "SetAttribute", then we assume that arguments may + /// escape. + // + // TODO: To reduce false negatives here, we should track the container + // allocation site and check if a proper deallocator was set there. + static bool isCFCGAllowingEscape(StringRef FName) { + if (FName[0] == 'C' && (FName[1] == 'F' || FName[1] == 'G')) + if (StrInStrNoCase(FName, "InsertValue") != StringRef::npos|| + StrInStrNoCase(FName, "AddValue") != StringRef::npos || + StrInStrNoCase(FName, "SetValue") != StringRef::npos || + StrInStrNoCase(FName, "WithData") != StringRef::npos || + StrInStrNoCase(FName, "AppendValue") != StringRef::npos|| + StrInStrNoCase(FName, "SetAttribute") != StringRef::npos) { + return true; + } + return false; + } +}; + +} +} + +#endif diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h new file mode 100644 index 0000000..360d648 --- /dev/null +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h @@ -0,0 +1,796 @@ +//== ProgramState.h - Path-sensitive "State" for tracking values -*- C++ -*--=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines SymbolRef, ExprBindKey, and ProgramState*. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_GR_VALUESTATE_H +#define LLVM_CLANG_GR_VALUESTATE_H + +#include "clang/Basic/LLVM.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/Environment.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/TaintTag.h" +#include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/ImmutableMap.h" + +namespace llvm { +class APSInt; +class BumpPtrAllocator; +} + +namespace clang { +class ASTContext; + +namespace ento { + +class CallOrObjCMessage; + +typedef ConstraintManager* (*ConstraintManagerCreator)(ProgramStateManager&, + SubEngine&); +typedef StoreManager* (*StoreManagerCreator)(ProgramStateManager&); + +//===----------------------------------------------------------------------===// +// ProgramStateTrait - Traits used by the Generic Data Map of a ProgramState. +//===----------------------------------------------------------------------===// + +template <typename T> struct ProgramStatePartialTrait; + +template <typename T> struct ProgramStateTrait { + typedef typename T::data_type data_type; + static inline void *GDMIndex() { return &T::TagInt; } + static inline void *MakeVoidPtr(data_type D) { return (void*) D; } + static inline data_type MakeData(void *const* P) { + return P ? (data_type) *P : (data_type) 0; + } +}; + +/// \class ProgramState +/// ProgramState - This class encapsulates: +/// +/// 1. A mapping from expressions to values (Environment) +/// 2. A mapping from locations to values (Store) +/// 3. Constraints on symbolic values (GenericDataMap) +/// +/// Together these represent the "abstract state" of a program. +/// +/// ProgramState is intended to be used as a functional object; that is, +/// once it is created and made "persistent" in a FoldingSet, its +/// values will never change. +class ProgramState : public llvm::FoldingSetNode { +public: + typedef llvm::ImmutableSet<llvm::APSInt*> IntSetTy; + typedef llvm::ImmutableMap<void*, void*> GenericDataMap; + +private: + void operator=(const ProgramState& R) const; // Do not implement. + + friend class ProgramStateManager; + friend class ExplodedGraph; + friend class ExplodedNode; + + ProgramStateManager *stateMgr; + Environment Env; // Maps a Stmt to its current SVal. + Store store; // Maps a location to its current value. + GenericDataMap GDM; // Custom data stored by a client of this class. + unsigned refCount; + + /// makeWithStore - Return a ProgramState with the same values as the current + /// state with the exception of using the specified Store. + ProgramStateRef makeWithStore(const StoreRef &store) const; + + void setStore(const StoreRef &storeRef); + +public: + /// This ctor is used when creating the first ProgramState object. + ProgramState(ProgramStateManager *mgr, const Environment& env, + StoreRef st, GenericDataMap gdm); + + /// Copy ctor - We must explicitly define this or else the "Next" ptr + /// in FoldingSetNode will also get copied. + ProgramState(const ProgramState &RHS); + + ~ProgramState(); + + /// Return the ProgramStateManager associated with this state. + ProgramStateManager &getStateManager() const { return *stateMgr; } + + /// getEnvironment - Return the environment associated with this state. + /// The environment is the mapping from expressions to values. + const Environment& getEnvironment() const { return Env; } + + /// Return the store associated with this state. The store + /// is a mapping from locations to values. + Store getStore() const { return store; } + + + /// getGDM - Return the generic data map associated with this state. + GenericDataMap getGDM() const { return GDM; } + + void setGDM(GenericDataMap gdm) { GDM = gdm; } + + /// Profile - Profile the contents of a ProgramState object for use in a + /// FoldingSet. Two ProgramState objects are considered equal if they + /// have the same Environment, Store, and GenericDataMap. + static void Profile(llvm::FoldingSetNodeID& ID, const ProgramState *V) { + V->Env.Profile(ID); + ID.AddPointer(V->store); + V->GDM.Profile(ID); + } + + /// Profile - Used to profile the contents of this object for inclusion + /// in a FoldingSet. + void Profile(llvm::FoldingSetNodeID& ID) const { + Profile(ID, this); + } + + BasicValueFactory &getBasicVals() const; + SymbolManager &getSymbolManager() const; + + //==---------------------------------------------------------------------==// + // Constraints on values. + //==---------------------------------------------------------------------==// + // + // Each ProgramState records constraints on symbolic values. These constraints + // are managed using the ConstraintManager associated with a ProgramStateManager. + // As constraints gradually accrue on symbolic values, added constraints + // may conflict and indicate that a state is infeasible (as no real values + // could satisfy all the constraints). This is the principal mechanism + // for modeling path-sensitivity in ExprEngine/ProgramState. + // + // Various "assume" methods form the interface for adding constraints to + // symbolic values. A call to 'assume' indicates an assumption being placed + // on one or symbolic values. 'assume' methods take the following inputs: + // + // (1) A ProgramState object representing the current state. + // + // (2) The assumed constraint (which is specific to a given "assume" method). + // + // (3) A binary value "Assumption" that indicates whether the constraint is + // assumed to be true or false. + // + // The output of "assume*" is a new ProgramState object with the added constraints. + // If no new state is feasible, NULL is returned. + // + + ProgramStateRef assume(DefinedOrUnknownSVal cond, bool assumption) const; + + /// This method assumes both "true" and "false" for 'cond', and + /// returns both corresponding states. It's shorthand for doing + /// 'assume' twice. + std::pair<ProgramStateRef , ProgramStateRef > + assume(DefinedOrUnknownSVal cond) const; + + ProgramStateRef assumeInBound(DefinedOrUnknownSVal idx, + DefinedOrUnknownSVal upperBound, + bool assumption, + QualType IndexType = QualType()) const; + + /// Utility method for getting regions. + const VarRegion* getRegion(const VarDecl *D, const LocationContext *LC) const; + + //==---------------------------------------------------------------------==// + // Binding and retrieving values to/from the environment and symbolic store. + //==---------------------------------------------------------------------==// + + /// BindCompoundLiteral - Return the state that has the bindings currently + /// in this state plus the bindings for the CompoundLiteral. + ProgramStateRef bindCompoundLiteral(const CompoundLiteralExpr *CL, + const LocationContext *LC, + SVal V) const; + + /// Create a new state by binding the value 'V' to the statement 'S' in the + /// state's environment. + ProgramStateRef BindExpr(const Stmt *S, const LocationContext *LCtx, + SVal V, bool Invalidate = true) const; + + /// Create a new state by binding the value 'V' and location 'locaton' to the + /// statement 'S' in the state's environment. + ProgramStateRef bindExprAndLocation(const Stmt *S, + const LocationContext *LCtx, + SVal location, SVal V) const; + + ProgramStateRef bindDecl(const VarRegion *VR, SVal V) const; + + ProgramStateRef bindDeclWithNoInit(const VarRegion *VR) const; + + ProgramStateRef bindLoc(Loc location, SVal V) const; + + ProgramStateRef bindLoc(SVal location, SVal V) const; + + ProgramStateRef bindDefault(SVal loc, SVal V) const; + + ProgramStateRef unbindLoc(Loc LV) const; + + /// invalidateRegions - Returns the state with bindings for the given regions + /// cleared from the store. The regions are provided as a continuous array + /// from Begin to End. Optionally invalidates global regions as well. + ProgramStateRef invalidateRegions(ArrayRef<const MemRegion *> Regions, + const Expr *E, unsigned BlockCount, + const LocationContext *LCtx, + StoreManager::InvalidatedSymbols *IS = 0, + const CallOrObjCMessage *Call = 0) const; + + /// enterStackFrame - Returns the state for entry to the given stack frame, + /// preserving the current state. + ProgramStateRef enterStackFrame(const LocationContext *callerCtx, + const StackFrameContext *calleeCtx) const; + + /// Get the lvalue for a variable reference. + Loc getLValue(const VarDecl *D, const LocationContext *LC) const; + + Loc getLValue(const CompoundLiteralExpr *literal, + const LocationContext *LC) const; + + /// Get the lvalue for an ivar reference. + SVal getLValue(const ObjCIvarDecl *decl, SVal base) const; + + /// Get the lvalue for a field reference. + SVal getLValue(const FieldDecl *decl, SVal Base) const; + + /// Get the lvalue for an array index. + SVal getLValue(QualType ElementType, SVal Idx, SVal Base) const; + + const llvm::APSInt *getSymVal(SymbolRef sym) const; + + /// Returns the SVal bound to the statement 'S' in the state's environment. + SVal getSVal(const Stmt *S, const LocationContext *LCtx, + bool useOnlyDirectBindings = false) const; + + SVal getSValAsScalarOrLoc(const Stmt *Ex, const LocationContext *LCtx) const; + + /// \brief Return the value bound to the specified location. + /// Returns UnknownVal() if none found. + SVal getSVal(Loc LV, QualType T = QualType()) const; + + /// Returns the "raw" SVal bound to LV before any value simplfication. + SVal getRawSVal(Loc LV, QualType T= QualType()) const; + + /// \brief Return the value bound to the specified location. + /// Returns UnknownVal() if none found. + SVal getSVal(const MemRegion* R) const; + + SVal getSValAsScalarOrLoc(const MemRegion *R) const; + + /// \brief Visits the symbols reachable from the given SVal using the provided + /// SymbolVisitor. + /// + /// This is a convenience API. Consider using ScanReachableSymbols class + /// directly when making multiple scans on the same state with the same + /// visitor to avoid repeated initialization cost. + /// \sa ScanReachableSymbols + bool scanReachableSymbols(SVal val, SymbolVisitor& visitor) const; + + /// \brief Visits the symbols reachable from the SVals in the given range + /// using the provided SymbolVisitor. + bool scanReachableSymbols(const SVal *I, const SVal *E, + SymbolVisitor &visitor) const; + + /// \brief Visits the symbols reachable from the regions in the given + /// MemRegions range using the provided SymbolVisitor. + bool scanReachableSymbols(const MemRegion * const *I, + const MemRegion * const *E, + SymbolVisitor &visitor) const; + + template <typename CB> CB scanReachableSymbols(SVal val) const; + template <typename CB> CB scanReachableSymbols(const SVal *beg, + const SVal *end) const; + + template <typename CB> CB + scanReachableSymbols(const MemRegion * const *beg, + const MemRegion * const *end) const; + + /// Create a new state in which the statement is marked as tainted. + ProgramStateRef addTaint(const Stmt *S, const LocationContext *LCtx, + TaintTagType Kind = TaintTagGeneric) const; + + /// Create a new state in which the symbol is marked as tainted. + ProgramStateRef addTaint(SymbolRef S, + TaintTagType Kind = TaintTagGeneric) const; + + /// Create a new state in which the region symbol is marked as tainted. + ProgramStateRef addTaint(const MemRegion *R, + TaintTagType Kind = TaintTagGeneric) const; + + /// Check if the statement is tainted in the current state. + bool isTainted(const Stmt *S, const LocationContext *LCtx, + TaintTagType Kind = TaintTagGeneric) const; + bool isTainted(SVal V, TaintTagType Kind = TaintTagGeneric) const; + bool isTainted(SymbolRef Sym, TaintTagType Kind = TaintTagGeneric) const; + bool isTainted(const MemRegion *Reg, TaintTagType Kind=TaintTagGeneric) const; + + //==---------------------------------------------------------------------==// + // Accessing the Generic Data Map (GDM). + //==---------------------------------------------------------------------==// + + void *const* FindGDM(void *K) const; + + template<typename T> + ProgramStateRef add(typename ProgramStateTrait<T>::key_type K) const; + + template <typename T> + typename ProgramStateTrait<T>::data_type + get() const { + return ProgramStateTrait<T>::MakeData(FindGDM(ProgramStateTrait<T>::GDMIndex())); + } + + template<typename T> + typename ProgramStateTrait<T>::lookup_type + get(typename ProgramStateTrait<T>::key_type key) const { + void *const* d = FindGDM(ProgramStateTrait<T>::GDMIndex()); + return ProgramStateTrait<T>::Lookup(ProgramStateTrait<T>::MakeData(d), key); + } + + template <typename T> + typename ProgramStateTrait<T>::context_type get_context() const; + + + template<typename T> + ProgramStateRef remove(typename ProgramStateTrait<T>::key_type K) const; + + template<typename T> + ProgramStateRef remove(typename ProgramStateTrait<T>::key_type K, + typename ProgramStateTrait<T>::context_type C) const; + template <typename T> + ProgramStateRef remove() const; + + template<typename T> + ProgramStateRef set(typename ProgramStateTrait<T>::data_type D) const; + + template<typename T> + ProgramStateRef set(typename ProgramStateTrait<T>::key_type K, + typename ProgramStateTrait<T>::value_type E) const; + + template<typename T> + ProgramStateRef set(typename ProgramStateTrait<T>::key_type K, + typename ProgramStateTrait<T>::value_type E, + typename ProgramStateTrait<T>::context_type C) const; + + template<typename T> + bool contains(typename ProgramStateTrait<T>::key_type key) const { + void *const* d = FindGDM(ProgramStateTrait<T>::GDMIndex()); + return ProgramStateTrait<T>::Contains(ProgramStateTrait<T>::MakeData(d), key); + } + + // Pretty-printing. + void print(raw_ostream &Out, const char *nl = "\n", + const char *sep = "") const; + void printDOT(raw_ostream &Out) const; + void printTaint(raw_ostream &Out, const char *nl = "\n", + const char *sep = "") const; + + void dump() const; + void dumpTaint() const; + +private: + friend void ProgramStateRetain(const ProgramState *state); + friend void ProgramStateRelease(const ProgramState *state); + + ProgramStateRef + invalidateRegionsImpl(ArrayRef<const MemRegion *> Regions, + const Expr *E, unsigned BlockCount, + const LocationContext *LCtx, + StoreManager::InvalidatedSymbols &IS, + const CallOrObjCMessage *Call) const; +}; + +//===----------------------------------------------------------------------===// +// ProgramStateManager - Factory object for ProgramStates. +//===----------------------------------------------------------------------===// + +class ProgramStateManager { + friend class ProgramState; + friend void ProgramStateRelease(const ProgramState *state); +private: + /// Eng - The SubEngine that owns this state manager. + SubEngine *Eng; /* Can be null. */ + + EnvironmentManager EnvMgr; + OwningPtr<StoreManager> StoreMgr; + OwningPtr<ConstraintManager> ConstraintMgr; + + ProgramState::GenericDataMap::Factory GDMFactory; + + typedef llvm::DenseMap<void*,std::pair<void*,void (*)(void*)> > GDMContextsTy; + GDMContextsTy GDMContexts; + + /// StateSet - FoldingSet containing all the states created for analyzing + /// a particular function. This is used to unique states. + llvm::FoldingSet<ProgramState> StateSet; + + /// Object that manages the data for all created SVals. + OwningPtr<SValBuilder> svalBuilder; + + /// A BumpPtrAllocator to allocate states. + llvm::BumpPtrAllocator &Alloc; + + /// A vector of ProgramStates that we can reuse. + std::vector<ProgramState *> freeStates; + +public: + ProgramStateManager(ASTContext &Ctx, + StoreManagerCreator CreateStoreManager, + ConstraintManagerCreator CreateConstraintManager, + llvm::BumpPtrAllocator& alloc, + SubEngine &subeng) + : Eng(&subeng), + EnvMgr(alloc), + GDMFactory(alloc), + svalBuilder(createSimpleSValBuilder(alloc, Ctx, *this)), + Alloc(alloc) { + StoreMgr.reset((*CreateStoreManager)(*this)); + ConstraintMgr.reset((*CreateConstraintManager)(*this, subeng)); + } + + ProgramStateManager(ASTContext &Ctx, + StoreManagerCreator CreateStoreManager, + ConstraintManager* ConstraintManagerPtr, + llvm::BumpPtrAllocator& alloc) + : Eng(0), + EnvMgr(alloc), + GDMFactory(alloc), + svalBuilder(createSimpleSValBuilder(alloc, Ctx, *this)), + Alloc(alloc) { + StoreMgr.reset((*CreateStoreManager)(*this)); + ConstraintMgr.reset(ConstraintManagerPtr); + } + + ~ProgramStateManager(); + + ProgramStateRef getInitialState(const LocationContext *InitLoc); + + ASTContext &getContext() { return svalBuilder->getContext(); } + const ASTContext &getContext() const { return svalBuilder->getContext(); } + + BasicValueFactory &getBasicVals() { + return svalBuilder->getBasicValueFactory(); + } + const BasicValueFactory& getBasicVals() const { + return svalBuilder->getBasicValueFactory(); + } + + SValBuilder &getSValBuilder() { + return *svalBuilder; + } + + SymbolManager &getSymbolManager() { + return svalBuilder->getSymbolManager(); + } + const SymbolManager &getSymbolManager() const { + return svalBuilder->getSymbolManager(); + } + + llvm::BumpPtrAllocator& getAllocator() { return Alloc; } + + MemRegionManager& getRegionManager() { + return svalBuilder->getRegionManager(); + } + const MemRegionManager& getRegionManager() const { + return svalBuilder->getRegionManager(); + } + + StoreManager& getStoreManager() { return *StoreMgr; } + ConstraintManager& getConstraintManager() { return *ConstraintMgr; } + SubEngine* getOwningEngine() { return Eng; } + + ProgramStateRef removeDeadBindings(ProgramStateRef St, + const StackFrameContext *LCtx, + SymbolReaper& SymReaper); + + /// Marshal a new state for the callee in another translation unit. + /// 'state' is owned by the caller's engine. + ProgramStateRef MarshalState(ProgramStateRef state, const StackFrameContext *L); + +public: + + SVal ArrayToPointer(Loc Array) { + return StoreMgr->ArrayToPointer(Array); + } + + // Methods that manipulate the GDM. + ProgramStateRef addGDM(ProgramStateRef St, void *Key, void *Data); + ProgramStateRef removeGDM(ProgramStateRef state, void *Key); + + // Methods that query & manipulate the Store. + + void iterBindings(ProgramStateRef state, StoreManager::BindingsHandler& F) { + StoreMgr->iterBindings(state->getStore(), F); + } + + ProgramStateRef getPersistentState(ProgramState &Impl); + ProgramStateRef getPersistentStateWithGDM(ProgramStateRef FromState, + ProgramStateRef GDMState); + + bool haveEqualEnvironments(ProgramStateRef S1, ProgramStateRef S2) { + return S1->Env == S2->Env; + } + + bool haveEqualStores(ProgramStateRef S1, ProgramStateRef S2) { + return S1->store == S2->store; + } + + //==---------------------------------------------------------------------==// + // Generic Data Map methods. + //==---------------------------------------------------------------------==// + // + // ProgramStateManager and ProgramState support a "generic data map" that allows + // different clients of ProgramState objects to embed arbitrary data within a + // ProgramState object. The generic data map is essentially an immutable map + // from a "tag" (that acts as the "key" for a client) and opaque values. + // Tags/keys and values are simply void* values. The typical way that clients + // generate unique tags are by taking the address of a static variable. + // Clients are responsible for ensuring that data values referred to by a + // the data pointer are immutable (and thus are essentially purely functional + // data). + // + // The templated methods below use the ProgramStateTrait<T> class + // to resolve keys into the GDM and to return data values to clients. + // + + // Trait based GDM dispatch. + template <typename T> + ProgramStateRef set(ProgramStateRef st, typename ProgramStateTrait<T>::data_type D) { + return addGDM(st, ProgramStateTrait<T>::GDMIndex(), + ProgramStateTrait<T>::MakeVoidPtr(D)); + } + + template<typename T> + ProgramStateRef set(ProgramStateRef st, + typename ProgramStateTrait<T>::key_type K, + typename ProgramStateTrait<T>::value_type V, + typename ProgramStateTrait<T>::context_type C) { + + return addGDM(st, ProgramStateTrait<T>::GDMIndex(), + ProgramStateTrait<T>::MakeVoidPtr(ProgramStateTrait<T>::Set(st->get<T>(), K, V, C))); + } + + template <typename T> + ProgramStateRef add(ProgramStateRef st, + typename ProgramStateTrait<T>::key_type K, + typename ProgramStateTrait<T>::context_type C) { + return addGDM(st, ProgramStateTrait<T>::GDMIndex(), + ProgramStateTrait<T>::MakeVoidPtr(ProgramStateTrait<T>::Add(st->get<T>(), K, C))); + } + + template <typename T> + ProgramStateRef remove(ProgramStateRef st, + typename ProgramStateTrait<T>::key_type K, + typename ProgramStateTrait<T>::context_type C) { + + return addGDM(st, ProgramStateTrait<T>::GDMIndex(), + ProgramStateTrait<T>::MakeVoidPtr(ProgramStateTrait<T>::Remove(st->get<T>(), K, C))); + } + + template <typename T> + ProgramStateRef remove(ProgramStateRef st) { + return removeGDM(st, ProgramStateTrait<T>::GDMIndex()); + } + + void *FindGDMContext(void *index, + void *(*CreateContext)(llvm::BumpPtrAllocator&), + void (*DeleteContext)(void*)); + + template <typename T> + typename ProgramStateTrait<T>::context_type get_context() { + void *p = FindGDMContext(ProgramStateTrait<T>::GDMIndex(), + ProgramStateTrait<T>::CreateContext, + ProgramStateTrait<T>::DeleteContext); + + return ProgramStateTrait<T>::MakeContext(p); + } + + const llvm::APSInt* getSymVal(ProgramStateRef St, SymbolRef sym) { + return ConstraintMgr->getSymVal(St, sym); + } + + void EndPath(ProgramStateRef St) { + ConstraintMgr->EndPath(St); + } +}; + + +//===----------------------------------------------------------------------===// +// Out-of-line method definitions for ProgramState. +//===----------------------------------------------------------------------===// + +inline const VarRegion* ProgramState::getRegion(const VarDecl *D, + const LocationContext *LC) const +{ + return getStateManager().getRegionManager().getVarRegion(D, LC); +} + +inline ProgramStateRef ProgramState::assume(DefinedOrUnknownSVal Cond, + bool Assumption) const { + if (Cond.isUnknown()) + return this; + + return getStateManager().ConstraintMgr->assume(this, cast<DefinedSVal>(Cond), + Assumption); +} + +inline std::pair<ProgramStateRef , ProgramStateRef > +ProgramState::assume(DefinedOrUnknownSVal Cond) const { + if (Cond.isUnknown()) + return std::make_pair(this, this); + + return getStateManager().ConstraintMgr->assumeDual(this, + cast<DefinedSVal>(Cond)); +} + +inline ProgramStateRef ProgramState::bindLoc(SVal LV, SVal V) const { + return !isa<Loc>(LV) ? this : bindLoc(cast<Loc>(LV), V); +} + +inline Loc ProgramState::getLValue(const VarDecl *VD, + const LocationContext *LC) const { + return getStateManager().StoreMgr->getLValueVar(VD, LC); +} + +inline Loc ProgramState::getLValue(const CompoundLiteralExpr *literal, + const LocationContext *LC) const { + return getStateManager().StoreMgr->getLValueCompoundLiteral(literal, LC); +} + +inline SVal ProgramState::getLValue(const ObjCIvarDecl *D, SVal Base) const { + return getStateManager().StoreMgr->getLValueIvar(D, Base); +} + +inline SVal ProgramState::getLValue(const FieldDecl *D, SVal Base) const { + return getStateManager().StoreMgr->getLValueField(D, Base); +} + +inline SVal ProgramState::getLValue(QualType ElementType, SVal Idx, SVal Base) const{ + if (NonLoc *N = dyn_cast<NonLoc>(&Idx)) + return getStateManager().StoreMgr->getLValueElement(ElementType, *N, Base); + return UnknownVal(); +} + +inline const llvm::APSInt *ProgramState::getSymVal(SymbolRef sym) const { + return getStateManager().getSymVal(this, sym); +} + +inline SVal ProgramState::getSVal(const Stmt *Ex, const LocationContext *LCtx, + bool useOnlyDirectBindings) const{ + return Env.getSVal(EnvironmentEntry(Ex, LCtx), + *getStateManager().svalBuilder, + useOnlyDirectBindings); +} + +inline SVal +ProgramState::getSValAsScalarOrLoc(const Stmt *S, + const LocationContext *LCtx) const { + if (const Expr *Ex = dyn_cast<Expr>(S)) { + QualType T = Ex->getType(); + if (Ex->isLValue() || Loc::isLocType(T) || T->isIntegerType()) + return getSVal(S, LCtx); + } + + return UnknownVal(); +} + +inline SVal ProgramState::getRawSVal(Loc LV, QualType T) const { + return getStateManager().StoreMgr->getBinding(getStore(), LV, T); +} + +inline SVal ProgramState::getSVal(const MemRegion* R) const { + return getStateManager().StoreMgr->getBinding(getStore(), + loc::MemRegionVal(R)); +} + +inline BasicValueFactory &ProgramState::getBasicVals() const { + return getStateManager().getBasicVals(); +} + +inline SymbolManager &ProgramState::getSymbolManager() const { + return getStateManager().getSymbolManager(); +} + +template<typename T> +ProgramStateRef ProgramState::add(typename ProgramStateTrait<T>::key_type K) const { + return getStateManager().add<T>(this, K, get_context<T>()); +} + +template <typename T> +typename ProgramStateTrait<T>::context_type ProgramState::get_context() const { + return getStateManager().get_context<T>(); +} + +template<typename T> +ProgramStateRef ProgramState::remove(typename ProgramStateTrait<T>::key_type K) const { + return getStateManager().remove<T>(this, K, get_context<T>()); +} + +template<typename T> +ProgramStateRef ProgramState::remove(typename ProgramStateTrait<T>::key_type K, + typename ProgramStateTrait<T>::context_type C) const { + return getStateManager().remove<T>(this, K, C); +} + +template <typename T> +ProgramStateRef ProgramState::remove() const { + return getStateManager().remove<T>(this); +} + +template<typename T> +ProgramStateRef ProgramState::set(typename ProgramStateTrait<T>::data_type D) const { + return getStateManager().set<T>(this, D); +} + +template<typename T> +ProgramStateRef ProgramState::set(typename ProgramStateTrait<T>::key_type K, + typename ProgramStateTrait<T>::value_type E) const { + return getStateManager().set<T>(this, K, E, get_context<T>()); +} + +template<typename T> +ProgramStateRef ProgramState::set(typename ProgramStateTrait<T>::key_type K, + typename ProgramStateTrait<T>::value_type E, + typename ProgramStateTrait<T>::context_type C) const { + return getStateManager().set<T>(this, K, E, C); +} + +template <typename CB> +CB ProgramState::scanReachableSymbols(SVal val) const { + CB cb(this); + scanReachableSymbols(val, cb); + return cb; +} + +template <typename CB> +CB ProgramState::scanReachableSymbols(const SVal *beg, const SVal *end) const { + CB cb(this); + scanReachableSymbols(beg, end, cb); + return cb; +} + +template <typename CB> +CB ProgramState::scanReachableSymbols(const MemRegion * const *beg, + const MemRegion * const *end) const { + CB cb(this); + scanReachableSymbols(beg, end, cb); + return cb; +} + +/// \class ScanReachableSymbols +/// A Utility class that allows to visit the reachable symbols using a custom +/// SymbolVisitor. +class ScanReachableSymbols : public SubRegionMap::Visitor { + virtual void anchor(); + typedef llvm::DenseMap<const void*, unsigned> VisitedItems; + + VisitedItems visited; + ProgramStateRef state; + SymbolVisitor &visitor; + OwningPtr<SubRegionMap> SRM; +public: + + ScanReachableSymbols(ProgramStateRef st, SymbolVisitor& v) + : state(st), visitor(v) {} + + bool scan(nonloc::CompoundVal val); + bool scan(SVal val); + bool scan(const MemRegion *R); + bool scan(const SymExpr *sym); + + // From SubRegionMap::Visitor. + bool Visit(const MemRegion* Parent, const MemRegion* SubRegion) { + return scan(SubRegion); + } +}; + +} // end GR namespace + +} // end clang namespace + +#endif diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h new file mode 100644 index 0000000..1c7bedb --- /dev/null +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h @@ -0,0 +1,197 @@ +//ProgramStateTrait.h - Partial implementations of ProgramStateTrait -*- C++ -*- +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines partial implementations of template specializations of +// the class ProgramStateTrait<>. ProgramStateTrait<> is used by ProgramState +// to implement set/get methods for manipulating a ProgramState's +// generic data map. +// +//===----------------------------------------------------------------------===// + + +#ifndef LLVM_CLANG_GR_PROGRAMSTATETRAIT_H +#define LLVM_CLANG_GR_PROGRAMSTATETRAIT_H + +namespace llvm { + class BumpPtrAllocator; + template <typename K, typename D, typename I> class ImmutableMap; + template <typename K, typename I> class ImmutableSet; + template <typename T> class ImmutableList; + template <typename T> class ImmutableListImpl; +} + +namespace clang { + +namespace ento { + template <typename T> struct ProgramStatePartialTrait; + + // Partial-specialization for ImmutableMap. + + template <typename Key, typename Data, typename Info> + struct ProgramStatePartialTrait< llvm::ImmutableMap<Key,Data,Info> > { + typedef llvm::ImmutableMap<Key,Data,Info> data_type; + typedef typename data_type::Factory& context_type; + typedef Key key_type; + typedef Data value_type; + typedef const value_type* lookup_type; + + static inline data_type MakeData(void *const* p) { + return p ? data_type((typename data_type::TreeTy*) *p) : data_type(0); + } + static inline void *MakeVoidPtr(data_type B) { + return B.getRoot(); + } + static lookup_type Lookup(data_type B, key_type K) { + return B.lookup(K); + } + static data_type Set(data_type B, key_type K, value_type E,context_type F){ + return F.add(B, K, E); + } + + static data_type Remove(data_type B, key_type K, context_type F) { + return F.remove(B, K); + } + + static inline context_type MakeContext(void *p) { + return *((typename data_type::Factory*) p); + } + + static void *CreateContext(llvm::BumpPtrAllocator& Alloc) { + return new typename data_type::Factory(Alloc); + } + + static void DeleteContext(void *Ctx) { + delete (typename data_type::Factory*) Ctx; + } + }; + + + // Partial-specialization for ImmutableSet. + + template <typename Key, typename Info> + struct ProgramStatePartialTrait< llvm::ImmutableSet<Key,Info> > { + typedef llvm::ImmutableSet<Key,Info> data_type; + typedef typename data_type::Factory& context_type; + typedef Key key_type; + + static inline data_type MakeData(void *const* p) { + return p ? data_type((typename data_type::TreeTy*) *p) : data_type(0); + } + + static inline void *MakeVoidPtr(data_type B) { + return B.getRoot(); + } + + static data_type Add(data_type B, key_type K, context_type F) { + return F.add(B, K); + } + + static data_type Remove(data_type B, key_type K, context_type F) { + return F.remove(B, K); + } + + static bool Contains(data_type B, key_type K) { + return B.contains(K); + } + + static inline context_type MakeContext(void *p) { + return *((typename data_type::Factory*) p); + } + + static void *CreateContext(llvm::BumpPtrAllocator& Alloc) { + return new typename data_type::Factory(Alloc); + } + + static void DeleteContext(void *Ctx) { + delete (typename data_type::Factory*) Ctx; + } + }; + + // Partial-specialization for ImmutableList. + + template <typename T> + struct ProgramStatePartialTrait< llvm::ImmutableList<T> > { + typedef llvm::ImmutableList<T> data_type; + typedef T key_type; + typedef typename data_type::Factory& context_type; + + static data_type Add(data_type L, key_type K, context_type F) { + return F.add(K, L); + } + + static bool Contains(data_type L, key_type K) { + return L.contains(K); + } + + static inline data_type MakeData(void *const* p) { + return p ? data_type((const llvm::ImmutableListImpl<T>*) *p) + : data_type(0); + } + + static inline void *MakeVoidPtr(data_type D) { + return (void*) D.getInternalPointer(); + } + + static inline context_type MakeContext(void *p) { + return *((typename data_type::Factory*) p); + } + + static void *CreateContext(llvm::BumpPtrAllocator& Alloc) { + return new typename data_type::Factory(Alloc); + } + + static void DeleteContext(void *Ctx) { + delete (typename data_type::Factory*) Ctx; + } + }; + + // Partial specialization for bool. + template <> struct ProgramStatePartialTrait<bool> { + typedef bool data_type; + + static inline data_type MakeData(void *const* p) { + return p ? (data_type) (uintptr_t) *p + : data_type(); + } + static inline void *MakeVoidPtr(data_type d) { + return (void*) (uintptr_t) d; + } + }; + + // Partial specialization for unsigned. + template <> struct ProgramStatePartialTrait<unsigned> { + typedef unsigned data_type; + + static inline data_type MakeData(void *const* p) { + return p ? (data_type) (uintptr_t) *p + : data_type(); + } + static inline void *MakeVoidPtr(data_type d) { + return (void*) (uintptr_t) d; + } + }; + + // Partial specialization for void*. + template <> struct ProgramStatePartialTrait<void*> { + typedef void *data_type; + + static inline data_type MakeData(void *const* p) { + return p ? *p + : data_type(); + } + static inline void *MakeVoidPtr(data_type d) { + return d; + } + }; + +} // end GR namespace + +} // end clang namespace + +#endif diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h new file mode 100644 index 0000000..371f3c5 --- /dev/null +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h @@ -0,0 +1,43 @@ +//== ProgramState_Fwd.h - Incomplete declarations of ProgramState -*- C++ -*--=/ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_PROGRAMSTATE_FWD_H +#define LLVM_CLANG_PROGRAMSTATE_FWD_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" + +namespace clang { +namespace ento { + class ProgramState; + class ProgramStateManager; + void ProgramStateRetain(const ProgramState *state); + void ProgramStateRelease(const ProgramState *state); +} +} + +namespace llvm { + template <> struct IntrusiveRefCntPtrInfo<const clang::ento::ProgramState> { + static void retain(const clang::ento::ProgramState *state) { + clang::ento::ProgramStateRetain(state); + } + static void release(const clang::ento::ProgramState *state) { + clang::ento::ProgramStateRelease(state); + } + }; +} + +namespace clang { +namespace ento { + typedef IntrusiveRefCntPtr<const ProgramState> ProgramStateRef; +} +} + +#endif + diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h new file mode 100644 index 0000000..4ad36f9 --- /dev/null +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h @@ -0,0 +1,320 @@ +// SValBuilder.h - Construction of SVals from evaluating expressions -*- C++ -*- +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines SValBuilder, a class that defines the interface for +// "symbolical evaluators" which construct an SVal from an expression. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_GR_SVALBUILDER +#define LLVM_CLANG_GR_SVALBUILDER + +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprObjC.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" + +namespace clang { + +class CXXBoolLiteralExpr; + +namespace ento { + +class SValBuilder { + virtual void anchor(); +protected: + ASTContext &Context; + + /// Manager of APSInt values. + BasicValueFactory BasicVals; + + /// Manages the creation of symbols. + SymbolManager SymMgr; + + /// Manages the creation of memory regions. + MemRegionManager MemMgr; + + ProgramStateManager &StateMgr; + + /// The scalar type to use for array indices. + const QualType ArrayIndexTy; + + /// The width of the scalar type used for array indices. + const unsigned ArrayIndexWidth; + + virtual SVal evalCastFromNonLoc(NonLoc val, QualType castTy) = 0; + virtual SVal evalCastFromLoc(Loc val, QualType castTy) = 0; + +public: + // FIXME: Make these protected again once RegionStoreManager correctly + // handles loads from different bound value types. + virtual SVal dispatchCast(SVal val, QualType castTy) = 0; + +public: + SValBuilder(llvm::BumpPtrAllocator &alloc, ASTContext &context, + ProgramStateManager &stateMgr) + : Context(context), BasicVals(context, alloc), + SymMgr(context, BasicVals, alloc), + MemMgr(context, alloc), + StateMgr(stateMgr), + ArrayIndexTy(context.IntTy), + ArrayIndexWidth(context.getTypeSize(ArrayIndexTy)) {} + + virtual ~SValBuilder() {} + + bool haveSameType(const SymExpr *Sym1, const SymExpr *Sym2) { + return haveSameType(Sym1->getType(Context), Sym2->getType(Context)); + } + + bool haveSameType(QualType Ty1, QualType Ty2) { + // FIXME: Remove the second disjunct when we support symbolic + // truncation/extension. + return (Context.getCanonicalType(Ty1) == Context.getCanonicalType(Ty2) || + (Ty2->isIntegerType() && Ty2->isIntegerType())); + } + + SVal evalCast(SVal val, QualType castTy, QualType originalType); + + virtual SVal evalMinus(NonLoc val) = 0; + + virtual SVal evalComplement(NonLoc val) = 0; + + /// Create a new value which represents a binary expression with two non + /// location operands. + virtual SVal evalBinOpNN(ProgramStateRef state, BinaryOperator::Opcode op, + NonLoc lhs, NonLoc rhs, QualType resultTy) = 0; + + /// Create a new value which represents a binary expression with two memory + /// location operands. + virtual SVal evalBinOpLL(ProgramStateRef state, BinaryOperator::Opcode op, + Loc lhs, Loc rhs, QualType resultTy) = 0; + + /// Create a new value which represents a binary expression with a memory + /// location and non location operands. For example, this would be used to + /// evaluate a pointer arithmetic operation. + virtual SVal evalBinOpLN(ProgramStateRef state, BinaryOperator::Opcode op, + Loc lhs, NonLoc rhs, QualType resultTy) = 0; + + /// Evaluates a given SVal. If the SVal has only one possible (integer) value, + /// that value is returned. Otherwise, returns NULL. + virtual const llvm::APSInt *getKnownValue(ProgramStateRef state, SVal val) = 0; + + /// Handles generation of the value in case the builder is not smart enough to + /// handle the given binary expression. Depending on the state, decides to + /// either keep the expression or forget the history and generate an + /// UnknownVal. + SVal makeGenericVal(ProgramStateRef state, BinaryOperator::Opcode op, + NonLoc lhs, NonLoc rhs, QualType resultTy); + + SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op, + SVal lhs, SVal rhs, QualType type); + + DefinedOrUnknownSVal evalEQ(ProgramStateRef state, DefinedOrUnknownSVal lhs, + DefinedOrUnknownSVal rhs); + + ASTContext &getContext() { return Context; } + const ASTContext &getContext() const { return Context; } + + ProgramStateManager &getStateManager() { return StateMgr; } + + QualType getConditionType() const { + return getContext().IntTy; + } + + QualType getArrayIndexType() const { + return ArrayIndexTy; + } + + BasicValueFactory &getBasicValueFactory() { return BasicVals; } + const BasicValueFactory &getBasicValueFactory() const { return BasicVals; } + + SymbolManager &getSymbolManager() { return SymMgr; } + const SymbolManager &getSymbolManager() const { return SymMgr; } + + MemRegionManager &getRegionManager() { return MemMgr; } + const MemRegionManager &getRegionManager() const { return MemMgr; } + + // Forwarding methods to SymbolManager. + + const SymbolConjured* getConjuredSymbol(const Stmt *stmt, + const LocationContext *LCtx, + QualType type, + unsigned visitCount, + const void *symbolTag = 0) { + return SymMgr.getConjuredSymbol(stmt, LCtx, type, visitCount, symbolTag); + } + + const SymbolConjured* getConjuredSymbol(const Expr *expr, + const LocationContext *LCtx, + unsigned visitCount, + const void *symbolTag = 0) { + return SymMgr.getConjuredSymbol(expr, LCtx, visitCount, symbolTag); + } + + /// Construct an SVal representing '0' for the specified type. + DefinedOrUnknownSVal makeZeroVal(QualType type); + + /// Make a unique symbol for value of region. + DefinedOrUnknownSVal getRegionValueSymbolVal(const TypedValueRegion *region); + + /// \brief Create a new symbol with a unique 'name'. + /// + /// We resort to conjured symbols when we cannot construct a derived symbol. + /// The advantage of symbols derived/built from other symbols is that we + /// preserve the relation between related(or even equivalent) expressions, so + /// conjured symbols should be used sparingly. + DefinedOrUnknownSVal getConjuredSymbolVal(const void *symbolTag, + const Expr *expr, + const LocationContext *LCtx, + unsigned count); + DefinedOrUnknownSVal getConjuredSymbolVal(const void *symbolTag, + const Expr *expr, + const LocationContext *LCtx, + QualType type, + unsigned count); + + DefinedOrUnknownSVal getConjuredSymbolVal(const Stmt *stmt, + const LocationContext *LCtx, + QualType type, + unsigned visitCount); + + DefinedOrUnknownSVal getDerivedRegionValueSymbolVal( + SymbolRef parentSymbol, const TypedValueRegion *region); + + DefinedSVal getMetadataSymbolVal( + const void *symbolTag, const MemRegion *region, + const Expr *expr, QualType type, unsigned count); + + DefinedSVal getFunctionPointer(const FunctionDecl *func); + + DefinedSVal getBlockPointer(const BlockDecl *block, CanQualType locTy, + const LocationContext *locContext); + + NonLoc makeCompoundVal(QualType type, llvm::ImmutableList<SVal> vals) { + return nonloc::CompoundVal(BasicVals.getCompoundValData(type, vals)); + } + + NonLoc makeLazyCompoundVal(const StoreRef &store, + const TypedValueRegion *region) { + return nonloc::LazyCompoundVal( + BasicVals.getLazyCompoundValData(store, region)); + } + + NonLoc makeZeroArrayIndex() { + return nonloc::ConcreteInt(BasicVals.getValue(0, ArrayIndexTy)); + } + + NonLoc makeArrayIndex(uint64_t idx) { + return nonloc::ConcreteInt(BasicVals.getValue(idx, ArrayIndexTy)); + } + + SVal convertToArrayIndex(SVal val); + + nonloc::ConcreteInt makeIntVal(const IntegerLiteral* integer) { + return nonloc::ConcreteInt( + BasicVals.getValue(integer->getValue(), + integer->getType()->isUnsignedIntegerOrEnumerationType())); + } + + nonloc::ConcreteInt makeBoolVal(const ObjCBoolLiteralExpr *boolean) { + return makeTruthVal(boolean->getValue(), boolean->getType()); + } + + nonloc::ConcreteInt makeBoolVal(const CXXBoolLiteralExpr *boolean); + + nonloc::ConcreteInt makeIntVal(const llvm::APSInt& integer) { + return nonloc::ConcreteInt(BasicVals.getValue(integer)); + } + + loc::ConcreteInt makeIntLocVal(const llvm::APSInt &integer) { + return loc::ConcreteInt(BasicVals.getValue(integer)); + } + + NonLoc makeIntVal(const llvm::APInt& integer, bool isUnsigned) { + return nonloc::ConcreteInt(BasicVals.getValue(integer, isUnsigned)); + } + + DefinedSVal makeIntVal(uint64_t integer, QualType type) { + if (Loc::isLocType(type)) + return loc::ConcreteInt(BasicVals.getValue(integer, type)); + + return nonloc::ConcreteInt(BasicVals.getValue(integer, type)); + } + + NonLoc makeIntVal(uint64_t integer, bool isUnsigned) { + return nonloc::ConcreteInt(BasicVals.getIntValue(integer, isUnsigned)); + } + + NonLoc makeIntValWithPtrWidth(uint64_t integer, bool isUnsigned) { + return nonloc::ConcreteInt( + BasicVals.getIntWithPtrWidth(integer, isUnsigned)); + } + + NonLoc makeIntVal(uint64_t integer, unsigned bitWidth, bool isUnsigned) { + return nonloc::ConcreteInt( + BasicVals.getValue(integer, bitWidth, isUnsigned)); + } + + NonLoc makeLocAsInteger(Loc loc, unsigned bits) { + return nonloc::LocAsInteger(BasicVals.getPersistentSValWithData(loc, bits)); + } + + NonLoc makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op, + const llvm::APSInt& rhs, QualType type); + + NonLoc makeNonLoc(const llvm::APSInt& rhs, BinaryOperator::Opcode op, + const SymExpr *lhs, QualType type); + + NonLoc makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op, + const SymExpr *rhs, QualType type); + + /// \brief Create a NonLoc value for cast. + NonLoc makeNonLoc(const SymExpr *operand, QualType fromTy, QualType toTy); + + nonloc::ConcreteInt makeTruthVal(bool b, QualType type) { + return nonloc::ConcreteInt(BasicVals.getTruthValue(b, type)); + } + + nonloc::ConcreteInt makeTruthVal(bool b) { + return nonloc::ConcreteInt(BasicVals.getTruthValue(b)); + } + + Loc makeNull() { + return loc::ConcreteInt(BasicVals.getZeroWithPtrWidth()); + } + + Loc makeLoc(SymbolRef sym) { + return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym)); + } + + Loc makeLoc(const MemRegion* region) { + return loc::MemRegionVal(region); + } + + Loc makeLoc(const AddrLabelExpr *expr) { + return loc::GotoLabel(expr->getLabel()); + } + + Loc makeLoc(const llvm::APSInt& integer) { + return loc::ConcreteInt(BasicVals.getValue(integer)); + } + +}; + +SValBuilder* createSimpleSValBuilder(llvm::BumpPtrAllocator &alloc, + ASTContext &context, + ProgramStateManager &stateMgr); + +} // end GR namespace + +} // end clang namespace + +#endif diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h new file mode 100644 index 0000000..ce3eb1d --- /dev/null +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h @@ -0,0 +1,519 @@ +//== SVals.h - Abstract Values for Static Analysis ---------*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines SVal, Loc, and NonLoc, classes that represent +// abstract r-values for use with path-sensitive value tracking. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_GR_RVALUE_H +#define LLVM_CLANG_GR_RVALUE_H + +#include "clang/Basic/LLVM.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h" +#include "llvm/ADT/ImmutableList.h" + +//==------------------------------------------------------------------------==// +// Base SVal types. +//==------------------------------------------------------------------------==// + +namespace clang { + +namespace ento { + +class CompoundValData; +class LazyCompoundValData; +class ProgramState; +class BasicValueFactory; +class MemRegion; +class TypedRegion; +class MemRegionManager; +class ProgramStateManager; +class SValBuilder; + +/// SVal - This represents a symbolic expression, which can be either +/// an L-value or an R-value. +/// +class SVal { +public: + enum BaseKind { + // The enumerators must be representable using 2 bits. + UndefinedKind = 0, // for subclass UndefinedVal (an uninitialized value) + UnknownKind = 1, // for subclass UnknownVal (a void value) + LocKind = 2, // for subclass Loc (an L-value) + NonLocKind = 3 // for subclass NonLoc (an R-value that's not + // an L-value) + }; + enum { BaseBits = 2, BaseMask = 0x3 }; + +protected: + const void *Data; + + /// The lowest 2 bits are a BaseKind (0 -- 3). + /// The higher bits are an unsigned "kind" value. + unsigned Kind; + + explicit SVal(const void *d, bool isLoc, unsigned ValKind) + : Data(d), Kind((isLoc ? LocKind : NonLocKind) | (ValKind << BaseBits)) {} + + explicit SVal(BaseKind k, const void *D = NULL) + : Data(D), Kind(k) {} + +public: + explicit SVal() : Data(0), Kind(0) {} + ~SVal() {} + + /// BufferTy - A temporary buffer to hold a set of SVals. + typedef SmallVector<SVal,5> BufferTy; + + inline unsigned getRawKind() const { return Kind; } + inline BaseKind getBaseKind() const { return (BaseKind) (Kind & BaseMask); } + inline unsigned getSubKind() const { return (Kind & ~BaseMask) >> BaseBits; } + + // This method is required for using SVal in a FoldingSetNode. It + // extracts a unique signature for this SVal object. + inline void Profile(llvm::FoldingSetNodeID& ID) const { + ID.AddInteger((unsigned) getRawKind()); + ID.AddPointer(Data); + } + + inline bool operator==(const SVal& R) const { + return getRawKind() == R.getRawKind() && Data == R.Data; + } + + inline bool operator!=(const SVal& R) const { + return !(*this == R); + } + + inline bool isUnknown() const { + return getRawKind() == UnknownKind; + } + + inline bool isUndef() const { + return getRawKind() == UndefinedKind; + } + + inline bool isUnknownOrUndef() const { + return getRawKind() <= UnknownKind; + } + + inline bool isValid() const { + return getRawKind() > UnknownKind; + } + + bool isConstant() const; + + bool isConstant(int I) const; + + bool isZeroConstant() const; + + /// hasConjuredSymbol - If this SVal wraps a conjured symbol, return true; + bool hasConjuredSymbol() const; + + /// getAsFunctionDecl - If this SVal is a MemRegionVal and wraps a + /// CodeTextRegion wrapping a FunctionDecl, return that FunctionDecl. + /// Otherwise return 0. + const FunctionDecl *getAsFunctionDecl() const; + + /// If this SVal is a location (subclasses Loc) and + /// wraps a symbol, return that SymbolRef. Otherwise return 0. + SymbolRef getAsLocSymbol() const; + + /// Get the symbol in the SVal or its base region. + SymbolRef getLocSymbolInBase() const; + + /// If this SVal wraps a symbol return that SymbolRef. + /// Otherwise, return 0. + SymbolRef getAsSymbol() const; + + /// getAsSymbolicExpression - If this Sval wraps a symbolic expression then + /// return that expression. Otherwise return NULL. + const SymExpr *getAsSymbolicExpression() const; + + const SymExpr* getAsSymExpr() const; + + const MemRegion *getAsRegion() const; + + void dumpToStream(raw_ostream &OS) const; + void dump() const; + + SymExpr::symbol_iterator symbol_begin() const { + const SymExpr *SE = getAsSymbolicExpression(); + if (SE) + return SE->symbol_begin(); + else + return SymExpr::symbol_iterator(); + } + + SymExpr::symbol_iterator symbol_end() const { + return SymExpr::symbol_end(); + } + + // Implement isa<T> support. + static inline bool classof(const SVal*) { return true; } +}; + + +class UndefinedVal : public SVal { +public: + UndefinedVal() : SVal(UndefinedKind) {} + UndefinedVal(const void *D) : SVal(UndefinedKind, D) {} + + static inline bool classof(const SVal* V) { + return V->getBaseKind() == UndefinedKind; + } + + const void *getData() const { return Data; } +}; + +class DefinedOrUnknownSVal : public SVal { +private: + // Do not implement. We want calling these methods to be a compiler + // error since they are tautologically false. + bool isUndef() const; + bool isValid() const; + +protected: + explicit DefinedOrUnknownSVal(const void *d, bool isLoc, unsigned ValKind) + : SVal(d, isLoc, ValKind) {} + + explicit DefinedOrUnknownSVal(BaseKind k, void *D = NULL) + : SVal(k, D) {} + +public: + // Implement isa<T> support. + static inline bool classof(const SVal *V) { + return !V->isUndef(); + } +}; + +class UnknownVal : public DefinedOrUnknownSVal { +public: + explicit UnknownVal() : DefinedOrUnknownSVal(UnknownKind) {} + + static inline bool classof(const SVal *V) { + return V->getBaseKind() == UnknownKind; + } +}; + +class DefinedSVal : public DefinedOrUnknownSVal { +private: + // Do not implement. We want calling these methods to be a compiler + // error since they are tautologically true/false. + bool isUnknown() const; + bool isUnknownOrUndef() const; + bool isValid() const; +protected: + explicit DefinedSVal(const void *d, bool isLoc, unsigned ValKind) + : DefinedOrUnknownSVal(d, isLoc, ValKind) {} +public: + // Implement isa<T> support. + static inline bool classof(const SVal *V) { + return !V->isUnknownOrUndef(); + } +}; + +class NonLoc : public DefinedSVal { +protected: + explicit NonLoc(unsigned SubKind, const void *d) + : DefinedSVal(d, false, SubKind) {} + +public: + void dumpToStream(raw_ostream &Out) const; + + // Implement isa<T> support. + static inline bool classof(const SVal* V) { + return V->getBaseKind() == NonLocKind; + } +}; + +class Loc : public DefinedSVal { +protected: + explicit Loc(unsigned SubKind, const void *D) + : DefinedSVal(const_cast<void*>(D), true, SubKind) {} + +public: + void dumpToStream(raw_ostream &Out) const; + + Loc(const Loc& X) : DefinedSVal(X.Data, true, X.getSubKind()) {} + + // Implement isa<T> support. + static inline bool classof(const SVal* V) { + return V->getBaseKind() == LocKind; + } + + static inline bool isLocType(QualType T) { + return T->isAnyPointerType() || T->isBlockPointerType() || + T->isReferenceType(); + } +}; + +//==------------------------------------------------------------------------==// +// Subclasses of NonLoc. +//==------------------------------------------------------------------------==// + +namespace nonloc { + +enum Kind { ConcreteIntKind, SymbolValKind, SymExprValKind, + LocAsIntegerKind, CompoundValKind, LazyCompoundValKind }; + +/// \brief Represents symbolic expression. +class SymbolVal : public NonLoc { +public: + SymbolVal(SymbolRef sym) : NonLoc(SymbolValKind, sym) {} + + SymbolRef getSymbol() const { + return (const SymExpr*) Data; + } + + bool isExpression() { + return !isa<SymbolData>(getSymbol()); + } + + static inline bool classof(const SVal* V) { + return V->getBaseKind() == NonLocKind && + V->getSubKind() == SymbolValKind; + } + + static inline bool classof(const NonLoc* V) { + return V->getSubKind() == SymbolValKind; + } +}; + +/// \brief Value representing integer constant. +class ConcreteInt : public NonLoc { +public: + explicit ConcreteInt(const llvm::APSInt& V) : NonLoc(ConcreteIntKind, &V) {} + + const llvm::APSInt& getValue() const { + return *static_cast<const llvm::APSInt*>(Data); + } + + // Transfer functions for binary/unary operations on ConcreteInts. + SVal evalBinOp(SValBuilder &svalBuilder, BinaryOperator::Opcode Op, + const ConcreteInt& R) const; + + ConcreteInt evalComplement(SValBuilder &svalBuilder) const; + + ConcreteInt evalMinus(SValBuilder &svalBuilder) const; + + // Implement isa<T> support. + static inline bool classof(const SVal* V) { + return V->getBaseKind() == NonLocKind && + V->getSubKind() == ConcreteIntKind; + } + + static inline bool classof(const NonLoc* V) { + return V->getSubKind() == ConcreteIntKind; + } +}; + +class LocAsInteger : public NonLoc { + friend class ento::SValBuilder; + + explicit LocAsInteger(const std::pair<SVal, uintptr_t>& data) : + NonLoc(LocAsIntegerKind, &data) { + assert (isa<Loc>(data.first)); + } + +public: + + Loc getLoc() const { + return cast<Loc>(((std::pair<SVal, uintptr_t>*) Data)->first); + } + + const Loc& getPersistentLoc() const { + const SVal& V = ((std::pair<SVal, uintptr_t>*) Data)->first; + return cast<Loc>(V); + } + + unsigned getNumBits() const { + return ((std::pair<SVal, unsigned>*) Data)->second; + } + + // Implement isa<T> support. + static inline bool classof(const SVal* V) { + return V->getBaseKind() == NonLocKind && + V->getSubKind() == LocAsIntegerKind; + } + + static inline bool classof(const NonLoc* V) { + return V->getSubKind() == LocAsIntegerKind; + } +}; + +class CompoundVal : public NonLoc { + friend class ento::SValBuilder; + + explicit CompoundVal(const CompoundValData* D) : NonLoc(CompoundValKind, D) {} + +public: + const CompoundValData* getValue() const { + return static_cast<const CompoundValData*>(Data); + } + + typedef llvm::ImmutableList<SVal>::iterator iterator; + iterator begin() const; + iterator end() const; + + static bool classof(const SVal* V) { + return V->getBaseKind() == NonLocKind && V->getSubKind() == CompoundValKind; + } + + static bool classof(const NonLoc* V) { + return V->getSubKind() == CompoundValKind; + } +}; + +class LazyCompoundVal : public NonLoc { + friend class ento::SValBuilder; + + explicit LazyCompoundVal(const LazyCompoundValData *D) + : NonLoc(LazyCompoundValKind, D) {} +public: + const LazyCompoundValData *getCVData() const { + return static_cast<const LazyCompoundValData*>(Data); + } + const void *getStore() const; + const TypedRegion *getRegion() const; + + static bool classof(const SVal *V) { + return V->getBaseKind() == NonLocKind && + V->getSubKind() == LazyCompoundValKind; + } + static bool classof(const NonLoc *V) { + return V->getSubKind() == LazyCompoundValKind; + } +}; + +} // end namespace ento::nonloc + +//==------------------------------------------------------------------------==// +// Subclasses of Loc. +//==------------------------------------------------------------------------==// + +namespace loc { + +enum Kind { GotoLabelKind, MemRegionKind, ConcreteIntKind, ObjCPropRefKind }; + +class GotoLabel : public Loc { +public: + explicit GotoLabel(LabelDecl *Label) : Loc(GotoLabelKind, Label) {} + + const LabelDecl *getLabel() const { + return static_cast<const LabelDecl*>(Data); + } + + static inline bool classof(const SVal* V) { + return V->getBaseKind() == LocKind && V->getSubKind() == GotoLabelKind; + } + + static inline bool classof(const Loc* V) { + return V->getSubKind() == GotoLabelKind; + } +}; + + +class MemRegionVal : public Loc { +public: + explicit MemRegionVal(const MemRegion* r) : Loc(MemRegionKind, r) {} + + /// \brief Get the underlining region. + const MemRegion* getRegion() const { + return static_cast<const MemRegion*>(Data); + } + + /// \brief Get the underlining region and strip casts. + const MemRegion* stripCasts() const; + + template <typename REGION> + const REGION* getRegionAs() const { + return llvm::dyn_cast<REGION>(getRegion()); + } + + inline bool operator==(const MemRegionVal& R) const { + return getRegion() == R.getRegion(); + } + + inline bool operator!=(const MemRegionVal& R) const { + return getRegion() != R.getRegion(); + } + + // Implement isa<T> support. + static inline bool classof(const SVal* V) { + return V->getBaseKind() == LocKind && + V->getSubKind() == MemRegionKind; + } + + static inline bool classof(const Loc* V) { + return V->getSubKind() == MemRegionKind; + } +}; + +class ConcreteInt : public Loc { +public: + explicit ConcreteInt(const llvm::APSInt& V) : Loc(ConcreteIntKind, &V) {} + + const llvm::APSInt& getValue() const { + return *static_cast<const llvm::APSInt*>(Data); + } + + // Transfer functions for binary/unary operations on ConcreteInts. + SVal evalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op, + const ConcreteInt& R) const; + + // Implement isa<T> support. + static inline bool classof(const SVal* V) { + return V->getBaseKind() == LocKind && + V->getSubKind() == ConcreteIntKind; + } + + static inline bool classof(const Loc* V) { + return V->getSubKind() == ConcreteIntKind; + } +}; + +/// \brief Pseudo-location SVal used by the ExprEngine to simulate a "load" or +/// "store" of an ObjC property for the dot syntax. +class ObjCPropRef : public Loc { +public: + explicit ObjCPropRef(const ObjCPropertyRefExpr *E) + : Loc(ObjCPropRefKind, E) {} + + const ObjCPropertyRefExpr *getPropRefExpr() const { + return static_cast<const ObjCPropertyRefExpr *>(Data); + } + + // Implement isa<T> support. + static inline bool classof(const SVal* V) { + return V->getBaseKind() == LocKind && + V->getSubKind() == ObjCPropRefKind; + } + + static inline bool classof(const Loc* V) { + return V->getSubKind() == ObjCPropRefKind; + } +}; + +} // end ento::loc namespace +} // end GR namespace + +} // end clang namespace + +namespace llvm { +static inline raw_ostream &operator<<(raw_ostream &os, + clang::ento::SVal V) { + V.dumpToStream(os); + return os; +} + +} // end llvm namespace + +#endif diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h new file mode 100644 index 0000000..5315f4b --- /dev/null +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h @@ -0,0 +1,304 @@ +//== Store.h - Interface for maps from Locations to Values ------*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defined the types Store and StoreManager. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_GR_STORE_H +#define LLVM_CLANG_GR_STORE_H + +#include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/Optional.h" + +namespace clang { + +class Stmt; +class Expr; +class ObjCIvarDecl; +class StackFrameContext; + +namespace ento { + +class CallOrObjCMessage; +class ProgramState; +class ProgramStateManager; +class SubRegionMap; + +class StoreManager { +protected: + SValBuilder &svalBuilder; + ProgramStateManager &StateMgr; + + /// MRMgr - Manages region objects associated with this StoreManager. + MemRegionManager &MRMgr; + ASTContext &Ctx; + + StoreManager(ProgramStateManager &stateMgr); + +public: + virtual ~StoreManager() {} + + /// Return the value bound to specified location in a given state. + /// \param[in] state The analysis state. + /// \param[in] loc The symbolic memory location. + /// \param[in] T An optional type that provides a hint indicating the + /// expected type of the returned value. This is used if the value is + /// lazily computed. + /// \return The value bound to the location \c loc. + virtual SVal getBinding(Store store, Loc loc, QualType T = QualType()) = 0; + + /// Return a state with the specified value bound to the given location. + /// \param[in] state The analysis state. + /// \param[in] loc The symbolic memory location. + /// \param[in] val The value to bind to location \c loc. + /// \return A pointer to a ProgramState object that contains the same bindings as + /// \c state with the addition of having the value specified by \c val bound + /// to the location given for \c loc. + virtual StoreRef Bind(Store store, Loc loc, SVal val) = 0; + + virtual StoreRef BindDefault(Store store, const MemRegion *R, SVal V); + virtual StoreRef Remove(Store St, Loc L) = 0; + + /// BindCompoundLiteral - Return the store that has the bindings currently + /// in 'store' plus the bindings for the CompoundLiteral. 'R' is the region + /// for the compound literal and 'BegInit' and 'EndInit' represent an + /// array of initializer values. + virtual StoreRef BindCompoundLiteral(Store store, + const CompoundLiteralExpr *cl, + const LocationContext *LC, SVal v) = 0; + + /// getInitialStore - Returns the initial "empty" store representing the + /// value bindings upon entry to an analyzed function. + virtual StoreRef getInitialStore(const LocationContext *InitLoc) = 0; + + /// getRegionManager - Returns the internal RegionManager object that is + /// used to query and manipulate MemRegion objects. + MemRegionManager& getRegionManager() { return MRMgr; } + + /// getSubRegionMap - Returns an opaque map object that clients can query + /// to get the subregions of a given MemRegion object. It is the + // caller's responsibility to 'delete' the returned map. + virtual SubRegionMap *getSubRegionMap(Store store) = 0; + + virtual Loc getLValueVar(const VarDecl *VD, const LocationContext *LC) { + return svalBuilder.makeLoc(MRMgr.getVarRegion(VD, LC)); + } + + Loc getLValueCompoundLiteral(const CompoundLiteralExpr *CL, + const LocationContext *LC) { + return loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, LC)); + } + + virtual SVal getLValueIvar(const ObjCIvarDecl *decl, SVal base); + + virtual SVal getLValueField(const FieldDecl *D, SVal Base) { + return getLValueFieldOrIvar(D, Base); + } + + virtual SVal getLValueElement(QualType elementType, NonLoc offset, SVal Base); + + // FIXME: This should soon be eliminated altogether; clients should deal with + // region extents directly. + virtual DefinedOrUnknownSVal getSizeInElements(ProgramStateRef state, + const MemRegion *region, + QualType EleTy) { + return UnknownVal(); + } + + /// ArrayToPointer - Used by ExprEngine::VistCast to handle implicit + /// conversions between arrays and pointers. + virtual SVal ArrayToPointer(Loc Array) = 0; + + /// Evaluates DerivedToBase casts. + virtual SVal evalDerivedToBase(SVal derived, QualType basePtrType) = 0; + + /// \brief Evaluates C++ dynamic_cast cast. + /// The callback may result in the following 3 scenarios: + /// - Successful cast (ex: derived is subclass of base). + /// - Failed cast (ex: derived is definitely not a subclass of base). + /// - We don't know (base is a symbolic region and we don't have + /// enough info to determine if the cast will succeed at run time). + /// The function returns an SVal representing the derived class; it's + /// valid only if Failed flag is set to false. + virtual SVal evalDynamicCast(SVal base, QualType derivedPtrType, + bool &Failed) = 0; + + class CastResult { + ProgramStateRef state; + const MemRegion *region; + public: + ProgramStateRef getState() const { return state; } + const MemRegion* getRegion() const { return region; } + CastResult(ProgramStateRef s, const MemRegion* r = 0) : state(s), region(r){} + }; + + const ElementRegion *GetElementZeroRegion(const MemRegion *R, QualType T); + + /// castRegion - Used by ExprEngine::VisitCast to handle casts from + /// a MemRegion* to a specific location type. 'R' is the region being + /// casted and 'CastToTy' the result type of the cast. + const MemRegion *castRegion(const MemRegion *region, QualType CastToTy); + + virtual StoreRef removeDeadBindings(Store store, const StackFrameContext *LCtx, + SymbolReaper& SymReaper) = 0; + + virtual StoreRef BindDecl(Store store, const VarRegion *VR, SVal initVal) = 0; + + virtual StoreRef BindDeclWithNoInit(Store store, const VarRegion *VR) = 0; + + virtual bool includedInBindings(Store store, + const MemRegion *region) const = 0; + + /// If the StoreManager supports it, increment the reference count of + /// the specified Store object. + virtual void incrementReferenceCount(Store store) {} + + /// If the StoreManager supports it, decrement the reference count of + /// the specified Store object. If the reference count hits 0, the memory + /// associated with the object is recycled. + virtual void decrementReferenceCount(Store store) {} + + typedef llvm::DenseSet<SymbolRef> InvalidatedSymbols; + typedef SmallVector<const MemRegion *, 8> InvalidatedRegions; + + /// invalidateRegions - Clears out the specified regions from the store, + /// marking their values as unknown. Depending on the store, this may also + /// invalidate additional regions that may have changed based on accessing + /// the given regions. Optionally, invalidates non-static globals as well. + /// \param[in] store The initial store + /// \param[in] Begin A pointer to the first region to invalidate. + /// \param[in] End A pointer just past the last region to invalidate. + /// \param[in] E The current statement being evaluated. Used to conjure + /// symbols to mark the values of invalidated regions. + /// \param[in] Count The current block count. Used to conjure + /// symbols to mark the values of invalidated regions. + /// \param[in,out] IS A set to fill with any symbols that are no longer + /// accessible. Pass \c NULL if this information will not be used. + /// \param[in] Call The call expression which will be used to determine which + /// globals should get invalidated. + /// \param[in,out] Regions A vector to fill with any regions being + /// invalidated. This should include any regions explicitly invalidated + /// even if they do not currently have bindings. Pass \c NULL if this + /// information will not be used. + virtual StoreRef invalidateRegions(Store store, + ArrayRef<const MemRegion *> Regions, + const Expr *E, unsigned Count, + const LocationContext *LCtx, + InvalidatedSymbols &IS, + const CallOrObjCMessage *Call, + InvalidatedRegions *Invalidated) = 0; + + /// enterStackFrame - Let the StoreManager to do something when execution + /// engine is about to execute into a callee. + virtual StoreRef enterStackFrame(ProgramStateRef state, + const LocationContext *callerCtx, + const StackFrameContext *calleeCtx); + + virtual void print(Store store, raw_ostream &Out, + const char* nl, const char *sep) = 0; + + class BindingsHandler { + public: + virtual ~BindingsHandler(); + virtual bool HandleBinding(StoreManager& SMgr, Store store, + const MemRegion *region, SVal val) = 0; + }; + + class FindUniqueBinding : + public BindingsHandler { + SymbolRef Sym; + const MemRegion* Binding; + bool First; + + public: + FindUniqueBinding(SymbolRef sym) : Sym(sym), Binding(0), First(true) {} + + bool HandleBinding(StoreManager& SMgr, Store store, const MemRegion* R, + SVal val); + operator bool() { return First && Binding; } + const MemRegion *getRegion() { return Binding; } + }; + + /// iterBindings - Iterate over the bindings in the Store. + virtual void iterBindings(Store store, BindingsHandler& f) = 0; + +protected: + const MemRegion *MakeElementRegion(const MemRegion *baseRegion, + QualType pointeeTy, uint64_t index = 0); + + /// CastRetrievedVal - Used by subclasses of StoreManager to implement + /// implicit casts that arise from loads from regions that are reinterpreted + /// as another region. + SVal CastRetrievedVal(SVal val, const TypedValueRegion *region, + QualType castTy, bool performTestOnly = true); + +private: + SVal getLValueFieldOrIvar(const Decl *decl, SVal base); +}; + + +inline StoreRef::StoreRef(Store store, StoreManager & smgr) + : store(store), mgr(smgr) { + if (store) + mgr.incrementReferenceCount(store); +} + +inline StoreRef::StoreRef(const StoreRef &sr) + : store(sr.store), mgr(sr.mgr) +{ + if (store) + mgr.incrementReferenceCount(store); +} + +inline StoreRef::~StoreRef() { + if (store) + mgr.decrementReferenceCount(store); +} + +inline StoreRef &StoreRef::operator=(StoreRef const &newStore) { + assert(&newStore.mgr == &mgr); + if (store != newStore.store) { + mgr.incrementReferenceCount(newStore.store); + mgr.decrementReferenceCount(store); + store = newStore.getStore(); + } + return *this; +} + +// FIXME: Do we still need this? +/// SubRegionMap - An abstract interface that represents a queryable map +/// between MemRegion objects and their subregions. +class SubRegionMap { + virtual void anchor(); +public: + virtual ~SubRegionMap() {} + + class Visitor { + virtual void anchor(); + public: + virtual ~Visitor() {} + virtual bool Visit(const MemRegion* Parent, const MemRegion* SubRegion) = 0; + }; + + virtual bool iterSubRegions(const MemRegion *region, Visitor& V) const = 0; +}; + +// FIXME: Do we need to pass ProgramStateManager anymore? +StoreManager *CreateRegionStoreManager(ProgramStateManager& StMgr); +StoreManager *CreateFieldsOnlyRegionStoreManager(ProgramStateManager& StMgr); + +} // end GR namespace + +} // end clang namespace + +#endif diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h new file mode 100644 index 0000000..d5ba003 --- /dev/null +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h @@ -0,0 +1,51 @@ +//== StoreRef.h - Smart pointer for store objects ---------------*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defined the type StoreRef. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_GR_STOREREF_H +#define LLVM_CLANG_GR_STOREREF_H + +#include <cassert> + +namespace clang { +namespace ento { + +/// Store - This opaque type encapsulates an immutable mapping from +/// locations to values. At a high-level, it represents the symbolic +/// memory model. Different subclasses of StoreManager may choose +/// different types to represent the locations and values. +typedef const void *Store; + +class StoreManager; + +class StoreRef { + Store store; + StoreManager &mgr; +public: + StoreRef(Store, StoreManager &); + StoreRef(const StoreRef &); + StoreRef &operator=(StoreRef const &); + + bool operator==(const StoreRef &x) const { + assert(&mgr == &x.mgr); + return x.store == store; + } + bool operator!=(const StoreRef &x) const { return !operator==(x); } + + ~StoreRef(); + + Store getStore() const { return store; } + const StoreManager &getStoreManager() const { return mgr; } +}; + +}} +#endif diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h new file mode 100644 index 0000000..baf57d4 --- /dev/null +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h @@ -0,0 +1,130 @@ +//== SubEngine.h - Interface of the subengine of CoreEngine --------*- C++ -*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the interface of a subengine of the CoreEngine. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_GR_SUBENGINE_H +#define LLVM_CLANG_GR_SUBENGINE_H + +#include "clang/Analysis/ProgramPoint.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h" + +namespace clang { + +class CFGBlock; +class CFGElement; +class LocationContext; +class Stmt; + +namespace ento { + +struct NodeBuilderContext; +class AnalysisManager; +class ExplodedNodeSet; +class ExplodedNode; +class ProgramState; +class ProgramStateManager; +class BlockCounter; +class BranchNodeBuilder; +class IndirectGotoNodeBuilder; +class SwitchNodeBuilder; +class EndOfFunctionNodeBuilder; +class NodeBuilderWithSinks; +class MemRegion; + +class SubEngine { + virtual void anchor(); +public: + virtual ~SubEngine() {} + + virtual ProgramStateRef getInitialState(const LocationContext *InitLoc) = 0; + + virtual AnalysisManager &getAnalysisManager() = 0; + + virtual ProgramStateManager &getStateManager() = 0; + + /// Called by CoreEngine. Used to generate new successor + /// nodes by processing the 'effects' of a block-level statement. + virtual void processCFGElement(const CFGElement E, ExplodedNode* Pred, + unsigned StmtIdx, NodeBuilderContext *Ctx)=0; + + /// Called by CoreEngine when it starts processing a CFGBlock. The + /// SubEngine is expected to populate dstNodes with new nodes representing + /// updated analysis state, or generate no nodes at all if it doesn't. + virtual void processCFGBlockEntrance(const BlockEdge &L, + NodeBuilderWithSinks &nodeBuilder) = 0; + + /// Called by CoreEngine. Used to generate successor + /// nodes by processing the 'effects' of a branch condition. + virtual void processBranch(const Stmt *Condition, const Stmt *Term, + NodeBuilderContext& BuilderCtx, + ExplodedNode *Pred, + ExplodedNodeSet &Dst, + const CFGBlock *DstT, + const CFGBlock *DstF) = 0; + + /// Called by CoreEngine. Used to generate successor + /// nodes by processing the 'effects' of a computed goto jump. + virtual void processIndirectGoto(IndirectGotoNodeBuilder& builder) = 0; + + /// Called by CoreEngine. Used to generate successor + /// nodes by processing the 'effects' of a switch statement. + virtual void processSwitch(SwitchNodeBuilder& builder) = 0; + + /// Called by CoreEngine. Used to generate end-of-path + /// nodes when the control reaches the end of a function. + virtual void processEndOfFunction(NodeBuilderContext& BC) = 0; + + // Generate the entry node of the callee. + virtual void processCallEnter(CallEnter CE, ExplodedNode *Pred) = 0; + + // Generate the first post callsite node. + virtual void processCallExit(ExplodedNode *Pred) = 0; + + /// Called by ConstraintManager. Used to call checker-specific + /// logic for handling assumptions on symbolic values. + virtual ProgramStateRef processAssume(ProgramStateRef state, + SVal cond, bool assumption) = 0; + + /// wantsRegionChangeUpdate - Called by ProgramStateManager to determine if a + /// region change should trigger a processRegionChanges update. + virtual bool wantsRegionChangeUpdate(ProgramStateRef state) = 0; + + /// processRegionChanges - Called by ProgramStateManager whenever a change is + /// made to the store. Used to update checkers that track region values. + virtual ProgramStateRef + processRegionChanges(ProgramStateRef state, + const StoreManager::InvalidatedSymbols *invalidated, + ArrayRef<const MemRegion *> ExplicitRegions, + ArrayRef<const MemRegion *> Regions, + const CallOrObjCMessage *Call) = 0; + + + inline ProgramStateRef + processRegionChange(ProgramStateRef state, + const MemRegion* MR) { + return processRegionChanges(state, 0, MR, MR, 0); + } + + /// printState - Called by ProgramStateManager to print checker-specific data. + virtual void printState(raw_ostream &Out, ProgramStateRef State, + const char *NL, const char *Sep) = 0; + + /// Called by CoreEngine when the analysis worklist is either empty or the + // maximum number of analysis steps have been reached. + virtual void processEndWorklist(bool hasWorkRemaining) = 0; +}; + +} // end GR namespace + +} // end clang namespace + +#endif diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SummaryManager.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SummaryManager.h new file mode 100644 index 0000000..ed87851 --- /dev/null +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SummaryManager.h @@ -0,0 +1,61 @@ +//== SummaryManager.h - Generic handling of function summaries --*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines SummaryManager and related classes, which provides +// a generic mechanism for managing function summaries. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_GR_SUMMARY +#define LLVM_CLANG_GR_SUMMARY + +#include "llvm/ADT/FoldingSet.h" +#include "llvm/Support/Allocator.h" + +namespace clang { + +namespace ento { + +namespace summMgr { + + +/* Key kinds: + + - C functions + - C++ functions (name + parameter types) + - ObjC methods: + - Class, selector (class method) + - Class, selector (instance method) + - Category, selector (instance method) + - Protocol, selector (instance method) + - C++ methods + - Class, function name + parameter types + const + */ + +class SummaryKey { + +}; + +} // end namespace clang::summMgr + +class SummaryManagerImpl { + +}; + + +template <typename T> +class SummaryManager : SummaryManagerImpl { + +}; + +} // end GR namespace + +} // end clang namespace + +#endif diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h new file mode 100644 index 0000000..c7de7ef --- /dev/null +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h @@ -0,0 +1,668 @@ +//== SymbolManager.h - Management of Symbolic Values ------------*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines SymbolManager, a class that manages symbolic values +// created for use by ExprEngine and related classes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_GR_SYMMGR_H +#define LLVM_CLANG_GR_SYMMGR_H + +#include "clang/AST/Decl.h" +#include "clang/AST/Expr.h" +#include "clang/Analysis/AnalysisContext.h" +#include "clang/Basic/LLVM.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/DenseMap.h" + +namespace llvm { +class BumpPtrAllocator; +} + +namespace clang { + class ASTContext; + class StackFrameContext; + +namespace ento { + class BasicValueFactory; + class MemRegion; + class SubRegion; + class TypedValueRegion; + class VarRegion; + +/// \brief Symbolic value. These values used to capture symbolic execution of +/// the program. +class SymExpr : public llvm::FoldingSetNode { + virtual void anchor(); +public: + enum Kind { RegionValueKind, ConjuredKind, DerivedKind, ExtentKind, + MetadataKind, + BEGIN_SYMBOLS = RegionValueKind, + END_SYMBOLS = MetadataKind, + SymIntKind, IntSymKind, SymSymKind, CastSymbolKind }; +private: + Kind K; + +protected: + SymExpr(Kind k) : K(k) {} + +public: + virtual ~SymExpr() {} + + Kind getKind() const { return K; } + + virtual void dump() const; + + virtual void dumpToStream(raw_ostream &os) const {} + + virtual QualType getType(ASTContext&) const = 0; + virtual void Profile(llvm::FoldingSetNodeID& profile) = 0; + + // Implement isa<T> support. + static inline bool classof(const SymExpr*) { return true; } + + /// \brief Iterator over symbols that the current symbol depends on. + /// + /// For SymbolData, it's the symbol itself; for expressions, it's the + /// expression symbol and all the operands in it. Note, SymbolDerived is + /// treated as SymbolData - the iterator will NOT visit the parent region. + class symbol_iterator { + SmallVector<const SymExpr*, 5> itr; + void expand(); + public: + symbol_iterator() {} + symbol_iterator(const SymExpr *SE); + + symbol_iterator &operator++(); + const SymExpr* operator*(); + + bool operator==(const symbol_iterator &X) const; + bool operator!=(const symbol_iterator &X) const; + }; + + symbol_iterator symbol_begin() const { + return symbol_iterator(this); + } + static symbol_iterator symbol_end() { return symbol_iterator(); } +}; + +typedef const SymExpr* SymbolRef; +typedef llvm::SmallVector<SymbolRef, 2> SymbolRefSmallVectorTy; + +typedef unsigned SymbolID; +/// \brief A symbol representing data which can be stored in a memory location +/// (region). +class SymbolData : public SymExpr { + virtual void anchor(); + const SymbolID Sym; + +protected: + SymbolData(Kind k, SymbolID sym) : SymExpr(k), Sym(sym) {} + +public: + virtual ~SymbolData() {} + + SymbolID getSymbolID() const { return Sym; } + + // Implement isa<T> support. + static inline bool classof(const SymExpr *SE) { + Kind k = SE->getKind(); + return k >= BEGIN_SYMBOLS && k <= END_SYMBOLS; + } +}; + +///\brief A symbol representing the value stored at a MemRegion. +class SymbolRegionValue : public SymbolData { + const TypedValueRegion *R; + +public: + SymbolRegionValue(SymbolID sym, const TypedValueRegion *r) + : SymbolData(RegionValueKind, sym), R(r) {} + + const TypedValueRegion* getRegion() const { return R; } + + static void Profile(llvm::FoldingSetNodeID& profile, const TypedValueRegion* R) { + profile.AddInteger((unsigned) RegionValueKind); + profile.AddPointer(R); + } + + virtual void Profile(llvm::FoldingSetNodeID& profile) { + Profile(profile, R); + } + + virtual void dumpToStream(raw_ostream &os) const; + + QualType getType(ASTContext&) const; + + // Implement isa<T> support. + static inline bool classof(const SymExpr *SE) { + return SE->getKind() == RegionValueKind; + } +}; + +/// A symbol representing the result of an expression in the case when we do +/// not know anything about what the expression is. +class SymbolConjured : public SymbolData { + const Stmt *S; + QualType T; + unsigned Count; + const LocationContext *LCtx; + const void *SymbolTag; + +public: + SymbolConjured(SymbolID sym, const Stmt *s, const LocationContext *lctx, + QualType t, unsigned count, + const void *symbolTag) + : SymbolData(ConjuredKind, sym), S(s), T(t), Count(count), + LCtx(lctx), + SymbolTag(symbolTag) {} + + const Stmt *getStmt() const { return S; } + unsigned getCount() const { return Count; } + const void *getTag() const { return SymbolTag; } + + QualType getType(ASTContext&) const; + + virtual void dumpToStream(raw_ostream &os) const; + + static void Profile(llvm::FoldingSetNodeID& profile, const Stmt *S, + QualType T, unsigned Count, const LocationContext *LCtx, + const void *SymbolTag) { + profile.AddInteger((unsigned) ConjuredKind); + profile.AddPointer(S); + profile.AddPointer(LCtx); + profile.Add(T); + profile.AddInteger(Count); + profile.AddPointer(SymbolTag); + } + + virtual void Profile(llvm::FoldingSetNodeID& profile) { + Profile(profile, S, T, Count, LCtx, SymbolTag); + } + + // Implement isa<T> support. + static inline bool classof(const SymExpr *SE) { + return SE->getKind() == ConjuredKind; + } +}; + +/// A symbol representing the value of a MemRegion whose parent region has +/// symbolic value. +class SymbolDerived : public SymbolData { + SymbolRef parentSymbol; + const TypedValueRegion *R; + +public: + SymbolDerived(SymbolID sym, SymbolRef parent, const TypedValueRegion *r) + : SymbolData(DerivedKind, sym), parentSymbol(parent), R(r) {} + + SymbolRef getParentSymbol() const { return parentSymbol; } + const TypedValueRegion *getRegion() const { return R; } + + QualType getType(ASTContext&) const; + + virtual void dumpToStream(raw_ostream &os) const; + + static void Profile(llvm::FoldingSetNodeID& profile, SymbolRef parent, + const TypedValueRegion *r) { + profile.AddInteger((unsigned) DerivedKind); + profile.AddPointer(r); + profile.AddPointer(parent); + } + + virtual void Profile(llvm::FoldingSetNodeID& profile) { + Profile(profile, parentSymbol, R); + } + + // Implement isa<T> support. + static inline bool classof(const SymExpr *SE) { + return SE->getKind() == DerivedKind; + } +}; + +/// SymbolExtent - Represents the extent (size in bytes) of a bounded region. +/// Clients should not ask the SymbolManager for a region's extent. Always use +/// SubRegion::getExtent instead -- the value returned may not be a symbol. +class SymbolExtent : public SymbolData { + const SubRegion *R; + +public: + SymbolExtent(SymbolID sym, const SubRegion *r) + : SymbolData(ExtentKind, sym), R(r) {} + + const SubRegion *getRegion() const { return R; } + + QualType getType(ASTContext&) const; + + virtual void dumpToStream(raw_ostream &os) const; + + static void Profile(llvm::FoldingSetNodeID& profile, const SubRegion *R) { + profile.AddInteger((unsigned) ExtentKind); + profile.AddPointer(R); + } + + virtual void Profile(llvm::FoldingSetNodeID& profile) { + Profile(profile, R); + } + + // Implement isa<T> support. + static inline bool classof(const SymExpr *SE) { + return SE->getKind() == ExtentKind; + } +}; + +/// SymbolMetadata - Represents path-dependent metadata about a specific region. +/// Metadata symbols remain live as long as they are marked as in use before +/// dead-symbol sweeping AND their associated regions are still alive. +/// Intended for use by checkers. +class SymbolMetadata : public SymbolData { + const MemRegion* R; + const Stmt *S; + QualType T; + unsigned Count; + const void *Tag; +public: + SymbolMetadata(SymbolID sym, const MemRegion* r, const Stmt *s, QualType t, + unsigned count, const void *tag) + : SymbolData(MetadataKind, sym), R(r), S(s), T(t), Count(count), Tag(tag) {} + + const MemRegion *getRegion() const { return R; } + const Stmt *getStmt() const { return S; } + unsigned getCount() const { return Count; } + const void *getTag() const { return Tag; } + + QualType getType(ASTContext&) const; + + virtual void dumpToStream(raw_ostream &os) const; + + static void Profile(llvm::FoldingSetNodeID& profile, const MemRegion *R, + const Stmt *S, QualType T, unsigned Count, + const void *Tag) { + profile.AddInteger((unsigned) MetadataKind); + profile.AddPointer(R); + profile.AddPointer(S); + profile.Add(T); + profile.AddInteger(Count); + profile.AddPointer(Tag); + } + + virtual void Profile(llvm::FoldingSetNodeID& profile) { + Profile(profile, R, S, T, Count, Tag); + } + + // Implement isa<T> support. + static inline bool classof(const SymExpr *SE) { + return SE->getKind() == MetadataKind; + } +}; + +/// \brief Represents a cast expression. +class SymbolCast : public SymExpr { + const SymExpr *Operand; + /// Type of the operand. + QualType FromTy; + /// The type of the result. + QualType ToTy; + +public: + SymbolCast(const SymExpr *In, QualType From, QualType To) : + SymExpr(CastSymbolKind), Operand(In), FromTy(From), ToTy(To) { } + + QualType getType(ASTContext &C) const { return ToTy; } + + const SymExpr *getOperand() const { return Operand; } + + virtual void dumpToStream(raw_ostream &os) const; + + static void Profile(llvm::FoldingSetNodeID& ID, + const SymExpr *In, QualType From, QualType To) { + ID.AddInteger((unsigned) CastSymbolKind); + ID.AddPointer(In); + ID.Add(From); + ID.Add(To); + } + + void Profile(llvm::FoldingSetNodeID& ID) { + Profile(ID, Operand, FromTy, ToTy); + } + + // Implement isa<T> support. + static inline bool classof(const SymExpr *SE) { + return SE->getKind() == CastSymbolKind; + } +}; + +/// SymIntExpr - Represents symbolic expression like 'x' + 3. +class SymIntExpr : public SymExpr { + const SymExpr *LHS; + BinaryOperator::Opcode Op; + const llvm::APSInt& RHS; + QualType T; + +public: + SymIntExpr(const SymExpr *lhs, BinaryOperator::Opcode op, + const llvm::APSInt& rhs, QualType t) + : SymExpr(SymIntKind), LHS(lhs), Op(op), RHS(rhs), T(t) {} + + // FIXME: We probably need to make this out-of-line to avoid redundant + // generation of virtual functions. + QualType getType(ASTContext &C) const { return T; } + + BinaryOperator::Opcode getOpcode() const { return Op; } + + virtual void dumpToStream(raw_ostream &os) const; + + const SymExpr *getLHS() const { return LHS; } + const llvm::APSInt &getRHS() const { return RHS; } + + static void Profile(llvm::FoldingSetNodeID& ID, const SymExpr *lhs, + BinaryOperator::Opcode op, const llvm::APSInt& rhs, + QualType t) { + ID.AddInteger((unsigned) SymIntKind); + ID.AddPointer(lhs); + ID.AddInteger(op); + ID.AddPointer(&rhs); + ID.Add(t); + } + + void Profile(llvm::FoldingSetNodeID& ID) { + Profile(ID, LHS, Op, RHS, T); + } + + // Implement isa<T> support. + static inline bool classof(const SymExpr *SE) { + return SE->getKind() == SymIntKind; + } +}; + +/// IntSymExpr - Represents symbolic expression like 3 - 'x'. +class IntSymExpr : public SymExpr { + const llvm::APSInt& LHS; + BinaryOperator::Opcode Op; + const SymExpr *RHS; + QualType T; + +public: + IntSymExpr(const llvm::APSInt& lhs, BinaryOperator::Opcode op, + const SymExpr *rhs, QualType t) + : SymExpr(IntSymKind), LHS(lhs), Op(op), RHS(rhs), T(t) {} + + QualType getType(ASTContext &C) const { return T; } + + BinaryOperator::Opcode getOpcode() const { return Op; } + + virtual void dumpToStream(raw_ostream &os) const; + + const SymExpr *getRHS() const { return RHS; } + const llvm::APSInt &getLHS() const { return LHS; } + + static void Profile(llvm::FoldingSetNodeID& ID, const llvm::APSInt& lhs, + BinaryOperator::Opcode op, const SymExpr *rhs, + QualType t) { + ID.AddInteger((unsigned) IntSymKind); + ID.AddPointer(&lhs); + ID.AddInteger(op); + ID.AddPointer(rhs); + ID.Add(t); + } + + void Profile(llvm::FoldingSetNodeID& ID) { + Profile(ID, LHS, Op, RHS, T); + } + + // Implement isa<T> support. + static inline bool classof(const SymExpr *SE) { + return SE->getKind() == IntSymKind; + } +}; + +/// SymSymExpr - Represents symbolic expression like 'x' + 'y'. +class SymSymExpr : public SymExpr { + const SymExpr *LHS; + BinaryOperator::Opcode Op; + const SymExpr *RHS; + QualType T; + +public: + SymSymExpr(const SymExpr *lhs, BinaryOperator::Opcode op, const SymExpr *rhs, + QualType t) + : SymExpr(SymSymKind), LHS(lhs), Op(op), RHS(rhs), T(t) {} + + BinaryOperator::Opcode getOpcode() const { return Op; } + const SymExpr *getLHS() const { return LHS; } + const SymExpr *getRHS() const { return RHS; } + + // FIXME: We probably need to make this out-of-line to avoid redundant + // generation of virtual functions. + QualType getType(ASTContext &C) const { return T; } + + virtual void dumpToStream(raw_ostream &os) const; + + static void Profile(llvm::FoldingSetNodeID& ID, const SymExpr *lhs, + BinaryOperator::Opcode op, const SymExpr *rhs, QualType t) { + ID.AddInteger((unsigned) SymSymKind); + ID.AddPointer(lhs); + ID.AddInteger(op); + ID.AddPointer(rhs); + ID.Add(t); + } + + void Profile(llvm::FoldingSetNodeID& ID) { + Profile(ID, LHS, Op, RHS, T); + } + + // Implement isa<T> support. + static inline bool classof(const SymExpr *SE) { + return SE->getKind() == SymSymKind; + } +}; + +class SymbolManager { + typedef llvm::FoldingSet<SymExpr> DataSetTy; + typedef llvm::DenseMap<SymbolRef, SymbolRefSmallVectorTy*> SymbolDependTy; + + DataSetTy DataSet; + /// Stores the extra dependencies between symbols: the data should be kept + /// alive as long as the key is live. + SymbolDependTy SymbolDependencies; + unsigned SymbolCounter; + llvm::BumpPtrAllocator& BPAlloc; + BasicValueFactory &BV; + ASTContext &Ctx; + +public: + SymbolManager(ASTContext &ctx, BasicValueFactory &bv, + llvm::BumpPtrAllocator& bpalloc) + : SymbolDependencies(16), SymbolCounter(0), + BPAlloc(bpalloc), BV(bv), Ctx(ctx) {} + + ~SymbolManager(); + + static bool canSymbolicate(QualType T); + + /// \brief Make a unique symbol for MemRegion R according to its kind. + const SymbolRegionValue* getRegionValueSymbol(const TypedValueRegion* R); + + const SymbolConjured* getConjuredSymbol(const Stmt *E, + const LocationContext *LCtx, + QualType T, + unsigned VisitCount, + const void *SymbolTag = 0); + + const SymbolConjured* getConjuredSymbol(const Expr *E, + const LocationContext *LCtx, + unsigned VisitCount, + const void *SymbolTag = 0) { + return getConjuredSymbol(E, LCtx, E->getType(), + VisitCount, SymbolTag); + } + + const SymbolDerived *getDerivedSymbol(SymbolRef parentSymbol, + const TypedValueRegion *R); + + const SymbolExtent *getExtentSymbol(const SubRegion *R); + + /// \brief Creates a metadata symbol associated with a specific region. + /// + /// VisitCount can be used to differentiate regions corresponding to + /// different loop iterations, thus, making the symbol path-dependent. + const SymbolMetadata* getMetadataSymbol(const MemRegion* R, const Stmt *S, + QualType T, unsigned VisitCount, + const void *SymbolTag = 0); + + const SymbolCast* getCastSymbol(const SymExpr *Operand, + QualType From, QualType To); + + const SymIntExpr *getSymIntExpr(const SymExpr *lhs, BinaryOperator::Opcode op, + const llvm::APSInt& rhs, QualType t); + + const SymIntExpr *getSymIntExpr(const SymExpr &lhs, BinaryOperator::Opcode op, + const llvm::APSInt& rhs, QualType t) { + return getSymIntExpr(&lhs, op, rhs, t); + } + + const IntSymExpr *getIntSymExpr(const llvm::APSInt& lhs, + BinaryOperator::Opcode op, + const SymExpr *rhs, QualType t); + + const SymSymExpr *getSymSymExpr(const SymExpr *lhs, BinaryOperator::Opcode op, + const SymExpr *rhs, QualType t); + + QualType getType(const SymExpr *SE) const { + return SE->getType(Ctx); + } + + /// \brief Add artificial symbol dependency. + /// + /// The dependent symbol should stay alive as long as the primary is alive. + void addSymbolDependency(const SymbolRef Primary, const SymbolRef Dependent); + + const SymbolRefSmallVectorTy *getDependentSymbols(const SymbolRef Primary); + + ASTContext &getContext() { return Ctx; } + BasicValueFactory &getBasicVals() { return BV; } +}; + +class SymbolReaper { + enum SymbolStatus { + NotProcessed, + HaveMarkedDependents + }; + + typedef llvm::DenseSet<SymbolRef> SymbolSetTy; + typedef llvm::DenseMap<SymbolRef, SymbolStatus> SymbolMapTy; + typedef llvm::DenseSet<const MemRegion *> RegionSetTy; + + SymbolMapTy TheLiving; + SymbolSetTy MetadataInUse; + SymbolSetTy TheDead; + + RegionSetTy RegionRoots; + + const LocationContext *LCtx; + const Stmt *Loc; + SymbolManager& SymMgr; + StoreRef reapedStore; + llvm::DenseMap<const MemRegion *, unsigned> includedRegionCache; + +public: + SymbolReaper(const LocationContext *ctx, const Stmt *s, SymbolManager& symmgr, + StoreManager &storeMgr) + : LCtx(ctx), Loc(s), SymMgr(symmgr), reapedStore(0, storeMgr) {} + + ~SymbolReaper() {} + + const LocationContext *getLocationContext() const { return LCtx; } + const Stmt *getCurrentStatement() const { return Loc; } + + bool isLive(SymbolRef sym); + bool isLiveRegion(const MemRegion *region); + bool isLive(const Stmt *ExprVal, const LocationContext *LCtx) const; + bool isLive(const VarRegion *VR, bool includeStoreBindings = false) const; + + /// \brief Unconditionally marks a symbol as live. + /// + /// This should never be + /// used by checkers, only by the state infrastructure such as the store and + /// environment. Checkers should instead use metadata symbols and markInUse. + void markLive(SymbolRef sym); + + /// \brief Marks a symbol as important to a checker. + /// + /// For metadata symbols, + /// this will keep the symbol alive as long as its associated region is also + /// live. For other symbols, this has no effect; checkers are not permitted + /// to influence the life of other symbols. This should be used before any + /// symbol marking has occurred, i.e. in the MarkLiveSymbols callback. + void markInUse(SymbolRef sym); + + /// \brief If a symbol is known to be live, marks the symbol as live. + /// + /// Otherwise, if the symbol cannot be proven live, it is marked as dead. + /// Returns true if the symbol is dead, false if live. + bool maybeDead(SymbolRef sym); + + typedef SymbolSetTy::const_iterator dead_iterator; + dead_iterator dead_begin() const { return TheDead.begin(); } + dead_iterator dead_end() const { return TheDead.end(); } + + bool hasDeadSymbols() const { + return !TheDead.empty(); + } + + typedef RegionSetTy::const_iterator region_iterator; + region_iterator region_begin() const { return RegionRoots.begin(); } + region_iterator region_end() const { return RegionRoots.end(); } + + /// \brief Returns whether or not a symbol has been confirmed dead. + /// + /// This should only be called once all marking of dead symbols has completed. + /// (For checkers, this means only in the evalDeadSymbols callback.) + bool isDead(SymbolRef sym) const { + return TheDead.count(sym); + } + + void markLive(const MemRegion *region); + + /// \brief Set to the value of the symbolic store after + /// StoreManager::removeDeadBindings has been called. + void setReapedStore(StoreRef st) { reapedStore = st; } + +private: + /// Mark the symbols dependent on the input symbol as live. + void markDependentsLive(SymbolRef sym); +}; + +class SymbolVisitor { +public: + /// \brief A visitor method invoked by ProgramStateManager::scanReachableSymbols. + /// + /// The method returns \c true if symbols should continue be scanned and \c + /// false otherwise. + virtual bool VisitSymbol(SymbolRef sym) = 0; + virtual bool VisitMemRegion(const MemRegion *region) { return true; } + virtual ~SymbolVisitor(); +}; + +} // end GR namespace + +} // end clang namespace + +namespace llvm { +static inline raw_ostream &operator<<(raw_ostream &os, + const clang::ento::SymExpr *SE) { + SE->dumpToStream(os); + return os; +} +} // end llvm namespace +#endif diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h new file mode 100644 index 0000000..53205d3 --- /dev/null +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h @@ -0,0 +1,40 @@ +//== TaintManager.h - Managing taint --------------------------- -*- C++ -*--=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides APIs for adding, removing, querying symbol taint. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TAINTMANAGER_H +#define LLVM_CLANG_TAINTMANAGER_H + +#include "clang/StaticAnalyzer/Core/PathSensitive/TaintTag.h" + +namespace clang { +namespace ento { + +/// The GDM component containing the tainted root symbols. We lazily infer the +/// taint of the dependent symbols. Currently, this is a map from a symbol to +/// tag kind. TODO: Should support multiple tag kinds. +struct TaintMap {}; +typedef llvm::ImmutableMap<SymbolRef, TaintTagType> TaintMapImpl; +template<> struct ProgramStateTrait<TaintMap> + : public ProgramStatePartialTrait<TaintMapImpl> { + static void *GDMIndex() { static int index = 0; return &index; } +}; + +class TaintManager { + + TaintManager() {} +}; + +} +} + +#endif diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/TaintTag.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/TaintTag.h new file mode 100644 index 0000000..8ddc8b9 --- /dev/null +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/TaintTag.h @@ -0,0 +1,27 @@ +//== TaintTag.h - Path-sensitive "State" for tracking values -*- C++ -*--=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Defines a set of taint tags. Several tags are used to differentiate kinds +// of taint. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_TAINTTAG_H +#define LLVM_CLANG_TAINTTAG_H + +namespace clang { +namespace ento { + +/// The type of taint, which helps to differentiate between different types of +/// taint. +typedef unsigned TaintTagType; +static const TaintTagType TaintTagGeneric = 0; + +}} + +#endif diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h new file mode 100644 index 0000000..51aa753 --- /dev/null +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h @@ -0,0 +1,102 @@ +//==- WorkList.h - Worklist class used by CoreEngine ---------------*- C++ -*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines WorkList, a pure virtual class that represents an opaque +// worklist used by CoreEngine to explore the reachability state space. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_GR_WORKLIST +#define LLVM_CLANG_GR_WORKLIST + +#include "clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h" +#include <cstddef> + +namespace clang { + +class CFGBlock; + +namespace ento { + +class ExplodedNode; +class ExplodedNodeImpl; + +class WorkListUnit { + ExplodedNode *node; + BlockCounter counter; + const CFGBlock *block; + unsigned blockIdx; // This is the index of the next statement. + +public: + WorkListUnit(ExplodedNode *N, BlockCounter C, + const CFGBlock *B, unsigned idx) + : node(N), + counter(C), + block(B), + blockIdx(idx) {} + + explicit WorkListUnit(ExplodedNode *N, BlockCounter C) + : node(N), + counter(C), + block(NULL), + blockIdx(0) {} + + /// Returns the node associated with the worklist unit. + ExplodedNode *getNode() const { return node; } + + /// Returns the block counter map associated with the worklist unit. + BlockCounter getBlockCounter() const { return counter; } + + /// Returns the CFGblock associated with the worklist unit. + const CFGBlock *getBlock() const { return block; } + + /// Return the index within the CFGBlock for the worklist unit. + unsigned getIndex() const { return blockIdx; } +}; + +class WorkList { + BlockCounter CurrentCounter; +public: + virtual ~WorkList(); + virtual bool hasWork() const = 0; + + virtual void enqueue(const WorkListUnit& U) = 0; + + void enqueue(ExplodedNode *N, const CFGBlock *B, unsigned idx) { + enqueue(WorkListUnit(N, CurrentCounter, B, idx)); + } + + void enqueue(ExplodedNode *N) { + assert(N->getLocation().getKind() != ProgramPoint::PostStmtKind); + enqueue(WorkListUnit(N, CurrentCounter)); + } + + virtual WorkListUnit dequeue() = 0; + + void setBlockCounter(BlockCounter C) { CurrentCounter = C; } + BlockCounter getBlockCounter() const { return CurrentCounter; } + + class Visitor { + public: + Visitor() {} + virtual ~Visitor(); + virtual bool visit(const WorkListUnit &U) = 0; + }; + virtual bool visitItemsInWorkList(Visitor &V) = 0; + + static WorkList *makeDFS(); + static WorkList *makeBFS(); + static WorkList *makeBFSBlockDFSContents(); +}; + +} // end GR namespace + +} // end clang namespace + +#endif diff --git a/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h b/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h new file mode 100644 index 0000000..492edd4 --- /dev/null +++ b/clang/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h @@ -0,0 +1,33 @@ +//===-- CheckerRegistration.h - Checker Registration Function ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SA_FRONTEND_CHECKERREGISTRATION_H +#define LLVM_CLANG_SA_FRONTEND_CHECKERREGISTRATION_H + +#include "clang/Basic/LLVM.h" +#include <string> + +namespace clang { + class AnalyzerOptions; + class LangOptions; + class DiagnosticsEngine; + +namespace ento { + class CheckerManager; + +CheckerManager *createCheckerManager(const AnalyzerOptions &opts, + const LangOptions &langOpts, + ArrayRef<std::string> plugins, + DiagnosticsEngine &diags); + +} // end ento namespace + +} // end namespace clang + +#endif diff --git a/clang/include/clang/StaticAnalyzer/Frontend/FrontendActions.h b/clang/include/clang/StaticAnalyzer/Frontend/FrontendActions.h new file mode 100644 index 0000000..838ac92 --- /dev/null +++ b/clang/include/clang/StaticAnalyzer/Frontend/FrontendActions.h @@ -0,0 +1,35 @@ +//===-- FrontendActions.h - Useful Frontend Actions -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_GR_FRONTENDACTIONS_H +#define LLVM_CLANG_GR_FRONTENDACTIONS_H + +#include "clang/Frontend/FrontendAction.h" + +namespace clang { + +namespace ento { + +//===----------------------------------------------------------------------===// +// AST Consumer Actions +//===----------------------------------------------------------------------===// + +class AnalysisAction : public ASTFrontendAction { +protected: + virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, + StringRef InFile); +}; + +void printCheckerHelp(raw_ostream &OS, ArrayRef<std::string> plugins); + +} // end GR namespace + +} // end namespace clang + +#endif diff --git a/clang/include/clang/Tooling/CompilationDatabase.h b/clang/include/clang/Tooling/CompilationDatabase.h new file mode 100644 index 0000000..625c8ec --- /dev/null +++ b/clang/include/clang/Tooling/CompilationDatabase.h @@ -0,0 +1,218 @@ +//===--- CompilationDatabase.h - --------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides an interface and multiple implementations for +// CompilationDatabases. +// +// While C++ refactoring and analysis tools are not compilers, and thus +// don't run as part of the build system, they need the exact information +// of a build in order to be able to correctly understand the C++ code of +// the project. This information is provided via the CompilationDatabase +// interface. +// +// To create a CompilationDatabase from a build directory one can call +// CompilationDatabase::loadFromDirectory(), which deduces the correct +// compilation database from the root of the build tree. +// +// See the concrete subclasses of CompilationDatabase for currently supported +// formats. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_COMPILATION_DATABASE_H +#define LLVM_CLANG_TOOLING_COMPILATION_DATABASE_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/YAMLParser.h" +#include <string> +#include <vector> + +namespace clang { +namespace tooling { + +/// \brief Specifies the working directory and command of a compilation. +struct CompileCommand { + CompileCommand() {} + CompileCommand(Twine Directory, ArrayRef<std::string> CommandLine) + : Directory(Directory.str()), CommandLine(CommandLine) {} + + /// \brief The working directory the command was executed from. + std::string Directory; + + /// \brief The command line that was executed. + std::vector<std::string> CommandLine; +}; + +/// \brief Interface for compilation databases. +/// +/// A compilation database allows the user to retrieve all compile command lines +/// that a specified file is compiled with in a project. +/// The retrieved compile command lines can be used to run clang tools over +/// a subset of the files in a project. +class CompilationDatabase { +public: + virtual ~CompilationDatabase(); + + /// \brief Loads a compilation database from a build directory. + /// + /// Looks at the specified 'BuildDirectory' and creates a compilation database + /// that allows to query compile commands for source files in the + /// corresponding source tree. + /// + /// Returns NULL and sets ErrorMessage if we were not able to build up a + /// compilation database for the build directory. + /// + /// FIXME: Currently only supports JSON compilation databases, which + /// are named 'compile_commands.json' in the given directory. Extend this + /// for other build types (like ninja build files). + static CompilationDatabase *loadFromDirectory(StringRef BuildDirectory, + std::string &ErrorMessage); + + /// \brief Returns all compile commands in which the specified file was + /// compiled. + /// + /// This includes compile comamnds that span multiple source files. + /// For example, consider a project with the following compilations: + /// $ clang++ -o test a.cc b.cc t.cc + /// $ clang++ -o production a.cc b.cc -DPRODUCTION + /// A compilation database representing the project would return both command + /// lines for a.cc and b.cc and only the first command line for t.cc. + virtual std::vector<CompileCommand> getCompileCommands( + StringRef FilePath) const = 0; +}; + +/// \brief A compilation database that returns a single compile command line. +/// +/// Useful when we want a tool to behave more like a compiler invocation. +class FixedCompilationDatabase : public CompilationDatabase { +public: + /// \brief Creates a FixedCompilationDatabase from the arguments after "--". + /// + /// Parses the given command line for "--". If "--" is found, the rest of + /// the arguments will make up the command line in the returned + /// FixedCompilationDatabase. + /// The arguments after "--" must not include positional parameters or the + /// argv[0] of the tool. Those will be added by the FixedCompilationDatabase + /// when a CompileCommand is requested. The argv[0] of the returned command + /// line will be "clang-tool". + /// + /// Returns NULL in case "--" is not found. + /// + /// The argument list is meant to be compatible with normal llvm command line + /// parsing in main methods. + /// int main(int argc, char **argv) { + /// llvm::OwningPtr<FixedCompilationDatabase> Compilations( + /// FixedCompilationDatabase::loadFromCommandLine(argc, argv)); + /// cl::ParseCommandLineOptions(argc, argv); + /// ... + /// } + /// + /// \param Argc The number of command line arguments - will be changed to + /// the number of arguments before "--", if "--" was found in the argument + /// list. + /// \param Argv Points to the command line arguments. + /// \param Directory The base directory used in the FixedCompilationDatabase. + static FixedCompilationDatabase *loadFromCommandLine(int &Argc, + const char **Argv, + Twine Directory = "."); + + /// \brief Constructs a compilation data base from a specified directory + /// and command line. + FixedCompilationDatabase(Twine Directory, ArrayRef<std::string> CommandLine); + + /// \brief Returns the given compile command. + /// + /// Will always return a vector with one entry that contains the directory + /// and command line specified at construction with "clang-tool" as argv[0] + /// and 'FilePath' as positional argument. + virtual std::vector<CompileCommand> getCompileCommands( + StringRef FilePath) const; + +private: + /// This is built up to contain a single entry vector to be returned from + /// getCompileCommands after adding the positional argument. + std::vector<CompileCommand> CompileCommands; +}; + +/// \brief A JSON based compilation database. +/// +/// JSON compilation database files must contain a list of JSON objects which +/// provide the command lines in the attributes 'directory', 'command' and +/// 'file': +/// [ +/// { "directory": "<working directory of the compile>", +/// "command": "<compile command line>", +/// "file": "<path to source file>" +/// }, +/// ... +/// ] +/// Each object entry defines one compile action. The specified file is +/// considered to be the main source file for the translation unit. +/// +/// JSON compilation databases can for example be generated in CMake projects +/// by setting the flag -DCMAKE_EXPORT_COMPILE_COMMANDS. +class JSONCompilationDatabase : public CompilationDatabase { +public: + /// \brief Loads a JSON compilation database from the specified file. + /// + /// Returns NULL and sets ErrorMessage if the database could not be + /// loaded from the given file. + static JSONCompilationDatabase *loadFromFile(StringRef FilePath, + std::string &ErrorMessage); + + /// \brief Loads a JSON compilation database from a data buffer. + /// + /// Returns NULL and sets ErrorMessage if the database could not be loaded. + static JSONCompilationDatabase *loadFromBuffer(StringRef DatabaseString, + std::string &ErrorMessage); + + /// \brief Returns all compile comamnds in which the specified file was + /// compiled. + /// + /// FIXME: Currently FilePath must be an absolute path inside the + /// source directory which does not have symlinks resolved. + virtual std::vector<CompileCommand> getCompileCommands( + StringRef FilePath) const; + +private: + /// \brief Constructs a JSON compilation database on a memory buffer. + JSONCompilationDatabase(llvm::MemoryBuffer *Database) + : Database(Database), YAMLStream(Database->getBuffer(), SM) {} + + /// \brief Parses the database file and creates the index. + /// + /// Returns whether parsing succeeded. Sets ErrorMessage if parsing + /// failed. + bool parse(std::string &ErrorMessage); + + // Tuple (directory, commandline) where 'commandline' pointing to the + // corresponding nodes in the YAML stream. + typedef std::pair<llvm::yaml::ScalarNode*, + llvm::yaml::ScalarNode*> CompileCommandRef; + + // Maps file paths to the compile command lines for that file. + llvm::StringMap< std::vector<CompileCommandRef> > IndexByFile; + + llvm::OwningPtr<llvm::MemoryBuffer> Database; + llvm::SourceMgr SM; + llvm::yaml::Stream YAMLStream; +}; + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_COMPILATION_DATABASE_H + diff --git a/clang/include/clang/Tooling/Tooling.h b/clang/include/clang/Tooling/Tooling.h new file mode 100644 index 0000000..868eae3 --- /dev/null +++ b/clang/include/clang/Tooling/Tooling.h @@ -0,0 +1,213 @@ +//===--- Tooling.h - Framework for standalone Clang tools -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements functions to run clang tools standalone instead +// of running them as a plugin. +// +// A ClangTool is initialized with a CompilationDatabase and a set of files +// to run over. The tool will then run a user-specified FrontendAction over +// all TUs in which the given files are compiled. +// +// It is also possible to run a FrontendAction over a snippet of code by +// calling runSyntaxOnlyToolOnCode, which is useful for unit testing. +// +// Applications that need more fine grained control over how to run +// multiple FrontendActions over code can use ToolInvocation. +// +// Example tools: +// - running clang -fsyntax-only over source code from an editor to get +// fast syntax checks +// - running match/replace tools over C++ code +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_TOOLING_H +#define LLVM_CLANG_TOOLING_TOOLING_H + +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/Twine.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/LLVM.h" +#include "clang/Driver/Util.h" +#include <string> +#include <vector> + +namespace clang { + +namespace driver { +class Compilation; +} // end namespace driver + +class CompilerInvocation; +class SourceManager; +class FrontendAction; + +namespace tooling { + +class CompilationDatabase; + +/// \brief Interface to generate clang::FrontendActions. +class FrontendActionFactory { +public: + virtual ~FrontendActionFactory(); + + /// \brief Returns a new clang::FrontendAction. + /// + /// The caller takes ownership of the returned action. + virtual clang::FrontendAction *create() = 0; +}; + +/// \brief Returns a new FrontendActionFactory for a given type. +/// +/// T must extend clang::FrontendAction. +/// +/// Example: +/// FrontendActionFactory *Factory = +/// newFrontendActionFactory<clang::SyntaxOnlyAction>(); +template <typename T> +FrontendActionFactory *newFrontendActionFactory(); + +/// \brief Returns a new FrontendActionFactory for any type that provides an +/// implementation of newFrontendAction(). +/// +/// FactoryT must implement: FrontendAction *newFrontendAction(). +/// +/// Example: +/// struct ProvidesFrontendActions { +/// FrontendAction *newFrontendAction(); +/// } Factory; +/// FrontendActionFactory *FactoryAdapter = +/// newFrontendActionFactory(&Factory); +template <typename FactoryT> +FrontendActionFactory *newFrontendActionFactory(FactoryT *ActionFactory); + +/// \brief Runs (and deletes) the tool on 'Code' with the -fsyntax-only flag. +/// +/// \param ToolAction The action to run over the code. +/// \param Code C++ code. +/// \param FileName The file name which 'Code' will be mapped as. +/// +/// \return - True if 'ToolAction' was successfully executed. +bool runToolOnCode(clang::FrontendAction *ToolAction, const Twine &Code, + const Twine &FileName = "input.cc"); + +/// \brief Utility to run a FrontendAction in a single clang invocation. +class ToolInvocation { + public: + /// \brief Create a tool invocation. + /// + /// \param CommandLine The command line arguments to clang. + /// \param ToolAction The action to be executed. Class takes ownership. + /// \param Files The FileManager used for the execution. Class does not take + /// ownership. + ToolInvocation(ArrayRef<std::string> CommandLine, FrontendAction *ToolAction, + FileManager *Files); + + /// \brief Map a virtual file to be used while running the tool. + /// + /// \param FilePath The path at which the content will be mapped. + /// \param Content A null terminated buffer of the file's content. + void mapVirtualFile(StringRef FilePath, StringRef Content); + + /// \brief Run the clang invocation. + /// + /// \returns True if there were no errors during execution. + bool run(); + + private: + void addFileMappingsTo(SourceManager &SourceManager); + + bool runInvocation(const char *BinaryName, + clang::driver::Compilation *Compilation, + clang::CompilerInvocation *Invocation, + const clang::driver::ArgStringList &CC1Args, + clang::FrontendAction *ToolAction); + + std::vector<std::string> CommandLine; + llvm::OwningPtr<FrontendAction> ToolAction; + FileManager *Files; + // Maps <file name> -> <file content>. + llvm::StringMap<StringRef> MappedFileContents; +}; + +/// \brief Utility to run a FrontendAction over a set of files. +/// +/// This class is written to be usable for command line utilities. +class ClangTool { + public: + /// \brief Constructs a clang tool to run over a list of files. + /// + /// \param Compilations The CompilationDatabase which contains the compile + /// command lines for the given source paths. + /// \param SourcePaths The source files to run over. If a source files is + /// not found in Compilations, it is skipped. + ClangTool(const CompilationDatabase &Compilations, + ArrayRef<std::string> SourcePaths); + + /// \brief Map a virtual file to be used while running the tool. + /// + /// \param FilePath The path at which the content will be mapped. + /// \param Content A null terminated buffer of the file's content. + void mapVirtualFile(StringRef FilePath, StringRef Content); + + /// Runs a frontend action over all files specified in the command line. + /// + /// \param ActionFactory Factory generating the frontend actions. The function + /// takes ownership of this parameter. A new action is generated for every + /// processed translation unit. + int run(FrontendActionFactory *ActionFactory); + + /// \brief Returns the file manager used in the tool. + /// + /// The file manager is shared between all translation units. + FileManager &getFiles() { return Files; } + + private: + // We store command lines as pair (file name, command line). + typedef std::pair< std::string, std::vector<std::string> > CommandLine; + std::vector<CommandLine> CommandLines; + + FileManager Files; + // Contains a list of pairs (<file name>, <file content>). + std::vector< std::pair<StringRef, StringRef> > MappedFileContents; +}; + +template <typename T> +FrontendActionFactory *newFrontendActionFactory() { + class SimpleFrontendActionFactory : public FrontendActionFactory { + public: + virtual clang::FrontendAction *create() { return new T; } + }; + + return new SimpleFrontendActionFactory; +} + +template <typename FactoryT> +FrontendActionFactory *newFrontendActionFactory(FactoryT *ActionFactory) { + class FrontendActionFactoryAdapter : public FrontendActionFactory { + public: + explicit FrontendActionFactoryAdapter(FactoryT *ActionFactory) + : ActionFactory(ActionFactory) {} + + virtual clang::FrontendAction *create() { + return ActionFactory->newFrontendAction(); + } + + private: + FactoryT *ActionFactory; + }; + + return new FrontendActionFactoryAdapter(ActionFactory); +} + +} // end namespace tooling +} // end namespace clang + +#endif // LLVM_CLANG_TOOLING_TOOLING_H + |