Update clang to r108428.
This commit is contained in:
parent
4ba675006b
commit
4e58654b47
@ -92,7 +92,7 @@ class Decl {
|
||||
/// These are meant as bitmasks, so that searches in
|
||||
/// C++ can look into the "tag" namespace during ordinary lookup.
|
||||
///
|
||||
/// Decl currently provides 16 bits of IDNS bits.
|
||||
/// Decl currently provides 15 bits of IDNS bits.
|
||||
enum IdentifierNamespace {
|
||||
/// Labels, declared with 'x:' and referenced with 'goto x'.
|
||||
IDNS_Label = 0x0001,
|
||||
@ -225,10 +225,10 @@ class Decl {
|
||||
|
||||
// PCHLevel - the "level" of precompiled header/AST file from which this
|
||||
// declaration was built.
|
||||
unsigned PCHLevel : 2;
|
||||
unsigned PCHLevel : 3;
|
||||
|
||||
/// IdentifierNamespace - This specifies what IDNS_* namespace this lives in.
|
||||
unsigned IdentifierNamespace : 16;
|
||||
unsigned IdentifierNamespace : 15;
|
||||
|
||||
private:
|
||||
#ifndef NDEBUG
|
||||
@ -358,14 +358,14 @@ class Decl {
|
||||
unsigned getPCHLevel() const { return PCHLevel; }
|
||||
|
||||
/// \brief The maximum PCH level that any declaration may have.
|
||||
static const unsigned MaxPCHLevel = 3;
|
||||
|
||||
static const unsigned MaxPCHLevel = 7;
|
||||
|
||||
/// \brief Set the PCH level of this declaration.
|
||||
void setPCHLevel(unsigned Level) {
|
||||
assert(Level < MaxPCHLevel && "PCH level exceeds the maximum");
|
||||
assert(Level <= MaxPCHLevel && "PCH level exceeds the maximum");
|
||||
PCHLevel = Level;
|
||||
}
|
||||
|
||||
|
||||
unsigned getIdentifierNamespace() const {
|
||||
return IdentifierNamespace;
|
||||
}
|
||||
|
@ -242,7 +242,7 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext {
|
||||
/// \brief Determine the type of an expression that sends a message to this
|
||||
/// function.
|
||||
QualType getSendResultType() const {
|
||||
return getResultType().getCallResultType(getASTContext());
|
||||
return getResultType().getNonLValueExprType(getASTContext());
|
||||
}
|
||||
|
||||
TypeSourceInfo *getResultTypeSourceInfo() const { return ResultTInfo; }
|
||||
|
@ -1854,6 +1854,10 @@ class CastExpr : public Expr {
|
||||
/// CK_BitCast - Used for reinterpret_cast.
|
||||
CK_BitCast,
|
||||
|
||||
/// CK_LValueBitCast - Used for reinterpret_cast of expressions to
|
||||
/// a reference type.
|
||||
CK_LValueBitCast,
|
||||
|
||||
/// CK_NoOp - Used for const_cast.
|
||||
CK_NoOp,
|
||||
|
||||
@ -1957,6 +1961,7 @@ class CastExpr : public Expr {
|
||||
// These should not have an inheritance path.
|
||||
case CK_Unknown:
|
||||
case CK_BitCast:
|
||||
case CK_LValueBitCast:
|
||||
case CK_NoOp:
|
||||
case CK_Dynamic:
|
||||
case CK_ToUnion:
|
||||
|
@ -629,13 +629,15 @@ class QualType {
|
||||
bool isAtLeastAsQualifiedAs(QualType Other) const;
|
||||
QualType getNonReferenceType() const;
|
||||
|
||||
/// \brief Determine the type of an expression that calls a function of
|
||||
/// with the given result type.
|
||||
/// \brief Determine the type of a (typically non-lvalue) expression with the
|
||||
/// specified result type.
|
||||
///
|
||||
/// This routine removes a top-level reference (since there are no
|
||||
/// 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 getCallResultType(ASTContext &Context) const;
|
||||
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
|
||||
@ -784,19 +786,27 @@ class Type {
|
||||
|
||||
/// \brief Linkage of this type.
|
||||
mutable unsigned CachedLinkage : 2;
|
||||
|
||||
|
||||
/// \brief FromPCH - Whether this type comes from a PCH file.
|
||||
mutable bool FromPCH : 1;
|
||||
|
||||
/// \brief Set whether this type comes from a PCH file.
|
||||
void setFromPCH(bool V = true) const {
|
||||
FromPCH = V;
|
||||
}
|
||||
|
||||
protected:
|
||||
/// \brief Compute the linkage of this type.
|
||||
virtual Linkage getLinkageImpl() const;
|
||||
|
||||
enum { BitsRemainingInType = 20 };
|
||||
enum { BitsRemainingInType = 19 };
|
||||
|
||||
// silence VC++ warning C4355: 'this' : used in base member initializer list
|
||||
Type *this_() { return this; }
|
||||
Type(TypeClass tc, QualType Canonical, bool dependent)
|
||||
: CanonicalType(Canonical.isNull() ? QualType(this_(), 0) : Canonical),
|
||||
TC(tc), Dependent(dependent), LinkageKnown(false),
|
||||
CachedLinkage(NoLinkage) {}
|
||||
CachedLinkage(NoLinkage), FromPCH(false) {}
|
||||
virtual ~Type() {}
|
||||
virtual void Destroy(ASTContext& C);
|
||||
friend class ASTContext;
|
||||
@ -804,6 +814,9 @@ class Type {
|
||||
public:
|
||||
TypeClass getTypeClass() const { return static_cast<TypeClass>(TC); }
|
||||
|
||||
/// \brief Whether this type comes from a PCH file.
|
||||
bool isFromPCH() const { return FromPCH; }
|
||||
|
||||
bool isCanonicalUnqualified() const {
|
||||
return CanonicalType.getTypePtr() == this;
|
||||
}
|
||||
@ -1907,7 +1920,7 @@ class FunctionType : public Type {
|
||||
/// \brief Determine the type of an expression that calls a function of
|
||||
/// this type.
|
||||
QualType getCallResultType(ASTContext &Context) const {
|
||||
return getResultType().getCallResultType(Context);
|
||||
return getResultType().getNonLValueExprType(Context);
|
||||
}
|
||||
|
||||
static llvm::StringRef getNameForCallConv(CallingConv CC);
|
||||
|
@ -314,6 +314,7 @@ BUILTIN(__builtin_setjmp, "iv**", "")
|
||||
BUILTIN(__builtin_longjmp, "vv**i", "r")
|
||||
BUILTIN(__builtin_unwind_init, "v", "")
|
||||
BUILTIN(__builtin_eh_return_data_regno, "ii", "nc")
|
||||
BUILTIN(__builtin_snprintf, "ic*zcC*.", "nFp:2:")
|
||||
BUILTIN(__builtin_vsprintf, "ic*cC*a", "nFP:1:")
|
||||
BUILTIN(__builtin_vsnprintf, "ic*zcC*a", "nFP:2:")
|
||||
|
||||
|
@ -48,6 +48,7 @@ def CXXHexFloats : DiagGroup<"c++-hex-floats">;
|
||||
def : DiagGroup<"c++0x-compat", [CXXHexFloats]>;
|
||||
def FourByteMultiChar : DiagGroup<"four-char-constants">;
|
||||
def : DiagGroup<"idiomatic-parentheses">;
|
||||
def IgnoredQualifiers : DiagGroup<"ignored-qualifiers">;
|
||||
def : DiagGroup<"import">;
|
||||
def : DiagGroup<"init-self">;
|
||||
def : DiagGroup<"inline">;
|
||||
@ -167,6 +168,7 @@ def Format2 : DiagGroup<"format=2",
|
||||
|
||||
def Extra : DiagGroup<"extra", [
|
||||
MissingFieldInitializers,
|
||||
IgnoredQualifiers,
|
||||
InitializerOverrides,
|
||||
SemiBeforeMethodBody,
|
||||
SignCompare,
|
||||
|
@ -121,7 +121,8 @@ def warn_use_out_of_scope_declaration : Warning<
|
||||
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">;
|
||||
"'%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{"
|
||||
@ -1986,6 +1987,10 @@ 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_logical_instead_of_bitwise : Warning<
|
||||
"use of logical %0 with constant operand; switch to bitwise %1 or "
|
||||
"remove constant">, InGroup<DiagGroup<"logical-bitwise-confusion">>;
|
||||
|
||||
def err_sizeof_nonfragile_interface : Error<
|
||||
"invalid application of '%select{alignof|sizeof}1' to interface %0 in "
|
||||
|
@ -189,7 +189,7 @@ class FileManager {
|
||||
/// getDirectory - Lookup, cache, and verify the specified directory. This
|
||||
/// returns null if the directory doesn't exist.
|
||||
///
|
||||
const DirectoryEntry *getDirectory(const llvm::StringRef &Filename) {
|
||||
const DirectoryEntry *getDirectory(llvm::StringRef Filename) {
|
||||
return getDirectory(Filename.begin(), Filename.end());
|
||||
}
|
||||
const DirectoryEntry *getDirectory(const char *FileStart,const char *FileEnd);
|
||||
@ -197,7 +197,7 @@ class FileManager {
|
||||
/// getFile - Lookup, cache, and verify the specified file. This returns null
|
||||
/// if the file doesn't exist.
|
||||
///
|
||||
const FileEntry *getFile(const llvm::StringRef &Filename) {
|
||||
const FileEntry *getFile(llvm::StringRef Filename) {
|
||||
return getFile(Filename.begin(), Filename.end());
|
||||
}
|
||||
const FileEntry *getFile(const char *FilenameStart,
|
||||
@ -206,8 +206,8 @@ class FileManager {
|
||||
/// \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(const llvm::StringRef &Filename,
|
||||
off_t Size, time_t ModificationTime);
|
||||
const FileEntry *getVirtualFile(llvm::StringRef Filename, off_t Size,
|
||||
time_t ModificationTime);
|
||||
void PrintStats() const;
|
||||
};
|
||||
|
||||
|
@ -61,6 +61,7 @@ class TargetInfo {
|
||||
std::string CXXABI;
|
||||
|
||||
unsigned HasAlignMac68kSupport : 1;
|
||||
unsigned RealTypeUsesObjCFPRet : 3;
|
||||
|
||||
// TargetInfo Constructor. Default initializes all fields.
|
||||
TargetInfo(const std::string &T);
|
||||
@ -87,6 +88,13 @@ class TargetInfo {
|
||||
SignedLongLong,
|
||||
UnsignedLongLong
|
||||
};
|
||||
|
||||
enum RealType {
|
||||
Float = 0,
|
||||
Double,
|
||||
LongDouble
|
||||
};
|
||||
|
||||
protected:
|
||||
IntType SizeType, IntMaxType, UIntMaxType, PtrDiffType, IntPtrType, WCharType,
|
||||
WIntType, Char16Type, Char32Type, Int64Type, SigAtomicType;
|
||||
@ -233,6 +241,12 @@ class TargetInfo {
|
||||
/// 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);
|
||||
}
|
||||
|
||||
///===---- Other target property query methods --------------------------===//
|
||||
|
||||
/// getTargetDefines - Appends the target-specific #define values for this
|
||||
|
@ -179,6 +179,8 @@ namespace driver {
|
||||
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;
|
||||
|
||||
/// getArgString - Return the input argument string at \arg Index.
|
||||
virtual const char *getArgString(unsigned Index) const = 0;
|
||||
|
@ -62,6 +62,9 @@ class Driver {
|
||||
/// command line.
|
||||
std::string Dir;
|
||||
|
||||
/// The original path to the clang executable.
|
||||
std::string ClangExecutable;
|
||||
|
||||
/// The path to the compiler resource directory.
|
||||
std::string ResourceDir;
|
||||
|
||||
@ -163,6 +166,11 @@ class Driver {
|
||||
const std::string &getTitle() { return DriverTitle; }
|
||||
void setTitle(std::string Value) { DriverTitle = Value; }
|
||||
|
||||
/// \brief Get the path to the main clang executable.
|
||||
std::string getClangProgramPath() const {
|
||||
return ClangExecutable;
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name Primary Functionality
|
||||
/// @{
|
||||
|
@ -230,6 +230,7 @@ def exported__symbols__list : Separate<"-exported_symbols_list">;
|
||||
def e : JoinedOrSeparate<"-e">;
|
||||
def fPIC : Flag<"-fPIC">, 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 fapple_kext : Flag<"-fapple-kext">, Group<f_Group>;
|
||||
def fasm : Flag<"-fasm">, Group<f_Group>;
|
||||
@ -356,6 +357,7 @@ 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 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]>;
|
||||
@ -436,11 +438,11 @@ def mfix_and_continue : Flag<"-mfix-and-continue">, Group<clang_ignored_m_Group>
|
||||
def mfloat_abi_EQ : Joined<"-mfloat-abi=">, Group<m_Group>;
|
||||
def mfpu_EQ : Joined<"-mfpu=">, Group<m_Group>;
|
||||
def mhard_float : Flag<"-mhard-float">, Group<m_Group>;
|
||||
def miphoneos_version_min_EQ : Joined<"-miphoneos-version-min=">, Group<m_Group>, Flags<[DriverOption]>;
|
||||
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 mkernel : Flag<"-mkernel">, Group<m_Group>;
|
||||
def mllvm : Separate<"-mllvm">;
|
||||
def mmacosx_version_min_EQ : Joined<"-mmacosx-version-min=">, Group<m_Group>, Flags<[DriverOption]>;
|
||||
def mmacosx_version_min_EQ : Joined<"-mmacosx-version-min=">, 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>;
|
||||
|
@ -84,9 +84,8 @@ class ToolChain {
|
||||
|
||||
// Helper methods
|
||||
|
||||
std::string GetFilePath(const Compilation &C, const char *Name) const;
|
||||
std::string GetProgramPath(const Compilation &C, const char *Name,
|
||||
bool WantFile = false) const;
|
||||
std::string GetFilePath(const char *Name) const;
|
||||
std::string GetProgramPath(const char *Name, bool WantFile = false) const;
|
||||
|
||||
// Platform defaults information
|
||||
|
||||
|
@ -69,8 +69,8 @@ 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", "")
|
||||
TYPE("ir", LLVM_BC, INVALID, "bc", "")
|
||||
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", "")
|
||||
|
||||
|
@ -63,7 +63,7 @@ ASTConsumer *CreateDeclContextPrinter();
|
||||
// times.
|
||||
ASTConsumer *CreatePCHGenerator(const Preprocessor &PP,
|
||||
llvm::raw_ostream *OS,
|
||||
const PCHReader *Chain,
|
||||
PCHReader *Chain,
|
||||
const char *isysroot = 0);
|
||||
|
||||
// Inheritance viewer: for C++ code, creates a graph of the inheritance
|
||||
|
36
include/clang/Frontend/PCHDeserializationListener.h
Normal file
36
include/clang/Frontend/PCHDeserializationListener.h
Normal file
@ -0,0 +1,36 @@
|
||||
//===- PCHDeserializationListener.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 PCHDeserializationListener class, which is notified
|
||||
// by the PCHReader whenever a type or declaration is deserialized.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_FRONTEND_PCH_DESERIALIZATION_LISTENER_H
|
||||
#define LLVM_CLANG_FRONTEND_PCH_DESERIALIZATION_LISTENER_H
|
||||
|
||||
#include "clang/Frontend/PCHBitCodes.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class Decl;
|
||||
class QualType;
|
||||
|
||||
class PCHDeserializationListener {
|
||||
protected:
|
||||
~PCHDeserializationListener() {}
|
||||
|
||||
public:
|
||||
virtual void TypeRead(pch::TypeID ID, QualType T) = 0;
|
||||
virtual void DeclRead(pch::DeclID ID, const Decl *D) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -59,12 +59,22 @@ class GotoStmt;
|
||||
class LabelStmt;
|
||||
class MacroDefinition;
|
||||
class NamedDecl;
|
||||
class PCHDeserializationListener;
|
||||
class Preprocessor;
|
||||
class Sema;
|
||||
class SwitchCase;
|
||||
class PCHReader;
|
||||
struct HeaderFileInfo;
|
||||
|
||||
struct PCHPredefinesBlock {
|
||||
/// \brief The file ID for this predefines buffer in a PCH file.
|
||||
FileID BufferID;
|
||||
|
||||
/// \brief This predefines buffer in a PCH file.
|
||||
llvm::StringRef Data;
|
||||
};
|
||||
typedef llvm::SmallVector<PCHPredefinesBlock, 2> PCHPredefinesBlocks;
|
||||
|
||||
/// \brief Abstract interface for callback invocations by the PCHReader.
|
||||
///
|
||||
/// While reading a PCH file, the PCHReader will call the methods of the
|
||||
@ -91,10 +101,7 @@ class PCHReaderListener {
|
||||
|
||||
/// \brief Receives the contents of the predefines buffer.
|
||||
///
|
||||
/// \param PCHPredef The start of the predefines buffer in the PCH
|
||||
/// file.
|
||||
///
|
||||
/// \param PCHBufferID The FileID for the PCH predefines buffer.
|
||||
/// \param Buffers Information about the predefines buffers.
|
||||
///
|
||||
/// \param OriginalFileName The original file name for the PCH, which will
|
||||
/// appear as an entry in the predefines buffer.
|
||||
@ -103,8 +110,7 @@ class PCHReaderListener {
|
||||
/// here.
|
||||
///
|
||||
/// \returns true to indicate the predefines are invalid or false otherwise.
|
||||
virtual bool ReadPredefinesBuffer(llvm::StringRef PCHPredef,
|
||||
FileID PCHBufferID,
|
||||
virtual bool ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
|
||||
llvm::StringRef OriginalFileName,
|
||||
std::string &SuggestedPredefines) {
|
||||
return false;
|
||||
@ -131,8 +137,7 @@ class PCHValidator : public PCHReaderListener {
|
||||
|
||||
virtual bool ReadLanguageOptions(const LangOptions &LangOpts);
|
||||
virtual bool ReadTargetTriple(llvm::StringRef Triple);
|
||||
virtual bool ReadPredefinesBuffer(llvm::StringRef PCHPredef,
|
||||
FileID PCHBufferID,
|
||||
virtual bool ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
|
||||
llvm::StringRef OriginalFileName,
|
||||
std::string &SuggestedPredefines);
|
||||
virtual void ReadHeaderFileInfo(const HeaderFileInfo &HFI, unsigned ID);
|
||||
@ -165,9 +170,12 @@ class PCHReader
|
||||
enum PCHReadResult { Success, Failure, IgnorePCH };
|
||||
friend class PCHValidator;
|
||||
private:
|
||||
/// \ brief The receiver of some callbacks invoked by PCHReader.
|
||||
/// \brief The receiver of some callbacks invoked by PCHReader.
|
||||
llvm::OwningPtr<PCHReaderListener> Listener;
|
||||
|
||||
/// \brief The receiver of deserialization events.
|
||||
PCHDeserializationListener *DeserializationListener;
|
||||
|
||||
SourceManager &SourceMgr;
|
||||
FileManager &FileMgr;
|
||||
Diagnostic &Diags;
|
||||
@ -483,15 +491,9 @@ class PCHReader
|
||||
~ReadingKindTracker() { Reader.ReadingKind = PrevKind; }
|
||||
};
|
||||
|
||||
/// \brief The file ID for the predefines buffer in the PCH file.
|
||||
FileID PCHPredefinesBufferID;
|
||||
|
||||
/// \brief Pointer to the beginning of the predefines buffer in the
|
||||
/// PCH file.
|
||||
const char *PCHPredefines;
|
||||
|
||||
/// \brief Length of the predefines buffer in the PCH file.
|
||||
unsigned PCHPredefinesLen;
|
||||
/// \brief All predefines buffers in all PCH files, to be treated as if
|
||||
/// concatenated.
|
||||
PCHPredefinesBlocks PCHPredefinesBuffers;
|
||||
|
||||
/// \brief Suggested contents of the predefines buffer, after this
|
||||
/// PCH file has been processed.
|
||||
@ -509,7 +511,7 @@ class PCHReader
|
||||
void MaybeAddSystemRootToFilename(std::string &Filename);
|
||||
|
||||
PCHReadResult ReadPCHBlock();
|
||||
bool CheckPredefinesBuffer(llvm::StringRef PCHPredef, FileID PCHBufferID);
|
||||
bool CheckPredefinesBuffers();
|
||||
bool ParseLineTable(llvm::SmallVectorImpl<uint64_t> &Record);
|
||||
PCHReadResult ReadSourceManagerBlock();
|
||||
PCHReadResult ReadSLocEntryRecord(unsigned ID);
|
||||
@ -576,6 +578,10 @@ class PCHReader
|
||||
Listener.reset(listener);
|
||||
}
|
||||
|
||||
void setDeserializationListener(PCHDeserializationListener *Listener) {
|
||||
DeserializationListener = Listener;
|
||||
}
|
||||
|
||||
/// \brief Set the Preprocessor to use.
|
||||
void setPreprocessor(Preprocessor &pp);
|
||||
|
||||
@ -602,6 +608,16 @@ class PCHReader
|
||||
/// \brief Read preprocessed entities into the
|
||||
virtual void ReadPreprocessedEntities();
|
||||
|
||||
/// \brief Returns the number of types found in this file.
|
||||
unsigned getTotalNumTypes() const {
|
||||
return static_cast<unsigned>(TypesLoaded.size());
|
||||
}
|
||||
|
||||
/// \brief Returns the number of declarations found in this file.
|
||||
unsigned getTotalNumDecls() const {
|
||||
return static_cast<unsigned>(DeclsLoaded.size());
|
||||
}
|
||||
|
||||
/// \brief Reads a TemplateArgumentLocInfo appropriate for the
|
||||
/// given TemplateArgument kind.
|
||||
TemplateArgumentLocInfo
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "clang/AST/DeclarationName.h"
|
||||
#include "clang/AST/TemplateBase.h"
|
||||
#include "clang/Frontend/PCHBitCodes.h"
|
||||
#include "clang/Frontend/PCHDeserializationListener.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include <map>
|
||||
@ -71,7 +72,7 @@ struct UnsafeQualTypeDenseMapInfo {
|
||||
/// representation of a given abstract syntax tree and its supporting
|
||||
/// data structures. This bitstream can be de-serialized via an
|
||||
/// instance of the PCHReader class.
|
||||
class PCHWriter {
|
||||
class PCHWriter : public PCHDeserializationListener {
|
||||
public:
|
||||
typedef llvm::SmallVector<uint64_t, 64> RecordData;
|
||||
|
||||
@ -79,6 +80,9 @@ class PCHWriter {
|
||||
/// \brief The bitstream writer used to emit this precompiled header.
|
||||
llvm::BitstreamWriter &Stream;
|
||||
|
||||
/// \brief The reader of existing PCH files, if we're chaining.
|
||||
PCHReader *Chain;
|
||||
|
||||
/// \brief Stores a declaration or a type to be written to the PCH file.
|
||||
class DeclOrType {
|
||||
public:
|
||||
@ -220,7 +224,7 @@ class PCHWriter {
|
||||
void WriteSubStmt(Stmt *S);
|
||||
|
||||
void WriteBlockInfoBlock();
|
||||
void WriteMetadata(ASTContext &Context, const PCHReader *Chain, const char *isysroot);
|
||||
void WriteMetadata(ASTContext &Context, const char *isysroot);
|
||||
void WriteLanguageOptions(const LangOptions &LangOpts);
|
||||
void WriteStatCache(MemorizeStatCalls &StatCalls);
|
||||
void WriteSourceManagerBlock(SourceManager &SourceMgr,
|
||||
@ -242,12 +246,12 @@ class PCHWriter {
|
||||
void WritePCHCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
|
||||
const char* isysroot);
|
||||
void WritePCHChain(Sema &SemaRef, MemorizeStatCalls *StatCalls,
|
||||
const PCHReader *Chain, const char* isysroot);
|
||||
const char* isysroot);
|
||||
|
||||
public:
|
||||
/// \brief Create a new precompiled header writer that outputs to
|
||||
/// the given bitstream.
|
||||
PCHWriter(llvm::BitstreamWriter &Stream);
|
||||
PCHWriter(llvm::BitstreamWriter &Stream, PCHReader *Chain);
|
||||
|
||||
/// \brief Write a precompiled header for the given semantic analysis.
|
||||
///
|
||||
@ -263,7 +267,7 @@ class PCHWriter {
|
||||
/// \param PPRec Record of the preprocessing actions that occurred while
|
||||
/// preprocessing this file, e.g., macro instantiations
|
||||
void WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls,
|
||||
const PCHReader *Chain, const char* isysroot);
|
||||
const char* isysroot);
|
||||
|
||||
/// \brief Emit a source location.
|
||||
void AddSourceLocation(SourceLocation Loc, RecordData &Record);
|
||||
@ -393,6 +397,10 @@ class PCHWriter {
|
||||
unsigned GetLabelID(LabelStmt *S);
|
||||
|
||||
unsigned getParmVarDeclAbbrev() const { return ParmVarDeclAbbrev; }
|
||||
|
||||
// PCHDeserializationListener implementation
|
||||
void TypeRead(pch::TypeID ID, QualType T);
|
||||
void DeclRead(pch::DeclID ID, const Decl *D);
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
@ -64,7 +64,7 @@ class RewriteBuffer {
|
||||
/// the buffer is specified relative to the original SourceBuffer. The
|
||||
/// text is inserted after the specified location.
|
||||
///
|
||||
void InsertText(unsigned OrigOffset, const llvm::StringRef &Str,
|
||||
void InsertText(unsigned OrigOffset, llvm::StringRef Str,
|
||||
bool InsertAfter = true);
|
||||
|
||||
|
||||
@ -72,14 +72,14 @@ class RewriteBuffer {
|
||||
/// 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, const llvm::StringRef &Str) {
|
||||
void InsertTextBefore(unsigned OrigOffset, llvm::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, const llvm::StringRef &Str) {
|
||||
void InsertTextAfter(unsigned OrigOffset, llvm::StringRef Str) {
|
||||
InsertText(OrigOffset, Str);
|
||||
}
|
||||
|
||||
@ -87,7 +87,7 @@ class RewriteBuffer {
|
||||
/// buffer with a new string. This is effectively a combined "remove/insert"
|
||||
/// operation.
|
||||
void ReplaceText(unsigned OrigOffset, unsigned OrigLength,
|
||||
const llvm::StringRef &NewStr);
|
||||
llvm::StringRef NewStr);
|
||||
|
||||
private: // Methods only usable by Rewriter.
|
||||
|
||||
@ -164,7 +164,7 @@ class Rewriter {
|
||||
/// 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.
|
||||
bool InsertText(SourceLocation Loc, const llvm::StringRef &Str,
|
||||
bool InsertText(SourceLocation Loc, llvm::StringRef Str,
|
||||
bool InsertAfter = true);
|
||||
|
||||
/// InsertTextAfter - Insert the specified string at the specified location in
|
||||
@ -172,7 +172,7 @@ class Rewriter {
|
||||
/// 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, const llvm::StringRef &Str) {
|
||||
bool InsertTextAfter(SourceLocation Loc, llvm::StringRef Str) {
|
||||
return InsertText(Loc, Str);
|
||||
}
|
||||
|
||||
@ -181,7 +181,7 @@ class Rewriter {
|
||||
/// 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, const llvm::StringRef &Str) {
|
||||
bool InsertTextBefore(SourceLocation Loc, llvm::StringRef Str) {
|
||||
return InsertText(Loc, Str, false);
|
||||
}
|
||||
|
||||
@ -192,7 +192,7 @@ class Rewriter {
|
||||
/// buffer with a new string. This is effectively a combined "remove/insert"
|
||||
/// operation.
|
||||
bool ReplaceText(SourceLocation Start, unsigned OrigLength,
|
||||
const llvm::StringRef &NewStr);
|
||||
llvm::StringRef NewStr);
|
||||
|
||||
/// ReplaceStmt - This replaces a Stmt/Expr with another, using the pretty
|
||||
/// printer to generate the replacement code. This returns true if the input
|
||||
|
@ -223,7 +223,7 @@ ClassTemplateDecl::getInjectedClassNameSpecialization() {
|
||||
} else if (NonTypeTemplateParmDecl *NTTP =
|
||||
dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
|
||||
Expr *E = new (Context) DeclRefExpr(NTTP,
|
||||
NTTP->getType().getNonReferenceType(),
|
||||
NTTP->getType().getNonLValueExprType(Context),
|
||||
NTTP->getLocation());
|
||||
TemplateArgs.push_back(TemplateArgument(E));
|
||||
} else {
|
||||
|
@ -684,6 +684,8 @@ const char *CastExpr::getCastKindName() const {
|
||||
return "Unknown";
|
||||
case CastExpr::CK_BitCast:
|
||||
return "BitCast";
|
||||
case CastExpr::CK_LValueBitCast:
|
||||
return "LValueBitCast";
|
||||
case CastExpr::CK_NoOp:
|
||||
return "NoOp";
|
||||
case CastExpr::CK_BaseToDerived:
|
||||
|
@ -563,6 +563,7 @@ bool PointerExprEvaluator::VisitCastExpr(CastExpr* E) {
|
||||
|
||||
case CastExpr::CK_NoOp:
|
||||
case CastExpr::CK_BitCast:
|
||||
case CastExpr::CK_LValueBitCast:
|
||||
case CastExpr::CK_AnyPointerToObjCPointerCast:
|
||||
case CastExpr::CK_AnyPointerToBlockPointerCast:
|
||||
return Visit(SubExpr);
|
||||
|
@ -992,7 +992,7 @@ const char *BuiltinType::getName(const LangOptions &LO) const {
|
||||
|
||||
void FunctionType::ANCHOR() {} // Key function for FunctionType.
|
||||
|
||||
QualType QualType::getCallResultType(ASTContext &Context) const {
|
||||
QualType QualType::getNonLValueExprType(ASTContext &Context) const {
|
||||
if (const ReferenceType *RefType = getTypePtr()->getAs<ReferenceType>())
|
||||
return RefType->getPointeeType();
|
||||
|
||||
@ -1002,7 +1002,7 @@ QualType QualType::getCallResultType(ASTContext &Context) const {
|
||||
//
|
||||
// See also C99 6.3.2.1p2.
|
||||
if (!Context.getLangOptions().CPlusPlus ||
|
||||
!getTypePtr()->isDependentType() && !getTypePtr()->isRecordType())
|
||||
(!getTypePtr()->isDependentType() && !getTypePtr()->isRecordType()))
|
||||
return getUnqualifiedType();
|
||||
|
||||
return *this;
|
||||
|
@ -331,8 +331,8 @@ const FileEntry *FileManager::getFile(const char *NameStart,
|
||||
}
|
||||
|
||||
const FileEntry *
|
||||
FileManager::getVirtualFile(const llvm::StringRef &Filename,
|
||||
off_t Size, time_t ModificationTime) {
|
||||
FileManager::getVirtualFile(llvm::StringRef Filename, off_t Size,
|
||||
time_t ModificationTime) {
|
||||
const char *NameStart = Filename.begin(), *NameEnd = Filename.end();
|
||||
|
||||
++NumFileLookups;
|
||||
|
@ -55,6 +55,9 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) {
|
||||
"i64:64:64-f32:32:32-f64:64:64-n32";
|
||||
UserLabelPrefix = "_";
|
||||
HasAlignMac68kSupport = false;
|
||||
|
||||
// Default to no types using fpret.
|
||||
RealTypeUsesObjCFPRet = 0;
|
||||
}
|
||||
|
||||
// Out of line virtual dtor for TargetInfo.
|
||||
|
@ -1245,6 +1245,11 @@ class X86_32TargetInfo : public X86TargetInfo {
|
||||
PtrDiffType = SignedInt;
|
||||
IntPtrType = SignedInt;
|
||||
RegParmMax = 3;
|
||||
|
||||
// Use fpret for all types.
|
||||
RealTypeUsesObjCFPRet = ((1 << TargetInfo::Float) |
|
||||
(1 << TargetInfo::Double) |
|
||||
(1 << TargetInfo::LongDouble));
|
||||
}
|
||||
virtual const char *getVAListDeclaration() const {
|
||||
return "typedef char* __builtin_va_list;";
|
||||
@ -1411,6 +1416,9 @@ class X86_64TargetInfo : public X86TargetInfo {
|
||||
DescriptionString = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
|
||||
"i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-"
|
||||
"a0:0:64-s0:64:64-f80:128:128-n8:16:32:64";
|
||||
|
||||
// Use fpret only for long double.
|
||||
RealTypeUsesObjCFPRet = (1 << TargetInfo::LongDouble);
|
||||
}
|
||||
virtual const char *getVAListDeclaration() const {
|
||||
return "typedef struct __va_list_tag {"
|
||||
|
@ -2438,6 +2438,7 @@ void GRExprEngine::VisitCast(CastExpr *CastE, Expr *Ex, ExplodedNode *Pred,
|
||||
case CastExpr::CK_Unknown:
|
||||
case CastExpr::CK_ArrayToPointerDecay:
|
||||
case CastExpr::CK_BitCast:
|
||||
case CastExpr::CK_LValueBitCast:
|
||||
case CastExpr::CK_IntegralCast:
|
||||
case CastExpr::CK_IntegralToPointer:
|
||||
case CastExpr::CK_PointerToIntegral:
|
||||
|
@ -36,7 +36,7 @@ static bool IsLLVMStringRef(QualType T) {
|
||||
|
||||
/// Check whether the declaration is semantically inside the top-level
|
||||
/// namespace named by ns.
|
||||
static bool InNamespace(const Decl *D, const llvm::StringRef &NS) {
|
||||
static bool InNamespace(const Decl *D, llvm::StringRef NS) {
|
||||
const DeclContext *DC = D->getDeclContext();
|
||||
const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(D->getDeclContext());
|
||||
if (!ND)
|
||||
|
@ -253,7 +253,7 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
|
||||
CodeGenTypes &Types = CGM.getTypes();
|
||||
const CGFunctionInfo &FnInfo = Types.getFunctionInfo(ResultType, Args,
|
||||
FunctionType::ExtInfo());
|
||||
if (CGM.ReturnTypeUsesSret(FnInfo))
|
||||
if (CGM.ReturnTypeUsesSRet(FnInfo))
|
||||
flags |= BLOCK_USE_STRET;
|
||||
}
|
||||
const llvm::IntegerType *IntTy = cast<llvm::IntegerType>(
|
||||
|
@ -564,10 +564,28 @@ static void CreateCoercedStore(llvm::Value *Src,
|
||||
|
||||
/***/
|
||||
|
||||
bool CodeGenModule::ReturnTypeUsesSret(const CGFunctionInfo &FI) {
|
||||
bool CodeGenModule::ReturnTypeUsesSRet(const CGFunctionInfo &FI) {
|
||||
return FI.getReturnInfo().isIndirect();
|
||||
}
|
||||
|
||||
bool CodeGenModule::ReturnTypeUsesFPRet(QualType ResultType) {
|
||||
if (const BuiltinType *BT = ResultType->getAs<BuiltinType>()) {
|
||||
switch (BT->getKind()) {
|
||||
default:
|
||||
return false;
|
||||
case BuiltinType::Float:
|
||||
return getContext().Target.useObjCFPRetForRealType(TargetInfo::Float);
|
||||
case BuiltinType::Double:
|
||||
return getContext().Target.useObjCFPRetForRealType(TargetInfo::Double);
|
||||
case BuiltinType::LongDouble:
|
||||
return getContext().Target.useObjCFPRetForRealType(
|
||||
TargetInfo::LongDouble);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const llvm::FunctionType *CodeGenTypes::GetFunctionType(GlobalDecl GD) {
|
||||
const CGFunctionInfo &FI = getFunctionInfo(GD);
|
||||
|
||||
@ -841,7 +859,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
|
||||
llvm::Function::arg_iterator AI = Fn->arg_begin();
|
||||
|
||||
// Name the struct return argument.
|
||||
if (CGM.ReturnTypeUsesSret(FI)) {
|
||||
if (CGM.ReturnTypeUsesSRet(FI)) {
|
||||
AI->setName("agg.result");
|
||||
++AI;
|
||||
}
|
||||
@ -1116,7 +1134,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
|
||||
|
||||
// If the call returns a temporary with struct return, create a temporary
|
||||
// alloca to hold the result, unless one is given to us.
|
||||
if (CGM.ReturnTypeUsesSret(CallInfo)) {
|
||||
if (CGM.ReturnTypeUsesSRet(CallInfo)) {
|
||||
llvm::Value *Value = ReturnValue.getValue();
|
||||
if (!Value)
|
||||
Value = CreateMemTemp(RetTy);
|
||||
|
@ -340,7 +340,7 @@ static void EmitBaseInitializer(CodeGenFunction &CGF,
|
||||
|
||||
if (CGF.Exceptions && !BaseClassDecl->hasTrivialDestructor()) {
|
||||
// FIXME: Is this OK for C++0x delegating constructors?
|
||||
CodeGenFunction::CleanupBlock Cleanup(CGF, CodeGenFunction::EHCleanup);
|
||||
CodeGenFunction::CleanupBlock Cleanup(CGF, EHCleanup);
|
||||
|
||||
CXXDestructorDecl *DD = BaseClassDecl->getDestructor();
|
||||
CGF.EmitCXXDestructorCall(DD, Dtor_Base, isBaseVirtual, V);
|
||||
@ -534,7 +534,7 @@ static void EmitMemberInitializer(CodeGenFunction &CGF,
|
||||
CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
|
||||
if (!RD->hasTrivialDestructor()) {
|
||||
// FIXME: Is this OK for C++0x delegating constructors?
|
||||
CodeGenFunction::CleanupBlock Cleanup(CGF, CodeGenFunction::EHCleanup);
|
||||
CodeGenFunction::CleanupBlock Cleanup(CGF, EHCleanup);
|
||||
|
||||
llvm::Value *ThisPtr = CGF.LoadCXXThis();
|
||||
LValue LHS = CGF.EmitLValueForField(ThisPtr, Field, 0);
|
||||
|
@ -537,11 +537,17 @@ CGDebugInfo::getOrCreateMethodType(const CXXMethodDecl *Method,
|
||||
llvm::DIType ThisPtrType =
|
||||
DebugFactory.CreateArtificialType(getOrCreateType(ThisPtr, Unit));
|
||||
|
||||
if (Method->getTypeQualifiers() && Qualifiers::Const)
|
||||
unsigned Quals = Method->getTypeQualifiers();
|
||||
if (Quals & Qualifiers::Const)
|
||||
ThisPtrType =
|
||||
DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_const_type,
|
||||
Unit, "", Unit,
|
||||
0, 0, 0, 0, 0, ThisPtrType);
|
||||
if (Quals & Qualifiers::Volatile)
|
||||
ThisPtrType =
|
||||
DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_volatile_type,
|
||||
Unit, "", Unit,
|
||||
0, 0, 0, 0, 0, ThisPtrType);
|
||||
|
||||
TypeCache[ThisPtr.getAsOpaquePtr()] = ThisPtrType;
|
||||
Elts.push_back(ThisPtrType);
|
||||
|
@ -388,6 +388,58 @@ const llvm::Type *CodeGenFunction::BuildByRefType(const ValueDecl *D) {
|
||||
return Info.first;
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct CallArrayDtor : EHScopeStack::LazyCleanup {
|
||||
CallArrayDtor(const CXXDestructorDecl *Dtor,
|
||||
const ConstantArrayType *Type,
|
||||
llvm::Value *Loc)
|
||||
: Dtor(Dtor), Type(Type), Loc(Loc) {}
|
||||
|
||||
const CXXDestructorDecl *Dtor;
|
||||
const ConstantArrayType *Type;
|
||||
llvm::Value *Loc;
|
||||
|
||||
void Emit(CodeGenFunction &CGF, bool IsForEH) {
|
||||
QualType BaseElementTy = CGF.getContext().getBaseElementType(Type);
|
||||
const llvm::Type *BasePtr = CGF.ConvertType(BaseElementTy);
|
||||
BasePtr = llvm::PointerType::getUnqual(BasePtr);
|
||||
llvm::Value *BaseAddrPtr = CGF.Builder.CreateBitCast(Loc, BasePtr);
|
||||
CGF.EmitCXXAggrDestructorCall(Dtor, Type, BaseAddrPtr);
|
||||
}
|
||||
};
|
||||
|
||||
struct CallVarDtor : EHScopeStack::LazyCleanup {
|
||||
CallVarDtor(const CXXDestructorDecl *Dtor,
|
||||
llvm::Value *NRVOFlag,
|
||||
llvm::Value *Loc)
|
||||
: Dtor(Dtor), NRVOFlag(NRVOFlag), Loc(Loc) {}
|
||||
|
||||
const CXXDestructorDecl *Dtor;
|
||||
llvm::Value *NRVOFlag;
|
||||
llvm::Value *Loc;
|
||||
|
||||
void Emit(CodeGenFunction &CGF, bool IsForEH) {
|
||||
// Along the exceptions path we always execute the dtor.
|
||||
bool NRVO = !IsForEH && NRVOFlag;
|
||||
|
||||
llvm::BasicBlock *SkipDtorBB = 0;
|
||||
if (NRVO) {
|
||||
// If we exited via NRVO, we skip the destructor call.
|
||||
llvm::BasicBlock *RunDtorBB = CGF.createBasicBlock("nrvo.unused");
|
||||
SkipDtorBB = CGF.createBasicBlock("nrvo.skipdtor");
|
||||
llvm::Value *DidNRVO = CGF.Builder.CreateLoad(NRVOFlag, "nrvo.val");
|
||||
CGF.Builder.CreateCondBr(DidNRVO, SkipDtorBB, RunDtorBB);
|
||||
CGF.EmitBlock(RunDtorBB);
|
||||
}
|
||||
|
||||
CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete,
|
||||
/*ForVirtualBase=*/false, Loc);
|
||||
|
||||
if (NRVO) CGF.EmitBlock(SkipDtorBB);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// EmitLocalBlockVarDecl - Emit code and set up an entry in LocalDeclMap for a
|
||||
/// variable declaration with auto, register, or no storage class specifier.
|
||||
/// These turn into simple stack objects, or GlobalValues depending on target.
|
||||
@ -686,53 +738,11 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D,
|
||||
|
||||
if (const ConstantArrayType *Array =
|
||||
getContext().getAsConstantArrayType(Ty)) {
|
||||
CleanupBlock Scope(*this, NormalCleanup);
|
||||
|
||||
QualType BaseElementTy = getContext().getBaseElementType(Array);
|
||||
const llvm::Type *BasePtr = ConvertType(BaseElementTy);
|
||||
BasePtr = llvm::PointerType::getUnqual(BasePtr);
|
||||
llvm::Value *BaseAddrPtr =
|
||||
Builder.CreateBitCast(Loc, BasePtr);
|
||||
EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr);
|
||||
|
||||
if (Exceptions) {
|
||||
Scope.beginEHCleanup();
|
||||
|
||||
QualType BaseElementTy = getContext().getBaseElementType(Array);
|
||||
const llvm::Type *BasePtr = ConvertType(BaseElementTy);
|
||||
BasePtr = llvm::PointerType::getUnqual(BasePtr);
|
||||
llvm::Value *BaseAddrPtr =
|
||||
Builder.CreateBitCast(Loc, BasePtr);
|
||||
EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr);
|
||||
}
|
||||
EHStack.pushLazyCleanup<CallArrayDtor>(NormalAndEHCleanup,
|
||||
D, Array, Loc);
|
||||
} else {
|
||||
// Normal destruction.
|
||||
CleanupBlock Scope(*this, NormalCleanup);
|
||||
|
||||
llvm::BasicBlock *SkipDtor = 0;
|
||||
if (NRVO) {
|
||||
// If we exited via NRVO, we skip the destructor call.
|
||||
llvm::BasicBlock *NoNRVO = createBasicBlock("nrvo.unused");
|
||||
SkipDtor = createBasicBlock("nrvo.skipdtor");
|
||||
Builder.CreateCondBr(Builder.CreateLoad(NRVOFlag, "nrvo.val"),
|
||||
SkipDtor,
|
||||
NoNRVO);
|
||||
EmitBlock(NoNRVO);
|
||||
}
|
||||
|
||||
// We don't call the destructor along the normal edge if we're
|
||||
// applying the NRVO.
|
||||
EmitCXXDestructorCall(D, Dtor_Complete, /*ForVirtualBase=*/false,
|
||||
Loc);
|
||||
|
||||
if (NRVO) EmitBlock(SkipDtor);
|
||||
|
||||
// Along the exceptions path we always execute the dtor.
|
||||
if (Exceptions) {
|
||||
Scope.beginEHCleanup();
|
||||
EmitCXXDestructorCall(D, Dtor_Complete, /*ForVirtualBase=*/false,
|
||||
Loc);
|
||||
}
|
||||
EHStack.pushLazyCleanup<CallVarDtor>(NormalAndEHCleanup,
|
||||
D, NRVOFlag, Loc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -62,12 +62,37 @@ EHScopeStack::getEnclosingEHCleanup(iterator it) const {
|
||||
return stabilize(it);
|
||||
return cast<EHCleanupScope>(*it).getEnclosingEHCleanup();
|
||||
}
|
||||
if (isa<EHLazyCleanupScope>(*it)) {
|
||||
if (cast<EHLazyCleanupScope>(*it).isEHCleanup())
|
||||
return stabilize(it);
|
||||
return cast<EHLazyCleanupScope>(*it).getEnclosingEHCleanup();
|
||||
}
|
||||
++it;
|
||||
} while (it != end());
|
||||
return stable_end();
|
||||
}
|
||||
|
||||
|
||||
void *EHScopeStack::pushLazyCleanup(CleanupKind Kind, size_t Size) {
|
||||
assert(((Size % sizeof(void*)) == 0) && "cleanup type is misaligned");
|
||||
char *Buffer = allocate(EHLazyCleanupScope::getSizeForCleanupSize(Size));
|
||||
bool IsNormalCleanup = Kind != EHCleanup;
|
||||
bool IsEHCleanup = Kind != NormalCleanup;
|
||||
EHLazyCleanupScope *Scope =
|
||||
new (Buffer) EHLazyCleanupScope(IsNormalCleanup,
|
||||
IsEHCleanup,
|
||||
Size,
|
||||
BranchFixups.size(),
|
||||
InnermostNormalCleanup,
|
||||
InnermostEHCleanup);
|
||||
if (IsNormalCleanup)
|
||||
InnermostNormalCleanup = stable_begin();
|
||||
if (IsEHCleanup)
|
||||
InnermostEHCleanup = stable_begin();
|
||||
|
||||
return Scope->getCleanupBuffer();
|
||||
}
|
||||
|
||||
void EHScopeStack::pushCleanup(llvm::BasicBlock *NormalEntry,
|
||||
llvm::BasicBlock *NormalExit,
|
||||
llvm::BasicBlock *EHEntry,
|
||||
@ -86,11 +111,18 @@ void EHScopeStack::pushCleanup(llvm::BasicBlock *NormalEntry,
|
||||
void EHScopeStack::popCleanup() {
|
||||
assert(!empty() && "popping exception stack when not empty");
|
||||
|
||||
assert(isa<EHCleanupScope>(*begin()));
|
||||
EHCleanupScope &Cleanup = cast<EHCleanupScope>(*begin());
|
||||
InnermostNormalCleanup = Cleanup.getEnclosingNormalCleanup();
|
||||
InnermostEHCleanup = Cleanup.getEnclosingEHCleanup();
|
||||
StartOfData += EHCleanupScope::getSize();
|
||||
if (isa<EHLazyCleanupScope>(*begin())) {
|
||||
EHLazyCleanupScope &Cleanup = cast<EHLazyCleanupScope>(*begin());
|
||||
InnermostNormalCleanup = Cleanup.getEnclosingNormalCleanup();
|
||||
InnermostEHCleanup = Cleanup.getEnclosingEHCleanup();
|
||||
StartOfData += Cleanup.getAllocatedSize();
|
||||
} else {
|
||||
assert(isa<EHCleanupScope>(*begin()));
|
||||
EHCleanupScope &Cleanup = cast<EHCleanupScope>(*begin());
|
||||
InnermostNormalCleanup = Cleanup.getEnclosingNormalCleanup();
|
||||
InnermostEHCleanup = Cleanup.getEnclosingEHCleanup();
|
||||
StartOfData += EHCleanupScope::getSize();
|
||||
}
|
||||
|
||||
// Check whether we can shrink the branch-fixups stack.
|
||||
if (!BranchFixups.empty()) {
|
||||
@ -144,7 +176,11 @@ void EHScopeStack::popNullFixups() {
|
||||
assert(hasNormalCleanups());
|
||||
|
||||
EHScopeStack::iterator it = find(InnermostNormalCleanup);
|
||||
unsigned MinSize = cast<EHCleanupScope>(*it).getFixupDepth();
|
||||
unsigned MinSize;
|
||||
if (isa<EHCleanupScope>(*it))
|
||||
MinSize = cast<EHCleanupScope>(*it).getFixupDepth();
|
||||
else
|
||||
MinSize = cast<EHLazyCleanupScope>(*it).getFixupDepth();
|
||||
assert(BranchFixups.size() >= MinSize && "fixup stack out of order");
|
||||
|
||||
while (BranchFixups.size() > MinSize &&
|
||||
@ -364,6 +400,33 @@ static llvm::Constant *getCleanupValue(CodeGenFunction &CGF) {
|
||||
return llvm::ConstantInt::get(CGF.Builder.getInt32Ty(), 0);
|
||||
}
|
||||
|
||||
namespace {
|
||||
/// A cleanup to free the exception object if its initialization
|
||||
/// throws.
|
||||
struct FreeExceptionCleanup : EHScopeStack::LazyCleanup {
|
||||
FreeExceptionCleanup(llvm::Value *ShouldFreeVar,
|
||||
llvm::Value *ExnLocVar)
|
||||
: ShouldFreeVar(ShouldFreeVar), ExnLocVar(ExnLocVar) {}
|
||||
|
||||
llvm::Value *ShouldFreeVar;
|
||||
llvm::Value *ExnLocVar;
|
||||
|
||||
void Emit(CodeGenFunction &CGF, bool IsForEH) {
|
||||
llvm::BasicBlock *FreeBB = CGF.createBasicBlock("free-exnobj");
|
||||
llvm::BasicBlock *DoneBB = CGF.createBasicBlock("free-exnobj.done");
|
||||
|
||||
llvm::Value *ShouldFree = CGF.Builder.CreateLoad(ShouldFreeVar,
|
||||
"should-free-exnobj");
|
||||
CGF.Builder.CreateCondBr(ShouldFree, FreeBB, DoneBB);
|
||||
CGF.EmitBlock(FreeBB);
|
||||
llvm::Value *ExnLocLocal = CGF.Builder.CreateLoad(ExnLocVar, "exnobj");
|
||||
CGF.Builder.CreateCall(getFreeExceptionFn(CGF), ExnLocLocal)
|
||||
->setDoesNotThrow();
|
||||
CGF.EmitBlock(DoneBB);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Emits an exception expression into the given location. This
|
||||
// differs from EmitAnyExprToMem only in that, if a final copy-ctor
|
||||
// call is required, an exception within that copy ctor causes
|
||||
@ -388,22 +451,11 @@ static void EmitAnyExprToExn(CodeGenFunction &CGF, const Expr *E,
|
||||
|
||||
// Make sure the exception object is cleaned up if there's an
|
||||
// exception during initialization.
|
||||
// FIXME: StmtExprs probably force this to include a non-EH
|
||||
// handler.
|
||||
{
|
||||
CodeGenFunction::CleanupBlock Cleanup(CGF, CodeGenFunction::EHCleanup);
|
||||
llvm::BasicBlock *FreeBB = CGF.createBasicBlock("free-exnobj");
|
||||
llvm::BasicBlock *DoneBB = CGF.createBasicBlock("free-exnobj.done");
|
||||
|
||||
llvm::Value *ShouldFree = CGF.Builder.CreateLoad(ShouldFreeVar,
|
||||
"should-free-exnobj");
|
||||
CGF.Builder.CreateCondBr(ShouldFree, FreeBB, DoneBB);
|
||||
CGF.EmitBlock(FreeBB);
|
||||
llvm::Value *ExnLocLocal = CGF.Builder.CreateLoad(ExnLocVar, "exnobj");
|
||||
CGF.Builder.CreateCall(getFreeExceptionFn(CGF), ExnLocLocal)
|
||||
->setDoesNotThrow();
|
||||
CGF.EmitBlock(DoneBB);
|
||||
}
|
||||
// FIXME: stmt expressions might require this to be a normal
|
||||
// cleanup, too.
|
||||
CGF.EHStack.pushLazyCleanup<FreeExceptionCleanup>(EHCleanup,
|
||||
ShouldFreeVar,
|
||||
ExnLocVar);
|
||||
EHScopeStack::stable_iterator Cleanup = CGF.EHStack.stable_begin();
|
||||
|
||||
CGF.Builder.CreateStore(ExnLoc, ExnLocVar);
|
||||
@ -598,13 +650,28 @@ void CodeGenFunction::EnterCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) {
|
||||
/// affect exception handling. Currently, the only non-EH scopes are
|
||||
/// normal-only cleanup scopes.
|
||||
static bool isNonEHScope(const EHScope &S) {
|
||||
return isa<EHCleanupScope>(S) && !cast<EHCleanupScope>(S).isEHCleanup();
|
||||
switch (S.getKind()) {
|
||||
case EHScope::Cleanup:
|
||||
return !cast<EHCleanupScope>(S).isEHCleanup();
|
||||
case EHScope::LazyCleanup:
|
||||
return !cast<EHLazyCleanupScope>(S).isEHCleanup();
|
||||
case EHScope::Filter:
|
||||
case EHScope::Catch:
|
||||
case EHScope::Terminate:
|
||||
return false;
|
||||
}
|
||||
|
||||
// Suppress warning.
|
||||
return false;
|
||||
}
|
||||
|
||||
llvm::BasicBlock *CodeGenFunction::getInvokeDestImpl() {
|
||||
assert(EHStack.requiresLandingPad());
|
||||
assert(!EHStack.empty());
|
||||
|
||||
if (!Exceptions)
|
||||
return 0;
|
||||
|
||||
// Check the innermost scope for a cached landing pad. If this is
|
||||
// a non-EH cleanup, we'll check enclosing scopes in EmitLandingPad.
|
||||
llvm::BasicBlock *LP = EHStack.begin()->getCachedLandingPad();
|
||||
@ -713,6 +780,12 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() {
|
||||
I != E; ++I) {
|
||||
|
||||
switch (I->getKind()) {
|
||||
case EHScope::LazyCleanup:
|
||||
if (!HasEHCleanup)
|
||||
HasEHCleanup = cast<EHLazyCleanupScope>(*I).isEHCleanup();
|
||||
// We otherwise don't care about cleanups.
|
||||
continue;
|
||||
|
||||
case EHScope::Cleanup:
|
||||
if (!HasEHCleanup)
|
||||
HasEHCleanup = cast<EHCleanupScope>(*I).isEHCleanup();
|
||||
@ -947,19 +1020,45 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() {
|
||||
return LP;
|
||||
}
|
||||
|
||||
namespace {
|
||||
/// A cleanup to call __cxa_end_catch. In many cases, the caught
|
||||
/// exception type lets us state definitively that the thrown exception
|
||||
/// type does not have a destructor. In particular:
|
||||
/// - Catch-alls tell us nothing, so we have to conservatively
|
||||
/// assume that the thrown exception might have a destructor.
|
||||
/// - Catches by reference behave according to their base types.
|
||||
/// - Catches of non-record types will only trigger for exceptions
|
||||
/// of non-record types, which never have destructors.
|
||||
/// - Catches of record types can trigger for arbitrary subclasses
|
||||
/// of the caught type, so we have to assume the actual thrown
|
||||
/// exception type might have a throwing destructor, even if the
|
||||
/// caught type's destructor is trivial or nothrow.
|
||||
struct CallEndCatch : EHScopeStack::LazyCleanup {
|
||||
CallEndCatch(bool MightThrow) : MightThrow(MightThrow) {}
|
||||
bool MightThrow;
|
||||
|
||||
void Emit(CodeGenFunction &CGF, bool IsForEH) {
|
||||
if (!MightThrow) {
|
||||
CGF.Builder.CreateCall(getEndCatchFn(CGF))->setDoesNotThrow();
|
||||
return;
|
||||
}
|
||||
|
||||
CGF.EmitCallOrInvoke(getEndCatchFn(CGF), 0, 0);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Emits a call to __cxa_begin_catch and enters a cleanup to call
|
||||
/// __cxa_end_catch.
|
||||
static llvm::Value *CallBeginCatch(CodeGenFunction &CGF, llvm::Value *Exn) {
|
||||
///
|
||||
/// \param EndMightThrow - true if __cxa_end_catch might throw
|
||||
static llvm::Value *CallBeginCatch(CodeGenFunction &CGF,
|
||||
llvm::Value *Exn,
|
||||
bool EndMightThrow) {
|
||||
llvm::CallInst *Call = CGF.Builder.CreateCall(getBeginCatchFn(CGF), Exn);
|
||||
Call->setDoesNotThrow();
|
||||
|
||||
{
|
||||
CodeGenFunction::CleanupBlock EndCatchCleanup(CGF,
|
||||
CodeGenFunction::NormalAndEHCleanup);
|
||||
|
||||
// __cxa_end_catch never throws, so this can just be a call.
|
||||
CGF.Builder.CreateCall(getEndCatchFn(CGF))->setDoesNotThrow();
|
||||
}
|
||||
CGF.EHStack.pushLazyCleanup<CallEndCatch>(NormalAndEHCleanup, EndMightThrow);
|
||||
|
||||
return Call;
|
||||
}
|
||||
@ -979,8 +1078,11 @@ static void InitCatchParam(CodeGenFunction &CGF,
|
||||
// If we're catching by reference, we can just cast the object
|
||||
// pointer to the appropriate pointer.
|
||||
if (isa<ReferenceType>(CatchType)) {
|
||||
bool EndCatchMightThrow = cast<ReferenceType>(CatchType)->getPointeeType()
|
||||
->isRecordType();
|
||||
|
||||
// __cxa_begin_catch returns the adjusted object pointer.
|
||||
llvm::Value *AdjustedExn = CallBeginCatch(CGF, Exn);
|
||||
llvm::Value *AdjustedExn = CallBeginCatch(CGF, Exn, EndCatchMightThrow);
|
||||
llvm::Value *ExnCast =
|
||||
CGF.Builder.CreateBitCast(AdjustedExn, LLVMCatchTy, "exn.byref");
|
||||
CGF.Builder.CreateStore(ExnCast, ParamAddr);
|
||||
@ -991,7 +1093,7 @@ static void InitCatchParam(CodeGenFunction &CGF,
|
||||
bool IsComplex = false;
|
||||
if (!CGF.hasAggregateLLVMType(CatchType) ||
|
||||
(IsComplex = CatchType->isAnyComplexType())) {
|
||||
llvm::Value *AdjustedExn = CallBeginCatch(CGF, Exn);
|
||||
llvm::Value *AdjustedExn = CallBeginCatch(CGF, Exn, false);
|
||||
|
||||
// If the catch type is a pointer type, __cxa_begin_catch returns
|
||||
// the pointer by value.
|
||||
@ -1026,7 +1128,7 @@ static void InitCatchParam(CodeGenFunction &CGF,
|
||||
const llvm::Type *PtrTy = LLVMCatchTy->getPointerTo(0); // addrspace 0 ok
|
||||
|
||||
if (RD->hasTrivialCopyConstructor()) {
|
||||
llvm::Value *AdjustedExn = CallBeginCatch(CGF, Exn);
|
||||
llvm::Value *AdjustedExn = CallBeginCatch(CGF, Exn, true);
|
||||
llvm::Value *Cast = CGF.Builder.CreateBitCast(AdjustedExn, PtrTy);
|
||||
CGF.EmitAggregateCopy(ParamAddr, Cast, CatchType);
|
||||
return;
|
||||
@ -1059,7 +1161,7 @@ static void InitCatchParam(CodeGenFunction &CGF,
|
||||
CGF.EHStack.popTerminate();
|
||||
|
||||
// Finally we can call __cxa_begin_catch.
|
||||
CallBeginCatch(CGF, Exn);
|
||||
CallBeginCatch(CGF, Exn, true);
|
||||
}
|
||||
|
||||
/// Begins a catch statement by initializing the catch variable and
|
||||
@ -1092,7 +1194,7 @@ static void BeginCatch(CodeGenFunction &CGF,
|
||||
VarDecl *CatchParam = S->getExceptionDecl();
|
||||
if (!CatchParam) {
|
||||
llvm::Value *Exn = CGF.Builder.CreateLoad(CGF.getExceptionSlot(), "exn");
|
||||
CallBeginCatch(CGF, Exn);
|
||||
CallBeginCatch(CGF, Exn, true);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1100,6 +1202,14 @@ static void BeginCatch(CodeGenFunction &CGF,
|
||||
CGF.EmitLocalBlockVarDecl(*CatchParam, &InitCatchParam);
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct CallRethrow : EHScopeStack::LazyCleanup {
|
||||
void Emit(CodeGenFunction &CGF, bool IsForEH) {
|
||||
CGF.EmitCallOrInvoke(getReThrowFn(CGF), 0, 0);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) {
|
||||
unsigned NumHandlers = S.getNumHandlers();
|
||||
EHCatchScope &CatchScope = cast<EHCatchScope>(*EHStack.begin());
|
||||
@ -1140,12 +1250,10 @@ void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) {
|
||||
BeginCatch(*this, C);
|
||||
|
||||
// If there's an implicit rethrow, push a normal "cleanup" to call
|
||||
// _cxa_rethrow. This needs to happen before _cxa_end_catch is
|
||||
// called.
|
||||
if (ImplicitRethrow) {
|
||||
CleanupBlock Rethrow(*this, NormalCleanup);
|
||||
EmitCallOrInvoke(getReThrowFn(*this), 0, 0);
|
||||
}
|
||||
// _cxa_rethrow. This needs to happen before __cxa_end_catch is
|
||||
// called, and so it is pushed after BeginCatch.
|
||||
if (ImplicitRethrow)
|
||||
EHStack.pushLazyCleanup<CallRethrow>(NormalCleanup);
|
||||
|
||||
// Perform the body of the catch.
|
||||
EmitStmt(C->getHandlerBlock());
|
||||
@ -1213,13 +1321,11 @@ CodeGenFunction::EnterFinallyBlock(const Stmt *Body,
|
||||
|
||||
// Enter a normal cleanup which will perform the @finally block.
|
||||
{
|
||||
CodeGenFunction::CleanupBlock
|
||||
NormalCleanup(*this, CodeGenFunction::NormalCleanup);
|
||||
CodeGenFunction::CleanupBlock Cleanup(*this, NormalCleanup);
|
||||
|
||||
// Enter a cleanup to call the end-catch function if one was provided.
|
||||
if (EndCatchFn) {
|
||||
CodeGenFunction::CleanupBlock
|
||||
FinallyExitCleanup(CGF, CodeGenFunction::NormalAndEHCleanup);
|
||||
CodeGenFunction::CleanupBlock FinallyExitCleanup(CGF, NormalAndEHCleanup);
|
||||
|
||||
llvm::BasicBlock *EndCatchBB = createBasicBlock("finally.endcatch");
|
||||
llvm::BasicBlock *CleanupContBB = createBasicBlock("finally.cleanup.cont");
|
||||
@ -1228,7 +1334,7 @@ CodeGenFunction::EnterFinallyBlock(const Stmt *Body,
|
||||
Builder.CreateLoad(ForEHVar, "finally.endcatch");
|
||||
Builder.CreateCondBr(ShouldEndCatch, EndCatchBB, CleanupContBB);
|
||||
EmitBlock(EndCatchBB);
|
||||
Builder.CreateCall(EndCatchFn)->setDoesNotThrow();
|
||||
EmitCallOrInvoke(EndCatchFn, 0, 0); // catch-all, so might throw
|
||||
EmitBlock(CleanupContBB);
|
||||
}
|
||||
|
||||
@ -1435,3 +1541,6 @@ CodeGenFunction::CleanupBlock::~CleanupBlock() {
|
||||
CGF.Builder.restoreIP(SavedIP);
|
||||
}
|
||||
|
||||
EHScopeStack::LazyCleanup::~LazyCleanup() {
|
||||
llvm_unreachable("LazyCleanup is indestructable");
|
||||
}
|
||||
|
@ -31,13 +31,13 @@ namespace CodeGen {
|
||||
class EHScope {
|
||||
llvm::BasicBlock *CachedLandingPad;
|
||||
|
||||
unsigned K : 2;
|
||||
unsigned K : 3;
|
||||
|
||||
protected:
|
||||
enum { BitsRemaining = 30 };
|
||||
enum { BitsRemaining = 29 };
|
||||
|
||||
public:
|
||||
enum Kind { Cleanup, Catch, Terminate, Filter };
|
||||
enum Kind { Cleanup, LazyCleanup, Catch, Terminate, Filter };
|
||||
|
||||
EHScope(Kind K) : CachedLandingPad(0), K(K) {}
|
||||
|
||||
@ -127,6 +127,87 @@ class EHCatchScope : public EHScope {
|
||||
}
|
||||
};
|
||||
|
||||
/// A cleanup scope which generates the cleanup blocks lazily.
|
||||
class EHLazyCleanupScope : public EHScope {
|
||||
/// Whether this cleanup needs to be run along normal edges.
|
||||
bool IsNormalCleanup : 1;
|
||||
|
||||
/// Whether this cleanup needs to be run along exception edges.
|
||||
bool IsEHCleanup : 1;
|
||||
|
||||
/// The amount of extra storage needed by the LazyCleanup.
|
||||
/// Always a multiple of the scope-stack alignment.
|
||||
unsigned CleanupSize : 12;
|
||||
|
||||
/// The number of fixups required by enclosing scopes (not including
|
||||
/// this one). If this is the top cleanup scope, all the fixups
|
||||
/// from this index onwards belong to this scope.
|
||||
unsigned FixupDepth : BitsRemaining - 14;
|
||||
|
||||
/// The nearest normal cleanup scope enclosing this one.
|
||||
EHScopeStack::stable_iterator EnclosingNormal;
|
||||
|
||||
/// The nearest EH cleanup scope enclosing this one.
|
||||
EHScopeStack::stable_iterator EnclosingEH;
|
||||
|
||||
/// The dual entry/exit block along the normal edge. This is lazily
|
||||
/// created if needed before the cleanup is popped.
|
||||
llvm::BasicBlock *NormalBlock;
|
||||
|
||||
/// The dual entry/exit block along the EH edge. This is lazily
|
||||
/// created if needed before the cleanup is popped.
|
||||
llvm::BasicBlock *EHBlock;
|
||||
|
||||
public:
|
||||
/// Gets the size required for a lazy cleanup scope with the given
|
||||
/// cleanup-data requirements.
|
||||
static size_t getSizeForCleanupSize(size_t Size) {
|
||||
return sizeof(EHLazyCleanupScope) + Size;
|
||||
}
|
||||
|
||||
size_t getAllocatedSize() const {
|
||||
return sizeof(EHLazyCleanupScope) + CleanupSize;
|
||||
}
|
||||
|
||||
EHLazyCleanupScope(bool IsNormal, bool IsEH, unsigned CleanupSize,
|
||||
unsigned FixupDepth,
|
||||
EHScopeStack::stable_iterator EnclosingNormal,
|
||||
EHScopeStack::stable_iterator EnclosingEH)
|
||||
: EHScope(EHScope::LazyCleanup),
|
||||
IsNormalCleanup(IsNormal), IsEHCleanup(IsEH),
|
||||
CleanupSize(CleanupSize), FixupDepth(FixupDepth),
|
||||
EnclosingNormal(EnclosingNormal), EnclosingEH(EnclosingEH),
|
||||
NormalBlock(0), EHBlock(0)
|
||||
{}
|
||||
|
||||
bool isNormalCleanup() const { return IsNormalCleanup; }
|
||||
llvm::BasicBlock *getNormalBlock() const { return NormalBlock; }
|
||||
void setNormalBlock(llvm::BasicBlock *BB) { NormalBlock = BB; }
|
||||
|
||||
bool isEHCleanup() const { return IsEHCleanup; }
|
||||
llvm::BasicBlock *getEHBlock() const { return EHBlock; }
|
||||
void setEHBlock(llvm::BasicBlock *BB) { EHBlock = BB; }
|
||||
|
||||
unsigned getFixupDepth() const { return FixupDepth; }
|
||||
EHScopeStack::stable_iterator getEnclosingNormalCleanup() const {
|
||||
return EnclosingNormal;
|
||||
}
|
||||
EHScopeStack::stable_iterator getEnclosingEHCleanup() const {
|
||||
return EnclosingEH;
|
||||
}
|
||||
|
||||
size_t getCleanupSize() const { return CleanupSize; }
|
||||
void *getCleanupBuffer() { return this + 1; }
|
||||
|
||||
EHScopeStack::LazyCleanup *getCleanup() {
|
||||
return reinterpret_cast<EHScopeStack::LazyCleanup*>(getCleanupBuffer());
|
||||
}
|
||||
|
||||
static bool classof(const EHScope *Scope) {
|
||||
return (Scope->getKind() == LazyCleanup);
|
||||
}
|
||||
};
|
||||
|
||||
/// A scope which needs to execute some code if we try to unwind ---
|
||||
/// either normally, via the EH mechanism, or both --- through it.
|
||||
class EHCleanupScope : public EHScope {
|
||||
@ -267,6 +348,11 @@ class EHScopeStack::iterator {
|
||||
static_cast<const EHFilterScope*>(get())->getNumFilters());
|
||||
break;
|
||||
|
||||
case EHScope::LazyCleanup:
|
||||
Ptr += static_cast<const EHLazyCleanupScope*>(get())
|
||||
->getAllocatedSize();
|
||||
break;
|
||||
|
||||
case EHScope::Cleanup:
|
||||
Ptr += EHCleanupScope::getSize();
|
||||
break;
|
||||
|
@ -1816,7 +1816,7 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
|
||||
|
||||
return LValue::MakeAddr(Derived, MakeQualifiers(E->getType()));
|
||||
}
|
||||
case CastExpr::CK_BitCast: {
|
||||
case CastExpr::CK_LValueBitCast: {
|
||||
// This must be a reinterpret_cast (or c-style equivalent).
|
||||
const ExplicitCastExpr *CE = cast<ExplicitCastExpr>(E);
|
||||
|
||||
|
@ -307,6 +307,10 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
|
||||
break;
|
||||
}
|
||||
|
||||
case CastExpr::CK_LValueBitCast:
|
||||
llvm_unreachable("there are no lvalue bit-casts on aggregates");
|
||||
break;
|
||||
|
||||
case CastExpr::CK_BitCast: {
|
||||
// This must be a member function pointer cast.
|
||||
Visit(E->getSubExpr());
|
||||
|
@ -131,14 +131,14 @@ class ComplexExprEmitter
|
||||
|
||||
// FIXME: CompoundLiteralExpr
|
||||
|
||||
ComplexPairTy EmitCast(Expr *Op, QualType DestTy);
|
||||
ComplexPairTy EmitCast(CastExpr::CastKind CK, Expr *Op, QualType DestTy);
|
||||
ComplexPairTy VisitImplicitCastExpr(ImplicitCastExpr *E) {
|
||||
// Unlike for scalars, we don't have to worry about function->ptr demotion
|
||||
// here.
|
||||
return EmitCast(E->getSubExpr(), E->getType());
|
||||
return EmitCast(E->getCastKind(), E->getSubExpr(), E->getType());
|
||||
}
|
||||
ComplexPairTy VisitCastExpr(CastExpr *E) {
|
||||
return EmitCast(E->getSubExpr(), E->getType());
|
||||
return EmitCast(E->getCastKind(), E->getSubExpr(), E->getType());
|
||||
}
|
||||
ComplexPairTy VisitCallExpr(const CallExpr *E);
|
||||
ComplexPairTy VisitStmtExpr(const StmtExpr *E);
|
||||
@ -339,11 +339,22 @@ ComplexPairTy ComplexExprEmitter::EmitComplexToComplexCast(ComplexPairTy Val,
|
||||
return Val;
|
||||
}
|
||||
|
||||
ComplexPairTy ComplexExprEmitter::EmitCast(Expr *Op, QualType DestTy) {
|
||||
ComplexPairTy ComplexExprEmitter::EmitCast(CastExpr::CastKind CK, Expr *Op,
|
||||
QualType DestTy) {
|
||||
// Two cases here: cast from (complex to complex) and (scalar to complex).
|
||||
if (Op->getType()->isAnyComplexType())
|
||||
return EmitComplexToComplexCast(Visit(Op), Op->getType(), DestTy);
|
||||
|
||||
// FIXME: We should be looking at all of the cast kinds here, not
|
||||
// cherry-picking the ones we have test cases for.
|
||||
if (CK == CastExpr::CK_LValueBitCast) {
|
||||
llvm::Value *V = CGF.EmitLValue(Op).getAddress();
|
||||
V = Builder.CreateBitCast(V,
|
||||
CGF.ConvertType(CGF.getContext().getPointerType(DestTy)));
|
||||
// FIXME: Are the qualifiers correct here?
|
||||
return EmitLoadOfComplex(V, DestTy.isVolatileQualified());
|
||||
}
|
||||
|
||||
// C99 6.3.1.7: When a value of real type is converted to a complex type, the
|
||||
// real part of the complex result value is determined by the rules of
|
||||
// conversion to the corresponding real type and the imaginary part of the
|
||||
@ -521,7 +532,7 @@ EmitCompoundAssign(const CompoundAssignOperator *E,
|
||||
// improve codegen a little. It is possible for the RHS to be complex or
|
||||
// scalar.
|
||||
OpInfo.Ty = E->getComputationResultType();
|
||||
OpInfo.RHS = EmitCast(E->getRHS(), OpInfo.Ty);
|
||||
OpInfo.RHS = EmitCast(CastExpr::CK_Unknown, E->getRHS(), OpInfo.Ty);
|
||||
|
||||
LValue LHS = CGF.EmitLValue(E->getLHS());
|
||||
// We know the LHS is a complex lvalue.
|
||||
@ -572,8 +583,8 @@ ComplexPairTy ComplexExprEmitter::VisitBinAssign(const BinaryOperator *E) {
|
||||
TestAndClearIgnoreImag();
|
||||
bool ignreal = TestAndClearIgnoreRealAssign();
|
||||
bool ignimag = TestAndClearIgnoreImagAssign();
|
||||
assert(CGF.getContext().getCanonicalType(E->getLHS()->getType()) ==
|
||||
CGF.getContext().getCanonicalType(E->getRHS()->getType()) &&
|
||||
assert(CGF.getContext().hasSameUnqualifiedType(E->getLHS()->getType(),
|
||||
E->getRHS()->getType()) &&
|
||||
"Invalid assignment");
|
||||
// Emit the RHS.
|
||||
ComplexPairTy Val = Visit(E->getRHS());
|
||||
|
@ -925,6 +925,15 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) {
|
||||
//assert(0 && "Unknown cast kind!");
|
||||
break;
|
||||
|
||||
case CastExpr::CK_LValueBitCast: {
|
||||
Value *V = EmitLValue(E).getAddress();
|
||||
V = Builder.CreateBitCast(V,
|
||||
ConvertType(CGF.getContext().getPointerType(DestTy)));
|
||||
// FIXME: Are the qualifiers correct here?
|
||||
return EmitLoadOfLValue(LValue::MakeAddr(V, CGF.MakeQualifiers(DestTy)),
|
||||
DestTy);
|
||||
}
|
||||
|
||||
case CastExpr::CK_AnyPointerToObjCPointerCast:
|
||||
case CastExpr::CK_AnyPointerToBlockPointerCast:
|
||||
case CastExpr::CK_BitCast: {
|
||||
|
@ -1871,8 +1871,7 @@ void CGObjCGNU::EmitSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
|
||||
|
||||
// Register an all-paths cleanup to release the lock.
|
||||
{
|
||||
CodeGenFunction::CleanupBlock
|
||||
ReleaseScope(CGF, CodeGenFunction::NormalAndEHCleanup);
|
||||
CodeGenFunction::CleanupBlock ReleaseScope(CGF, NormalAndEHCleanup);
|
||||
|
||||
llvm::Value *SyncExit = CGM.CreateRuntimeFunction(FTy, "objc_sync_exit");
|
||||
SyncArg = CGF.Builder.CreateBitCast(SyncArg, IdTy);
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "llvm/ADT/SetVector.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/Support/CallSite.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Target/TargetData.h"
|
||||
#include <cstdio>
|
||||
@ -1649,29 +1650,17 @@ CGObjCCommonMac::EmitLegacyMessageSend(CodeGen::CodeGenFunction &CGF,
|
||||
"Result type mismatch!");
|
||||
|
||||
llvm::Constant *Fn = NULL;
|
||||
if (CGM.ReturnTypeUsesSret(FnInfo)) {
|
||||
if (CGM.ReturnTypeUsesSRet(FnInfo)) {
|
||||
Fn = (ObjCABI == 2) ? ObjCTypes.getSendStretFn2(IsSuper)
|
||||
: ObjCTypes.getSendStretFn(IsSuper);
|
||||
} else if (ResultType->isRealFloatingType()) {
|
||||
if (ObjCABI == 2) {
|
||||
if (const BuiltinType *BT = ResultType->getAs<BuiltinType>()) {
|
||||
BuiltinType::Kind k = BT->getKind();
|
||||
Fn = (k == BuiltinType::LongDouble) ? ObjCTypes.getSendFpretFn2(IsSuper)
|
||||
: ObjCTypes.getSendFn2(IsSuper);
|
||||
} else {
|
||||
Fn = ObjCTypes.getSendFn2(IsSuper);
|
||||
}
|
||||
} else
|
||||
// FIXME. This currently matches gcc's API for x86-32. May need to change
|
||||
// for others if we have their API.
|
||||
Fn = ObjCTypes.getSendFpretFn(IsSuper);
|
||||
} else if (CGM.ReturnTypeUsesFPRet(ResultType)) {
|
||||
Fn = (ObjCABI == 2) ? ObjCTypes.getSendFpretFn2(IsSuper)
|
||||
: ObjCTypes.getSendFpretFn(IsSuper);
|
||||
} else {
|
||||
Fn = (ObjCABI == 2) ? ObjCTypes.getSendFn2(IsSuper)
|
||||
: ObjCTypes.getSendFn(IsSuper);
|
||||
}
|
||||
assert(Fn && "EmitLegacyMessageSend - unknown API");
|
||||
Fn = llvm::ConstantExpr::getBitCast(Fn,
|
||||
llvm::PointerType::getUnqual(FTy));
|
||||
Fn = llvm::ConstantExpr::getBitCast(Fn, llvm::PointerType::getUnqual(FTy));
|
||||
return CGF.EmitCall(FnInfo, Fn, Return, ActualArgs);
|
||||
}
|
||||
|
||||
@ -2697,8 +2686,7 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
|
||||
|
||||
// Push a normal cleanup to leave the try scope.
|
||||
{
|
||||
CodeGenFunction::CleanupBlock
|
||||
FinallyScope(CGF, CodeGenFunction::NormalCleanup);
|
||||
CodeGenFunction::CleanupBlock FinallyScope(CGF, NormalCleanup);
|
||||
|
||||
// Check whether we need to call objc_exception_try_exit.
|
||||
// In optimized code, this branch will always be folded.
|
||||
@ -5295,7 +5283,7 @@ CodeGen::RValue CGObjCNonFragileABIMac::EmitMessageSend(
|
||||
FunctionType::ExtInfo());
|
||||
llvm::Constant *Fn = 0;
|
||||
std::string Name("\01l_");
|
||||
if (CGM.ReturnTypeUsesSret(FnInfo)) {
|
||||
if (CGM.ReturnTypeUsesSRet(FnInfo)) {
|
||||
#if 0
|
||||
// unlike what is documented. gcc never generates this API!!
|
||||
if (Receiver->getType() == ObjCTypes.ObjectPtrTy) {
|
||||
@ -5312,14 +5300,9 @@ CodeGen::RValue CGObjCNonFragileABIMac::EmitMessageSend(
|
||||
Fn = ObjCTypes.getMessageSendStretFixupFn();
|
||||
Name += "objc_msgSend_stret_fixup";
|
||||
}
|
||||
} else if (!IsSuper && ResultType->isRealFloatingType()) {
|
||||
if (ResultType->isSpecificBuiltinType(BuiltinType::LongDouble)) {
|
||||
Fn = ObjCTypes.getMessageSendFpretFixupFn();
|
||||
Name += "objc_msgSend_fpret_fixup";
|
||||
} else {
|
||||
Fn = ObjCTypes.getMessageSendFixupFn();
|
||||
Name += "objc_msgSend_fixup";
|
||||
}
|
||||
} else if (!IsSuper && CGM.ReturnTypeUsesFPRet(ResultType)) {
|
||||
Fn = ObjCTypes.getMessageSendFpretFixupFn();
|
||||
Name += "objc_msgSend_fpret_fixup";
|
||||
} else {
|
||||
#if 0
|
||||
// unlike what is documented. gcc never generates this API!!
|
||||
@ -5693,8 +5676,7 @@ CGObjCNonFragileABIMac::EmitSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
|
||||
|
||||
// Register an all-paths cleanup to release the lock.
|
||||
{
|
||||
CodeGenFunction::CleanupBlock
|
||||
ReleaseScope(CGF, CodeGenFunction::NormalAndEHCleanup);
|
||||
CodeGenFunction::CleanupBlock ReleaseScope(CGF, NormalAndEHCleanup);
|
||||
|
||||
CGF.Builder.CreateCall(ObjCTypes.getSyncExitFn(), SyncArg)
|
||||
->setDoesNotThrow();
|
||||
@ -5714,6 +5696,22 @@ namespace {
|
||||
llvm::BasicBlock *Block;
|
||||
llvm::Value *TypeInfo;
|
||||
};
|
||||
|
||||
struct CallObjCEndCatch : EHScopeStack::LazyCleanup {
|
||||
CallObjCEndCatch(bool MightThrow, llvm::Value *Fn) :
|
||||
MightThrow(MightThrow), Fn(Fn) {}
|
||||
bool MightThrow;
|
||||
llvm::Value *Fn;
|
||||
|
||||
void Emit(CodeGenFunction &CGF, bool IsForEH) {
|
||||
if (!MightThrow) {
|
||||
CGF.Builder.CreateCall(Fn)->setDoesNotThrow();
|
||||
return;
|
||||
}
|
||||
|
||||
CGF.EmitCallOrInvoke(Fn, 0, 0);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void CGObjCNonFragileABIMac::EmitTryStmt(CodeGen::CodeGenFunction &CGF,
|
||||
@ -5803,14 +5801,10 @@ void CGObjCNonFragileABIMac::EmitTryStmt(CodeGen::CodeGenFunction &CGF,
|
||||
Exn->setDoesNotThrow();
|
||||
|
||||
// Add a cleanup to leave the catch.
|
||||
{
|
||||
CodeGenFunction::CleanupBlock
|
||||
EndCatchBlock(CGF, CodeGenFunction::NormalAndEHCleanup);
|
||||
|
||||
// __objc_end_catch never throws.
|
||||
CGF.Builder.CreateCall(ObjCTypes.getObjCEndCatchFn())
|
||||
->setDoesNotThrow();
|
||||
}
|
||||
bool EndCatchMightThrow = (Handler.Variable == 0);
|
||||
CGF.EHStack.pushLazyCleanup<CallObjCEndCatch>(NormalAndEHCleanup,
|
||||
EndCatchMightThrow,
|
||||
ObjCTypes.getObjCEndCatchFn());
|
||||
|
||||
// Bind the catch parameter if it exists.
|
||||
if (const VarDecl *CatchParam = Handler.Variable) {
|
||||
|
@ -825,11 +825,168 @@ static void SimplifyCleanupEdges(CodeGenFunction &CGF,
|
||||
SimplifyCleanupEntry(CGF, Entry);
|
||||
}
|
||||
|
||||
static void EmitLazyCleanup(CodeGenFunction &CGF,
|
||||
EHScopeStack::LazyCleanup *Fn,
|
||||
bool ForEH) {
|
||||
if (ForEH) CGF.EHStack.pushTerminate();
|
||||
Fn->Emit(CGF, ForEH);
|
||||
if (ForEH) CGF.EHStack.popTerminate();
|
||||
assert(CGF.HaveInsertPoint() && "cleanup ended with no insertion point?");
|
||||
}
|
||||
|
||||
static void SplitAndEmitLazyCleanup(CodeGenFunction &CGF,
|
||||
EHScopeStack::LazyCleanup *Fn,
|
||||
bool ForEH,
|
||||
llvm::BasicBlock *Entry) {
|
||||
assert(Entry && "no entry block for cleanup");
|
||||
|
||||
// Remove the switch and load from the end of the entry block.
|
||||
llvm::Instruction *Switch = &Entry->getInstList().back();
|
||||
Entry->getInstList().remove(Switch);
|
||||
assert(isa<llvm::SwitchInst>(Switch));
|
||||
llvm::Instruction *Load = &Entry->getInstList().back();
|
||||
Entry->getInstList().remove(Load);
|
||||
assert(isa<llvm::LoadInst>(Load));
|
||||
|
||||
assert(Entry->getInstList().empty() &&
|
||||
"lazy cleanup block not empty after removing load/switch pair?");
|
||||
|
||||
// Emit the actual cleanup at the end of the entry block.
|
||||
CGF.Builder.SetInsertPoint(Entry);
|
||||
EmitLazyCleanup(CGF, Fn, ForEH);
|
||||
|
||||
// Put the load and switch at the end of the exit block.
|
||||
llvm::BasicBlock *Exit = CGF.Builder.GetInsertBlock();
|
||||
Exit->getInstList().push_back(Load);
|
||||
Exit->getInstList().push_back(Switch);
|
||||
|
||||
// Clean up the edges if possible.
|
||||
SimplifyCleanupEdges(CGF, Entry, Exit);
|
||||
|
||||
CGF.Builder.ClearInsertionPoint();
|
||||
}
|
||||
|
||||
static void PopLazyCleanupBlock(CodeGenFunction &CGF) {
|
||||
assert(isa<EHLazyCleanupScope>(*CGF.EHStack.begin()) && "top not a cleanup!");
|
||||
EHLazyCleanupScope &Scope = cast<EHLazyCleanupScope>(*CGF.EHStack.begin());
|
||||
assert(Scope.getFixupDepth() <= CGF.EHStack.getNumBranchFixups());
|
||||
|
||||
// Check whether we need an EH cleanup. This is only true if we've
|
||||
// generated a lazy EH cleanup block.
|
||||
llvm::BasicBlock *EHEntry = Scope.getEHBlock();
|
||||
bool RequiresEHCleanup = (EHEntry != 0);
|
||||
|
||||
// Check the three conditions which might require a normal cleanup:
|
||||
|
||||
// - whether there are branch fix-ups through this cleanup
|
||||
unsigned FixupDepth = Scope.getFixupDepth();
|
||||
bool HasFixups = CGF.EHStack.getNumBranchFixups() != FixupDepth;
|
||||
|
||||
// - whether control has already been threaded through this cleanup
|
||||
llvm::BasicBlock *NormalEntry = Scope.getNormalBlock();
|
||||
bool HasExistingBranches = (NormalEntry != 0);
|
||||
|
||||
// - whether there's a fallthrough
|
||||
llvm::BasicBlock *FallthroughSource = CGF.Builder.GetInsertBlock();
|
||||
bool HasFallthrough = (FallthroughSource != 0);
|
||||
|
||||
bool RequiresNormalCleanup = false;
|
||||
if (Scope.isNormalCleanup() &&
|
||||
(HasFixups || HasExistingBranches || HasFallthrough)) {
|
||||
RequiresNormalCleanup = true;
|
||||
}
|
||||
|
||||
// If we don't need the cleanup at all, we're done.
|
||||
if (!RequiresNormalCleanup && !RequiresEHCleanup) {
|
||||
CGF.EHStack.popCleanup();
|
||||
assert(CGF.EHStack.getNumBranchFixups() == 0 ||
|
||||
CGF.EHStack.hasNormalCleanups());
|
||||
return;
|
||||
}
|
||||
|
||||
// Copy the cleanup emission data out. Note that SmallVector
|
||||
// guarantees maximal alignment for its buffer regardless of its
|
||||
// type parameter.
|
||||
llvm::SmallVector<char, 8*sizeof(void*)> CleanupBuffer;
|
||||
CleanupBuffer.reserve(Scope.getCleanupSize());
|
||||
memcpy(CleanupBuffer.data(),
|
||||
Scope.getCleanupBuffer(), Scope.getCleanupSize());
|
||||
CleanupBuffer.set_size(Scope.getCleanupSize());
|
||||
EHScopeStack::LazyCleanup *Fn =
|
||||
reinterpret_cast<EHScopeStack::LazyCleanup*>(CleanupBuffer.data());
|
||||
|
||||
// We're done with the scope; pop it off so we can emit the cleanups.
|
||||
CGF.EHStack.popCleanup();
|
||||
|
||||
if (RequiresNormalCleanup) {
|
||||
// If we have a fallthrough and no other need for the cleanup,
|
||||
// emit it directly.
|
||||
if (HasFallthrough && !HasFixups && !HasExistingBranches) {
|
||||
EmitLazyCleanup(CGF, Fn, /*ForEH*/ false);
|
||||
|
||||
// Otherwise, the best approach is to thread everything through
|
||||
// the cleanup block and then try to clean up after ourselves.
|
||||
} else {
|
||||
// Force the entry block to exist.
|
||||
if (!HasExistingBranches) {
|
||||
NormalEntry = CGF.createBasicBlock("cleanup");
|
||||
CreateCleanupSwitch(CGF, NormalEntry);
|
||||
}
|
||||
|
||||
CGF.EmitBlock(NormalEntry);
|
||||
|
||||
// Thread the fallthrough edge through the (momentarily trivial)
|
||||
// cleanup.
|
||||
llvm::BasicBlock *FallthroughDestination = 0;
|
||||
if (HasFallthrough) {
|
||||
assert(isa<llvm::BranchInst>(FallthroughSource->getTerminator()));
|
||||
FallthroughDestination = CGF.createBasicBlock("cleanup.cont");
|
||||
|
||||
BranchFixup Fix;
|
||||
Fix.Destination = FallthroughDestination;
|
||||
Fix.LatestBranch = FallthroughSource->getTerminator();
|
||||
Fix.LatestBranchIndex = 0;
|
||||
Fix.Origin = Fix.LatestBranch;
|
||||
|
||||
// Restore fixup invariant. EmitBlock added a branch to the
|
||||
// cleanup which we need to redirect to the destination.
|
||||
cast<llvm::BranchInst>(Fix.LatestBranch)
|
||||
->setSuccessor(0, Fix.Destination);
|
||||
|
||||
ThreadFixupThroughCleanup(CGF, Fix, NormalEntry, NormalEntry);
|
||||
}
|
||||
|
||||
// Thread any "real" fixups we need to thread.
|
||||
for (unsigned I = FixupDepth, E = CGF.EHStack.getNumBranchFixups();
|
||||
I != E; ++I)
|
||||
if (CGF.EHStack.getBranchFixup(I).Destination)
|
||||
ThreadFixupThroughCleanup(CGF, CGF.EHStack.getBranchFixup(I),
|
||||
NormalEntry, NormalEntry);
|
||||
|
||||
SplitAndEmitLazyCleanup(CGF, Fn, /*ForEH*/ false, NormalEntry);
|
||||
|
||||
if (HasFallthrough)
|
||||
CGF.EmitBlock(FallthroughDestination);
|
||||
}
|
||||
}
|
||||
|
||||
// Emit the EH cleanup if required.
|
||||
if (RequiresEHCleanup) {
|
||||
CGBuilderTy::InsertPoint SavedIP = CGF.Builder.saveAndClearIP();
|
||||
CGF.EmitBlock(EHEntry);
|
||||
SplitAndEmitLazyCleanup(CGF, Fn, /*ForEH*/ true, EHEntry);
|
||||
CGF.Builder.restoreIP(SavedIP);
|
||||
}
|
||||
}
|
||||
|
||||
/// Pops a cleanup block. If the block includes a normal cleanup, the
|
||||
/// current insertion point is threaded through the cleanup, as are
|
||||
/// any branch fixups on the cleanup.
|
||||
void CodeGenFunction::PopCleanupBlock() {
|
||||
assert(!EHStack.empty() && "cleanup stack is empty!");
|
||||
if (isa<EHLazyCleanupScope>(*EHStack.begin()))
|
||||
return PopLazyCleanupBlock(*this);
|
||||
|
||||
assert(isa<EHCleanupScope>(*EHStack.begin()) && "top not a cleanup!");
|
||||
EHCleanupScope &Scope = cast<EHCleanupScope>(*EHStack.begin());
|
||||
assert(Scope.getFixupDepth() <= EHStack.getNumBranchFixups());
|
||||
@ -1007,6 +1164,16 @@ void CodeGenFunction::EmitBranchThroughCleanup(JumpDest Dest) {
|
||||
if (Scope.isNormalCleanup())
|
||||
ThreadFixupThroughCleanup(*this, Fixup, Scope.getNormalEntry(),
|
||||
Scope.getNormalExit());
|
||||
} else if (isa<EHLazyCleanupScope>(*I)) {
|
||||
EHLazyCleanupScope &Scope = cast<EHLazyCleanupScope>(*I);
|
||||
if (Scope.isNormalCleanup()) {
|
||||
llvm::BasicBlock *Block = Scope.getNormalBlock();
|
||||
if (!Block) {
|
||||
Block = createBasicBlock("cleanup");
|
||||
Scope.setNormalBlock(Block);
|
||||
}
|
||||
ThreadFixupThroughCleanup(*this, Fixup, Block, Block);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1046,6 +1213,16 @@ void CodeGenFunction::EmitBranchThroughEHCleanup(JumpDest Dest) {
|
||||
if (Scope.isEHCleanup())
|
||||
ThreadFixupThroughCleanup(*this, Fixup, Scope.getEHEntry(),
|
||||
Scope.getEHExit());
|
||||
} else if (isa<EHLazyCleanupScope>(*I)) {
|
||||
EHLazyCleanupScope &Scope = cast<EHLazyCleanupScope>(*I);
|
||||
if (Scope.isEHCleanup()) {
|
||||
llvm::BasicBlock *Block = Scope.getEHBlock();
|
||||
if (!Block) {
|
||||
Block = createBasicBlock("eh.cleanup");
|
||||
Scope.setEHBlock(Block);
|
||||
}
|
||||
ThreadFixupThroughCleanup(*this, Fixup, Block, Block);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -95,6 +95,8 @@ struct BranchFixup {
|
||||
unsigned LatestBranchIndex;
|
||||
};
|
||||
|
||||
enum CleanupKind { NormalAndEHCleanup, EHCleanup, NormalCleanup };
|
||||
|
||||
/// A stack of scopes which respond to exceptions, including cleanups
|
||||
/// and catch blocks.
|
||||
class EHScopeStack {
|
||||
@ -123,6 +125,33 @@ class EHScopeStack {
|
||||
}
|
||||
};
|
||||
|
||||
/// A lazy cleanup. Subclasses must be POD-like: cleanups will
|
||||
/// not be destructed, and they will be allocated on the cleanup
|
||||
/// stack and freely copied and moved around.
|
||||
///
|
||||
/// LazyCleanup implementations should generally be declared in an
|
||||
/// anonymous namespace.
|
||||
class LazyCleanup {
|
||||
public:
|
||||
// Anchor the construction vtable. We use the destructor because
|
||||
// gcc gives an obnoxious warning if there are virtual methods
|
||||
// with an accessible non-virtual destructor. Unfortunately,
|
||||
// declaring this destructor makes it non-trivial, but there
|
||||
// doesn't seem to be any other way around this warning.
|
||||
//
|
||||
// This destructor will never be called.
|
||||
virtual ~LazyCleanup();
|
||||
|
||||
/// Emit the cleanup. For normal cleanups, this is run in the
|
||||
/// same EH context as when the cleanup was pushed, i.e. the
|
||||
/// immediately-enclosing context of the cleanup scope. For
|
||||
/// EH cleanups, this is run in a terminate context.
|
||||
///
|
||||
// \param IsForEHCleanup true if this is for an EH cleanup, false
|
||||
/// if for a normal cleanup.
|
||||
virtual void Emit(CodeGenFunction &CGF, bool IsForEHCleanup) = 0;
|
||||
};
|
||||
|
||||
private:
|
||||
// The implementation for this class is in CGException.h and
|
||||
// CGException.cpp; the definition is here because it's used as a
|
||||
@ -171,6 +200,8 @@ class EHScopeStack {
|
||||
|
||||
void popNullFixups();
|
||||
|
||||
void *pushLazyCleanup(CleanupKind K, size_t DataSize);
|
||||
|
||||
public:
|
||||
EHScopeStack() : StartOfBuffer(0), EndOfBuffer(0), StartOfData(0),
|
||||
InnermostNormalCleanup(stable_end()),
|
||||
@ -178,6 +209,48 @@ class EHScopeStack {
|
||||
CatchDepth(0) {}
|
||||
~EHScopeStack() { delete[] StartOfBuffer; }
|
||||
|
||||
// Variadic templates would make this not terrible.
|
||||
|
||||
/// Push a lazily-created cleanup on the stack.
|
||||
template <class T>
|
||||
void pushLazyCleanup(CleanupKind Kind) {
|
||||
void *Buffer = pushLazyCleanup(Kind, sizeof(T));
|
||||
LazyCleanup *Obj = new(Buffer) T();
|
||||
(void) Obj;
|
||||
}
|
||||
|
||||
/// Push a lazily-created cleanup on the stack.
|
||||
template <class T, class A0>
|
||||
void pushLazyCleanup(CleanupKind Kind, A0 a0) {
|
||||
void *Buffer = pushLazyCleanup(Kind, sizeof(T));
|
||||
LazyCleanup *Obj = new(Buffer) T(a0);
|
||||
(void) Obj;
|
||||
}
|
||||
|
||||
/// Push a lazily-created cleanup on the stack.
|
||||
template <class T, class A0, class A1>
|
||||
void pushLazyCleanup(CleanupKind Kind, A0 a0, A1 a1) {
|
||||
void *Buffer = pushLazyCleanup(Kind, sizeof(T));
|
||||
LazyCleanup *Obj = new(Buffer) T(a0, a1);
|
||||
(void) Obj;
|
||||
}
|
||||
|
||||
/// Push a lazily-created cleanup on the stack.
|
||||
template <class T, class A0, class A1, class A2>
|
||||
void pushLazyCleanup(CleanupKind Kind, A0 a0, A1 a1, A2 a2) {
|
||||
void *Buffer = pushLazyCleanup(Kind, sizeof(T));
|
||||
LazyCleanup *Obj = new(Buffer) T(a0, a1, a2);
|
||||
(void) Obj;
|
||||
}
|
||||
|
||||
/// Push a lazily-created cleanup on the stack.
|
||||
template <class T, class A0, class A1, class A2, class A3>
|
||||
void pushLazyCleanup(CleanupKind Kind, A0 a0, A1 a1, A2 a2, A3 a3) {
|
||||
void *Buffer = pushLazyCleanup(Kind, sizeof(T));
|
||||
LazyCleanup *Obj = new(Buffer) T(a0, a1, a2, a3);
|
||||
(void) Obj;
|
||||
}
|
||||
|
||||
/// Push a cleanup on the stack.
|
||||
void pushCleanup(llvm::BasicBlock *NormalEntry,
|
||||
llvm::BasicBlock *NormalExit,
|
||||
@ -375,8 +448,6 @@ class CodeGenFunction : public BlockFunction {
|
||||
llvm::Constant *RethrowFn);
|
||||
void ExitFinallyBlock(FinallyInfo &FinallyInfo);
|
||||
|
||||
enum CleanupKind { NormalAndEHCleanup, EHCleanup, NormalCleanup };
|
||||
|
||||
/// PushDestructorCleanup - Push a cleanup to call the
|
||||
/// complete-object destructor of an object of the given type at the
|
||||
/// given address. Does nothing if T is not a C++ class type with a
|
||||
|
@ -444,9 +444,13 @@ class CodeGenModule : public BlockModule {
|
||||
/// which only apply to a function definintion.
|
||||
void SetLLVMFunctionAttributesForDefinition(const Decl *D, llvm::Function *F);
|
||||
|
||||
/// ReturnTypeUsesSret - Return true iff the given type uses 'sret' when used
|
||||
/// ReturnTypeUsesSRet - Return true iff the given type uses 'sret' when used
|
||||
/// as a return type.
|
||||
bool ReturnTypeUsesSret(const CGFunctionInfo &FI);
|
||||
bool ReturnTypeUsesSRet(const CGFunctionInfo &FI);
|
||||
|
||||
/// ReturnTypeUsesSret - Return true iff the given type uses 'fpret' when used
|
||||
/// as a return type.
|
||||
bool ReturnTypeUsesFPRet(QualType ResultType);
|
||||
|
||||
/// ConstructAttributeList - Get the LLVM attributes and calling convention to
|
||||
/// use for a particular function type.
|
||||
|
@ -169,7 +169,9 @@ class CXXNameMangler {
|
||||
|
||||
void mangle(const NamedDecl *D, llvm::StringRef Prefix = "_Z");
|
||||
void mangleCallOffset(int64_t NonVirtual, int64_t Virtual);
|
||||
void mangleNumber(const llvm::APSInt &I);
|
||||
void mangleNumber(int64_t Number);
|
||||
void mangleFloat(const llvm::APFloat &F);
|
||||
void mangleFunctionEncoding(const FunctionDecl *FD);
|
||||
void mangleName(const NamedDecl *ND);
|
||||
void mangleType(QualType T);
|
||||
@ -230,6 +232,7 @@ class CXXNameMangler {
|
||||
#include "clang/AST/TypeNodes.def"
|
||||
|
||||
void mangleType(const TagType*);
|
||||
void mangleType(TemplateName);
|
||||
void mangleBareFunctionType(const FunctionType *T,
|
||||
bool MangleReturnType);
|
||||
|
||||
@ -526,6 +529,21 @@ void CXXNameMangler::mangleUnscopedTemplateName(TemplateName Template) {
|
||||
addSubstitution(Template);
|
||||
}
|
||||
|
||||
void CXXNameMangler::mangleFloat(const llvm::APFloat &F) {
|
||||
// TODO: avoid this copy with careful stream management.
|
||||
llvm::SmallString<20> Buffer;
|
||||
F.bitcastToAPInt().toString(Buffer, 16, false);
|
||||
Out.write(Buffer.data(), Buffer.size());
|
||||
}
|
||||
|
||||
void CXXNameMangler::mangleNumber(const llvm::APSInt &Value) {
|
||||
if (Value.isSigned() && Value.isNegative()) {
|
||||
Out << 'n';
|
||||
Value.abs().print(Out, true);
|
||||
} else
|
||||
Value.print(Out, Value.isSigned());
|
||||
}
|
||||
|
||||
void CXXNameMangler::mangleNumber(int64_t Number) {
|
||||
// <number> ::= [n] <non-negative decimal integer>
|
||||
if (Number < 0) {
|
||||
@ -939,6 +957,53 @@ void CXXNameMangler::mangleTemplatePrefix(const TemplateDecl *ND) {
|
||||
addSubstitution(ND);
|
||||
}
|
||||
|
||||
/// Mangles a template name under the production <type>. Required for
|
||||
/// template template arguments.
|
||||
/// <type> ::= <class-enum-type>
|
||||
/// ::= <template-param>
|
||||
/// ::= <substitution>
|
||||
void CXXNameMangler::mangleType(TemplateName TN) {
|
||||
if (mangleSubstitution(TN))
|
||||
return;
|
||||
|
||||
TemplateDecl *TD = 0;
|
||||
|
||||
switch (TN.getKind()) {
|
||||
case TemplateName::QualifiedTemplate:
|
||||
TD = TN.getAsQualifiedTemplateName()->getTemplateDecl();
|
||||
goto HaveDecl;
|
||||
|
||||
case TemplateName::Template:
|
||||
TD = TN.getAsTemplateDecl();
|
||||
goto HaveDecl;
|
||||
|
||||
HaveDecl:
|
||||
if (isa<TemplateTemplateParmDecl>(TD))
|
||||
mangleTemplateParameter(cast<TemplateTemplateParmDecl>(TD)->getIndex());
|
||||
else
|
||||
mangleName(TD);
|
||||
break;
|
||||
|
||||
case TemplateName::OverloadedTemplate:
|
||||
llvm_unreachable("can't mangle an overloaded template name as a <type>");
|
||||
break;
|
||||
|
||||
case TemplateName::DependentTemplate: {
|
||||
const DependentTemplateName *Dependent = TN.getAsDependentTemplateName();
|
||||
assert(Dependent->isIdentifier());
|
||||
|
||||
// <class-enum-type> ::= <name>
|
||||
// <name> ::= <nested-name>
|
||||
mangleUnresolvedScope(Dependent->getQualifier());
|
||||
mangleSourceName(Dependent->getIdentifier());
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
addSubstitution(TN);
|
||||
}
|
||||
|
||||
void
|
||||
CXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity) {
|
||||
switch (OO) {
|
||||
@ -1301,8 +1366,6 @@ void CXXNameMangler::mangleType(const TemplateTypeParmType *T) {
|
||||
mangleTemplateParameter(T->getIndex());
|
||||
}
|
||||
|
||||
// FIXME: <type> ::= <template-template-param> <template-args>
|
||||
|
||||
// <type> ::= P <type> # pointer-to
|
||||
void CXXNameMangler::mangleType(const PointerType *T) {
|
||||
Out << 'P';
|
||||
@ -1467,11 +1530,7 @@ void CXXNameMangler::mangleIntegerLiteral(QualType T,
|
||||
// Boolean values are encoded as 0/1.
|
||||
Out << (Value.getBoolValue() ? '1' : '0');
|
||||
} else {
|
||||
if (Value.isSigned() && Value.isNegative()) {
|
||||
Out << 'n';
|
||||
Value.abs().print(Out, true);
|
||||
} else
|
||||
Value.print(Out, Value.isSigned());
|
||||
mangleNumber(Value);
|
||||
}
|
||||
Out << 'E';
|
||||
|
||||
@ -1535,10 +1594,44 @@ void CXXNameMangler::mangleExpression(const Expr *E) {
|
||||
#define STMT(Type, Base) \
|
||||
case Expr::Type##Class:
|
||||
#include "clang/AST/StmtNodes.inc"
|
||||
// fallthrough
|
||||
|
||||
// These all can only appear in local or variable-initialization
|
||||
// contexts and so should never appear in a mangling.
|
||||
case Expr::AddrLabelExprClass:
|
||||
case Expr::BlockDeclRefExprClass:
|
||||
case Expr::CXXThisExprClass:
|
||||
case Expr::DesignatedInitExprClass:
|
||||
case Expr::ImplicitValueInitExprClass:
|
||||
case Expr::InitListExprClass:
|
||||
case Expr::ParenListExprClass:
|
||||
case Expr::CXXScalarValueInitExprClass:
|
||||
llvm_unreachable("unexpected statement kind");
|
||||
break;
|
||||
|
||||
default: {
|
||||
// FIXME: invent manglings for all these.
|
||||
case Expr::BlockExprClass:
|
||||
case Expr::CXXPseudoDestructorExprClass:
|
||||
case Expr::ChooseExprClass:
|
||||
case Expr::CompoundLiteralExprClass:
|
||||
case Expr::ExtVectorElementExprClass:
|
||||
case Expr::ObjCEncodeExprClass:
|
||||
case Expr::ObjCImplicitSetterGetterRefExprClass:
|
||||
case Expr::ObjCIsaExprClass:
|
||||
case Expr::ObjCIvarRefExprClass:
|
||||
case Expr::ObjCMessageExprClass:
|
||||
case Expr::ObjCPropertyRefExprClass:
|
||||
case Expr::ObjCProtocolExprClass:
|
||||
case Expr::ObjCSelectorExprClass:
|
||||
case Expr::ObjCStringLiteralClass:
|
||||
case Expr::ObjCSuperExprClass:
|
||||
case Expr::OffsetOfExprClass:
|
||||
case Expr::PredefinedExprClass:
|
||||
case Expr::ShuffleVectorExprClass:
|
||||
case Expr::StmtExprClass:
|
||||
case Expr::TypesCompatibleExprClass:
|
||||
case Expr::UnaryTypeTraitExprClass:
|
||||
case Expr::VAArgExprClass: {
|
||||
// As bad as this diagnostic is, it's better than crashing.
|
||||
Diagnostic &Diags = Context.getDiags();
|
||||
unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Error,
|
||||
@ -1550,6 +1643,11 @@ void CXXNameMangler::mangleExpression(const Expr *E) {
|
||||
break;
|
||||
}
|
||||
|
||||
case Expr::CXXDefaultArgExprClass:
|
||||
mangleExpression(cast<CXXDefaultArgExpr>(E)->getExpr());
|
||||
break;
|
||||
|
||||
case Expr::CXXMemberCallExprClass: // fallthrough
|
||||
case Expr::CallExprClass: {
|
||||
const CallExpr *CE = cast<CallExpr>(E);
|
||||
Out << "cl";
|
||||
@ -1560,6 +1658,26 @@ void CXXNameMangler::mangleExpression(const Expr *E) {
|
||||
break;
|
||||
}
|
||||
|
||||
case Expr::CXXNewExprClass: {
|
||||
// Proposal from David Vandervoorde, 2010.06.30
|
||||
const CXXNewExpr *New = cast<CXXNewExpr>(E);
|
||||
if (New->isGlobalNew()) Out << "gs";
|
||||
Out << (New->isArray() ? "na" : "nw");
|
||||
for (CXXNewExpr::const_arg_iterator I = New->placement_arg_begin(),
|
||||
E = New->placement_arg_end(); I != E; ++I)
|
||||
mangleExpression(*I);
|
||||
Out << '_';
|
||||
mangleType(New->getAllocatedType());
|
||||
if (New->hasInitializer()) {
|
||||
Out << "pi";
|
||||
for (CXXNewExpr::const_arg_iterator I = New->constructor_arg_begin(),
|
||||
E = New->constructor_arg_end(); I != E; ++I)
|
||||
mangleExpression(*I);
|
||||
}
|
||||
Out << 'E';
|
||||
break;
|
||||
}
|
||||
|
||||
case Expr::MemberExprClass: {
|
||||
const MemberExpr *ME = cast<MemberExpr>(E);
|
||||
mangleMemberExpr(ME->getBase(), ME->isArrow(),
|
||||
@ -1633,6 +1751,43 @@ void CXXNameMangler::mangleExpression(const Expr *E) {
|
||||
break;
|
||||
}
|
||||
|
||||
case Expr::CXXThrowExprClass: {
|
||||
const CXXThrowExpr *TE = cast<CXXThrowExpr>(E);
|
||||
|
||||
// Proposal from David Vandervoorde, 2010.06.30
|
||||
if (TE->getSubExpr()) {
|
||||
Out << "tw";
|
||||
mangleExpression(TE->getSubExpr());
|
||||
} else {
|
||||
Out << "tr";
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Expr::CXXTypeidExprClass: {
|
||||
const CXXTypeidExpr *TIE = cast<CXXTypeidExpr>(E);
|
||||
|
||||
// Proposal from David Vandervoorde, 2010.06.30
|
||||
if (TIE->isTypeOperand()) {
|
||||
Out << "ti";
|
||||
mangleType(TIE->getTypeOperand());
|
||||
} else {
|
||||
Out << "te";
|
||||
mangleExpression(TIE->getExprOperand());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Expr::CXXDeleteExprClass: {
|
||||
const CXXDeleteExpr *DE = cast<CXXDeleteExpr>(E);
|
||||
|
||||
// Proposal from David Vandervoorde, 2010.06.30
|
||||
if (DE->isGlobalDelete()) Out << "gs";
|
||||
Out << (DE->isArrayForm() ? "da" : "dl");
|
||||
mangleExpression(DE->getArgument());
|
||||
break;
|
||||
}
|
||||
|
||||
case Expr::UnaryOperatorClass: {
|
||||
const UnaryOperator *UO = cast<UnaryOperator>(E);
|
||||
mangleOperatorName(UnaryOperator::getOverloadedOperator(UO->getOpcode()),
|
||||
@ -1641,6 +1796,18 @@ void CXXNameMangler::mangleExpression(const Expr *E) {
|
||||
break;
|
||||
}
|
||||
|
||||
case Expr::ArraySubscriptExprClass: {
|
||||
const ArraySubscriptExpr *AE = cast<ArraySubscriptExpr>(E);
|
||||
|
||||
// Array subscript is treated as a syntactically wierd form of
|
||||
// binary operator.
|
||||
Out << "ix";
|
||||
mangleExpression(AE->getLHS());
|
||||
mangleExpression(AE->getRHS());
|
||||
break;
|
||||
}
|
||||
|
||||
case Expr::CompoundAssignOperatorClass: // fallthrough
|
||||
case Expr::BinaryOperatorClass: {
|
||||
const BinaryOperator *BO = cast<BinaryOperator>(E);
|
||||
mangleOperatorName(BinaryOperator::getOverloadedOperator(BO->getOpcode()),
|
||||
@ -1757,12 +1924,7 @@ void CXXNameMangler::mangleExpression(const Expr *E) {
|
||||
const FloatingLiteral *FL = cast<FloatingLiteral>(E);
|
||||
Out << 'L';
|
||||
mangleType(FL->getType());
|
||||
|
||||
// TODO: avoid this copy with careful stream management.
|
||||
llvm::SmallString<20> Buffer;
|
||||
FL->getValue().bitcastToAPInt().toString(Buffer, 16, false);
|
||||
Out.write(Buffer.data(), Buffer.size());
|
||||
|
||||
mangleFloat(FL->getValue());
|
||||
Out << 'E';
|
||||
break;
|
||||
}
|
||||
@ -1780,17 +1942,63 @@ void CXXNameMangler::mangleExpression(const Expr *E) {
|
||||
Out << 'E';
|
||||
break;
|
||||
|
||||
case Expr::IntegerLiteralClass:
|
||||
mangleIntegerLiteral(E->getType(),
|
||||
llvm::APSInt(cast<IntegerLiteral>(E)->getValue()));
|
||||
case Expr::IntegerLiteralClass: {
|
||||
llvm::APSInt Value(cast<IntegerLiteral>(E)->getValue());
|
||||
if (E->getType()->isSignedIntegerType())
|
||||
Value.setIsSigned(true);
|
||||
mangleIntegerLiteral(E->getType(), Value);
|
||||
break;
|
||||
}
|
||||
|
||||
case Expr::ImaginaryLiteralClass: {
|
||||
const ImaginaryLiteral *IE = cast<ImaginaryLiteral>(E);
|
||||
// Mangle as if a complex literal.
|
||||
// Proposal from David Vandervoorde, 2010.06.30.
|
||||
Out << 'L';
|
||||
mangleType(E->getType());
|
||||
if (const FloatingLiteral *Imag =
|
||||
dyn_cast<FloatingLiteral>(IE->getSubExpr())) {
|
||||
// Mangle a floating-point zero of the appropriate type.
|
||||
mangleFloat(llvm::APFloat(Imag->getValue().getSemantics()));
|
||||
Out << '_';
|
||||
mangleFloat(Imag->getValue());
|
||||
} else {
|
||||
Out << '0' << '_';
|
||||
llvm::APSInt Value(cast<IntegerLiteral>(IE->getSubExpr())->getValue());
|
||||
if (IE->getSubExpr()->getType()->isSignedIntegerType())
|
||||
Value.setIsSigned(true);
|
||||
mangleNumber(Value);
|
||||
}
|
||||
Out << 'E';
|
||||
break;
|
||||
}
|
||||
|
||||
case Expr::StringLiteralClass: {
|
||||
// Proposal from David Vandervoorde, 2010.06.30.
|
||||
// I've sent a comment off asking whether this needs to also
|
||||
// represent the length of the string.
|
||||
Out << 'L';
|
||||
const ConstantArrayType *T = cast<ConstantArrayType>(E->getType());
|
||||
QualType CharTy = T->getElementType().getUnqualifiedType();
|
||||
mangleType(CharTy);
|
||||
Out << 'E';
|
||||
break;
|
||||
}
|
||||
|
||||
case Expr::GNUNullExprClass:
|
||||
// FIXME: should this really be mangled the same as nullptr?
|
||||
// fallthrough
|
||||
|
||||
case Expr::CXXNullPtrLiteralExprClass: {
|
||||
// Proposal from David Vandervoorde, 2010.06.30, as
|
||||
// modified by ABI list discussion.
|
||||
Out << "LDnE";
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: <type> ::= G <type> # imaginary (C 2000)
|
||||
// FIXME: <type> ::= U <source-name> <type> # vendor extended type qualifier
|
||||
|
||||
void CXXNameMangler::mangleCXXCtorType(CXXCtorType T) {
|
||||
// <ctor-dtor-name> ::= C1 # complete object constructor
|
||||
// ::= C2 # base object constructor
|
||||
@ -1874,9 +2082,8 @@ void CXXNameMangler::mangleTemplateArg(const NamedDecl *P,
|
||||
mangleType(A.getAsType());
|
||||
break;
|
||||
case TemplateArgument::Template:
|
||||
assert(A.getAsTemplate().getAsTemplateDecl() &&
|
||||
"Can't get dependent template names here");
|
||||
mangleName(A.getAsTemplate().getAsTemplateDecl());
|
||||
// This is mangled as <type>.
|
||||
mangleType(A.getAsTemplate());
|
||||
break;
|
||||
case TemplateArgument::Expression:
|
||||
Out << 'X';
|
||||
|
@ -2365,7 +2365,6 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() const {
|
||||
case llvm::Triple::DragonFly:
|
||||
case llvm::Triple::FreeBSD:
|
||||
case llvm::Triple::OpenBSD:
|
||||
case llvm::Triple::Minix:
|
||||
return *(TheTargetCodeGenInfo =
|
||||
new X86_32TargetCodeGenInfo(Context, false, true));
|
||||
|
||||
|
@ -95,6 +95,25 @@ Arg *ArgList::getLastArg(OptSpecifier Id0, OptSpecifier Id1,
|
||||
return Res;
|
||||
}
|
||||
|
||||
Arg *ArgList::getLastArg(OptSpecifier Id0, OptSpecifier Id1,
|
||||
OptSpecifier Id2, OptSpecifier Id3) const {
|
||||
Arg *Res = 0;
|
||||
for (const_reverse_iterator it = rbegin(), ie = rend(); it != ie; ++it) {
|
||||
if ((*it)->getOption().matches(Id0) ||
|
||||
(*it)->getOption().matches(Id1) ||
|
||||
(*it)->getOption().matches(Id2) ||
|
||||
(*it)->getOption().matches(Id3)) {
|
||||
Res = *it;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Res)
|
||||
Res->claim();
|
||||
|
||||
return Res;
|
||||
}
|
||||
|
||||
bool ArgList::hasFlag(OptSpecifier Pos, OptSpecifier Neg, bool Default) const {
|
||||
if (Arg *A = getLastArg(Pos, Neg))
|
||||
return A->getOption().matches(Pos);
|
||||
|
@ -75,6 +75,11 @@ Driver::Driver(llvm::StringRef _Name, llvm::StringRef _Dir,
|
||||
P.appendComponent("clang");
|
||||
P.appendComponent(CLANG_VERSION_STRING);
|
||||
ResourceDir = P.str();
|
||||
|
||||
// Save the original clang executable path.
|
||||
P = Dir;
|
||||
P.appendComponent(Name);
|
||||
ClangExecutable = P.str();
|
||||
}
|
||||
|
||||
Driver::~Driver() {
|
||||
|
@ -26,14 +26,11 @@ const Driver &ToolChain::getDriver() const {
|
||||
return Host.getDriver();
|
||||
}
|
||||
|
||||
std::string ToolChain::GetFilePath(const Compilation &C,
|
||||
const char *Name) const {
|
||||
std::string ToolChain::GetFilePath(const char *Name) const {
|
||||
return Host.getDriver().GetFilePath(Name, *this);
|
||||
|
||||
}
|
||||
|
||||
std::string ToolChain::GetProgramPath(const Compilation &C,
|
||||
const char *Name,
|
||||
bool WantFile) const {
|
||||
std::string ToolChain::GetProgramPath(const char *Name, bool WantFile) const {
|
||||
return Host.getDriver().GetProgramPath(Name, *this, WantFile);
|
||||
}
|
||||
|
@ -469,19 +469,10 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args,
|
||||
iPhoneVersion = DAL->MakeJoinedArg(0, O, iPhoneOSTarget);
|
||||
DAL->append(iPhoneVersion);
|
||||
} else {
|
||||
// Otherwise, choose a default platform based on the tool chain.
|
||||
//
|
||||
// FIXME: Don't hardcode default here.
|
||||
if (getTriple().getArch() == llvm::Triple::arm ||
|
||||
getTriple().getArch() == llvm::Triple::thumb) {
|
||||
const Option *O = Opts.getOption(options::OPT_miphoneos_version_min_EQ);
|
||||
iPhoneVersion = DAL->MakeJoinedArg(0, O, "3.0");
|
||||
DAL->append(iPhoneVersion);
|
||||
} else {
|
||||
const Option *O = Opts.getOption(options::OPT_mmacosx_version_min_EQ);
|
||||
OSXVersion = DAL->MakeJoinedArg(0, O, MacosxVersionMin);
|
||||
DAL->append(OSXVersion);
|
||||
}
|
||||
// Otherwise, assume we are targeting OS X.
|
||||
const Option *O = Opts.getOption(options::OPT_mmacosx_version_min_EQ);
|
||||
OSXVersion = DAL->MakeJoinedArg(0, O, MacosxVersionMin);
|
||||
DAL->append(OSXVersion);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1489,8 +1489,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
|
||||
Args.AddAllArgs(CmdArgs, options::OPT_undef);
|
||||
|
||||
const char *Exec =
|
||||
Args.MakeArgString(getToolChain().GetProgramPath(C, "clang"));
|
||||
std::string Exec = getToolChain().getDriver().getClangProgramPath();
|
||||
|
||||
// Optionally embed the -cc1 level arguments into the debug info, for build
|
||||
// analysis.
|
||||
@ -1510,7 +1509,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
CmdArgs.push_back(Args.MakeArgString(Flags.str()));
|
||||
}
|
||||
|
||||
Dest.addCommand(new Command(JA, *this, Exec, CmdArgs));
|
||||
Dest.addCommand(new Command(JA, *this, Exec.c_str(), CmdArgs));
|
||||
|
||||
// Explicitly warn that these options are unsupported, even though
|
||||
// we are allowing compilation to continue.
|
||||
@ -1589,9 +1588,8 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
CmdArgs.push_back(Input.getFilename());
|
||||
}
|
||||
|
||||
const char *Exec =
|
||||
Args.MakeArgString(getToolChain().GetProgramPath(C, "clang"));
|
||||
Dest.addCommand(new Command(JA, *this, Exec, CmdArgs));
|
||||
std::string Exec = getToolChain().getDriver().getClangProgramPath();
|
||||
Dest.addCommand(new Command(JA, *this, Exec.c_str(), CmdArgs));
|
||||
}
|
||||
|
||||
void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
@ -1691,7 +1689,7 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
|
||||
const char *GCCName = getToolChain().getDriver().CCCGenericGCCName.c_str();
|
||||
const char *Exec =
|
||||
Args.MakeArgString(getToolChain().GetProgramPath(C, GCCName));
|
||||
Args.MakeArgString(getToolChain().GetProgramPath(GCCName));
|
||||
Dest.addCommand(new Command(JA, *this, Exec, CmdArgs));
|
||||
}
|
||||
|
||||
@ -2098,7 +2096,7 @@ void darwin::Preprocess::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
|
||||
const char *CC1Name = getCC1Name(Inputs[0].getType());
|
||||
const char *Exec =
|
||||
Args.MakeArgString(getToolChain().GetProgramPath(C, CC1Name));
|
||||
Args.MakeArgString(getToolChain().GetProgramPath(CC1Name));
|
||||
Dest.addCommand(new Command(JA, *this, Exec, CmdArgs));
|
||||
}
|
||||
|
||||
@ -2198,7 +2196,7 @@ void darwin::Compile::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
|
||||
const char *CC1Name = getCC1Name(Inputs[0].getType());
|
||||
const char *Exec =
|
||||
Args.MakeArgString(getToolChain().GetProgramPath(C, CC1Name));
|
||||
Args.MakeArgString(getToolChain().GetProgramPath(CC1Name));
|
||||
Dest.addCommand(new Command(JA, *this, Exec, CmdArgs));
|
||||
}
|
||||
|
||||
@ -2253,7 +2251,7 @@ void darwin::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
// asm_final spec is empty.
|
||||
|
||||
const char *Exec =
|
||||
Args.MakeArgString(getToolChain().GetProgramPath(C, "as"));
|
||||
Args.MakeArgString(getToolChain().GetProgramPath("as"));
|
||||
Dest.addCommand(new Command(JA, *this, Exec, CmdArgs));
|
||||
}
|
||||
|
||||
@ -2356,8 +2354,15 @@ void darwin::Link::AddLinkArgs(const ArgList &Args,
|
||||
Args.AddAllArgs(CmdArgs, options::OPT_multiply__defined);
|
||||
Args.AddAllArgs(CmdArgs, options::OPT_multiply__defined__unused);
|
||||
|
||||
if (Args.hasArg(options::OPT_fpie))
|
||||
CmdArgs.push_back("-pie");
|
||||
if (const Arg *A = Args.getLastArg(options::OPT_fpie, options::OPT_fPIE,
|
||||
options::OPT_fno_pie,
|
||||
options::OPT_fno_PIE)) {
|
||||
if (A->getOption().matches(options::OPT_fpie) ||
|
||||
A->getOption().matches(options::OPT_fPIE))
|
||||
CmdArgs.push_back("-pie");
|
||||
else
|
||||
CmdArgs.push_back("-no_pie");
|
||||
}
|
||||
|
||||
Args.AddLastArg(CmdArgs, options::OPT_prebind);
|
||||
Args.AddLastArg(CmdArgs, options::OPT_noprebind);
|
||||
@ -2505,7 +2510,7 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
Args.hasArg(options::OPT_shared_libgcc) &&
|
||||
getDarwinToolChain().isMacosxVersionLT(10, 5)) {
|
||||
const char *Str =
|
||||
Args.MakeArgString(getToolChain().GetFilePath(C, "crt3.o"));
|
||||
Args.MakeArgString(getToolChain().GetFilePath("crt3.o"));
|
||||
CmdArgs.push_back(Str);
|
||||
}
|
||||
}
|
||||
@ -2565,7 +2570,7 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
Args.AddAllArgs(CmdArgs, options::OPT_F);
|
||||
|
||||
const char *Exec =
|
||||
Args.MakeArgString(getToolChain().GetProgramPath(C, "ld"));
|
||||
Args.MakeArgString(getToolChain().GetProgramPath("ld"));
|
||||
Dest.addCommand(new Command(JA, *this, Exec, CmdArgs));
|
||||
}
|
||||
|
||||
@ -2589,7 +2594,7 @@ void darwin::Lipo::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
CmdArgs.push_back(II.getFilename());
|
||||
}
|
||||
const char *Exec =
|
||||
Args.MakeArgString(getToolChain().GetProgramPath(C, "lipo"));
|
||||
Args.MakeArgString(getToolChain().GetProgramPath("lipo"));
|
||||
Dest.addCommand(new Command(JA, *this, Exec, CmdArgs));
|
||||
}
|
||||
|
||||
@ -2609,7 +2614,7 @@ void darwin::Dsymutil::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
CmdArgs.push_back(Output.getFilename());
|
||||
|
||||
const char *Exec =
|
||||
Args.MakeArgString(getToolChain().GetProgramPath(C, "dsymutil"));
|
||||
Args.MakeArgString(getToolChain().GetProgramPath("dsymutil"));
|
||||
Dest.addCommand(new Command(JA, *this, Exec, CmdArgs));
|
||||
}
|
||||
|
||||
@ -2639,7 +2644,7 @@ void auroraux::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
}
|
||||
|
||||
const char *Exec =
|
||||
Args.MakeArgString(getToolChain().GetProgramPath(C, "gas"));
|
||||
Args.MakeArgString(getToolChain().GetProgramPath("gas"));
|
||||
Dest.addCommand(new Command(JA, *this, Exec, CmdArgs));
|
||||
}
|
||||
|
||||
@ -2685,17 +2690,17 @@ void auroraux::Link::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
!Args.hasArg(options::OPT_nostartfiles)) {
|
||||
if (!Args.hasArg(options::OPT_shared)) {
|
||||
CmdArgs.push_back(Args.MakeArgString(
|
||||
getToolChain().GetFilePath(C, "crt1.o")));
|
||||
getToolChain().GetFilePath("crt1.o")));
|
||||
CmdArgs.push_back(Args.MakeArgString(
|
||||
getToolChain().GetFilePath(C, "crti.o")));
|
||||
getToolChain().GetFilePath("crti.o")));
|
||||
CmdArgs.push_back(Args.MakeArgString(
|
||||
getToolChain().GetFilePath(C, "crtbegin.o")));
|
||||
getToolChain().GetFilePath("crtbegin.o")));
|
||||
} else {
|
||||
CmdArgs.push_back(Args.MakeArgString(
|
||||
getToolChain().GetFilePath(C, "crti.o")));
|
||||
getToolChain().GetFilePath("crti.o")));
|
||||
}
|
||||
CmdArgs.push_back(Args.MakeArgString(
|
||||
getToolChain().GetFilePath(C, "crtn.o")));
|
||||
getToolChain().GetFilePath("crtn.o")));
|
||||
}
|
||||
|
||||
CmdArgs.push_back(Args.MakeArgString("-L/opt/gcc4/lib/gcc/"
|
||||
@ -2741,11 +2746,11 @@ void auroraux::Link::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
!Args.hasArg(options::OPT_nostartfiles)) {
|
||||
if (!Args.hasArg(options::OPT_shared))
|
||||
CmdArgs.push_back(Args.MakeArgString(
|
||||
getToolChain().GetFilePath(C, "crtend.o")));
|
||||
getToolChain().GetFilePath("crtend.o")));
|
||||
}
|
||||
|
||||
const char *Exec =
|
||||
Args.MakeArgString(getToolChain().GetProgramPath(C, "ld"));
|
||||
Args.MakeArgString(getToolChain().GetProgramPath("ld"));
|
||||
Dest.addCommand(new Command(JA, *this, Exec, CmdArgs));
|
||||
}
|
||||
|
||||
@ -2775,7 +2780,7 @@ void openbsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
}
|
||||
|
||||
const char *Exec =
|
||||
Args.MakeArgString(getToolChain().GetProgramPath(C, "as"));
|
||||
Args.MakeArgString(getToolChain().GetProgramPath("as"));
|
||||
Dest.addCommand(new Command(JA, *this, Exec, CmdArgs));
|
||||
}
|
||||
|
||||
@ -2820,12 +2825,12 @@ void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
!Args.hasArg(options::OPT_nostartfiles)) {
|
||||
if (!Args.hasArg(options::OPT_shared)) {
|
||||
CmdArgs.push_back(Args.MakeArgString(
|
||||
getToolChain().GetFilePath(C, "crt0.o")));
|
||||
getToolChain().GetFilePath("crt0.o")));
|
||||
CmdArgs.push_back(Args.MakeArgString(
|
||||
getToolChain().GetFilePath(C, "crtbegin.o")));
|
||||
getToolChain().GetFilePath("crtbegin.o")));
|
||||
} else {
|
||||
CmdArgs.push_back(Args.MakeArgString(
|
||||
getToolChain().GetFilePath(C, "crtbeginS.o")));
|
||||
getToolChain().GetFilePath("crtbeginS.o")));
|
||||
}
|
||||
}
|
||||
|
||||
@ -2874,14 +2879,14 @@ void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
!Args.hasArg(options::OPT_nostartfiles)) {
|
||||
if (!Args.hasArg(options::OPT_shared))
|
||||
CmdArgs.push_back(Args.MakeArgString(
|
||||
getToolChain().GetFilePath(C, "crtend.o")));
|
||||
getToolChain().GetFilePath("crtend.o")));
|
||||
else
|
||||
CmdArgs.push_back(Args.MakeArgString(
|
||||
getToolChain().GetFilePath(C, "crtendS.o")));
|
||||
getToolChain().GetFilePath("crtendS.o")));
|
||||
}
|
||||
|
||||
const char *Exec =
|
||||
Args.MakeArgString(getToolChain().GetProgramPath(C, "ld"));
|
||||
Args.MakeArgString(getToolChain().GetProgramPath("ld"));
|
||||
Dest.addCommand(new Command(JA, *this, Exec, CmdArgs));
|
||||
}
|
||||
|
||||
@ -2923,7 +2928,7 @@ void freebsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
}
|
||||
|
||||
const char *Exec =
|
||||
Args.MakeArgString(getToolChain().GetProgramPath(C, "as"));
|
||||
Args.MakeArgString(getToolChain().GetProgramPath("as"));
|
||||
Dest.addCommand(new Command(JA, *this, Exec, CmdArgs));
|
||||
}
|
||||
|
||||
@ -2968,16 +2973,16 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
!Args.hasArg(options::OPT_nostartfiles)) {
|
||||
if (!Args.hasArg(options::OPT_shared)) {
|
||||
CmdArgs.push_back(Args.MakeArgString(
|
||||
getToolChain().GetFilePath(C, "crt1.o")));
|
||||
getToolChain().GetFilePath("crt1.o")));
|
||||
CmdArgs.push_back(Args.MakeArgString(
|
||||
getToolChain().GetFilePath(C, "crti.o")));
|
||||
getToolChain().GetFilePath("crti.o")));
|
||||
CmdArgs.push_back(Args.MakeArgString(
|
||||
getToolChain().GetFilePath(C, "crtbegin.o")));
|
||||
getToolChain().GetFilePath("crtbegin.o")));
|
||||
} else {
|
||||
CmdArgs.push_back(Args.MakeArgString(
|
||||
getToolChain().GetFilePath(C, "crti.o")));
|
||||
getToolChain().GetFilePath("crti.o")));
|
||||
CmdArgs.push_back(Args.MakeArgString(
|
||||
getToolChain().GetFilePath(C, "crtbeginS.o")));
|
||||
getToolChain().GetFilePath("crtbeginS.o")));
|
||||
}
|
||||
}
|
||||
|
||||
@ -3037,17 +3042,17 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
if (!Args.hasArg(options::OPT_nostdlib) &&
|
||||
!Args.hasArg(options::OPT_nostartfiles)) {
|
||||
if (!Args.hasArg(options::OPT_shared))
|
||||
CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C,
|
||||
CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(
|
||||
"crtend.o")));
|
||||
else
|
||||
CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C,
|
||||
CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(
|
||||
"crtendS.o")));
|
||||
CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C,
|
||||
CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(
|
||||
"crtn.o")));
|
||||
}
|
||||
|
||||
const char *Exec =
|
||||
Args.MakeArgString(getToolChain().GetProgramPath(C, "ld"));
|
||||
Args.MakeArgString(getToolChain().GetProgramPath("ld"));
|
||||
Dest.addCommand(new Command(JA, *this, Exec, CmdArgs));
|
||||
}
|
||||
|
||||
@ -3077,7 +3082,7 @@ void minix::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
}
|
||||
|
||||
const char *Exec =
|
||||
Args.MakeArgString(getToolChain().GetProgramPath(C, "gas"));
|
||||
Args.MakeArgString(getToolChain().GetProgramPath("gas"));
|
||||
Dest.addCommand(new Command(JA, *this, Exec, CmdArgs));
|
||||
}
|
||||
|
||||
@ -3101,7 +3106,7 @@ void minix::Link::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
|
||||
if (!Args.hasArg(options::OPT_nostdlib) &&
|
||||
!Args.hasArg(options::OPT_nostartfiles))
|
||||
CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C,
|
||||
CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(
|
||||
"/usr/gnu/lib/crtso.o")));
|
||||
|
||||
Args.AddAllArgs(CmdArgs, options::OPT_L);
|
||||
@ -3145,12 +3150,12 @@ void minix::Link::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
|
||||
if (!Args.hasArg(options::OPT_nostdlib) &&
|
||||
!Args.hasArg(options::OPT_nostartfiles)) {
|
||||
CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C,
|
||||
CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(
|
||||
"/usr/gnu/lib/libend.a")));
|
||||
}
|
||||
|
||||
const char *Exec =
|
||||
Args.MakeArgString(getToolChain().GetProgramPath(C, "/usr/gnu/bin/gld"));
|
||||
Args.MakeArgString(getToolChain().GetProgramPath("/usr/gnu/bin/gld"));
|
||||
Dest.addCommand(new Command(JA, *this, Exec, CmdArgs));
|
||||
}
|
||||
|
||||
@ -3189,7 +3194,7 @@ void dragonfly::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
}
|
||||
|
||||
const char *Exec =
|
||||
Args.MakeArgString(getToolChain().GetProgramPath(C, "as"));
|
||||
Args.MakeArgString(getToolChain().GetProgramPath("as"));
|
||||
Dest.addCommand(new Command(JA, *this, Exec, CmdArgs));
|
||||
}
|
||||
|
||||
@ -3233,16 +3238,16 @@ void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
!Args.hasArg(options::OPT_nostartfiles)) {
|
||||
if (!Args.hasArg(options::OPT_shared)) {
|
||||
CmdArgs.push_back(
|
||||
Args.MakeArgString(getToolChain().GetFilePath(C, "crt1.o")));
|
||||
Args.MakeArgString(getToolChain().GetFilePath("crt1.o")));
|
||||
CmdArgs.push_back(
|
||||
Args.MakeArgString(getToolChain().GetFilePath(C, "crti.o")));
|
||||
Args.MakeArgString(getToolChain().GetFilePath("crti.o")));
|
||||
CmdArgs.push_back(
|
||||
Args.MakeArgString(getToolChain().GetFilePath(C, "crtbegin.o")));
|
||||
Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o")));
|
||||
} else {
|
||||
CmdArgs.push_back(
|
||||
Args.MakeArgString(getToolChain().GetFilePath(C, "crti.o")));
|
||||
Args.MakeArgString(getToolChain().GetFilePath("crti.o")));
|
||||
CmdArgs.push_back(
|
||||
Args.MakeArgString(getToolChain().GetFilePath(C, "crtbeginS.o")));
|
||||
Args.MakeArgString(getToolChain().GetFilePath("crtbeginS.o")));
|
||||
}
|
||||
}
|
||||
|
||||
@ -3313,15 +3318,15 @@ void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA,
|
||||
!Args.hasArg(options::OPT_nostartfiles)) {
|
||||
if (!Args.hasArg(options::OPT_shared))
|
||||
CmdArgs.push_back(Args.MakeArgString(
|
||||
getToolChain().GetFilePath(C, "crtend.o")));
|
||||
getToolChain().GetFilePath("crtend.o")));
|
||||
else
|
||||
CmdArgs.push_back(Args.MakeArgString(
|
||||
getToolChain().GetFilePath(C, "crtendS.o")));
|
||||
getToolChain().GetFilePath("crtendS.o")));
|
||||
CmdArgs.push_back(Args.MakeArgString(
|
||||
getToolChain().GetFilePath(C, "crtn.o")));
|
||||
getToolChain().GetFilePath("crtn.o")));
|
||||
}
|
||||
|
||||
const char *Exec =
|
||||
Args.MakeArgString(getToolChain().GetProgramPath(C, "ld"));
|
||||
Args.MakeArgString(getToolChain().GetProgramPath("ld"));
|
||||
Dest.addCommand(new Command(JA, *this, Exec, CmdArgs));
|
||||
}
|
||||
|
@ -74,11 +74,13 @@ class PCHInfoCollector : public PCHReaderListener {
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool ReadPredefinesBuffer(llvm::StringRef PCHPredef,
|
||||
FileID PCHBufferID,
|
||||
virtual bool ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
|
||||
llvm::StringRef OriginalFileName,
|
||||
std::string &SuggestedPredefines) {
|
||||
Predefines = PCHPredef;
|
||||
Predefines = Buffers[0].Data;
|
||||
for (unsigned I = 1, N = Buffers.size(); I != N; ++I) {
|
||||
Predefines += Buffers[I].Data;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -80,7 +80,7 @@ ASTConsumer *GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI,
|
||||
if (!OS)
|
||||
return 0;
|
||||
|
||||
const PCHReader *Chain = CI.getInvocation().getFrontendOpts().ChainedPCH ?
|
||||
PCHReader *Chain = CI.getInvocation().getFrontendOpts().ChainedPCH ?
|
||||
CI.getPCHReader() : 0;
|
||||
const char *isysroot = CI.getFrontendOpts().RelocatablePCH ?
|
||||
Sysroot.c_str() : 0;
|
||||
|
@ -28,28 +28,28 @@ using namespace clang;
|
||||
namespace {
|
||||
class PCHGenerator : public SemaConsumer {
|
||||
const Preprocessor &PP;
|
||||
const PCHReader *Chain;
|
||||
const char *isysroot;
|
||||
llvm::raw_ostream *Out;
|
||||
Sema *SemaPtr;
|
||||
MemorizeStatCalls *StatCalls; // owned by the FileManager
|
||||
std::vector<unsigned char> Buffer;
|
||||
llvm::BitstreamWriter Stream;
|
||||
PCHWriter Writer;
|
||||
|
||||
public:
|
||||
explicit PCHGenerator(const Preprocessor &PP,
|
||||
const PCHReader *Chain,
|
||||
const char *isysroot,
|
||||
llvm::raw_ostream *Out);
|
||||
PCHGenerator(const Preprocessor &PP, PCHReader *Chain,
|
||||
const char *isysroot, llvm::raw_ostream *Out);
|
||||
virtual void InitializeSema(Sema &S) { SemaPtr = &S; }
|
||||
virtual void HandleTranslationUnit(ASTContext &Ctx);
|
||||
};
|
||||
}
|
||||
|
||||
PCHGenerator::PCHGenerator(const Preprocessor &PP,
|
||||
const PCHReader *Chain,
|
||||
PCHReader *Chain,
|
||||
const char *isysroot,
|
||||
llvm::raw_ostream *OS)
|
||||
: PP(PP), Chain(Chain), isysroot(isysroot), Out(OS), SemaPtr(0),
|
||||
StatCalls(0) {
|
||||
: PP(PP), isysroot(isysroot), Out(OS), SemaPtr(0), StatCalls(0),
|
||||
Stream(Buffer), Writer(Stream, Chain) {
|
||||
|
||||
// Install a stat() listener to keep track of all of the stat()
|
||||
// calls.
|
||||
@ -61,25 +61,23 @@ void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) {
|
||||
if (PP.getDiagnostics().hasErrorOccurred())
|
||||
return;
|
||||
|
||||
// Write the PCH contents into a buffer
|
||||
std::vector<unsigned char> Buffer;
|
||||
llvm::BitstreamWriter Stream(Buffer);
|
||||
PCHWriter Writer(Stream);
|
||||
|
||||
// Emit the PCH file
|
||||
assert(SemaPtr && "No Sema?");
|
||||
Writer.WritePCH(*SemaPtr, StatCalls, Chain, isysroot);
|
||||
Writer.WritePCH(*SemaPtr, StatCalls, isysroot);
|
||||
|
||||
// Write the generated bitstream to "Out".
|
||||
Out->write((char *)&Buffer.front(), Buffer.size());
|
||||
|
||||
// Make sure it hits disk now.
|
||||
Out->flush();
|
||||
|
||||
// Free up some memory, in case the process is kept alive.
|
||||
Buffer.clear();
|
||||
}
|
||||
|
||||
ASTConsumer *clang::CreatePCHGenerator(const Preprocessor &PP,
|
||||
llvm::raw_ostream *OS,
|
||||
const PCHReader *Chain,
|
||||
PCHReader *Chain,
|
||||
const char *isysroot) {
|
||||
return new PCHGenerator(PP, Chain, isysroot, OS);
|
||||
}
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
#include "clang/Frontend/PCHReader.h"
|
||||
#include "clang/Frontend/FrontendDiagnostic.h"
|
||||
#include "clang/Frontend/PCHDeserializationListener.h"
|
||||
#include "clang/Frontend/Utils.h"
|
||||
#include "../Sema/Sema.h" // FIXME: move Sema headers elsewhere
|
||||
#include "clang/AST/ASTConsumer.h"
|
||||
@ -140,8 +141,86 @@ bool PCHValidator::ReadTargetTriple(llvm::StringRef Triple) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PCHValidator::ReadPredefinesBuffer(llvm::StringRef PCHPredef,
|
||||
FileID PCHBufferID,
|
||||
struct EmptyStringRef {
|
||||
bool operator ()(llvm::StringRef r) const { return r.empty(); }
|
||||
};
|
||||
struct EmptyBlock {
|
||||
bool operator ()(const PCHPredefinesBlock &r) const { return r.Data.empty(); }
|
||||
};
|
||||
|
||||
static bool EqualConcatenations(llvm::SmallVector<llvm::StringRef, 2> L,
|
||||
PCHPredefinesBlocks R) {
|
||||
// First, sum up the lengths.
|
||||
unsigned LL = 0, RL = 0;
|
||||
for (unsigned I = 0, N = L.size(); I != N; ++I) {
|
||||
LL += L[I].size();
|
||||
}
|
||||
for (unsigned I = 0, N = R.size(); I != N; ++I) {
|
||||
RL += R[I].Data.size();
|
||||
}
|
||||
if (LL != RL)
|
||||
return false;
|
||||
if (LL == 0 && RL == 0)
|
||||
return true;
|
||||
|
||||
// Kick out empty parts, they confuse the algorithm below.
|
||||
L.erase(std::remove_if(L.begin(), L.end(), EmptyStringRef()), L.end());
|
||||
R.erase(std::remove_if(R.begin(), R.end(), EmptyBlock()), R.end());
|
||||
|
||||
// Do it the hard way. At this point, both vectors must be non-empty.
|
||||
llvm::StringRef LR = L[0], RR = R[0].Data;
|
||||
unsigned LI = 0, RI = 0, LN = L.size(), RN = R.size();
|
||||
for (;;) {
|
||||
// Compare the current pieces.
|
||||
if (LR.size() == RR.size()) {
|
||||
// If they're the same length, it's pretty easy.
|
||||
if (LR != RR)
|
||||
return false;
|
||||
// Both pieces are done, advance.
|
||||
++LI;
|
||||
++RI;
|
||||
// If either string is done, they're both done, since they're the same
|
||||
// length.
|
||||
if (LI == LN) {
|
||||
assert(RI == RN && "Strings not the same length after all?");
|
||||
return true;
|
||||
}
|
||||
LR = L[LI];
|
||||
RR = R[RI].Data;
|
||||
} else if (LR.size() < RR.size()) {
|
||||
// Right piece is longer.
|
||||
if (!RR.startswith(LR))
|
||||
return false;
|
||||
++LI;
|
||||
assert(LI != LN && "Strings not the same length after all?");
|
||||
RR = RR.substr(LR.size());
|
||||
LR = L[LI];
|
||||
} else {
|
||||
// Left piece is longer.
|
||||
if (!LR.startswith(RR))
|
||||
return false;
|
||||
++RI;
|
||||
assert(RI != RN && "Strings not the same length after all?");
|
||||
LR = LR.substr(RR.size());
|
||||
RR = R[RI].Data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static std::pair<FileID, llvm::StringRef::size_type>
|
||||
FindMacro(const PCHPredefinesBlocks &Buffers, llvm::StringRef MacroDef) {
|
||||
std::pair<FileID, llvm::StringRef::size_type> Res;
|
||||
for (unsigned I = 0, N = Buffers.size(); I != N; ++I) {
|
||||
Res.second = Buffers[I].Data.find(MacroDef);
|
||||
if (Res.second != llvm::StringRef::npos) {
|
||||
Res.first = Buffers[I].BufferID;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return Res;
|
||||
}
|
||||
|
||||
bool PCHValidator::ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers,
|
||||
llvm::StringRef OriginalFileName,
|
||||
std::string &SuggestedPredefines) {
|
||||
// We are in the context of an implicit include, so the predefines buffer will
|
||||
@ -160,9 +239,15 @@ bool PCHValidator::ReadPredefinesBuffer(llvm::StringRef PCHPredef,
|
||||
return true;
|
||||
}
|
||||
|
||||
// If the predefines is equal to the joined left and right halves, we're done!
|
||||
if (Left.size() + Right.size() == PCHPredef.size() &&
|
||||
PCHPredef.startswith(Left) && PCHPredef.endswith(Right))
|
||||
// If the concatenation of all the PCH buffers is equal to the adjusted
|
||||
// command line, we're done.
|
||||
// We build a SmallVector of the command line here, because we'll eventually
|
||||
// need to support an arbitrary amount of pieces anyway (when we have chained
|
||||
// PCH reading).
|
||||
llvm::SmallVector<llvm::StringRef, 2> CommandLine;
|
||||
CommandLine.push_back(Left);
|
||||
CommandLine.push_back(Right);
|
||||
if (EqualConcatenations(CommandLine, Buffers))
|
||||
return false;
|
||||
|
||||
SourceManager &SourceMgr = PP.getSourceManager();
|
||||
@ -170,7 +255,8 @@ bool PCHValidator::ReadPredefinesBuffer(llvm::StringRef PCHPredef,
|
||||
// The predefines buffers are different. Determine what the differences are,
|
||||
// and whether they require us to reject the PCH file.
|
||||
llvm::SmallVector<llvm::StringRef, 8> PCHLines;
|
||||
PCHPredef.split(PCHLines, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
|
||||
for (unsigned I = 0, N = Buffers.size(); I != N; ++I)
|
||||
Buffers[I].Data.split(PCHLines, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
|
||||
|
||||
llvm::SmallVector<llvm::StringRef, 8> CmdLineLines;
|
||||
Left.split(CmdLineLines, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
|
||||
@ -235,10 +321,12 @@ bool PCHValidator::ReadPredefinesBuffer(llvm::StringRef PCHPredef,
|
||||
<< MacroName;
|
||||
|
||||
// Show the definition of this macro within the PCH file.
|
||||
llvm::StringRef::size_type Offset = PCHPredef.find(Missing);
|
||||
assert(Offset != llvm::StringRef::npos && "Unable to find macro!");
|
||||
SourceLocation PCHMissingLoc = SourceMgr.getLocForStartOfFile(PCHBufferID)
|
||||
.getFileLocWithOffset(Offset);
|
||||
std::pair<FileID, llvm::StringRef::size_type> MacroLoc =
|
||||
FindMacro(Buffers, Missing);
|
||||
assert(MacroLoc.second!=llvm::StringRef::npos && "Unable to find macro!");
|
||||
SourceLocation PCHMissingLoc =
|
||||
SourceMgr.getLocForStartOfFile(MacroLoc.first)
|
||||
.getFileLocWithOffset(MacroLoc.second);
|
||||
Reader.Diag(PCHMissingLoc, diag::note_pch_macro_defined_as) << MacroName;
|
||||
|
||||
ConflictingDefines = true;
|
||||
@ -256,10 +344,12 @@ bool PCHValidator::ReadPredefinesBuffer(llvm::StringRef PCHPredef,
|
||||
}
|
||||
|
||||
// Show the definition of this macro within the PCH file.
|
||||
llvm::StringRef::size_type Offset = PCHPredef.find(Missing);
|
||||
assert(Offset != llvm::StringRef::npos && "Unable to find macro!");
|
||||
SourceLocation PCHMissingLoc = SourceMgr.getLocForStartOfFile(PCHBufferID)
|
||||
.getFileLocWithOffset(Offset);
|
||||
std::pair<FileID, llvm::StringRef::size_type> MacroLoc =
|
||||
FindMacro(Buffers, Missing);
|
||||
assert(MacroLoc.second!=llvm::StringRef::npos && "Unable to find macro!");
|
||||
SourceLocation PCHMissingLoc =
|
||||
SourceMgr.getLocForStartOfFile(MacroLoc.first)
|
||||
.getFileLocWithOffset(MacroLoc.second);
|
||||
Reader.Diag(PCHMissingLoc, diag::note_using_macro_def_from_pch);
|
||||
}
|
||||
|
||||
@ -324,10 +414,10 @@ void PCHValidator::ReadCounter(unsigned Value) {
|
||||
|
||||
PCHReader::PCHReader(Preprocessor &PP, ASTContext *Context,
|
||||
const char *isysroot)
|
||||
: Listener(new PCHValidator(PP, *this)), SourceMgr(PP.getSourceManager()),
|
||||
FileMgr(PP.getFileManager()), Diags(PP.getDiagnostics()),
|
||||
SemaObj(0), PP(&PP), Context(Context), StatCache(0), Consumer(0),
|
||||
IdentifierTableData(0), IdentifierLookupTable(0),
|
||||
: Listener(new PCHValidator(PP, *this)), DeserializationListener(0),
|
||||
SourceMgr(PP.getSourceManager()), FileMgr(PP.getFileManager()),
|
||||
Diags(PP.getDiagnostics()), SemaObj(0), PP(&PP), Context(Context),
|
||||
StatCache(0), Consumer(0), IdentifierTableData(0), IdentifierLookupTable(0),
|
||||
IdentifierOffsets(0),
|
||||
MethodPoolLookupTable(0), MethodPoolLookupTableData(0),
|
||||
TotalSelectorsInMethodPool(0), SelectorOffsets(0),
|
||||
@ -343,8 +433,8 @@ PCHReader::PCHReader(Preprocessor &PP, ASTContext *Context,
|
||||
|
||||
PCHReader::PCHReader(SourceManager &SourceMgr, FileManager &FileMgr,
|
||||
Diagnostic &Diags, const char *isysroot)
|
||||
: SourceMgr(SourceMgr), FileMgr(FileMgr), Diags(Diags),
|
||||
SemaObj(0), PP(0), Context(0), StatCache(0), Consumer(0),
|
||||
: DeserializationListener(0), SourceMgr(SourceMgr), FileMgr(FileMgr),
|
||||
Diags(Diags), SemaObj(0), PP(0), Context(0), StatCache(0), Consumer(0),
|
||||
IdentifierTableData(0), IdentifierLookupTable(0),
|
||||
IdentifierOffsets(0),
|
||||
MethodPoolLookupTable(0), MethodPoolLookupTableData(0),
|
||||
@ -609,27 +699,18 @@ void PCHReader::Error(const char *Msg) {
|
||||
Diag(diag::err_fe_pch_malformed) << Msg;
|
||||
}
|
||||
|
||||
/// \brief Check the contents of the predefines buffer against the
|
||||
/// contents of the predefines buffer used to build the PCH file.
|
||||
/// \brief Check the contents of the concatenation of all predefines buffers in
|
||||
/// the PCH chain against the contents of the predefines buffer of the current
|
||||
/// compiler invocation.
|
||||
///
|
||||
/// The contents of the two predefines buffers should be the same. If
|
||||
/// not, then some command-line option changed the preprocessor state
|
||||
/// and we must reject the PCH file.
|
||||
///
|
||||
/// \param PCHPredef The start of the predefines buffer in the PCH
|
||||
/// file.
|
||||
///
|
||||
/// \param PCHPredefLen The length of the predefines buffer in the PCH
|
||||
/// file.
|
||||
///
|
||||
/// \param PCHBufferID The FileID for the PCH predefines buffer.
|
||||
/// The contents should be the same. If not, then some command-line option
|
||||
/// changed the preprocessor state and we must probably reject the PCH file.
|
||||
///
|
||||
/// \returns true if there was a mismatch (in which case the PCH file
|
||||
/// should be ignored), or false otherwise.
|
||||
bool PCHReader::CheckPredefinesBuffer(llvm::StringRef PCHPredef,
|
||||
FileID PCHBufferID) {
|
||||
bool PCHReader::CheckPredefinesBuffers() {
|
||||
if (Listener)
|
||||
return Listener->ReadPredefinesBuffer(PCHPredef, PCHBufferID,
|
||||
return Listener->ReadPredefinesBuffer(PCHPredefinesBuffers,
|
||||
ActualOriginalFileName,
|
||||
SuggestedPredefines);
|
||||
return false;
|
||||
@ -958,9 +1039,11 @@ PCHReader::PCHReadResult PCHReader::ReadSLocEntryRecord(unsigned ID) {
|
||||
FileID BufferID = SourceMgr.createFileIDForMemBuffer(Buffer, ID, Offset);
|
||||
|
||||
if (strcmp(Name, "<built-in>") == 0) {
|
||||
PCHPredefinesBufferID = BufferID;
|
||||
PCHPredefines = BlobStart;
|
||||
PCHPredefinesLen = BlobLen - 1;
|
||||
PCHPredefinesBlock Block = {
|
||||
BufferID,
|
||||
llvm::StringRef(BlobStart, BlobLen - 1)
|
||||
};
|
||||
PCHPredefinesBuffers.push_back(Block);
|
||||
}
|
||||
|
||||
break;
|
||||
@ -1636,8 +1719,7 @@ PCHReader::PCHReadResult PCHReader::ReadPCH(const std::string &FileName) {
|
||||
}
|
||||
|
||||
// Check the predefines buffer.
|
||||
if (CheckPredefinesBuffer(llvm::StringRef(PCHPredefines, PCHPredefinesLen),
|
||||
PCHPredefinesBufferID))
|
||||
if (CheckPredefinesBuffers())
|
||||
return IgnorePCH;
|
||||
|
||||
if (PP) {
|
||||
@ -2545,8 +2627,12 @@ QualType PCHReader::GetType(pch::TypeID ID) {
|
||||
|
||||
Index -= pch::NUM_PREDEF_TYPE_IDS;
|
||||
//assert(Index < TypesLoaded.size() && "Type index out-of-range");
|
||||
if (TypesLoaded[Index].isNull())
|
||||
if (TypesLoaded[Index].isNull()) {
|
||||
TypesLoaded[Index] = ReadTypeRecord(TypeOffsets[Index]);
|
||||
TypesLoaded[Index]->setFromPCH();
|
||||
if (DeserializationListener)
|
||||
DeserializationListener->TypeRead(ID, TypesLoaded[Index]);
|
||||
}
|
||||
|
||||
return TypesLoaded[Index].withFastQualifiers(FastQuals);
|
||||
}
|
||||
@ -2592,8 +2678,11 @@ Decl *PCHReader::GetExternalDecl(uint32_t ID) {
|
||||
}
|
||||
|
||||
TranslationUnitDecl *PCHReader::GetTranslationUnitDecl() {
|
||||
if (!DeclsLoaded[0])
|
||||
if (!DeclsLoaded[0]) {
|
||||
ReadDeclRecord(DeclOffsets[0], 0);
|
||||
if (DeserializationListener)
|
||||
DeserializationListener->DeclRead(0, DeclsLoaded[0]);
|
||||
}
|
||||
|
||||
return cast<TranslationUnitDecl>(DeclsLoaded[0]);
|
||||
}
|
||||
@ -2608,8 +2697,11 @@ Decl *PCHReader::GetDecl(pch::DeclID ID) {
|
||||
}
|
||||
|
||||
unsigned Index = ID - 1;
|
||||
if (!DeclsLoaded[Index])
|
||||
if (!DeclsLoaded[Index]) {
|
||||
ReadDeclRecord(DeclOffsets[Index], Index);
|
||||
if (DeserializationListener)
|
||||
DeserializationListener->DeclRead(ID, DeclsLoaded[Index]);
|
||||
}
|
||||
|
||||
return DeclsLoaded[Index];
|
||||
}
|
||||
|
@ -743,8 +743,7 @@ adjustFilenameForRelocatablePCH(const char *Filename, const char *isysroot) {
|
||||
}
|
||||
|
||||
/// \brief Write the PCH metadata (e.g., i686-apple-darwin9).
|
||||
void PCHWriter::WriteMetadata(ASTContext &Context, const PCHReader *Chain,
|
||||
const char *isysroot) {
|
||||
void PCHWriter::WriteMetadata(ASTContext &Context, const char *isysroot) {
|
||||
using namespace llvm;
|
||||
|
||||
// Metadata
|
||||
@ -2074,13 +2073,16 @@ void PCHWriter::SetSelectorOffset(Selector Sel, uint32_t Offset) {
|
||||
SelectorOffsets[ID - 1] = Offset;
|
||||
}
|
||||
|
||||
PCHWriter::PCHWriter(llvm::BitstreamWriter &Stream)
|
||||
: Stream(Stream), NextTypeID(pch::NUM_PREDEF_TYPE_IDS),
|
||||
PCHWriter::PCHWriter(llvm::BitstreamWriter &Stream, PCHReader *Chain)
|
||||
: Stream(Stream), Chain(Chain), NextTypeID(pch::NUM_PREDEF_TYPE_IDS),
|
||||
CollectedStmts(&StmtsToEmit), NumStatements(0), NumMacros(0),
|
||||
NumLexicalDeclContexts(0), NumVisibleDeclContexts(0) { }
|
||||
NumLexicalDeclContexts(0), NumVisibleDeclContexts(0) {
|
||||
if (Chain)
|
||||
Chain->setDeserializationListener(this);
|
||||
}
|
||||
|
||||
void PCHWriter::WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls,
|
||||
const PCHReader *Chain, const char *isysroot) {
|
||||
const char *isysroot) {
|
||||
// Emit the file header.
|
||||
Stream.Emit((unsigned)'C', 8);
|
||||
Stream.Emit((unsigned)'P', 8);
|
||||
@ -2090,7 +2092,7 @@ void PCHWriter::WritePCH(Sema &SemaRef, MemorizeStatCalls *StatCalls,
|
||||
WriteBlockInfoBlock();
|
||||
|
||||
if (Chain)
|
||||
WritePCHChain(SemaRef, StatCalls, Chain, isysroot);
|
||||
WritePCHChain(SemaRef, StatCalls, isysroot);
|
||||
else
|
||||
WritePCHCore(SemaRef, StatCalls, isysroot);
|
||||
}
|
||||
@ -2164,7 +2166,7 @@ void PCHWriter::WritePCHCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
|
||||
// Write the remaining PCH contents.
|
||||
RecordData Record;
|
||||
Stream.EnterSubblock(pch::PCH_BLOCK_ID, 5);
|
||||
WriteMetadata(Context, 0, isysroot);
|
||||
WriteMetadata(Context, isysroot);
|
||||
WriteLanguageOptions(Context.getLangOptions());
|
||||
if (StatCalls && !isysroot)
|
||||
WriteStatCache(*StatCalls);
|
||||
@ -2275,7 +2277,7 @@ void PCHWriter::WritePCHCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
|
||||
}
|
||||
|
||||
void PCHWriter::WritePCHChain(Sema &SemaRef, MemorizeStatCalls *StatCalls,
|
||||
const PCHReader *Chain, const char *isysroot) {
|
||||
const char *isysroot) {
|
||||
using namespace llvm;
|
||||
|
||||
ASTContext &Context = SemaRef.Context;
|
||||
@ -2284,7 +2286,7 @@ void PCHWriter::WritePCHChain(Sema &SemaRef, MemorizeStatCalls *StatCalls,
|
||||
|
||||
RecordData Record;
|
||||
Stream.EnterSubblock(pch::PCH_BLOCK_ID, 5);
|
||||
WriteMetadata(Context, Chain, isysroot);
|
||||
WriteMetadata(Context, isysroot);
|
||||
// FIXME: StatCache
|
||||
// FIXME: Source manager block
|
||||
|
||||
@ -2737,3 +2739,10 @@ void PCHWriter::AddCXXBaseSpecifier(const CXXBaseSpecifier &Base,
|
||||
AddTypeRef(Base.getType(), Record);
|
||||
AddSourceRange(Base.getSourceRange(), Record);
|
||||
}
|
||||
|
||||
void PCHWriter::TypeRead(pch::TypeID ID, QualType T) {
|
||||
}
|
||||
|
||||
void PCHWriter::DeclRead(pch::DeclID ID, const Decl *D) {
|
||||
}
|
||||
|
||||
|
@ -40,7 +40,7 @@ void RewriteBuffer::RemoveText(unsigned OrigOffset, unsigned Size) {
|
||||
AddReplaceDelta(OrigOffset, -Size);
|
||||
}
|
||||
|
||||
void RewriteBuffer::InsertText(unsigned OrigOffset, const llvm::StringRef &Str,
|
||||
void RewriteBuffer::InsertText(unsigned OrigOffset, llvm::StringRef Str,
|
||||
bool InsertAfter) {
|
||||
|
||||
// Nothing to insert, exit early.
|
||||
@ -57,7 +57,7 @@ void RewriteBuffer::InsertText(unsigned OrigOffset, const llvm::StringRef &Str,
|
||||
/// buffer with a new string. This is effectively a combined "remove+insert"
|
||||
/// operation.
|
||||
void RewriteBuffer::ReplaceText(unsigned OrigOffset, unsigned OrigLength,
|
||||
const llvm::StringRef &NewStr) {
|
||||
llvm::StringRef NewStr) {
|
||||
unsigned RealOffset = getMappedOffset(OrigOffset, true);
|
||||
Buffer.erase(RealOffset, OrigLength);
|
||||
Buffer.insert(RealOffset, NewStr.begin(), NewStr.end());
|
||||
@ -185,7 +185,7 @@ RewriteBuffer &Rewriter::getEditBuffer(FileID FID) {
|
||||
|
||||
/// InsertText - Insert the specified string at the specified location in the
|
||||
/// original buffer.
|
||||
bool Rewriter::InsertText(SourceLocation Loc, const llvm::StringRef &Str,
|
||||
bool Rewriter::InsertText(SourceLocation Loc, llvm::StringRef Str,
|
||||
bool InsertAfter) {
|
||||
if (!isRewritable(Loc)) return true;
|
||||
FileID FID;
|
||||
@ -207,7 +207,7 @@ bool Rewriter::RemoveText(SourceLocation Start, unsigned Length) {
|
||||
/// buffer with a new string. This is effectively a combined "remove/insert"
|
||||
/// operation.
|
||||
bool Rewriter::ReplaceText(SourceLocation Start, unsigned OrigLength,
|
||||
const llvm::StringRef &NewStr) {
|
||||
llvm::StringRef NewStr) {
|
||||
if (!isRewritable(Start)) return true;
|
||||
FileID StartFileID;
|
||||
unsigned StartOffs = getLocationOffsetAndFileID(Start, StartFileID);
|
||||
|
@ -118,7 +118,8 @@ struct FunctionScopeInfo {
|
||||
|
||||
/// \brief Set true when a function, method contains a VLA or ObjC try block,
|
||||
/// which introduce scopes that need to be checked for goto conditions. If a
|
||||
/// function does not contain this, then it need not have the jump checker run on it.
|
||||
/// function does not contain this, then it need not have the jump checker run
|
||||
/// on it.
|
||||
bool NeedsScopeChecking;
|
||||
|
||||
/// \brief The number of errors that had occurred before starting this
|
||||
@ -1540,7 +1541,7 @@ class Sema : public Action {
|
||||
|
||||
// Decl attributes - this routine is the top level dispatcher.
|
||||
void ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD);
|
||||
void ProcessDeclAttributeList(Scope *S, Decl *D, const AttributeList *AttrList);
|
||||
void ProcessDeclAttributeList(Scope *S, Decl *D, const AttributeList *AL);
|
||||
|
||||
void WarnUndefinedMethod(SourceLocation ImpLoc, ObjCMethodDecl *method,
|
||||
bool &IncompleteImpl, unsigned DiagID);
|
||||
@ -2955,7 +2956,8 @@ class Sema : public Action {
|
||||
TemplateParameterList **ParamLists,
|
||||
unsigned NumParamLists,
|
||||
bool IsFriend,
|
||||
bool &IsExplicitSpecialization);
|
||||
bool &IsExplicitSpecialization,
|
||||
bool &Invalid);
|
||||
|
||||
DeclResult CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
|
||||
SourceLocation KWLoc, CXXScopeSpec &SS,
|
||||
@ -3021,7 +3023,7 @@ class Sema : public Action {
|
||||
Declarator &D);
|
||||
|
||||
virtual DeclPtrTy ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope,
|
||||
MultiTemplateParamsArg TemplateParameterLists,
|
||||
MultiTemplateParamsArg TemplateParameterLists,
|
||||
Declarator &D);
|
||||
|
||||
bool
|
||||
@ -3029,7 +3031,7 @@ class Sema : public Action {
|
||||
TemplateSpecializationKind NewTSK,
|
||||
NamedDecl *PrevDecl,
|
||||
TemplateSpecializationKind PrevTSK,
|
||||
SourceLocation PrevPointOfInstantiation,
|
||||
SourceLocation PrevPtOfInstantiation,
|
||||
bool &SuppressNew);
|
||||
|
||||
bool CheckDependentFunctionTemplateSpecialization(FunctionDecl *FD,
|
||||
@ -3969,7 +3971,7 @@ class Sema : public Action {
|
||||
SourceLocation *IdentLocs,
|
||||
unsigned NumElts);
|
||||
|
||||
virtual DeclPtrTy ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc,
|
||||
virtual DeclPtrTy ActOnForwardProtocolDeclaration(SourceLocation AtProtoclLoc,
|
||||
const IdentifierLocPair *IdentList,
|
||||
unsigned NumElts,
|
||||
AttributeList *attrList);
|
||||
@ -4326,7 +4328,7 @@ class Sema : public Action {
|
||||
bool IgnoreBaseAccess = false);
|
||||
bool PerformImplicitConversion(Expr *&From, QualType ToType,
|
||||
const StandardConversionSequence& SCS,
|
||||
AssignmentAction Action, bool IgnoreBaseAccess);
|
||||
AssignmentAction Action,bool IgnoreBaseAccess);
|
||||
|
||||
/// the following "Check" methods will return a valid/converted QualType
|
||||
/// or a null QualType (indicating an error diagnostic was issued).
|
||||
@ -4347,11 +4349,12 @@ class Sema : public Action {
|
||||
QualType CheckShiftOperands( // C99 6.5.7
|
||||
Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false);
|
||||
QualType CheckCompareOperands( // C99 6.5.8/9
|
||||
Expr *&lex, Expr *&rex, SourceLocation OpLoc, unsigned Opc, bool isRelational);
|
||||
Expr *&lex, Expr *&rex, SourceLocation OpLoc, unsigned Opc,
|
||||
bool isRelational);
|
||||
QualType CheckBitwiseOperands( // C99 6.5.[10...12]
|
||||
Expr *&lex, Expr *&rex, SourceLocation OpLoc, bool isCompAssign = false);
|
||||
QualType CheckLogicalOperands( // C99 6.5.[13,14]
|
||||
Expr *&lex, Expr *&rex, SourceLocation OpLoc);
|
||||
Expr *&lex, Expr *&rex, SourceLocation OpLoc, 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.
|
||||
|
@ -153,7 +153,8 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
|
||||
case tok::kw_const_cast:
|
||||
if (!TypeDependent)
|
||||
CheckConstCast(*this, Ex, DestType, OpRange, DestRange);
|
||||
return Owned(new (Context) CXXConstCastExpr(DestType.getNonReferenceType(),
|
||||
return Owned(new (Context) CXXConstCastExpr(
|
||||
DestType.getNonLValueExprType(Context),
|
||||
Ex, DestTInfo, OpLoc));
|
||||
|
||||
case tok::kw_dynamic_cast: {
|
||||
@ -161,7 +162,8 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
|
||||
CXXBaseSpecifierArray BasePath;
|
||||
if (!TypeDependent)
|
||||
CheckDynamicCast(*this, Ex, DestType, OpRange, DestRange, Kind, BasePath);
|
||||
return Owned(new (Context)CXXDynamicCastExpr(DestType.getNonReferenceType(),
|
||||
return Owned(new (Context)CXXDynamicCastExpr(
|
||||
DestType.getNonLValueExprType(Context),
|
||||
Kind, Ex, BasePath, DestTInfo,
|
||||
OpLoc));
|
||||
}
|
||||
@ -170,7 +172,7 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
|
||||
if (!TypeDependent)
|
||||
CheckReinterpretCast(*this, Ex, DestType, OpRange, DestRange, Kind);
|
||||
return Owned(new (Context) CXXReinterpretCastExpr(
|
||||
DestType.getNonReferenceType(),
|
||||
DestType.getNonLValueExprType(Context),
|
||||
Kind, Ex, CXXBaseSpecifierArray(),
|
||||
DestTInfo, OpLoc));
|
||||
}
|
||||
@ -180,7 +182,8 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
|
||||
if (!TypeDependent)
|
||||
CheckStaticCast(*this, Ex, DestType, OpRange, Kind, BasePath);
|
||||
|
||||
return Owned(new (Context) CXXStaticCastExpr(DestType.getNonReferenceType(),
|
||||
return Owned(new (Context) CXXStaticCastExpr(
|
||||
DestType.getNonLValueExprType(Context),
|
||||
Kind, Ex, BasePath,
|
||||
DestTInfo, OpLoc));
|
||||
}
|
||||
@ -1049,6 +1052,8 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr,
|
||||
const SourceRange &OpRange,
|
||||
unsigned &msg,
|
||||
CastExpr::CastKind &Kind) {
|
||||
bool IsLValueCast = false;
|
||||
|
||||
DestType = Self.Context.getCanonicalType(DestType);
|
||||
QualType SrcType = SrcExpr->getType();
|
||||
if (const ReferenceType *DestTypeTmp = DestType->getAs<ReferenceType>()) {
|
||||
@ -1066,6 +1071,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr,
|
||||
// This code does this transformation for the checked types.
|
||||
DestType = Self.Context.getPointerType(DestTypeTmp->getPointeeType());
|
||||
SrcType = Self.Context.getPointerType(SrcType);
|
||||
IsLValueCast = true;
|
||||
}
|
||||
|
||||
// Canonicalize source for comparison.
|
||||
@ -1092,7 +1098,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr,
|
||||
}
|
||||
|
||||
// A valid member pointer cast.
|
||||
Kind = CastExpr::CK_BitCast;
|
||||
Kind = IsLValueCast? CastExpr::CK_LValueBitCast : CastExpr::CK_BitCast;
|
||||
return TC_Success;
|
||||
}
|
||||
|
||||
@ -1209,7 +1215,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, Expr *SrcExpr,
|
||||
|
||||
// Not casting away constness, so the only remaining check is for compatible
|
||||
// pointer categories.
|
||||
Kind = CastExpr::CK_BitCast;
|
||||
Kind = IsLValueCast? CastExpr::CK_LValueBitCast : CastExpr::CK_BitCast;
|
||||
|
||||
if (SrcType->isFunctionPointerType()) {
|
||||
if (DestType->isFunctionPointerType()) {
|
||||
|
@ -407,13 +407,16 @@ bool ResultBuilder::isInterestingDecl(NamedDecl *ND,
|
||||
return false;
|
||||
|
||||
// Filter out names reserved for the implementation (C99 7.1.3,
|
||||
// C++ [lib.global.names]). Users don't need to see those.
|
||||
// C++ [lib.global.names]) if they come from a system header.
|
||||
//
|
||||
// FIXME: Add predicate for this.
|
||||
if (Id->getLength() >= 2) {
|
||||
const char *Name = Id->getNameStart();
|
||||
if (Name[0] == '_' &&
|
||||
(Name[1] == '_' || (Name[1] >= 'A' && Name[1] <= 'Z')))
|
||||
(Name[1] == '_' || (Name[1] >= 'A' && Name[1] <= 'Z')) &&
|
||||
(ND->getLocation().isInvalid() ||
|
||||
SemaRef.SourceMgr.isInSystemHeader(
|
||||
SemaRef.SourceMgr.getSpellingLoc(ND->getLocation()))))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -2572,6 +2572,7 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
|
||||
// determine whether we have a template or a template specialization.
|
||||
bool isExplicitSpecialization = false;
|
||||
unsigned NumMatchedTemplateParamLists = TemplateParamLists.size();
|
||||
bool Invalid = false;
|
||||
if (TemplateParameterList *TemplateParams
|
||||
= MatchTemplateParametersToScopeSpecifier(
|
||||
D.getDeclSpec().getSourceRange().getBegin(),
|
||||
@ -2579,7 +2580,8 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
|
||||
(TemplateParameterList**)TemplateParamLists.get(),
|
||||
TemplateParamLists.size(),
|
||||
/*never a friend*/ false,
|
||||
isExplicitSpecialization)) {
|
||||
isExplicitSpecialization,
|
||||
Invalid)) {
|
||||
// All but one template parameter lists have been matching.
|
||||
--NumMatchedTemplateParamLists;
|
||||
|
||||
@ -2606,7 +2608,7 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
|
||||
VarDecl *NewVD = VarDecl::Create(Context, DC, D.getIdentifierLoc(),
|
||||
II, R, TInfo, SC, SCAsWritten);
|
||||
|
||||
if (D.isInvalidType())
|
||||
if (D.isInvalidType() || Invalid)
|
||||
NewVD->setInvalidDecl();
|
||||
|
||||
SetNestedNameSpecifier(NewVD, D);
|
||||
@ -3156,6 +3158,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
|
||||
bool isExplicitSpecialization = false;
|
||||
bool isFunctionTemplateSpecialization = false;
|
||||
unsigned NumMatchedTemplateParamLists = TemplateParamLists.size();
|
||||
bool Invalid = false;
|
||||
if (TemplateParameterList *TemplateParams
|
||||
= MatchTemplateParametersToScopeSpecifier(
|
||||
D.getDeclSpec().getSourceRange().getBegin(),
|
||||
@ -3163,7 +3166,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
|
||||
(TemplateParameterList**)TemplateParamLists.get(),
|
||||
TemplateParamLists.size(),
|
||||
isFriend,
|
||||
isExplicitSpecialization)) {
|
||||
isExplicitSpecialization,
|
||||
Invalid)) {
|
||||
// All but one template parameter lists have been matching.
|
||||
--NumMatchedTemplateParamLists;
|
||||
|
||||
@ -3214,6 +3218,12 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
|
||||
(TemplateParameterList**)TemplateParamLists.release());
|
||||
}
|
||||
|
||||
if (Invalid) {
|
||||
NewFD->setInvalidDecl();
|
||||
if (FunctionTemplate)
|
||||
FunctionTemplate->setInvalidDecl();
|
||||
}
|
||||
|
||||
// C++ [dcl.fct.spec]p5:
|
||||
// The virtual specifier shall only be used in declarations of
|
||||
// nonstatic class member functions that appear within a
|
||||
@ -5037,19 +5047,24 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
|
||||
// FIXME: Check explicit specializations more carefully.
|
||||
bool isExplicitSpecialization = false;
|
||||
unsigned NumMatchedTemplateParamLists = TemplateParameterLists.size();
|
||||
bool Invalid = false;
|
||||
if (TUK != TUK_Reference) {
|
||||
if (TemplateParameterList *TemplateParams
|
||||
= MatchTemplateParametersToScopeSpecifier(KWLoc, SS,
|
||||
(TemplateParameterList**)TemplateParameterLists.get(),
|
||||
TemplateParameterLists.size(),
|
||||
TUK == TUK_Friend,
|
||||
isExplicitSpecialization)) {
|
||||
isExplicitSpecialization,
|
||||
Invalid)) {
|
||||
// All but one template parameter lists have been matching.
|
||||
--NumMatchedTemplateParamLists;
|
||||
|
||||
if (TemplateParams->size() > 0) {
|
||||
// This is a declaration or definition of a class template (which may
|
||||
// be a member of another template).
|
||||
if (Invalid)
|
||||
return DeclPtrTy();
|
||||
|
||||
OwnedDecl = false;
|
||||
DeclResult Result = CheckClassTemplate(S, TagSpec, TUK, KWLoc,
|
||||
SS, Name, NameLoc, Attr,
|
||||
@ -5069,7 +5084,6 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
|
||||
DeclContext *SearchDC = CurContext;
|
||||
DeclContext *DC = CurContext;
|
||||
bool isStdBadAlloc = false;
|
||||
bool Invalid = false;
|
||||
|
||||
RedeclarationKind Redecl = ForRedeclaration;
|
||||
if (TUK == TUK_Friend || TUK == TUK_Reference)
|
||||
|
@ -164,7 +164,7 @@ void Sema::DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
|
||||
if (!sentinelExpr) return;
|
||||
if (sentinelExpr->isTypeDependent()) return;
|
||||
if (sentinelExpr->isValueDependent()) return;
|
||||
if (sentinelExpr->getType()->isPointerType() &&
|
||||
if (sentinelExpr->getType()->isAnyPointerType() &&
|
||||
sentinelExpr->IgnoreParenCasts()->isNullPointerConstant(Context,
|
||||
Expr::NPC_ValueDependentIsNull))
|
||||
return;
|
||||
@ -475,6 +475,7 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, SourceLocation Loc,
|
||||
if (isa<NonTypeTemplateParmDecl>(VD)) {
|
||||
// Non-type template parameters can be referenced anywhere they are
|
||||
// visible.
|
||||
Ty = Ty.getNonLValueExprType(Context);
|
||||
} else if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) {
|
||||
if (const FunctionDecl *FD = MD->getParent()->isLocalClass()) {
|
||||
if (VD->hasLocalStorage() && VD->getDeclContext() != CurContext) {
|
||||
@ -4008,7 +4009,8 @@ Sema::BuildCStyleCastExpr(SourceLocation LParenLoc, TypeSourceInfo *Ty,
|
||||
return ExprError();
|
||||
|
||||
Op.release();
|
||||
return Owned(new (Context) CStyleCastExpr(Ty->getType().getNonReferenceType(),
|
||||
return Owned(new (Context) CStyleCastExpr(
|
||||
Ty->getType().getNonLValueExprType(Context),
|
||||
Kind, castExpr, BasePath, Ty,
|
||||
LParenLoc, RParenLoc));
|
||||
}
|
||||
@ -4904,7 +4906,7 @@ Sema::CheckSingleAssignmentConstraints(QualType lhsType, Expr *&rExpr) {
|
||||
// The getNonReferenceType() call makes sure that the resulting expression
|
||||
// does not have reference type.
|
||||
if (result != Incompatible && rExpr->getType() != lhsType)
|
||||
ImpCastExprToType(rExpr, lhsType.getNonReferenceType(),
|
||||
ImpCastExprToType(rExpr, lhsType.getNonLValueExprType(Context),
|
||||
CastExpr::CK_Unknown);
|
||||
return result;
|
||||
}
|
||||
@ -5733,7 +5735,25 @@ inline QualType Sema::CheckBitwiseOperands(
|
||||
}
|
||||
|
||||
inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14]
|
||||
Expr *&lex, Expr *&rex, SourceLocation Loc) {
|
||||
Expr *&lex, Expr *&rex, SourceLocation Loc, unsigned Opc) {
|
||||
|
||||
// Diagnose cases where the user write a logical and/or but probably meant a
|
||||
// bitwise one. We do this when the LHS is a non-bool integer and the RHS
|
||||
// is a constant.
|
||||
if (lex->getType()->isIntegerType() && !lex->getType()->isBooleanType() &&
|
||||
rex->getType()->isIntegerType() && rex->isEvaluatable(Context) &&
|
||||
// Don't warn if the RHS is a (constant folded) boolean expression like
|
||||
// "sizeof(int) == 4".
|
||||
!rex->isKnownToHaveBooleanValue() &&
|
||||
// Don't warn in macros.
|
||||
!Loc.isMacroID())
|
||||
Diag(Loc, diag::warn_logical_instead_of_bitwise)
|
||||
<< rex->getSourceRange()
|
||||
<< (Opc == BinaryOperator::LAnd ? "&&" : "||")
|
||||
<< (Opc == BinaryOperator::LAnd ? "&" : "|");
|
||||
|
||||
|
||||
|
||||
if (!Context.getLangOptions().CPlusPlus) {
|
||||
UsualUnaryConversions(lex);
|
||||
UsualUnaryConversions(rex);
|
||||
@ -6361,7 +6381,7 @@ Action::OwningExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
|
||||
break;
|
||||
case BinaryOperator::LAnd:
|
||||
case BinaryOperator::LOr:
|
||||
ResultTy = CheckLogicalOperands(lhs, rhs, OpLoc);
|
||||
ResultTy = CheckLogicalOperands(lhs, rhs, OpLoc, Opc);
|
||||
break;
|
||||
case BinaryOperator::MulAssign:
|
||||
case BinaryOperator::DivAssign:
|
||||
@ -7348,7 +7368,8 @@ Sema::OwningExprResult Sema::ActOnVAArg(SourceLocation BuiltinLoc,
|
||||
// FIXME: Warn if a non-POD type is passed in.
|
||||
|
||||
expr.release();
|
||||
return Owned(new (Context) VAArgExpr(BuiltinLoc, E, T.getNonReferenceType(),
|
||||
return Owned(new (Context) VAArgExpr(BuiltinLoc, E,
|
||||
T.getNonLValueExprType(Context),
|
||||
RPLoc));
|
||||
}
|
||||
|
||||
|
@ -540,7 +540,8 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep,
|
||||
|
||||
exprs.release();
|
||||
|
||||
return Owned(new (Context) CXXFunctionalCastExpr(Ty.getNonReferenceType(),
|
||||
return Owned(new (Context) CXXFunctionalCastExpr(
|
||||
Ty.getNonLValueExprType(Context),
|
||||
TInfo, TyBeginLoc, Kind,
|
||||
Exprs[0], BasePath,
|
||||
RParenLoc));
|
||||
@ -1879,7 +1880,7 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType,
|
||||
case ICK_Qualification:
|
||||
// FIXME: Not sure about lvalue vs rvalue here in the presence of rvalue
|
||||
// references.
|
||||
ImpCastExprToType(From, ToType.getNonReferenceType(),
|
||||
ImpCastExprToType(From, ToType.getNonLValueExprType(Context),
|
||||
CastExpr::CK_NoOp, ToType->isLValueReferenceType());
|
||||
|
||||
if (SCS.DeprecatedStringLiteralToCharPtr)
|
||||
|
@ -523,8 +523,9 @@ void InitListChecker::CheckExplicitInitList(const InitializedEntity &Entity,
|
||||
StructuredList->setSyntacticForm(IList);
|
||||
CheckListElementTypes(Entity, IList, T, /*SubobjectIsDesignatorContext=*/true,
|
||||
Index, StructuredList, StructuredIndex, TopLevelObject);
|
||||
IList->setType(T.getNonReferenceType());
|
||||
StructuredList->setType(T.getNonReferenceType());
|
||||
QualType ExprTy = T.getNonLValueExprType(SemaRef.Context);
|
||||
IList->setType(ExprTy);
|
||||
StructuredList->setType(ExprTy);
|
||||
if (hadError)
|
||||
return;
|
||||
|
||||
@ -1716,7 +1717,7 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index,
|
||||
InitRange.getBegin(), 0, 0,
|
||||
InitRange.getEnd());
|
||||
|
||||
Result->setType(CurrentObjectType.getNonReferenceType());
|
||||
Result->setType(CurrentObjectType.getNonLValueExprType(SemaRef.Context));
|
||||
|
||||
// Pre-allocate storage for the structured initializer list.
|
||||
unsigned NumElements = 0;
|
||||
@ -2370,13 +2371,14 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
|
||||
|
||||
// Add the user-defined conversion step.
|
||||
Sequence.AddUserConversionStep(Function, Best->FoundDecl,
|
||||
T2.getNonReferenceType());
|
||||
T2.getNonLValueExprType(S.Context));
|
||||
|
||||
// Determine whether we need to perform derived-to-base or
|
||||
// cv-qualification adjustments.
|
||||
bool NewDerivedToBase = false;
|
||||
Sema::ReferenceCompareResult NewRefRelationship
|
||||
= S.CompareReferenceRelationship(DeclLoc, T1, T2.getNonReferenceType(),
|
||||
= S.CompareReferenceRelationship(DeclLoc, T1,
|
||||
T2.getNonLValueExprType(S.Context),
|
||||
NewDerivedToBase);
|
||||
if (NewRefRelationship == Sema::Ref_Incompatible) {
|
||||
// If the type we've converted to is not reference-related to the
|
||||
|
@ -52,18 +52,22 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
|
||||
cast<ObjCContainerDecl>(ClassCategory.getAs<Decl>());
|
||||
|
||||
if (ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl))
|
||||
if (CDecl->IsClassExtension())
|
||||
return HandlePropertyInClassExtension(S, CDecl, AtLoc,
|
||||
FD, GetterSel, SetterSel,
|
||||
isAssign, isReadWrite,
|
||||
Attributes,
|
||||
isOverridingProperty, TSI,
|
||||
MethodImplKind);
|
||||
|
||||
if (CDecl->IsClassExtension()) {
|
||||
DeclPtrTy Res = HandlePropertyInClassExtension(S, CDecl, AtLoc,
|
||||
FD, GetterSel, SetterSel,
|
||||
isAssign, isReadWrite,
|
||||
Attributes,
|
||||
isOverridingProperty, TSI,
|
||||
MethodImplKind);
|
||||
if (Res)
|
||||
CheckObjCPropertyAttributes(Res, AtLoc, Attributes);
|
||||
return Res;
|
||||
}
|
||||
|
||||
DeclPtrTy Res = DeclPtrTy::make(CreatePropertyDecl(S, ClassDecl, AtLoc, FD,
|
||||
GetterSel, SetterSel,
|
||||
isAssign, isReadWrite,
|
||||
Attributes, TSI, MethodImplKind));
|
||||
GetterSel, SetterSel,
|
||||
isAssign, isReadWrite,
|
||||
Attributes, TSI, MethodImplKind));
|
||||
// Validate the attributes on the @property.
|
||||
CheckObjCPropertyAttributes(Res, AtLoc, Attributes);
|
||||
return Res;
|
||||
@ -926,6 +930,10 @@ void Sema::DefaultSynthesizeProperties (Scope *S, ObjCImplDecl* IMPDecl,
|
||||
Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional ||
|
||||
IMPDecl->FindPropertyImplIvarDecl(Prop->getIdentifier()))
|
||||
continue;
|
||||
// Property may have been synthesized by user.
|
||||
if (IMPDecl->FindPropertyImplDecl(Prop->getIdentifier()))
|
||||
continue;
|
||||
|
||||
ActOnPropertyImplDecl(S, IMPDecl->getLocation(), IMPDecl->getLocation(),
|
||||
true, DeclPtrTy::make(IMPDecl),
|
||||
Prop->getIdentifier(), Prop->getIdentifier());
|
||||
|
@ -3727,7 +3727,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
|
||||
// there are 0 arguments (i.e., nothing is allocated using ASTContext's
|
||||
// allocator).
|
||||
CallExpr Call(Context, &ConversionFn, 0, 0,
|
||||
Conversion->getConversionType().getNonReferenceType(),
|
||||
Conversion->getConversionType().getNonLValueExprType(Context),
|
||||
From->getLocStart());
|
||||
ImplicitConversionSequence ICS =
|
||||
TryCopyInitialization(*this, &Call, ToType,
|
||||
@ -6287,7 +6287,8 @@ FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization(Expr *From) {
|
||||
// specified and it, along with any default template arguments,
|
||||
// identifies a single function template specialization, then the
|
||||
// template-id is an lvalue for the function template specialization.
|
||||
FunctionTemplateDecl *FunctionTemplate = cast<FunctionTemplateDecl>(*I);
|
||||
FunctionTemplateDecl *FunctionTemplate
|
||||
= cast<FunctionTemplateDecl>((*I)->getUnderlyingDecl());
|
||||
|
||||
// C++ [over.over]p2:
|
||||
// If the name is a function template, template argument deduction is
|
||||
|
@ -1233,7 +1233,8 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
|
||||
TemplateParameterList **ParamLists,
|
||||
unsigned NumParamLists,
|
||||
bool IsFriend,
|
||||
bool &IsExplicitSpecialization) {
|
||||
bool &IsExplicitSpecialization,
|
||||
bool &Invalid) {
|
||||
IsExplicitSpecialization = false;
|
||||
|
||||
// Find the template-ids that occur within the nested-name-specifier. These
|
||||
@ -1311,6 +1312,7 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
|
||||
diag::err_template_spec_needs_template_parameters)
|
||||
<< TemplateId
|
||||
<< SS.getRange();
|
||||
Invalid = true;
|
||||
} else {
|
||||
Diag(SS.getRange().getBegin(), diag::err_template_spec_needs_header)
|
||||
<< SS.getRange()
|
||||
@ -1373,7 +1375,13 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
|
||||
<< ExplicitSpecializationsInSpecifier.back();
|
||||
ExplicitSpecializationsInSpecifier.pop_back();
|
||||
}
|
||||
|
||||
|
||||
// We have a template parameter list with no corresponding scope, which
|
||||
// means that the resulting template declaration can't be instantiated
|
||||
// properly (we'll end up with dependent nodes when we shouldn't).
|
||||
if (!isExplicitSpecHeader)
|
||||
Invalid = true;
|
||||
|
||||
++Idx;
|
||||
}
|
||||
}
|
||||
@ -3622,12 +3630,17 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
|
||||
// template.
|
||||
// FIXME: We probably shouldn't complain about these headers for
|
||||
// friend declarations.
|
||||
bool Invalid = false;
|
||||
TemplateParameterList *TemplateParams
|
||||
= MatchTemplateParametersToScopeSpecifier(TemplateNameLoc, SS,
|
||||
(TemplateParameterList**)TemplateParameterLists.get(),
|
||||
TemplateParameterLists.size(),
|
||||
TUK == TUK_Friend,
|
||||
isExplicitSpecialization);
|
||||
isExplicitSpecialization,
|
||||
Invalid);
|
||||
if (Invalid)
|
||||
return true;
|
||||
|
||||
unsigned NumMatchedTemplateParamLists = TemplateParameterLists.size();
|
||||
if (TemplateParams)
|
||||
--NumMatchedTemplateParamLists;
|
||||
|
@ -1067,6 +1067,9 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
|
||||
NewParm->setHasInheritedDefaultArg(OldParm->hasInheritedDefaultArg());
|
||||
|
||||
CurrentInstantiationScope->InstantiatedLocal(OldParm, NewParm);
|
||||
// Set DeclContext if inside a Block.
|
||||
NewParm->setDeclContext(CurContext);
|
||||
|
||||
return NewParm;
|
||||
}
|
||||
|
||||
|
@ -4198,10 +4198,6 @@ TreeTransform<Derived>::TransformDeclRefExpr(DeclRefExpr *E) {
|
||||
if (!ND)
|
||||
return SemaRef.ExprError();
|
||||
|
||||
// Set DeclContext if inside a Block.
|
||||
if (BlockScopeInfo *CurBlock = SemaRef.getCurBlock())
|
||||
ND->setDeclContext(CurBlock->TheDecl);
|
||||
|
||||
if (!getDerived().AlwaysRebuild() &&
|
||||
Qualifier == E->getQualifier() &&
|
||||
ND == E->getDecl() &&
|
||||
|
104
runtime/Makefile
Normal file
104
runtime/Makefile
Normal file
@ -0,0 +1,104 @@
|
||||
##===- clang/runtime/Makefile ------------------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
#
|
||||
# This file defines support for building the Clang runtime libraries (which are
|
||||
# implemented by compiler-rt) and placing them in the proper locations in the
|
||||
# Clang resources directory (i.e., where the driver expects them).
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
CLANG_LEVEL := ..
|
||||
include $(CLANG_LEVEL)/Makefile
|
||||
|
||||
CLANG_VERSION := $(word 3,$(shell grep "CLANG_VERSION " \
|
||||
$(PROJ_OBJ_DIR)/$(CLANG_LEVEL)/include/clang/Basic/Version.inc))
|
||||
|
||||
ResourceDir := $(PROJ_OBJ_ROOT)/$(BuildMode)/lib/clang/$(CLANG_VERSION)
|
||||
PROJ_resources := $(DESTDIR)$(PROJ_prefix)/lib/clang/$(CLANG_VERSION)
|
||||
|
||||
ResourceLibDir := $(ResourceDir)/lib
|
||||
PROJ_resources_lib := $(PROJ_resources)/lib
|
||||
|
||||
# Expect compiler-rt to be in llvm/projects/compiler-rt
|
||||
COMPILERRT_SRC_ROOT := $(LLVM_SRC_ROOT)/projects/compiler-rt
|
||||
|
||||
ifndef CLANG_NO_RUNTIME
|
||||
ifeq ($(shell test -d $(COMPILERRT_SRC_ROOT) && echo OK),OK)
|
||||
|
||||
# Select the compiler-rt configuration to use, and install directory.
|
||||
#
|
||||
# FIXME: Eventually, we want some kind of configure support for this. We want to
|
||||
# build/install runtime libraries for as many targets as clang was configured to
|
||||
# support.
|
||||
RuntimeDirs :=
|
||||
ifeq ($(OS),Darwin)
|
||||
RuntimeDirs += darwin
|
||||
RuntimeLibrary.darwin.Configs = 10.4 armv6 cc_kext
|
||||
endif
|
||||
|
||||
# Rule to build the compiler-rt libraries we need.
|
||||
#
|
||||
# We build all the libraries in a single shot to avoid recursive make as much as
|
||||
# possible.
|
||||
BuildRuntimeLibraries:
|
||||
$(Verb) $(MAKE) -C $(COMPILERRT_SRC_ROOT) \
|
||||
ProjSrcRoot=$(COMPILERRT_SRC_ROOT) \
|
||||
ProjObjRoot=$(PROJ_OBJ_DIR) \
|
||||
CC="$(ToolDir)/clang -no-integrated-as" \
|
||||
$(RuntimeDirs:%=clang_%)
|
||||
.PHONY: BuildRuntimeLibraries
|
||||
CleanRuntimeLibraries:
|
||||
$(Verb) $(MAKE) -C $(COMPILERRT_SRC_ROOT) \
|
||||
ProjSrcRoot=$(COMPILERRT_SRC_ROOT) \
|
||||
ProjObjRoot=$(PROJ_OBJ_DIR) \
|
||||
clean
|
||||
.PHONY: CleanRuntimeLibraries
|
||||
|
||||
$(PROJ_resources_lib):
|
||||
$(Verb) $(MKDIR) $@
|
||||
|
||||
# Expand rules for copying/installing each individual library. We can't use
|
||||
# implicit rules here because we need to match against multiple things.
|
||||
define RuntimeLibraryTemplate
|
||||
$(PROJ_OBJ_DIR)/clang_$1/%/libcompiler_rt.a: BuildRuntimeLibraries
|
||||
@true
|
||||
.PRECIOUS: $(PROJ_OBJ_DIR)/clang_$1/%/libcompiler_rt.a
|
||||
|
||||
# Rule to copy the libraries to their resource directory location.
|
||||
$(ResourceLibDir)/$1/libclang_rt.%.a: \
|
||||
$(PROJ_OBJ_DIR)/clang_$1/%/libcompiler_rt.a \
|
||||
$(ResourceLibDir)/$1/.dir
|
||||
$(Echo) Copying runtime library $1/$$* to build dir
|
||||
$(Verb) cp $(PROJ_OBJ_DIR)/clang_$1/$$*/libcompiler_rt.a $$@
|
||||
RuntimeLibrary.$1: \
|
||||
$(RuntimeLibrary.$1.Configs:%=$(ResourceLibDir)/$1/libclang_rt.%.a)
|
||||
.PHONY: RuntimeLibrary.$1
|
||||
|
||||
$(PROJ_resources_lib)/$1: $(PROJ_resources_lib)
|
||||
$(Verb) $(MKDIR) $$@
|
||||
|
||||
$(PROJ_resources_lib)/$1/libclang_rt.%.a: \
|
||||
$(ResourceLibDir)/$1/libclang_rt.%.a | $(PROJ_resources_lib)/$1
|
||||
$(Echo) Installing compiler runtime library: $1/$$*
|
||||
$(Verb) $(DataInstall) $$< $(PROJ_resources_lib)/$1
|
||||
|
||||
# Rule to install runtime libraries.
|
||||
RuntimeLibraryInstall.$1: \
|
||||
$(RuntimeLibrary.$1.Configs:%=$(PROJ_resources_lib)/$1/libclang_rt.%.a)
|
||||
.PHONY: RuntimeLibraryInstall.$1
|
||||
endef
|
||||
$(foreach lib,$(RuntimeDirs), $(eval $(call RuntimeLibraryTemplate,$(lib))))
|
||||
|
||||
# Hook into the standard Makefile rules.
|
||||
all-local:: $(RuntimeDirs:%=RuntimeLibrary.%)
|
||||
install-local:: $(RuntimeDirs:%=RuntimeLibraryInstall.%)
|
||||
clean-local:: CleanRuntimeLibraries
|
||||
|
||||
endif
|
||||
endif
|
@ -43,3 +43,23 @@ namespace PR5949 {
|
||||
return Foo<T>(b, quuz);
|
||||
}
|
||||
}
|
||||
|
||||
// PR7641
|
||||
namespace PR7641 {
|
||||
namespace N2
|
||||
{
|
||||
template<class>
|
||||
int f0(int);
|
||||
}
|
||||
namespace N
|
||||
{
|
||||
using N2::f0;
|
||||
}
|
||||
|
||||
template<class R,class B1>
|
||||
int
|
||||
f1(R(a)(B1));
|
||||
|
||||
void f2()
|
||||
{ f1(N::f0<int>); }
|
||||
}
|
||||
|
2
test/CodeCompletion/Inputs/reserved.h
Normal file
2
test/CodeCompletion/Inputs/reserved.h
Normal file
@ -0,0 +1,2 @@
|
||||
typedef int _INTEGER_TYPE;
|
||||
typedef float FLOATING_TYPE;
|
@ -1,10 +1,14 @@
|
||||
#include <reserved.h>
|
||||
struct X { int x; };
|
||||
|
||||
typedef struct t TYPEDEF;
|
||||
|
||||
typedef struct t _TYPEDEF;
|
||||
void foo() {
|
||||
int y;
|
||||
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:6:9 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s
|
||||
// RUN: %clang_cc1 -isystem %S/Inputs -fsyntax-only -code-completion-at=%s:6:9 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s
|
||||
// CHECK-CC1: _Imaginary
|
||||
// CHECK-CC1-NOT: _INTEGER_TYPE;
|
||||
// CHECK-CC1: _TYPEDEF
|
||||
// CHECK-CC1: FLOATING_TYPE
|
||||
// CHECK-CC1: foo
|
||||
// CHECK-CC1: y
|
||||
// CHECK-CC1: TYPEDEF
|
||||
// CHECK-CC1: y
|
||||
|
@ -26,6 +26,7 @@ struct Y {
|
||||
|
||||
X getX();
|
||||
|
||||
// CHECK: define void @_Z11if_destructi(
|
||||
void if_destruct(int z) {
|
||||
// Verify that the condition variable is destroyed at the end of the
|
||||
// "if" statement.
|
||||
|
@ -136,9 +136,6 @@ namespace test7 {
|
||||
// CHECK-NEXT: invoke void @__cxa_throw(i8* [[EXNALLOC]], i8* bitcast (i8** @_ZTIi to i8*), i8* null
|
||||
throw 1;
|
||||
}
|
||||
// This cleanup ends up here for no good reason. It's actually unused.
|
||||
// CHECK: load i8** [[EXNALLOCVAR]]
|
||||
// CHECK-NEXT: call void @__cxa_free_exception(
|
||||
|
||||
// CHECK: [[CAUGHTEXN:%.*]] = call i8* @llvm.eh.exception()
|
||||
// CHECK-NEXT: store i8* [[CAUGHTEXN]], i8** [[CAUGHTEXNVAR]]
|
||||
@ -184,11 +181,7 @@ namespace test8 {
|
||||
// CHECK-NEXT: invoke void @_ZN5test81AC1ERKS0_(
|
||||
// CHECK: call i8* @__cxa_begin_catch
|
||||
// CHECK-NEXT: invoke void @_ZN5test81AD1Ev(
|
||||
|
||||
// CHECK: call void @__cxa_end_catch()
|
||||
// CHECK-NEXT: load
|
||||
// CHECK-NEXT: switch
|
||||
|
||||
// CHECK: ret void
|
||||
}
|
||||
}
|
||||
@ -220,3 +213,39 @@ namespace test9 {
|
||||
// CHECK: call i8* @llvm.eh.exception
|
||||
// CHECK: call i32 (i8*, i8*, ...)* @llvm.eh.selector(i8* {{.*}}, i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i8* bitcast (i8** @_ZTIi to i8*), i8* null)
|
||||
}
|
||||
|
||||
// __cxa_end_catch can throw for some kinds of caught exceptions.
|
||||
namespace test10 {
|
||||
void opaque();
|
||||
|
||||
struct A { ~A(); };
|
||||
struct B { int x; };
|
||||
|
||||
// CHECK: define void @_ZN6test103fooEv()
|
||||
void foo() {
|
||||
A a; // force a cleanup context
|
||||
|
||||
try {
|
||||
// CHECK: invoke void @_ZN6test106opaqueEv()
|
||||
opaque();
|
||||
} catch (int i) {
|
||||
// CHECK: call i8* @__cxa_begin_catch
|
||||
// CHECK-NEXT: bitcast
|
||||
// CHECK-NEXT: load i32*
|
||||
// CHECK-NEXT: store i32
|
||||
// CHECK-NEXT: call void @__cxa_end_catch() nounwind
|
||||
} catch (B a) {
|
||||
// CHECK: call i8* @__cxa_begin_catch
|
||||
// CHECK-NEXT: bitcast
|
||||
// CHECK-NEXT: bitcast
|
||||
// CHECK-NEXT: bitcast
|
||||
// CHECK-NEXT: call void @llvm.memcpy
|
||||
// CHECK-NEXT: invoke void @__cxa_end_catch()
|
||||
} catch (...) {
|
||||
// CHECK: call i8* @__cxa_begin_catch
|
||||
// CHECK-NEXT: invoke void @__cxa_end_catch()
|
||||
}
|
||||
|
||||
// CHECK: call void @_ZN6test101AD1Ev(
|
||||
}
|
||||
}
|
||||
|
@ -31,3 +31,29 @@ void test2(void)
|
||||
{
|
||||
foo(100, 'a');
|
||||
}
|
||||
|
||||
namespace rdar6182276 {
|
||||
extern "C" {
|
||||
int printf(const char *, ...);
|
||||
}
|
||||
|
||||
template <typename T> T foo(T t)
|
||||
{
|
||||
void (^testing)(int) = ^(int bar) { printf("bar is %d\n", bar); };
|
||||
printf("bar is\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
template <typename T> void gorf(T t)
|
||||
{
|
||||
foo(t);
|
||||
}
|
||||
|
||||
|
||||
void test(void)
|
||||
{
|
||||
gorf(2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
163
test/CodeGenCXX/lvalue-bitcasts.cpp
Normal file
163
test/CodeGenCXX/lvalue-bitcasts.cpp
Normal file
@ -0,0 +1,163 @@
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin10.0.0 -emit-llvm -o - %s | FileCheck %s
|
||||
|
||||
struct X { int i; float f; };
|
||||
struct Y { X x; };
|
||||
|
||||
// CHECK: define void @_Z21reinterpret_cast_testRiRfR1X
|
||||
void reinterpret_cast_test(int &ir, float &fr, X &xr) {
|
||||
// CHECK: load float**
|
||||
// CHECK: bitcast float*
|
||||
// CHECK: load i32*
|
||||
ir = reinterpret_cast<int&>(fr);
|
||||
// CHECK: load
|
||||
// CHECK: {{bitcast.*to i32\*}}
|
||||
// CHECK: load i32*
|
||||
ir = reinterpret_cast<int&>(xr);
|
||||
// CHECK: load i32
|
||||
// CHECK: {{bitcast.*to float\*}}
|
||||
// CHECK: load float*
|
||||
fr = reinterpret_cast<float&>(ir);
|
||||
// CHECK: load
|
||||
// CHECK: {{bitcast.*to float\*}}
|
||||
// CHECK: load float*
|
||||
fr = reinterpret_cast<float&>(xr);
|
||||
// CHECK: load i32**
|
||||
// CHECK: bitcast i32*
|
||||
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64
|
||||
xr = reinterpret_cast<X&>(ir);
|
||||
// CHECK: load float**
|
||||
// CHECK: bitcast float*
|
||||
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64
|
||||
xr = reinterpret_cast<X&>(fr);
|
||||
_Complex float cf;
|
||||
_Complex float &cfr = cf;
|
||||
// CHECK: load i32**
|
||||
// CHECK: bitcast i32*
|
||||
// CHECK: load float*
|
||||
// CHECK: load float*
|
||||
cfr = reinterpret_cast<_Complex float&>(ir);
|
||||
// CHECK: load float**
|
||||
// CHECK: bitcast float*
|
||||
// CHECK: load float*
|
||||
// CHECK: load float*
|
||||
cfr = reinterpret_cast<_Complex float&>(fr);
|
||||
// CHECK: bitcast
|
||||
// CHECK: load float*
|
||||
// CHECK: load float*
|
||||
cfr = reinterpret_cast<_Complex float&>(xr);
|
||||
// CHECK: ret void
|
||||
}
|
||||
|
||||
// CHECK: define void @_Z6c_castRiRfR1X
|
||||
void c_cast(int &ir, float &fr, X &xr) {
|
||||
// CHECK: load float**
|
||||
// CHECK: bitcast float*
|
||||
// CHECK: load i32*
|
||||
ir = (int&)fr;
|
||||
// CHECK: load
|
||||
// CHECK: {{bitcast.*to i32\*}}
|
||||
// CHECK: load i32*
|
||||
ir = (int&)xr;
|
||||
// CHECK: load i32
|
||||
// CHECK: {{bitcast.*to float\*}}
|
||||
// CHECK: load float*
|
||||
fr = (float&)ir;
|
||||
// CHECK: load
|
||||
// CHECK: {{bitcast.*to float\*}}
|
||||
// CHECK: load float*
|
||||
fr = (float&)xr;
|
||||
// CHECK: load i32**
|
||||
// CHECK: bitcast i32*
|
||||
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64
|
||||
xr = (X&)ir;
|
||||
// CHECK: load float**
|
||||
// CHECK: bitcast float*
|
||||
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64
|
||||
xr = (X&)fr;
|
||||
_Complex float cf;
|
||||
_Complex float &cfr = cf;
|
||||
// CHECK: load i32**
|
||||
// CHECK: bitcast i32*
|
||||
// CHECK: load float*
|
||||
// CHECK: load float*
|
||||
cfr = (_Complex float&)ir;
|
||||
// CHECK: load float**
|
||||
// CHECK: bitcast float*
|
||||
// CHECK: load float*
|
||||
// CHECK: load float*
|
||||
cfr = (_Complex float&)fr;
|
||||
// CHECK: bitcast
|
||||
// CHECK: load float*
|
||||
// CHECK: load float*
|
||||
cfr = (_Complex float&)xr;
|
||||
// CHECK: ret void
|
||||
}
|
||||
|
||||
// CHECK: define void @_Z15functional_castRiRfR1X
|
||||
void functional_cast(int &ir, float &fr, X &xr) {
|
||||
typedef int &intref;
|
||||
typedef float &floatref;
|
||||
typedef X &Xref;
|
||||
// CHECK: load float**
|
||||
// CHECK: bitcast float*
|
||||
// CHECK: load i32*
|
||||
ir = intref(fr);
|
||||
// CHECK: load
|
||||
// CHECK: {{bitcast.*to i32\*}}
|
||||
// CHECK: load i32*
|
||||
ir = intref(xr);
|
||||
// CHECK: load i32
|
||||
// CHECK: {{bitcast.*to float\*}}
|
||||
// CHECK: load float*
|
||||
fr = floatref(ir);
|
||||
// CHECK: load
|
||||
// CHECK: {{bitcast.*to float\*}}
|
||||
// CHECK: load float*
|
||||
fr = floatref(xr);
|
||||
// CHECK: load i32**
|
||||
// CHECK: bitcast i32*
|
||||
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64
|
||||
xr = Xref(ir);
|
||||
// CHECK: load float**
|
||||
// CHECK: bitcast float*
|
||||
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64
|
||||
xr = Xref(fr);
|
||||
typedef _Complex float &complex_float_ref;
|
||||
_Complex float cf;
|
||||
_Complex float &cfr = cf;
|
||||
// CHECK: load i32**
|
||||
// CHECK: bitcast i32*
|
||||
// CHECK: load float*
|
||||
// CHECK: load float*
|
||||
cfr = complex_float_ref(ir);
|
||||
// CHECK: load float**
|
||||
// CHECK: bitcast float*
|
||||
// CHECK: load float*
|
||||
// CHECK: load float*
|
||||
cfr = complex_float_ref(fr);
|
||||
// CHECK: bitcast
|
||||
// CHECK: load float*
|
||||
// CHECK: load float*
|
||||
cfr = complex_float_ref(xr);
|
||||
// CHECK: ret void
|
||||
}
|
||||
|
||||
namespace PR6437 {
|
||||
struct in_addr {};
|
||||
void copy( const struct in_addr &new_addr ) {
|
||||
int addr = (int&)new_addr;
|
||||
}
|
||||
}
|
||||
|
||||
namespace PR7593 {
|
||||
void foo(double &X, char *A) {
|
||||
X = reinterpret_cast<double&>(A[4]);
|
||||
}
|
||||
}
|
||||
|
||||
namespace PR7344 {
|
||||
void serialize_annotatable_id( void*& id )
|
||||
{
|
||||
unsigned long l_id = (unsigned long&)id;
|
||||
}
|
||||
}
|
@ -495,4 +495,15 @@ namespace test12 {
|
||||
// CHECK: _ZN6test121fENS_1AILt33000EEE
|
||||
template <unsigned short> struct A { };
|
||||
void f(A<33000>) { }
|
||||
}
|
||||
}
|
||||
|
||||
// PR7446
|
||||
namespace test13 {
|
||||
template <template <class> class T> class A {};
|
||||
template <class U> class B {};
|
||||
|
||||
template <template<class> class T> void foo(const A<T> &a) {}
|
||||
|
||||
// CHECK: define weak_odr void @_ZN6test133fooINS_1BEEEvRKNS_1AIT_EE(
|
||||
template void foo(const A<B> &a);
|
||||
}
|
||||
|
20
test/CodeGenCXX/member-qual-debug-info.cpp
Normal file
20
test/CodeGenCXX/member-qual-debug-info.cpp
Normal file
@ -0,0 +1,20 @@
|
||||
// RUN: %clang_cc1 -g -S -masm-verbose -x c++ -o %t %s
|
||||
// RUN: grep DW_TAG_volatile_type %t | count 3
|
||||
// RUN: grep DW_TAG_const_type %t | count 3
|
||||
// one for decl, one for def, one for abbrev
|
||||
|
||||
namespace A {
|
||||
class B {
|
||||
public:
|
||||
void dump() const volatile;
|
||||
};
|
||||
}
|
||||
|
||||
int main () {
|
||||
using namespace A;
|
||||
B b;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void A::B::dump() const volatile{
|
||||
}
|
@ -57,20 +57,15 @@ X test2(bool B) {
|
||||
|
||||
// CHECK-EH: call void @_ZN1XC1Ev
|
||||
// CHECK-EH-NEXT: invoke void @_ZN1XC1Ev
|
||||
// -> %invoke.cont1, %lpad
|
||||
// -> %invoke.cont, %lpad
|
||||
|
||||
// %invoke.cont1:
|
||||
// %invoke.cont:
|
||||
// CHECK-EH: br i1
|
||||
// -> %if.then, %if.end
|
||||
|
||||
// %if.then: returning 'x'
|
||||
// CHECK-EH: invoke void @_ZN1XC1ERKS_
|
||||
// -> %cleanup, %lpad5
|
||||
|
||||
// %invoke.cont: rethrow block for %eh.cleanup.
|
||||
// This really should be elsewhere in the function.
|
||||
// CHECK-EH: call void @_Unwind_Resume_or_Rethrow
|
||||
// CHECK-EH-NEXT: unreachable
|
||||
// -> %cleanup, %lpad1
|
||||
|
||||
// %lpad: landing pad for ctor of 'y', dtor of 'y'
|
||||
// CHECK-EH: call i8* @llvm.eh.exception()
|
||||
@ -78,25 +73,30 @@ X test2(bool B) {
|
||||
// CHECK-EH-NEXT: br label
|
||||
// -> %eh.cleanup
|
||||
|
||||
// %invoke.cont2: normal cleanup for 'x'
|
||||
// CHECK-EH: call void @_ZN1XD1Ev
|
||||
// CHECK-EH-NEXT: ret void
|
||||
|
||||
// %lpad5: landing pad for return copy ctors, EH cleanup for 'y'
|
||||
// %lpad1: landing pad for return copy ctors, EH cleanup for 'y'
|
||||
// CHECK-EH: invoke void @_ZN1XD1Ev
|
||||
// -> %eh.cleanup, %terminate.lpad
|
||||
|
||||
// %if.end: returning 'y'
|
||||
// CHECK-EH: invoke void @_ZN1XC1ERKS_
|
||||
// -> %cleanup, %lpad5
|
||||
// -> %cleanup, %lpad1
|
||||
|
||||
// %cleanup: normal cleanup for 'y'
|
||||
// CHECK-EH: invoke void @_ZN1XD1Ev
|
||||
// -> %invoke.cont2, %lpad
|
||||
// -> %invoke.cont11, %lpad
|
||||
|
||||
// %invoke.cont11: normal cleanup for 'x'
|
||||
// CHECK-EH: call void @_ZN1XD1Ev
|
||||
// CHECK-EH-NEXT: ret void
|
||||
|
||||
// %eh.cleanup: EH cleanup for 'x'
|
||||
// CHECK-EH: invoke void @_ZN1XD1Ev
|
||||
// -> %invoke.cont, %terminate.lpad
|
||||
// -> %invoke.cont17, %terminate.lpad
|
||||
|
||||
// %invoke.cont17: rethrow block for %eh.cleanup.
|
||||
// This really should be elsewhere in the function.
|
||||
// CHECK-EH: call void @_Unwind_Resume_or_Rethrow
|
||||
// CHECK-EH-NEXT: unreachable
|
||||
|
||||
// %terminate.lpad: terminate landing pad.
|
||||
// CHECK-EH: call i8* @llvm.eh.exception()
|
||||
|
@ -3,4 +3,4 @@
|
||||
// Make sure we don't crash generating y; its value is constant, but the
|
||||
// initializer has side effects, so EmitConstantExpr should fail.
|
||||
int x();
|
||||
int y = x() && 0;
|
||||
int y = x() && 0; // expected-warning {{use of logical && with constant operand}}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -emit-llvm -o %t %s
|
||||
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-nonfragile-abi -emit-llvm -fexceptions -o %t %s
|
||||
// RUN: FileCheck -check-prefix=CHECK-X86_64 < %t %s
|
||||
// RUN: grep '@"OBJC_EHTYPE_$_EH3"' %t | count 3
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
// RUN: %clang_cc1 -fobjc-nonfragile-abi -emit-llvm -o - %s | FileCheck --check-prefix=DEFAULT_EH %s
|
||||
// RUN: %clang_cc1 -fsjlj-exceptions -fobjc-nonfragile-abi -emit-llvm -o - %s | FileCheck --check-prefix=SJLJ_EH %s
|
||||
// RUN: %clang_cc1 -fobjc-nonfragile-abi -emit-llvm -fexceptions -o - %s | FileCheck --check-prefix=DEFAULT_EH %s
|
||||
// RUN: %clang_cc1 -fsjlj-exceptions -fobjc-nonfragile-abi -fexceptions -emit-llvm -o - %s | FileCheck --check-prefix=SJLJ_EH %s
|
||||
|
||||
// DEFAULT_EH: declare void @_Unwind_Resume_or_Rethrow(i8*)
|
||||
// SJLJ_EH: declare void @_Unwind_SjLj_Resume(i8*)
|
||||
|
@ -1,4 +1,4 @@
|
||||
// RUN: %clang -ccc-host-triple i386-apple-darwin9 -arch armv7 -flto -S -o - %s | FileCheck %s
|
||||
// RUN: %clang -ccc-host-triple i386-apple-darwin9 -miphoneos-version-min=3.0 -arch armv7 -flto -S -o - %s | FileCheck %s
|
||||
|
||||
// CHECK: @f0
|
||||
// CHECK-NOT: ssp
|
||||
|
@ -70,3 +70,15 @@
|
||||
// LINK_IPHONE_3_1: ld"
|
||||
// LINK_IPHONE_3_1-NOT: -lbundle1.o
|
||||
// LINK_IPHONE_3_1: -lSystem
|
||||
|
||||
// RUN: %clang -ccc-host-triple i386-apple-darwin9 -### -fpie %t.o 2> %t.log
|
||||
// RUN: FileCheck -check-prefix=LINK_EXPLICIT_PIE %s < %t.log
|
||||
//
|
||||
// LINK_EXPLICIT_PIE: ld"
|
||||
// LINK_EXPLICIT_PIE: "-pie"
|
||||
|
||||
// RUN: %clang -ccc-host-triple i386-apple-darwin9 -### -fno-pie %t.o 2> %t.log
|
||||
// RUN: FileCheck -check-prefix=LINK_EXPLICIT_NO_PIE %s < %t.log
|
||||
//
|
||||
// LINK_EXPLICIT_NO_PIE: ld"
|
||||
// LINK_EXPLICIT_NO_PIE: "-no_pie"
|
||||
|
@ -1,4 +1,7 @@
|
||||
// RUN: %clang -ccc-host-triple armv6-apple-darwin9 -dM -E -o %t %s
|
||||
// RUN: grep '__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__' %t | count 0
|
||||
// RUN: grep '__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__' %t | grep '1050' | count 1
|
||||
// RUN: %clang -ccc-host-triple armv6-apple-darwin9 -miphoneos-version-min=3.0 -dM -E -o %t %s
|
||||
// RUN: grep '__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__' %t | grep '30000' | count 1
|
||||
// RUN: grep '__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__' %t | count 0
|
||||
// RUN: %clang -ccc-host-triple armv6-apple-darwin9 -miphoneos-version-min=2.0 -dM -E -o %t %s
|
||||
|
@ -66,6 +66,10 @@ int main (int argc, const char * argv[]) {
|
||||
- (IBAction) actionMethod:(id)arg;
|
||||
@end
|
||||
|
||||
typedef struct X0 X1;
|
||||
struct X0;
|
||||
struct X0 {};
|
||||
|
||||
// CHECK: c-index-api-loadTU-test.m:4:12: ObjCInterfaceDecl=Foo:4:12 Extent=[4:1 - 12:5]
|
||||
// CHECK: c-index-api-loadTU-test.m:6:32: ObjCIvarDecl=myoutlet:6:32 (Definition) Extent=[6:32 - 6:40]
|
||||
// CHECK: <invalid loc>:0:0: attribute(iboutlet)=
|
||||
|
@ -50,4 +50,8 @@ lit.site.cfg: FORCE
|
||||
clean::
|
||||
@ find . -name Output | xargs rm -fr
|
||||
|
||||
# Daniel hates Chris.
|
||||
chris-lit:
|
||||
make LIT_ARGS='-j16 -s'
|
||||
|
||||
.PHONY: all report clean
|
||||
|
6
test/PCH/pchpch.c
Normal file
6
test/PCH/pchpch.c
Normal file
@ -0,0 +1,6 @@
|
||||
// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-pch -o %t1 %S/pchpch1.h
|
||||
// RUN: %clang_cc1 -triple i386-unknown-unknown -emit-pch -o %t2 %S/pchpch2.h -include-pch %t1
|
||||
// RUN: %clang_cc1 -triple i386-unknown-unknown -fsyntax-only %s -include-pch %t2
|
||||
|
||||
// The purpose of this test is to make sure that a PCH created while including
|
||||
// an existing PCH can be loaded.
|
0
test/PCH/pchpch1.h
Normal file
0
test/PCH/pchpch1.h
Normal file
0
test/PCH/pchpch2.h
Normal file
0
test/PCH/pchpch2.h
Normal file
@ -13,10 +13,9 @@ int main() {
|
||||
int (^IFP) () = PFR; // OK
|
||||
|
||||
|
||||
const int (^CIC) () = IFP; // expected-error {{incompatible block pointer types initializing 'int const (^)()' with an expression of type 'int (^)()'}} \
|
||||
// expected-warning{{type qualifier on return type has no effect}}
|
||||
const int (^CIC) () = IFP; // expected-error {{incompatible block pointer types initializing 'int const (^)()' with an expression of type 'int (^)()'}}
|
||||
|
||||
const int (^CICC) () = CIC; // expected-warning{{type qualifier on return type has no effect}}
|
||||
const int (^CICC) () = CIC;
|
||||
|
||||
|
||||
int * const (^IPCC) () = 0;
|
||||
|
@ -109,10 +109,9 @@ void foo6() {
|
||||
|
||||
void foo7()
|
||||
{
|
||||
const int (^BB) (void) = ^{ const int i = 1; return i; }; // expected-error{{incompatible block pointer types initializing 'int const (^)(void)' with an expression of type 'int (^)(void)'}} \
|
||||
// expected-warning{{type qualifier on return type has no effect}}
|
||||
const int (^BB) (void) = ^{ const int i = 1; return i; }; // expected-error{{incompatible block pointer types initializing 'int const (^)(void)' with an expression of type 'int (^)(void)'}}
|
||||
|
||||
const int (^CC) (void) = ^const int{ const int i = 1; return i; }; // expected-warning{{type qualifier on return type has no effect}}
|
||||
const int (^CC) (void) = ^const int{ const int i = 1; return i; };
|
||||
|
||||
|
||||
int i;
|
||||
|
@ -142,3 +142,8 @@ void test19() {
|
||||
*(volatile int*)0 = 0; // Ok.
|
||||
}
|
||||
|
||||
int test20(int x) {
|
||||
return x && 4; // expected-warning {{use of logical && with constant operand; switch to bitwise & or remove constant}}
|
||||
|
||||
return x && sizeof(int) == 4; // no warning.
|
||||
}
|
||||
|
@ -51,7 +51,8 @@ char z[__builtin_constant_p(4) ? 1 : -1];
|
||||
|
||||
// Comma tests
|
||||
int comma1[0?1,2:3]; // expected-warning {{expression result unused}}
|
||||
int comma2[1||(1,2)]; // expected-warning {{expression result unused}}
|
||||
int comma2[1||(1,2)]; // expected-warning {{expression result unused}} \
|
||||
// expected-warning {{use of logical || with constant operand}}
|
||||
int comma3[(1,2)]; // expected-warning {{size of static array must be an integer constant expression}} \
|
||||
// expected-warning {{expression result unused}}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
// RUN: %clang %s -fsyntax-only -Wreturn-type -Xclang -verify -fblocks -Wno-unreachable-code -Wno-unused-value
|
||||
// RUN: %clang %s -fsyntax-only -Wignored-qualifiers -Wreturn-type -Xclang -verify -fblocks -Wno-unreachable-code -Wno-unused-value
|
||||
|
||||
// clang emits the following warning by default.
|
||||
// With GCC, -pedantic, -Wreturn-type or -Wall are required to produce the
|
||||
@ -239,3 +239,6 @@ int test_static_inline(int x) {
|
||||
}
|
||||
static inline int si_forward() {} // expected-warning{{control reaches end of non-void function}}
|
||||
|
||||
// Test warnings on ignored qualifiers on return types.
|
||||
const int ignored_c_quals(); // expected-warning{{'const' type qualifier on return type has no effect}}
|
||||
const volatile int ignored_cv_quals(); // expected-warning{{'const volatile' type qualifiers on return type have no effect}}
|
||||
|
@ -5,7 +5,7 @@ struct S {
|
||||
int two;
|
||||
};
|
||||
|
||||
struct S const foo(void); // expected-warning{{type qualifier on return type has no effect}}
|
||||
struct S const foo(void);
|
||||
|
||||
|
||||
struct S tmp;
|
||||
|
@ -50,12 +50,14 @@ void test4()
|
||||
}
|
||||
|
||||
switch (cond) {
|
||||
case g() && 0: // expected-error {{expression is not an integer constant expression}} // expected-note {{subexpression not valid in an integer constant expression}}
|
||||
case g() && 0: // expected-error {{expression is not an integer constant expression}} // expected-note {{subexpression not valid in an integer constant expression}} \
|
||||
expected-warning {{use of logical && with constant operand}}
|
||||
break;
|
||||
}
|
||||
|
||||
switch (cond) {
|
||||
case 0 ... g() || 1: // expected-error {{expression is not an integer constant expression}} // expected-note {{subexpression not valid in an integer constant expression}}
|
||||
case 0 ... g() || 1: // expected-error {{expression is not an integer constant expression}} // expected-note {{subexpression not valid in an integer constant expression}} \\
|
||||
expected-warning {{use of logical || with constant operand}}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ namespace test0 {
|
||||
void func(const char ci, const B b); // expected-note {{candidate function}}
|
||||
void func(const B b, const int ci); // expected-note {{candidate function}}
|
||||
|
||||
const int Test1() { // expected-warning{{type qualifier on return type has no effect}}
|
||||
const int Test1() {
|
||||
|
||||
func(b1, f()); // expected-error {{call to 'func' is ambiguous}}
|
||||
return f(); // expected-error {{conversion from 'test0::B' to 'int const' is ambiguous}}
|
||||
|
@ -25,6 +25,6 @@ void static_assert_arg_is_bool(T x) {
|
||||
|
||||
void test2() {
|
||||
int n = 2;
|
||||
static_assert_arg_is_bool(n && 4);
|
||||
static_assert_arg_is_bool(n || 5);
|
||||
static_assert_arg_is_bool(n && 4); // expected-warning {{use of logical && with constant operand}}
|
||||
static_assert_arg_is_bool(n || 5); // expected-warning {{use of logical || with constant operand}}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user