Update clang to r93512.
This commit is contained in:
parent
abe15e553e
commit
ee791dde72
@ -4,7 +4,7 @@ LLVM Release License
|
||||
University of Illinois/NCSA
|
||||
Open Source License
|
||||
|
||||
Copyright (c) 2007-2009 University of Illinois at Urbana-Champaign.
|
||||
Copyright (c) 2007-2010 University of Illinois at Urbana-Champaign.
|
||||
All rights reserved.
|
||||
|
||||
Developed by:
|
||||
|
@ -289,7 +289,7 @@ Clang:</p>
|
||||
<tr><td>Example:</td><td><tt>"must be a %select{unary|binary|unary or binary}2
|
||||
operator"</tt></td></tr>
|
||||
<tr><td>Class:</td><td>Integers</td></tr>
|
||||
<tr><td>Description:</td><td>This format specifier is used to merge multiple
|
||||
<tr><td>Description:</td><td><p>This format specifier is used to merge multiple
|
||||
related diagnostics together into one common one, without requiring the
|
||||
difference to be specified as an English string argument. Instead of
|
||||
specifying the string, the diagnostic gets an integer argument and the
|
||||
@ -298,7 +298,8 @@ Clang:</p>
|
||||
it is 1 it prints 'binary' if it is 2, it prints 'unary or binary'. This
|
||||
allows other language translations to substitute reasonable words (or entire
|
||||
phrases) based on the semantics of the diagnostic instead of having to do
|
||||
things textually.</td></tr>
|
||||
things textually.</p>
|
||||
<p>The selected string does undergo formatting.</p></td></tr>
|
||||
|
||||
<tr><td colspan="2"><b>"plural" format</b></td></tr>
|
||||
<tr><td>Example:</td><td><tt>"you have %1 %plural{1:mouse|:mice}1 connected to
|
||||
@ -330,6 +331,15 @@ Clang:</p>
|
||||
abort, as will a failure to match the argument against any
|
||||
expression.</p></td></tr>
|
||||
|
||||
<tr><td colspan="2"><b>"ordinal" format</b></td></tr>
|
||||
<tr><td>Example:</td><td><tt>"ambiguity in %ordinal0 argument"</tt></td></tr>
|
||||
<tr><td>Class:</td><td>Integers</td></tr>
|
||||
<tr><td>Description:</td><td><p>This is a formatter which represents the
|
||||
argument number as an ordinal: the value <tt>1</tt> becomes <tt>1st</tt>,
|
||||
<tt>3</tt> becomes <tt>3rd</tt>, and so on. Values less than <tt>1</tt>
|
||||
are not supported.</p>
|
||||
<p>This formatter is currently hard-coded to use English ordinals.</p></td></tr>
|
||||
|
||||
<tr><td colspan="2"><b>"objcclass" format</b></td></tr>
|
||||
<tr><td>Example:</td><td><tt>"method %objcclass0 not found"</tt></td></tr>
|
||||
<tr><td>Class:</td><td>DeclarationName</td></tr>
|
||||
|
@ -28,6 +28,19 @@ td {
|
||||
<li><a href="#cxx_exceptions">C++ exceptions</a></li>
|
||||
<li><a href="#cxx_rtti">C++ RTTI</a></li>
|
||||
</ul>
|
||||
<li><a href="#checking_upcoming_features">Checks for Upcoming Standard Language Features</a></li>
|
||||
<ul>
|
||||
<li><a href="#cxx_attributes">C++0x attributes</a></li>
|
||||
<li><a href="#cxx_decltype">C++0x <tt>decltype()</tt></a></li>
|
||||
<li><a href="#cxx_deleted_functions">C++0x deleted functions</a></li>
|
||||
<li><a href="#cxx_concepts">C++ TR concepts</a></li>
|
||||
<li><a href="#cxx_lambdas">C++0x lambdas</a></li>
|
||||
<li><a href="#cxx_nullptr">C++0x nullptr</a></li>
|
||||
<li><a href="#cxx_rvalue_references">C++0x rvalue references</a></li>
|
||||
<li><a href="#cxx_static_assert">C++0x <tt>static_assert()</tt></a></li>
|
||||
<li><a href="#cxx_auto_type">C++0x type inference</a></li>
|
||||
<li><a href="#cxx_variadic_templates">C++0x variadic templates</a></li>
|
||||
</ul>
|
||||
<li><a href="#blocks">Blocks</a></li>
|
||||
<li><a href="#overloading-in-c">Function Overloading in C</a></li>
|
||||
<li><a href="#builtins">Builtin Functions</a>
|
||||
@ -215,6 +228,70 @@ example, compiling code with <tt>-fexceptions</tt> enables C++ exceptions.</p>
|
||||
<p>Use <tt>__has_feature(cxx_rtti)</tt> to determine if C++ RTTI has been enabled. For example,
|
||||
compiling code with <tt>-fno-rtti</tt> disables the use of RTTI.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="checking_upcoming_features">Checks for Upcoming Standard Language Features</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
||||
<p>The <tt>__has_feature</tt> macro can be used to query if certain upcoming
|
||||
standard language features are enabled. Those features are listed here.</p>
|
||||
|
||||
<p>Currently, all features listed here are slated for inclusion in the upcoming
|
||||
C++0x standard. As a result, all the features that clang supports are enabled
|
||||
with the <tt>-std=c++0x</tt> option when compiling C++ code. Features that are
|
||||
not yet implemented will be noted.</p>
|
||||
|
||||
<h3 id="cxx_decltype">C++0x <tt>decltype()</tt></h3>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_decltype)</tt> to determine if support for the
|
||||
<tt>decltype()</tt> specifier is enabled.</p>
|
||||
|
||||
<h3 id="cxx_attributes">C++0x attributes</h3>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_attributes)</tt> to determine if support for
|
||||
attribute parsing with C++0x's square bracket notation is enabled.
|
||||
|
||||
<h3 id="cxx_deleted_functions">C++0x deleted functions</tt></h3>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_deleted_functions)</tt> to determine if support for
|
||||
deleted function definitions (with <tt>= delete</tt>) is enabled.
|
||||
|
||||
<h3 id="cxx_concepts">C++ TR <tt>concepts</tt></h3>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_lambdas)</tt> to determine if support for
|
||||
concepts is enabled. clang does not currently implement this feature.
|
||||
|
||||
<h3 id="cxx_lambdas">C++0x lambdas</h3>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_lambdas)</tt> to determine if support for
|
||||
lambdas is enabled. clang does not currently implement this feature.
|
||||
|
||||
<h3 id="cxx_nullptr">C++0x <tt>nullptr</tt></h3>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_nullptr)</tt> to determine if support for
|
||||
<tt>nullptr</tt> is enabled. clang does not yet fully implement this feature.
|
||||
|
||||
<h3 id="cxx_rvalue_references">C++0x rvalue references</tt></h3>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_rvalue_references)</tt> to determine if support for
|
||||
rvalue references is enabled. clang does not yet fully implement this feature.
|
||||
|
||||
<h3 id="cxx_static_assert">C++0x <tt>static_assert()</tt></h3>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_static_assert)</tt> to determine if support for
|
||||
compile-time assertions using <tt>static_assert</tt> is enabled.</p>
|
||||
|
||||
<h3 id="cxx_auto_type">C++0x type inference</h3>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_auto_type)</tt> to determine C++0x type inference
|
||||
is supported using the <tt>auto</tt> specifier. If this is disabled,
|
||||
<tt>auto</tt> will instead be a storage class specifier, as in C or C++98.</p>
|
||||
|
||||
<h3 id="cxx_variadic_templates">C++0x variadic templates</tt></h3>
|
||||
|
||||
<p>Use <tt>__has_feature(cxx_variadic_templates)</tt> to determine if support
|
||||
for templates taking any number of arguments with the ellipsis notation is
|
||||
enabled. clang does not yet fully implement this feature.</p>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<h2 id="blocks">Blocks</h2>
|
||||
<!-- ======================================================================= -->
|
||||
|
@ -6,5 +6,5 @@ TOOL_NO_EXPORT in the tools/clang Makefile).
|
||||
|
||||
Once the plugin is built, you can run it using:
|
||||
--
|
||||
$ clang -cc1 -load path/to/PrintFunctionNames.so -plugin=print-fns some-input-file.c
|
||||
$ clang -cc1 -load path/to/PrintFunctionNames.so -plugin print-fns some-input-file.c
|
||||
--
|
||||
|
@ -139,10 +139,14 @@ typedef struct {
|
||||
enum CXCursorKind kind;
|
||||
CXDecl decl;
|
||||
CXStmt stmt; /* expression reference */
|
||||
CXDecl referringDecl;
|
||||
} CXCursor;
|
||||
|
||||
/* A unique token for looking up "visible" CXDecls from a CXTranslationUnit. */
|
||||
typedef void *CXEntity;
|
||||
typedef struct {
|
||||
CXIndex index;
|
||||
void *data;
|
||||
} CXEntity;
|
||||
|
||||
/**
|
||||
* For functions returning a string that might or might not need
|
||||
@ -321,20 +325,40 @@ CINDEX_LINKAGE time_t clang_getFileTime(CXFile SFile);
|
||||
/*
|
||||
* CXEntity Operations.
|
||||
*/
|
||||
CINDEX_LINKAGE const char *clang_getDeclarationName(CXEntity);
|
||||
CINDEX_LINKAGE const char *clang_getURI(CXEntity);
|
||||
CINDEX_LINKAGE CXEntity clang_getEntity(const char *URI);
|
||||
|
||||
/* clang_getDeclaration() maps from a CXEntity to the matching CXDecl (if any)
|
||||
* in a specified translation unit. */
|
||||
CINDEX_LINKAGE CXDecl clang_getDeclaration(CXEntity, CXTranslationUnit);
|
||||
|
||||
/*
|
||||
* CXDecl Operations.
|
||||
*/
|
||||
CINDEX_LINKAGE CXCursor clang_getCursorFromDecl(CXDecl);
|
||||
CINDEX_LINKAGE CXEntity clang_getEntityFromDecl(CXDecl);
|
||||
CINDEX_LINKAGE CXEntity clang_getEntityFromDecl(CXIndex, CXDecl);
|
||||
CINDEX_LINKAGE CXString clang_getDeclSpelling(CXDecl);
|
||||
CINDEX_LINKAGE unsigned clang_getDeclLine(CXDecl);
|
||||
CINDEX_LINKAGE unsigned clang_getDeclColumn(CXDecl);
|
||||
CINDEX_LINKAGE CXString clang_getDeclUSR(CXDecl);
|
||||
CINDEX_LINKAGE const char *clang_getDeclSource(CXDecl); /* deprecate */
|
||||
CINDEX_LINKAGE CXFile clang_getDeclSourceFile(CXDecl);
|
||||
|
||||
typedef struct CXSourceLineColumn {
|
||||
unsigned line;
|
||||
unsigned column;
|
||||
} CXSourceLineColumn;
|
||||
|
||||
typedef struct CXDeclExtent {
|
||||
CXSourceLineColumn begin;
|
||||
CXSourceLineColumn end;
|
||||
} CXSourceExtent;
|
||||
|
||||
/* clang_getDeclExtent() returns the physical extent of a declaration. The
|
||||
* beginning line/column pair points to the start of the first token in the
|
||||
* declaration, and the ending line/column pair points to the last character in
|
||||
* the last token of the declaration.
|
||||
*/
|
||||
CINDEX_LINKAGE CXSourceExtent clang_getDeclExtent(CXDecl);
|
||||
|
||||
/*
|
||||
* CXCursor Operations.
|
||||
*/
|
||||
@ -564,7 +588,28 @@ enum CXCompletionChunkKind {
|
||||
* the text buffer. Rather, it is meant to illustrate the type that an
|
||||
* expression using the given completion string would have.
|
||||
*/
|
||||
CXCompletionChunk_ResultType
|
||||
CXCompletionChunk_ResultType,
|
||||
/**
|
||||
* \brief A colon (':').
|
||||
*/
|
||||
CXCompletionChunk_Colon,
|
||||
/**
|
||||
* \brief A semicolon (';').
|
||||
*/
|
||||
CXCompletionChunk_SemiColon,
|
||||
/**
|
||||
* \brief An '=' sign.
|
||||
*/
|
||||
CXCompletionChunk_Equal,
|
||||
/**
|
||||
* Horizontal space (' ').
|
||||
*/
|
||||
CXCompletionChunk_HorizontalSpace,
|
||||
/**
|
||||
* Vertical space ('\n'), after which it is generally a good idea to
|
||||
* perform indentation.
|
||||
*/
|
||||
CXCompletionChunk_VerticalSpace
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "llvm/ADT/APFloat.h"
|
||||
|
||||
namespace clang {
|
||||
class CharUnits;
|
||||
class Expr;
|
||||
|
||||
/// APValue - This class implements a discriminated union of [uninitialized]
|
||||
@ -47,10 +48,6 @@ private:
|
||||
ComplexAPFloat() : Real(0.0), Imag(0.0) {}
|
||||
};
|
||||
|
||||
struct LV {
|
||||
Expr* Base;
|
||||
uint64_t Offset;
|
||||
};
|
||||
struct Vec {
|
||||
APValue *Elts;
|
||||
unsigned NumElts;
|
||||
@ -88,9 +85,11 @@ public:
|
||||
APValue(const APValue &RHS) : Kind(Uninitialized) {
|
||||
*this = RHS;
|
||||
}
|
||||
APValue(Expr* B, uint64_t O) : Kind(Uninitialized) {
|
||||
APValue(Expr* B, const CharUnits &O) : Kind(Uninitialized) {
|
||||
MakeLValue(); setLValue(B, O);
|
||||
}
|
||||
APValue(Expr* B);
|
||||
|
||||
~APValue() {
|
||||
MakeUninit();
|
||||
}
|
||||
@ -164,14 +163,8 @@ public:
|
||||
return const_cast<APValue*>(this)->getComplexFloatImag();
|
||||
}
|
||||
|
||||
Expr* getLValueBase() const {
|
||||
assert(isLValue() && "Invalid accessor");
|
||||
return ((const LV*)(const void*)Data)->Base;
|
||||
}
|
||||
uint64_t getLValueOffset() const {
|
||||
assert(isLValue() && "Invalid accessor");
|
||||
return ((const LV*)(const void*)Data)->Offset;
|
||||
}
|
||||
Expr* getLValueBase() const;
|
||||
CharUnits getLValueOffset() const;
|
||||
|
||||
void setInt(const APSInt &I) {
|
||||
assert(isInt() && "Invalid accessor");
|
||||
@ -202,11 +195,7 @@ public:
|
||||
((ComplexAPFloat*)(char*)Data)->Real = R;
|
||||
((ComplexAPFloat*)(char*)Data)->Imag = I;
|
||||
}
|
||||
void setLValue(Expr *B, uint64_t O) {
|
||||
assert(isLValue() && "Invalid accessor");
|
||||
((LV*)(char*)Data)->Base = B;
|
||||
((LV*)(char*)Data)->Offset = O;
|
||||
}
|
||||
void setLValue(Expr *B, const CharUnits &O);
|
||||
|
||||
const APValue &operator=(const APValue &RHS);
|
||||
|
||||
@ -237,11 +226,7 @@ private:
|
||||
new ((void*)(char*)Data) ComplexAPFloat();
|
||||
Kind = ComplexFloat;
|
||||
}
|
||||
void MakeLValue() {
|
||||
assert(isUninit() && "Bad state change");
|
||||
new ((void*)(char*)Data) LV();
|
||||
Kind = LValue;
|
||||
}
|
||||
void MakeLValue();
|
||||
};
|
||||
|
||||
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const APValue &V) {
|
||||
|
@ -699,8 +699,8 @@ public:
|
||||
ObjCProtocolDecl *rProto);
|
||||
|
||||
/// getObjCEncodingTypeSize returns size of type for objective-c encoding
|
||||
/// purpose.
|
||||
int getObjCEncodingTypeSize(QualType t);
|
||||
/// purpose in characters.
|
||||
CharUnits getObjCEncodingTypeSize(QualType t);
|
||||
|
||||
/// This setter/getter represents the ObjC 'id' type. It is setup lazily, by
|
||||
/// Sema. id is always a (typedef for a) pointer type, a pointer to a struct.
|
||||
@ -898,17 +898,18 @@ public:
|
||||
return getCanonicalType(T1) == getCanonicalType(T2);
|
||||
}
|
||||
|
||||
/// \brief Returns this type as a completely-unqualified array type, capturing
|
||||
/// the qualifiers in Quals. This only operates on canonical types in order
|
||||
/// to ensure the ArrayType doesn't itself have qualifiers.
|
||||
/// \brief Returns this type as a completely-unqualified array type,
|
||||
/// capturing the qualifiers in Quals. This will remove the minimal amount of
|
||||
/// sugaring from the types, similar to the behavior of
|
||||
/// QualType::getUnqualifiedType().
|
||||
///
|
||||
/// \param T is the canonicalized QualType, which may be an ArrayType
|
||||
/// \param T is the qualified type, which may be an ArrayType
|
||||
///
|
||||
/// \param Quals will receive the full set of qualifiers that were
|
||||
/// applied to the element type of the array.
|
||||
/// applied to the array.
|
||||
///
|
||||
/// \returns if this is an array type, the completely unqualified array type
|
||||
/// that corresponds to it. Otherwise, returns this->getUnqualifiedType().
|
||||
/// that corresponds to it. Otherwise, returns T.getUnqualifiedType().
|
||||
QualType getUnqualifiedArrayType(QualType T, Qualifiers &Quals);
|
||||
|
||||
/// \brief Determine whether the given types are equivalent after
|
||||
@ -996,7 +997,10 @@ public:
|
||||
const IncompleteArrayType *getAsIncompleteArrayType(QualType T) {
|
||||
return dyn_cast_or_null<IncompleteArrayType>(getAsArrayType(T));
|
||||
}
|
||||
|
||||
const DependentSizedArrayType *getAsDependentSizedArrayType(QualType T) {
|
||||
return dyn_cast_or_null<DependentSizedArrayType>(getAsArrayType(T));
|
||||
}
|
||||
|
||||
/// getBaseElementType - Returns the innermost element type of an array type.
|
||||
/// For example, will return "int" for int[m][n]
|
||||
QualType getBaseElementType(const ArrayType *VAT);
|
||||
|
@ -55,8 +55,6 @@ public:
|
||||
Cleanup,
|
||||
Const,
|
||||
Constructor,
|
||||
DLLExport,
|
||||
DLLImport,
|
||||
Deprecated,
|
||||
Destructor,
|
||||
FastCall,
|
||||
@ -93,7 +91,12 @@ public:
|
||||
Visibility,
|
||||
WarnUnusedResult,
|
||||
Weak,
|
||||
WeakImport
|
||||
WeakImport,
|
||||
|
||||
FIRST_TARGET_ATTRIBUTE,
|
||||
DLLExport,
|
||||
DLLImport,
|
||||
MSP430Interrupt
|
||||
};
|
||||
|
||||
private:
|
||||
@ -158,7 +161,7 @@ public:
|
||||
class ATTR##Attr : public Attr { \
|
||||
public: \
|
||||
ATTR##Attr() : Attr(ATTR) {} \
|
||||
virtual Attr *clone(ASTContext &C) const { return ::new (C) ATTR##Attr; }\
|
||||
virtual Attr *clone(ASTContext &C) const; \
|
||||
static bool classof(const Attr *A) { return A->getKind() == ATTR; } \
|
||||
static bool classof(const ATTR##Attr *A) { return true; } \
|
||||
}
|
||||
@ -174,9 +177,7 @@ public:
|
||||
/// getAlignment - The specified alignment in bits.
|
||||
unsigned getAlignment() const { return Alignment; }
|
||||
|
||||
virtual Attr* clone(ASTContext &C) const {
|
||||
return ::new (C) PragmaPackAttr(Alignment);
|
||||
}
|
||||
virtual Attr* clone(ASTContext &C) const;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) {
|
||||
@ -203,9 +204,7 @@ public:
|
||||
return Alignment;
|
||||
}
|
||||
|
||||
virtual Attr* clone(ASTContext &C) const {
|
||||
return ::new (C) AlignedAttr(Alignment);
|
||||
}
|
||||
virtual Attr* clone(ASTContext &C) const;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) {
|
||||
@ -221,7 +220,7 @@ public:
|
||||
|
||||
const std::string& getAnnotation() const { return Annotation; }
|
||||
|
||||
virtual Attr* clone(ASTContext &C) const { return ::new (C) AnnotateAttr(Annotation); }
|
||||
virtual Attr* clone(ASTContext &C) const;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) {
|
||||
@ -237,7 +236,7 @@ public:
|
||||
|
||||
const std::string& getLabel() const { return Label; }
|
||||
|
||||
virtual Attr* clone(ASTContext &C) const { return ::new (C) AsmLabelAttr(Label); }
|
||||
virtual Attr* clone(ASTContext &C) const;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) {
|
||||
@ -255,7 +254,7 @@ public:
|
||||
|
||||
const std::string& getAliasee() const { return Aliasee; }
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const { return ::new (C) AliasAttr(Aliasee); }
|
||||
virtual Attr *clone(ASTContext &C) const;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) { return A->getKind() == Alias; }
|
||||
@ -269,7 +268,7 @@ public:
|
||||
|
||||
int getPriority() const { return priority; }
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const { return ::new (C) ConstructorAttr(priority); }
|
||||
virtual Attr *clone(ASTContext &C) const;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) { return A->getKind() == Constructor; }
|
||||
@ -283,7 +282,7 @@ public:
|
||||
|
||||
int getPriority() const { return priority; }
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const { return ::new (C) DestructorAttr(priority); }
|
||||
virtual Attr *clone(ASTContext &C) const;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) { return A->getKind() == Destructor; }
|
||||
@ -294,7 +293,7 @@ class GNUInlineAttr : public Attr {
|
||||
public:
|
||||
GNUInlineAttr() : Attr(GNUInline) {}
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const { return ::new (C) GNUInlineAttr; }
|
||||
virtual Attr *clone(ASTContext &C) const;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) {
|
||||
@ -307,7 +306,7 @@ class IBOutletAttr : public Attr {
|
||||
public:
|
||||
IBOutletAttr() : Attr(IBOutletKind) {}
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const { return ::new (C) IBOutletAttr; }
|
||||
virtual Attr *clone(ASTContext &C) const;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) {
|
||||
@ -329,7 +328,7 @@ public:
|
||||
|
||||
const std::string& getName() const { return Name; }
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const { return ::new (C) SectionAttr(Name); }
|
||||
virtual Attr *clone(ASTContext &C) const;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) {
|
||||
@ -374,7 +373,7 @@ public:
|
||||
return ArgNums ? std::binary_search(ArgNums, ArgNums+Size, arg) : true;
|
||||
}
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const { return ::new (C) NonNullAttr(ArgNums, Size); }
|
||||
virtual Attr *clone(ASTContext &C) const;
|
||||
|
||||
static bool classof(const Attr *A) { return A->getKind() == NonNull; }
|
||||
static bool classof(const NonNullAttr *A) { return true; }
|
||||
@ -392,9 +391,7 @@ public:
|
||||
int getFormatIdx() const { return formatIdx; }
|
||||
int getFirstArg() const { return firstArg; }
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const {
|
||||
return ::new (C) FormatAttr(Type, formatIdx, firstArg);
|
||||
}
|
||||
virtual Attr *clone(ASTContext &C) const;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) { return A->getKind() == Format; }
|
||||
@ -407,9 +404,7 @@ public:
|
||||
FormatArgAttr(int idx) : Attr(FormatArg), formatIdx(idx) {}
|
||||
int getFormatIdx() const { return formatIdx; }
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const {
|
||||
return ::new (C) FormatArgAttr(formatIdx);
|
||||
}
|
||||
virtual Attr *clone(ASTContext &C) const;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) { return A->getKind() == FormatArg; }
|
||||
@ -424,9 +419,7 @@ public:
|
||||
int getSentinel() const { return sentinel; }
|
||||
int getNullPos() const { return NullPos; }
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const {
|
||||
return ::new (C) SentinelAttr(sentinel, NullPos);
|
||||
}
|
||||
virtual Attr *clone(ASTContext &C) const;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) { return A->getKind() == Sentinel; }
|
||||
@ -449,15 +442,13 @@ public:
|
||||
|
||||
VisibilityTypes getVisibility() const { return VisibilityType; }
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const { return ::new (C) VisibilityAttr(VisibilityType); }
|
||||
virtual Attr *clone(ASTContext &C) const;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) { return A->getKind() == Visibility; }
|
||||
static bool classof(const VisibilityAttr *A) { return true; }
|
||||
};
|
||||
|
||||
DEF_SIMPLE_ATTR(DLLImport);
|
||||
DEF_SIMPLE_ATTR(DLLExport);
|
||||
DEF_SIMPLE_ATTR(FastCall);
|
||||
DEF_SIMPLE_ATTR(StdCall);
|
||||
DEF_SIMPLE_ATTR(CDecl);
|
||||
@ -471,9 +462,7 @@ public:
|
||||
|
||||
virtual bool isMerged() const { return false; }
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const {
|
||||
return ::new (C) OverloadableAttr;
|
||||
}
|
||||
virtual Attr *clone(ASTContext &C) const;
|
||||
|
||||
static bool classof(const Attr *A) { return A->getKind() == Overloadable; }
|
||||
static bool classof(const OverloadableAttr *) { return true; }
|
||||
@ -491,7 +480,7 @@ public:
|
||||
|
||||
BlocksAttrTypes getType() const { return BlocksAttrType; }
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const { return ::new (C) BlocksAttr(BlocksAttrType); }
|
||||
virtual Attr *clone(ASTContext &C) const;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) { return A->getKind() == Blocks; }
|
||||
@ -508,7 +497,7 @@ public:
|
||||
|
||||
const FunctionDecl *getFunctionDecl() const { return FD; }
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const { return ::new (C) CleanupAttr(FD); }
|
||||
virtual Attr *clone(ASTContext &C) const;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) { return A->getKind() == Cleanup; }
|
||||
@ -527,9 +516,7 @@ public:
|
||||
|
||||
unsigned getNumParams() const { return NumParams; }
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const {
|
||||
return ::new (C) RegparmAttr(NumParams);
|
||||
}
|
||||
virtual Attr *clone(ASTContext &C) const;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) { return A->getKind() == Regparm; }
|
||||
@ -546,9 +533,7 @@ public:
|
||||
unsigned getYDim() const { return Y; }
|
||||
unsigned getZDim() const { return Z; }
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const {
|
||||
return ::new (C) ReqdWorkGroupSizeAttr(X, Y, Z);
|
||||
}
|
||||
virtual Attr *clone(ASTContext &C) const;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) {
|
||||
@ -566,6 +551,25 @@ DEF_SIMPLE_ATTR(BaseCheck);
|
||||
DEF_SIMPLE_ATTR(Hiding);
|
||||
DEF_SIMPLE_ATTR(Override);
|
||||
|
||||
// Target-specific attributes
|
||||
DEF_SIMPLE_ATTR(DLLImport);
|
||||
DEF_SIMPLE_ATTR(DLLExport);
|
||||
|
||||
class MSP430InterruptAttr : public Attr {
|
||||
unsigned Number;
|
||||
|
||||
public:
|
||||
MSP430InterruptAttr(unsigned n) : Attr(MSP430Interrupt), Number(n) {}
|
||||
|
||||
unsigned getNumber() const { return Number; }
|
||||
|
||||
virtual Attr *clone(ASTContext &C) const;
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Attr *A) { return A->getKind() == MSP430Interrupt; }
|
||||
static bool classof(const MSP430InterruptAttr *A) { return true; }
|
||||
};
|
||||
|
||||
#undef DEF_SIMPLE_ATTR
|
||||
|
||||
} // end namespace clang
|
||||
|
@ -36,12 +36,12 @@ namespace clang {
|
||||
/// in character units.
|
||||
class CharUnits {
|
||||
public:
|
||||
typedef int64_t RawType;
|
||||
typedef int64_t QuantityType;
|
||||
|
||||
private:
|
||||
RawType Quantity;
|
||||
QuantityType Quantity;
|
||||
|
||||
explicit CharUnits(RawType C) : Quantity(C) {}
|
||||
explicit CharUnits(QuantityType C) : Quantity(C) {}
|
||||
|
||||
public:
|
||||
|
||||
@ -58,8 +58,8 @@ namespace clang {
|
||||
return CharUnits(1);
|
||||
}
|
||||
|
||||
/// fromRaw - Construct a CharUnits quantity from a raw integer type.
|
||||
static CharUnits fromRaw(RawType Quantity) {
|
||||
/// fromQuantity - Construct a CharUnits quantity from a raw integer type.
|
||||
static CharUnits fromQuantity(QuantityType Quantity) {
|
||||
return CharUnits(Quantity);
|
||||
}
|
||||
|
||||
@ -103,26 +103,26 @@ namespace clang {
|
||||
/// isOne - Test whether the quantity equals one.
|
||||
bool isOne() const { return Quantity == 1; }
|
||||
|
||||
/// isPositive - Test whether the quanity is greater than zero.
|
||||
/// isPositive - Test whether the quantity is greater than zero.
|
||||
bool isPositive() const { return Quantity > 0; }
|
||||
|
||||
/// isNegative - Test whether the quantity is less than zero.
|
||||
bool isNegative() const { return Quantity < 0; }
|
||||
|
||||
// Arithmetic operators.
|
||||
CharUnits operator* (RawType N) const {
|
||||
CharUnits operator* (QuantityType N) const {
|
||||
return CharUnits(Quantity * N);
|
||||
}
|
||||
CharUnits operator/ (RawType N) const {
|
||||
CharUnits operator/ (QuantityType N) const {
|
||||
return CharUnits(Quantity / N);
|
||||
}
|
||||
RawType operator/ (const CharUnits &Other) const {
|
||||
QuantityType operator/ (const CharUnits &Other) const {
|
||||
return Quantity / Other.Quantity;
|
||||
}
|
||||
CharUnits operator% (RawType N) const {
|
||||
CharUnits operator% (QuantityType N) const {
|
||||
return CharUnits(Quantity % N);
|
||||
}
|
||||
RawType operator% (const CharUnits &Other) const {
|
||||
QuantityType operator% (const CharUnits &Other) const {
|
||||
return Quantity % Other.Quantity;
|
||||
}
|
||||
CharUnits operator+ (const CharUnits &Other) const {
|
||||
@ -134,14 +134,14 @@ namespace clang {
|
||||
|
||||
// Conversions.
|
||||
|
||||
/// getRaw - Get the raw integer representation of this quantity.
|
||||
RawType getRaw() const { return Quantity; }
|
||||
/// getQuantity - Get the raw integer representation of this quantity.
|
||||
QuantityType getQuantity() const { return Quantity; }
|
||||
|
||||
|
||||
}; // class CharUnit
|
||||
} // namespace clang
|
||||
|
||||
inline clang::CharUnits operator* (clang::CharUnits::RawType Scale,
|
||||
inline clang::CharUnits operator* (clang::CharUnits::QuantityType Scale,
|
||||
const clang::CharUnits &CU) {
|
||||
return CU * Scale;
|
||||
}
|
||||
|
@ -1184,6 +1184,8 @@ public:
|
||||
|
||||
OverloadedOperatorKind getOverloadedOperator() const;
|
||||
|
||||
const IdentifierInfo *getLiteralIdentifier() const;
|
||||
|
||||
/// \brief If this function is an instantiation of a member function
|
||||
/// of a class template specialization, retrieves the function from
|
||||
/// which it was instantiated.
|
||||
|
@ -393,6 +393,9 @@ public:
|
||||
return reverse_base_class_const_iterator(vbases_begin());
|
||||
}
|
||||
|
||||
/// \brief Determine whether this class has any dependent base classes.
|
||||
bool hasAnyDependentBases() const;
|
||||
|
||||
/// Iterator access to method members. The method iterator visits
|
||||
/// all method members of the class, including non-instance methods,
|
||||
/// special methods, etc.
|
||||
|
@ -289,7 +289,9 @@ struct ObjCMethodList {
|
||||
/// ObjCProtocolDecl, and ObjCImplDecl.
|
||||
///
|
||||
class ObjCContainerDecl : public NamedDecl, public DeclContext {
|
||||
SourceLocation AtEndLoc; // marks the end of the method container.
|
||||
// These two locations in the range mark the end of the method container.
|
||||
// The first points to the '@' token, and the second to the 'end' token.
|
||||
SourceRange AtEnd;
|
||||
public:
|
||||
|
||||
ObjCContainerDecl(Kind DK, DeclContext *DC, SourceLocation L,
|
||||
@ -351,11 +353,15 @@ public:
|
||||
IdentifierInfo *PropertyId) const;
|
||||
|
||||
// Marks the end of the container.
|
||||
SourceLocation getAtEndLoc() const { return AtEndLoc; }
|
||||
void setAtEndLoc(SourceLocation L) { AtEndLoc = L; }
|
||||
SourceRange getAtEndRange() const {
|
||||
return AtEnd;
|
||||
}
|
||||
void setAtEndRange(SourceRange atEnd) {
|
||||
AtEnd = atEnd;
|
||||
}
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(getLocation(), getAtEndLoc());
|
||||
return SourceRange(getLocation(), getAtEndRange().getEnd());
|
||||
}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
|
@ -190,6 +190,14 @@ public:
|
||||
/// getNameKind - Determine what kind of name this is.
|
||||
NameKind getNameKind() const;
|
||||
|
||||
/// \brief Determines whether the name itself is dependent, e.g., because it
|
||||
/// involves a C++ type that is itself dependent.
|
||||
///
|
||||
/// Note that this does not capture all of the notions of "dependent name",
|
||||
/// because an identifier can be a dependent name if it is used as the
|
||||
/// callee in a call expression with dependent arguments.
|
||||
bool isDependentName() const;
|
||||
|
||||
/// getName - Retrieve the human-readable string for this name.
|
||||
std::string getAsString() const;
|
||||
|
||||
@ -301,6 +309,7 @@ inline bool operator>=(DeclarationName LHS, DeclarationName RHS) {
|
||||
class DeclarationNameTable {
|
||||
void *CXXSpecialNamesImpl; // Actually a FoldingSet<CXXSpecialName> *
|
||||
CXXOperatorIdName *CXXOperatorNames; // Operator names
|
||||
void *CXXLiteralOperatorNames; // Actually a FoldingSet<...> *
|
||||
|
||||
DeclarationNameTable(const DeclarationNameTable&); // NONCOPYABLE
|
||||
DeclarationNameTable& operator=(const DeclarationNameTable&); // NONCOPYABLE
|
||||
|
@ -241,6 +241,11 @@ public:
|
||||
/// stack based objects.
|
||||
bool EvaluateAsAny(EvalResult &Result, ASTContext &Ctx) const;
|
||||
|
||||
/// EvaluateAsBooleanCondition - Return true if this is a constant
|
||||
/// which we we can fold and convert to a boolean condition using
|
||||
/// any crazy technique that we want to.
|
||||
bool EvaluateAsBooleanCondition(bool &Result, ASTContext &Ctx) const;
|
||||
|
||||
/// isEvaluatable - Call Evaluate to see if this expression can be constant
|
||||
/// folded, but discard the result.
|
||||
bool isEvaluatable(ASTContext &Ctx) const;
|
||||
@ -2552,7 +2557,7 @@ private:
|
||||
unsigned NumSubExprs : 16;
|
||||
|
||||
|
||||
DesignatedInitExpr(QualType Ty, unsigned NumDesignators,
|
||||
DesignatedInitExpr(ASTContext &C, QualType Ty, unsigned NumDesignators,
|
||||
const Designator *Designators,
|
||||
SourceLocation EqualOrColonLoc, bool GNUSyntax,
|
||||
Expr **IndexExprs, unsigned NumIndexExprs,
|
||||
@ -2565,6 +2570,8 @@ private:
|
||||
protected:
|
||||
virtual void DoDestroy(ASTContext &C);
|
||||
|
||||
void DestroyDesignators(ASTContext &C);
|
||||
|
||||
public:
|
||||
/// A field designator, e.g., ".x".
|
||||
struct FieldDesignator {
|
||||
@ -2732,7 +2739,8 @@ public:
|
||||
|
||||
Designator *getDesignator(unsigned Idx) { return &designators_begin()[Idx]; }
|
||||
|
||||
void setDesignators(const Designator *Desigs, unsigned NumDesigs);
|
||||
void setDesignators(ASTContext &C, const Designator *Desigs,
|
||||
unsigned NumDesigs);
|
||||
|
||||
Expr *getArrayIndex(const Designator& D);
|
||||
Expr *getArrayRangeStart(const Designator& D);
|
||||
@ -2779,7 +2787,7 @@ public:
|
||||
|
||||
/// \brief Replaces the designator at index @p Idx with the series
|
||||
/// of designators in [First, Last).
|
||||
void ExpandDesignator(unsigned Idx, const Designator *First,
|
||||
void ExpandDesignator(ASTContext &C, unsigned Idx, const Designator *First,
|
||||
const Designator *Last);
|
||||
|
||||
virtual SourceRange getSourceRange() const;
|
||||
|
@ -324,17 +324,21 @@ public:
|
||||
/// @endcode
|
||||
class CXXThisExpr : public Expr {
|
||||
SourceLocation Loc;
|
||||
|
||||
bool Implicit : 1;
|
||||
|
||||
public:
|
||||
CXXThisExpr(SourceLocation L, QualType Type)
|
||||
CXXThisExpr(SourceLocation L, QualType Type, bool isImplicit)
|
||||
: Expr(CXXThisExprClass, Type,
|
||||
// 'this' is type-dependent if the class type of the enclosing
|
||||
// member function is dependent (C++ [temp.dep.expr]p2)
|
||||
Type->isDependentType(), Type->isDependentType()),
|
||||
Loc(L) { }
|
||||
Loc(L), Implicit(isImplicit) { }
|
||||
|
||||
virtual SourceRange getSourceRange() const { return SourceRange(Loc); }
|
||||
|
||||
bool isImplicit() const { return Implicit; }
|
||||
void setImplicit(bool I) { Implicit = I; }
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CXXThisExprClass;
|
||||
}
|
||||
|
@ -1116,6 +1116,7 @@ class AsmStmt : public Stmt {
|
||||
|
||||
bool IsSimple;
|
||||
bool IsVolatile;
|
||||
bool MSAsm;
|
||||
|
||||
unsigned NumOutputs;
|
||||
unsigned NumInputs;
|
||||
@ -1126,7 +1127,7 @@ class AsmStmt : public Stmt {
|
||||
|
||||
llvm::SmallVector<StringLiteral*, 4> Clobbers;
|
||||
public:
|
||||
AsmStmt(SourceLocation asmloc, bool issimple, bool isvolatile,
|
||||
AsmStmt(SourceLocation asmloc, bool issimple, bool isvolatile, bool msasm,
|
||||
unsigned numoutputs, unsigned numinputs,
|
||||
std::string *names, StringLiteral **constraints,
|
||||
Expr **exprs, StringLiteral *asmstr, unsigned numclobbers,
|
||||
@ -1143,7 +1144,9 @@ public:
|
||||
bool isVolatile() const { return IsVolatile; }
|
||||
void setVolatile(bool V) { IsVolatile = V; }
|
||||
bool isSimple() const { return IsSimple; }
|
||||
void setSimple(bool V) { IsSimple = false; }
|
||||
void setSimple(bool V) { IsSimple = V; }
|
||||
bool isMSAsm() const { return MSAsm; }
|
||||
void setMSAsm(bool V) { MSAsm = V; }
|
||||
|
||||
//===--- Asm String Analysis ---===//
|
||||
|
||||
|
@ -1029,18 +1029,88 @@ class ComplexTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
|
||||
ComplexType> {
|
||||
};
|
||||
|
||||
// FIXME: location of the 'typeof' and parens (the expression is
|
||||
// carried by the type).
|
||||
class TypeOfExprTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
|
||||
TypeOfExprTypeLoc,
|
||||
TypeOfExprType> {
|
||||
struct TypeofLocInfo {
|
||||
SourceLocation TypeofLoc;
|
||||
SourceLocation LParenLoc;
|
||||
SourceLocation RParenLoc;
|
||||
};
|
||||
|
||||
// FIXME: location of the 'typeof' and parens; also the TypeSourceInfo
|
||||
// for the inner type, or (maybe) just express that inline to the TypeLoc.
|
||||
class TypeOfTypeLoc : public InheritingConcreteTypeLoc<TypeSpecTypeLoc,
|
||||
TypeOfTypeLoc,
|
||||
TypeOfType> {
|
||||
struct TypeOfExprTypeLocInfo : public TypeofLocInfo {
|
||||
};
|
||||
|
||||
struct TypeOfTypeLocInfo : public TypeofLocInfo {
|
||||
TypeSourceInfo* UnderlyingTInfo;
|
||||
};
|
||||
|
||||
template <class Derived, class TypeClass, class LocalData = TypeofLocInfo>
|
||||
class TypeofLikeTypeLoc
|
||||
: public ConcreteTypeLoc<UnqualTypeLoc, Derived, TypeClass, LocalData> {
|
||||
public:
|
||||
SourceLocation getTypeofLoc() const {
|
||||
return this->getLocalData()->TypeofLoc;
|
||||
}
|
||||
void setTypeofLoc(SourceLocation Loc) {
|
||||
this->getLocalData()->TypeofLoc = Loc;
|
||||
}
|
||||
|
||||
SourceLocation getLParenLoc() const {
|
||||
return this->getLocalData()->LParenLoc;
|
||||
}
|
||||
void setLParenLoc(SourceLocation Loc) {
|
||||
this->getLocalData()->LParenLoc = Loc;
|
||||
}
|
||||
|
||||
SourceLocation getRParenLoc() const {
|
||||
return this->getLocalData()->RParenLoc;
|
||||
}
|
||||
void setRParenLoc(SourceLocation Loc) {
|
||||
this->getLocalData()->RParenLoc = Loc;
|
||||
}
|
||||
|
||||
SourceRange getParensRange() const {
|
||||
return SourceRange(getLParenLoc(), getRParenLoc());
|
||||
}
|
||||
void setParensRange(SourceRange range) {
|
||||
setLParenLoc(range.getBegin());
|
||||
setRParenLoc(range.getEnd());
|
||||
}
|
||||
|
||||
SourceRange getSourceRange() const {
|
||||
return SourceRange(getTypeofLoc(), getRParenLoc());
|
||||
}
|
||||
|
||||
void initializeLocal(SourceLocation Loc) {
|
||||
setTypeofLoc(Loc);
|
||||
setLParenLoc(Loc);
|
||||
setRParenLoc(Loc);
|
||||
}
|
||||
};
|
||||
|
||||
class TypeOfExprTypeLoc : public TypeofLikeTypeLoc<TypeOfExprTypeLoc,
|
||||
TypeOfExprType,
|
||||
TypeOfExprTypeLocInfo> {
|
||||
public:
|
||||
Expr* getUnderlyingExpr() const {
|
||||
return getTypePtr()->getUnderlyingExpr();
|
||||
}
|
||||
// Reimplemented to account for GNU/C++ extension
|
||||
// typeof unary-expression
|
||||
// where there are no parentheses.
|
||||
SourceRange getSourceRange() const;
|
||||
};
|
||||
|
||||
class TypeOfTypeLoc
|
||||
: public TypeofLikeTypeLoc<TypeOfTypeLoc, TypeOfType, TypeOfTypeLocInfo> {
|
||||
public:
|
||||
QualType getUnderlyingType() const {
|
||||
return this->getTypePtr()->getUnderlyingType();
|
||||
}
|
||||
TypeSourceInfo* getUnderlyingTInfo() const {
|
||||
return this->getLocalData()->UnderlyingTInfo;
|
||||
}
|
||||
void setUnderlyingTInfo(TypeSourceInfo* TI) const {
|
||||
this->getLocalData()->UnderlyingTInfo = TI;
|
||||
}
|
||||
};
|
||||
|
||||
// FIXME: location of the 'decltype' and parens.
|
||||
|
@ -23,7 +23,6 @@
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/SmallSet.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/ADT/ImmutableSet.h"
|
||||
#include <list>
|
||||
|
||||
@ -104,9 +103,9 @@ public:
|
||||
// BugReporter.
|
||||
const Stmt* getStmt() const;
|
||||
|
||||
const std::string& getDescription() const { return Description; }
|
||||
const llvm::StringRef getDescription() const { return Description; }
|
||||
|
||||
const std::string& getShortDescription() const {
|
||||
const llvm::StringRef getShortDescription() const {
|
||||
return ShortDescription.empty() ? Description : ShortDescription;
|
||||
}
|
||||
|
||||
@ -444,7 +443,7 @@ public:
|
||||
// FIXME: Move out-of-line (virtual function).
|
||||
SourceLocation getLocation() const { return L; }
|
||||
|
||||
void addString(const std::string& s) { Strs.push_back(s); }
|
||||
void addString(llvm::StringRef s) { Strs.push_back(s); }
|
||||
|
||||
typedef std::list<std::string>::const_iterator str_iterator;
|
||||
str_iterator str_begin() const { return Strs.begin(); }
|
||||
|
@ -25,6 +25,7 @@ namespace clang {
|
||||
|
||||
class GRState;
|
||||
class GRStateManager;
|
||||
class GRSubEngine;
|
||||
class SVal;
|
||||
|
||||
class ConstraintManager {
|
||||
@ -64,8 +65,10 @@ public:
|
||||
virtual bool canReasonAbout(SVal X) const = 0;
|
||||
};
|
||||
|
||||
ConstraintManager* CreateBasicConstraintManager(GRStateManager& statemgr);
|
||||
ConstraintManager* CreateRangeConstraintManager(GRStateManager& statemgr);
|
||||
ConstraintManager* CreateBasicConstraintManager(GRStateManager& statemgr,
|
||||
GRSubEngine &subengine);
|
||||
ConstraintManager* CreateRangeConstraintManager(GRStateManager& statemgr,
|
||||
GRSubEngine &subengine);
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
|
@ -87,9 +87,11 @@ class GRExprEngine : public GRSubEngine {
|
||||
// this object be placed at the very end of member variables so that its
|
||||
// destructor is called before the rest of the GRExprEngine is destroyed.
|
||||
GRBugReporter BR;
|
||||
|
||||
llvm::OwningPtr<GRTransferFuncs> TF;
|
||||
|
||||
public:
|
||||
GRExprEngine(AnalysisManager &mgr);
|
||||
GRExprEngine(AnalysisManager &mgr, GRTransferFuncs *tf);
|
||||
|
||||
~GRExprEngine();
|
||||
|
||||
@ -104,18 +106,14 @@ public:
|
||||
|
||||
SValuator &getSValuator() { return SVator; }
|
||||
|
||||
GRTransferFuncs& getTF() { return *StateMgr.TF; }
|
||||
GRTransferFuncs& getTF() { return *TF; }
|
||||
|
||||
BugReporter& getBugReporter() { return BR; }
|
||||
|
||||
GRStmtNodeBuilder &getBuilder() { assert(Builder); return *Builder; }
|
||||
|
||||
/// setTransferFunctions
|
||||
void setTransferFunctionsAndCheckers(GRTransferFuncs* tf);
|
||||
|
||||
void setTransferFunctions(GRTransferFuncs& tf) {
|
||||
setTransferFunctionsAndCheckers(&tf);
|
||||
}
|
||||
// FIXME: Remove once GRTransferFuncs is no longer referenced.
|
||||
void setTransferFunction(GRTransferFuncs* tf);
|
||||
|
||||
/// ViewGraph - Visualize the ExplodedGraph created by executing the
|
||||
/// simulation.
|
||||
@ -173,6 +171,10 @@ public:
|
||||
/// ProcessEndPath - Called by GRCoreEngine. Used to generate end-of-path
|
||||
/// nodes when the control reaches the end of a function.
|
||||
void ProcessEndPath(GREndPathNodeBuilder& builder);
|
||||
|
||||
/// EvalAssume - Callback function invoked by the ConstraintManager when
|
||||
/// making assumptions about state values.
|
||||
const GRState *ProcessAssume(const GRState *state, SVal cond, bool assumption);
|
||||
|
||||
GRStateManager& getStateManager() { return StateMgr; }
|
||||
const GRStateManager& getStateManager() const { return StateMgr; }
|
||||
@ -351,6 +353,10 @@ protected:
|
||||
void VisitCXXThisExpr(CXXThisExpr *TE, ExplodedNode *Pred,
|
||||
ExplodedNodeSet & Dst);
|
||||
|
||||
/// Create a C++ temporary object for an rvalue.
|
||||
void CreateCXXTemporaryObject(Expr *Ex, ExplodedNode *Pred,
|
||||
ExplodedNodeSet &Dst);
|
||||
|
||||
/// EvalEagerlyAssume - Given the nodes in 'Src', eagerly assume symbolic
|
||||
/// expressions of the form 'x != 0' and generate new nodes (stored in Dst)
|
||||
/// with those assumptions.
|
||||
|
@ -40,10 +40,10 @@
|
||||
namespace clang {
|
||||
|
||||
class GRStateManager;
|
||||
class GRTransferFuncs;
|
||||
class Checker;
|
||||
|
||||
typedef ConstraintManager* (*ConstraintManagerCreator)(GRStateManager&);
|
||||
typedef ConstraintManager* (*ConstraintManagerCreator)(GRStateManager&,
|
||||
GRSubEngine&);
|
||||
typedef StoreManager* (*StoreManagerCreator)(GRStateManager&);
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -159,10 +159,6 @@ public:
|
||||
|
||||
BasicValueFactory &getBasicVals() const;
|
||||
SymbolManager &getSymbolManager() const;
|
||||
GRTransferFuncs &getTransferFuncs() const;
|
||||
|
||||
std::vector<std::pair<void *, Checker *> >::iterator checker_begin() const;
|
||||
std::vector<std::pair<void *, Checker *> >::iterator checker_end() const;
|
||||
|
||||
//==---------------------------------------------------------------------==//
|
||||
// Constraints on values.
|
||||
@ -391,9 +387,8 @@ public:
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
class GRStateManager {
|
||||
friend class GRExprEngine;
|
||||
friend class GRState;
|
||||
|
||||
friend class GRExprEngine; // FIXME: Remove.
|
||||
private:
|
||||
EnvironmentManager EnvMgr;
|
||||
llvm::OwningPtr<StoreManager> StoreMgr;
|
||||
@ -416,27 +411,20 @@ private:
|
||||
ValueManager ValueMgr;
|
||||
|
||||
/// Alloc - A BumpPtrAllocator to allocate states.
|
||||
llvm::BumpPtrAllocator& Alloc;
|
||||
|
||||
/// TF - Object that represents a bundle of transfer functions
|
||||
/// for manipulating and creating SVals.
|
||||
GRTransferFuncs* TF;
|
||||
|
||||
/// Reference to all checkers in GRExprEngine.
|
||||
std::vector<std::pair<void *, Checker*> > *Checkers;
|
||||
llvm::BumpPtrAllocator &Alloc;
|
||||
|
||||
public:
|
||||
|
||||
GRStateManager(ASTContext& Ctx,
|
||||
StoreManagerCreator CreateStoreManager,
|
||||
ConstraintManagerCreator CreateConstraintManager,
|
||||
llvm::BumpPtrAllocator& alloc)
|
||||
llvm::BumpPtrAllocator& alloc,
|
||||
GRSubEngine &subeng)
|
||||
: EnvMgr(alloc),
|
||||
GDMFactory(alloc),
|
||||
ValueMgr(alloc, Ctx, *this),
|
||||
Alloc(alloc) {
|
||||
StoreMgr.reset((*CreateStoreManager)(*this));
|
||||
ConstraintMgr.reset((*CreateConstraintManager)(*this));
|
||||
ConstraintMgr.reset((*CreateConstraintManager)(*this, subeng));
|
||||
}
|
||||
|
||||
~GRStateManager();
|
||||
@ -446,10 +434,6 @@ public:
|
||||
ASTContext &getContext() { return ValueMgr.getContext(); }
|
||||
const ASTContext &getContext() const { return ValueMgr.getContext(); }
|
||||
|
||||
GRTransferFuncs& getTransferFuncs() { return *TF; }
|
||||
|
||||
std::vector<std::pair<void *, Checker *> > &getCheckers() { return *Checkers;}
|
||||
|
||||
BasicValueFactory &getBasicVals() {
|
||||
return ValueMgr.getBasicValueFactory();
|
||||
}
|
||||
@ -702,20 +686,6 @@ inline SymbolManager &GRState::getSymbolManager() const {
|
||||
return getStateManager().getSymbolManager();
|
||||
}
|
||||
|
||||
inline GRTransferFuncs &GRState::getTransferFuncs() const {
|
||||
return getStateManager().getTransferFuncs();
|
||||
}
|
||||
|
||||
inline std::vector<std::pair<void *, Checker *> >::iterator
|
||||
GRState::checker_begin() const {
|
||||
return getStateManager().getCheckers().begin();
|
||||
}
|
||||
|
||||
inline std::vector<std::pair<void *, Checker *> >::iterator
|
||||
GRState::checker_end() const {
|
||||
return getStateManager().getCheckers().end();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const GRState *GRState::add(typename GRStateTrait<T>::key_type K) const {
|
||||
return getStateManager().add<T>(this, K, get_context<T>());
|
||||
|
@ -13,6 +13,8 @@
|
||||
#ifndef LLVM_CLANG_ANALYSIS_GRSUBENGINE_H
|
||||
#define LLVM_CLANG_ANALYSIS_GRSUBENGINE_H
|
||||
|
||||
#include "clang/Analysis/PathSensitive/SVals.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
class Stmt;
|
||||
@ -62,8 +64,12 @@ public:
|
||||
/// ProcessEndPath - Called by GRCoreEngine. Used to generate end-of-path
|
||||
/// nodes when the control reaches the end of a function.
|
||||
virtual void ProcessEndPath(GREndPathNodeBuilder& builder) = 0;
|
||||
|
||||
/// EvalAssume - Called by ConstraintManager. Used to call checker-specific
|
||||
/// logic for handling assumptions on symbolic values.
|
||||
virtual const GRState* ProcessAssume(const GRState *state,
|
||||
SVal cond, bool assumption) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -65,6 +65,7 @@ public:
|
||||
BlockTextRegionKind,
|
||||
BlockDataRegionKind,
|
||||
CompoundLiteralRegionKind,
|
||||
CXXThisRegionKind,
|
||||
StringRegionKind,
|
||||
ElementRegionKind,
|
||||
// Decl Regions.
|
||||
@ -99,17 +100,13 @@ public:
|
||||
|
||||
const MemRegion *StripCasts() const;
|
||||
|
||||
bool hasStackStorage() const;
|
||||
|
||||
bool hasParametersStorage() const;
|
||||
|
||||
bool hasGlobalsStorage() const;
|
||||
|
||||
bool hasGlobalsOrParametersStorage() const;
|
||||
|
||||
bool hasHeapStorage() const;
|
||||
|
||||
bool hasHeapOrStackStorage() const;
|
||||
bool hasStackStorage() const;
|
||||
|
||||
bool hasStackNonParametersStorage() const;
|
||||
|
||||
bool hasStackParametersStorage() const;
|
||||
|
||||
virtual void dumpToStream(llvm::raw_ostream& os) const;
|
||||
|
||||
@ -634,6 +631,36 @@ public:
|
||||
return R->getKind() == VarRegionKind;
|
||||
}
|
||||
};
|
||||
|
||||
/// CXXThisRegion - Represents the region for the implicit 'this' parameter
|
||||
/// in a call to a C++ method. This region doesn't represent the object
|
||||
/// referred to by 'this', but rather 'this' itself.
|
||||
class CXXThisRegion : public TypedRegion {
|
||||
friend class MemRegionManager;
|
||||
CXXThisRegion(const PointerType *thisPointerTy,
|
||||
const MemRegion *sReg)
|
||||
: TypedRegion(sReg, CXXThisRegionKind), ThisPointerTy(thisPointerTy) {}
|
||||
|
||||
static void ProfileRegion(llvm::FoldingSetNodeID &ID,
|
||||
const PointerType *PT,
|
||||
const MemRegion *sReg);
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) const;
|
||||
|
||||
public:
|
||||
QualType getValueType(ASTContext &C) const {
|
||||
return QualType(ThisPointerTy, 0);
|
||||
}
|
||||
|
||||
void dumpToStream(llvm::raw_ostream& os) const;
|
||||
|
||||
static bool classof(const MemRegion* R) {
|
||||
return R->getKind() == CXXThisRegionKind;
|
||||
}
|
||||
|
||||
private:
|
||||
const PointerType *ThisPointerTy;
|
||||
};
|
||||
|
||||
class FieldRegion : public DeclRegion {
|
||||
friend class MemRegionManager;
|
||||
@ -725,21 +752,21 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
// C++ temporary object associated with an expression.
|
||||
class CXXObjectRegion : public TypedRegion {
|
||||
friend class MemRegionManager;
|
||||
|
||||
// T - The object type.
|
||||
QualType T;
|
||||
Expr const *Ex;
|
||||
|
||||
CXXObjectRegion(QualType t, const MemRegion *sReg)
|
||||
: TypedRegion(sReg, CXXObjectRegionKind), T(t) {}
|
||||
CXXObjectRegion(Expr const *E, MemRegion const *sReg)
|
||||
: TypedRegion(sReg, CXXObjectRegionKind), Ex(E) {}
|
||||
|
||||
static void ProfileRegion(llvm::FoldingSetNodeID &ID,
|
||||
QualType T, const MemRegion *sReg);
|
||||
Expr const *E, const MemRegion *sReg);
|
||||
|
||||
public:
|
||||
QualType getValueType(ASTContext& C) const {
|
||||
return T;
|
||||
return Ex->getType();
|
||||
}
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) const;
|
||||
@ -824,6 +851,11 @@ public:
|
||||
const CompoundLiteralRegion*
|
||||
getCompoundLiteralRegion(const CompoundLiteralExpr* CL,
|
||||
const LocationContext *LC);
|
||||
|
||||
/// getCXXThisRegion - Retrieve the [artifical] region associated with the
|
||||
/// parameter 'this'.
|
||||
const CXXThisRegion *getCXXThisRegion(QualType thisPointerTy,
|
||||
const LocationContext *LC);
|
||||
|
||||
/// getSymbolicRegion - Retrieve or create a "symbolic" memory region.
|
||||
const SymbolicRegion* getSymbolicRegion(SymbolRef sym);
|
||||
@ -869,7 +901,8 @@ public:
|
||||
const ObjCIvarRegion *getObjCIvarRegion(const ObjCIvarDecl* ivd,
|
||||
const MemRegion* superRegion);
|
||||
|
||||
const CXXObjectRegion *getCXXObjectRegion(QualType T);
|
||||
const CXXObjectRegion *getCXXObjectRegion(Expr const *Ex,
|
||||
LocationContext const *LC);
|
||||
|
||||
const FunctionTextRegion *getFunctionTextRegion(const FunctionDecl *FD);
|
||||
const BlockTextRegion *getBlockTextRegion(const BlockDecl *BD,
|
||||
|
@ -28,8 +28,10 @@ class SValuator {
|
||||
protected:
|
||||
ValueManager &ValMgr;
|
||||
|
||||
public:
|
||||
// FIXME: Make these protected again one RegionStoreManager correctly
|
||||
// handles loads from differening bound value types.
|
||||
virtual SVal EvalCastNL(NonLoc val, QualType castTy) = 0;
|
||||
|
||||
virtual SVal EvalCastL(Loc val, QualType castTy) = 0;
|
||||
|
||||
public:
|
||||
|
@ -103,9 +103,6 @@ public:
|
||||
|
||||
virtual SVal getLValueElement(QualType elementType, SVal offset, SVal Base)=0;
|
||||
|
||||
// T - the object type.
|
||||
Loc getThisObject(QualType T);
|
||||
|
||||
// FIXME: Make out-of-line.
|
||||
virtual DefinedOrUnknownSVal getSizeInElements(const GRState *state,
|
||||
const MemRegion *region) {
|
||||
@ -192,7 +189,8 @@ protected:
|
||||
/// CastRetrievedVal - Used by subclasses of StoreManager to implement
|
||||
/// implicit casts that arise from loads from regions that are reinterpreted
|
||||
/// as another region.
|
||||
SVal CastRetrievedVal(SVal val, const TypedRegion *R, QualType castTy);
|
||||
SVal CastRetrievedVal(SVal val, const TypedRegion *R, QualType castTy,
|
||||
bool performTestOnly = true);
|
||||
};
|
||||
|
||||
// FIXME: Do we still need this?
|
||||
|
@ -781,6 +781,11 @@ public:
|
||||
/// formal arguments into the %0 slots. The result is appended onto the Str
|
||||
/// array.
|
||||
void FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const;
|
||||
|
||||
/// FormatDiagnostic - Format the given format-string into the
|
||||
/// output buffer using the arguments stored in this diagnostic.
|
||||
void FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
|
||||
llvm::SmallVectorImpl<char> &OutStr) const;
|
||||
};
|
||||
|
||||
/// DiagnosticClient - This is an abstract interface implemented by clients of
|
||||
|
@ -81,5 +81,7 @@ def warn_drv_clang_unsupported : Warning<
|
||||
"the clang compiler does not support '%0'">;
|
||||
def warn_drv_assuming_mfloat_abi_is : Warning<
|
||||
"unknown platform, assuming -mfloat-abi=%0">;
|
||||
def warn_ignoring_ftabstop_value : Warning<
|
||||
"ignoring invalid -ftabstop value '%0', using default value %1">;
|
||||
|
||||
}
|
||||
|
@ -84,6 +84,9 @@ def err_exponent_has_no_digits : Error<"exponent has no digits">;
|
||||
def ext_imaginary_constant : Extension<"imaginary constants are an extension">;
|
||||
def err_hexconstant_requires_exponent : Error<
|
||||
"hexadecimal floating constants require an exponent">;
|
||||
def ext_hexconstant_cplusplus : ExtWarn<
|
||||
"hexadecimal floating constants are a C99 feature that is incompatible with "
|
||||
"C++0x">;
|
||||
def ext_hexconstant_invalid : Extension<
|
||||
"hexadecimal floating constants are a C99 feature">;
|
||||
def ext_binary_literal : Extension<
|
||||
@ -169,6 +172,9 @@ def err_pp_hash_error : Error<"#error%0">;
|
||||
def err_pp_file_not_found : Error<"'%0' file not found">, DefaultFatal;
|
||||
def err_pp_error_opening_file : Error<
|
||||
"error opening file '%0': %1">, DefaultFatal;
|
||||
def warn_pp_relative_include_from_framework : Warning<
|
||||
"published framework headers should always #import headers within the "
|
||||
"framework with framework paths">, InGroup<DiagGroup<"framework-headers">>;
|
||||
def err_pp_empty_filename : Error<"empty filename">;
|
||||
def err_pp_include_too_deep : Error<"#include nested too deeply">;
|
||||
def err_pp_expects_filename : Error<"expected \"FILENAME\" or <FILENAME>">;
|
||||
|
@ -261,6 +261,8 @@ def err_attributes_not_allowed : Error<"an attribute list cannot appear here">;
|
||||
|
||||
/// C++ Templates
|
||||
def err_expected_template : Error<"expected template">;
|
||||
def err_unknown_template_name : Error<
|
||||
"unknown template name %0">;
|
||||
def err_expected_comma_greater : Error<
|
||||
"expected ',' or '>' in template-parameter-list">;
|
||||
def err_expected_type_id_after : Error<"expected type-id after '%0'">;
|
||||
@ -289,6 +291,16 @@ def err_explicit_instantiation_with_definition : Error<
|
||||
"definition is meant to be an explicit specialization, add '<>' after the "
|
||||
"'template' keyword">;
|
||||
|
||||
// Constructor template diagnostics.
|
||||
def err_out_of_line_constructor_template_id : Error<
|
||||
"out-of-line constructor for %0 cannot have template arguments">;
|
||||
def err_out_of_line_template_id_names_constructor : Error<
|
||||
"qualified reference to %0 is a constructor name rather than a "
|
||||
"template name wherever a constructor can be declared">;
|
||||
def err_out_of_line_type_names_constructor : Error<
|
||||
"qualified reference to %0 is a constructor name rather than a "
|
||||
"type wherever a constructor can be declared">;
|
||||
|
||||
def err_expected_qualified_after_typename : Error<
|
||||
"expected a qualified name after 'typename'">;
|
||||
def err_typename_refers_to_non_type_template : Error<
|
||||
|
@ -89,7 +89,7 @@ def warn_decl_in_param_list : Warning<
|
||||
def warn_implicit_function_decl : Warning<
|
||||
"implicit declaration of function %0">,
|
||||
InGroup<ImplicitFunctionDeclare>, DefaultIgnore;
|
||||
def ext_implicit_function_decl : Extension<
|
||||
def ext_implicit_function_decl : ExtWarn<
|
||||
"implicit declaration of function %0 is invalid in C99">,
|
||||
InGroup<ImplicitFunctionDeclare>;
|
||||
|
||||
@ -160,6 +160,8 @@ def warn_suggest_noreturn_function : Warning<
|
||||
def warn_suggest_noreturn_block : Warning<
|
||||
"block could be attribute 'noreturn'">,
|
||||
InGroup<DiagGroup<"missing-noreturn">>, DefaultIgnore;
|
||||
def warn_unreachable : Warning<"will never be executed">,
|
||||
InGroup<DiagGroup<"unreachable-code">>, DefaultIgnore;
|
||||
|
||||
/// Built-in functions.
|
||||
def ext_implicit_lib_function_decl : ExtWarn<
|
||||
@ -683,6 +685,8 @@ def err_attribute_not_string : Error<
|
||||
"argument to %0 attribute was not a string literal">;
|
||||
def err_attribute_section_invalid_for_target : Error<
|
||||
"argument to 'section' attribute is not valid for this target: %0">;
|
||||
def err_attribute_section_local_variable : Error<
|
||||
"'section' attribute is not valid on local variables">;
|
||||
def err_attribute_aligned_not_power_of_two : Error<
|
||||
"requested alignment is not a power of 2">;
|
||||
def warn_redeclaration_without_attribute_prev_attribute_ignored : Warning<
|
||||
@ -895,18 +899,61 @@ def err_ovl_ambiguous_member_call : Error<
|
||||
"call to member function %0 is ambiguous">;
|
||||
def err_ovl_deleted_member_call : Error<
|
||||
"call to %select{unavailable|deleted}0 member function %1">;
|
||||
def err_ovl_candidate : Note<"candidate function">;
|
||||
def err_ovl_candidate_not_viable : Note<"function not viable because"
|
||||
" of ambiguity in conversion of argument %0">;
|
||||
def note_ovl_candidate : Note<"candidate "
|
||||
"%select{function|function|constructor|"
|
||||
"function |function |constructor |"
|
||||
"is the implicit default constructor|"
|
||||
"is the implicit copy constructor|"
|
||||
"is the implicit copy assignment operator}0%1">;
|
||||
// Note that we don't treat templates differently for this diagnostic.
|
||||
def note_ovl_candidate_arity : Note<"candidate "
|
||||
"%select{function|function|constructor|function|function|constructor|"
|
||||
"constructor (the implicit default constructor)|"
|
||||
"constructor (the implicit copy constructor)|"
|
||||
"function (the implicit copy assignment operator)}0 not viable: requires"
|
||||
"%select{ at least| at most|}2 %3 argument%s3, but %4 %plural{1:was|:were}4 "
|
||||
"provided">;
|
||||
def note_ovl_candidate_deleted : Note<
|
||||
"candidate %select{function|function|constructor|"
|
||||
"function |function |constructor |||}0%1 "
|
||||
"has been explicitly %select{made unavailable|deleted}2">;
|
||||
def note_ovl_candidate_bad_conv : Note<"candidate "
|
||||
"%select{function|function|constructor|"
|
||||
"function |function |constructor |"
|
||||
"constructor (the implicit default constructor)|"
|
||||
"constructor (the implicit copy constructor)|"
|
||||
"function (the implicit copy assignment operator)}0%1"
|
||||
" not viable: no known conversion from %2 to %3 for "
|
||||
"%select{%ordinal5 argument|object argument}4">;
|
||||
def note_ovl_candidate_bad_addrspace : Note<"candidate "
|
||||
"%select{function|function|constructor|"
|
||||
"function |function |constructor |"
|
||||
"constructor (the implicit default constructor)|"
|
||||
"constructor (the implicit copy constructor)|"
|
||||
"function (the implicit copy assignment operator)}0%1 not viable: "
|
||||
"%select{%ordinal6|'this'}5 argument (%2) is in "
|
||||
"address space %3, but parameter must be in address space %4">;
|
||||
def note_ovl_candidate_bad_cvr_this : Note<"candidate "
|
||||
"%select{|function|||function||||"
|
||||
"function (the implicit copy assignment operator)}0 not viable: "
|
||||
"'this' argument has type %2, but method is not marked "
|
||||
"%select{const|volatile|const or volatile|restrict|const or restrict|"
|
||||
"volatile or restrict|const, volatile, or restrict}3">;
|
||||
def note_ovl_candidate_bad_cvr : Note<"candidate "
|
||||
"%select{function|function|constructor|"
|
||||
"function |function |constructor |"
|
||||
"constructor (the implicit default constructor)|"
|
||||
"constructor (the implicit copy constructor)|"
|
||||
"function (the implicit copy assignment operator)}0%1 not viable: "
|
||||
"%ordinal4 argument (%2) would lose "
|
||||
"%select{const|volatile|const and volatile|restrict|const and restrict|"
|
||||
"volatile and restrict|const, volatile, and restrict}3 qualifier"
|
||||
"%select{||s||s|s|s}3">;
|
||||
def note_ambiguous_type_conversion: Note<
|
||||
"because of ambiguity in conversion of %0 to %1">;
|
||||
def err_ovl_template_candidate : Note<
|
||||
"candidate function template specialization %0">;
|
||||
def err_ovl_candidate_deleted : Note<
|
||||
"candidate function has been explicitly %select{made unavailable|deleted}0">;
|
||||
def err_ovl_builtin_binary_candidate : Note<
|
||||
def note_ovl_builtin_binary_candidate : Note<
|
||||
"built-in candidate %0">;
|
||||
def err_ovl_builtin_unary_candidate : Note<
|
||||
def note_ovl_builtin_unary_candidate : Note<
|
||||
"built-in candidate %0">;
|
||||
def err_ovl_no_viable_function_in_init : Error<
|
||||
"no matching constructor for initialization of %0">;
|
||||
@ -920,6 +967,10 @@ def err_ovl_ambiguous_oper : Error<
|
||||
def err_ovl_no_viable_oper : Error<"no viable overloaded '%0'">;
|
||||
def err_ovl_deleted_oper : Error<
|
||||
"overload resolution selected %select{unavailable|deleted}0 operator '%1'">;
|
||||
def err_ovl_no_viable_subscript :
|
||||
Error<"no viable overloaded operator[] for type %0">;
|
||||
def err_ovl_no_oper :
|
||||
Error<"type %0 does not provide a %select{subscript|call}1 operator">;
|
||||
|
||||
def err_ovl_no_viable_object_call : Error<
|
||||
"no matching function for call to object of type %0">;
|
||||
@ -927,7 +978,7 @@ def err_ovl_ambiguous_object_call : Error<
|
||||
"call to object of type %0 is ambiguous">;
|
||||
def err_ovl_deleted_object_call : Error<
|
||||
"call to %select{unavailable|deleted}0 function call operator in type %1">;
|
||||
def err_ovl_surrogate_cand : Note<"conversion candidate of type %0">;
|
||||
def note_ovl_surrogate_cand : Note<"conversion candidate of type %0">;
|
||||
def err_member_call_without_object : Error<
|
||||
"call to non-static member function without an object argument">;
|
||||
|
||||
@ -1295,6 +1346,8 @@ def err_template_kw_refers_to_class_template : Error<
|
||||
"'%0%1' instantiated to a class template, not a function template">;
|
||||
def note_referenced_class_template : Error<
|
||||
"class template declared here">;
|
||||
def err_template_kw_missing : Error<
|
||||
"missing 'template' keyword prior to dependent template name '%0%1'">;
|
||||
|
||||
// C++0x Variadic Templates
|
||||
def err_template_param_pack_default_arg : Error<
|
||||
@ -1472,7 +1525,7 @@ def note_protected_by___block : Note<
|
||||
"jump bypasses setup of __block variable">;
|
||||
|
||||
def err_func_returning_array_function : Error<
|
||||
"function cannot return array or function type %0">;
|
||||
"function cannot return %select{array|function}0 type %1">;
|
||||
def err_field_declared_as_function : Error<"field %0 declared as a function">;
|
||||
def err_field_incomplete : Error<"field has incomplete type %0">;
|
||||
def ext_variable_sized_type_in_struct : ExtWarn<
|
||||
@ -1543,15 +1596,17 @@ def warn_floatingpoint_eq : Warning<
|
||||
"comparing floating point with == or != is unsafe">,
|
||||
InGroup<DiagGroup<"float-equal">>, DefaultIgnore;
|
||||
|
||||
def warn_shift_negative : Warning<
|
||||
"shift count is negative">;
|
||||
def warn_shift_gt_typewidth : Warning<
|
||||
"shift count >= width of type">;
|
||||
def warn_division_by_zero : Warning<"division by zero is undefined">;
|
||||
def warn_remainder_by_zero : Warning<"remainder by zero is undefined">;
|
||||
def warn_shift_negative : Warning<"shift count is negative">;
|
||||
def warn_shift_gt_typewidth : Warning<"shift count >= width of type">;
|
||||
|
||||
def warn_precedence_bitwise_rel : Warning<
|
||||
"%0 has lower precedence than %1; %1 will be evaluated first">,
|
||||
InGroup<Parentheses>;
|
||||
|
||||
def note_precedence_bitwise_first : Note<
|
||||
"place parentheses around the %0 expression to evaluate it first">;
|
||||
|
||||
def err_sizeof_nonfragile_interface : Error<
|
||||
"invalid application of '%select{alignof|sizeof}1' to interface %0 in "
|
||||
"non-fragile ABI">;
|
||||
@ -1647,6 +1702,8 @@ def err_static_block_func : Error<
|
||||
def err_typecheck_address_of : Error<"address of %0 requested">;
|
||||
def ext_typecheck_addrof_void : Extension<
|
||||
"ISO C forbids taking the address of an expression of type 'void'">;
|
||||
def err_unqualified_pointer_member_function : Error<
|
||||
"must explicitly qualify member function %0 when taking its address">;
|
||||
def err_typecheck_invalid_lvalue_addrof : Error<
|
||||
"address expression must be an lvalue or a function designator">;
|
||||
def err_typecheck_unary_expr : Error<
|
||||
@ -1721,6 +1778,10 @@ def warn_printf_nonliteral : Warning<
|
||||
def err_unexpected_interface : Error<
|
||||
"unexpected interface name %0: expected expression">;
|
||||
def err_ref_non_value : Error<"%0 does not refer to a value">;
|
||||
def err_ref_vm_type : Error<
|
||||
"cannot refer to declaration with a variably modified type inside block">;
|
||||
def err_ref_array_type : Error<
|
||||
"cannot refer to declaration with an array type inside block">;
|
||||
def err_property_not_found : Error<
|
||||
"property %0 not found on object of type %1">;
|
||||
def err_duplicate_property : Error<
|
||||
@ -1952,6 +2013,8 @@ def warn_condition_is_assignment : Warning<"using the result of an "
|
||||
def warn_condition_is_idiomatic_assignment : Warning<"using the result "
|
||||
"of an assignment as a condition without parentheses">,
|
||||
InGroup<DiagGroup<"idiomatic-parentheses">>, DefaultIgnore;
|
||||
def note_condition_assign_to_comparison : Note<
|
||||
"use '==' to turn this assignment into an equality comparison">;
|
||||
|
||||
def warn_value_always_zero : Warning<
|
||||
"%0 is always %select{zero|false|NULL}1 in this context">;
|
||||
@ -2303,6 +2366,13 @@ def err_operator_delete_dependent_param_type : Error<
|
||||
def err_operator_delete_param_type : Error<
|
||||
"%0 takes type %1 as first parameter">;
|
||||
|
||||
// C++ literal operators
|
||||
def err_literal_operator_outside_namespace : Error<
|
||||
"literal operator %0 must be in a namespace or global scope">;
|
||||
// FIXME: This diagnostic sucks
|
||||
def err_literal_operator_params : Error<
|
||||
"parameter declaration for literal operator %0 is not valid">;
|
||||
|
||||
// C++ conversion functions
|
||||
def err_conv_function_not_member : Error<
|
||||
"conversion function must be a non-static member function">;
|
||||
@ -2569,7 +2639,21 @@ def err_mem_init_not_member_or_class_suggest : Error<
|
||||
def err_field_designator_unknown_suggest : Error<
|
||||
"field designator %0 does not refer to any field in type %1; did you mean "
|
||||
"%2?">;
|
||||
|
||||
def err_typecheck_member_reference_ivar_suggest : Error<
|
||||
"%0 does not have a member named %1; did you mean %2?">;
|
||||
def err_property_not_found_suggest : Error<
|
||||
"property %0 not found on object of type %1; did you mean %2?">;
|
||||
def err_undef_interface_suggest : Error<
|
||||
"cannot find interface declaration for %0; did you mean %1?">;
|
||||
def warn_undef_interface_suggest : Warning<
|
||||
"cannot find interface declaration for %0; did you mean %1?">;
|
||||
def err_undef_superclass_suggest : Error<
|
||||
"cannot find interface declaration for %0, superclass of %1; did you mean "
|
||||
"%2?">;
|
||||
def err_undeclared_protocol_suggest : Error<
|
||||
"cannot find protocol declaration for %0; did you mean %1?">;
|
||||
def note_base_class_specified_here : Note<
|
||||
"base class %0 specified here">;
|
||||
}
|
||||
|
||||
|
||||
|
@ -26,7 +26,8 @@ class DeclarationName;
|
||||
|
||||
class PartialDiagnostic {
|
||||
struct Storage {
|
||||
Storage() : NumDiagArgs(0), NumDiagRanges(0) { }
|
||||
Storage() : NumDiagArgs(0), NumDiagRanges(0), NumCodeModificationHints(0) {
|
||||
}
|
||||
|
||||
enum {
|
||||
/// MaxArguments - The maximum number of arguments we can hold. We
|
||||
@ -42,6 +43,10 @@ class PartialDiagnostic {
|
||||
/// NumDiagRanges - This is the number of ranges in the DiagRanges array.
|
||||
unsigned char NumDiagRanges;
|
||||
|
||||
/// \brief The number of code modifications hints in the
|
||||
/// CodeModificationHints array.
|
||||
unsigned char NumCodeModificationHints;
|
||||
|
||||
/// DiagArgumentsKind - This is an array of ArgumentKind::ArgumentKind enum
|
||||
/// values, with one for each argument. This specifies whether the argument
|
||||
/// is in DiagArgumentsStr or in DiagArguments.
|
||||
@ -56,6 +61,12 @@ class PartialDiagnostic {
|
||||
/// DiagRanges - The list of ranges added to this diagnostic. It currently
|
||||
/// only support 10 ranges, could easily be extended if needed.
|
||||
SourceRange DiagRanges[10];
|
||||
|
||||
enum { MaxCodeModificationHints = 3 };
|
||||
|
||||
/// CodeModificationHints - If valid, provides a hint with some code
|
||||
/// to insert, remove, or modify at a particular position.
|
||||
CodeModificationHint CodeModificationHints[MaxCodeModificationHints];
|
||||
};
|
||||
|
||||
/// DiagID - The diagnostic ID.
|
||||
@ -84,6 +95,20 @@ class PartialDiagnostic {
|
||||
DiagStorage->DiagRanges[DiagStorage->NumDiagRanges++] = R;
|
||||
}
|
||||
|
||||
void AddCodeModificationHint(const CodeModificationHint &Hint) const {
|
||||
if (Hint.isNull())
|
||||
return;
|
||||
|
||||
if (!DiagStorage)
|
||||
DiagStorage = new Storage;
|
||||
|
||||
assert(DiagStorage->NumCodeModificationHints <
|
||||
Storage::MaxCodeModificationHints &&
|
||||
"Too many code modification hints!");
|
||||
DiagStorage->CodeModificationHints[DiagStorage->NumCodeModificationHints++]
|
||||
= Hint;
|
||||
}
|
||||
|
||||
public:
|
||||
PartialDiagnostic(unsigned DiagID)
|
||||
: DiagID(DiagID), DiagStorage(0) { }
|
||||
@ -130,6 +155,10 @@ public:
|
||||
// Add all ranges.
|
||||
for (unsigned i = 0, e = DiagStorage->NumDiagRanges; i != e; ++i)
|
||||
DB.AddSourceRange(DiagStorage->DiagRanges[i]);
|
||||
|
||||
// Add all code modification hints
|
||||
for (unsigned i = 0, e = DiagStorage->NumCodeModificationHints; i != e; ++i)
|
||||
DB.AddCodeModificationHint(DiagStorage->CodeModificationHints[i]);
|
||||
}
|
||||
|
||||
friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
|
||||
@ -165,6 +194,13 @@ public:
|
||||
|
||||
friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
|
||||
DeclarationName N);
|
||||
|
||||
friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
|
||||
const CodeModificationHint &Hint) {
|
||||
PD.AddCodeModificationHint(Hint);
|
||||
return PD;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
inline PartialDiagnostic PDiag(unsigned DiagID = 0) {
|
||||
|
@ -162,6 +162,7 @@ public:
|
||||
void setEnd(SourceLocation e) { E = e; }
|
||||
|
||||
bool isValid() const { return B.isValid() && E.isValid(); }
|
||||
bool isInvalid() const { return !isValid(); }
|
||||
|
||||
bool operator==(const SourceRange &X) const {
|
||||
return B == X.B && E == X.E;
|
||||
|
@ -30,6 +30,7 @@ class StringRef;
|
||||
namespace clang {
|
||||
class Diagnostic;
|
||||
class LangOptions;
|
||||
class MacroBuilder;
|
||||
class SourceLocation;
|
||||
class SourceManager;
|
||||
class TargetOptions;
|
||||
@ -209,7 +210,7 @@ public:
|
||||
/// getTargetDefines - Appends the target-specific #define values for this
|
||||
/// target set to the specified buffer.
|
||||
virtual void getTargetDefines(const LangOptions &Opts,
|
||||
std::vector<char> &DefineBuffer) const = 0;
|
||||
MacroBuilder &Builder) const = 0;
|
||||
|
||||
|
||||
/// getTargetBuiltins - Return information about target-specific builtins for
|
||||
|
@ -178,6 +178,8 @@ def fdiagnostics_print_source_range_info : Flag<"-fdiagnostics-print-source-rang
|
||||
HelpText<"Print source range spans in numeric form">;
|
||||
def fdiagnostics_show_option : Flag<"-fdiagnostics-show-option">,
|
||||
HelpText<"Print diagnostic name with mappable diagnostics">;
|
||||
def ftabstop : Separate<"-ftabstop">, MetaVarName<"<N>">,
|
||||
HelpText<"Set the tab stop distance.">;
|
||||
def fmessage_length : Separate<"-fmessage-length">, MetaVarName<"<N>">,
|
||||
HelpText<"Format message diagnostics so that they fit within N columns or fewer, when possible.">;
|
||||
def fcolor_diagnostics : Flag<"-fcolor-diagnostics">,
|
||||
@ -323,6 +325,8 @@ def fgnu_runtime : Flag<"-fgnu-runtime">,
|
||||
HelpText<"Generate output compatible with the standard GNU Objective-C runtime">;
|
||||
def std_EQ : Joined<"-std=">,
|
||||
HelpText<"Language standard to compile for">;
|
||||
def fmath_errno : Flag<"-fmath-errno">,
|
||||
HelpText<"Require math functions to indicate errors by setting errno">;
|
||||
def fms_extensions : Flag<"-fms-extensions">,
|
||||
HelpText<"Accept some non-standard constructs used in Microsoft header files ">;
|
||||
def main_file_name : Separate<"-main-file-name">,
|
||||
@ -331,8 +335,6 @@ def fno_elide_constructors : Flag<"-fno-elide-constructors">,
|
||||
HelpText<"Disable C++ copy constructor elision">;
|
||||
def fno_lax_vector_conversions : Flag<"-fno-lax-vector-conversions">,
|
||||
HelpText<"Disallow implicit conversions between vectors with a different number of elements or different element types">;
|
||||
def fno_math_errno : Flag<"-fno-math-errno">,
|
||||
HelpText<"Don't require math functions to respect errno">;
|
||||
def fno_signed_char : Flag<"-fno-signed-char">,
|
||||
HelpText<"Char is unsigned">;
|
||||
def fno_operator_names : Flag<"-fno-operator-names">,
|
||||
|
@ -345,6 +345,7 @@ def fstack_protector_all : Flag<"-fstack-protector-all">, Group<f_Group>;
|
||||
def fstack_protector : Flag<"-fstack-protector">, Group<f_Group>;
|
||||
def fstrict_aliasing : Flag<"-fstrict-aliasing">, Group<clang_ignored_f_Group>;
|
||||
def fsyntax_only : Flag<"-fsyntax-only">, Flags<[DriverOption]>;
|
||||
def ftabstop_EQ : Joined<"-ftabstop=">, Group<f_Group>;
|
||||
def ftemplate_depth_ : Joined<"-ftemplate-depth-">, Group<f_Group>;
|
||||
def fterminated_vtables : Flag<"-fterminated-vtables">, Group<f_Group>;
|
||||
def ftime_report : Flag<"-ftime-report">, Group<f_Group>;
|
||||
|
@ -87,10 +87,6 @@ public:
|
||||
|
||||
// Platform defaults information
|
||||
|
||||
/// IsMathErrnoDefault - Does this tool chain set -fmath-errno by
|
||||
/// default.
|
||||
virtual bool IsMathErrnoDefault() const = 0;
|
||||
|
||||
/// IsBlocksDefault - Does this tool chain enable -fblocks by default.
|
||||
virtual bool IsBlocksDefault() const { return false; }
|
||||
|
||||
|
@ -41,6 +41,7 @@
|
||||
// C family source language (with and without preprocessing).
|
||||
TYPE("cpp-output", PP_C, INVALID, "i", "u")
|
||||
TYPE("c", C, PP_C, 0, "u")
|
||||
TYPE("cl", CL, PP_C, 0, "u")
|
||||
TYPE("objective-c-cpp-output", PP_ObjC, INVALID, "mi", "u")
|
||||
TYPE("objective-c", ObjC, PP_ObjC, 0, "u")
|
||||
TYPE("c++-cpp-output", PP_CXX, INVALID, "ii", "u")
|
||||
|
@ -32,6 +32,7 @@ class Diagnostic;
|
||||
class DiagnosticClient;
|
||||
class ExternalASTSource;
|
||||
class FileManager;
|
||||
class FrontendAction;
|
||||
class Preprocessor;
|
||||
class Source;
|
||||
class SourceManager;
|
||||
@ -103,6 +104,42 @@ public:
|
||||
bool _OwnsLLVMContext = true);
|
||||
~CompilerInstance();
|
||||
|
||||
/// @name High-Level Operations
|
||||
/// {
|
||||
|
||||
/// ExecuteAction - Execute the provided action against the compiler's
|
||||
/// CompilerInvocation object.
|
||||
///
|
||||
/// This function makes the following assumptions:
|
||||
///
|
||||
/// - The invocation options should be initialized. This function does not
|
||||
/// handle the '-help' or '-version' options, clients should handle those
|
||||
/// directly.
|
||||
///
|
||||
/// - The diagnostics engine should have already been created by the client.
|
||||
///
|
||||
/// - No other CompilerInstance state should have been initialized (this is
|
||||
/// an unchecked error).
|
||||
///
|
||||
/// - Clients should have initialized any LLVM target features that may be
|
||||
/// required.
|
||||
///
|
||||
/// - Clients should eventually call llvm_shutdown() upon the completion of
|
||||
/// this routine to ensure that any managed objects are properly destroyed.
|
||||
///
|
||||
/// Note that this routine may write output to 'stderr'.
|
||||
///
|
||||
/// \param Act - The action to execute.
|
||||
/// \return - True on success.
|
||||
//
|
||||
// FIXME: This function should take the stream to write any debugging /
|
||||
// verbose output to as an argument.
|
||||
//
|
||||
// FIXME: Eliminate the llvm_shutdown requirement, that should either be part
|
||||
// of the context or else not CompilerInstance specific.
|
||||
bool ExecuteAction(FrontendAction &Act);
|
||||
|
||||
/// }
|
||||
/// @name LLVM Context
|
||||
/// {
|
||||
|
||||
@ -451,6 +488,7 @@ public:
|
||||
const HeaderSearchOptions &,
|
||||
const DependencyOutputOptions &,
|
||||
const TargetInfo &,
|
||||
const FrontendOptions &,
|
||||
SourceManager &, FileManager &);
|
||||
|
||||
/// Create the AST context.
|
||||
|
@ -35,6 +35,10 @@ public:
|
||||
/// diagnostics, indicated by markers in the
|
||||
/// input source file.
|
||||
|
||||
/// The distance between tab stops.
|
||||
unsigned TabStop;
|
||||
enum { DefaultTabStop = 8, MaxTabStop = 100 };
|
||||
|
||||
/// Column limit for formatting message diagnostics, or 0 if unused.
|
||||
unsigned MessageLength;
|
||||
|
||||
@ -49,6 +53,7 @@ public:
|
||||
public:
|
||||
DiagnosticOptions() {
|
||||
IgnoreWarnings = 0;
|
||||
TabStop = DefaultTabStop;
|
||||
MessageLength = 0;
|
||||
NoRewriteMacros = 0;
|
||||
Pedantic = 0;
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "clang/AST/DeclObjC.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/AST/TemplateBase.h"
|
||||
#include "clang/Lex/ExternalPreprocessorSource.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "clang/Basic/IdentifierTable.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
@ -146,7 +147,8 @@ public:
|
||||
/// required when traversing the AST. Only those AST nodes that are
|
||||
/// actually required will be de-serialized.
|
||||
class PCHReader
|
||||
: public ExternalSemaSource,
|
||||
: public ExternalPreprocessorSource,
|
||||
public ExternalSemaSource,
|
||||
public IdentifierInfoLookup,
|
||||
public ExternalIdentifierLookup,
|
||||
public ExternalSLocEntrySource {
|
||||
@ -183,6 +185,10 @@ private:
|
||||
llvm::BitstreamReader StreamFile;
|
||||
llvm::BitstreamCursor Stream;
|
||||
|
||||
/// \brief The cursor to the start of the preprocessor block, which stores
|
||||
/// all of the macro definitions.
|
||||
llvm::BitstreamCursor MacroCursor;
|
||||
|
||||
/// DeclsCursor - This is a cursor to the start of the DECLS_BLOCK block. It
|
||||
/// has read all the abbreviations at the start of the block and is ready to
|
||||
/// jump around with these in context.
|
||||
@ -634,8 +640,7 @@ public:
|
||||
/// This routine builds a new IdentifierInfo for the given identifier. If any
|
||||
/// declarations with this name are visible from translation unit scope, their
|
||||
/// declarations will be deserialized and introduced into the declaration
|
||||
/// chain of the identifier. FIXME: if this identifier names a macro,
|
||||
/// deserialize the macro.
|
||||
/// chain of the identifier.
|
||||
virtual IdentifierInfo* get(const char *NameStart, const char *NameEnd);
|
||||
IdentifierInfo* get(llvm::StringRef Name) {
|
||||
return get(Name.begin(), Name.end());
|
||||
@ -712,6 +717,9 @@ public:
|
||||
/// \brief Reads the macro record located at the given offset.
|
||||
void ReadMacroRecord(uint64_t Offset);
|
||||
|
||||
/// \brief Read the set of macros defined by this external macro source.
|
||||
virtual void ReadDefinedMacros();
|
||||
|
||||
/// \brief Retrieve the AST context that this PCH reader
|
||||
/// supplements.
|
||||
ASTContext *getContext() { return Context; }
|
||||
|
@ -15,13 +15,11 @@
|
||||
#define LLVM_CLANG_FRONTEND_UTILS_H
|
||||
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "llvm/ADT/Twine.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
namespace llvm {
|
||||
class Triple;
|
||||
class raw_ostream;
|
||||
class raw_fd_ostream;
|
||||
}
|
||||
|
||||
namespace clang {
|
||||
@ -41,6 +39,29 @@ class PreprocessorOutputOptions;
|
||||
class SourceManager;
|
||||
class Stmt;
|
||||
class TargetInfo;
|
||||
class FrontendOptions;
|
||||
|
||||
class MacroBuilder {
|
||||
llvm::raw_ostream &Out;
|
||||
public:
|
||||
MacroBuilder(llvm::raw_ostream &Output) : Out(Output) {}
|
||||
|
||||
/// Append a #define line for macro of the form "#define Name Value\n".
|
||||
void defineMacro(const llvm::Twine &Name, const llvm::Twine &Value = "1") {
|
||||
Out << "#define " << Name << ' ' << Value << '\n';
|
||||
}
|
||||
|
||||
/// Append a #undef line for Name. Name should be of the form XXX
|
||||
/// and we emit "#undef XXX".
|
||||
void undefineMacro(const llvm::Twine &Name) {
|
||||
Out << "#undef " << Name << '\n';
|
||||
}
|
||||
|
||||
/// Directly append Str and a newline to the underlying buffer.
|
||||
void append(const llvm::Twine &Str) {
|
||||
Out << Str << '\n';
|
||||
}
|
||||
};
|
||||
|
||||
/// Normalize \arg File for use in a user defined #include directive (in the
|
||||
/// predefines buffer).
|
||||
@ -56,7 +77,8 @@ void ApplyHeaderSearchOptions(HeaderSearch &HS,
|
||||
/// environment ready to process a single file.
|
||||
void InitializePreprocessor(Preprocessor &PP,
|
||||
const PreprocessorOptions &PPOpts,
|
||||
const HeaderSearchOptions &HSOpts);
|
||||
const HeaderSearchOptions &HSOpts,
|
||||
const FrontendOptions &FEOpts);
|
||||
|
||||
/// ProcessWarningOptions - Initialize the diagnostic client and process the
|
||||
/// warning options specified on the command line.
|
||||
|
@ -16,6 +16,9 @@
|
||||
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
|
||||
namespace llvm {
|
||||
class StringRef;
|
||||
}
|
||||
namespace clang {
|
||||
class HeaderMap;
|
||||
class DirectoryEntry;
|
||||
@ -118,12 +121,10 @@ public:
|
||||
|
||||
/// LookupFile - Lookup the specified file in this search path, returning it
|
||||
/// if it exists or returning null if not.
|
||||
const FileEntry *LookupFile(const char *FilenameStart,
|
||||
const char *FilenameEnd, HeaderSearch &HS) const;
|
||||
const FileEntry *LookupFile(llvm::StringRef Filename, HeaderSearch &HS) const;
|
||||
|
||||
private:
|
||||
const FileEntry *DoFrameworkLookup(const char *FilenameStart,
|
||||
const char *FilenameEnd,
|
||||
const FileEntry *DoFrameworkLookup(llvm::StringRef Filename,
|
||||
HeaderSearch &HS) const;
|
||||
|
||||
};
|
||||
|
34
include/clang/Lex/ExternalPreprocessorSource.h
Normal file
34
include/clang/Lex/ExternalPreprocessorSource.h
Normal file
@ -0,0 +1,34 @@
|
||||
//===- ExternalPreprocessorSource.h - Abstract Macro Interface --*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the ExternalPreprocessorSource interface, which enables
|
||||
// construction of macro definitions from some external source.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef LLVM_CLANG_LEX_EXTERNAL_PREPROCESSOR_SOURCE_H
|
||||
#define LLVM_CLANG_LEX_EXTERNAL_PREPROCESSOR_SOURCE_H
|
||||
|
||||
namespace clang {
|
||||
|
||||
/// \brief Abstract interface for external sources of preprocessor
|
||||
/// information.
|
||||
///
|
||||
/// This abstract class allows an external sources (such as the \c PCHReader)
|
||||
/// to provide additional macro definitions.
|
||||
class ExternalPreprocessorSource {
|
||||
public:
|
||||
virtual ~ExternalPreprocessorSource();
|
||||
|
||||
/// \brief Read the set of macros defined by this external macro source.
|
||||
virtual void ReadDefinedMacros() = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // LLVM_CLANG_LEX_EXTERNAL_PREPROCESSOR_SOURCE_H
|
@ -16,6 +16,7 @@
|
||||
|
||||
namespace llvm {
|
||||
class MemoryBuffer;
|
||||
class StringRef;
|
||||
}
|
||||
namespace clang {
|
||||
class FileEntry;
|
||||
@ -46,8 +47,7 @@ public:
|
||||
|
||||
/// LookupFile - Check to see if the specified relative filename is located in
|
||||
/// this HeaderMap. If so, open it and return its FileEntry.
|
||||
const FileEntry *LookupFile(const char *FilenameStart,const char *FilenameEnd,
|
||||
FileManager &FM) const;
|
||||
const FileEntry *LookupFile(llvm::StringRef Filename, FileManager &FM) const;
|
||||
|
||||
/// getFileName - Return the filename of the headermap.
|
||||
const char *getFileName() const;
|
||||
|
@ -150,8 +150,7 @@ public:
|
||||
/// search location. This is used to implement #include_next. CurFileEnt, if
|
||||
/// non-null, indicates where the #including file is, in case a relative
|
||||
/// search is needed.
|
||||
const FileEntry *LookupFile(const char *FilenameStart,
|
||||
const char *FilenameEnd, bool isAngled,
|
||||
const FileEntry *LookupFile(llvm::StringRef Filename, bool isAngled,
|
||||
const DirectoryLookup *FromDir,
|
||||
const DirectoryLookup *&CurDir,
|
||||
const FileEntry *CurFileEnt);
|
||||
@ -161,16 +160,14 @@ public:
|
||||
/// within ".../Carbon.framework/Headers/Carbon.h", check to see if HIToolbox
|
||||
/// is a subframework within Carbon.framework. If so, return the FileEntry
|
||||
/// for the designated file, otherwise return null.
|
||||
const FileEntry *LookupSubframeworkHeader(const char *FilenameStart,
|
||||
const char *FilenameEnd,
|
||||
const FileEntry *LookupSubframeworkHeader(llvm::StringRef Filename,
|
||||
const FileEntry *RelativeFileEnt);
|
||||
|
||||
/// LookupFrameworkCache - Look up the specified framework name in our
|
||||
/// framework cache, returning the DirectoryEntry it is in if we know,
|
||||
/// otherwise, return null.
|
||||
const DirectoryEntry *&LookupFrameworkCache(const char *FWNameStart,
|
||||
const char *FWNameEnd) {
|
||||
return FrameworkMap.GetOrCreateValue(FWNameStart, FWNameEnd).getValue();
|
||||
const DirectoryEntry *&LookupFrameworkCache(llvm::StringRef FWName) {
|
||||
return FrameworkMap.GetOrCreateValue(FWName).getValue();
|
||||
}
|
||||
|
||||
/// ShouldEnterIncludeFile - Mark the specified file as a target of of a
|
||||
|
@ -32,6 +32,7 @@
|
||||
namespace clang {
|
||||
|
||||
class SourceManager;
|
||||
class ExternalPreprocessorSource;
|
||||
class FileManager;
|
||||
class FileEntry;
|
||||
class HeaderSearch;
|
||||
@ -42,7 +43,7 @@ class ScratchBuffer;
|
||||
class TargetInfo;
|
||||
class PPCallbacks;
|
||||
class DirectoryLookup;
|
||||
|
||||
|
||||
/// Preprocessor - This object engages in a tight little dance with the lexer to
|
||||
/// efficiently preprocess tokens. Lexers know only about tokens within a
|
||||
/// single source file, and don't know anything about preprocessor-level issues
|
||||
@ -57,6 +58,9 @@ class Preprocessor {
|
||||
ScratchBuffer *ScratchBuf;
|
||||
HeaderSearch &HeaderInfo;
|
||||
|
||||
/// \brief External source of macros.
|
||||
ExternalPreprocessorSource *ExternalSource;
|
||||
|
||||
/// PTH - An optional PTHManager object used for getting tokens from
|
||||
/// a token cache rather than lexing the original source file.
|
||||
llvm::OwningPtr<PTHManager> PTH;
|
||||
@ -99,6 +103,9 @@ class Preprocessor {
|
||||
/// DisableMacroExpansion - True if macro expansion is disabled.
|
||||
bool DisableMacroExpansion : 1;
|
||||
|
||||
/// \brief Whether we have already loaded macros from the external source.
|
||||
mutable bool ReadMacrosFromExternalSource : 1;
|
||||
|
||||
/// Identifiers - This is mapping/lookup information for all identifiers in
|
||||
/// the program, including program keywords.
|
||||
mutable IdentifierTable Identifiers;
|
||||
@ -247,6 +254,14 @@ public:
|
||||
|
||||
PTHManager *getPTHManager() { return PTH.get(); }
|
||||
|
||||
void setExternalSource(ExternalPreprocessorSource *Source) {
|
||||
ExternalSource = Source;
|
||||
}
|
||||
|
||||
ExternalPreprocessorSource *getExternalSource() const {
|
||||
return ExternalSource;
|
||||
}
|
||||
|
||||
/// SetCommentRetentionState - Control whether or not the preprocessor retains
|
||||
/// comments in output.
|
||||
void SetCommentRetentionState(bool KeepComments, bool KeepMacroComments) {
|
||||
@ -296,11 +311,9 @@ public:
|
||||
/// state of the macro table. This visits every currently-defined macro.
|
||||
typedef llvm::DenseMap<IdentifierInfo*,
|
||||
MacroInfo*>::const_iterator macro_iterator;
|
||||
macro_iterator macro_begin() const { return Macros.begin(); }
|
||||
macro_iterator macro_end() const { return Macros.end(); }
|
||||
|
||||
|
||||
|
||||
macro_iterator macro_begin(bool IncludeExternalMacros = true) const;
|
||||
macro_iterator macro_end(bool IncludeExternalMacros = true) const;
|
||||
|
||||
const std::string &getPredefines() const { return Predefines; }
|
||||
/// setPredefines - Set the predefines for this Preprocessor. These
|
||||
/// predefines are automatically injected when parsing the main file.
|
||||
@ -678,14 +691,14 @@ public:
|
||||
/// caller is expected to provide a buffer that is large enough to hold the
|
||||
/// spelling of the filename, but is also expected to handle the case when
|
||||
/// this method decides to use a different buffer.
|
||||
bool GetIncludeFilenameSpelling(SourceLocation Loc,
|
||||
const char *&BufStart, const char *&BufEnd);
|
||||
bool GetIncludeFilenameSpelling(SourceLocation Loc,llvm::StringRef &Filename);
|
||||
|
||||
/// LookupFile - Given a "foo" or <foo> reference, look up the indicated file,
|
||||
/// return null on failure. isAngled indicates whether the file reference is
|
||||
/// for system #include's or not (i.e. using <> instead of "").
|
||||
const FileEntry *LookupFile(const char *FilenameStart,const char *FilenameEnd,
|
||||
bool isAngled, const DirectoryLookup *FromDir,
|
||||
const FileEntry *LookupFile(llvm::StringRef Filename,
|
||||
SourceLocation FilenameTokLoc, bool isAngled,
|
||||
const DirectoryLookup *FromDir,
|
||||
const DirectoryLookup *&CurDir);
|
||||
|
||||
/// GetCurLookup - The DirectoryLookup structure used to find the current
|
||||
|
@ -291,6 +291,42 @@ public:
|
||||
bool EnteringContext,
|
||||
TemplateTy &Template) = 0;
|
||||
|
||||
/// \brief Action called as part of error recovery when the parser has
|
||||
/// determined that the given name must refer to a template, but
|
||||
/// \c isTemplateName() did not return a result.
|
||||
///
|
||||
/// This callback permits the action to give a detailed diagnostic when an
|
||||
/// unknown template name is encountered and, potentially, to try to recover
|
||||
/// by producing a new template in \p SuggestedTemplate.
|
||||
///
|
||||
/// \param II the name that should be a template.
|
||||
///
|
||||
/// \param IILoc the location of the name in the source.
|
||||
///
|
||||
/// \param S the scope in which name lookup was performed.
|
||||
///
|
||||
/// \param SS the C++ scope specifier that preceded the name.
|
||||
///
|
||||
/// \param SuggestedTemplate if the action sets this template to a non-NULL,
|
||||
/// template, the parser will recover by consuming the template name token
|
||||
/// and the template argument list that follows.
|
||||
///
|
||||
/// \param SuggestedTemplateKind as input, the kind of template that we
|
||||
/// expect (e.g., \c TNK_Type_template or \c TNK_Function_template). If the
|
||||
/// action provides a suggested template, this should be set to the kind of
|
||||
/// template.
|
||||
///
|
||||
/// \returns true if a diagnostic was emitted, false otherwise. When false,
|
||||
/// the parser itself will emit a generic "unknown template name" diagnostic.
|
||||
virtual bool DiagnoseUnknownTemplateName(const IdentifierInfo &II,
|
||||
SourceLocation IILoc,
|
||||
Scope *S,
|
||||
const CXXScopeSpec *SS,
|
||||
TemplateTy &SuggestedTemplate,
|
||||
TemplateNameKind &SuggestedKind) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// ActOnCXXGlobalScopeSpecifier - Return the object that represents the
|
||||
/// global scope ('::').
|
||||
virtual CXXScopeTy *ActOnCXXGlobalScopeSpecifier(Scope *S,
|
||||
@ -866,7 +902,8 @@ public:
|
||||
MultiExprArg Exprs,
|
||||
ExprArg AsmString,
|
||||
MultiExprArg Clobbers,
|
||||
SourceLocation RParenLoc) {
|
||||
SourceLocation RParenLoc,
|
||||
bool MSAsm = false) {
|
||||
return StmtEmpty();
|
||||
}
|
||||
|
||||
@ -2176,7 +2213,7 @@ public:
|
||||
// protocols, categories), the parser passes all methods/properties.
|
||||
// For class implementations, these values default to 0. For implementations,
|
||||
// methods are processed incrementally (by ActOnMethodDeclaration above).
|
||||
virtual void ActOnAtEnd(SourceLocation AtEndLoc,
|
||||
virtual void ActOnAtEnd(SourceRange AtEnd,
|
||||
DeclPtrTy classDecl,
|
||||
DeclPtrTy *allMethods = 0,
|
||||
unsigned allNum = 0,
|
||||
@ -2339,11 +2376,49 @@ public:
|
||||
/// \todo Code completion for attributes.
|
||||
//@{
|
||||
|
||||
/// \brief Describes the context in which code completion occurs.
|
||||
enum CodeCompletionContext {
|
||||
/// \brief Code completion occurs at top-level or namespace context.
|
||||
CCC_Namespace,
|
||||
/// \brief Code completion occurs within a class, struct, or union.
|
||||
CCC_Class,
|
||||
/// \brief Code completion occurs within an Objective-C interface, protocol,
|
||||
/// or category.
|
||||
CCC_ObjCInterface,
|
||||
/// \brief Code completion occurs within an Objective-C implementation or
|
||||
/// category implementation
|
||||
CCC_ObjCImplementation,
|
||||
/// \brief Code completion occurs within the list of instance variables
|
||||
/// in an Objective-C interface, protocol, category, or implementation.
|
||||
CCC_ObjCInstanceVariableList,
|
||||
/// \brief Code completion occurs following one or more template
|
||||
/// headers.
|
||||
CCC_Template,
|
||||
/// \brief Code completion occurs following one or more template
|
||||
/// headers within a class.
|
||||
CCC_MemberTemplate,
|
||||
/// \brief Code completion occurs within an expression.
|
||||
CCC_Expression,
|
||||
/// \brief Code completion occurs within a statement, which may
|
||||
/// also be an expression or a declaration.
|
||||
CCC_Statement,
|
||||
/// \brief Code completion occurs at the beginning of the
|
||||
/// initialization statement (or expression) in a for loop.
|
||||
CCC_ForInit,
|
||||
/// \brief Code completion ocurs within the condition of an if,
|
||||
/// while, switch, or for statement.
|
||||
CCC_Condition
|
||||
};
|
||||
|
||||
/// \brief Code completion for an ordinary name that occurs within the given
|
||||
/// scope.
|
||||
///
|
||||
/// \param S the scope in which the name occurs.
|
||||
virtual void CodeCompleteOrdinaryName(Scope *S) { }
|
||||
///
|
||||
/// \param CompletionContext the context in which code completion
|
||||
/// occurs.
|
||||
virtual void CodeCompleteOrdinaryName(Scope *S,
|
||||
CodeCompletionContext CompletionContext) { }
|
||||
|
||||
/// \brief Code completion for a member access expression.
|
||||
///
|
||||
@ -2458,6 +2533,9 @@ public:
|
||||
virtual void CodeCompleteObjCAtDirective(Scope *S, DeclPtrTy ObjCImpDecl,
|
||||
bool InInterface) { }
|
||||
|
||||
/// \brief Code completion after the '@' in the list of instance variables.
|
||||
virtual void CodeCompleteObjCAtVisibility(Scope *S) { }
|
||||
|
||||
/// \brief Code completion after the '@' in a statement.
|
||||
virtual void CodeCompleteObjCAtStatement(Scope *S) { }
|
||||
|
||||
|
@ -194,6 +194,7 @@ private:
|
||||
|
||||
SourceLocation StorageClassSpecLoc, SCS_threadLoc;
|
||||
SourceLocation TSWLoc, TSCLoc, TSSLoc, TSTLoc;
|
||||
SourceRange TypeofParensRange;
|
||||
SourceLocation TQ_constLoc, TQ_restrictLoc, TQ_volatileLoc;
|
||||
SourceLocation FS_inlineLoc, FS_virtualLoc, FS_explicitLoc;
|
||||
SourceLocation FriendLoc, ConstexprLoc;
|
||||
@ -257,6 +258,9 @@ public:
|
||||
SourceLocation getTypeSpecSignLoc() const { return TSSLoc; }
|
||||
SourceLocation getTypeSpecTypeLoc() const { return TSTLoc; }
|
||||
|
||||
SourceRange getTypeofParensRange() const { return TypeofParensRange; }
|
||||
void setTypeofParensRange(SourceRange range) { TypeofParensRange = range; }
|
||||
|
||||
/// getSpecifierName - Turn a type-specifier-type into a string like "_Bool"
|
||||
/// or "union".
|
||||
static const char *getSpecifierName(DeclSpec::TST T);
|
||||
@ -493,6 +497,8 @@ public:
|
||||
IK_LiteralOperatorId,
|
||||
/// \brief A constructor name.
|
||||
IK_ConstructorName,
|
||||
/// \brief A constructor named via a template-id.
|
||||
IK_ConstructorTemplateId,
|
||||
/// \brief A destructor name.
|
||||
IK_DestructorName,
|
||||
/// \brief A template-id, e.g., f<int>.
|
||||
@ -534,8 +540,9 @@ public:
|
||||
/// class-name.
|
||||
ActionBase::TypeTy *DestructorName;
|
||||
|
||||
/// \brief When Kind == IK_TemplateId, the template-id annotation that
|
||||
/// contains the template name and template arguments.
|
||||
/// \brief When Kind == IK_TemplateId or IK_ConstructorTemplateId,
|
||||
/// the template-id annotation that contains the template name and
|
||||
/// template arguments.
|
||||
TemplateIdAnnotation *TemplateId;
|
||||
};
|
||||
|
||||
@ -648,6 +655,14 @@ public:
|
||||
ConstructorName = ClassType;
|
||||
}
|
||||
|
||||
/// \brief Specify that this unqualified-id was parsed as a
|
||||
/// template-id that names a constructor.
|
||||
///
|
||||
/// \param TemplateId the template-id annotation that describes the parsed
|
||||
/// template-id. This UnqualifiedId instance will take ownership of the
|
||||
/// \p TemplateId and will free it on destruction.
|
||||
void setConstructorTemplateId(TemplateIdAnnotation *TemplateId);
|
||||
|
||||
/// \brief Specify that this unqualified-id was parsed as a destructor name.
|
||||
///
|
||||
/// \param TildeLoc the location of the '~' that introduces the destructor
|
||||
|
@ -784,7 +784,7 @@ private:
|
||||
llvm::SmallVector<DeclPtrTy, 4> PendingObjCImpDecl;
|
||||
|
||||
DeclPtrTy ParseObjCAtImplementationDeclaration(SourceLocation atLoc);
|
||||
DeclPtrTy ParseObjCAtEndDeclaration(SourceLocation atLoc);
|
||||
DeclPtrTy ParseObjCAtEndDeclaration(SourceRange atEnd);
|
||||
DeclPtrTy ParseObjCAtAliasDeclaration(SourceLocation atLoc);
|
||||
DeclPtrTy ParseObjCPropertySynthesize(SourceLocation atLoc);
|
||||
DeclPtrTy ParseObjCPropertyDynamic(SourceLocation atLoc);
|
||||
@ -1037,7 +1037,8 @@ private:
|
||||
/// would be best implemented in the parser.
|
||||
enum DeclSpecContext {
|
||||
DSC_normal, // normal context
|
||||
DSC_class // class context, enables 'friend'
|
||||
DSC_class, // class context, enables 'friend'
|
||||
DSC_top_level // top-level/namespace declaration context
|
||||
};
|
||||
|
||||
DeclGroupPtrTy ParseDeclaration(unsigned Context, SourceLocation &DeclEnd,
|
||||
@ -1056,6 +1057,7 @@ private:
|
||||
bool ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
|
||||
const ParsedTemplateInfo &TemplateInfo,
|
||||
AccessSpecifier AS);
|
||||
DeclSpecContext getDeclSpecContextFromDeclaratorContext(unsigned Context);
|
||||
void ParseDeclarationSpecifiers(DeclSpec &DS,
|
||||
const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(),
|
||||
AccessSpecifier AS = AS_none,
|
||||
@ -1109,6 +1111,11 @@ private:
|
||||
return isDeclarationSpecifier();
|
||||
}
|
||||
|
||||
/// \brief Starting with a scope specifier, identifier, or
|
||||
/// template-id that refers to the current class, determine whether
|
||||
/// this is a constructor declarator.
|
||||
bool isConstructorDeclarator();
|
||||
|
||||
/// \brief Specifies the context in which type-id/expression
|
||||
/// disambiguation will occur.
|
||||
enum TentativeCXXTypeIdContext {
|
||||
|
@ -146,13 +146,13 @@ public:
|
||||
/// are in the same file. If not, this returns -1.
|
||||
int getRangeSize(SourceRange Range) const;
|
||||
|
||||
/// getRewritenText - Return the rewritten form of the text in the specified
|
||||
/// getRewrittenText - Return the rewritten form of the text in the specified
|
||||
/// range. If the start or end of the range was unrewritable or if they are
|
||||
/// in different buffers, this returns an empty string.
|
||||
///
|
||||
/// Note that this method is not particularly efficient.
|
||||
///
|
||||
std::string getRewritenText(SourceRange Range) const;
|
||||
std::string getRewrittenText(SourceRange Range) const;
|
||||
|
||||
/// InsertText - Insert the specified string at the specified location in the
|
||||
/// original buffer. This method returns true (and does nothing) if the input
|
||||
|
@ -85,7 +85,18 @@ public:
|
||||
/// \brief A right angle bracket ('>').
|
||||
CK_RightAngle,
|
||||
/// \brief A comma separator (',').
|
||||
CK_Comma
|
||||
CK_Comma,
|
||||
/// \brief A colon (':').
|
||||
CK_Colon,
|
||||
/// \brief A semicolon (';').
|
||||
CK_SemiColon,
|
||||
/// \brief An '=' sign.
|
||||
CK_Equal,
|
||||
/// \brief Horizontal whitespace (' ').
|
||||
CK_HorizontalSpace,
|
||||
/// \brief Verticle whitespace ('\n' or '\r\n', depending on the
|
||||
/// platform).
|
||||
CK_VerticalSpace
|
||||
};
|
||||
|
||||
/// \brief One piece of the code completion string.
|
||||
@ -270,10 +281,6 @@ public:
|
||||
IdentifierInfo *Macro;
|
||||
};
|
||||
|
||||
/// \brief Describes how good this result is, with zero being the best
|
||||
/// result and progressively higher numbers representing poorer results.
|
||||
unsigned Rank;
|
||||
|
||||
/// \brief Specifiers which parameter (of a function, Objective-C method,
|
||||
/// macro, etc.) we should start with when formatting the result.
|
||||
unsigned StartParameter;
|
||||
@ -298,32 +305,32 @@ public:
|
||||
NestedNameSpecifier *Qualifier;
|
||||
|
||||
/// \brief Build a result that refers to a declaration.
|
||||
Result(NamedDecl *Declaration, unsigned Rank,
|
||||
Result(NamedDecl *Declaration,
|
||||
NestedNameSpecifier *Qualifier = 0,
|
||||
bool QualifierIsInformative = false)
|
||||
: Kind(RK_Declaration), Declaration(Declaration), Rank(Rank),
|
||||
: Kind(RK_Declaration), Declaration(Declaration),
|
||||
StartParameter(0), Hidden(false),
|
||||
QualifierIsInformative(QualifierIsInformative),
|
||||
StartsNestedNameSpecifier(false), AllParametersAreInformative(false),
|
||||
Qualifier(Qualifier) { }
|
||||
|
||||
/// \brief Build a result that refers to a keyword or symbol.
|
||||
Result(const char *Keyword, unsigned Rank)
|
||||
: Kind(RK_Keyword), Keyword(Keyword), Rank(Rank), StartParameter(0),
|
||||
Result(const char *Keyword)
|
||||
: Kind(RK_Keyword), Keyword(Keyword), StartParameter(0),
|
||||
Hidden(false), QualifierIsInformative(0),
|
||||
StartsNestedNameSpecifier(false), AllParametersAreInformative(false),
|
||||
Qualifier(0) { }
|
||||
|
||||
/// \brief Build a result that refers to a macro.
|
||||
Result(IdentifierInfo *Macro, unsigned Rank)
|
||||
: Kind(RK_Macro), Macro(Macro), Rank(Rank), StartParameter(0),
|
||||
Result(IdentifierInfo *Macro)
|
||||
: Kind(RK_Macro), Macro(Macro), StartParameter(0),
|
||||
Hidden(false), QualifierIsInformative(0),
|
||||
StartsNestedNameSpecifier(false), AllParametersAreInformative(false),
|
||||
Qualifier(0) { }
|
||||
|
||||
/// \brief Build a result that refers to a pattern.
|
||||
Result(CodeCompletionString *Pattern, unsigned Rank)
|
||||
: Kind(RK_Pattern), Pattern(Pattern), Rank(Rank), StartParameter(0),
|
||||
Result(CodeCompletionString *Pattern)
|
||||
: Kind(RK_Pattern), Pattern(Pattern), StartParameter(0),
|
||||
Hidden(false), QualifierIsInformative(0),
|
||||
StartsNestedNameSpecifier(false), AllParametersAreInformative(false),
|
||||
Qualifier(0) { }
|
||||
|
@ -12,9 +12,20 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/AST/APValue.h"
|
||||
#include "clang/AST/CharUnits.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
using namespace clang;
|
||||
|
||||
namespace {
|
||||
struct LV {
|
||||
Expr* Base;
|
||||
CharUnits Offset;
|
||||
};
|
||||
}
|
||||
|
||||
APValue::APValue(Expr* B) : Kind(Uninitialized) {
|
||||
MakeLValue(); setLValue(B, CharUnits::Zero());
|
||||
}
|
||||
|
||||
const APValue &APValue::operator=(const APValue &RHS) {
|
||||
if (Kind != RHS.Kind) {
|
||||
@ -106,3 +117,25 @@ void APValue::print(llvm::raw_ostream &OS) const {
|
||||
}
|
||||
}
|
||||
|
||||
Expr* APValue::getLValueBase() const {
|
||||
assert(isLValue() && "Invalid accessor");
|
||||
return ((const LV*)(const void*)Data)->Base;
|
||||
}
|
||||
|
||||
CharUnits APValue::getLValueOffset() const {
|
||||
assert(isLValue() && "Invalid accessor");
|
||||
return ((const LV*)(const void*)Data)->Offset;
|
||||
}
|
||||
|
||||
void APValue::setLValue(Expr *B, const CharUnits &O) {
|
||||
assert(isLValue() && "Invalid accessor");
|
||||
((LV*)(char*)Data)->Base = B;
|
||||
((LV*)(char*)Data)->Offset = O;
|
||||
}
|
||||
|
||||
void APValue::MakeLValue() {
|
||||
assert(isUninit() && "Bad state change");
|
||||
new ((void*)(char*)Data) LV();
|
||||
Kind = LValue;
|
||||
}
|
||||
|
||||
|
@ -814,10 +814,10 @@ ASTContext::getTypeInfo(const Type *T) {
|
||||
/// getTypeSizeInChars - Return the size of the specified type, in characters.
|
||||
/// This method does not work on incomplete types.
|
||||
CharUnits ASTContext::getTypeSizeInChars(QualType T) {
|
||||
return CharUnits::fromRaw(getTypeSize(T) / getCharWidth());
|
||||
return CharUnits::fromQuantity(getTypeSize(T) / getCharWidth());
|
||||
}
|
||||
CharUnits ASTContext::getTypeSizeInChars(const Type *T) {
|
||||
return CharUnits::fromRaw(getTypeSize(T) / getCharWidth());
|
||||
return CharUnits::fromQuantity(getTypeSize(T) / getCharWidth());
|
||||
}
|
||||
|
||||
/// getPreferredTypeAlign - Return the "preferred" alignment of the specified
|
||||
@ -2374,16 +2374,14 @@ CanQualType ASTContext::getCanonicalType(QualType T) {
|
||||
|
||||
QualType ASTContext::getUnqualifiedArrayType(QualType T,
|
||||
Qualifiers &Quals) {
|
||||
assert(T.isCanonical() && "Only operates on canonical types");
|
||||
Quals = T.getQualifiers();
|
||||
if (!isa<ArrayType>(T)) {
|
||||
Quals = T.getLocalQualifiers();
|
||||
return T.getLocalUnqualifiedType();
|
||||
return T.getUnqualifiedType();
|
||||
}
|
||||
|
||||
assert(!T.hasQualifiers() && "canonical array type has qualifiers!");
|
||||
const ArrayType *AT = cast<ArrayType>(T);
|
||||
QualType Elt = AT->getElementType();
|
||||
QualType UnqualElt = getUnqualifiedArrayType(getCanonicalType(Elt), Quals);
|
||||
QualType UnqualElt = getUnqualifiedArrayType(Elt, Quals);
|
||||
if (Elt == UnqualElt)
|
||||
return T;
|
||||
|
||||
@ -2396,12 +2394,6 @@ QualType ASTContext::getUnqualifiedArrayType(QualType T,
|
||||
return getIncompleteArrayType(UnqualElt, IAT->getSizeModifier(), 0);
|
||||
}
|
||||
|
||||
if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(T)) {
|
||||
return getVariableArrayType(UnqualElt, VAT->getSizeExpr()->Retain(),
|
||||
VAT->getSizeModifier(), 0,
|
||||
SourceRange());
|
||||
}
|
||||
|
||||
const DependentSizedArrayType *DSAT = cast<DependentSizedArrayType>(T);
|
||||
return getDependentSizedArrayType(UnqualElt, DSAT->getSizeExpr()->Retain(),
|
||||
DSAT->getSizeModifier(), 0,
|
||||
@ -3143,16 +3135,21 @@ static bool isTypeTypedefedAsBOOL(QualType T) {
|
||||
|
||||
/// getObjCEncodingTypeSize returns size of type for objective-c encoding
|
||||
/// purpose.
|
||||
int ASTContext::getObjCEncodingTypeSize(QualType type) {
|
||||
uint64_t sz = getTypeSize(type);
|
||||
CharUnits ASTContext::getObjCEncodingTypeSize(QualType type) {
|
||||
CharUnits sz = getTypeSizeInChars(type);
|
||||
|
||||
// Make all integer and enum types at least as large as an int
|
||||
if (sz > 0 && type->isIntegralType())
|
||||
sz = std::max(sz, getTypeSize(IntTy));
|
||||
if (sz.isPositive() && type->isIntegralType())
|
||||
sz = std::max(sz, getTypeSizeInChars(IntTy));
|
||||
// Treat arrays as pointers, since that's how they're passed in.
|
||||
else if (type->isArrayType())
|
||||
sz = getTypeSize(VoidPtrTy);
|
||||
return sz / getTypeSize(CharTy);
|
||||
sz = getTypeSizeInChars(VoidPtrTy);
|
||||
return sz;
|
||||
}
|
||||
|
||||
static inline
|
||||
std::string charUnitsToString(const CharUnits &CU) {
|
||||
return llvm::itostr(CU.getQuantity());
|
||||
}
|
||||
|
||||
/// getObjCEncodingForBlockDecl - Return the encoded type for this method
|
||||
@ -3168,17 +3165,17 @@ void ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr,
|
||||
// Start with computing size of a pointer in number of bytes.
|
||||
// FIXME: There might(should) be a better way of doing this computation!
|
||||
SourceLocation Loc;
|
||||
int PtrSize = getTypeSize(VoidPtrTy) / getTypeSize(CharTy);
|
||||
int ParmOffset = PtrSize;
|
||||
CharUnits PtrSize = getTypeSizeInChars(VoidPtrTy);
|
||||
CharUnits ParmOffset = PtrSize;
|
||||
for (ObjCMethodDecl::param_iterator PI = Decl->param_begin(),
|
||||
E = Decl->param_end(); PI != E; ++PI) {
|
||||
QualType PType = (*PI)->getType();
|
||||
int sz = getObjCEncodingTypeSize(PType);
|
||||
assert (sz > 0 && "BlockExpr - Incomplete param type");
|
||||
CharUnits sz = getObjCEncodingTypeSize(PType);
|
||||
assert (sz.isPositive() && "BlockExpr - Incomplete param type");
|
||||
ParmOffset += sz;
|
||||
}
|
||||
// Size of the argument frame
|
||||
S += llvm::utostr(ParmOffset);
|
||||
S += charUnitsToString(ParmOffset);
|
||||
// Block pointer and offset.
|
||||
S += "@?0";
|
||||
ParmOffset = PtrSize;
|
||||
@ -3198,7 +3195,7 @@ void ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr,
|
||||
} else if (PType->isFunctionType())
|
||||
PType = PVDecl->getType();
|
||||
getObjCEncodingForType(PType, S);
|
||||
S += llvm::utostr(ParmOffset);
|
||||
S += charUnitsToString(ParmOffset);
|
||||
ParmOffset += getObjCEncodingTypeSize(PType);
|
||||
}
|
||||
}
|
||||
@ -3216,20 +3213,21 @@ void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl,
|
||||
// Start with computing size of a pointer in number of bytes.
|
||||
// FIXME: There might(should) be a better way of doing this computation!
|
||||
SourceLocation Loc;
|
||||
int PtrSize = getTypeSize(VoidPtrTy) / getTypeSize(CharTy);
|
||||
CharUnits PtrSize = getTypeSizeInChars(VoidPtrTy);
|
||||
// The first two arguments (self and _cmd) are pointers; account for
|
||||
// their size.
|
||||
int ParmOffset = 2 * PtrSize;
|
||||
CharUnits ParmOffset = 2 * PtrSize;
|
||||
for (ObjCMethodDecl::param_iterator PI = Decl->param_begin(),
|
||||
E = Decl->param_end(); PI != E; ++PI) {
|
||||
QualType PType = (*PI)->getType();
|
||||
int sz = getObjCEncodingTypeSize(PType);
|
||||
assert (sz > 0 && "getObjCEncodingForMethodDecl - Incomplete param type");
|
||||
CharUnits sz = getObjCEncodingTypeSize(PType);
|
||||
assert (sz.isPositive() &&
|
||||
"getObjCEncodingForMethodDecl - Incomplete param type");
|
||||
ParmOffset += sz;
|
||||
}
|
||||
S += llvm::utostr(ParmOffset);
|
||||
S += charUnitsToString(ParmOffset);
|
||||
S += "@0:";
|
||||
S += llvm::utostr(PtrSize);
|
||||
S += charUnitsToString(PtrSize);
|
||||
|
||||
// Argument types.
|
||||
ParmOffset = 2 * PtrSize;
|
||||
@ -3249,7 +3247,7 @@ void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl,
|
||||
// 'in', 'inout', etc.
|
||||
getObjCEncodingForTypeQualifier(PVDecl->getObjCDeclQualifier(), S);
|
||||
getObjCEncodingForType(PType, S);
|
||||
S += llvm::utostr(ParmOffset);
|
||||
S += charUnitsToString(ParmOffset);
|
||||
ParmOffset += getObjCEncodingTypeSize(PType);
|
||||
}
|
||||
}
|
||||
|
143
lib/AST/AttrImpl.cpp
Normal file
143
lib/AST/AttrImpl.cpp
Normal file
@ -0,0 +1,143 @@
|
||||
//===--- AttrImpl.cpp - Classes for representing attributes -----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains out-of-line virtual methods for Attr classes.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
#include "clang/AST/Attr.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
using namespace clang;
|
||||
|
||||
#define DEF_SIMPLE_ATTR_CLONE(ATTR) \
|
||||
Attr *ATTR##Attr::clone(ASTContext &C) const { \
|
||||
return ::new (C) ATTR##Attr; \
|
||||
}
|
||||
|
||||
// FIXME: Can we use variadic macro to define DEF_SIMPLE_ATTR_CLONE for
|
||||
// "non-simple" classes?
|
||||
|
||||
DEF_SIMPLE_ATTR_CLONE(Packed)
|
||||
DEF_SIMPLE_ATTR_CLONE(AlwaysInline)
|
||||
DEF_SIMPLE_ATTR_CLONE(Malloc)
|
||||
DEF_SIMPLE_ATTR_CLONE(NoReturn)
|
||||
DEF_SIMPLE_ATTR_CLONE(AnalyzerNoReturn)
|
||||
DEF_SIMPLE_ATTR_CLONE(Deprecated)
|
||||
DEF_SIMPLE_ATTR_CLONE(Final)
|
||||
DEF_SIMPLE_ATTR_CLONE(Unavailable)
|
||||
DEF_SIMPLE_ATTR_CLONE(Unused)
|
||||
DEF_SIMPLE_ATTR_CLONE(Used)
|
||||
DEF_SIMPLE_ATTR_CLONE(Weak)
|
||||
DEF_SIMPLE_ATTR_CLONE(WeakImport)
|
||||
DEF_SIMPLE_ATTR_CLONE(NoThrow)
|
||||
DEF_SIMPLE_ATTR_CLONE(Const)
|
||||
DEF_SIMPLE_ATTR_CLONE(Pure)
|
||||
DEF_SIMPLE_ATTR_CLONE(FastCall)
|
||||
DEF_SIMPLE_ATTR_CLONE(StdCall)
|
||||
DEF_SIMPLE_ATTR_CLONE(CDecl)
|
||||
DEF_SIMPLE_ATTR_CLONE(TransparentUnion)
|
||||
DEF_SIMPLE_ATTR_CLONE(ObjCNSObject)
|
||||
DEF_SIMPLE_ATTR_CLONE(ObjCException)
|
||||
DEF_SIMPLE_ATTR_CLONE(NoDebug)
|
||||
DEF_SIMPLE_ATTR_CLONE(WarnUnusedResult)
|
||||
DEF_SIMPLE_ATTR_CLONE(NoInline)
|
||||
DEF_SIMPLE_ATTR_CLONE(CFReturnsRetained)
|
||||
DEF_SIMPLE_ATTR_CLONE(NSReturnsRetained)
|
||||
DEF_SIMPLE_ATTR_CLONE(BaseCheck)
|
||||
DEF_SIMPLE_ATTR_CLONE(Hiding)
|
||||
DEF_SIMPLE_ATTR_CLONE(Override)
|
||||
DEF_SIMPLE_ATTR_CLONE(DLLImport)
|
||||
DEF_SIMPLE_ATTR_CLONE(DLLExport)
|
||||
|
||||
Attr* PragmaPackAttr::clone(ASTContext &C) const {
|
||||
return ::new (C) PragmaPackAttr(Alignment);
|
||||
}
|
||||
|
||||
Attr* AlignedAttr::clone(ASTContext &C) const {
|
||||
return ::new (C) AlignedAttr(Alignment);
|
||||
}
|
||||
|
||||
Attr* AnnotateAttr::clone(ASTContext &C) const {
|
||||
return ::new (C) AnnotateAttr(Annotation);
|
||||
}
|
||||
|
||||
Attr *AsmLabelAttr::clone(ASTContext &C) const {
|
||||
return ::new (C) AsmLabelAttr(Label);
|
||||
}
|
||||
|
||||
Attr *AliasAttr::clone(ASTContext &C) const {
|
||||
return ::new (C) AliasAttr(Aliasee);
|
||||
}
|
||||
|
||||
Attr *ConstructorAttr::clone(ASTContext &C) const {
|
||||
return ::new (C) ConstructorAttr(priority);
|
||||
}
|
||||
|
||||
Attr *DestructorAttr::clone(ASTContext &C) const {
|
||||
return ::new (C) DestructorAttr(priority);
|
||||
}
|
||||
|
||||
Attr *IBOutletAttr::clone(ASTContext &C) const {
|
||||
return ::new (C) IBOutletAttr;
|
||||
}
|
||||
|
||||
Attr *GNUInlineAttr::clone(ASTContext &C) const {
|
||||
return ::new (C) GNUInlineAttr;
|
||||
}
|
||||
|
||||
Attr *SectionAttr::clone(ASTContext &C) const {
|
||||
return ::new (C) SectionAttr(Name);
|
||||
}
|
||||
|
||||
Attr *NonNullAttr::clone(ASTContext &C) const {
|
||||
return ::new (C) NonNullAttr(ArgNums, Size);
|
||||
}
|
||||
|
||||
Attr *FormatAttr::clone(ASTContext &C) const {
|
||||
return ::new (C) FormatAttr(Type, formatIdx, firstArg);
|
||||
}
|
||||
|
||||
Attr *FormatArgAttr::clone(ASTContext &C) const {
|
||||
return ::new (C) FormatArgAttr(formatIdx);
|
||||
}
|
||||
|
||||
Attr *SentinelAttr::clone(ASTContext &C) const {
|
||||
return ::new (C) SentinelAttr(sentinel, NullPos);
|
||||
}
|
||||
|
||||
Attr *VisibilityAttr::clone(ASTContext &C) const {
|
||||
return ::new (C) VisibilityAttr(VisibilityType);
|
||||
}
|
||||
|
||||
Attr *OverloadableAttr::clone(ASTContext &C) const {
|
||||
return ::new (C) OverloadableAttr;
|
||||
}
|
||||
|
||||
Attr *BlocksAttr::clone(ASTContext &C) const {
|
||||
return ::new (C) BlocksAttr(BlocksAttrType);
|
||||
}
|
||||
|
||||
Attr *CleanupAttr::clone(ASTContext &C) const {
|
||||
return ::new (C) CleanupAttr(FD);
|
||||
}
|
||||
|
||||
Attr *RegparmAttr::clone(ASTContext &C) const {
|
||||
return ::new (C) RegparmAttr(NumParams);
|
||||
}
|
||||
|
||||
Attr *ReqdWorkGroupSizeAttr::clone(ASTContext &C) const {
|
||||
return ::new (C) ReqdWorkGroupSizeAttr(X, Y, Z);
|
||||
}
|
||||
|
||||
Attr *MSP430InterruptAttr::clone(ASTContext &C) const {
|
||||
return ::new (C) MSP430InterruptAttr(Number);
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ add_clang_library(clangAST
|
||||
APValue.cpp
|
||||
ASTConsumer.cpp
|
||||
ASTContext.cpp
|
||||
AttrImpl.cpp
|
||||
CXXInheritance.cpp
|
||||
Decl.cpp
|
||||
DeclBase.cpp
|
||||
|
@ -957,7 +957,7 @@ bool FunctionDecl::isInlined() const {
|
||||
/// "externally" visible to other translation units in the program.
|
||||
///
|
||||
/// In C99, inline definitions are not externally visible by default. However,
|
||||
/// if even one of the globa-scope declarations is marked "extern inline", the
|
||||
/// if even one of the global-scope declarations is marked "extern inline", the
|
||||
/// inline definition becomes externally visible (C99 6.7.4p6).
|
||||
///
|
||||
/// In GNU89 mode, or if the gnu_inline attribute is attached to the function
|
||||
@ -1039,6 +1039,15 @@ OverloadedOperatorKind FunctionDecl::getOverloadedOperator() const {
|
||||
return OO_None;
|
||||
}
|
||||
|
||||
/// getLiteralIdentifier - The literal suffix identifier this function
|
||||
/// represents, if any.
|
||||
const IdentifierInfo *FunctionDecl::getLiteralIdentifier() const {
|
||||
if (getDeclName().getNameKind() == DeclarationName::CXXLiteralOperatorName)
|
||||
return getDeclName().getCXXLiteralIdentifier();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
FunctionDecl *FunctionDecl::getInstantiatedFromMemberFunction() const {
|
||||
if (MemberSpecializationInfo *Info = getMemberSpecializationInfo())
|
||||
return cast<FunctionDecl>(Info->getInstantiatedFrom());
|
||||
|
@ -144,6 +144,19 @@ CXXRecordDecl::setBases(ASTContext &C,
|
||||
}
|
||||
}
|
||||
|
||||
/// Callback function for CXXRecordDecl::forallBases that acknowledges
|
||||
/// that it saw a base class.
|
||||
static bool SawBase(const CXXRecordDecl *, void *) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CXXRecordDecl::hasAnyDependentBases() const {
|
||||
if (!isDependentContext())
|
||||
return false;
|
||||
|
||||
return !forallBases(SawBase, 0);
|
||||
}
|
||||
|
||||
bool CXXRecordDecl::hasConstCopyConstructor(ASTContext &Context) const {
|
||||
return getCopyConstructor(Context, Qualifiers::Const) != 0;
|
||||
}
|
||||
@ -643,23 +656,15 @@ QualType CXXMethodDecl::getThisType(ASTContext &C) const {
|
||||
return C.getPointerType(ClassTy);
|
||||
}
|
||||
|
||||
static bool MethodHasBody(const CXXMethodDecl *MD, const FunctionDecl *&fn) {
|
||||
// Simple case: function has a body
|
||||
if (MD->getBody(fn))
|
||||
return true;
|
||||
|
||||
// Complex case: function is an instantiation of a function which has a
|
||||
// body, but the definition hasn't been instantiated.
|
||||
const FunctionDecl *PatternDecl = MD->getTemplateInstantiationPattern();
|
||||
if (PatternDecl && PatternDecl->getBody(fn))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CXXMethodDecl::hasInlineBody() const {
|
||||
// If this function is a template instantiation, look at the template from
|
||||
// which it was instantiated.
|
||||
const FunctionDecl *CheckFn = getTemplateInstantiationPattern();
|
||||
if (!CheckFn)
|
||||
CheckFn = this;
|
||||
|
||||
const FunctionDecl *fn;
|
||||
return MethodHasBody(this, fn) && !fn->isOutOfLine();
|
||||
return CheckFn->getBody(fn) && !fn->isOutOfLine();
|
||||
}
|
||||
|
||||
CXXBaseOrMemberInitializer::
|
||||
|
@ -56,9 +56,14 @@ public:
|
||||
/// This identifier is stored here rather than directly in DeclarationName so as
|
||||
/// to allow Objective-C selectors, which are about a million times more common,
|
||||
/// to consume minimal memory.
|
||||
class CXXLiteralOperatorIdName : public DeclarationNameExtra {
|
||||
class CXXLiteralOperatorIdName
|
||||
: public DeclarationNameExtra, public llvm::FoldingSetNode {
|
||||
public:
|
||||
IdentifierInfo *ID;
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &FSID) {
|
||||
FSID.AddPointer(ID);
|
||||
}
|
||||
};
|
||||
|
||||
bool operator<(DeclarationName LHS, DeclarationName RHS) {
|
||||
@ -180,6 +185,11 @@ DeclarationName::NameKind DeclarationName::getNameKind() const {
|
||||
return Identifier;
|
||||
}
|
||||
|
||||
bool DeclarationName::isDependentName() const {
|
||||
QualType T = getCXXNameType();
|
||||
return !T.isNull() && T->isDependentType();
|
||||
}
|
||||
|
||||
std::string DeclarationName::getAsString() const {
|
||||
switch (getNameKind()) {
|
||||
case Identifier:
|
||||
@ -353,6 +363,7 @@ void DeclarationName::dump() const {
|
||||
|
||||
DeclarationNameTable::DeclarationNameTable() {
|
||||
CXXSpecialNamesImpl = new llvm::FoldingSet<CXXSpecialName>;
|
||||
CXXLiteralOperatorNames = new llvm::FoldingSet<CXXLiteralOperatorIdName>;
|
||||
|
||||
// Initialize the overloaded operator names.
|
||||
CXXOperatorNames = new CXXOperatorIdName[NUM_OVERLOADED_OPERATORS];
|
||||
@ -364,16 +375,30 @@ DeclarationNameTable::DeclarationNameTable() {
|
||||
}
|
||||
|
||||
DeclarationNameTable::~DeclarationNameTable() {
|
||||
llvm::FoldingSet<CXXSpecialName> *set =
|
||||
llvm::FoldingSet<CXXSpecialName> *SpecialNames =
|
||||
static_cast<llvm::FoldingSet<CXXSpecialName>*>(CXXSpecialNamesImpl);
|
||||
llvm::FoldingSetIterator<CXXSpecialName> I = set->begin(), E = set->end();
|
||||
llvm::FoldingSetIterator<CXXSpecialName>
|
||||
SI = SpecialNames->begin(), SE = SpecialNames->end();
|
||||
|
||||
while (I != E) {
|
||||
CXXSpecialName *n = &*I++;
|
||||
while (SI != SE) {
|
||||
CXXSpecialName *n = &*SI++;
|
||||
delete n;
|
||||
}
|
||||
|
||||
delete set;
|
||||
|
||||
llvm::FoldingSet<CXXLiteralOperatorIdName> *LiteralNames
|
||||
= static_cast<llvm::FoldingSet<CXXLiteralOperatorIdName>*>
|
||||
(CXXLiteralOperatorNames);
|
||||
llvm::FoldingSetIterator<CXXLiteralOperatorIdName>
|
||||
LI = LiteralNames->begin(), LE = LiteralNames->end();
|
||||
|
||||
while (LI != LE) {
|
||||
CXXLiteralOperatorIdName *n = &*LI++;
|
||||
delete n;
|
||||
}
|
||||
|
||||
delete SpecialNames;
|
||||
delete LiteralNames;
|
||||
delete [] CXXOperatorNames;
|
||||
}
|
||||
|
||||
@ -428,9 +453,23 @@ DeclarationNameTable::getCXXOperatorName(OverloadedOperatorKind Op) {
|
||||
|
||||
DeclarationName
|
||||
DeclarationNameTable::getCXXLiteralOperatorName(IdentifierInfo *II) {
|
||||
llvm::FoldingSet<CXXLiteralOperatorIdName> *LiteralNames
|
||||
= static_cast<llvm::FoldingSet<CXXLiteralOperatorIdName>*>
|
||||
(CXXLiteralOperatorNames);
|
||||
|
||||
llvm::FoldingSetNodeID ID;
|
||||
ID.AddPointer(II);
|
||||
|
||||
void *InsertPos = 0;
|
||||
if (CXXLiteralOperatorIdName *Name =
|
||||
LiteralNames->FindNodeOrInsertPos(ID, InsertPos))
|
||||
return DeclarationName (Name);
|
||||
|
||||
CXXLiteralOperatorIdName *LiteralName = new CXXLiteralOperatorIdName;
|
||||
LiteralName->ExtraKindOrNumArgs = DeclarationNameExtra::CXXLiteralOperator;
|
||||
LiteralName->ID = II;
|
||||
|
||||
LiteralNames->InsertNode(LiteralName, InsertPos);
|
||||
return DeclarationName(LiteralName);
|
||||
}
|
||||
|
||||
|
@ -2154,7 +2154,8 @@ IdentifierInfo *DesignatedInitExpr::Designator::getFieldName() {
|
||||
return getField()->getIdentifier();
|
||||
}
|
||||
|
||||
DesignatedInitExpr::DesignatedInitExpr(QualType Ty, unsigned NumDesignators,
|
||||
DesignatedInitExpr::DesignatedInitExpr(ASTContext &C, QualType Ty,
|
||||
unsigned NumDesignators,
|
||||
const Designator *Designators,
|
||||
SourceLocation EqualOrColonLoc,
|
||||
bool GNUSyntax,
|
||||
@ -2165,7 +2166,7 @@ DesignatedInitExpr::DesignatedInitExpr(QualType Ty, unsigned NumDesignators,
|
||||
Init->isTypeDependent(), Init->isValueDependent()),
|
||||
EqualOrColonLoc(EqualOrColonLoc), GNUSyntax(GNUSyntax),
|
||||
NumDesignators(NumDesignators), NumSubExprs(NumIndexExprs + 1) {
|
||||
this->Designators = new Designator[NumDesignators];
|
||||
this->Designators = new (C) Designator[NumDesignators];
|
||||
|
||||
// Record the initializer itself.
|
||||
child_iterator Child = child_begin();
|
||||
@ -2210,7 +2211,7 @@ DesignatedInitExpr::Create(ASTContext &C, Designator *Designators,
|
||||
bool UsesColonSyntax, Expr *Init) {
|
||||
void *Mem = C.Allocate(sizeof(DesignatedInitExpr) +
|
||||
sizeof(Stmt *) * (NumIndexExprs + 1), 8);
|
||||
return new (Mem) DesignatedInitExpr(C.VoidTy, NumDesignators, Designators,
|
||||
return new (Mem) DesignatedInitExpr(C, C.VoidTy, NumDesignators, Designators,
|
||||
ColonOrEqualLoc, UsesColonSyntax,
|
||||
IndexExprs, NumIndexExprs, Init);
|
||||
}
|
||||
@ -2222,12 +2223,12 @@ DesignatedInitExpr *DesignatedInitExpr::CreateEmpty(ASTContext &C,
|
||||
return new (Mem) DesignatedInitExpr(NumIndexExprs + 1);
|
||||
}
|
||||
|
||||
void DesignatedInitExpr::setDesignators(const Designator *Desigs,
|
||||
void DesignatedInitExpr::setDesignators(ASTContext &C,
|
||||
const Designator *Desigs,
|
||||
unsigned NumDesigs) {
|
||||
if (Designators)
|
||||
delete [] Designators;
|
||||
DestroyDesignators(C);
|
||||
|
||||
Designators = new Designator[NumDesigs];
|
||||
Designators = new (C) Designator[NumDesigs];
|
||||
NumDesignators = NumDesigs;
|
||||
for (unsigned I = 0; I != NumDesigs; ++I)
|
||||
Designators[I] = Desigs[I];
|
||||
@ -2276,7 +2277,7 @@ Expr *DesignatedInitExpr::getArrayRangeEnd(const Designator& D) {
|
||||
|
||||
/// \brief Replaces the designator at index @p Idx with the series
|
||||
/// of designators in [First, Last).
|
||||
void DesignatedInitExpr::ExpandDesignator(unsigned Idx,
|
||||
void DesignatedInitExpr::ExpandDesignator(ASTContext &C, unsigned Idx,
|
||||
const Designator *First,
|
||||
const Designator *Last) {
|
||||
unsigned NumNewDesignators = Last - First;
|
||||
@ -2292,21 +2293,28 @@ void DesignatedInitExpr::ExpandDesignator(unsigned Idx,
|
||||
}
|
||||
|
||||
Designator *NewDesignators
|
||||
= new Designator[NumDesignators - 1 + NumNewDesignators];
|
||||
= new (C) Designator[NumDesignators - 1 + NumNewDesignators];
|
||||
std::copy(Designators, Designators + Idx, NewDesignators);
|
||||
std::copy(First, Last, NewDesignators + Idx);
|
||||
std::copy(Designators + Idx + 1, Designators + NumDesignators,
|
||||
NewDesignators + Idx + NumNewDesignators);
|
||||
delete [] Designators;
|
||||
DestroyDesignators(C);
|
||||
Designators = NewDesignators;
|
||||
NumDesignators = NumDesignators - 1 + NumNewDesignators;
|
||||
}
|
||||
|
||||
void DesignatedInitExpr::DoDestroy(ASTContext &C) {
|
||||
delete [] Designators;
|
||||
DestroyDesignators(C);
|
||||
Expr::DoDestroy(C);
|
||||
}
|
||||
|
||||
void DesignatedInitExpr::DestroyDesignators(ASTContext &C) {
|
||||
for (unsigned I = 0; I != NumDesignators; ++I)
|
||||
Designators[I].~Designator();
|
||||
C.Deallocate(Designators);
|
||||
Designators = 0;
|
||||
}
|
||||
|
||||
ParenListExpr::ParenListExpr(ASTContext& C, SourceLocation lparenloc,
|
||||
Expr **exprs, unsigned nexprs,
|
||||
SourceLocation rparenloc)
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
#include "clang/AST/APValue.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/CharUnits.h"
|
||||
#include "clang/AST/RecordLayout.h"
|
||||
#include "clang/AST/StmtVisitor.h"
|
||||
#include "clang/AST/ASTDiagnostic.h"
|
||||
@ -69,11 +70,12 @@ static bool EvaluateComplex(const Expr *E, APValue &Result, EvalInfo &Info);
|
||||
static bool EvalPointerValueAsBool(APValue& Value, bool& Result) {
|
||||
// FIXME: Is this accurate for all kinds of bases? If not, what would
|
||||
// the check look like?
|
||||
Result = Value.getLValueBase() || Value.getLValueOffset();
|
||||
Result = Value.getLValueBase() || !Value.getLValueOffset().isZero();
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleConversionToBool(Expr* E, bool& Result, EvalInfo &Info) {
|
||||
static bool HandleConversionToBool(const Expr* E, bool& Result,
|
||||
EvalInfo &Info) {
|
||||
if (E->getType()->isIntegralType()) {
|
||||
APSInt IntResult;
|
||||
if (!EvaluateInteger(E, IntResult, Info))
|
||||
@ -222,11 +224,11 @@ public:
|
||||
|
||||
APValue VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
|
||||
APValue VisitDeclRefExpr(DeclRefExpr *E);
|
||||
APValue VisitPredefinedExpr(PredefinedExpr *E) { return APValue(E, 0); }
|
||||
APValue VisitPredefinedExpr(PredefinedExpr *E) { return APValue(E); }
|
||||
APValue VisitCompoundLiteralExpr(CompoundLiteralExpr *E);
|
||||
APValue VisitMemberExpr(MemberExpr *E);
|
||||
APValue VisitStringLiteral(StringLiteral *E) { return APValue(E, 0); }
|
||||
APValue VisitObjCEncodeExpr(ObjCEncodeExpr *E) { return APValue(E, 0); }
|
||||
APValue VisitStringLiteral(StringLiteral *E) { return APValue(E); }
|
||||
APValue VisitObjCEncodeExpr(ObjCEncodeExpr *E) { return APValue(E); }
|
||||
APValue VisitArraySubscriptExpr(ArraySubscriptExpr *E);
|
||||
APValue VisitUnaryDeref(UnaryOperator *E);
|
||||
APValue VisitUnaryExtension(const UnaryOperator *E)
|
||||
@ -254,12 +256,12 @@ static bool EvaluateLValue(const Expr* E, APValue& Result, EvalInfo &Info) {
|
||||
|
||||
APValue LValueExprEvaluator::VisitDeclRefExpr(DeclRefExpr *E) {
|
||||
if (isa<FunctionDecl>(E->getDecl())) {
|
||||
return APValue(E, 0);
|
||||
return APValue(E);
|
||||
} else if (VarDecl* VD = dyn_cast<VarDecl>(E->getDecl())) {
|
||||
if (!Info.AnyLValue && !VD->hasGlobalStorage())
|
||||
return APValue();
|
||||
if (!VD->getType()->isReferenceType())
|
||||
return APValue(E, 0);
|
||||
return APValue(E);
|
||||
// FIXME: Check whether VD might be overridden!
|
||||
const VarDecl *Def = 0;
|
||||
if (const Expr *Init = VD->getDefinition(Def))
|
||||
@ -272,7 +274,7 @@ APValue LValueExprEvaluator::VisitDeclRefExpr(DeclRefExpr *E) {
|
||||
APValue LValueExprEvaluator::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
|
||||
if (!Info.AnyLValue && !E->isFileScope())
|
||||
return APValue();
|
||||
return APValue(E, 0);
|
||||
return APValue(E);
|
||||
}
|
||||
|
||||
APValue LValueExprEvaluator::VisitMemberExpr(MemberExpr *E) {
|
||||
@ -309,7 +311,8 @@ APValue LValueExprEvaluator::VisitMemberExpr(MemberExpr *E) {
|
||||
}
|
||||
|
||||
result.setLValue(result.getLValueBase(),
|
||||
result.getLValueOffset() + RL.getFieldOffset(i) / 8);
|
||||
result.getLValueOffset() +
|
||||
CharUnits::fromQuantity(RL.getFieldOffset(i) / 8));
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -324,9 +327,9 @@ APValue LValueExprEvaluator::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
|
||||
if (!EvaluateInteger(E->getIdx(), Index, Info))
|
||||
return APValue();
|
||||
|
||||
uint64_t ElementSize = Info.Ctx.getTypeSize(E->getType()) / 8;
|
||||
CharUnits ElementSize = Info.Ctx.getTypeSizeInChars(E->getType());
|
||||
|
||||
uint64_t Offset = Index.getSExtValue() * ElementSize;
|
||||
CharUnits Offset = Index.getSExtValue() * ElementSize;
|
||||
Result.setLValue(Result.getLValueBase(),
|
||||
Result.getLValueOffset() + Offset);
|
||||
return Result;
|
||||
@ -363,22 +366,22 @@ public:
|
||||
{ return Visit(E->getSubExpr()); }
|
||||
APValue VisitUnaryAddrOf(const UnaryOperator *E);
|
||||
APValue VisitObjCStringLiteral(ObjCStringLiteral *E)
|
||||
{ return APValue(E, 0); }
|
||||
{ return APValue(E); }
|
||||
APValue VisitAddrLabelExpr(AddrLabelExpr *E)
|
||||
{ return APValue(E, 0); }
|
||||
{ return APValue(E); }
|
||||
APValue VisitCallExpr(CallExpr *E);
|
||||
APValue VisitBlockExpr(BlockExpr *E) {
|
||||
if (!E->hasBlockDeclRefExprs())
|
||||
return APValue(E, 0);
|
||||
return APValue(E);
|
||||
return APValue();
|
||||
}
|
||||
APValue VisitImplicitValueInitExpr(ImplicitValueInitExpr *E)
|
||||
{ return APValue((Expr*)0, 0); }
|
||||
{ return APValue((Expr*)0); }
|
||||
APValue VisitConditionalOperator(ConditionalOperator *E);
|
||||
APValue VisitChooseExpr(ChooseExpr *E)
|
||||
{ return Visit(E->getChosenSubExpr(Info.Ctx)); }
|
||||
APValue VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E)
|
||||
{ return APValue((Expr*)0, 0); }
|
||||
{ return APValue((Expr*)0); }
|
||||
// FIXME: Missing: @protocol, @selector
|
||||
};
|
||||
} // end anonymous namespace
|
||||
@ -409,15 +412,15 @@ APValue PointerExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
|
||||
return APValue();
|
||||
|
||||
QualType PointeeType = PExp->getType()->getAs<PointerType>()->getPointeeType();
|
||||
uint64_t SizeOfPointee;
|
||||
CharUnits SizeOfPointee;
|
||||
|
||||
// Explicitly handle GNU void* and function pointer arithmetic extensions.
|
||||
if (PointeeType->isVoidType() || PointeeType->isFunctionType())
|
||||
SizeOfPointee = 1;
|
||||
SizeOfPointee = CharUnits::One();
|
||||
else
|
||||
SizeOfPointee = Info.Ctx.getTypeSize(PointeeType) / 8;
|
||||
SizeOfPointee = Info.Ctx.getTypeSizeInChars(PointeeType);
|
||||
|
||||
uint64_t Offset = ResultLValue.getLValueOffset();
|
||||
CharUnits Offset = ResultLValue.getLValueOffset();
|
||||
|
||||
if (E->getOpcode() == BinaryOperator::Add)
|
||||
Offset += AdditionalOffset.getLimitedValue() * SizeOfPointee;
|
||||
@ -459,7 +462,8 @@ APValue PointerExprEvaluator::VisitCastExpr(CastExpr* E) {
|
||||
|
||||
if (Result.isInt()) {
|
||||
Result.getInt().extOrTrunc((unsigned)Info.Ctx.getTypeSize(E->getType()));
|
||||
return APValue(0, Result.getInt().getZExtValue());
|
||||
return APValue(0,
|
||||
CharUnits::fromQuantity(Result.getInt().getZExtValue()));
|
||||
}
|
||||
|
||||
// Cast is of an lvalue, no need to change value.
|
||||
@ -481,7 +485,8 @@ APValue PointerExprEvaluator::VisitCastExpr(CastExpr* E) {
|
||||
|
||||
if (Result.isInt()) {
|
||||
Result.getInt().extOrTrunc((unsigned)Info.Ctx.getTypeSize(E->getType()));
|
||||
return APValue(0, Result.getInt().getZExtValue());
|
||||
return APValue(0,
|
||||
CharUnits::fromQuantity(Result.getInt().getZExtValue()));
|
||||
}
|
||||
|
||||
// Cast is of an lvalue, no need to change value.
|
||||
@ -502,7 +507,7 @@ APValue PointerExprEvaluator::VisitCastExpr(CastExpr* E) {
|
||||
APValue PointerExprEvaluator::VisitCallExpr(CallExpr *E) {
|
||||
if (E->isBuiltinCall(Info.Ctx) ==
|
||||
Builtin::BI__builtin___CFStringMakeConstantString)
|
||||
return APValue(E, 0);
|
||||
return APValue(E);
|
||||
return APValue();
|
||||
}
|
||||
|
||||
@ -976,20 +981,20 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
|
||||
&& VD->getType()->isObjectType()
|
||||
&& !VD->getType()->isVariablyModifiedType()
|
||||
&& !VD->getType()->isDependentType()) {
|
||||
uint64_t Size = Info.Ctx.getTypeSize(VD->getType()) / 8;
|
||||
uint64_t Offset = Base.Val.getLValueOffset();
|
||||
if (Offset <= Size)
|
||||
Size -= Base.Val.getLValueOffset();
|
||||
CharUnits Size = Info.Ctx.getTypeSizeInChars(VD->getType());
|
||||
CharUnits Offset = Base.Val.getLValueOffset();
|
||||
if (!Offset.isNegative() && Offset <= Size)
|
||||
Size -= Offset;
|
||||
else
|
||||
Size = 0;
|
||||
return Success(Size, E);
|
||||
Size = CharUnits::Zero();
|
||||
return Success(Size.getQuantity(), E);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Perhaps we should let LLVM lower this?
|
||||
if (E->getArg(0)->HasSideEffects(Info.Ctx)) {
|
||||
if (E->getArg(1)->EvaluateAsInt(Info.Ctx).getZExtValue() == 0)
|
||||
if (E->getArg(1)->EvaluateAsInt(Info.Ctx).getZExtValue() <= 1)
|
||||
return Success(-1ULL, E);
|
||||
return Success(0, E);
|
||||
}
|
||||
@ -1151,7 +1156,7 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
|
||||
if (LHSValue.getLValueBase()) {
|
||||
if (!E->isEqualityOp())
|
||||
return false;
|
||||
if (RHSValue.getLValueBase() || RHSValue.getLValueOffset())
|
||||
if (RHSValue.getLValueBase() || !RHSValue.getLValueOffset().isZero())
|
||||
return false;
|
||||
bool bres;
|
||||
if (!EvalPointerValueAsBool(LHSValue, bres))
|
||||
@ -1160,7 +1165,7 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
|
||||
} else if (RHSValue.getLValueBase()) {
|
||||
if (!E->isEqualityOp())
|
||||
return false;
|
||||
if (LHSValue.getLValueBase() || LHSValue.getLValueOffset())
|
||||
if (LHSValue.getLValueBase() || !LHSValue.getLValueOffset().isZero())
|
||||
return false;
|
||||
bool bres;
|
||||
if (!EvalPointerValueAsBool(RHSValue, bres))
|
||||
@ -1172,11 +1177,13 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
|
||||
const QualType Type = E->getLHS()->getType();
|
||||
const QualType ElementType = Type->getAs<PointerType>()->getPointeeType();
|
||||
|
||||
uint64_t D = LHSValue.getLValueOffset() - RHSValue.getLValueOffset();
|
||||
CharUnits ElementSize = CharUnits::One();
|
||||
if (!ElementType->isVoidType() && !ElementType->isFunctionType())
|
||||
D /= Info.Ctx.getTypeSize(ElementType) / 8;
|
||||
ElementSize = Info.Ctx.getTypeSizeInChars(ElementType);
|
||||
|
||||
return Success(D, E);
|
||||
CharUnits Diff = LHSValue.getLValueOffset() -
|
||||
RHSValue.getLValueOffset();
|
||||
return Success(Diff / ElementSize, E);
|
||||
}
|
||||
bool Result;
|
||||
if (E->getOpcode() == BinaryOperator::EQ) {
|
||||
@ -1204,21 +1211,23 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
|
||||
|
||||
// Handle cases like (unsigned long)&a + 4.
|
||||
if (E->isAdditiveOp() && Result.isLValue() && RHSVal.isInt()) {
|
||||
uint64_t offset = Result.getLValueOffset();
|
||||
CharUnits Offset = Result.getLValueOffset();
|
||||
CharUnits AdditionalOffset = CharUnits::fromQuantity(
|
||||
RHSVal.getInt().getZExtValue());
|
||||
if (E->getOpcode() == BinaryOperator::Add)
|
||||
offset += RHSVal.getInt().getZExtValue();
|
||||
Offset += AdditionalOffset;
|
||||
else
|
||||
offset -= RHSVal.getInt().getZExtValue();
|
||||
Result = APValue(Result.getLValueBase(), offset);
|
||||
Offset -= AdditionalOffset;
|
||||
Result = APValue(Result.getLValueBase(), Offset);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Handle cases like 4 + (unsigned long)&a
|
||||
if (E->getOpcode() == BinaryOperator::Add &&
|
||||
RHSVal.isLValue() && Result.isInt()) {
|
||||
uint64_t offset = RHSVal.getLValueOffset();
|
||||
offset += Result.getInt().getZExtValue();
|
||||
Result = APValue(RHSVal.getLValueBase(), offset);
|
||||
CharUnits Offset = RHSVal.getLValueOffset();
|
||||
Offset += CharUnits::fromQuantity(Result.getInt().getZExtValue());
|
||||
Result = APValue(RHSVal.getLValueBase(), Offset);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1334,8 +1343,7 @@ bool IntExprEvaluator::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E) {
|
||||
return false;
|
||||
|
||||
// Get information about the size.
|
||||
unsigned BitWidth = Info.Ctx.getTypeSize(SrcTy);
|
||||
return Success(BitWidth / Info.Ctx.Target.getCharWidth(), E);
|
||||
return Success(Info.Ctx.getTypeSizeInChars(SrcTy).getQuantity(), E);
|
||||
}
|
||||
|
||||
bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
|
||||
@ -1349,7 +1357,7 @@ bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
|
||||
return false;
|
||||
if (LV.getLValueBase())
|
||||
return false;
|
||||
return Success(LV.getLValueOffset(), E);
|
||||
return Success(LV.getLValueOffset().getQuantity(), E);
|
||||
}
|
||||
|
||||
if (E->getOpcode() == UnaryOperator::LNot) {
|
||||
@ -1432,7 +1440,8 @@ bool IntExprEvaluator::VisitCastExpr(CastExpr *E) {
|
||||
return true;
|
||||
}
|
||||
|
||||
APSInt AsInt = Info.Ctx.MakeIntValue(LV.getLValueOffset(), SrcType);
|
||||
APSInt AsInt = Info.Ctx.MakeIntValue(LV.getLValueOffset().getQuantity(),
|
||||
SrcType);
|
||||
return Success(HandleIntToIntCast(DestType, SrcType, AsInt, Info.Ctx), E);
|
||||
}
|
||||
|
||||
@ -1978,6 +1987,13 @@ bool Expr::EvaluateAsAny(EvalResult &Result, ASTContext &Ctx) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Expr::EvaluateAsBooleanCondition(bool &Result, ASTContext &Ctx) const {
|
||||
EvalResult Scratch;
|
||||
EvalInfo Info(Ctx, Scratch);
|
||||
|
||||
return HandleConversionToBool(this, Result, Info);
|
||||
}
|
||||
|
||||
bool Expr::EvaluateAsLValue(EvalResult &Result, ASTContext &Ctx) const {
|
||||
EvalInfo Info(Ctx, Result);
|
||||
|
||||
|
@ -719,11 +719,6 @@ ASTRecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) {
|
||||
// If a class isnt' polymorphic it doesn't have a key function.
|
||||
if (!RD->isPolymorphic())
|
||||
return 0;
|
||||
|
||||
// A class template specialization or instantation does not have a key
|
||||
// function.
|
||||
if (RD->getTemplateSpecializationKind() != TSK_Undeclared)
|
||||
return 0;
|
||||
|
||||
// A class inside an anonymous namespace doesn't have a key function. (Or
|
||||
// at least, there's no point to assigning a key function to such a class;
|
||||
@ -741,13 +736,13 @@ ASTRecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) {
|
||||
if (MD->isPure())
|
||||
continue;
|
||||
|
||||
if (MD->isInlineSpecified())
|
||||
continue;
|
||||
|
||||
// Ignore implicit member functions, they are always marked as inline, but
|
||||
// they don't have a body until they're defined.
|
||||
if (MD->isImplicit())
|
||||
continue;
|
||||
|
||||
if (MD->isInlineSpecified())
|
||||
continue;
|
||||
|
||||
if (MD->hasInlineBody())
|
||||
continue;
|
||||
|
@ -337,12 +337,12 @@ unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl<AsmStringPiece>&Pieces,
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
AsmStmt::AsmStmt(SourceLocation asmloc, bool issimple, bool isvolatile,
|
||||
unsigned numoutputs, unsigned numinputs,
|
||||
bool msasm, unsigned numoutputs, unsigned numinputs,
|
||||
std::string *names, StringLiteral **constraints,
|
||||
Expr **exprs, StringLiteral *asmstr, unsigned numclobbers,
|
||||
StringLiteral **clobbers, SourceLocation rparenloc)
|
||||
: Stmt(AsmStmtClass), AsmLoc(asmloc), RParenLoc(rparenloc), AsmStr(asmstr)
|
||||
, IsSimple(issimple), IsVolatile(isvolatile)
|
||||
, IsSimple(issimple), IsVolatile(isvolatile), MSAsm(msasm)
|
||||
, NumOutputs(numoutputs), NumInputs(numinputs) {
|
||||
for (unsigned i = 0, e = numinputs + numoutputs; i != e; i++) {
|
||||
Names.push_back(names[i]);
|
||||
|
@ -739,9 +739,10 @@ void StmtPrinter::VisitCallExpr(CallExpr *Call) {
|
||||
void StmtPrinter::VisitMemberExpr(MemberExpr *Node) {
|
||||
// FIXME: Suppress printing implicit bases (like "this")
|
||||
PrintExpr(Node->getBase());
|
||||
if (FieldDecl *FD = dyn_cast<FieldDecl>(Node->getMemberDecl()))
|
||||
if (FD->isAnonymousStructOrUnion())
|
||||
return;
|
||||
OS << (Node->isArrow() ? "->" : ".");
|
||||
// FIXME: Suppress printing references to unnamed objects
|
||||
// representing anonymous unions/structs
|
||||
if (NestedNameSpecifier *Qualifier = Node->getQualifier())
|
||||
Qualifier->print(OS, Policy);
|
||||
|
||||
@ -1120,6 +1121,13 @@ void StmtPrinter::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) {
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitCXXConstructExpr(CXXConstructExpr *E) {
|
||||
// FIXME. For now we just print a trivial constructor call expression,
|
||||
// constructing its first argument object.
|
||||
if (E->getNumArgs() == 1) {
|
||||
CXXConstructorDecl *CD = E->getConstructor();
|
||||
if (CD->isTrivial())
|
||||
PrintExpr(E->getArg(0));
|
||||
}
|
||||
// Nothing to print.
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "clang/AST/TypeLocVisitor.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
using namespace clang;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -123,3 +124,14 @@ bool TypeSpecTypeLoc::classof(const TypeLoc *TL) {
|
||||
if (TL->getType().hasLocalQualifiers()) return false;
|
||||
return TSTChecker().Visit(*TL);
|
||||
}
|
||||
|
||||
// Reimplemented to account for GNU/C++ extension
|
||||
// typeof unary-expression
|
||||
// where there are no parentheses.
|
||||
SourceRange TypeOfExprTypeLoc::getSourceRange() const {
|
||||
if (getRParenLoc().isValid())
|
||||
return SourceRange(getTypeofLoc(), getRParenLoc());
|
||||
else
|
||||
return SourceRange(getTypeofLoc(),
|
||||
getUnderlyingExpr()->getSourceRange().getEnd());
|
||||
}
|
||||
|
@ -271,6 +271,10 @@ void TypePrinter::PrintFunctionProto(const FunctionProtoType *T,
|
||||
|
||||
S += ")";
|
||||
|
||||
if (T->getNoReturnAttr())
|
||||
S += " __attribute__((noreturn))";
|
||||
|
||||
|
||||
if (T->hasExceptionSpec()) {
|
||||
S += " throw(";
|
||||
if (T->hasAnyExceptionSpec())
|
||||
@ -287,10 +291,9 @@ void TypePrinter::PrintFunctionProto(const FunctionProtoType *T,
|
||||
S += ")";
|
||||
}
|
||||
|
||||
if (T->getNoReturnAttr())
|
||||
S += " __attribute__((noreturn))";
|
||||
Print(T->getResultType(), S);
|
||||
AppendTypeQualList(S, T->getTypeQuals());
|
||||
|
||||
Print(T->getResultType(), S);
|
||||
}
|
||||
|
||||
void TypePrinter::PrintFunctionNoProto(const FunctionNoProtoType *T,
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "clang/Analysis/CFG.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/DeclObjC.h"
|
||||
#include "clang/AST/DeclTemplate.h"
|
||||
#include "clang/AST/ParentMap.h"
|
||||
#include "clang/AST/StmtVisitor.h"
|
||||
#include "clang/Analysis/Support/BumpVector.h"
|
||||
@ -38,6 +39,9 @@ Stmt *AnalysisContext::getBody() {
|
||||
return MD->getBody();
|
||||
else if (const BlockDecl *BD = dyn_cast<BlockDecl>(D))
|
||||
return BD->getBody();
|
||||
else if (const FunctionTemplateDecl *FunTmpl
|
||||
= dyn_cast_or_null<FunctionTemplateDecl>(D))
|
||||
return FunTmpl->getTemplatedDecl()->getBody();
|
||||
|
||||
llvm_unreachable("unknown code decl");
|
||||
}
|
||||
|
@ -49,8 +49,9 @@ class BasicConstraintManager
|
||||
: public SimpleConstraintManager {
|
||||
GRState::IntSetTy::Factory ISetFactory;
|
||||
public:
|
||||
BasicConstraintManager(GRStateManager& statemgr)
|
||||
: ISetFactory(statemgr.getAllocator()) {}
|
||||
BasicConstraintManager(GRStateManager &statemgr, GRSubEngine &subengine)
|
||||
: SimpleConstraintManager(subengine),
|
||||
ISetFactory(statemgr.getAllocator()) {}
|
||||
|
||||
const GRState* AssumeSymNE(const GRState* state, SymbolRef sym,
|
||||
const llvm::APSInt& V);
|
||||
@ -88,9 +89,9 @@ public:
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
ConstraintManager* clang::CreateBasicConstraintManager(GRStateManager& StateMgr)
|
||||
{
|
||||
return new BasicConstraintManager(StateMgr);
|
||||
ConstraintManager* clang::CreateBasicConstraintManager(GRStateManager& statemgr,
|
||||
GRSubEngine &subengine) {
|
||||
return new BasicConstraintManager(statemgr, subengine);
|
||||
}
|
||||
|
||||
const GRState*
|
||||
|
@ -1818,8 +1818,23 @@ void BugReporter::FlushReport(BugReportEquivClass& EQ) {
|
||||
R->getRanges(Beg, End);
|
||||
Diagnostic& Diag = getDiagnostic();
|
||||
FullSourceLoc L(R->getLocation(), getSourceManager());
|
||||
unsigned ErrorDiag = Diag.getCustomDiagID(Diagnostic::Warning,
|
||||
R->getShortDescription().c_str());
|
||||
|
||||
// Search the description for '%', as that will be interpretted as a
|
||||
// format character by FormatDiagnostics.
|
||||
llvm::StringRef desc = R->getShortDescription();
|
||||
unsigned ErrorDiag;
|
||||
{
|
||||
llvm::SmallString<512> TmpStr;
|
||||
llvm::raw_svector_ostream Out(TmpStr);
|
||||
for (llvm::StringRef::iterator I=desc.begin(), E=desc.end(); I!=E; ++I)
|
||||
if (*I == '%')
|
||||
Out << "%%";
|
||||
else
|
||||
Out << *I;
|
||||
|
||||
Out.flush();
|
||||
ErrorDiag = Diag.getCustomDiagID(Diagnostic::Warning, TmpStr);
|
||||
}
|
||||
|
||||
switch (End-Beg) {
|
||||
default: assert(0 && "Don't handle this many ranges yet!");
|
||||
|
@ -52,8 +52,8 @@ using namespace clang;
|
||||
// not release it."
|
||||
//
|
||||
|
||||
using llvm::CStrInCStrNoCase;
|
||||
using llvm::StringsEqualNoCase;
|
||||
using llvm::StrInStrNoCase;
|
||||
using llvm::StringRef;
|
||||
|
||||
enum NamingConvention { NoConvention, CreateRule, InitRule };
|
||||
|
||||
@ -122,20 +122,20 @@ static NamingConvention deriveNamingConvention(Selector S) {
|
||||
break;
|
||||
case 3:
|
||||
// Methods starting with 'new' follow the create rule.
|
||||
if (AtBeginning && StringsEqualNoCase("new", s, len))
|
||||
if (AtBeginning && StringRef(s, len).equals_lower("new"))
|
||||
C = CreateRule;
|
||||
break;
|
||||
case 4:
|
||||
// Methods starting with 'alloc' or contain 'copy' follow the
|
||||
// create rule
|
||||
if (C == NoConvention && StringsEqualNoCase("copy", s, len))
|
||||
if (C == NoConvention && StringRef(s, len).equals_lower("copy"))
|
||||
C = CreateRule;
|
||||
else // Methods starting with 'init' follow the init rule.
|
||||
if (AtBeginning && StringsEqualNoCase("init", s, len))
|
||||
if (AtBeginning && StringRef(s, len).equals_lower("init"))
|
||||
C = InitRule;
|
||||
break;
|
||||
case 5:
|
||||
if (AtBeginning && StringsEqualNoCase("alloc", s, len))
|
||||
if (AtBeginning && StringRef(s, len).equals_lower("alloc"))
|
||||
C = CreateRule;
|
||||
break;
|
||||
}
|
||||
@ -1372,11 +1372,11 @@ RetainSummary* RetainSummaryManager::getSummary(FunctionDecl* FD) {
|
||||
// "AppendValue", or "SetAttribute", then we assume that arguments may
|
||||
// "escape." This means that something else holds on to the object,
|
||||
// allowing it be used even after its local retain count drops to 0.
|
||||
ArgEffect E = (CStrInCStrNoCase(FName, "InsertValue") ||
|
||||
CStrInCStrNoCase(FName, "AddValue") ||
|
||||
CStrInCStrNoCase(FName, "SetValue") ||
|
||||
CStrInCStrNoCase(FName, "AppendValue") ||
|
||||
CStrInCStrNoCase(FName, "SetAttribute"))
|
||||
ArgEffect E = (StrInStrNoCase(FName, "InsertValue") != StringRef::npos||
|
||||
StrInStrNoCase(FName, "AddValue") != StringRef::npos ||
|
||||
StrInStrNoCase(FName, "SetValue") != StringRef::npos ||
|
||||
StrInStrNoCase(FName, "AppendValue") != StringRef::npos||
|
||||
StrInStrNoCase(FName, "SetAttribute") != StringRef::npos)
|
||||
? MayEscape : DoNothing;
|
||||
|
||||
S = getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, E);
|
||||
@ -1555,7 +1555,8 @@ RetainSummaryManager::getCommonMethodSummary(const ObjCMethodDecl* MD,
|
||||
if (S.isKeywordSelector()) {
|
||||
const std::string &str = S.getAsString();
|
||||
assert(!str.empty());
|
||||
if (CStrInCStrNoCase(&str[0], "delegate:")) ReceiverEff = StopTracking;
|
||||
if (StrInStrNoCase(str, "delegate:") != StringRef::npos)
|
||||
ReceiverEff = StopTracking;
|
||||
}
|
||||
|
||||
// Look for methods that return an owned object.
|
||||
|
@ -11,6 +11,7 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
#include "clang/Analysis/PathSensitive/BugReporter.h"
|
||||
#include "clang/Analysis/LocalCheckers.h"
|
||||
#include "clang/AST/StmtVisitor.h"
|
||||
@ -18,6 +19,12 @@
|
||||
|
||||
using namespace clang;
|
||||
|
||||
static bool isArc4RandomAvailable(const ASTContext &Ctx) {
|
||||
const llvm::Triple &T = Ctx.Target.getTriple();
|
||||
return T.getVendor() == llvm::Triple::Apple ||
|
||||
T.getOS() == llvm::Triple::FreeBSD;
|
||||
}
|
||||
|
||||
namespace {
|
||||
class WalkAST : public StmtVisitor<WalkAST> {
|
||||
BugReporter &BR;
|
||||
@ -29,11 +36,14 @@ class WalkAST : public StmtVisitor<WalkAST> {
|
||||
IdentifierInfo *II_random;
|
||||
enum { num_setids = 6 };
|
||||
IdentifierInfo *II_setid[num_setids];
|
||||
|
||||
const bool CheckRand;
|
||||
|
||||
public:
|
||||
WalkAST(BugReporter &br) : BR(br),
|
||||
II_gets(0), II_getpw(0), II_mktemp(0),
|
||||
II_rand(), II_random(0), II_setid() {}
|
||||
II_rand(), II_random(0), II_setid(),
|
||||
CheckRand(isArc4RandomAvailable(BR.getContext())) {}
|
||||
|
||||
// Statement visitor methods.
|
||||
void VisitCallExpr(CallExpr *CE);
|
||||
@ -83,8 +93,10 @@ void WalkAST::VisitCallExpr(CallExpr *CE) {
|
||||
CheckCall_gets(CE, FD);
|
||||
CheckCall_getpw(CE, FD);
|
||||
CheckCall_mktemp(CE, FD);
|
||||
CheckCall_rand(CE, FD);
|
||||
CheckCall_random(CE, FD);
|
||||
if (CheckRand) {
|
||||
CheckCall_rand(CE, FD);
|
||||
CheckCall_random(CE, FD);
|
||||
}
|
||||
}
|
||||
|
||||
// Recurse and check children.
|
||||
|
@ -37,7 +37,12 @@ SVal Environment::GetSVal(const Stmt *E, ValueManager& ValMgr) const {
|
||||
}
|
||||
|
||||
case Stmt::IntegerLiteralClass: {
|
||||
return ValMgr.makeIntVal(cast<IntegerLiteral>(E));
|
||||
// In C++, this expression may have been bound to a temporary object.
|
||||
SVal const *X = ExprBindings.lookup(E);
|
||||
if (X)
|
||||
return *X;
|
||||
else
|
||||
return ValMgr.makeIntVal(cast<IntegerLiteral>(E));
|
||||
}
|
||||
|
||||
// Casts where the source and target type are the same
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
|
||||
#include "clang/Analysis/PathSensitive/GRExprEngineBuilders.h"
|
||||
#include "clang/Analysis/PathSensitive/Checker.h"
|
||||
#include "clang/AST/CharUnits.h"
|
||||
#include "clang/AST/ParentMap.h"
|
||||
#include "clang/AST/StmtObjC.h"
|
||||
#include "clang/Basic/Builtins.h"
|
||||
@ -47,10 +48,9 @@ static inline Selector GetNullarySelector(const char* name, ASTContext& Ctx) {
|
||||
}
|
||||
|
||||
|
||||
static bool CalleeReturnsReference(const CallExpr *CE) {
|
||||
static QualType GetCalleeReturnType(const CallExpr *CE) {
|
||||
const Expr *Callee = CE->getCallee();
|
||||
QualType T = Callee->getType();
|
||||
|
||||
if (const PointerType *PT = T->getAs<PointerType>()) {
|
||||
const FunctionType *FT = PT->getPointeeType()->getAs<FunctionType>();
|
||||
T = FT->getResultType();
|
||||
@ -58,17 +58,36 @@ static bool CalleeReturnsReference(const CallExpr *CE) {
|
||||
else {
|
||||
const BlockPointerType *BT = T->getAs<BlockPointerType>();
|
||||
T = BT->getPointeeType()->getAs<FunctionType>()->getResultType();
|
||||
}
|
||||
return T->isReferenceType();
|
||||
}
|
||||
return T;
|
||||
}
|
||||
|
||||
static bool CalleeReturnsReference(const CallExpr *CE) {
|
||||
return (bool) GetCalleeReturnType(CE)->getAs<ReferenceType>();
|
||||
}
|
||||
|
||||
static bool ReceiverReturnsReference(const ObjCMessageExpr *ME) {
|
||||
const ObjCMethodDecl *MD = ME->getMethodDecl();
|
||||
if (!MD)
|
||||
return false;
|
||||
return MD->getResultType()->isReferenceType();
|
||||
return MD->getResultType()->getAs<ReferenceType>();
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
static bool ReceiverReturnsReferenceOrRecord(const ObjCMessageExpr *ME) {
|
||||
const ObjCMethodDecl *MD = ME->getMethodDecl();
|
||||
if (!MD)
|
||||
return false;
|
||||
QualType T = MD->getResultType();
|
||||
return T->getAs<RecordType>() || T->getAs<ReferenceType>();
|
||||
}
|
||||
|
||||
static bool CalleeReturnsReferenceOrRecord(const CallExpr *CE) {
|
||||
QualType T = GetCalleeReturnType(CE);
|
||||
return T->getAs<ReferenceType>() || T->getAs<RecordType>();
|
||||
}
|
||||
#endif
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Batch auditor. DEPRECATED.
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -300,23 +319,27 @@ static void RegisterInternalChecks(GRExprEngine &Eng) {
|
||||
RegisterOSAtomicChecker(Eng);
|
||||
}
|
||||
|
||||
GRExprEngine::GRExprEngine(AnalysisManager &mgr)
|
||||
GRExprEngine::GRExprEngine(AnalysisManager &mgr, GRTransferFuncs *tf)
|
||||
: AMgr(mgr),
|
||||
CoreEngine(mgr.getASTContext(), *this),
|
||||
G(CoreEngine.getGraph()),
|
||||
Builder(NULL),
|
||||
StateMgr(G.getContext(), mgr.getStoreManagerCreator(),
|
||||
mgr.getConstraintManagerCreator(), G.getAllocator()),
|
||||
mgr.getConstraintManagerCreator(), G.getAllocator(),
|
||||
*this),
|
||||
SymMgr(StateMgr.getSymbolManager()),
|
||||
ValMgr(StateMgr.getValueManager()),
|
||||
SVator(ValMgr.getSValuator()),
|
||||
CurrentStmt(NULL),
|
||||
NSExceptionII(NULL), NSExceptionInstanceRaiseSelectors(NULL),
|
||||
RaiseSel(GetNullarySelector("raise", G.getContext())),
|
||||
BR(mgr, *this)
|
||||
{
|
||||
BR(mgr, *this), TF(tf) {
|
||||
// Register internal checks.
|
||||
RegisterInternalChecks(*this);
|
||||
|
||||
// FIXME: Eventually remove the TF object entirely.
|
||||
TF->RegisterChecks(*this);
|
||||
TF->RegisterPrinters(getStateManager().Printers);
|
||||
}
|
||||
|
||||
GRExprEngine::~GRExprEngine() {
|
||||
@ -330,13 +353,6 @@ GRExprEngine::~GRExprEngine() {
|
||||
// Utility methods.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void GRExprEngine::setTransferFunctionsAndCheckers(GRTransferFuncs* tf) {
|
||||
StateMgr.TF = tf;
|
||||
StateMgr.Checkers = &Checkers;
|
||||
tf->RegisterChecks(*this);
|
||||
tf->RegisterPrinters(getStateManager().Printers);
|
||||
}
|
||||
|
||||
void GRExprEngine::AddCheck(GRSimpleAPICheck* A, Stmt::StmtClass C) {
|
||||
if (!BatchAuditor)
|
||||
BatchAuditor.reset(new MappedBatchAuditor(getGraph().getAllocator()));
|
||||
@ -415,6 +431,25 @@ const GRState* GRExprEngine::getInitialState(const LocationContext *InitLoc) {
|
||||
// Top-level transfer function logic (Dispatcher).
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// EvalAssume - Called by ConstraintManager. Used to call checker-specific
|
||||
/// logic for handling assumptions on symbolic values.
|
||||
const GRState *GRExprEngine::ProcessAssume(const GRState *state, SVal cond,
|
||||
bool assumption) {
|
||||
for (CheckersOrdered::iterator I = Checkers.begin(), E = Checkers.end();
|
||||
I != E; ++I) {
|
||||
|
||||
if (!state)
|
||||
return NULL;
|
||||
|
||||
state = I->second->EvalAssume(state, cond, assumption);
|
||||
}
|
||||
|
||||
if (!state)
|
||||
return NULL;
|
||||
|
||||
return TF->EvalAssume(state, cond, assumption);
|
||||
}
|
||||
|
||||
void GRExprEngine::ProcessStmt(CFGElement CE, GRStmtNodeBuilder& builder) {
|
||||
CurrentStmt = CE.getStmt();
|
||||
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
|
||||
@ -809,7 +844,7 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred,
|
||||
case Stmt::CallExprClass:
|
||||
case Stmt::CXXOperatorCallExprClass: {
|
||||
CallExpr *C = cast<CallExpr>(Ex);
|
||||
assert(CalleeReturnsReference(C));
|
||||
assert(CalleeReturnsReferenceOrRecord(C));
|
||||
VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst, true);
|
||||
break;
|
||||
}
|
||||
@ -840,7 +875,7 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred,
|
||||
|
||||
case Stmt::ObjCMessageExprClass: {
|
||||
ObjCMessageExpr *ME = cast<ObjCMessageExpr>(Ex);
|
||||
assert(ReceiverReturnsReference(ME));
|
||||
assert(ReceiverReturnsReferenceOrRecord(ME));
|
||||
VisitObjCMessageExpr(ME, Pred, Dst, true);
|
||||
return;
|
||||
}
|
||||
@ -871,6 +906,11 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred,
|
||||
case Stmt::UnaryOperatorClass:
|
||||
VisitUnaryOperator(cast<UnaryOperator>(Ex), Pred, Dst, true);
|
||||
return;
|
||||
|
||||
// In C++, binding an rvalue to a reference requires to create an object.
|
||||
case Stmt::IntegerLiteralClass:
|
||||
CreateCXXTemporaryObject(Ex, Pred, Dst);
|
||||
return;
|
||||
|
||||
default:
|
||||
// Arbitrary subexpressions can return aggregate temporaries that
|
||||
@ -1205,7 +1245,8 @@ void GRExprEngine::ProcessSwitch(GRSwitchNodeBuilder& builder) {
|
||||
|
||||
do {
|
||||
nonloc::ConcreteInt CaseVal(getBasicVals().getValue(V1.Val.getInt()));
|
||||
DefinedOrUnknownSVal Res = SVator.EvalEQ(DefaultSt, CondV, CaseVal);
|
||||
DefinedOrUnknownSVal Res = SVator.EvalEQ(DefaultSt ? DefaultSt : state,
|
||||
CondV, CaseVal);
|
||||
|
||||
// Now "assume" that the case matches.
|
||||
if (const GRState* stateNew = state->Assume(Res, true)) {
|
||||
@ -1220,11 +1261,17 @@ void GRExprEngine::ProcessSwitch(GRSwitchNodeBuilder& builder) {
|
||||
|
||||
// Now "assume" that the case doesn't match. Add this state
|
||||
// to the default state (if it is feasible).
|
||||
if (const GRState *stateNew = DefaultSt->Assume(Res, false)) {
|
||||
defaultIsFeasible = true;
|
||||
DefaultSt = stateNew;
|
||||
if (DefaultSt) {
|
||||
if (const GRState *stateNew = DefaultSt->Assume(Res, false)) {
|
||||
defaultIsFeasible = true;
|
||||
DefaultSt = stateNew;
|
||||
}
|
||||
else {
|
||||
defaultIsFeasible = false;
|
||||
DefaultSt = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Concretize the next value in the range.
|
||||
if (V1.Val.getInt() == V2.Val.getInt())
|
||||
break;
|
||||
@ -2375,12 +2422,12 @@ void GRExprEngine::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex,
|
||||
ExplodedNode* Pred,
|
||||
ExplodedNodeSet& Dst) {
|
||||
QualType T = Ex->getTypeOfArgument();
|
||||
uint64_t amt;
|
||||
CharUnits amt;
|
||||
|
||||
if (Ex->isSizeOf()) {
|
||||
if (T == getContext().VoidTy) {
|
||||
// sizeof(void) == 1 byte.
|
||||
amt = 1;
|
||||
amt = CharUnits::One();
|
||||
}
|
||||
else if (!T.getTypePtr()->isConstantSizeType()) {
|
||||
// FIXME: Add support for VLAs.
|
||||
@ -2394,14 +2441,15 @@ void GRExprEngine::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex,
|
||||
}
|
||||
else {
|
||||
// All other cases.
|
||||
amt = getContext().getTypeSize(T) / 8;
|
||||
amt = getContext().getTypeSizeInChars(T);
|
||||
}
|
||||
}
|
||||
else // Get alignment of the type.
|
||||
amt = getContext().getTypeAlign(T) / 8;
|
||||
amt = CharUnits::fromQuantity(getContext().getTypeAlign(T) / 8);
|
||||
|
||||
MakeNode(Dst, Ex, Pred,
|
||||
GetState(Pred)->BindExpr(Ex, ValMgr.makeIntVal(amt, Ex->getType())));
|
||||
GetState(Pred)->BindExpr(Ex,
|
||||
ValMgr.makeIntVal(amt.getQuantity(), Ex->getType())));
|
||||
}
|
||||
|
||||
|
||||
@ -2695,8 +2743,13 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred,
|
||||
void GRExprEngine::VisitCXXThisExpr(CXXThisExpr *TE, ExplodedNode *Pred,
|
||||
ExplodedNodeSet & Dst) {
|
||||
// Get the this object region from StoreManager.
|
||||
Loc V = getStoreManager().getThisObject(TE->getType()->getPointeeType());
|
||||
MakeNode(Dst, TE, Pred, GetState(Pred)->BindExpr(TE, V));
|
||||
const MemRegion *R =
|
||||
ValMgr.getRegionManager().getCXXThisRegion(TE->getType(),
|
||||
Pred->getLocationContext());
|
||||
|
||||
const GRState *state = GetState(Pred);
|
||||
SVal V = state->getSVal(loc::MemRegionVal(R));
|
||||
MakeNode(Dst, TE, Pred, state->BindExpr(TE, V));
|
||||
}
|
||||
|
||||
void GRExprEngine::VisitAsmStmt(AsmStmt* A, ExplodedNode* Pred,
|
||||
@ -2964,6 +3017,26 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
|
||||
CheckerVisit(B, Dst, Tmp3, false);
|
||||
}
|
||||
|
||||
void GRExprEngine::CreateCXXTemporaryObject(Expr *Ex, ExplodedNode *Pred,
|
||||
ExplodedNodeSet &Dst) {
|
||||
ExplodedNodeSet Tmp;
|
||||
Visit(Ex, Pred, Tmp);
|
||||
for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) {
|
||||
const GRState *state = GetState(*I);
|
||||
|
||||
// Bind the temporary object to the value of the expression. Then bind
|
||||
// the expression to the location of the object.
|
||||
SVal V = state->getSVal(Ex);
|
||||
|
||||
const MemRegion *R =
|
||||
ValMgr.getRegionManager().getCXXObjectRegion(Ex,
|
||||
Pred->getLocationContext());
|
||||
|
||||
state = state->bindLoc(loc::MemRegionVal(R), V);
|
||||
MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, loc::MemRegionVal(R)));
|
||||
}
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Checker registration/lookup.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -267,6 +267,9 @@ bool ScanReachableSymbols::scan(SVal val) {
|
||||
if (loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(&val))
|
||||
return scan(X->getRegion());
|
||||
|
||||
if (nonloc::LocAsInteger *X = dyn_cast<nonloc::LocAsInteger>(&val))
|
||||
return scan(X->getLoc());
|
||||
|
||||
if (SymbolRef Sym = val.getAsSymbol())
|
||||
return visitor.VisitSymbol(Sym);
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "clang/Analysis/PathSensitive/MemRegion.h"
|
||||
#include "clang/Analysis/PathSensitive/ValueManager.h"
|
||||
#include "clang/Analysis/PathSensitive/AnalysisContext.h"
|
||||
#include "clang/AST/CharUnits.h"
|
||||
#include "clang/AST/StmtVisitor.h"
|
||||
|
||||
using namespace clang;
|
||||
@ -215,6 +216,18 @@ void CompoundLiteralRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
|
||||
ID.AddPointer(superRegion);
|
||||
}
|
||||
|
||||
void CXXThisRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
|
||||
const PointerType *PT,
|
||||
const MemRegion *sRegion) {
|
||||
ID.AddInteger((unsigned) CXXThisRegionKind);
|
||||
ID.AddPointer(PT);
|
||||
ID.AddPointer(sRegion);
|
||||
}
|
||||
|
||||
void CXXThisRegion::Profile(llvm::FoldingSetNodeID &ID) const {
|
||||
CXXThisRegion::ProfileRegion(ID, ThisPointerTy, superRegion);
|
||||
}
|
||||
|
||||
void DeclRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, const Decl* D,
|
||||
const MemRegion* superRegion, Kind k) {
|
||||
ID.AddInteger((unsigned) k);
|
||||
@ -292,14 +305,14 @@ void BlockDataRegion::Profile(llvm::FoldingSetNodeID& ID) const {
|
||||
}
|
||||
|
||||
void CXXObjectRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,
|
||||
QualType T,
|
||||
Expr const *Ex,
|
||||
const MemRegion *sReg) {
|
||||
ID.AddPointer(T.getTypePtr());
|
||||
ID.AddPointer(Ex);
|
||||
ID.AddPointer(sReg);
|
||||
}
|
||||
|
||||
void CXXObjectRegion::Profile(llvm::FoldingSetNodeID &ID) const {
|
||||
ProfileRegion(ID, T, getSuperRegion());
|
||||
ProfileRegion(ID, Ex, getSuperRegion());
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -343,6 +356,10 @@ void CompoundLiteralRegion::dumpToStream(llvm::raw_ostream& os) const {
|
||||
os << "{ " << (void*) CL << " }";
|
||||
}
|
||||
|
||||
void CXXThisRegion::dumpToStream(llvm::raw_ostream &os) const {
|
||||
os << "this";
|
||||
}
|
||||
|
||||
void ElementRegion::dumpToStream(llvm::raw_ostream& os) const {
|
||||
os << "element{" << superRegion << ','
|
||||
<< Index << ',' << getElementType().getAsString() << '}';
|
||||
@ -551,7 +568,7 @@ const SymbolicRegion *MemRegionManager::getSymbolicRegion(SymbolRef sym) {
|
||||
return getSubRegion<SymbolicRegion>(sym, getUnknownRegion());
|
||||
}
|
||||
|
||||
const FieldRegion *
|
||||
const FieldRegion*
|
||||
MemRegionManager::getFieldRegion(const FieldDecl* d,
|
||||
const MemRegion* superRegion){
|
||||
return getSubRegion<FieldRegion>(d, superRegion);
|
||||
@ -563,9 +580,22 @@ MemRegionManager::getObjCIvarRegion(const ObjCIvarDecl* d,
|
||||
return getSubRegion<ObjCIvarRegion>(d, superRegion);
|
||||
}
|
||||
|
||||
const CXXObjectRegion *
|
||||
MemRegionManager::getCXXObjectRegion(QualType T) {
|
||||
return getSubRegion<CXXObjectRegion>(T, getUnknownRegion());
|
||||
const CXXObjectRegion*
|
||||
MemRegionManager::getCXXObjectRegion(Expr const *E,
|
||||
LocationContext const *LC) {
|
||||
const StackFrameContext *SFC = LC->getCurrentStackFrame();
|
||||
assert(SFC);
|
||||
return getSubRegion<CXXObjectRegion>(E, getStackLocalsRegion(SFC));
|
||||
}
|
||||
|
||||
const CXXThisRegion*
|
||||
MemRegionManager::getCXXThisRegion(QualType thisPointerTy,
|
||||
const LocationContext *LC) {
|
||||
const StackFrameContext *STC = LC->getCurrentStackFrame();
|
||||
assert(STC);
|
||||
const PointerType *PT = thisPointerTy->getAs<PointerType>();
|
||||
assert(PT);
|
||||
return getSubRegion<CXXThisRegion>(PT, getStackArgumentsRegion(STC));
|
||||
}
|
||||
|
||||
const AllocaRegion*
|
||||
@ -592,20 +622,11 @@ bool MemRegion::hasStackStorage() const {
|
||||
return isa<StackSpaceRegion>(getMemorySpace());
|
||||
}
|
||||
|
||||
bool MemRegion::hasHeapStorage() const {
|
||||
return isa<HeapSpaceRegion>(getMemorySpace());
|
||||
bool MemRegion::hasStackNonParametersStorage() const {
|
||||
return isa<StackLocalsSpaceRegion>(getMemorySpace());
|
||||
}
|
||||
|
||||
bool MemRegion::hasHeapOrStackStorage() const {
|
||||
const MemSpaceRegion *MS = getMemorySpace();
|
||||
return isa<StackSpaceRegion>(MS) || isa<HeapSpaceRegion>(MS);
|
||||
}
|
||||
|
||||
bool MemRegion::hasGlobalsStorage() const {
|
||||
return isa<GlobalsSpaceRegion>(getMemorySpace());
|
||||
}
|
||||
|
||||
bool MemRegion::hasParametersStorage() const {
|
||||
bool MemRegion::hasStackParametersStorage() const {
|
||||
return isa<StackArgumentsSpaceRegion>(getMemorySpace());
|
||||
}
|
||||
|
||||
@ -669,7 +690,7 @@ static bool IsCompleteType(ASTContext &Ctx, QualType Ty) {
|
||||
}
|
||||
|
||||
RegionRawOffset ElementRegion::getAsRawOffset() const {
|
||||
int64_t offset = 0;
|
||||
CharUnits offset = CharUnits::Zero();
|
||||
const ElementRegion *ER = this;
|
||||
const MemRegion *superR = NULL;
|
||||
ASTContext &C = getContext();
|
||||
@ -694,7 +715,7 @@ RegionRawOffset ElementRegion::getAsRawOffset() const {
|
||||
break;
|
||||
}
|
||||
|
||||
int64_t size = (int64_t) (C.getTypeSize(elemType) / 8);
|
||||
CharUnits size = C.getTypeSizeInChars(elemType);
|
||||
offset += (i * size);
|
||||
}
|
||||
|
||||
@ -707,7 +728,7 @@ RegionRawOffset ElementRegion::getAsRawOffset() const {
|
||||
}
|
||||
|
||||
assert(superR && "super region cannot be NULL");
|
||||
return RegionRawOffset(superR, offset);
|
||||
return RegionRawOffset(superR, offset.getQuantity());
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -103,19 +103,9 @@ bool OSAtomicChecker::EvalOSAtomicCompareAndSwap(CheckerContext &C,
|
||||
SVal location = state->getSVal(theValueExpr);
|
||||
// Here we should use the value type of the region as the load type.
|
||||
QualType LoadTy;
|
||||
if (const MemRegion *R = location.getAsRegion()) {
|
||||
// We must be careful, as SymbolicRegions aren't typed.
|
||||
const MemRegion *strippedR = R->StripCasts();
|
||||
// FIXME: This isn't quite the right solution. One test case in 'test/Analysis/NSString.m'
|
||||
// is giving the wrong result.
|
||||
const TypedRegion *typedR =
|
||||
isa<SymbolicRegion>(strippedR) ? cast<TypedRegion>(R) :
|
||||
dyn_cast<TypedRegion>(strippedR);
|
||||
|
||||
if (typedR) {
|
||||
LoadTy = typedR->getValueType(Ctx);
|
||||
location = loc::MemRegionVal(typedR);
|
||||
}
|
||||
if (const TypedRegion *TR =
|
||||
dyn_cast_or_null<TypedRegion>(location.getAsRegion())) {
|
||||
LoadTy = TR->getValueType(Ctx);
|
||||
}
|
||||
Engine.EvalLoad(Tmp, const_cast<Expr *>(theValueExpr), C.getPredecessor(),
|
||||
state, location, OSAtomicLoadTag, LoadTy);
|
||||
@ -184,14 +174,22 @@ bool OSAtomicChecker::EvalOSAtomicCompareAndSwap(CheckerContext &C,
|
||||
E2 = TmpStore.end(); I2 != E2; ++I2) {
|
||||
ExplodedNode *predNew = *I2;
|
||||
const GRState *stateNew = predNew->getState();
|
||||
SVal Res = Engine.getValueManager().makeTruthVal(true, CE->getType());
|
||||
// Check for 'void' return type if we have a bogus function prototype.
|
||||
SVal Res = UnknownVal();
|
||||
QualType T = CE->getType();
|
||||
if (!T->isVoidType())
|
||||
Res = Engine.getValueManager().makeTruthVal(true, T);
|
||||
C.GenerateNode(stateNew->BindExpr(CE, Res), predNew);
|
||||
}
|
||||
}
|
||||
|
||||
// Were they not equal?
|
||||
if (const GRState *stateNotEqual = stateLoad->Assume(Cmp, false)) {
|
||||
SVal Res = Engine.getValueManager().makeTruthVal(false, CE->getType());
|
||||
// Check for 'void' return type if we have a bogus function prototype.
|
||||
SVal Res = UnknownVal();
|
||||
QualType T = CE->getType();
|
||||
if (!T->isVoidType())
|
||||
Res = Engine.getValueManager().makeTruthVal(false, CE->getType());
|
||||
C.GenerateNode(stateNotEqual->BindExpr(CE, Res), N);
|
||||
}
|
||||
}
|
||||
|
@ -234,7 +234,8 @@ namespace {
|
||||
class RangeConstraintManager : public SimpleConstraintManager{
|
||||
RangeSet GetRange(const GRState *state, SymbolRef sym);
|
||||
public:
|
||||
RangeConstraintManager() {}
|
||||
RangeConstraintManager(GRSubEngine &subengine)
|
||||
: SimpleConstraintManager(subengine) {}
|
||||
|
||||
const GRState* AssumeSymNE(const GRState* St, SymbolRef sym,
|
||||
const llvm::APSInt& V);
|
||||
@ -273,8 +274,9 @@ private:
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
ConstraintManager* clang::CreateRangeConstraintManager(GRStateManager&) {
|
||||
return new RangeConstraintManager();
|
||||
ConstraintManager* clang::CreateRangeConstraintManager(GRStateManager&,
|
||||
GRSubEngine &subeng) {
|
||||
return new RangeConstraintManager(subeng);
|
||||
}
|
||||
|
||||
const llvm::APSInt* RangeConstraintManager::getSymVal(const GRState* St,
|
||||
|
@ -28,9 +28,12 @@
|
||||
|
||||
using namespace clang;
|
||||
|
||||
#define HEAP_UNDEFINED 0
|
||||
#define USE_EXPLICIT_COMPOUND 0
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Representation of value bindings.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace {
|
||||
class BindingVal {
|
||||
public:
|
||||
@ -77,8 +80,41 @@ llvm::raw_ostream& operator<<(llvm::raw_ostream& os, BindingVal V) {
|
||||
}
|
||||
} // end llvm namespace
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Representation of binding keys.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace {
|
||||
class BindingKey : public std::pair<const MemRegion*, uint64_t> {
|
||||
public:
|
||||
explicit BindingKey(const MemRegion *r, uint64_t offset)
|
||||
: std::pair<const MemRegion*,uint64_t>(r, offset) { assert(r); }
|
||||
|
||||
const MemRegion *getRegion() const { return first; }
|
||||
uint64_t getOffset() const { return second; }
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID& ID) const {
|
||||
ID.AddPointer(getRegion());
|
||||
ID.AddInteger(getOffset());
|
||||
}
|
||||
|
||||
static BindingKey Make(const MemRegion *R);
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
namespace llvm {
|
||||
static inline
|
||||
llvm::raw_ostream& operator<<(llvm::raw_ostream& os, BindingKey K) {
|
||||
os << '(' << K.getRegion() << ',' << K.getOffset() << ')';
|
||||
return os;
|
||||
}
|
||||
} // end llvm namespace
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Actual Store type.
|
||||
typedef llvm::ImmutableMap<const MemRegion*, BindingVal> RegionBindings;
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
typedef llvm::ImmutableMap<BindingKey, BindingVal> RegionBindings;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Fine-grained control of RegionStoreManager.
|
||||
@ -283,6 +319,16 @@ private:
|
||||
void RemoveSubRegionBindings(RegionBindings &B, const MemRegion *R,
|
||||
RegionStoreSubRegionMap &M);
|
||||
|
||||
RegionBindings Add(RegionBindings B, BindingKey K, BindingVal V);
|
||||
RegionBindings Add(RegionBindings B, const MemRegion *R, BindingVal V);
|
||||
|
||||
const BindingVal *Lookup(RegionBindings B, BindingKey K);
|
||||
const BindingVal *Lookup(RegionBindings B, const MemRegion *R);
|
||||
|
||||
RegionBindings Remove(RegionBindings B, BindingKey K);
|
||||
RegionBindings Remove(RegionBindings B, const MemRegion *R);
|
||||
Store Remove(Store store, BindingKey K);
|
||||
|
||||
public:
|
||||
const GRState *Bind(const GRState *state, Loc LV, SVal V);
|
||||
|
||||
@ -308,6 +354,7 @@ public:
|
||||
Store KillStruct(Store store, const TypedRegion* R);
|
||||
|
||||
Store Remove(Store store, Loc LV);
|
||||
|
||||
|
||||
//===------------------------------------------------------------------===//
|
||||
// Loading values from regions.
|
||||
@ -438,7 +485,7 @@ RegionStoreManager::getRegionStoreSubRegionMap(Store store) {
|
||||
llvm::SmallVector<const SubRegion*, 10> WL;
|
||||
|
||||
for (RegionBindings::iterator I=B.begin(), E=B.end(); I!=E; ++I)
|
||||
if (const SubRegion *R = dyn_cast<SubRegion>(I.getKey()))
|
||||
if (const SubRegion *R = dyn_cast<SubRegion>(I.getKey().getRegion()))
|
||||
M->process(WL, R);
|
||||
|
||||
// We also need to record in the subregion map "intermediate" regions that
|
||||
@ -467,8 +514,8 @@ void RegionStoreManager::RemoveSubRegionBindings(RegionBindings &B,
|
||||
|
||||
for (llvm::tie(I, E) = M.begin_end(R); I != E; ++I)
|
||||
RemoveSubRegionBindings(B, *I, M);
|
||||
|
||||
B = RBFactory.Remove(B, R);
|
||||
|
||||
B = Remove(B, R);
|
||||
}
|
||||
|
||||
const GRState *RegionStoreManager::InvalidateRegions(const GRState *state,
|
||||
@ -544,8 +591,8 @@ const GRState *RegionStoreManager::InvalidateRegions(const GRState *state,
|
||||
// Invalidate the region by setting its default value to
|
||||
// conjured symbol. The type of the symbol is irrelavant.
|
||||
DefinedOrUnknownSVal V = ValMgr.getConjuredSymbolVal(R, Ex, Ctx.IntTy,
|
||||
Count);
|
||||
B = RBFactory.Add(B, R, BindingVal(V, BindingVal::Default));
|
||||
Count);
|
||||
B = Add(B, R, BindingVal(V, BindingVal::Default));
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -566,7 +613,7 @@ const GRState *RegionStoreManager::InvalidateRegions(const GRState *state,
|
||||
// conjured symbol. The type of the symbol is irrelavant.
|
||||
DefinedOrUnknownSVal V = ValMgr.getConjuredSymbolVal(R, Ex, Ctx.IntTy,
|
||||
Count);
|
||||
B = RBFactory.Add(B, R, BindingVal(V, BindingVal::Default));
|
||||
B = Add(B, R, BindingVal(V, BindingVal::Default));
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -574,7 +621,7 @@ const GRState *RegionStoreManager::InvalidateRegions(const GRState *state,
|
||||
// Set the default value of the array to conjured symbol.
|
||||
DefinedOrUnknownSVal V =
|
||||
ValMgr.getConjuredSymbolVal(R, Ex, AT->getElementType(), Count);
|
||||
B = RBFactory.Add(B, R, BindingVal(V, BindingVal::Default));
|
||||
B = Add(B, R, BindingVal(V, BindingVal::Default));
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -583,14 +630,14 @@ const GRState *RegionStoreManager::InvalidateRegions(const GRState *state,
|
||||
// For fields and elements whose super region has also been invalidated,
|
||||
// only remove the old binding. The super region will get set with a
|
||||
// default value from which we can lazily derive a new symbolic value.
|
||||
B = RBFactory.Remove(B, R);
|
||||
B = Remove(B, R);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Invalidate the binding.
|
||||
DefinedOrUnknownSVal V = ValMgr.getConjuredSymbolVal(R, Ex, T, Count);
|
||||
assert(SymbolManager::canSymbolicate(T) || V.isUnknown());
|
||||
B = RBFactory.Add(B, R, BindingVal(V, BindingVal::Direct));
|
||||
B = Add(B, R, BindingVal(V, BindingVal::Direct));
|
||||
}
|
||||
|
||||
// Create a new state with the updated bindings.
|
||||
@ -723,6 +770,8 @@ DefinedOrUnknownSVal RegionStoreManager::getSizeInElements(const GRState *state,
|
||||
const MemRegion *R) {
|
||||
|
||||
switch (R->getKind()) {
|
||||
case MemRegion::CXXThisRegionKind:
|
||||
assert(0 && "Cannot get size of 'this' region");
|
||||
case MemRegion::GenericMemSpaceRegionKind:
|
||||
case MemRegion::StackLocalsSpaceRegionKind:
|
||||
case MemRegion::StackArgumentsSpaceRegionKind:
|
||||
@ -877,6 +926,9 @@ SVal RegionStoreManager::EvalBinOp(const GRState *state,
|
||||
// Technically this can happen if people do funny things with casts.
|
||||
return UnknownVal();
|
||||
|
||||
case MemRegion::CXXThisRegionKind:
|
||||
assert(0 &&
|
||||
"Cannot perform pointer arithmetic on implicit argument 'this'");
|
||||
case MemRegion::GenericMemSpaceRegionKind:
|
||||
case MemRegion::StackLocalsSpaceRegionKind:
|
||||
case MemRegion::StackArgumentsSpaceRegionKind:
|
||||
@ -921,7 +973,7 @@ SVal RegionStoreManager::EvalBinOp(const GRState *state,
|
||||
|
||||
Optional<SVal> RegionStoreManager::getDirectBinding(RegionBindings B,
|
||||
const MemRegion *R) {
|
||||
if (const BindingVal *BV = B.lookup(R))
|
||||
if (const BindingVal *BV = Lookup(B, R))
|
||||
return Optional<SVal>::create(BV->getDirectValue());
|
||||
|
||||
return Optional<SVal>();
|
||||
@ -935,7 +987,7 @@ Optional<SVal> RegionStoreManager::getDefaultBinding(RegionBindings B,
|
||||
if (TR->getValueType(getContext())->isUnionType())
|
||||
return UnknownVal();
|
||||
|
||||
if (BindingVal const *V = B.lookup(R))
|
||||
if (const BindingVal *V = Lookup(B, R))
|
||||
return Optional<SVal>::create(V->getDefaultValue());
|
||||
|
||||
return Optional<SVal>();
|
||||
@ -943,7 +995,7 @@ Optional<SVal> RegionStoreManager::getDefaultBinding(RegionBindings B,
|
||||
|
||||
Optional<SVal> RegionStoreManager::getBinding(RegionBindings B,
|
||||
const MemRegion *R) {
|
||||
if (const BindingVal *BV = B.lookup(R))
|
||||
if (const BindingVal *BV = Lookup(B, R))
|
||||
return Optional<SVal>::create(BV->getValue());
|
||||
|
||||
return Optional<SVal>();
|
||||
@ -1051,22 +1103,46 @@ RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) {
|
||||
|
||||
if (const FieldRegion* FR = dyn_cast<FieldRegion>(R))
|
||||
return SValuator::CastResult(state,
|
||||
CastRetrievedVal(RetrieveField(state, FR), FR, T));
|
||||
CastRetrievedVal(RetrieveField(state, FR), FR,
|
||||
T, false));
|
||||
|
||||
if (const ElementRegion* ER = dyn_cast<ElementRegion>(R))
|
||||
if (const ElementRegion* ER = dyn_cast<ElementRegion>(R)) {
|
||||
// FIXME: Here we actually perform an implicit conversion from the loaded
|
||||
// value to the element type. Eventually we want to compose these values
|
||||
// more intelligently. For example, an 'element' can encompass multiple
|
||||
// bound regions (e.g., several bound bytes), or could be a subset of
|
||||
// a larger value.
|
||||
return SValuator::CastResult(state,
|
||||
CastRetrievedVal(RetrieveElement(state, ER), ER, T));
|
||||
CastRetrievedVal(RetrieveElement(state, ER),
|
||||
ER, T, false));
|
||||
}
|
||||
|
||||
if (const ObjCIvarRegion *IVR = dyn_cast<ObjCIvarRegion>(R))
|
||||
if (const ObjCIvarRegion *IVR = dyn_cast<ObjCIvarRegion>(R)) {
|
||||
// FIXME: Here we actually perform an implicit conversion from the loaded
|
||||
// value to the ivar type. What we should model is stores to ivars
|
||||
// that blow past the extent of the ivar. If the address of the ivar is
|
||||
// reinterpretted, it is possible we stored a different value that could
|
||||
// fit within the ivar. Either we need to cast these when storing them
|
||||
// or reinterpret them lazily (as we do here).
|
||||
return SValuator::CastResult(state,
|
||||
CastRetrievedVal(RetrieveObjCIvar(state, IVR), IVR, T));
|
||||
CastRetrievedVal(RetrieveObjCIvar(state, IVR),
|
||||
IVR, T, false));
|
||||
}
|
||||
|
||||
if (const VarRegion *VR = dyn_cast<VarRegion>(R))
|
||||
if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
|
||||
// FIXME: Here we actually perform an implicit conversion from the loaded
|
||||
// value to the variable type. What we should model is stores to variables
|
||||
// that blow past the extent of the variable. If the address of the
|
||||
// variable is reinterpretted, it is possible we stored a different value
|
||||
// that could fit within the variable. Either we need to cast these when
|
||||
// storing them or reinterpret them lazily (as we do here).
|
||||
return SValuator::CastResult(state,
|
||||
CastRetrievedVal(RetrieveVar(state, VR), VR, T));
|
||||
CastRetrievedVal(RetrieveVar(state, VR), VR, T,
|
||||
false));
|
||||
}
|
||||
|
||||
RegionBindings B = GetRegionBindings(state->getStore());
|
||||
RegionBindings::data_type* V = B.lookup(R);
|
||||
const BindingVal *V = Lookup(B, R);
|
||||
|
||||
// Check if the region has a binding.
|
||||
if (V)
|
||||
@ -1076,12 +1152,7 @@ RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) {
|
||||
// The location does not have a bound value. This means that it has
|
||||
// the value it had upon its creation and/or entry to the analyzed
|
||||
// function/method. These are either symbolic values or 'undefined'.
|
||||
|
||||
#if HEAP_UNDEFINED
|
||||
if (R->hasHeapOrStackStorage()) {
|
||||
#else
|
||||
if (R->hasStackStorage()) {
|
||||
#endif
|
||||
if (R->hasStackNonParametersStorage()) {
|
||||
// All stack variables are considered to have undefined values
|
||||
// upon creation. All heap allocated blocks are considered to
|
||||
// have undefined values as well unless they are explicitly bound
|
||||
@ -1124,7 +1195,7 @@ SVal RegionStoreManager::RetrieveElement(const GRState* state,
|
||||
const ElementRegion* R) {
|
||||
// Check if the region has a binding.
|
||||
RegionBindings B = GetRegionBindings(state->getStore());
|
||||
if (Optional<SVal> V = getDirectBinding(B, R))
|
||||
if (Optional<SVal> V = getDirectBinding(B, R))
|
||||
return *V;
|
||||
|
||||
const MemRegion* superR = R->getSuperRegion();
|
||||
@ -1174,7 +1245,7 @@ SVal RegionStoreManager::RetrieveElement(const GRState* state,
|
||||
// Other cases: give up.
|
||||
return UnknownVal();
|
||||
}
|
||||
|
||||
|
||||
return RetrieveFieldOrElementCommon(state, R, R->getElementType(), superR);
|
||||
}
|
||||
|
||||
@ -1240,8 +1311,7 @@ SVal RegionStoreManager::RetrieveFieldOrElementCommon(const GRState *state,
|
||||
cast<FieldRegion>(lazyBindingRegion));
|
||||
}
|
||||
|
||||
if (R->hasStackStorage() && !R->hasParametersStorage()) {
|
||||
|
||||
if (R->hasStackNonParametersStorage()) {
|
||||
if (isa<ElementRegion>(R)) {
|
||||
// Currently we don't reason specially about Clang-style vectors. Check
|
||||
// if superR is a vector and if so return Unknown.
|
||||
@ -1369,15 +1439,9 @@ SVal RegionStoreManager::RetrieveArray(const GRState *state,
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
Store RegionStoreManager::Remove(Store store, Loc L) {
|
||||
const MemRegion* R = 0;
|
||||
|
||||
if (isa<loc::MemRegionVal>(L))
|
||||
R = cast<loc::MemRegionVal>(L).getRegion();
|
||||
|
||||
if (R) {
|
||||
RegionBindings B = GetRegionBindings(store);
|
||||
return RBFactory.Remove(B, R).getRoot();
|
||||
}
|
||||
if (const MemRegion* R = cast<loc::MemRegionVal>(L).getRegion())
|
||||
return Remove(store, BindingKey::Make(R));
|
||||
|
||||
return store;
|
||||
}
|
||||
@ -1436,8 +1500,8 @@ const GRState *RegionStoreManager::Bind(const GRState *state, Loc L, SVal V) {
|
||||
|
||||
// Perform the binding.
|
||||
RegionBindings B = GetRegionBindings(state->getStore());
|
||||
return state->makeWithStore(
|
||||
RBFactory.Add(B, R, BindingVal(V, BindingVal::Direct)).getRoot());
|
||||
return state->makeWithStore(Add(B, R,
|
||||
BindingVal(V, BindingVal::Direct)).getRoot());
|
||||
}
|
||||
|
||||
const GRState *RegionStoreManager::BindDecl(const GRState *ST,
|
||||
@ -1483,9 +1547,9 @@ const GRState *RegionStoreManager::setImplicitDefaultValue(const GRState *state,
|
||||
else {
|
||||
return state;
|
||||
}
|
||||
|
||||
B = RBFactory.Add(B, R, BindingVal(V, BindingVal::Default));
|
||||
return state->makeWithStore(B.getRoot());
|
||||
|
||||
return state->makeWithStore(Add(B, R,
|
||||
BindingVal(V, BindingVal::Default)).getRoot());
|
||||
}
|
||||
|
||||
const GRState *RegionStoreManager::BindArray(const GRState *state,
|
||||
@ -1610,8 +1674,7 @@ RegionStoreManager::BindStruct(const GRState *state, const TypedRegion* R,
|
||||
if (FI != FE) {
|
||||
Store store = state->getStore();
|
||||
RegionBindings B = GetRegionBindings(store);
|
||||
B = RBFactory.Add(B, R,
|
||||
BindingVal(ValMgr.makeIntVal(0, false), BindingVal::Default));
|
||||
B = Add(B, R, BindingVal(ValMgr.makeIntVal(0, false), BindingVal::Default));
|
||||
state = state->makeWithStore(B.getRoot());
|
||||
}
|
||||
|
||||
@ -1625,7 +1688,7 @@ Store RegionStoreManager::KillStruct(Store store, const TypedRegion* R) {
|
||||
RemoveSubRegionBindings(B, R, *SubRegions);
|
||||
|
||||
// Set the default value of the struct region to "unknown".
|
||||
B = RBFactory.Add(B, R, BindingVal(UnknownVal(), BindingVal::Default));
|
||||
B = Add(B, R, BindingVal(UnknownVal(), BindingVal::Default));
|
||||
|
||||
return B.getRoot();
|
||||
}
|
||||
@ -1646,8 +1709,58 @@ RegionStoreManager::CopyLazyBindings(nonloc::LazyCompoundVal V,
|
||||
|
||||
// Now copy the bindings. This amounts to just binding 'V' to 'R'. This
|
||||
// results in a zero-copy algorithm.
|
||||
return state->makeWithStore(
|
||||
RBFactory.Add(B, R, BindingVal(V, BindingVal::Direct)).getRoot());
|
||||
return state->makeWithStore(Add(B, R,
|
||||
BindingVal(V, BindingVal::Direct)).getRoot());
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// "Raw" retrievals and bindings.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
BindingKey BindingKey::Make(const MemRegion *R) {
|
||||
if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
|
||||
const RegionRawOffset &O = ER->getAsRawOffset();
|
||||
|
||||
if (O.getRegion())
|
||||
return BindingKey(O.getRegion(), O.getByteOffset());
|
||||
|
||||
// FIXME: There are some ElementRegions for which we cannot compute
|
||||
// raw offsets yet, including regions with symbolic offsets.
|
||||
}
|
||||
|
||||
return BindingKey(R, 0);
|
||||
}
|
||||
|
||||
RegionBindings RegionStoreManager::Add(RegionBindings B, BindingKey K,
|
||||
BindingVal V) {
|
||||
return RBFactory.Add(B, K, V);
|
||||
}
|
||||
|
||||
RegionBindings RegionStoreManager::Add(RegionBindings B, const MemRegion *R,
|
||||
BindingVal V) {
|
||||
return Add(B, BindingKey::Make(R), V);
|
||||
}
|
||||
|
||||
const BindingVal *RegionStoreManager::Lookup(RegionBindings B, BindingKey K) {
|
||||
return B.lookup(K);
|
||||
}
|
||||
|
||||
const BindingVal *RegionStoreManager::Lookup(RegionBindings B,
|
||||
const MemRegion *R) {
|
||||
return Lookup(B, BindingKey::Make(R));
|
||||
}
|
||||
|
||||
RegionBindings RegionStoreManager::Remove(RegionBindings B, BindingKey K) {
|
||||
return RBFactory.Remove(B, K);
|
||||
}
|
||||
|
||||
RegionBindings RegionStoreManager::Remove(RegionBindings B, const MemRegion *R){
|
||||
return Remove(B, BindingKey::Make(R));
|
||||
}
|
||||
|
||||
Store RegionStoreManager::Remove(Store store, BindingKey K) {
|
||||
RegionBindings B = GetRegionBindings(store);
|
||||
return Remove(B, K).getRoot();
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -1674,7 +1787,7 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc,
|
||||
|
||||
// Scan the direct bindings for "intermediate" roots.
|
||||
for (RegionBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) {
|
||||
const MemRegion *R = I.getKey();
|
||||
const MemRegion *R = I.getKey().getRegion();
|
||||
IntermediateRoots.push_back(R);
|
||||
}
|
||||
|
||||
@ -1831,13 +1944,13 @@ tryAgain:
|
||||
// as live. We now remove all the regions that are dead from the store
|
||||
// as well as update DSymbols with the set symbols that are now dead.
|
||||
for (RegionBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) {
|
||||
const MemRegion* R = I.getKey();
|
||||
const MemRegion* R = I.getKey().getRegion();
|
||||
// If this region live? Is so, none of its symbols are dead.
|
||||
if (Visited.count(std::make_pair(&state, R)))
|
||||
continue;
|
||||
|
||||
// Remove this dead region from the store.
|
||||
store = Remove(store, ValMgr.makeLoc(R));
|
||||
store = Remove(store, I.getKey());
|
||||
|
||||
// Mark all non-live symbols that this region references as dead.
|
||||
if (const SymbolicRegion* SymR = dyn_cast<SymbolicRegion>(R))
|
||||
|
@ -67,6 +67,9 @@ void ReturnStackAddressChecker::PreVisitReturnStmt(CheckerContext &C,
|
||||
llvm::raw_svector_ostream os(buf);
|
||||
SourceRange range;
|
||||
|
||||
// Get the base region, stripping away fields and elements.
|
||||
R = R->getBaseRegion();
|
||||
|
||||
// Check if the region is a compound literal.
|
||||
if (const CompoundLiteralRegion* CR = dyn_cast<CompoundLiteralRegion>(R)) {
|
||||
const CompoundLiteralExpr* CL = CR->getLiteralExpr();
|
||||
@ -92,13 +95,18 @@ void ReturnStackAddressChecker::PreVisitReturnStmt(CheckerContext &C,
|
||||
<< C.getSourceManager().getInstantiationLineNumber(L)
|
||||
<< " returned to caller";
|
||||
}
|
||||
else {
|
||||
else if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
|
||||
os << "Address of stack memory associated with local variable '"
|
||||
<< R->getString() << "' returned.";
|
||||
<< VR->getString() << "' returned";
|
||||
range = VR->getDecl()->getSourceRange();
|
||||
}
|
||||
else {
|
||||
assert(false && "Invalid region in ReturnStackAddressChecker.");
|
||||
return;
|
||||
}
|
||||
|
||||
RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
|
||||
report->addRange(RS->getSourceRange());
|
||||
report->addRange(RetE->getSourceRange());
|
||||
if (range.isValid())
|
||||
report->addRange(range);
|
||||
|
||||
|
@ -97,6 +97,10 @@ const MemRegion *SVal::getAsRegion() const {
|
||||
if (const loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(this))
|
||||
return X->getRegion();
|
||||
|
||||
if (const nonloc::LocAsInteger *X = dyn_cast<nonloc::LocAsInteger>(this)) {
|
||||
return X->getLoc().getAsRegion();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -62,8 +62,12 @@ SValuator::CastResult SValuator::EvalCast(SVal val, const GRState *state,
|
||||
ASTContext &C = ValMgr.getContext();
|
||||
|
||||
// For const casts, just propagate the value.
|
||||
if (C.hasSameUnqualifiedType(castTy, originalTy))
|
||||
return CastResult(state, val);
|
||||
if (!castTy->isVariableArrayType() && !originalTy->isVariableArrayType())
|
||||
if (C.hasSameUnqualifiedType(castTy, originalTy))
|
||||
return CastResult(state, val);
|
||||
|
||||
if (castTy->isIntegerType() && originalTy->isIntegerType())
|
||||
return CastResult(state, EvalCastNL(cast<NonLoc>(val), castTy));
|
||||
|
||||
// Check for casts from pointers to integers.
|
||||
if (castTy->isIntegerType() && Loc::IsLocType(originalTy))
|
||||
|
@ -65,25 +65,10 @@ const GRState *SimpleConstraintManager::Assume(const GRState *state,
|
||||
return Assume(state, cast<Loc>(Cond), Assumption);
|
||||
}
|
||||
|
||||
const GRState *SimpleConstraintManager::Assume(const GRState *state, Loc Cond,
|
||||
bool Assumption) {
|
||||
|
||||
state = AssumeAux(state, Cond, Assumption);
|
||||
|
||||
// EvalAssume is used to call into the GRTransferFunction object to perform
|
||||
// any checker-specific update of the state based on this assumption being
|
||||
// true or false.
|
||||
|
||||
if (!state)
|
||||
return 0;
|
||||
|
||||
std::vector<std::pair<void *, Checker*> >::iterator
|
||||
I = state->checker_begin(), E = state->checker_end();
|
||||
|
||||
for (; I != E; ++I) {
|
||||
state = I->second->EvalAssume(state, Cond, Assumption);
|
||||
}
|
||||
return state->getTransferFuncs().EvalAssume(state, Cond, Assumption);
|
||||
const GRState *SimpleConstraintManager::Assume(const GRState *state, Loc cond,
|
||||
bool assumption) {
|
||||
state = AssumeAux(state, cond, assumption);
|
||||
return SU.ProcessAssume(state, cond, assumption);
|
||||
}
|
||||
|
||||
const GRState *SimpleConstraintManager::AssumeAux(const GRState *state,
|
||||
@ -130,26 +115,10 @@ const GRState *SimpleConstraintManager::AssumeAux(const GRState *state,
|
||||
}
|
||||
|
||||
const GRState *SimpleConstraintManager::Assume(const GRState *state,
|
||||
NonLoc Cond,
|
||||
bool Assumption) {
|
||||
|
||||
state = AssumeAux(state, Cond, Assumption);
|
||||
|
||||
// EvalAssume is used to call into the GRTransferFunction object to perform
|
||||
// any checker-specific update of the state based on this assumption being
|
||||
// true or false.
|
||||
|
||||
if (!state)
|
||||
return 0;
|
||||
|
||||
std::vector<std::pair<void *, Checker*> >::iterator
|
||||
I = state->checker_begin(), E = state->checker_end();
|
||||
|
||||
for (; I != E; ++I) {
|
||||
state = I->second->EvalAssume(state, Cond, Assumption);
|
||||
}
|
||||
|
||||
return state->getTransferFuncs().EvalAssume(state, Cond, Assumption);
|
||||
NonLoc cond,
|
||||
bool assumption) {
|
||||
state = AssumeAux(state, cond, assumption);
|
||||
return SU.ProcessAssume(state, cond, assumption);
|
||||
}
|
||||
|
||||
const GRState *SimpleConstraintManager::AssumeAux(const GRState *state,
|
||||
|
@ -20,8 +20,9 @@
|
||||
namespace clang {
|
||||
|
||||
class SimpleConstraintManager : public ConstraintManager {
|
||||
GRSubEngine &SU;
|
||||
public:
|
||||
SimpleConstraintManager() {}
|
||||
SimpleConstraintManager(GRSubEngine &subengine) : SU(subengine) {}
|
||||
virtual ~SimpleConstraintManager();
|
||||
|
||||
//===------------------------------------------------------------------===//
|
||||
|
@ -53,13 +53,13 @@ SVal SimpleSValuator::EvalCastNL(NonLoc val, QualType castTy) {
|
||||
if (isLocType)
|
||||
return LI->getLoc();
|
||||
|
||||
// FIXME: Correctly support promotions/truncations.
|
||||
ASTContext &Ctx = ValMgr.getContext();
|
||||
|
||||
// FIXME: Support promotions/truncations.
|
||||
if (Ctx.getTypeSize(castTy) == Ctx.getTypeSize(Ctx.VoidPtrTy))
|
||||
unsigned castSize = Ctx.getTypeSize(castTy);
|
||||
if (castSize == LI->getNumBits())
|
||||
return val;
|
||||
|
||||
return UnknownVal();
|
||||
return ValMgr.makeLocAsInteger(LI->getLoc(), castSize);
|
||||
}
|
||||
|
||||
if (const SymExpr *se = val.getAsSymbolicExpression()) {
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
#include "clang/Analysis/PathSensitive/Store.h"
|
||||
#include "clang/Analysis/PathSensitive/GRState.h"
|
||||
#include "clang/AST/CharUnits.h"
|
||||
|
||||
using namespace clang;
|
||||
|
||||
@ -77,6 +78,7 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy)
|
||||
|
||||
// Process region cast according to the kind of the region being cast.
|
||||
switch (R->getKind()) {
|
||||
case MemRegion::CXXThisRegionKind:
|
||||
case MemRegion::GenericMemSpaceRegionKind:
|
||||
case MemRegion::StackLocalsSpaceRegionKind:
|
||||
case MemRegion::StackArgumentsSpaceRegionKind:
|
||||
@ -137,9 +139,9 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy)
|
||||
if (!baseR)
|
||||
return NULL;
|
||||
|
||||
int64_t off = rawOff.getByteOffset();
|
||||
CharUnits off = CharUnits::fromQuantity(rawOff.getByteOffset());
|
||||
|
||||
if (off == 0) {
|
||||
if (off.isZero()) {
|
||||
// Edge case: we are at 0 bytes off the beginning of baseR. We
|
||||
// check to see if type we are casting to is the same as the base
|
||||
// region. If so, just return the base region.
|
||||
@ -167,7 +169,7 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy)
|
||||
// We can only compute sizeof(PointeeTy) if it is a complete type.
|
||||
if (IsCompleteType(Ctx, PointeeTy)) {
|
||||
// Compute the size in **bytes**.
|
||||
int64_t pointeeTySize = (int64_t) (Ctx.getTypeSize(PointeeTy) / 8);
|
||||
CharUnits pointeeTySize = Ctx.getTypeSizeInChars(PointeeTy);
|
||||
|
||||
// Is the offset a multiple of the size? If so, we can layer the
|
||||
// ElementRegion (with elementType == PointeeTy) directly on top of
|
||||
@ -181,7 +183,7 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy)
|
||||
if (!newSuperR) {
|
||||
// Create an intermediate ElementRegion to represent the raw byte.
|
||||
// This will be the super region of the final ElementRegion.
|
||||
newSuperR = MakeElementRegion(baseR, Ctx.CharTy, off);
|
||||
newSuperR = MakeElementRegion(baseR, Ctx.CharTy, off.getQuantity());
|
||||
}
|
||||
|
||||
return MakeElementRegion(newSuperR, PointeeTy, newIndex);
|
||||
@ -196,23 +198,29 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy)
|
||||
/// CastRetrievedVal - Used by subclasses of StoreManager to implement
|
||||
/// implicit casts that arise from loads from regions that are reinterpreted
|
||||
/// as another region.
|
||||
SVal StoreManager::CastRetrievedVal(SVal V, const TypedRegion *R,
|
||||
QualType castTy) {
|
||||
SVal StoreManager::CastRetrievedVal(SVal V, const TypedRegion *R,
|
||||
QualType castTy, bool performTestOnly) {
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (castTy.isNull())
|
||||
return V;
|
||||
|
||||
ASTContext &Ctx = ValMgr.getContext();
|
||||
QualType T = R->getValueType(Ctx);
|
||||
|
||||
// Automatically translate references to pointers.
|
||||
if (const ReferenceType *RT = T->getAs<ReferenceType>())
|
||||
T = Ctx.getPointerType(RT->getPointeeType());
|
||||
|
||||
assert(ValMgr.getContext().hasSameUnqualifiedType(castTy, T));
|
||||
#endif
|
||||
|
||||
if (performTestOnly) {
|
||||
// Automatically translate references to pointers.
|
||||
QualType T = R->getValueType(Ctx);
|
||||
if (const ReferenceType *RT = T->getAs<ReferenceType>())
|
||||
T = Ctx.getPointerType(RT->getPointeeType());
|
||||
|
||||
assert(ValMgr.getContext().hasSameUnqualifiedType(castTy, T));
|
||||
return V;
|
||||
}
|
||||
|
||||
if (const Loc *L = dyn_cast<Loc>(&V))
|
||||
return ValMgr.getSValuator().EvalCastL(*L, castTy);
|
||||
else if (const NonLoc *NL = dyn_cast<NonLoc>(&V))
|
||||
return ValMgr.getSValuator().EvalCastNL(*NL, castTy);
|
||||
|
||||
return V;
|
||||
}
|
||||
|
||||
@ -240,8 +248,3 @@ SVal StoreManager::getLValueCompoundLiteral(const CompoundLiteralExpr* CL,
|
||||
const LocationContext *LC) {
|
||||
return loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, LC));
|
||||
}
|
||||
|
||||
Loc StoreManager::getThisObject(QualType T) {
|
||||
const CXXObjectRegion *R = MRMgr.getCXXObjectRegion(T);
|
||||
return loc::MemRegionVal(R);
|
||||
}
|
||||
|
@ -541,19 +541,46 @@ static bool ModifierIs(const char *Modifier, unsigned ModifierLen,
|
||||
return StrLen-1 == ModifierLen && !memcmp(Modifier, Str, StrLen-1);
|
||||
}
|
||||
|
||||
/// ScanForward - Scans forward, looking for the given character, skipping
|
||||
/// nested clauses and escaped characters.
|
||||
static const char *ScanFormat(const char *I, const char *E, char Target) {
|
||||
unsigned Depth = 0;
|
||||
|
||||
for ( ; I != E; ++I) {
|
||||
if (Depth == 0 && *I == Target) return I;
|
||||
if (Depth != 0 && *I == '}') Depth--;
|
||||
|
||||
if (*I == '%') {
|
||||
I++;
|
||||
if (I == E) break;
|
||||
|
||||
// Escaped characters get implicitly skipped here.
|
||||
|
||||
// Format specifier.
|
||||
if (!isdigit(*I) && !ispunct(*I)) {
|
||||
for (I++; I != E && !isdigit(*I) && *I != '{'; I++) ;
|
||||
if (I == E) break;
|
||||
if (*I == '{')
|
||||
Depth++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return E;
|
||||
}
|
||||
|
||||
/// HandleSelectModifier - Handle the integer 'select' modifier. This is used
|
||||
/// like this: %select{foo|bar|baz}2. This means that the integer argument
|
||||
/// "%2" has a value from 0-2. If the value is 0, the diagnostic prints 'foo'.
|
||||
/// If the value is 1, it prints 'bar'. If it has the value 2, it prints 'baz'.
|
||||
/// This is very useful for certain classes of variant diagnostics.
|
||||
static void HandleSelectModifier(unsigned ValNo,
|
||||
static void HandleSelectModifier(const DiagnosticInfo &DInfo, unsigned ValNo,
|
||||
const char *Argument, unsigned ArgumentLen,
|
||||
llvm::SmallVectorImpl<char> &OutStr) {
|
||||
const char *ArgumentEnd = Argument+ArgumentLen;
|
||||
|
||||
// Skip over 'ValNo' |'s.
|
||||
while (ValNo) {
|
||||
const char *NextVal = std::find(Argument, ArgumentEnd, '|');
|
||||
const char *NextVal = ScanFormat(Argument, ArgumentEnd, '|');
|
||||
assert(NextVal != ArgumentEnd && "Value for integer select modifier was"
|
||||
" larger than the number of options in the diagnostic string!");
|
||||
Argument = NextVal+1; // Skip this string.
|
||||
@ -561,9 +588,10 @@ static void HandleSelectModifier(unsigned ValNo,
|
||||
}
|
||||
|
||||
// Get the end of the value. This is either the } or the |.
|
||||
const char *EndPtr = std::find(Argument, ArgumentEnd, '|');
|
||||
// Add the value to the output string.
|
||||
OutStr.append(Argument, EndPtr);
|
||||
const char *EndPtr = ScanFormat(Argument, ArgumentEnd, '|');
|
||||
|
||||
// Recursively format the result of the select clause into the output string.
|
||||
DInfo.FormatDiagnostic(Argument, EndPtr, OutStr);
|
||||
}
|
||||
|
||||
/// HandleIntegerSModifier - Handle the integer 's' modifier. This adds the
|
||||
@ -575,6 +603,37 @@ static void HandleIntegerSModifier(unsigned ValNo,
|
||||
OutStr.push_back('s');
|
||||
}
|
||||
|
||||
/// HandleOrdinalModifier - Handle the integer 'ord' modifier. This
|
||||
/// prints the ordinal form of the given integer, with 1 corresponding
|
||||
/// to the first ordinal. Currently this is hard-coded to use the
|
||||
/// English form.
|
||||
static void HandleOrdinalModifier(unsigned ValNo,
|
||||
llvm::SmallVectorImpl<char> &OutStr) {
|
||||
assert(ValNo != 0 && "ValNo must be strictly positive!");
|
||||
|
||||
llvm::raw_svector_ostream Out(OutStr);
|
||||
|
||||
// We could use text forms for the first N ordinals, but the numeric
|
||||
// forms are actually nicer in diagnostics because they stand out.
|
||||
Out << ValNo;
|
||||
|
||||
// It is critically important that we do this perfectly for
|
||||
// user-written sequences with over 100 elements.
|
||||
switch (ValNo % 100) {
|
||||
case 11:
|
||||
case 12:
|
||||
case 13:
|
||||
Out << "th"; return;
|
||||
default:
|
||||
switch (ValNo % 10) {
|
||||
case 1: Out << "st"; return;
|
||||
case 2: Out << "nd"; return;
|
||||
case 3: Out << "rd"; return;
|
||||
default: Out << "th"; return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// PluralNumber - Parse an unsigned integer and advance Start.
|
||||
static unsigned PluralNumber(const char *&Start, const char *End) {
|
||||
@ -685,11 +744,11 @@ static void HandlePluralModifier(unsigned ValNo,
|
||||
}
|
||||
if (EvalPluralExpr(ValNo, Argument, ExprEnd)) {
|
||||
Argument = ExprEnd + 1;
|
||||
ExprEnd = std::find(Argument, ArgumentEnd, '|');
|
||||
ExprEnd = ScanFormat(Argument, ArgumentEnd, '|');
|
||||
OutStr.append(Argument, ExprEnd);
|
||||
return;
|
||||
}
|
||||
Argument = std::find(Argument, ArgumentEnd - 1, '|') + 1;
|
||||
Argument = ScanFormat(Argument, ArgumentEnd - 1, '|') + 1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -702,6 +761,13 @@ FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const {
|
||||
const char *DiagStr = getDiags()->getDescription(getID());
|
||||
const char *DiagEnd = DiagStr+strlen(DiagStr);
|
||||
|
||||
FormatDiagnostic(DiagStr, DiagEnd, OutStr);
|
||||
}
|
||||
|
||||
void DiagnosticInfo::
|
||||
FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
|
||||
llvm::SmallVectorImpl<char> &OutStr) const {
|
||||
|
||||
/// FormattedArgs - Keep track of all of the arguments formatted by
|
||||
/// ConvertArgToString and pass them into subsequent calls to
|
||||
/// ConvertArgToString, allowing the implementation to avoid redundancies in
|
||||
@ -715,8 +781,8 @@ FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const {
|
||||
OutStr.append(DiagStr, StrEnd);
|
||||
DiagStr = StrEnd;
|
||||
continue;
|
||||
} else if (DiagStr[1] == '%') {
|
||||
OutStr.push_back('%'); // %% -> %.
|
||||
} else if (ispunct(DiagStr[1])) {
|
||||
OutStr.push_back(DiagStr[1]); // %% -> %.
|
||||
DiagStr += 2;
|
||||
continue;
|
||||
}
|
||||
@ -745,8 +811,8 @@ FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const {
|
||||
++DiagStr; // Skip {.
|
||||
Argument = DiagStr;
|
||||
|
||||
for (; DiagStr[0] != '}'; ++DiagStr)
|
||||
assert(DiagStr[0] && "Mismatched {}'s in diagnostic string!");
|
||||
DiagStr = ScanFormat(DiagStr, DiagEnd, '}');
|
||||
assert(DiagStr != DiagEnd && "Mismatched {}'s in diagnostic string!");
|
||||
ArgumentLen = DiagStr-Argument;
|
||||
++DiagStr; // Skip }.
|
||||
}
|
||||
@ -781,11 +847,13 @@ FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const {
|
||||
int Val = getArgSInt(ArgNo);
|
||||
|
||||
if (ModifierIs(Modifier, ModifierLen, "select")) {
|
||||
HandleSelectModifier((unsigned)Val, Argument, ArgumentLen, OutStr);
|
||||
HandleSelectModifier(*this, (unsigned)Val, Argument, ArgumentLen, OutStr);
|
||||
} else if (ModifierIs(Modifier, ModifierLen, "s")) {
|
||||
HandleIntegerSModifier(Val, OutStr);
|
||||
} else if (ModifierIs(Modifier, ModifierLen, "plural")) {
|
||||
HandlePluralModifier((unsigned)Val, Argument, ArgumentLen, OutStr);
|
||||
} else if (ModifierIs(Modifier, ModifierLen, "ordinal")) {
|
||||
HandleOrdinalModifier((unsigned)Val, OutStr);
|
||||
} else {
|
||||
assert(ModifierLen == 0 && "Unknown integer modifier");
|
||||
llvm::raw_svector_ostream(OutStr) << Val;
|
||||
@ -796,11 +864,13 @@ FormatDiagnostic(llvm::SmallVectorImpl<char> &OutStr) const {
|
||||
unsigned Val = getArgUInt(ArgNo);
|
||||
|
||||
if (ModifierIs(Modifier, ModifierLen, "select")) {
|
||||
HandleSelectModifier(Val, Argument, ArgumentLen, OutStr);
|
||||
HandleSelectModifier(*this, Val, Argument, ArgumentLen, OutStr);
|
||||
} else if (ModifierIs(Modifier, ModifierLen, "s")) {
|
||||
HandleIntegerSModifier(Val, OutStr);
|
||||
} else if (ModifierIs(Modifier, ModifierLen, "plural")) {
|
||||
HandlePluralModifier((unsigned)Val, Argument, ArgumentLen, OutStr);
|
||||
} else if (ModifierIs(Modifier, ModifierLen, "ordinal")) {
|
||||
HandleOrdinalModifier(Val, OutStr);
|
||||
} else {
|
||||
assert(ModifierLen == 0 && "Unknown integer modifier");
|
||||
llvm::raw_svector_ostream(OutStr) << Val;
|
||||
|
@ -18,51 +18,38 @@
|
||||
#include "clang/Basic/LangOptions.h"
|
||||
#include "clang/Basic/TargetBuiltins.h"
|
||||
#include "clang/Basic/TargetOptions.h"
|
||||
#include "clang/Frontend/Utils.h"
|
||||
#include "llvm/ADT/APFloat.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/MC/MCSectionMachO.h"
|
||||
#include <algorithm>
|
||||
using namespace clang;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Common code shared among targets.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
static void Define(std::vector<char> &Buf, const llvm::StringRef &Macro,
|
||||
const llvm::StringRef &Val = "1") {
|
||||
const char *Def = "#define ";
|
||||
Buf.insert(Buf.end(), Def, Def+strlen(Def));
|
||||
Buf.insert(Buf.end(), Macro.begin(), Macro.end());
|
||||
Buf.push_back(' ');
|
||||
Buf.insert(Buf.end(), Val.begin(), Val.end());
|
||||
Buf.push_back('\n');
|
||||
}
|
||||
|
||||
/// DefineStd - Define a macro name and standard variants. For example if
|
||||
/// MacroName is "unix", then this will define "__unix", "__unix__", and "unix"
|
||||
/// when in GNU mode.
|
||||
static void DefineStd(std::vector<char> &Buf, const char *MacroName,
|
||||
static void DefineStd(MacroBuilder &Builder, llvm::StringRef MacroName,
|
||||
const LangOptions &Opts) {
|
||||
assert(MacroName[0] != '_' && "Identifier should be in the user's namespace");
|
||||
|
||||
// If in GNU mode (e.g. -std=gnu99 but not -std=c99) define the raw identifier
|
||||
// in the user's namespace.
|
||||
if (Opts.GNUMode)
|
||||
Define(Buf, MacroName);
|
||||
Builder.defineMacro(MacroName);
|
||||
|
||||
// Define __unix.
|
||||
llvm::SmallString<20> TmpStr;
|
||||
TmpStr = "__";
|
||||
TmpStr += MacroName;
|
||||
Define(Buf, TmpStr.str());
|
||||
Builder.defineMacro("__" + MacroName);
|
||||
|
||||
// Define __unix__.
|
||||
TmpStr += "__";
|
||||
Define(Buf, TmpStr.str());
|
||||
Builder.defineMacro("__" + MacroName + "__");
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -74,44 +61,44 @@ template<typename TgtInfo>
|
||||
class OSTargetInfo : public TgtInfo {
|
||||
protected:
|
||||
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
|
||||
std::vector<char> &Defines) const=0;
|
||||
MacroBuilder &Builder) const=0;
|
||||
public:
|
||||
OSTargetInfo(const std::string& triple) : TgtInfo(triple) {}
|
||||
virtual void getTargetDefines(const LangOptions &Opts,
|
||||
std::vector<char> &Defines) const {
|
||||
TgtInfo::getTargetDefines(Opts, Defines);
|
||||
getOSDefines(Opts, TgtInfo::getTriple(), Defines);
|
||||
MacroBuilder &Builder) const {
|
||||
TgtInfo::getTargetDefines(Opts, Builder);
|
||||
getOSDefines(Opts, TgtInfo::getTriple(), Builder);
|
||||
}
|
||||
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
|
||||
static void getDarwinDefines(std::vector<char> &Defs, const LangOptions &Opts) {
|
||||
Define(Defs, "__APPLE_CC__", "5621");
|
||||
Define(Defs, "__APPLE__");
|
||||
Define(Defs, "__MACH__");
|
||||
Define(Defs, "OBJC_NEW_PROPERTIES");
|
||||
static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts) {
|
||||
Builder.defineMacro("__APPLE_CC__", "5621");
|
||||
Builder.defineMacro("__APPLE__");
|
||||
Builder.defineMacro("__MACH__");
|
||||
Builder.defineMacro("OBJC_NEW_PROPERTIES");
|
||||
|
||||
// __weak is always defined, for use in blocks and with objc pointers.
|
||||
Define(Defs, "__weak", "__attribute__((objc_gc(weak)))");
|
||||
Builder.defineMacro("__weak", "__attribute__((objc_gc(weak)))");
|
||||
|
||||
// Darwin defines __strong even in C mode (just to nothing).
|
||||
if (!Opts.ObjC1 || Opts.getGCMode() == LangOptions::NonGC)
|
||||
Define(Defs, "__strong", "");
|
||||
Builder.defineMacro("__strong", "");
|
||||
else
|
||||
Define(Defs, "__strong", "__attribute__((objc_gc(strong)))");
|
||||
Builder.defineMacro("__strong", "__attribute__((objc_gc(strong)))");
|
||||
|
||||
if (Opts.Static)
|
||||
Define(Defs, "__STATIC__");
|
||||
Builder.defineMacro("__STATIC__");
|
||||
else
|
||||
Define(Defs, "__DYNAMIC__");
|
||||
Builder.defineMacro("__DYNAMIC__");
|
||||
|
||||
if (Opts.POSIXThreads)
|
||||
Define(Defs, "_REENTRANT", "1");
|
||||
Builder.defineMacro("_REENTRANT");
|
||||
}
|
||||
|
||||
static void getDarwinOSXDefines(std::vector<char> &Defs,
|
||||
static void getDarwinOSXDefines(MacroBuilder &Builder,
|
||||
const llvm::Triple &Triple) {
|
||||
if (Triple.getOS() != llvm::Triple::Darwin)
|
||||
return;
|
||||
@ -129,10 +116,11 @@ static void getDarwinOSXDefines(std::vector<char> &Defs,
|
||||
// Handle minor version: 10.4.9 -> darwin8.9 -> "1049"
|
||||
// Cap 10.4.11 -> darwin8.11 -> "1049"
|
||||
MacOSXStr[3] = std::min(Min, 9U)+'0';
|
||||
Define(Defs, "__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__", MacOSXStr);
|
||||
Builder.defineMacro("__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__",
|
||||
MacOSXStr);
|
||||
}
|
||||
|
||||
static void getDarwinIPhoneOSDefines(std::vector<char> &Defs,
|
||||
static void getDarwinIPhoneOSDefines(MacroBuilder &Builder,
|
||||
const llvm::Triple &Triple) {
|
||||
if (Triple.getOS() != llvm::Triple::Darwin)
|
||||
return;
|
||||
@ -151,8 +139,8 @@ static void getDarwinIPhoneOSDefines(std::vector<char> &Defs,
|
||||
|
||||
// Handle minor version: 2.2 -> darwin9.2.2 -> 20200
|
||||
iPhoneOSStr[2] = std::min(Rev, 9U)+'0';
|
||||
Define(Defs, "__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__",
|
||||
iPhoneOSStr);
|
||||
Builder.defineMacro("__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__",
|
||||
iPhoneOSStr);
|
||||
}
|
||||
|
||||
namespace {
|
||||
@ -160,9 +148,9 @@ template<typename Target>
|
||||
class DarwinTargetInfo : public OSTargetInfo<Target> {
|
||||
protected:
|
||||
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
|
||||
std::vector<char> &Defines) const {
|
||||
getDarwinDefines(Defines, Opts);
|
||||
getDarwinOSXDefines(Defines, Triple);
|
||||
MacroBuilder &Builder) const {
|
||||
getDarwinDefines(Builder, Opts);
|
||||
getDarwinOSXDefines(Builder, Triple);
|
||||
}
|
||||
|
||||
public:
|
||||
@ -190,14 +178,14 @@ template<typename Target>
|
||||
class DragonFlyBSDTargetInfo : public OSTargetInfo<Target> {
|
||||
protected:
|
||||
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
|
||||
std::vector<char> &Defs) const {
|
||||
MacroBuilder &Builder) const {
|
||||
// DragonFly defines; list based off of gcc output
|
||||
Define(Defs, "__DragonFly__");
|
||||
Define(Defs, "__DragonFly_cc_version", "100001");
|
||||
Define(Defs, "__ELF__");
|
||||
Define(Defs, "__KPRINTF_ATTRIBUTE__");
|
||||
Define(Defs, "__tune_i386__");
|
||||
DefineStd(Defs, "unix", Opts);
|
||||
Builder.defineMacro("__DragonFly__");
|
||||
Builder.defineMacro("__DragonFly_cc_version", "100001");
|
||||
Builder.defineMacro("__ELF__");
|
||||
Builder.defineMacro("__KPRINTF_ATTRIBUTE__");
|
||||
Builder.defineMacro("__tune_i386__");
|
||||
DefineStd(Builder, "unix", Opts);
|
||||
}
|
||||
public:
|
||||
DragonFlyBSDTargetInfo(const std::string &triple)
|
||||
@ -209,7 +197,7 @@ template<typename Target>
|
||||
class FreeBSDTargetInfo : public OSTargetInfo<Target> {
|
||||
protected:
|
||||
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
|
||||
std::vector<char> &Defs) const {
|
||||
MacroBuilder &Builder) const {
|
||||
// FreeBSD defines; list based off of gcc output
|
||||
|
||||
// FIXME: Move version number handling to llvm::Triple.
|
||||
@ -221,11 +209,11 @@ protected:
|
||||
char version[] = "X00001";
|
||||
version[0] = FreeBSD[0];
|
||||
|
||||
Define(Defs, "__FreeBSD__", release);
|
||||
Define(Defs, "__FreeBSD_cc_version", version);
|
||||
Define(Defs, "__KPRINTF_ATTRIBUTE__");
|
||||
DefineStd(Defs, "unix", Opts);
|
||||
Define(Defs, "__ELF__", "1");
|
||||
Builder.defineMacro("__FreeBSD__", release);
|
||||
Builder.defineMacro("__FreeBSD_cc_version", version);
|
||||
Builder.defineMacro("__KPRINTF_ATTRIBUTE__");
|
||||
DefineStd(Builder, "unix", Opts);
|
||||
Builder.defineMacro("__ELF__");
|
||||
}
|
||||
public:
|
||||
FreeBSDTargetInfo(const std::string &triple)
|
||||
@ -239,14 +227,14 @@ template<typename Target>
|
||||
class LinuxTargetInfo : public OSTargetInfo<Target> {
|
||||
protected:
|
||||
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
|
||||
std::vector<char> &Defs) const {
|
||||
MacroBuilder &Builder) const {
|
||||
// Linux defines; list based off of gcc output
|
||||
DefineStd(Defs, "unix", Opts);
|
||||
DefineStd(Defs, "linux", Opts);
|
||||
Define(Defs, "__gnu_linux__");
|
||||
Define(Defs, "__ELF__", "1");
|
||||
DefineStd(Builder, "unix", Opts);
|
||||
DefineStd(Builder, "linux", Opts);
|
||||
Builder.defineMacro("__gnu_linux__");
|
||||
Builder.defineMacro("__ELF__");
|
||||
if (Opts.POSIXThreads)
|
||||
Define(Defs, "_REENTRANT", "1");
|
||||
Builder.defineMacro("_REENTRANT");
|
||||
}
|
||||
public:
|
||||
LinuxTargetInfo(const std::string& triple)
|
||||
@ -260,13 +248,13 @@ template<typename Target>
|
||||
class NetBSDTargetInfo : public OSTargetInfo<Target> {
|
||||
protected:
|
||||
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
|
||||
std::vector<char> &Defs) const {
|
||||
MacroBuilder &Builder) const {
|
||||
// NetBSD defines; list based off of gcc output
|
||||
Define(Defs, "__NetBSD__", "1");
|
||||
Define(Defs, "__unix__", "1");
|
||||
Define(Defs, "__ELF__", "1");
|
||||
Builder.defineMacro("__NetBSD__");
|
||||
Builder.defineMacro("__unix__");
|
||||
Builder.defineMacro("__ELF__");
|
||||
if (Opts.POSIXThreads)
|
||||
Define(Defs, "_POSIX_THREADS", "1");
|
||||
Builder.defineMacro("_POSIX_THREADS");
|
||||
}
|
||||
public:
|
||||
NetBSDTargetInfo(const std::string &triple)
|
||||
@ -280,14 +268,14 @@ template<typename Target>
|
||||
class OpenBSDTargetInfo : public OSTargetInfo<Target> {
|
||||
protected:
|
||||
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
|
||||
std::vector<char> &Defs) const {
|
||||
MacroBuilder &Builder) const {
|
||||
// OpenBSD defines; list based off of gcc output
|
||||
|
||||
Define(Defs, "__OpenBSD__", "1");
|
||||
DefineStd(Defs, "unix", Opts);
|
||||
Define(Defs, "__ELF__", "1");
|
||||
Builder.defineMacro("__OpenBSD__");
|
||||
DefineStd(Builder, "unix", Opts);
|
||||
Builder.defineMacro("__ELF__");
|
||||
if (Opts.POSIXThreads)
|
||||
Define(Defs, "_POSIX_THREADS", "1");
|
||||
Builder.defineMacro("_POSIX_THREADS");
|
||||
}
|
||||
public:
|
||||
OpenBSDTargetInfo(const std::string &triple)
|
||||
@ -299,12 +287,12 @@ template<typename Target>
|
||||
class PSPTargetInfo : public OSTargetInfo<Target> {
|
||||
protected:
|
||||
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
|
||||
std::vector<char> &Defs) const {
|
||||
MacroBuilder &Builder) const {
|
||||
// PSP defines; list based on the output of the pspdev gcc toolchain.
|
||||
Define(Defs, "PSP", "1");
|
||||
Define(Defs, "_PSP", "1");
|
||||
Define(Defs, "__psp__", "1");
|
||||
Define(Defs, "__ELF__", "1");
|
||||
Builder.defineMacro("PSP");
|
||||
Builder.defineMacro("_PSP");
|
||||
Builder.defineMacro("__psp__");
|
||||
Builder.defineMacro("__ELF__");
|
||||
}
|
||||
public:
|
||||
PSPTargetInfo(const std::string& triple)
|
||||
@ -318,12 +306,12 @@ template<typename Target>
|
||||
class PS3PPUTargetInfo : public OSTargetInfo<Target> {
|
||||
protected:
|
||||
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
|
||||
std::vector<char> &Defs) const {
|
||||
MacroBuilder &Builder) const {
|
||||
// PS3 PPU defines.
|
||||
Define(Defs, "__PPU__", "1");
|
||||
Define(Defs, "__CELLOS_LV2__", "1");
|
||||
Define(Defs, "__ELF__", "1");
|
||||
Define(Defs, "__LP32__", "1");
|
||||
Builder.defineMacro("__PPU__");
|
||||
Builder.defineMacro("__CELLOS_LV2__");
|
||||
Builder.defineMacro("__ELF__");
|
||||
Builder.defineMacro("__LP32__");
|
||||
}
|
||||
public:
|
||||
PS3PPUTargetInfo(const std::string& triple)
|
||||
@ -340,10 +328,10 @@ template<typename Target>
|
||||
class PS3SPUTargetInfo : public OSTargetInfo<Target> {
|
||||
protected:
|
||||
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
|
||||
std::vector<char> &Defs) const {
|
||||
MacroBuilder &Builder) const {
|
||||
// PS3 PPU defines.
|
||||
Define(Defs, "__SPU__", "1");
|
||||
Define(Defs, "__ELF__", "1");
|
||||
Builder.defineMacro("__SPU__");
|
||||
Builder.defineMacro("__ELF__");
|
||||
}
|
||||
public:
|
||||
PS3SPUTargetInfo(const std::string& triple)
|
||||
@ -357,12 +345,12 @@ template<typename Target>
|
||||
class AuroraUXTargetInfo : public OSTargetInfo<Target> {
|
||||
protected:
|
||||
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
|
||||
std::vector<char> &Defs) const {
|
||||
DefineStd(Defs, "sun", Opts);
|
||||
DefineStd(Defs, "unix", Opts);
|
||||
Define(Defs, "__ELF__");
|
||||
Define(Defs, "__svr4__");
|
||||
Define(Defs, "__SVR4");
|
||||
MacroBuilder &Builder) const {
|
||||
DefineStd(Builder, "sun", Opts);
|
||||
DefineStd(Builder, "unix", Opts);
|
||||
Builder.defineMacro("__ELF__");
|
||||
Builder.defineMacro("__svr4__");
|
||||
Builder.defineMacro("__SVR4");
|
||||
}
|
||||
public:
|
||||
AuroraUXTargetInfo(const std::string& triple)
|
||||
@ -378,12 +366,12 @@ template<typename Target>
|
||||
class SolarisTargetInfo : public OSTargetInfo<Target> {
|
||||
protected:
|
||||
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
|
||||
std::vector<char> &Defs) const {
|
||||
DefineStd(Defs, "sun", Opts);
|
||||
DefineStd(Defs, "unix", Opts);
|
||||
Define(Defs, "__ELF__");
|
||||
Define(Defs, "__svr4__");
|
||||
Define(Defs, "__SVR4");
|
||||
MacroBuilder &Builder) const {
|
||||
DefineStd(Builder, "sun", Opts);
|
||||
DefineStd(Builder, "unix", Opts);
|
||||
Builder.defineMacro("__ELF__");
|
||||
Builder.defineMacro("__svr4__");
|
||||
Builder.defineMacro("__SVR4");
|
||||
}
|
||||
public:
|
||||
SolarisTargetInfo(const std::string& triple)
|
||||
@ -416,7 +404,7 @@ public:
|
||||
}
|
||||
|
||||
virtual void getTargetDefines(const LangOptions &Opts,
|
||||
std::vector<char> &Defines) const;
|
||||
MacroBuilder &Builder) const;
|
||||
|
||||
virtual const char *getVAListDeclaration() const {
|
||||
return "typedef char* __builtin_va_list;";
|
||||
@ -460,34 +448,34 @@ const Builtin::Info PPCTargetInfo::BuiltinInfo[] = {
|
||||
/// PPCTargetInfo::getTargetDefines - Return a set of the PowerPC-specific
|
||||
/// #defines that are not tied to a specific subtarget.
|
||||
void PPCTargetInfo::getTargetDefines(const LangOptions &Opts,
|
||||
std::vector<char> &Defs) const {
|
||||
MacroBuilder &Builder) const {
|
||||
// Target identification.
|
||||
Define(Defs, "__ppc__");
|
||||
Define(Defs, "_ARCH_PPC");
|
||||
Define(Defs, "__POWERPC__");
|
||||
Builder.defineMacro("__ppc__");
|
||||
Builder.defineMacro("_ARCH_PPC");
|
||||
Builder.defineMacro("__POWERPC__");
|
||||
if (PointerWidth == 64) {
|
||||
Define(Defs, "_ARCH_PPC64");
|
||||
Define(Defs, "_LP64");
|
||||
Define(Defs, "__LP64__");
|
||||
Define(Defs, "__ppc64__");
|
||||
Builder.defineMacro("_ARCH_PPC64");
|
||||
Builder.defineMacro("_LP64");
|
||||
Builder.defineMacro("__LP64__");
|
||||
Builder.defineMacro("__ppc64__");
|
||||
} else {
|
||||
Define(Defs, "__ppc__");
|
||||
Builder.defineMacro("__ppc__");
|
||||
}
|
||||
|
||||
// Target properties.
|
||||
Define(Defs, "_BIG_ENDIAN");
|
||||
Define(Defs, "__BIG_ENDIAN__");
|
||||
Builder.defineMacro("_BIG_ENDIAN");
|
||||
Builder.defineMacro("__BIG_ENDIAN__");
|
||||
|
||||
// Subtarget options.
|
||||
Define(Defs, "__NATURAL_ALIGNMENT__");
|
||||
Define(Defs, "__REGISTER_PREFIX__", "");
|
||||
Builder.defineMacro("__NATURAL_ALIGNMENT__");
|
||||
Builder.defineMacro("__REGISTER_PREFIX__", "");
|
||||
|
||||
// FIXME: Should be controlled by command line option.
|
||||
Define(Defs, "__LONG_DOUBLE_128__");
|
||||
Builder.defineMacro("__LONG_DOUBLE_128__");
|
||||
|
||||
if (Opts.AltiVec) {
|
||||
Define(Defs, "__VEC__", "10206");
|
||||
Define(Defs, "__ALTIVEC__", "1");
|
||||
Builder.defineMacro("__VEC__", "10206");
|
||||
Builder.defineMacro("__ALTIVEC__");
|
||||
}
|
||||
}
|
||||
|
||||
@ -682,7 +670,7 @@ public:
|
||||
return "~{dirflag},~{fpsr},~{flags}";
|
||||
}
|
||||
virtual void getTargetDefines(const LangOptions &Opts,
|
||||
std::vector<char> &Defines) const;
|
||||
MacroBuilder &Builder) const;
|
||||
virtual bool setFeatureEnabled(llvm::StringMap<bool> &Features,
|
||||
const std::string &Name,
|
||||
bool Enabled) const;
|
||||
@ -828,51 +816,51 @@ void X86TargetInfo::HandleTargetFeatures(std::vector<std::string> &Features) {
|
||||
/// X86TargetInfo::getTargetDefines - Return a set of the X86-specific #defines
|
||||
/// that are not tied to a specific subtarget.
|
||||
void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
|
||||
std::vector<char> &Defs) const {
|
||||
MacroBuilder &Builder) const {
|
||||
// Target identification.
|
||||
if (PointerWidth == 64) {
|
||||
Define(Defs, "_LP64");
|
||||
Define(Defs, "__LP64__");
|
||||
Define(Defs, "__amd64__");
|
||||
Define(Defs, "__amd64");
|
||||
Define(Defs, "__x86_64");
|
||||
Define(Defs, "__x86_64__");
|
||||
Builder.defineMacro("_LP64");
|
||||
Builder.defineMacro("__LP64__");
|
||||
Builder.defineMacro("__amd64__");
|
||||
Builder.defineMacro("__amd64");
|
||||
Builder.defineMacro("__x86_64");
|
||||
Builder.defineMacro("__x86_64__");
|
||||
} else {
|
||||
DefineStd(Defs, "i386", Opts);
|
||||
DefineStd(Builder, "i386", Opts);
|
||||
}
|
||||
|
||||
// Target properties.
|
||||
Define(Defs, "__LITTLE_ENDIAN__");
|
||||
Builder.defineMacro("__LITTLE_ENDIAN__");
|
||||
|
||||
// Subtarget options.
|
||||
Define(Defs, "__nocona");
|
||||
Define(Defs, "__nocona__");
|
||||
Define(Defs, "__tune_nocona__");
|
||||
Define(Defs, "__REGISTER_PREFIX__", "");
|
||||
Builder.defineMacro("__nocona");
|
||||
Builder.defineMacro("__nocona__");
|
||||
Builder.defineMacro("__tune_nocona__");
|
||||
Builder.defineMacro("__REGISTER_PREFIX__", "");
|
||||
|
||||
// Define __NO_MATH_INLINES on linux/x86 so that we don't get inline
|
||||
// functions in glibc header files that use FP Stack inline asm which the
|
||||
// backend can't deal with (PR879).
|
||||
Define(Defs, "__NO_MATH_INLINES");
|
||||
Builder.defineMacro("__NO_MATH_INLINES");
|
||||
|
||||
// Each case falls through to the previous one here.
|
||||
switch (SSELevel) {
|
||||
case SSE42:
|
||||
Define(Defs, "__SSE4_2__");
|
||||
Builder.defineMacro("__SSE4_2__");
|
||||
case SSE41:
|
||||
Define(Defs, "__SSE4_1__");
|
||||
Builder.defineMacro("__SSE4_1__");
|
||||
case SSSE3:
|
||||
Define(Defs, "__SSSE3__");
|
||||
Builder.defineMacro("__SSSE3__");
|
||||
case SSE3:
|
||||
Define(Defs, "__SSE3__");
|
||||
Builder.defineMacro("__SSE3__");
|
||||
case SSE2:
|
||||
Define(Defs, "__SSE2__");
|
||||
Define(Defs, "__SSE2_MATH__"); // -mfp-math=sse always implied.
|
||||
Builder.defineMacro("__SSE2__");
|
||||
Builder.defineMacro("__SSE2_MATH__"); // -mfp-math=sse always implied.
|
||||
case SSE1:
|
||||
Define(Defs, "__SSE__");
|
||||
Define(Defs, "__SSE_MATH__"); // -mfp-math=sse always implied.
|
||||
Builder.defineMacro("__SSE__");
|
||||
Builder.defineMacro("__SSE_MATH__"); // -mfp-math=sse always implied.
|
||||
case MMX:
|
||||
Define(Defs, "__MMX__");
|
||||
Builder.defineMacro("__MMX__");
|
||||
case NoMMXSSE:
|
||||
break;
|
||||
}
|
||||
@ -999,13 +987,13 @@ public:
|
||||
"v128:128:128-a0:0:64-f80:32:32-n8:16:32";
|
||||
}
|
||||
virtual void getTargetDefines(const LangOptions &Opts,
|
||||
std::vector<char> &Defines) const {
|
||||
X86_32TargetInfo::getTargetDefines(Opts, Defines);
|
||||
MacroBuilder &Builder) const {
|
||||
X86_32TargetInfo::getTargetDefines(Opts, Builder);
|
||||
// This list is based off of the the list of things MingW defines
|
||||
Define(Defines, "_WIN32");
|
||||
DefineStd(Defines, "WIN32", Opts);
|
||||
DefineStd(Defines, "WINNT", Opts);
|
||||
Define(Defines, "_X86_");
|
||||
Builder.defineMacro("_WIN32");
|
||||
DefineStd(Builder, "WIN32", Opts);
|
||||
DefineStd(Builder, "WINNT", Opts);
|
||||
Builder.defineMacro("_X86_");
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace
|
||||
@ -1019,12 +1007,12 @@ public:
|
||||
: WindowsX86_32TargetInfo(triple) {
|
||||
}
|
||||
virtual void getTargetDefines(const LangOptions &Opts,
|
||||
std::vector<char> &Defines) const {
|
||||
WindowsX86_32TargetInfo::getTargetDefines(Opts, Defines);
|
||||
MacroBuilder &Builder) const {
|
||||
WindowsX86_32TargetInfo::getTargetDefines(Opts, Builder);
|
||||
// The value of the following reflects processor type.
|
||||
// 300=386, 400=486, 500=Pentium, 600=Blend (default)
|
||||
// We lost the original triple, so we use the default.
|
||||
Define(Defines, "_M_IX86", "600");
|
||||
Builder.defineMacro("_M_IX86", "600");
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace
|
||||
@ -1037,11 +1025,11 @@ public:
|
||||
: WindowsX86_32TargetInfo(triple) {
|
||||
}
|
||||
virtual void getTargetDefines(const LangOptions &Opts,
|
||||
std::vector<char> &Defines) const {
|
||||
WindowsX86_32TargetInfo::getTargetDefines(Opts, Defines);
|
||||
Define(Defines, "__MSVCRT__");
|
||||
Define(Defines, "__MINGW32__");
|
||||
Define(Defines, "__declspec", "__declspec");
|
||||
MacroBuilder &Builder) const {
|
||||
WindowsX86_32TargetInfo::getTargetDefines(Opts, Builder);
|
||||
Builder.defineMacro("__MSVCRT__");
|
||||
Builder.defineMacro("__MINGW32__");
|
||||
Builder.defineMacro("__declspec", "__declspec");
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace
|
||||
@ -1060,11 +1048,11 @@ public:
|
||||
"a0:0:64-f80:32:32-n8:16:32";
|
||||
}
|
||||
virtual void getTargetDefines(const LangOptions &Opts,
|
||||
std::vector<char> &Defines) const {
|
||||
X86_32TargetInfo::getTargetDefines(Opts, Defines);
|
||||
Define(Defines, "__CYGWIN__");
|
||||
Define(Defines, "__CYGWIN32__");
|
||||
DefineStd(Defines, "unix", Opts);
|
||||
MacroBuilder &Builder) const {
|
||||
X86_32TargetInfo::getTargetDefines(Opts, Builder);
|
||||
Builder.defineMacro("__CYGWIN__");
|
||||
Builder.defineMacro("__CYGWIN32__");
|
||||
DefineStd(Builder, "unix", Opts);
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace
|
||||
@ -1116,10 +1104,10 @@ public:
|
||||
DoubleAlign = LongLongAlign = 64;
|
||||
}
|
||||
virtual void getTargetDefines(const LangOptions &Opts,
|
||||
std::vector<char> &Defines) const {
|
||||
X86_64TargetInfo::getTargetDefines(Opts, Defines);
|
||||
Define(Defines, "_WIN64");
|
||||
DefineStd(Defines, "WIN64", Opts);
|
||||
MacroBuilder &Builder) const {
|
||||
X86_64TargetInfo::getTargetDefines(Opts, Builder);
|
||||
Builder.defineMacro("_WIN64");
|
||||
DefineStd(Builder, "WIN64", Opts);
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace
|
||||
@ -1132,9 +1120,9 @@ public:
|
||||
: WindowsX86_64TargetInfo(triple) {
|
||||
}
|
||||
virtual void getTargetDefines(const LangOptions &Opts,
|
||||
std::vector<char> &Defines) const {
|
||||
WindowsX86_64TargetInfo::getTargetDefines(Opts, Defines);
|
||||
Define(Defines, "_M_X64");
|
||||
MacroBuilder &Builder) const {
|
||||
WindowsX86_64TargetInfo::getTargetDefines(Opts, Builder);
|
||||
Builder.defineMacro("_M_X64");
|
||||
}
|
||||
virtual const char *getVAListDeclaration() const {
|
||||
return "typedef char* va_list;";
|
||||
@ -1150,11 +1138,11 @@ public:
|
||||
: WindowsX86_64TargetInfo(triple) {
|
||||
}
|
||||
virtual void getTargetDefines(const LangOptions &Opts,
|
||||
std::vector<char> &Defines) const {
|
||||
WindowsX86_64TargetInfo::getTargetDefines(Opts, Defines);
|
||||
Define(Defines, "__MSVCRT__");
|
||||
Define(Defines, "__MINGW64__");
|
||||
Define(Defines, "__declspec");
|
||||
MacroBuilder &Builder) const {
|
||||
WindowsX86_64TargetInfo::getTargetDefines(Opts, Builder);
|
||||
Builder.defineMacro("__MSVCRT__");
|
||||
Builder.defineMacro("__MINGW64__");
|
||||
Builder.defineMacro("__declspec");
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace
|
||||
@ -1342,61 +1330,58 @@ public:
|
||||
return true;
|
||||
}
|
||||
virtual void getTargetDefines(const LangOptions &Opts,
|
||||
std::vector<char> &Defs) const {
|
||||
MacroBuilder &Builder) const {
|
||||
// Target identification.
|
||||
Define(Defs, "__arm");
|
||||
Define(Defs, "__arm__");
|
||||
Builder.defineMacro("__arm");
|
||||
Builder.defineMacro("__arm__");
|
||||
|
||||
// Target properties.
|
||||
Define(Defs, "__ARMEL__");
|
||||
Define(Defs, "__LITTLE_ENDIAN__");
|
||||
Define(Defs, "__REGISTER_PREFIX__", "");
|
||||
Builder.defineMacro("__ARMEL__");
|
||||
Builder.defineMacro("__LITTLE_ENDIAN__");
|
||||
Builder.defineMacro("__REGISTER_PREFIX__", "");
|
||||
|
||||
llvm::StringRef CPUArch = getCPUDefineSuffix(CPU);
|
||||
std::string ArchName = "__ARM_ARCH_";
|
||||
ArchName += CPUArch;
|
||||
ArchName += "__";
|
||||
Define(Defs, ArchName);
|
||||
Builder.defineMacro("__ARM_ARCH_" + CPUArch + "__");
|
||||
|
||||
// Subtarget options.
|
||||
|
||||
// FIXME: It's more complicated than this and we don't really support
|
||||
// interworking.
|
||||
if ('5' <= CPUArch[0] && CPUArch[0] <= '7')
|
||||
Define(Defs, "__THUMB_INTERWORK__");
|
||||
Builder.defineMacro("__THUMB_INTERWORK__");
|
||||
|
||||
if (ABI == "aapcs" || ABI == "aapcs-linux")
|
||||
Define(Defs, "__ARM_EABI__");
|
||||
Builder.defineMacro("__ARM_EABI__");
|
||||
|
||||
if (SoftFloat)
|
||||
Define(Defs, "__SOFTFP__");
|
||||
Builder.defineMacro("__SOFTFP__");
|
||||
|
||||
if (CPU == "xscale")
|
||||
Define(Defs, "__XSCALE__");
|
||||
Builder.defineMacro("__XSCALE__");
|
||||
|
||||
bool IsThumb2 = IsThumb && (CPUArch == "6T2" || CPUArch.startswith("7"));
|
||||
if (IsThumb) {
|
||||
Define(Defs, "__THUMBEL__");
|
||||
Define(Defs, "__thumb__");
|
||||
Builder.defineMacro("__THUMBEL__");
|
||||
Builder.defineMacro("__thumb__");
|
||||
if (IsThumb2)
|
||||
Define(Defs, "__thumb2__");
|
||||
Builder.defineMacro("__thumb2__");
|
||||
}
|
||||
|
||||
// Note, this is always on in gcc, even though it doesn't make sense.
|
||||
Define(Defs, "__APCS_32__");
|
||||
Builder.defineMacro("__APCS_32__");
|
||||
|
||||
if (FPUModeIsVFP((FPUMode) FPU))
|
||||
Define(Defs, "__VFP_FP__");
|
||||
Builder.defineMacro("__VFP_FP__");
|
||||
|
||||
// This only gets set when Neon instructions are actually available, unlike
|
||||
// the VFP define, hence the soft float and arch check. This is subtly
|
||||
// different from gcc, we follow the intent which was that it should be set
|
||||
// when Neon instructions are actually available.
|
||||
if (FPU == NeonFPU && !SoftFloat && IsThumb2)
|
||||
Define(Defs, "__ARM_NEON__");
|
||||
Builder.defineMacro("__ARM_NEON__");
|
||||
|
||||
if (getTriple().getOS() == llvm::Triple::Darwin)
|
||||
Define(Defs, "__USING_SJLJ_EXCEPTIONS__");
|
||||
Builder.defineMacro("__USING_SJLJ_EXCEPTIONS__");
|
||||
}
|
||||
virtual void getTargetBuiltins(const Builtin::Info *&Records,
|
||||
unsigned &NumRecords) const {
|
||||
@ -1475,9 +1460,9 @@ class DarwinARMTargetInfo :
|
||||
public DarwinTargetInfo<ARMTargetInfo> {
|
||||
protected:
|
||||
virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
|
||||
std::vector<char> &Defines) const {
|
||||
getDarwinDefines(Defines, Opts);
|
||||
getDarwinIPhoneOSDefines(Defines, Triple);
|
||||
MacroBuilder &Builder) const {
|
||||
getDarwinDefines(Builder, Opts);
|
||||
getDarwinIPhoneOSDefines(Builder, Triple);
|
||||
}
|
||||
|
||||
public:
|
||||
@ -1497,10 +1482,10 @@ public:
|
||||
"i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32";
|
||||
}
|
||||
virtual void getTargetDefines(const LangOptions &Opts,
|
||||
std::vector<char> &Defines) const {
|
||||
DefineStd(Defines, "sparc", Opts);
|
||||
Define(Defines, "__sparcv8");
|
||||
Define(Defines, "__REGISTER_PREFIX__", "");
|
||||
MacroBuilder &Builder) const {
|
||||
DefineStd(Builder, "sparc", Opts);
|
||||
Builder.defineMacro("__sparcv8");
|
||||
Builder.defineMacro("__REGISTER_PREFIX__", "");
|
||||
}
|
||||
virtual void getTargetBuiltins(const Builtin::Info *&Records,
|
||||
unsigned &NumRecords) const {
|
||||
@ -1630,18 +1615,18 @@ namespace {
|
||||
virtual uint64_t getPointerWidthV(unsigned AddrSpace) const { return 16; }
|
||||
virtual uint64_t getPointerAlignV(unsigned AddrSpace) const { return 8; }
|
||||
virtual void getTargetDefines(const LangOptions &Opts,
|
||||
std::vector<char> &Defines) const {
|
||||
Define(Defines, "__pic16");
|
||||
Define(Defines, "rom", "__attribute__((address_space(1)))");
|
||||
Define(Defines, "ram", "__attribute__((address_space(0)))");
|
||||
Define(Defines, "_section(SectName)",
|
||||
MacroBuilder &Builder) const {
|
||||
Builder.defineMacro("__pic16");
|
||||
Builder.defineMacro("rom", "__attribute__((address_space(1)))");
|
||||
Builder.defineMacro("ram", "__attribute__((address_space(0)))");
|
||||
Builder.defineMacro("_section(SectName)",
|
||||
"__attribute__((section(SectName)))");
|
||||
Define(Defines, "near",
|
||||
Builder.defineMacro("near",
|
||||
"__attribute__((section(\"Address=NEAR\")))");
|
||||
Define(Defines, "_address(Addr)",
|
||||
Builder.defineMacro("_address(Addr)",
|
||||
"__attribute__((section(\"Address=\"#Addr)))");
|
||||
Define(Defines, "_CONFIG(conf)", "asm(\"CONFIG \"#conf)");
|
||||
Define(Defines, "_interrupt",
|
||||
Builder.defineMacro("_CONFIG(conf)", "asm(\"CONFIG \"#conf)");
|
||||
Builder.defineMacro("_interrupt",
|
||||
"__attribute__((section(\"interrupt=0x4\"))) \
|
||||
__attribute__((used))");
|
||||
}
|
||||
@ -1672,7 +1657,8 @@ namespace {
|
||||
MSP430TargetInfo(const std::string& triple) : TargetInfo(triple) {
|
||||
TLSSupported = false;
|
||||
IntWidth = 16;
|
||||
LongWidth = LongLongWidth = 32;
|
||||
LongWidth = 32;
|
||||
LongLongWidth = 64;
|
||||
PointerWidth = 16;
|
||||
IntAlign = 8;
|
||||
LongAlign = LongLongAlign = 8;
|
||||
@ -1686,9 +1672,9 @@ namespace {
|
||||
DescriptionString = "e-p:16:16:16-i8:8:8-i16:16:16-i32:16:32-n8:16";
|
||||
}
|
||||
virtual void getTargetDefines(const LangOptions &Opts,
|
||||
std::vector<char> &Defines) const {
|
||||
Define(Defines, "MSP430");
|
||||
Define(Defines, "__MSP430__");
|
||||
MacroBuilder &Builder) const {
|
||||
Builder.defineMacro("MSP430");
|
||||
Builder.defineMacro("__MSP430__");
|
||||
// FIXME: defines for different 'flavours' of MCU
|
||||
}
|
||||
virtual void getTargetBuiltins(const Builtin::Info *&Records,
|
||||
@ -1746,9 +1732,9 @@ namespace {
|
||||
"i64:64:64-f32:32:32-f64:64:64-f128:128:128-a0:16:16-n32:64";
|
||||
}
|
||||
virtual void getTargetDefines(const LangOptions &Opts,
|
||||
std::vector<char> &Defines) const {
|
||||
Define(Defines, "__s390__");
|
||||
Define(Defines, "__s390x__");
|
||||
MacroBuilder &Builder) const {
|
||||
Builder.defineMacro("__s390__");
|
||||
Builder.defineMacro("__s390x__");
|
||||
}
|
||||
virtual void getTargetBuiltins(const Builtin::Info *&Records,
|
||||
unsigned &NumRecords) const {
|
||||
@ -1805,12 +1791,12 @@ namespace {
|
||||
}
|
||||
|
||||
virtual void getTargetDefines(const LangOptions &Opts,
|
||||
std::vector<char> &Defines) const {
|
||||
DefineStd(Defines, "bfin", Opts);
|
||||
DefineStd(Defines, "BFIN", Opts);
|
||||
Define(Defines, "__ADSPBLACKFIN__");
|
||||
MacroBuilder &Builder) const {
|
||||
DefineStd(Builder, "bfin", Opts);
|
||||
DefineStd(Builder, "BFIN", Opts);
|
||||
Builder.defineMacro("__ADSPBLACKFIN__");
|
||||
// FIXME: This one is really dependent on -mcpu
|
||||
Define(Defines, "__ADSPLPBLACKFIN__");
|
||||
Builder.defineMacro("__ADSPLPBLACKFIN__");
|
||||
// FIXME: Add cpu-dependent defines and __SILICON_REVISION__
|
||||
}
|
||||
|
||||
@ -1906,10 +1892,10 @@ namespace {
|
||||
}
|
||||
|
||||
virtual void getTargetDefines(const LangOptions &Opts,
|
||||
std::vector<char> &Defines) const {
|
||||
DefineStd(Defines, "tce", Opts);
|
||||
Define(Defines, "__TCE__");
|
||||
Define(Defines, "__TCE_V1__");
|
||||
MacroBuilder &Builder) const {
|
||||
DefineStd(Builder, "tce", Opts);
|
||||
Builder.defineMacro("__TCE__");
|
||||
Builder.defineMacro("__TCE_V1__");
|
||||
}
|
||||
virtual void getTargetBuiltins(const Builtin::Info *&Records,
|
||||
unsigned &NumRecords) const {}
|
||||
@ -1940,12 +1926,12 @@ public:
|
||||
"i64:32:64-f32:32:32-f64:64:64-v64:64:64-n32";
|
||||
}
|
||||
virtual void getTargetDefines(const LangOptions &Opts,
|
||||
std::vector<char> &Defines) const {
|
||||
DefineStd(Defines, "mips", Opts);
|
||||
Define(Defines, "_mips");
|
||||
DefineStd(Defines, "MIPSEB", Opts);
|
||||
Define(Defines, "_MIPSEB");
|
||||
Define(Defines, "__REGISTER_PREFIX__", "");
|
||||
MacroBuilder &Builder) const {
|
||||
DefineStd(Builder, "mips", Opts);
|
||||
Builder.defineMacro("_mips");
|
||||
DefineStd(Builder, "MIPSEB", Opts);
|
||||
Builder.defineMacro("_MIPSEB");
|
||||
Builder.defineMacro("__REGISTER_PREFIX__", "");
|
||||
}
|
||||
virtual void getTargetBuiltins(const Builtin::Info *&Records,
|
||||
unsigned &NumRecords) const {
|
||||
@ -2047,16 +2033,16 @@ public:
|
||||
}
|
||||
|
||||
virtual void getTargetDefines(const LangOptions &Opts,
|
||||
std::vector<char> &Defines) const;
|
||||
MacroBuilder &Builder) const;
|
||||
};
|
||||
|
||||
void MipselTargetInfo::getTargetDefines(const LangOptions &Opts,
|
||||
std::vector<char> &Defines) const {
|
||||
DefineStd(Defines, "mips", Opts);
|
||||
Define(Defines, "_mips");
|
||||
DefineStd(Defines, "MIPSEL", Opts);
|
||||
Define(Defines, "_MIPSEL");
|
||||
Define(Defines, "__REGISTER_PREFIX__", "");
|
||||
MacroBuilder &Builder) const {
|
||||
DefineStd(Builder, "mips", Opts);
|
||||
Builder.defineMacro("_mips");
|
||||
DefineStd(Builder, "MIPSEL", Opts);
|
||||
Builder.defineMacro("_MIPSEL");
|
||||
Builder.defineMacro("__REGISTER_PREFIX__", "");
|
||||
}
|
||||
} // end anonymous namespace.
|
||||
|
||||
@ -2171,6 +2157,8 @@ static TargetInfo *AllocateTarget(const std::string &T) {
|
||||
return new DarwinX86_64TargetInfo(T);
|
||||
case llvm::Triple::Linux:
|
||||
return new LinuxTargetInfo<X86_64TargetInfo>(T);
|
||||
case llvm::Triple::DragonFly:
|
||||
return new DragonFlyBSDTargetInfo<X86_64TargetInfo>(T);
|
||||
case llvm::Triple::NetBSD:
|
||||
return new NetBSDTargetInfo<X86_64TargetInfo>(T);
|
||||
case llvm::Triple::OpenBSD:
|
||||
|
@ -24,7 +24,7 @@ using namespace clang;
|
||||
using namespace CodeGen;
|
||||
|
||||
llvm::Constant *CodeGenFunction::
|
||||
BuildDescriptorBlockDecl(bool BlockHasCopyDispose, uint64_t Size,
|
||||
BuildDescriptorBlockDecl(bool BlockHasCopyDispose, CharUnits Size,
|
||||
const llvm::StructType* Ty,
|
||||
std::vector<HelperInfo> *NoteForHelper) {
|
||||
const llvm::Type *UnsignedLongTy
|
||||
@ -40,7 +40,7 @@ BuildDescriptorBlockDecl(bool BlockHasCopyDispose, uint64_t Size,
|
||||
// FIXME: What is the right way to say this doesn't fit? We should give
|
||||
// a user diagnostic in that case. Better fix would be to change the
|
||||
// API to size_t.
|
||||
C = llvm::ConstantInt::get(UnsignedLongTy, Size);
|
||||
C = llvm::ConstantInt::get(UnsignedLongTy, Size.getQuantity());
|
||||
Elts.push_back(C);
|
||||
|
||||
if (BlockHasCopyDispose) {
|
||||
@ -176,7 +176,8 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
|
||||
// We run this first so that we set BlockHasCopyDispose from the entire
|
||||
// block literal.
|
||||
// __invoke
|
||||
uint64_t subBlockSize, subBlockAlign;
|
||||
CharUnits subBlockSize;
|
||||
uint64_t subBlockAlign;
|
||||
llvm::SmallVector<const Expr *, 8> subBlockDeclRefDecls;
|
||||
bool subBlockHasCopyDispose = false;
|
||||
llvm::Function *Fn
|
||||
@ -321,13 +322,13 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
|
||||
// compared to gcc by not grabbing the forwarding slot as this must
|
||||
// be done during Block_copy for us, and we can postpone the work
|
||||
// until then.
|
||||
uint64_t offset = BlockDecls[BDRE->getDecl()];
|
||||
CharUnits offset = BlockDecls[BDRE->getDecl()];
|
||||
|
||||
llvm::Value *BlockLiteral = LoadBlockStruct();
|
||||
|
||||
Loc = Builder.CreateGEP(BlockLiteral,
|
||||
llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
|
||||
offset),
|
||||
offset.getQuantity()),
|
||||
"block.literal");
|
||||
Ty = llvm::PointerType::get(Ty, 0);
|
||||
Loc = Builder.CreateBitCast(Loc, Ty);
|
||||
@ -513,12 +514,12 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E,
|
||||
return EmitCall(FnInfo, Func, ReturnValue, Args);
|
||||
}
|
||||
|
||||
uint64_t CodeGenFunction::AllocateBlockDecl(const BlockDeclRefExpr *E) {
|
||||
CharUnits CodeGenFunction::AllocateBlockDecl(const BlockDeclRefExpr *E) {
|
||||
const ValueDecl *VD = E->getDecl();
|
||||
uint64_t &offset = BlockDecls[VD];
|
||||
CharUnits &offset = BlockDecls[VD];
|
||||
|
||||
// See if we have already allocated an offset for this variable.
|
||||
if (offset)
|
||||
if (offset.isPositive())
|
||||
return offset;
|
||||
|
||||
// Don't run the expensive check, unless we have to.
|
||||
@ -535,13 +536,13 @@ uint64_t CodeGenFunction::AllocateBlockDecl(const BlockDeclRefExpr *E) {
|
||||
|
||||
llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const BlockDeclRefExpr *E) {
|
||||
const ValueDecl *VD = E->getDecl();
|
||||
uint64_t offset = AllocateBlockDecl(E);
|
||||
CharUnits offset = AllocateBlockDecl(E);
|
||||
|
||||
|
||||
llvm::Value *BlockLiteral = LoadBlockStruct();
|
||||
llvm::Value *V = Builder.CreateGEP(BlockLiteral,
|
||||
llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
|
||||
offset),
|
||||
offset.getQuantity()),
|
||||
"block.literal");
|
||||
if (E->isByRef()) {
|
||||
const llvm::Type *PtrStructTy
|
||||
@ -594,10 +595,10 @@ BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) {
|
||||
|
||||
// Block literal size. For global blocks we just use the size of the generic
|
||||
// block literal struct.
|
||||
uint64_t BlockLiteralSize =
|
||||
TheTargetData.getTypeStoreSizeInBits(getGenericBlockLiteralType()) / 8;
|
||||
CharUnits BlockLiteralSize = CharUnits::fromQuantity(
|
||||
TheTargetData.getTypeStoreSizeInBits(getGenericBlockLiteralType()) / 8);
|
||||
DescriptorFields[1] =
|
||||
llvm::ConstantInt::get(UnsignedLongTy,BlockLiteralSize);
|
||||
llvm::ConstantInt::get(UnsignedLongTy,BlockLiteralSize.getQuantity());
|
||||
|
||||
llvm::Constant *DescriptorStruct =
|
||||
llvm::ConstantStruct::get(VMContext, &DescriptorFields[0], 2, false);
|
||||
@ -615,7 +616,8 @@ BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) {
|
||||
std::vector<llvm::Constant*> LiteralFields(FieldCount);
|
||||
|
||||
CodeGenFunction::BlockInfo Info(0, n);
|
||||
uint64_t subBlockSize, subBlockAlign;
|
||||
CharUnits subBlockSize;
|
||||
uint64_t subBlockAlign;
|
||||
llvm::SmallVector<const Expr *, 8> subBlockDeclRefDecls;
|
||||
bool subBlockHasCopyDispose = false;
|
||||
llvm::DenseMap<const Decl*, llvm::Value*> LocalDeclMap;
|
||||
@ -677,7 +679,7 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
|
||||
const BlockInfo& Info,
|
||||
const Decl *OuterFuncDecl,
|
||||
llvm::DenseMap<const Decl*, llvm::Value*> ldm,
|
||||
uint64_t &Size,
|
||||
CharUnits &Size,
|
||||
uint64_t &Align,
|
||||
llvm::SmallVector<const Expr *, 8> &subBlockDeclRefDecls,
|
||||
bool &subBlockHasCopyDispose) {
|
||||
@ -698,8 +700,9 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
|
||||
LocalDeclMap[VD] = i->second;
|
||||
}
|
||||
|
||||
BlockOffset = CGM.getTargetData()
|
||||
.getTypeStoreSizeInBits(CGM.getGenericBlockLiteralType()) / 8;
|
||||
BlockOffset = CharUnits::fromQuantity(
|
||||
CGM.getTargetData()
|
||||
.getTypeStoreSizeInBits(CGM.getGenericBlockLiteralType()) / 8);
|
||||
BlockAlign = getContext().getTypeAlign(getContext().VoidPtrTy) / 8;
|
||||
|
||||
const FunctionType *BlockFunctionType = BExpr->getFunctionType();
|
||||
@ -799,7 +802,8 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
|
||||
|
||||
// The runtime needs a minimum alignment of a void *.
|
||||
uint64_t MinAlign = getContext().getTypeAlign(getContext().VoidPtrTy) / 8;
|
||||
BlockOffset = llvm::RoundUpToAlignment(BlockOffset, MinAlign);
|
||||
BlockOffset = CharUnits::fromQuantity(
|
||||
llvm::RoundUpToAlignment(BlockOffset.getQuantity(), MinAlign));
|
||||
|
||||
Size = BlockOffset;
|
||||
Align = BlockAlign;
|
||||
@ -808,30 +812,32 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
|
||||
return Fn;
|
||||
}
|
||||
|
||||
uint64_t BlockFunction::getBlockOffset(const BlockDeclRefExpr *BDRE) {
|
||||
CharUnits BlockFunction::getBlockOffset(const BlockDeclRefExpr *BDRE) {
|
||||
const ValueDecl *D = dyn_cast<ValueDecl>(BDRE->getDecl());
|
||||
|
||||
uint64_t Size = getContext().getTypeSize(D->getType()) / 8;
|
||||
CharUnits Size = getContext().getTypeSizeInChars(D->getType());
|
||||
uint64_t Align = getContext().getDeclAlignInBytes(D);
|
||||
|
||||
if (BDRE->isByRef()) {
|
||||
Size = getContext().getTypeSize(getContext().VoidPtrTy) / 8;
|
||||
Size = getContext().getTypeSizeInChars(getContext().VoidPtrTy);
|
||||
Align = getContext().getTypeAlign(getContext().VoidPtrTy) / 8;
|
||||
}
|
||||
|
||||
assert ((Align > 0) && "alignment must be 1 byte or more");
|
||||
|
||||
uint64_t OldOffset = BlockOffset;
|
||||
CharUnits OldOffset = BlockOffset;
|
||||
|
||||
// Ensure proper alignment, even if it means we have to have a gap
|
||||
BlockOffset = llvm::RoundUpToAlignment(BlockOffset, Align);
|
||||
BlockOffset = CharUnits::fromQuantity(
|
||||
llvm::RoundUpToAlignment(BlockOffset.getQuantity(), Align));
|
||||
BlockAlign = std::max(Align, BlockAlign);
|
||||
|
||||
uint64_t Pad = BlockOffset - OldOffset;
|
||||
if (Pad) {
|
||||
llvm::ArrayType::get(llvm::Type::getInt8Ty(VMContext), Pad);
|
||||
CharUnits Pad = BlockOffset - OldOffset;
|
||||
if (Pad.isPositive()) {
|
||||
llvm::ArrayType::get(llvm::Type::getInt8Ty(VMContext), Pad.getQuantity());
|
||||
QualType PadTy = getContext().getConstantArrayType(getContext().CharTy,
|
||||
llvm::APInt(32, Pad),
|
||||
llvm::APInt(32,
|
||||
Pad.getQuantity()),
|
||||
ArrayType::Normal, 0);
|
||||
ValueDecl *PadDecl = VarDecl::Create(getContext(), 0, SourceLocation(),
|
||||
0, QualType(PadTy), 0, VarDecl::None);
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
#include "clang/AST/CharUnits.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/AST/ExprCXX.h"
|
||||
#include "clang/AST/ExprObjC.h"
|
||||
@ -175,13 +176,13 @@ public:
|
||||
|
||||
/// BlockOffset - The offset in bytes for the next allocation of an
|
||||
/// imported block variable.
|
||||
uint64_t BlockOffset;
|
||||
CharUnits BlockOffset;
|
||||
/// BlockAlign - Maximal alignment needed for the Block expressed in bytes.
|
||||
uint64_t BlockAlign;
|
||||
|
||||
/// getBlockOffset - Allocate an offset for the ValueDecl from a
|
||||
/// BlockDeclRefExpr in a block literal (BlockExpr).
|
||||
uint64_t getBlockOffset(const BlockDeclRefExpr *E);
|
||||
CharUnits getBlockOffset(const BlockDeclRefExpr *E);
|
||||
|
||||
/// BlockHasCopyDispose - True iff the block uses copy/dispose.
|
||||
bool BlockHasCopyDispose;
|
||||
@ -191,7 +192,7 @@ public:
|
||||
llvm::SmallVector<const Expr *, 8> BlockDeclRefDecls;
|
||||
|
||||
/// BlockDecls - Offsets for all Decls in BlockDeclRefExprs.
|
||||
std::map<const Decl*, uint64_t> BlockDecls;
|
||||
std::map<const Decl*, CharUnits> BlockDecls;
|
||||
|
||||
ImplicitParamDecl *BlockStructDecl;
|
||||
ImplicitParamDecl *getBlockStructDecl() { return BlockStructDecl; }
|
||||
|
@ -26,269 +26,7 @@
|
||||
using namespace clang;
|
||||
using namespace CodeGen;
|
||||
|
||||
RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD,
|
||||
llvm::Value *Callee,
|
||||
ReturnValueSlot ReturnValue,
|
||||
llvm::Value *This,
|
||||
CallExpr::const_arg_iterator ArgBeg,
|
||||
CallExpr::const_arg_iterator ArgEnd) {
|
||||
assert(MD->isInstance() &&
|
||||
"Trying to emit a member call expr on a static method!");
|
||||
|
||||
const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
|
||||
|
||||
CallArgList Args;
|
||||
|
||||
// Push the this ptr.
|
||||
Args.push_back(std::make_pair(RValue::get(This),
|
||||
MD->getThisType(getContext())));
|
||||
|
||||
// And the rest of the call args
|
||||
EmitCallArgs(Args, FPT, ArgBeg, ArgEnd);
|
||||
|
||||
QualType ResultType = MD->getType()->getAs<FunctionType>()->getResultType();
|
||||
return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args), Callee,
|
||||
ReturnValue, Args, MD);
|
||||
}
|
||||
|
||||
/// canDevirtualizeMemberFunctionCalls - Checks whether virtual calls on given
|
||||
/// expr can be devirtualized.
|
||||
static bool canDevirtualizeMemberFunctionCalls(const Expr *Base) {
|
||||
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Base)) {
|
||||
if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
|
||||
// This is a record decl. We know the type and can devirtualize it.
|
||||
return VD->getType()->isRecordType();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// We can always devirtualize calls on temporary object expressions.
|
||||
if (isa<CXXTemporaryObjectExpr>(Base))
|
||||
return true;
|
||||
|
||||
// And calls on bound temporaries.
|
||||
if (isa<CXXBindTemporaryExpr>(Base))
|
||||
return true;
|
||||
|
||||
// Check if this is a call expr that returns a record type.
|
||||
if (const CallExpr *CE = dyn_cast<CallExpr>(Base))
|
||||
return CE->getCallReturnType()->isRecordType();
|
||||
|
||||
// We can't devirtualize the call.
|
||||
return false;
|
||||
}
|
||||
|
||||
RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
|
||||
ReturnValueSlot ReturnValue) {
|
||||
if (isa<BinaryOperator>(CE->getCallee()->IgnoreParens()))
|
||||
return EmitCXXMemberPointerCallExpr(CE, ReturnValue);
|
||||
|
||||
const MemberExpr *ME = cast<MemberExpr>(CE->getCallee()->IgnoreParens());
|
||||
const CXXMethodDecl *MD = cast<CXXMethodDecl>(ME->getMemberDecl());
|
||||
|
||||
if (MD->isStatic()) {
|
||||
// The method is static, emit it as we would a regular call.
|
||||
llvm::Value *Callee = CGM.GetAddrOfFunction(MD);
|
||||
return EmitCall(getContext().getPointerType(MD->getType()), Callee,
|
||||
ReturnValue, CE->arg_begin(), CE->arg_end());
|
||||
}
|
||||
|
||||
const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
|
||||
|
||||
const llvm::Type *Ty =
|
||||
CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
|
||||
FPT->isVariadic());
|
||||
llvm::Value *This;
|
||||
|
||||
if (ME->isArrow())
|
||||
This = EmitScalarExpr(ME->getBase());
|
||||
else {
|
||||
LValue BaseLV = EmitLValue(ME->getBase());
|
||||
This = BaseLV.getAddress();
|
||||
}
|
||||
|
||||
if (MD->isCopyAssignment() && MD->isTrivial()) {
|
||||
// We don't like to generate the trivial copy assignment operator when
|
||||
// it isn't necessary; just produce the proper effect here.
|
||||
llvm::Value *RHS = EmitLValue(*CE->arg_begin()).getAddress();
|
||||
EmitAggregateCopy(This, RHS, CE->getType());
|
||||
return RValue::get(This);
|
||||
}
|
||||
|
||||
// C++ [class.virtual]p12:
|
||||
// Explicit qualification with the scope operator (5.1) suppresses the
|
||||
// virtual call mechanism.
|
||||
//
|
||||
// We also don't emit a virtual call if the base expression has a record type
|
||||
// because then we know what the type is.
|
||||
llvm::Value *Callee;
|
||||
if (const CXXDestructorDecl *Destructor
|
||||
= dyn_cast<CXXDestructorDecl>(MD)) {
|
||||
if (Destructor->isTrivial())
|
||||
return RValue::get(0);
|
||||
if (MD->isVirtual() && !ME->hasQualifier() &&
|
||||
!canDevirtualizeMemberFunctionCalls(ME->getBase())) {
|
||||
Callee = BuildVirtualCall(Destructor, Dtor_Complete, This, Ty);
|
||||
} else {
|
||||
Callee = CGM.GetAddrOfFunction(GlobalDecl(Destructor, Dtor_Complete), Ty);
|
||||
}
|
||||
} else if (MD->isVirtual() && !ME->hasQualifier() &&
|
||||
!canDevirtualizeMemberFunctionCalls(ME->getBase())) {
|
||||
Callee = BuildVirtualCall(MD, This, Ty);
|
||||
} else {
|
||||
Callee = CGM.GetAddrOfFunction(MD, Ty);
|
||||
}
|
||||
|
||||
return EmitCXXMemberCall(MD, Callee, ReturnValue, This,
|
||||
CE->arg_begin(), CE->arg_end());
|
||||
}
|
||||
|
||||
RValue
|
||||
CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E,
|
||||
ReturnValueSlot ReturnValue) {
|
||||
const BinaryOperator *BO =
|
||||
cast<BinaryOperator>(E->getCallee()->IgnoreParens());
|
||||
const Expr *BaseExpr = BO->getLHS();
|
||||
const Expr *MemFnExpr = BO->getRHS();
|
||||
|
||||
const MemberPointerType *MPT =
|
||||
MemFnExpr->getType()->getAs<MemberPointerType>();
|
||||
const FunctionProtoType *FPT =
|
||||
MPT->getPointeeType()->getAs<FunctionProtoType>();
|
||||
const CXXRecordDecl *RD =
|
||||
cast<CXXRecordDecl>(MPT->getClass()->getAs<RecordType>()->getDecl());
|
||||
|
||||
const llvm::FunctionType *FTy =
|
||||
CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(RD, FPT),
|
||||
FPT->isVariadic());
|
||||
|
||||
const llvm::Type *Int8PtrTy =
|
||||
llvm::Type::getInt8Ty(VMContext)->getPointerTo();
|
||||
|
||||
// Get the member function pointer.
|
||||
llvm::Value *MemFnPtr =
|
||||
CreateTempAlloca(ConvertType(MemFnExpr->getType()), "mem.fn");
|
||||
EmitAggExpr(MemFnExpr, MemFnPtr, /*VolatileDest=*/false);
|
||||
|
||||
// Emit the 'this' pointer.
|
||||
llvm::Value *This;
|
||||
|
||||
if (BO->getOpcode() == BinaryOperator::PtrMemI)
|
||||
This = EmitScalarExpr(BaseExpr);
|
||||
else
|
||||
This = EmitLValue(BaseExpr).getAddress();
|
||||
|
||||
// Adjust it.
|
||||
llvm::Value *Adj = Builder.CreateStructGEP(MemFnPtr, 1);
|
||||
Adj = Builder.CreateLoad(Adj, "mem.fn.adj");
|
||||
|
||||
llvm::Value *Ptr = Builder.CreateBitCast(This, Int8PtrTy, "ptr");
|
||||
Ptr = Builder.CreateGEP(Ptr, Adj, "adj");
|
||||
|
||||
This = Builder.CreateBitCast(Ptr, This->getType(), "this");
|
||||
|
||||
llvm::Value *FnPtr = Builder.CreateStructGEP(MemFnPtr, 0, "mem.fn.ptr");
|
||||
|
||||
const llvm::Type *PtrDiffTy = ConvertType(getContext().getPointerDiffType());
|
||||
|
||||
llvm::Value *FnAsInt = Builder.CreateLoad(FnPtr, "fn");
|
||||
|
||||
// If the LSB in the function pointer is 1, the function pointer points to
|
||||
// a virtual function.
|
||||
llvm::Value *IsVirtual
|
||||
= Builder.CreateAnd(FnAsInt, llvm::ConstantInt::get(PtrDiffTy, 1),
|
||||
"and");
|
||||
|
||||
IsVirtual = Builder.CreateTrunc(IsVirtual,
|
||||
llvm::Type::getInt1Ty(VMContext));
|
||||
|
||||
llvm::BasicBlock *FnVirtual = createBasicBlock("fn.virtual");
|
||||
llvm::BasicBlock *FnNonVirtual = createBasicBlock("fn.nonvirtual");
|
||||
llvm::BasicBlock *FnEnd = createBasicBlock("fn.end");
|
||||
|
||||
Builder.CreateCondBr(IsVirtual, FnVirtual, FnNonVirtual);
|
||||
EmitBlock(FnVirtual);
|
||||
|
||||
const llvm::Type *VTableTy =
|
||||
FTy->getPointerTo()->getPointerTo()->getPointerTo();
|
||||
|
||||
llvm::Value *VTable = Builder.CreateBitCast(This, VTableTy);
|
||||
VTable = Builder.CreateLoad(VTable);
|
||||
|
||||
VTable = Builder.CreateGEP(VTable, FnAsInt, "fn");
|
||||
|
||||
// Since the function pointer is 1 plus the virtual table offset, we
|
||||
// subtract 1 by using a GEP.
|
||||
VTable = Builder.CreateConstGEP1_64(VTable, (uint64_t)-1);
|
||||
|
||||
llvm::Value *VirtualFn = Builder.CreateLoad(VTable, "virtualfn");
|
||||
|
||||
EmitBranch(FnEnd);
|
||||
EmitBlock(FnNonVirtual);
|
||||
|
||||
// If the function is not virtual, just load the pointer.
|
||||
llvm::Value *NonVirtualFn = Builder.CreateLoad(FnPtr, "fn");
|
||||
NonVirtualFn = Builder.CreateIntToPtr(NonVirtualFn, FTy->getPointerTo());
|
||||
|
||||
EmitBlock(FnEnd);
|
||||
|
||||
llvm::PHINode *Callee = Builder.CreatePHI(FTy->getPointerTo());
|
||||
Callee->reserveOperandSpace(2);
|
||||
Callee->addIncoming(VirtualFn, FnVirtual);
|
||||
Callee->addIncoming(NonVirtualFn, FnNonVirtual);
|
||||
|
||||
CallArgList Args;
|
||||
|
||||
QualType ThisType =
|
||||
getContext().getPointerType(getContext().getTagDeclType(RD));
|
||||
|
||||
// Push the this ptr.
|
||||
Args.push_back(std::make_pair(RValue::get(This), ThisType));
|
||||
|
||||
// And the rest of the call args
|
||||
EmitCallArgs(Args, FPT, E->arg_begin(), E->arg_end());
|
||||
QualType ResultType = BO->getType()->getAs<FunctionType>()->getResultType();
|
||||
return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args), Callee,
|
||||
ReturnValue, Args);
|
||||
}
|
||||
|
||||
RValue
|
||||
CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E,
|
||||
const CXXMethodDecl *MD,
|
||||
ReturnValueSlot ReturnValue) {
|
||||
assert(MD->isInstance() &&
|
||||
"Trying to emit a member call expr on a static method!");
|
||||
|
||||
if (MD->isCopyAssignment()) {
|
||||
const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(MD->getDeclContext());
|
||||
if (ClassDecl->hasTrivialCopyAssignment()) {
|
||||
assert(!ClassDecl->hasUserDeclaredCopyAssignment() &&
|
||||
"EmitCXXOperatorMemberCallExpr - user declared copy assignment");
|
||||
llvm::Value *This = EmitLValue(E->getArg(0)).getAddress();
|
||||
llvm::Value *Src = EmitLValue(E->getArg(1)).getAddress();
|
||||
QualType Ty = E->getType();
|
||||
EmitAggregateCopy(This, Src, Ty);
|
||||
return RValue::get(This);
|
||||
}
|
||||
}
|
||||
|
||||
const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
|
||||
const llvm::Type *Ty =
|
||||
CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
|
||||
FPT->isVariadic());
|
||||
|
||||
llvm::Value *This = EmitLValue(E->getArg(0)).getAddress();
|
||||
|
||||
llvm::Value *Callee;
|
||||
if (MD->isVirtual() && !canDevirtualizeMemberFunctionCalls(E->getArg(0)))
|
||||
Callee = BuildVirtualCall(MD, This, Ty);
|
||||
else
|
||||
Callee = CGM.GetAddrOfFunction(MD, Ty);
|
||||
|
||||
return EmitCXXMemberCall(MD, Callee, ReturnValue, This,
|
||||
E->arg_begin() + 1, E->arg_end());
|
||||
}
|
||||
|
||||
llvm::Value *CodeGenFunction::LoadCXXThis() {
|
||||
assert(isa<CXXMethodDecl>(CurFuncDecl) &&
|
||||
@ -302,320 +40,6 @@ llvm::Value *CodeGenFunction::LoadCXXThis() {
|
||||
return Builder.CreateLoad(LocalDeclMap[CXXThisDecl], "this");
|
||||
}
|
||||
|
||||
/// EmitCXXAggrConstructorCall - This routine essentially creates a (nested)
|
||||
/// for-loop to call the default constructor on individual members of the
|
||||
/// array.
|
||||
/// 'D' is the default constructor for elements of the array, 'ArrayTy' is the
|
||||
/// array type and 'ArrayPtr' points to the beginning fo the array.
|
||||
/// It is assumed that all relevant checks have been made by the caller.
|
||||
void
|
||||
CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D,
|
||||
const ConstantArrayType *ArrayTy,
|
||||
llvm::Value *ArrayPtr,
|
||||
CallExpr::const_arg_iterator ArgBeg,
|
||||
CallExpr::const_arg_iterator ArgEnd) {
|
||||
|
||||
const llvm::Type *SizeTy = ConvertType(getContext().getSizeType());
|
||||
llvm::Value * NumElements =
|
||||
llvm::ConstantInt::get(SizeTy,
|
||||
getContext().getConstantArrayElementCount(ArrayTy));
|
||||
|
||||
EmitCXXAggrConstructorCall(D, NumElements, ArrayPtr, ArgBeg, ArgEnd);
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D,
|
||||
llvm::Value *NumElements,
|
||||
llvm::Value *ArrayPtr,
|
||||
CallExpr::const_arg_iterator ArgBeg,
|
||||
CallExpr::const_arg_iterator ArgEnd) {
|
||||
const llvm::Type *SizeTy = ConvertType(getContext().getSizeType());
|
||||
|
||||
// Create a temporary for the loop index and initialize it with 0.
|
||||
llvm::Value *IndexPtr = CreateTempAlloca(SizeTy, "loop.index");
|
||||
llvm::Value *Zero = llvm::Constant::getNullValue(SizeTy);
|
||||
Builder.CreateStore(Zero, IndexPtr);
|
||||
|
||||
// Start the loop with a block that tests the condition.
|
||||
llvm::BasicBlock *CondBlock = createBasicBlock("for.cond");
|
||||
llvm::BasicBlock *AfterFor = createBasicBlock("for.end");
|
||||
|
||||
EmitBlock(CondBlock);
|
||||
|
||||
llvm::BasicBlock *ForBody = createBasicBlock("for.body");
|
||||
|
||||
// Generate: if (loop-index < number-of-elements fall to the loop body,
|
||||
// otherwise, go to the block after the for-loop.
|
||||
llvm::Value *Counter = Builder.CreateLoad(IndexPtr);
|
||||
llvm::Value *IsLess = Builder.CreateICmpULT(Counter, NumElements, "isless");
|
||||
// If the condition is true, execute the body.
|
||||
Builder.CreateCondBr(IsLess, ForBody, AfterFor);
|
||||
|
||||
EmitBlock(ForBody);
|
||||
|
||||
llvm::BasicBlock *ContinueBlock = createBasicBlock("for.inc");
|
||||
// Inside the loop body, emit the constructor call on the array element.
|
||||
Counter = Builder.CreateLoad(IndexPtr);
|
||||
llvm::Value *Address = Builder.CreateInBoundsGEP(ArrayPtr, Counter,
|
||||
"arrayidx");
|
||||
|
||||
// C++ [class.temporary]p4:
|
||||
// There are two contexts in which temporaries are destroyed at a different
|
||||
// point than the end of the full-expression. The first context is when a
|
||||
// default constructor is called to initialize an element of an array.
|
||||
// If the constructor has one or more default arguments, the destruction of
|
||||
// every temporary created in a default argument expression is sequenced
|
||||
// before the construction of the next array element, if any.
|
||||
|
||||
// Keep track of the current number of live temporaries.
|
||||
unsigned OldNumLiveTemporaries = LiveTemporaries.size();
|
||||
|
||||
EmitCXXConstructorCall(D, Ctor_Complete, Address, ArgBeg, ArgEnd);
|
||||
|
||||
// Pop temporaries.
|
||||
while (LiveTemporaries.size() > OldNumLiveTemporaries)
|
||||
PopCXXTemporary();
|
||||
|
||||
EmitBlock(ContinueBlock);
|
||||
|
||||
// Emit the increment of the loop counter.
|
||||
llvm::Value *NextVal = llvm::ConstantInt::get(SizeTy, 1);
|
||||
Counter = Builder.CreateLoad(IndexPtr);
|
||||
NextVal = Builder.CreateAdd(Counter, NextVal, "inc");
|
||||
Builder.CreateStore(NextVal, IndexPtr);
|
||||
|
||||
// Finally, branch back up to the condition for the next iteration.
|
||||
EmitBranch(CondBlock);
|
||||
|
||||
// Emit the fall-through block.
|
||||
EmitBlock(AfterFor, true);
|
||||
}
|
||||
|
||||
/// EmitCXXAggrDestructorCall - calls the default destructor on array
|
||||
/// elements in reverse order of construction.
|
||||
void
|
||||
CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D,
|
||||
const ArrayType *Array,
|
||||
llvm::Value *This) {
|
||||
const ConstantArrayType *CA = dyn_cast<ConstantArrayType>(Array);
|
||||
assert(CA && "Do we support VLA for destruction ?");
|
||||
uint64_t ElementCount = getContext().getConstantArrayElementCount(CA);
|
||||
|
||||
const llvm::Type *SizeLTy = ConvertType(getContext().getSizeType());
|
||||
llvm::Value* ElementCountPtr = llvm::ConstantInt::get(SizeLTy, ElementCount);
|
||||
EmitCXXAggrDestructorCall(D, ElementCountPtr, This);
|
||||
}
|
||||
|
||||
/// EmitCXXAggrDestructorCall - calls the default destructor on array
|
||||
/// elements in reverse order of construction.
|
||||
void
|
||||
CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D,
|
||||
llvm::Value *UpperCount,
|
||||
llvm::Value *This) {
|
||||
const llvm::Type *SizeLTy = ConvertType(getContext().getSizeType());
|
||||
llvm::Value *One = llvm::ConstantInt::get(SizeLTy, 1);
|
||||
|
||||
// Create a temporary for the loop index and initialize it with count of
|
||||
// array elements.
|
||||
llvm::Value *IndexPtr = CreateTempAlloca(SizeLTy, "loop.index");
|
||||
|
||||
// Store the number of elements in the index pointer.
|
||||
Builder.CreateStore(UpperCount, IndexPtr);
|
||||
|
||||
// Start the loop with a block that tests the condition.
|
||||
llvm::BasicBlock *CondBlock = createBasicBlock("for.cond");
|
||||
llvm::BasicBlock *AfterFor = createBasicBlock("for.end");
|
||||
|
||||
EmitBlock(CondBlock);
|
||||
|
||||
llvm::BasicBlock *ForBody = createBasicBlock("for.body");
|
||||
|
||||
// Generate: if (loop-index != 0 fall to the loop body,
|
||||
// otherwise, go to the block after the for-loop.
|
||||
llvm::Value* zeroConstant =
|
||||
llvm::Constant::getNullValue(SizeLTy);
|
||||
llvm::Value *Counter = Builder.CreateLoad(IndexPtr);
|
||||
llvm::Value *IsNE = Builder.CreateICmpNE(Counter, zeroConstant,
|
||||
"isne");
|
||||
// If the condition is true, execute the body.
|
||||
Builder.CreateCondBr(IsNE, ForBody, AfterFor);
|
||||
|
||||
EmitBlock(ForBody);
|
||||
|
||||
llvm::BasicBlock *ContinueBlock = createBasicBlock("for.inc");
|
||||
// Inside the loop body, emit the constructor call on the array element.
|
||||
Counter = Builder.CreateLoad(IndexPtr);
|
||||
Counter = Builder.CreateSub(Counter, One);
|
||||
llvm::Value *Address = Builder.CreateInBoundsGEP(This, Counter, "arrayidx");
|
||||
EmitCXXDestructorCall(D, Dtor_Complete, Address);
|
||||
|
||||
EmitBlock(ContinueBlock);
|
||||
|
||||
// Emit the decrement of the loop counter.
|
||||
Counter = Builder.CreateLoad(IndexPtr);
|
||||
Counter = Builder.CreateSub(Counter, One, "dec");
|
||||
Builder.CreateStore(Counter, IndexPtr);
|
||||
|
||||
// Finally, branch back up to the condition for the next iteration.
|
||||
EmitBranch(CondBlock);
|
||||
|
||||
// Emit the fall-through block.
|
||||
EmitBlock(AfterFor, true);
|
||||
}
|
||||
|
||||
/// GenerateCXXAggrDestructorHelper - Generates a helper function which when
|
||||
/// invoked, calls the default destructor on array elements in reverse order of
|
||||
/// construction.
|
||||
llvm::Constant *
|
||||
CodeGenFunction::GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D,
|
||||
const ArrayType *Array,
|
||||
llvm::Value *This) {
|
||||
FunctionArgList Args;
|
||||
ImplicitParamDecl *Dst =
|
||||
ImplicitParamDecl::Create(getContext(), 0,
|
||||
SourceLocation(), 0,
|
||||
getContext().getPointerType(getContext().VoidTy));
|
||||
Args.push_back(std::make_pair(Dst, Dst->getType()));
|
||||
|
||||
llvm::SmallString<16> Name;
|
||||
llvm::raw_svector_ostream(Name) << "__tcf_" << (++UniqueAggrDestructorCount);
|
||||
QualType R = getContext().VoidTy;
|
||||
const CGFunctionInfo &FI = CGM.getTypes().getFunctionInfo(R, Args);
|
||||
const llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI, false);
|
||||
llvm::Function *Fn =
|
||||
llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage,
|
||||
Name.str(),
|
||||
&CGM.getModule());
|
||||
IdentifierInfo *II = &CGM.getContext().Idents.get(Name.str());
|
||||
FunctionDecl *FD = FunctionDecl::Create(getContext(),
|
||||
getContext().getTranslationUnitDecl(),
|
||||
SourceLocation(), II, R, 0,
|
||||
FunctionDecl::Static,
|
||||
false, true);
|
||||
StartFunction(FD, R, Fn, Args, SourceLocation());
|
||||
QualType BaseElementTy = getContext().getBaseElementType(Array);
|
||||
const llvm::Type *BasePtr = ConvertType(BaseElementTy);
|
||||
BasePtr = llvm::PointerType::getUnqual(BasePtr);
|
||||
llvm::Value *BaseAddrPtr = Builder.CreateBitCast(This, BasePtr);
|
||||
EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr);
|
||||
FinishFunction();
|
||||
llvm::Type *Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext),
|
||||
0);
|
||||
llvm::Constant *m = llvm::ConstantExpr::getBitCast(Fn, Ptr8Ty);
|
||||
return m;
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
|
||||
CXXCtorType Type,
|
||||
llvm::Value *This,
|
||||
CallExpr::const_arg_iterator ArgBeg,
|
||||
CallExpr::const_arg_iterator ArgEnd) {
|
||||
if (D->isCopyConstructor()) {
|
||||
const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(D->getDeclContext());
|
||||
if (ClassDecl->hasTrivialCopyConstructor()) {
|
||||
assert(!ClassDecl->hasUserDeclaredCopyConstructor() &&
|
||||
"EmitCXXConstructorCall - user declared copy constructor");
|
||||
const Expr *E = (*ArgBeg);
|
||||
QualType Ty = E->getType();
|
||||
llvm::Value *Src = EmitLValue(E).getAddress();
|
||||
EmitAggregateCopy(This, Src, Ty);
|
||||
return;
|
||||
}
|
||||
} else if (D->isTrivial()) {
|
||||
// FIXME: Track down why we're trying to generate calls to the trivial
|
||||
// default constructor!
|
||||
return;
|
||||
}
|
||||
|
||||
llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Type);
|
||||
|
||||
EmitCXXMemberCall(D, Callee, ReturnValueSlot(), This, ArgBeg, ArgEnd);
|
||||
}
|
||||
|
||||
void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD,
|
||||
CXXDtorType Type,
|
||||
llvm::Value *This) {
|
||||
llvm::Value *Callee = CGM.GetAddrOfCXXDestructor(DD, Type);
|
||||
|
||||
CallArgList Args;
|
||||
|
||||
// Push the this ptr.
|
||||
Args.push_back(std::make_pair(RValue::get(This),
|
||||
DD->getThisType(getContext())));
|
||||
|
||||
// Add a VTT parameter if necessary.
|
||||
// FIXME: This should not be a dummy null parameter!
|
||||
if (Type == Dtor_Base && DD->getParent()->getNumVBases() != 0) {
|
||||
QualType T = getContext().getPointerType(getContext().VoidPtrTy);
|
||||
|
||||
Args.push_back(std::make_pair(RValue::get(CGM.EmitNullConstant(T)), T));
|
||||
}
|
||||
|
||||
// FIXME: We should try to share this code with EmitCXXMemberCall.
|
||||
|
||||
QualType ResultType = DD->getType()->getAs<FunctionType>()->getResultType();
|
||||
EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args), Callee,
|
||||
ReturnValueSlot(), Args, DD);
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest,
|
||||
const CXXConstructExpr *E) {
|
||||
assert(Dest && "Must have a destination!");
|
||||
const CXXConstructorDecl *CD = E->getConstructor();
|
||||
const ConstantArrayType *Array =
|
||||
getContext().getAsConstantArrayType(E->getType());
|
||||
// For a copy constructor, even if it is trivial, must fall thru so
|
||||
// its argument is code-gen'ed.
|
||||
if (!CD->isCopyConstructor()) {
|
||||
QualType InitType = E->getType();
|
||||
if (Array)
|
||||
InitType = getContext().getBaseElementType(Array);
|
||||
const CXXRecordDecl *RD =
|
||||
cast<CXXRecordDecl>(InitType->getAs<RecordType>()->getDecl());
|
||||
if (RD->hasTrivialConstructor())
|
||||
return;
|
||||
}
|
||||
// Code gen optimization to eliminate copy constructor and return
|
||||
// its first argument instead.
|
||||
if (getContext().getLangOptions().ElideConstructors && E->isElidable()) {
|
||||
const Expr *Arg = E->getArg(0);
|
||||
|
||||
if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) {
|
||||
assert((ICE->getCastKind() == CastExpr::CK_NoOp ||
|
||||
ICE->getCastKind() == CastExpr::CK_ConstructorConversion ||
|
||||
ICE->getCastKind() == CastExpr::CK_UserDefinedConversion) &&
|
||||
"Unknown implicit cast kind in constructor elision");
|
||||
Arg = ICE->getSubExpr();
|
||||
}
|
||||
|
||||
if (const CXXFunctionalCastExpr *FCE = dyn_cast<CXXFunctionalCastExpr>(Arg))
|
||||
Arg = FCE->getSubExpr();
|
||||
|
||||
if (const CXXBindTemporaryExpr *BindExpr =
|
||||
dyn_cast<CXXBindTemporaryExpr>(Arg))
|
||||
Arg = BindExpr->getSubExpr();
|
||||
|
||||
EmitAggExpr(Arg, Dest, false);
|
||||
return;
|
||||
}
|
||||
if (Array) {
|
||||
QualType BaseElementTy = getContext().getBaseElementType(Array);
|
||||
const llvm::Type *BasePtr = ConvertType(BaseElementTy);
|
||||
BasePtr = llvm::PointerType::getUnqual(BasePtr);
|
||||
llvm::Value *BaseAddrPtr =
|
||||
Builder.CreateBitCast(Dest, BasePtr);
|
||||
|
||||
EmitCXXAggrConstructorCall(CD, Array, BaseAddrPtr,
|
||||
E->arg_begin(), E->arg_end());
|
||||
}
|
||||
else
|
||||
// Call the constructor.
|
||||
EmitCXXConstructorCall(CD, Ctor_Complete, Dest,
|
||||
E->arg_begin(), E->arg_end());
|
||||
}
|
||||
|
||||
void CodeGenModule::EmitCXXConstructors(const CXXConstructorDecl *D) {
|
||||
EmitGlobal(GlobalDecl(D, Ctor_Complete));
|
||||
EmitGlobal(GlobalDecl(D, Ctor_Base));
|
||||
@ -1001,33 +425,6 @@ CodeGenModule::BuildCovariantThunk(const GlobalDecl &GD, bool Extern,
|
||||
return m;
|
||||
}
|
||||
|
||||
llvm::Value *
|
||||
CodeGenFunction::GetVirtualCXXBaseClassOffset(llvm::Value *This,
|
||||
const CXXRecordDecl *ClassDecl,
|
||||
const CXXRecordDecl *BaseClassDecl) {
|
||||
const llvm::Type *Int8PtrTy =
|
||||
llvm::Type::getInt8Ty(VMContext)->getPointerTo();
|
||||
|
||||
llvm::Value *VTablePtr = Builder.CreateBitCast(This,
|
||||
Int8PtrTy->getPointerTo());
|
||||
VTablePtr = Builder.CreateLoad(VTablePtr, "vtable");
|
||||
|
||||
int64_t VBaseOffsetIndex =
|
||||
CGM.getVtableInfo().getVirtualBaseOffsetIndex(ClassDecl, BaseClassDecl);
|
||||
|
||||
llvm::Value *VBaseOffsetPtr =
|
||||
Builder.CreateConstGEP1_64(VTablePtr, VBaseOffsetIndex, "vbase.offset.ptr");
|
||||
const llvm::Type *PtrDiffTy =
|
||||
ConvertType(getContext().getPointerDiffType());
|
||||
|
||||
VBaseOffsetPtr = Builder.CreateBitCast(VBaseOffsetPtr,
|
||||
PtrDiffTy->getPointerTo());
|
||||
|
||||
llvm::Value *VBaseOffset = Builder.CreateLoad(VBaseOffsetPtr, "vbase.offset");
|
||||
|
||||
return VBaseOffset;
|
||||
}
|
||||
|
||||
static llvm::Value *BuildVirtualCall(CodeGenFunction &CGF, uint64_t VtableIndex,
|
||||
llvm::Value *This, const llvm::Type *Ty) {
|
||||
Ty = Ty->getPointerTo()->getPointerTo()->getPointerTo();
|
||||
@ -1058,71 +455,3 @@ CodeGenFunction::BuildVirtualCall(const CXXDestructorDecl *DD, CXXDtorType Type,
|
||||
|
||||
return ::BuildVirtualCall(*this, VtableIndex, This, Ty);
|
||||
}
|
||||
|
||||
void CodeGenFunction::InitializeVtablePtrs(const CXXRecordDecl *ClassDecl) {
|
||||
if (!ClassDecl->isDynamicClass())
|
||||
return;
|
||||
|
||||
llvm::Constant *Vtable = CGM.getVtableInfo().getVtable(ClassDecl);
|
||||
CodeGenModule::AddrSubMap_t& AddressPoints =
|
||||
*(*CGM.AddressPoints[ClassDecl])[ClassDecl];
|
||||
llvm::Value *ThisPtr = LoadCXXThis();
|
||||
const ASTRecordLayout &Layout = getContext().getASTRecordLayout(ClassDecl);
|
||||
|
||||
// Store address points for virtual bases
|
||||
for (CXXRecordDecl::base_class_const_iterator I =
|
||||
ClassDecl->vbases_begin(), E = ClassDecl->vbases_end(); I != E; ++I) {
|
||||
const CXXBaseSpecifier &Base = *I;
|
||||
CXXRecordDecl *BaseClassDecl
|
||||
= cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
|
||||
uint64_t Offset = Layout.getVBaseClassOffset(BaseClassDecl);
|
||||
InitializeVtablePtrsRecursive(BaseClassDecl, Vtable, AddressPoints,
|
||||
ThisPtr, Offset);
|
||||
}
|
||||
|
||||
// Store address points for non-virtual bases and current class
|
||||
InitializeVtablePtrsRecursive(ClassDecl, Vtable, AddressPoints, ThisPtr, 0);
|
||||
}
|
||||
|
||||
void CodeGenFunction::InitializeVtablePtrsRecursive(
|
||||
const CXXRecordDecl *ClassDecl,
|
||||
llvm::Constant *Vtable,
|
||||
CodeGenModule::AddrSubMap_t& AddressPoints,
|
||||
llvm::Value *ThisPtr,
|
||||
uint64_t Offset) {
|
||||
if (!ClassDecl->isDynamicClass())
|
||||
return;
|
||||
|
||||
// Store address points for non-virtual bases
|
||||
const ASTRecordLayout &Layout = getContext().getASTRecordLayout(ClassDecl);
|
||||
for (CXXRecordDecl::base_class_const_iterator I =
|
||||
ClassDecl->bases_begin(), E = ClassDecl->bases_end(); I != E; ++I) {
|
||||
const CXXBaseSpecifier &Base = *I;
|
||||
if (Base.isVirtual())
|
||||
continue;
|
||||
CXXRecordDecl *BaseClassDecl
|
||||
= cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
|
||||
uint64_t NewOffset = Offset + Layout.getBaseClassOffset(BaseClassDecl);
|
||||
InitializeVtablePtrsRecursive(BaseClassDecl, Vtable, AddressPoints,
|
||||
ThisPtr, NewOffset);
|
||||
}
|
||||
|
||||
// Compute the address point
|
||||
assert(AddressPoints.count(std::make_pair(ClassDecl, Offset)) &&
|
||||
"Missing address point for class");
|
||||
uint64_t AddressPoint = AddressPoints[std::make_pair(ClassDecl, Offset)];
|
||||
llvm::Value *VtableAddressPoint =
|
||||
Builder.CreateConstInBoundsGEP2_64(Vtable, 0, AddressPoint);
|
||||
|
||||
// Compute the address to store the address point
|
||||
const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
|
||||
llvm::Value *VtableField = Builder.CreateBitCast(ThisPtr, Int8PtrTy);
|
||||
VtableField = Builder.CreateConstInBoundsGEP1_64(VtableField, Offset/8);
|
||||
const llvm::Type *AddressPointPtrTy =
|
||||
VtableAddressPoint->getType()->getPointerTo();
|
||||
VtableField = Builder.CreateBitCast(VtableField, AddressPointPtrTy);
|
||||
|
||||
// Store address point
|
||||
Builder.CreateStore(VtableAddressPoint, VtableField);
|
||||
}
|
||||
|
||||
|
@ -431,6 +431,37 @@ void CodeGenFunction::EmitClassAggrCopyAssignment(llvm::Value *Dest,
|
||||
EmitBlock(AfterFor, true);
|
||||
}
|
||||
|
||||
/// GetVTTParameter - Return the VTT parameter that should be passed to a
|
||||
/// base constructor/destructor with virtual bases.
|
||||
static llvm::Value *GetVTTParameter(CodeGenFunction &CGF, GlobalDecl GD) {
|
||||
if (!CGVtableInfo::needsVTTParameter(GD)) {
|
||||
// This constructor/destructor does not need a VTT parameter.
|
||||
return 0;
|
||||
}
|
||||
|
||||
const CXXRecordDecl *RD = cast<CXXMethodDecl>(CGF.CurFuncDecl)->getParent();
|
||||
const CXXRecordDecl *Base = cast<CXXMethodDecl>(GD.getDecl())->getParent();
|
||||
|
||||
llvm::Value *VTT;
|
||||
|
||||
uint64_t SubVTTIndex =
|
||||
CGF.CGM.getVtableInfo().getSubVTTIndex(RD, Base);
|
||||
assert(SubVTTIndex != 0 && "Sub-VTT index must be greater than zero!");
|
||||
|
||||
if (CGVtableInfo::needsVTTParameter(CGF.CurGD)) {
|
||||
// A VTT parameter was passed to the constructor, use it.
|
||||
VTT = CGF.LoadCXXVTT();
|
||||
VTT = CGF.Builder.CreateConstInBoundsGEP1_64(VTT, SubVTTIndex);
|
||||
} else {
|
||||
// We're the complete constructor, so get the VTT by name.
|
||||
VTT = CGF.CGM.getVtableInfo().getVTT(RD);
|
||||
VTT = CGF.Builder.CreateConstInBoundsGEP2_64(VTT, 0, SubVTTIndex);
|
||||
}
|
||||
|
||||
return VTT;
|
||||
}
|
||||
|
||||
|
||||
/// EmitClassMemberwiseCopy - This routine generates code to copy a class
|
||||
/// object from SrcValue to DestValue. Copying can be either a bitwise copy
|
||||
/// or via a copy constructor call.
|
||||
@ -438,11 +469,16 @@ void CodeGenFunction::EmitClassMemberwiseCopy(
|
||||
llvm::Value *Dest, llvm::Value *Src,
|
||||
const CXXRecordDecl *ClassDecl,
|
||||
const CXXRecordDecl *BaseClassDecl, QualType Ty) {
|
||||
CXXCtorType CtorType = Ctor_Complete;
|
||||
|
||||
if (ClassDecl) {
|
||||
Dest = GetAddressOfBaseClass(Dest, ClassDecl, BaseClassDecl,
|
||||
/*NullCheckValue=*/false);
|
||||
Src = GetAddressOfBaseClass(Src, ClassDecl, BaseClassDecl,
|
||||
/*NullCheckValue=*/false);
|
||||
|
||||
// We want to call the base constructor.
|
||||
CtorType = Ctor_Base;
|
||||
}
|
||||
if (BaseClassDecl->hasTrivialCopyConstructor()) {
|
||||
EmitAggregateCopy(Dest, Src, Ty);
|
||||
@ -451,13 +487,19 @@ void CodeGenFunction::EmitClassMemberwiseCopy(
|
||||
|
||||
if (CXXConstructorDecl *BaseCopyCtor =
|
||||
BaseClassDecl->getCopyConstructor(getContext(), 0)) {
|
||||
llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(BaseCopyCtor,
|
||||
Ctor_Complete);
|
||||
llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(BaseCopyCtor, CtorType);
|
||||
CallArgList CallArgs;
|
||||
// Push the this (Dest) ptr.
|
||||
CallArgs.push_back(std::make_pair(RValue::get(Dest),
|
||||
BaseCopyCtor->getThisType(getContext())));
|
||||
|
||||
// Push the VTT parameter, if necessary.
|
||||
if (llvm::Value *VTT =
|
||||
GetVTTParameter(*this, GlobalDecl(BaseCopyCtor, CtorType))) {
|
||||
QualType T = getContext().getPointerType(getContext().VoidPtrTy);
|
||||
CallArgs.push_back(std::make_pair(RValue::get(VTT), T));
|
||||
}
|
||||
|
||||
// Push the Src ptr.
|
||||
CallArgs.push_back(std::make_pair(RValue::get(Src),
|
||||
BaseCopyCtor->getParamDecl(0)->getType()));
|
||||
@ -787,10 +829,8 @@ static void EmitBaseInitializer(CodeGenFunction &CGF,
|
||||
V = CGF.Builder.CreateConstInBoundsGEP1_64(V, Offset/8);
|
||||
V = CGF.Builder.CreateBitCast(V, BaseClassType->getPointerTo());
|
||||
|
||||
// FIXME: This should always use Ctor_Base as the ctor type! (But that
|
||||
// causes crashes in tests.)
|
||||
CGF.EmitCXXConstructorCall(BaseInit->getConstructor(),
|
||||
CtorType, V,
|
||||
Ctor_Base, V,
|
||||
BaseInit->const_arg_begin(),
|
||||
BaseInit->const_arg_end());
|
||||
}
|
||||
@ -1044,3 +1084,347 @@ void CodeGenFunction::SynthesizeDefaultDestructor(const CXXDestructorDecl *Dtor,
|
||||
EmitDtorEpilogue(Dtor, DtorType);
|
||||
FinishFunction();
|
||||
}
|
||||
|
||||
/// EmitCXXAggrConstructorCall - This routine essentially creates a (nested)
|
||||
/// for-loop to call the default constructor on individual members of the
|
||||
/// array.
|
||||
/// 'D' is the default constructor for elements of the array, 'ArrayTy' is the
|
||||
/// array type and 'ArrayPtr' points to the beginning fo the array.
|
||||
/// It is assumed that all relevant checks have been made by the caller.
|
||||
void
|
||||
CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D,
|
||||
const ConstantArrayType *ArrayTy,
|
||||
llvm::Value *ArrayPtr,
|
||||
CallExpr::const_arg_iterator ArgBeg,
|
||||
CallExpr::const_arg_iterator ArgEnd) {
|
||||
|
||||
const llvm::Type *SizeTy = ConvertType(getContext().getSizeType());
|
||||
llvm::Value * NumElements =
|
||||
llvm::ConstantInt::get(SizeTy,
|
||||
getContext().getConstantArrayElementCount(ArrayTy));
|
||||
|
||||
EmitCXXAggrConstructorCall(D, NumElements, ArrayPtr, ArgBeg, ArgEnd);
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D,
|
||||
llvm::Value *NumElements,
|
||||
llvm::Value *ArrayPtr,
|
||||
CallExpr::const_arg_iterator ArgBeg,
|
||||
CallExpr::const_arg_iterator ArgEnd) {
|
||||
const llvm::Type *SizeTy = ConvertType(getContext().getSizeType());
|
||||
|
||||
// Create a temporary for the loop index and initialize it with 0.
|
||||
llvm::Value *IndexPtr = CreateTempAlloca(SizeTy, "loop.index");
|
||||
llvm::Value *Zero = llvm::Constant::getNullValue(SizeTy);
|
||||
Builder.CreateStore(Zero, IndexPtr);
|
||||
|
||||
// Start the loop with a block that tests the condition.
|
||||
llvm::BasicBlock *CondBlock = createBasicBlock("for.cond");
|
||||
llvm::BasicBlock *AfterFor = createBasicBlock("for.end");
|
||||
|
||||
EmitBlock(CondBlock);
|
||||
|
||||
llvm::BasicBlock *ForBody = createBasicBlock("for.body");
|
||||
|
||||
// Generate: if (loop-index < number-of-elements fall to the loop body,
|
||||
// otherwise, go to the block after the for-loop.
|
||||
llvm::Value *Counter = Builder.CreateLoad(IndexPtr);
|
||||
llvm::Value *IsLess = Builder.CreateICmpULT(Counter, NumElements, "isless");
|
||||
// If the condition is true, execute the body.
|
||||
Builder.CreateCondBr(IsLess, ForBody, AfterFor);
|
||||
|
||||
EmitBlock(ForBody);
|
||||
|
||||
llvm::BasicBlock *ContinueBlock = createBasicBlock("for.inc");
|
||||
// Inside the loop body, emit the constructor call on the array element.
|
||||
Counter = Builder.CreateLoad(IndexPtr);
|
||||
llvm::Value *Address = Builder.CreateInBoundsGEP(ArrayPtr, Counter,
|
||||
"arrayidx");
|
||||
|
||||
// C++ [class.temporary]p4:
|
||||
// There are two contexts in which temporaries are destroyed at a different
|
||||
// point than the end of the full-expression. The first context is when a
|
||||
// default constructor is called to initialize an element of an array.
|
||||
// If the constructor has one or more default arguments, the destruction of
|
||||
// every temporary created in a default argument expression is sequenced
|
||||
// before the construction of the next array element, if any.
|
||||
|
||||
// Keep track of the current number of live temporaries.
|
||||
unsigned OldNumLiveTemporaries = LiveTemporaries.size();
|
||||
|
||||
EmitCXXConstructorCall(D, Ctor_Complete, Address, ArgBeg, ArgEnd);
|
||||
|
||||
// Pop temporaries.
|
||||
while (LiveTemporaries.size() > OldNumLiveTemporaries)
|
||||
PopCXXTemporary();
|
||||
|
||||
EmitBlock(ContinueBlock);
|
||||
|
||||
// Emit the increment of the loop counter.
|
||||
llvm::Value *NextVal = llvm::ConstantInt::get(SizeTy, 1);
|
||||
Counter = Builder.CreateLoad(IndexPtr);
|
||||
NextVal = Builder.CreateAdd(Counter, NextVal, "inc");
|
||||
Builder.CreateStore(NextVal, IndexPtr);
|
||||
|
||||
// Finally, branch back up to the condition for the next iteration.
|
||||
EmitBranch(CondBlock);
|
||||
|
||||
// Emit the fall-through block.
|
||||
EmitBlock(AfterFor, true);
|
||||
}
|
||||
|
||||
/// EmitCXXAggrDestructorCall - calls the default destructor on array
|
||||
/// elements in reverse order of construction.
|
||||
void
|
||||
CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D,
|
||||
const ArrayType *Array,
|
||||
llvm::Value *This) {
|
||||
const ConstantArrayType *CA = dyn_cast<ConstantArrayType>(Array);
|
||||
assert(CA && "Do we support VLA for destruction ?");
|
||||
uint64_t ElementCount = getContext().getConstantArrayElementCount(CA);
|
||||
|
||||
const llvm::Type *SizeLTy = ConvertType(getContext().getSizeType());
|
||||
llvm::Value* ElementCountPtr = llvm::ConstantInt::get(SizeLTy, ElementCount);
|
||||
EmitCXXAggrDestructorCall(D, ElementCountPtr, This);
|
||||
}
|
||||
|
||||
/// EmitCXXAggrDestructorCall - calls the default destructor on array
|
||||
/// elements in reverse order of construction.
|
||||
void
|
||||
CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D,
|
||||
llvm::Value *UpperCount,
|
||||
llvm::Value *This) {
|
||||
const llvm::Type *SizeLTy = ConvertType(getContext().getSizeType());
|
||||
llvm::Value *One = llvm::ConstantInt::get(SizeLTy, 1);
|
||||
|
||||
// Create a temporary for the loop index and initialize it with count of
|
||||
// array elements.
|
||||
llvm::Value *IndexPtr = CreateTempAlloca(SizeLTy, "loop.index");
|
||||
|
||||
// Store the number of elements in the index pointer.
|
||||
Builder.CreateStore(UpperCount, IndexPtr);
|
||||
|
||||
// Start the loop with a block that tests the condition.
|
||||
llvm::BasicBlock *CondBlock = createBasicBlock("for.cond");
|
||||
llvm::BasicBlock *AfterFor = createBasicBlock("for.end");
|
||||
|
||||
EmitBlock(CondBlock);
|
||||
|
||||
llvm::BasicBlock *ForBody = createBasicBlock("for.body");
|
||||
|
||||
// Generate: if (loop-index != 0 fall to the loop body,
|
||||
// otherwise, go to the block after the for-loop.
|
||||
llvm::Value* zeroConstant =
|
||||
llvm::Constant::getNullValue(SizeLTy);
|
||||
llvm::Value *Counter = Builder.CreateLoad(IndexPtr);
|
||||
llvm::Value *IsNE = Builder.CreateICmpNE(Counter, zeroConstant,
|
||||
"isne");
|
||||
// If the condition is true, execute the body.
|
||||
Builder.CreateCondBr(IsNE, ForBody, AfterFor);
|
||||
|
||||
EmitBlock(ForBody);
|
||||
|
||||
llvm::BasicBlock *ContinueBlock = createBasicBlock("for.inc");
|
||||
// Inside the loop body, emit the constructor call on the array element.
|
||||
Counter = Builder.CreateLoad(IndexPtr);
|
||||
Counter = Builder.CreateSub(Counter, One);
|
||||
llvm::Value *Address = Builder.CreateInBoundsGEP(This, Counter, "arrayidx");
|
||||
EmitCXXDestructorCall(D, Dtor_Complete, Address);
|
||||
|
||||
EmitBlock(ContinueBlock);
|
||||
|
||||
// Emit the decrement of the loop counter.
|
||||
Counter = Builder.CreateLoad(IndexPtr);
|
||||
Counter = Builder.CreateSub(Counter, One, "dec");
|
||||
Builder.CreateStore(Counter, IndexPtr);
|
||||
|
||||
// Finally, branch back up to the condition for the next iteration.
|
||||
EmitBranch(CondBlock);
|
||||
|
||||
// Emit the fall-through block.
|
||||
EmitBlock(AfterFor, true);
|
||||
}
|
||||
|
||||
/// GenerateCXXAggrDestructorHelper - Generates a helper function which when
|
||||
/// invoked, calls the default destructor on array elements in reverse order of
|
||||
/// construction.
|
||||
llvm::Constant *
|
||||
CodeGenFunction::GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D,
|
||||
const ArrayType *Array,
|
||||
llvm::Value *This) {
|
||||
FunctionArgList Args;
|
||||
ImplicitParamDecl *Dst =
|
||||
ImplicitParamDecl::Create(getContext(), 0,
|
||||
SourceLocation(), 0,
|
||||
getContext().getPointerType(getContext().VoidTy));
|
||||
Args.push_back(std::make_pair(Dst, Dst->getType()));
|
||||
|
||||
llvm::SmallString<16> Name;
|
||||
llvm::raw_svector_ostream(Name) << "__tcf_" << (++UniqueAggrDestructorCount);
|
||||
QualType R = getContext().VoidTy;
|
||||
const CGFunctionInfo &FI = CGM.getTypes().getFunctionInfo(R, Args);
|
||||
const llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI, false);
|
||||
llvm::Function *Fn =
|
||||
llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage,
|
||||
Name.str(),
|
||||
&CGM.getModule());
|
||||
IdentifierInfo *II = &CGM.getContext().Idents.get(Name.str());
|
||||
FunctionDecl *FD = FunctionDecl::Create(getContext(),
|
||||
getContext().getTranslationUnitDecl(),
|
||||
SourceLocation(), II, R, 0,
|
||||
FunctionDecl::Static,
|
||||
false, true);
|
||||
StartFunction(FD, R, Fn, Args, SourceLocation());
|
||||
QualType BaseElementTy = getContext().getBaseElementType(Array);
|
||||
const llvm::Type *BasePtr = ConvertType(BaseElementTy);
|
||||
BasePtr = llvm::PointerType::getUnqual(BasePtr);
|
||||
llvm::Value *BaseAddrPtr = Builder.CreateBitCast(This, BasePtr);
|
||||
EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr);
|
||||
FinishFunction();
|
||||
llvm::Type *Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext),
|
||||
0);
|
||||
llvm::Constant *m = llvm::ConstantExpr::getBitCast(Fn, Ptr8Ty);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
|
||||
CXXCtorType Type,
|
||||
llvm::Value *This,
|
||||
CallExpr::const_arg_iterator ArgBeg,
|
||||
CallExpr::const_arg_iterator ArgEnd) {
|
||||
if (D->isCopyConstructor()) {
|
||||
const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(D->getDeclContext());
|
||||
if (ClassDecl->hasTrivialCopyConstructor()) {
|
||||
assert(!ClassDecl->hasUserDeclaredCopyConstructor() &&
|
||||
"EmitCXXConstructorCall - user declared copy constructor");
|
||||
const Expr *E = (*ArgBeg);
|
||||
QualType Ty = E->getType();
|
||||
llvm::Value *Src = EmitLValue(E).getAddress();
|
||||
EmitAggregateCopy(This, Src, Ty);
|
||||
return;
|
||||
}
|
||||
} else if (D->isTrivial()) {
|
||||
// FIXME: Track down why we're trying to generate calls to the trivial
|
||||
// default constructor!
|
||||
return;
|
||||
}
|
||||
|
||||
llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(D, Type));
|
||||
llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Type);
|
||||
|
||||
EmitCXXMemberCall(D, Callee, ReturnValueSlot(), This, VTT, ArgBeg, ArgEnd);
|
||||
}
|
||||
|
||||
void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD,
|
||||
CXXDtorType Type,
|
||||
llvm::Value *This) {
|
||||
llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(DD, Type));
|
||||
llvm::Value *Callee = CGM.GetAddrOfCXXDestructor(DD, Type);
|
||||
|
||||
EmitCXXMemberCall(DD, Callee, ReturnValueSlot(), This, VTT, 0, 0);
|
||||
}
|
||||
|
||||
llvm::Value *
|
||||
CodeGenFunction::GetVirtualCXXBaseClassOffset(llvm::Value *This,
|
||||
const CXXRecordDecl *ClassDecl,
|
||||
const CXXRecordDecl *BaseClassDecl) {
|
||||
const llvm::Type *Int8PtrTy =
|
||||
llvm::Type::getInt8Ty(VMContext)->getPointerTo();
|
||||
|
||||
llvm::Value *VTablePtr = Builder.CreateBitCast(This,
|
||||
Int8PtrTy->getPointerTo());
|
||||
VTablePtr = Builder.CreateLoad(VTablePtr, "vtable");
|
||||
|
||||
int64_t VBaseOffsetIndex =
|
||||
CGM.getVtableInfo().getVirtualBaseOffsetIndex(ClassDecl, BaseClassDecl);
|
||||
|
||||
llvm::Value *VBaseOffsetPtr =
|
||||
Builder.CreateConstGEP1_64(VTablePtr, VBaseOffsetIndex, "vbase.offset.ptr");
|
||||
const llvm::Type *PtrDiffTy =
|
||||
ConvertType(getContext().getPointerDiffType());
|
||||
|
||||
VBaseOffsetPtr = Builder.CreateBitCast(VBaseOffsetPtr,
|
||||
PtrDiffTy->getPointerTo());
|
||||
|
||||
llvm::Value *VBaseOffset = Builder.CreateLoad(VBaseOffsetPtr, "vbase.offset");
|
||||
|
||||
return VBaseOffset;
|
||||
}
|
||||
|
||||
void CodeGenFunction::InitializeVtablePtrs(const CXXRecordDecl *ClassDecl) {
|
||||
if (!ClassDecl->isDynamicClass())
|
||||
return;
|
||||
|
||||
llvm::Constant *Vtable = CGM.getVtableInfo().getVtable(ClassDecl);
|
||||
CGVtableInfo::AddrSubMap_t& AddressPoints =
|
||||
*(*CGM.getVtableInfo().AddressPoints[ClassDecl])[ClassDecl];
|
||||
llvm::Value *ThisPtr = LoadCXXThis();
|
||||
const ASTRecordLayout &Layout = getContext().getASTRecordLayout(ClassDecl);
|
||||
|
||||
// Store address points for virtual bases
|
||||
for (CXXRecordDecl::base_class_const_iterator I =
|
||||
ClassDecl->vbases_begin(), E = ClassDecl->vbases_end(); I != E; ++I) {
|
||||
const CXXBaseSpecifier &Base = *I;
|
||||
CXXRecordDecl *BaseClassDecl
|
||||
= cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
|
||||
uint64_t Offset = Layout.getVBaseClassOffset(BaseClassDecl);
|
||||
InitializeVtablePtrsRecursive(BaseClassDecl, Vtable, AddressPoints,
|
||||
ThisPtr, Offset);
|
||||
}
|
||||
|
||||
// Store address points for non-virtual bases and current class
|
||||
InitializeVtablePtrsRecursive(ClassDecl, Vtable, AddressPoints, ThisPtr, 0);
|
||||
}
|
||||
|
||||
void CodeGenFunction::InitializeVtablePtrsRecursive(
|
||||
const CXXRecordDecl *ClassDecl,
|
||||
llvm::Constant *Vtable,
|
||||
CGVtableInfo::AddrSubMap_t& AddressPoints,
|
||||
llvm::Value *ThisPtr,
|
||||
uint64_t Offset) {
|
||||
if (!ClassDecl->isDynamicClass())
|
||||
return;
|
||||
|
||||
// Store address points for non-virtual bases
|
||||
const ASTRecordLayout &Layout = getContext().getASTRecordLayout(ClassDecl);
|
||||
for (CXXRecordDecl::base_class_const_iterator I =
|
||||
ClassDecl->bases_begin(), E = ClassDecl->bases_end(); I != E; ++I) {
|
||||
const CXXBaseSpecifier &Base = *I;
|
||||
if (Base.isVirtual())
|
||||
continue;
|
||||
CXXRecordDecl *BaseClassDecl
|
||||
= cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
|
||||
uint64_t NewOffset = Offset + Layout.getBaseClassOffset(BaseClassDecl);
|
||||
InitializeVtablePtrsRecursive(BaseClassDecl, Vtable, AddressPoints,
|
||||
ThisPtr, NewOffset);
|
||||
}
|
||||
|
||||
// Compute the address point
|
||||
assert(AddressPoints.count(std::make_pair(ClassDecl, Offset)) &&
|
||||
"Missing address point for class");
|
||||
uint64_t AddressPoint = AddressPoints[std::make_pair(ClassDecl, Offset)];
|
||||
llvm::Value *VtableAddressPoint =
|
||||
Builder.CreateConstInBoundsGEP2_64(Vtable, 0, AddressPoint);
|
||||
|
||||
// Compute the address to store the address point
|
||||
const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
|
||||
llvm::Value *VtableField = Builder.CreateBitCast(ThisPtr, Int8PtrTy);
|
||||
VtableField = Builder.CreateConstInBoundsGEP1_64(VtableField, Offset/8);
|
||||
const llvm::Type *AddressPointPtrTy =
|
||||
VtableAddressPoint->getType()->getPointerTo();
|
||||
VtableField = Builder.CreateBitCast(VtableField, AddressPointPtrTy);
|
||||
|
||||
// Store address point
|
||||
Builder.CreateStore(VtableAddressPoint, VtableField);
|
||||
}
|
||||
|
||||
llvm::Value *CodeGenFunction::LoadCXXVTT() {
|
||||
assert((isa<CXXConstructorDecl>(CurFuncDecl) ||
|
||||
isa<CXXDestructorDecl>(CurFuncDecl)) &&
|
||||
"Must be in a C++ ctor or dtor to load the vtt parameter");
|
||||
|
||||
return Builder.CreateLoad(LocalDeclMap[CXXVTTDecl], "vtt");
|
||||
}
|
||||
|
@ -65,6 +65,25 @@ llvm::DIDescriptor CGDebugInfo::getContext(const VarDecl *Decl,
|
||||
return CompileUnit;
|
||||
}
|
||||
|
||||
/// getFunctionName - Get function name for the given FunctionDecl. If the
|
||||
/// name is constructred on demand (e.g. C++ destructor) then the name
|
||||
/// is stored on the side.
|
||||
llvm::StringRef CGDebugInfo::getFunctionName(const FunctionDecl *FD) {
|
||||
assert (FD && "Invalid FunctionDecl!");
|
||||
IdentifierInfo *FII = FD->getIdentifier();
|
||||
if (FII)
|
||||
return FII->getName();
|
||||
|
||||
// Otherwise construct human readable name for debug info.
|
||||
std::string NS = FD->getNameAsString();
|
||||
|
||||
// Copy this name on the side and use its reference.
|
||||
unsigned Length = NS.length() + 1;
|
||||
char *StrPtr = FunctionNames.Allocate<char>(Length);
|
||||
strncpy(StrPtr, NS.c_str(), Length);
|
||||
return llvm::StringRef(StrPtr);
|
||||
}
|
||||
|
||||
/// getOrCreateCompileUnit - Get the compile unit from the cache or create a new
|
||||
/// one if necessary. This returns null for invalid source locations.
|
||||
llvm::DICompileUnit CGDebugInfo::getOrCreateCompileUnit(SourceLocation Loc) {
|
||||
@ -972,18 +991,32 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty,
|
||||
|
||||
/// EmitFunctionStart - Constructs the debug code for entering a function -
|
||||
/// "llvm.dbg.func.start.".
|
||||
void CGDebugInfo::EmitFunctionStart(llvm::StringRef Name, QualType FnType,
|
||||
void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
|
||||
llvm::Function *Fn,
|
||||
CGBuilderTy &Builder) {
|
||||
llvm::StringRef LinkageName(Name);
|
||||
|
||||
// Skip the asm prefix if it exists.
|
||||
//
|
||||
// FIXME: This should probably be the unmangled name?
|
||||
if (Name[0] == '\01')
|
||||
Name = Name.substr(1);
|
||||
llvm::StringRef Name;
|
||||
llvm::StringRef LinkageName;
|
||||
|
||||
// FIXME: Why is this using CurLoc???
|
||||
const Decl *D = GD.getDecl();
|
||||
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
|
||||
Name = getFunctionName(FD);
|
||||
if (Name[0] == '\01')
|
||||
Name = Name.substr(1);
|
||||
// Use mangled name as linkage name for c/c++ functions.
|
||||
LinkageName = CGM.getMangledName(GD);
|
||||
} else {
|
||||
// Use llvm function name as linkage name.
|
||||
Name = Fn->getName();
|
||||
// Skip the asm prefix if it exists.
|
||||
if (Name[0] == '\01')
|
||||
Name = Name.substr(1);
|
||||
LinkageName = Name;
|
||||
}
|
||||
|
||||
// It is expected that CurLoc is set before using EmitFunctionStart.
|
||||
// Usually, CurLoc points to the left bracket location of compound
|
||||
// statement representing function body.
|
||||
llvm::DICompileUnit Unit = getOrCreateCompileUnit(CurLoc);
|
||||
SourceManager &SM = CGM.getContext().getSourceManager();
|
||||
unsigned LineNo = SM.getPresumedLoc(CurLoc).getLine();
|
||||
@ -1379,7 +1412,7 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag,
|
||||
else
|
||||
Unit = llvm::DICompileUnit();
|
||||
|
||||
uint64_t offset = CGF->BlockDecls[Decl];
|
||||
CharUnits offset = CGF->BlockDecls[Decl];
|
||||
llvm::SmallVector<llvm::Value *, 9> addr;
|
||||
llvm::LLVMContext &VMContext = CGM.getLLVMContext();
|
||||
addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
|
||||
@ -1387,22 +1420,24 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag,
|
||||
addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
|
||||
llvm::DIFactory::OpPlus));
|
||||
addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
|
||||
offset));
|
||||
offset.getQuantity()));
|
||||
if (BDRE->isByRef()) {
|
||||
addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
|
||||
llvm::DIFactory::OpDeref));
|
||||
addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
|
||||
llvm::DIFactory::OpPlus));
|
||||
offset = CGF->LLVMPointerWidth/8; // offset of __forwarding field
|
||||
// offset of __forwarding field
|
||||
offset = CharUnits::fromQuantity(CGF->LLVMPointerWidth/8);
|
||||
addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
|
||||
offset));
|
||||
offset.getQuantity()));
|
||||
addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
|
||||
llvm::DIFactory::OpDeref));
|
||||
addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
|
||||
llvm::DIFactory::OpPlus));
|
||||
offset = XOffset/8; // offset of x field
|
||||
// offset of x field
|
||||
offset = CharUnits::fromQuantity(XOffset/8);
|
||||
addr.push_back(llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
|
||||
offset));
|
||||
offset.getQuantity()));
|
||||
}
|
||||
|
||||
// Create the descriptor for the variable.
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/Analysis/DebugInfo.h"
|
||||
#include "llvm/Support/ValueHandle.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include <map>
|
||||
|
||||
#include "CGBuilder.h"
|
||||
@ -35,6 +36,7 @@ namespace clang {
|
||||
namespace CodeGen {
|
||||
class CodeGenModule;
|
||||
class CodeGenFunction;
|
||||
class GlobalDecl;
|
||||
|
||||
/// CGDebugInfo - This class gathers all debug information during compilation
|
||||
/// and is responsible for emitting to llvm globals or pass directly to
|
||||
@ -58,6 +60,10 @@ class CGDebugInfo {
|
||||
|
||||
std::vector<llvm::TrackingVH<llvm::MDNode> > RegionStack;
|
||||
|
||||
/// FunctionNames - This is a storage for function names that are
|
||||
/// constructed on demand. For example, C++ destructors, C++ operators etc..
|
||||
llvm::BumpPtrAllocator FunctionNames;
|
||||
|
||||
/// Helper functions for getOrCreateType.
|
||||
llvm::DIType CreateType(const BuiltinType *Ty, llvm::DICompileUnit U);
|
||||
llvm::DIType CreateType(const ComplexType *Ty, llvm::DICompileUnit U);
|
||||
@ -93,7 +99,7 @@ public:
|
||||
|
||||
/// EmitFunctionStart - Emit a call to llvm.dbg.function.start to indicate
|
||||
/// start of a new function.
|
||||
void EmitFunctionStart(llvm::StringRef Name, QualType FnType,
|
||||
void EmitFunctionStart(GlobalDecl GD, QualType FnType,
|
||||
llvm::Function *Fn, CGBuilderTy &Builder);
|
||||
|
||||
/// EmitRegionStart - Emit a call to llvm.dbg.region.start to indicate start
|
||||
@ -149,6 +155,11 @@ private:
|
||||
|
||||
/// CreateTypeNode - Create type metadata for a source language type.
|
||||
llvm::DIType CreateTypeNode(QualType Ty, llvm::DICompileUnit Unit);
|
||||
|
||||
/// getFunctionName - Get function name for the given FunctionDecl. If the
|
||||
/// name is constructred on demand (e.g. C++ destructor) then the name
|
||||
/// is stored on the side.
|
||||
llvm::StringRef getFunctionName(const FunctionDecl *FD);
|
||||
};
|
||||
} // namespace CodeGen
|
||||
} // namespace clang
|
||||
|
@ -473,7 +473,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
|
||||
llvm::IntegerType::get(VMContext, LLVMPointerWidth);
|
||||
llvm::Value *SizeVal =
|
||||
llvm::ConstantInt::get(IntPtr,
|
||||
getContext().getTypeSizeInChars(Ty).getRaw());
|
||||
getContext().getTypeSizeInChars(Ty).getQuantity());
|
||||
|
||||
const llvm::Type *BP = llvm::Type::getInt8PtrTy(VMContext);
|
||||
if (Loc->getType() != BP)
|
||||
|
@ -119,6 +119,22 @@ CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn,
|
||||
Builder.CreateCall(AtExitFn, &Args[0], llvm::array_endof(Args));
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D) {
|
||||
const llvm::FunctionType *FTy
|
||||
= llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
|
||||
false);
|
||||
|
||||
// Create a variable initialization function.
|
||||
llvm::Function *Fn =
|
||||
llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage,
|
||||
"__cxx_global_var_init", &TheModule);
|
||||
|
||||
CodeGenFunction(*this).GenerateCXXGlobalVarDeclInitFunc(Fn, D);
|
||||
|
||||
CXXGlobalInits.push_back(Fn);
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenModule::EmitCXXGlobalInitFunc() {
|
||||
if (CXXGlobalInits.empty())
|
||||
@ -140,18 +156,26 @@ CodeGenModule::EmitCXXGlobalInitFunc() {
|
||||
AddGlobalCtor(Fn);
|
||||
}
|
||||
|
||||
void CodeGenFunction::GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn,
|
||||
const VarDecl *D) {
|
||||
StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FunctionArgList(),
|
||||
SourceLocation());
|
||||
|
||||
llvm::Constant *DeclPtr = CGM.GetAddrOfGlobalVar(D);
|
||||
EmitCXXGlobalVarDeclInit(*D, DeclPtr);
|
||||
|
||||
FinishFunction();
|
||||
}
|
||||
|
||||
void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
|
||||
const VarDecl **Decls,
|
||||
llvm::Constant **Decls,
|
||||
unsigned NumDecls) {
|
||||
StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FunctionArgList(),
|
||||
SourceLocation());
|
||||
|
||||
for (unsigned i = 0; i != NumDecls; ++i) {
|
||||
const VarDecl *D = Decls[i];
|
||||
for (unsigned i = 0; i != NumDecls; ++i)
|
||||
Builder.CreateCall(Decls[i]);
|
||||
|
||||
llvm::Constant *DeclPtr = CGM.GetAddrOfGlobalVar(D);
|
||||
EmitCXXGlobalVarDeclInit(*D, DeclPtr);
|
||||
}
|
||||
FinishFunction();
|
||||
}
|
||||
|
||||
|
@ -240,6 +240,132 @@ void CodeGenFunction::EmitCheck(llvm::Value *Address, unsigned Size) {
|
||||
EmitBlock(Cont);
|
||||
}
|
||||
|
||||
|
||||
llvm::Value *CodeGenFunction::
|
||||
EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
|
||||
bool isInc, bool isPre) {
|
||||
QualType ValTy = E->getSubExpr()->getType();
|
||||
llvm::Value *InVal = EmitLoadOfLValue(LV, ValTy).getScalarVal();
|
||||
|
||||
int AmountVal = isInc ? 1 : -1;
|
||||
|
||||
if (ValTy->isPointerType() &&
|
||||
ValTy->getAs<PointerType>()->isVariableArrayType()) {
|
||||
// The amount of the addition/subtraction needs to account for the VLA size
|
||||
ErrorUnsupported(E, "VLA pointer inc/dec");
|
||||
}
|
||||
|
||||
llvm::Value *NextVal;
|
||||
if (const llvm::PointerType *PT =
|
||||
dyn_cast<llvm::PointerType>(InVal->getType())) {
|
||||
llvm::Constant *Inc =
|
||||
llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), AmountVal);
|
||||
if (!isa<llvm::FunctionType>(PT->getElementType())) {
|
||||
QualType PTEE = ValTy->getPointeeType();
|
||||
if (const ObjCInterfaceType *OIT =
|
||||
dyn_cast<ObjCInterfaceType>(PTEE)) {
|
||||
// Handle interface types, which are not represented with a concrete
|
||||
// type.
|
||||
int size = getContext().getTypeSize(OIT) / 8;
|
||||
if (!isInc)
|
||||
size = -size;
|
||||
Inc = llvm::ConstantInt::get(Inc->getType(), size);
|
||||
const llvm::Type *i8Ty = llvm::Type::getInt8PtrTy(VMContext);
|
||||
InVal = Builder.CreateBitCast(InVal, i8Ty);
|
||||
NextVal = Builder.CreateGEP(InVal, Inc, "add.ptr");
|
||||
llvm::Value *lhs = LV.getAddress();
|
||||
lhs = Builder.CreateBitCast(lhs, llvm::PointerType::getUnqual(i8Ty));
|
||||
LV = LValue::MakeAddr(lhs, MakeQualifiers(ValTy));
|
||||
} else
|
||||
NextVal = Builder.CreateInBoundsGEP(InVal, Inc, "ptrincdec");
|
||||
} else {
|
||||
const llvm::Type *i8Ty = llvm::Type::getInt8PtrTy(VMContext);
|
||||
NextVal = Builder.CreateBitCast(InVal, i8Ty, "tmp");
|
||||
NextVal = Builder.CreateGEP(NextVal, Inc, "ptrincdec");
|
||||
NextVal = Builder.CreateBitCast(NextVal, InVal->getType());
|
||||
}
|
||||
} else if (InVal->getType() == llvm::Type::getInt1Ty(VMContext) && isInc) {
|
||||
// Bool++ is an interesting case, due to promotion rules, we get:
|
||||
// Bool++ -> Bool = Bool+1 -> Bool = (int)Bool+1 ->
|
||||
// Bool = ((int)Bool+1) != 0
|
||||
// An interesting aspect of this is that increment is always true.
|
||||
// Decrement does not have this property.
|
||||
NextVal = llvm::ConstantInt::getTrue(VMContext);
|
||||
} else if (isa<llvm::IntegerType>(InVal->getType())) {
|
||||
NextVal = llvm::ConstantInt::get(InVal->getType(), AmountVal);
|
||||
|
||||
// Signed integer overflow is undefined behavior.
|
||||
if (ValTy->isSignedIntegerType())
|
||||
NextVal = Builder.CreateNSWAdd(InVal, NextVal, isInc ? "inc" : "dec");
|
||||
else
|
||||
NextVal = Builder.CreateAdd(InVal, NextVal, isInc ? "inc" : "dec");
|
||||
} else {
|
||||
// Add the inc/dec to the real part.
|
||||
if (InVal->getType()->isFloatTy())
|
||||
NextVal =
|
||||
llvm::ConstantFP::get(VMContext,
|
||||
llvm::APFloat(static_cast<float>(AmountVal)));
|
||||
else if (InVal->getType()->isDoubleTy())
|
||||
NextVal =
|
||||
llvm::ConstantFP::get(VMContext,
|
||||
llvm::APFloat(static_cast<double>(AmountVal)));
|
||||
else {
|
||||
llvm::APFloat F(static_cast<float>(AmountVal));
|
||||
bool ignored;
|
||||
F.convert(Target.getLongDoubleFormat(), llvm::APFloat::rmTowardZero,
|
||||
&ignored);
|
||||
NextVal = llvm::ConstantFP::get(VMContext, F);
|
||||
}
|
||||
NextVal = Builder.CreateFAdd(InVal, NextVal, isInc ? "inc" : "dec");
|
||||
}
|
||||
|
||||
// Store the updated result through the lvalue.
|
||||
if (LV.isBitfield())
|
||||
EmitStoreThroughBitfieldLValue(RValue::get(NextVal), LV, ValTy, &NextVal);
|
||||
else
|
||||
EmitStoreThroughLValue(RValue::get(NextVal), LV, ValTy);
|
||||
|
||||
// If this is a postinc, return the value read from memory, otherwise use the
|
||||
// updated value.
|
||||
return isPre ? NextVal : InVal;
|
||||
}
|
||||
|
||||
|
||||
CodeGenFunction::ComplexPairTy CodeGenFunction::
|
||||
EmitComplexPrePostIncDec(const UnaryOperator *E, LValue LV,
|
||||
bool isInc, bool isPre) {
|
||||
ComplexPairTy InVal = LoadComplexFromAddr(LV.getAddress(),
|
||||
LV.isVolatileQualified());
|
||||
|
||||
llvm::Value *NextVal;
|
||||
if (isa<llvm::IntegerType>(InVal.first->getType())) {
|
||||
uint64_t AmountVal = isInc ? 1 : -1;
|
||||
NextVal = llvm::ConstantInt::get(InVal.first->getType(), AmountVal, true);
|
||||
|
||||
// Add the inc/dec to the real part.
|
||||
NextVal = Builder.CreateAdd(InVal.first, NextVal, isInc ? "inc" : "dec");
|
||||
} else {
|
||||
QualType ElemTy = E->getType()->getAs<ComplexType>()->getElementType();
|
||||
llvm::APFloat FVal(getContext().getFloatTypeSemantics(ElemTy), 1);
|
||||
if (!isInc)
|
||||
FVal.changeSign();
|
||||
NextVal = llvm::ConstantFP::get(getLLVMContext(), FVal);
|
||||
|
||||
// Add the inc/dec to the real part.
|
||||
NextVal = Builder.CreateFAdd(InVal.first, NextVal, isInc ? "inc" : "dec");
|
||||
}
|
||||
|
||||
ComplexPairTy IncVal(NextVal, InVal.second);
|
||||
|
||||
// Store the updated result through the lvalue.
|
||||
StoreComplexToAddr(IncVal, LV.getAddress(), LV.isVolatileQualified());
|
||||
|
||||
// If this is a postinc, return the value read from memory, otherwise use the
|
||||
// updated value.
|
||||
return isPre ? IncVal : InVal;
|
||||
}
|
||||
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// LValue Expression Emission
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -994,8 +1120,16 @@ LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) {
|
||||
MakeQualifiers(ExprTy));
|
||||
}
|
||||
case UnaryOperator::PreInc:
|
||||
case UnaryOperator::PreDec:
|
||||
return EmitUnsupportedLValue(E, "pre-inc/dec expression");
|
||||
case UnaryOperator::PreDec: {
|
||||
LValue LV = EmitLValue(E->getSubExpr());
|
||||
bool isInc = E->getOpcode() == UnaryOperator::PreInc;
|
||||
|
||||
if (E->getType()->isAnyComplexType())
|
||||
EmitComplexPrePostIncDec(E, LV, isInc, true/*isPre*/);
|
||||
else
|
||||
EmitScalarPrePostIncDec(E, LV, isInc, true/*isPre*/);
|
||||
return LV;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1139,16 +1273,16 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) {
|
||||
|
||||
QualType BaseType = getContext().getBaseElementType(VAT);
|
||||
|
||||
uint64_t BaseTypeSize = getContext().getTypeSize(BaseType) / 8;
|
||||
CharUnits BaseTypeSize = getContext().getTypeSizeInChars(BaseType);
|
||||
Idx = Builder.CreateUDiv(Idx,
|
||||
llvm::ConstantInt::get(Idx->getType(),
|
||||
BaseTypeSize));
|
||||
BaseTypeSize.getQuantity()));
|
||||
Address = Builder.CreateInBoundsGEP(Base, Idx, "arrayidx");
|
||||
} else if (const ObjCInterfaceType *OIT =
|
||||
dyn_cast<ObjCInterfaceType>(E->getType())) {
|
||||
llvm::Value *InterfaceSize =
|
||||
llvm::ConstantInt::get(Idx->getType(),
|
||||
getContext().getTypeSize(OIT) / 8);
|
||||
getContext().getTypeSizeInChars(OIT).getQuantity());
|
||||
|
||||
Idx = Builder.CreateMul(Idx, InterfaceSize);
|
||||
|
||||
@ -1211,8 +1345,8 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) {
|
||||
Base = EmitLValue(E->getBase());
|
||||
} else {
|
||||
// Otherwise, the base is a normal rvalue (as in (V+V).x), emit it as such.
|
||||
const VectorType *VT = E->getBase()->getType()->getAs<VectorType>();
|
||||
assert(VT && "Result must be a vector");
|
||||
assert(E->getBase()->getType()->getAs<VectorType>() &&
|
||||
"Result must be a vector");
|
||||
llvm::Value *Vec = EmitScalarExpr(E->getBase());
|
||||
|
||||
// Store the vector to memory (because LValue wants an address).
|
||||
|
@ -313,7 +313,8 @@ void AggExprEmitter::VisitUnaryAddrOf(const UnaryOperator *E) {
|
||||
"Unexpected member pointer type!");
|
||||
|
||||
const DeclRefExpr *DRE = cast<DeclRefExpr>(E->getSubExpr());
|
||||
const CXXMethodDecl *MD = cast<CXXMethodDecl>(DRE->getDecl());
|
||||
const CXXMethodDecl *MD =
|
||||
cast<CXXMethodDecl>(DRE->getDecl())->getCanonicalDecl();
|
||||
|
||||
const llvm::Type *PtrDiffTy =
|
||||
CGF.ConvertType(CGF.getContext().getPointerDiffType());
|
||||
|
@ -15,6 +15,334 @@
|
||||
using namespace clang;
|
||||
using namespace CodeGen;
|
||||
|
||||
RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD,
|
||||
llvm::Value *Callee,
|
||||
ReturnValueSlot ReturnValue,
|
||||
llvm::Value *This,
|
||||
llvm::Value *VTT,
|
||||
CallExpr::const_arg_iterator ArgBeg,
|
||||
CallExpr::const_arg_iterator ArgEnd) {
|
||||
assert(MD->isInstance() &&
|
||||
"Trying to emit a member call expr on a static method!");
|
||||
|
||||
const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
|
||||
|
||||
CallArgList Args;
|
||||
|
||||
// Push the this ptr.
|
||||
Args.push_back(std::make_pair(RValue::get(This),
|
||||
MD->getThisType(getContext())));
|
||||
|
||||
// If there is a VTT parameter, emit it.
|
||||
if (VTT) {
|
||||
QualType T = getContext().getPointerType(getContext().VoidPtrTy);
|
||||
Args.push_back(std::make_pair(RValue::get(VTT), T));
|
||||
}
|
||||
|
||||
// And the rest of the call args
|
||||
EmitCallArgs(Args, FPT, ArgBeg, ArgEnd);
|
||||
|
||||
QualType ResultType = MD->getType()->getAs<FunctionType>()->getResultType();
|
||||
return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args), Callee,
|
||||
ReturnValue, Args, MD);
|
||||
}
|
||||
|
||||
/// canDevirtualizeMemberFunctionCalls - Checks whether virtual calls on given
|
||||
/// expr can be devirtualized.
|
||||
static bool canDevirtualizeMemberFunctionCalls(const Expr *Base) {
|
||||
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Base)) {
|
||||
if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
|
||||
// This is a record decl. We know the type and can devirtualize it.
|
||||
return VD->getType()->isRecordType();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// We can always devirtualize calls on temporary object expressions.
|
||||
if (isa<CXXTemporaryObjectExpr>(Base))
|
||||
return true;
|
||||
|
||||
// And calls on bound temporaries.
|
||||
if (isa<CXXBindTemporaryExpr>(Base))
|
||||
return true;
|
||||
|
||||
// Check if this is a call expr that returns a record type.
|
||||
if (const CallExpr *CE = dyn_cast<CallExpr>(Base))
|
||||
return CE->getCallReturnType()->isRecordType();
|
||||
|
||||
// We can't devirtualize the call.
|
||||
return false;
|
||||
}
|
||||
|
||||
RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
|
||||
ReturnValueSlot ReturnValue) {
|
||||
if (isa<BinaryOperator>(CE->getCallee()->IgnoreParens()))
|
||||
return EmitCXXMemberPointerCallExpr(CE, ReturnValue);
|
||||
|
||||
const MemberExpr *ME = cast<MemberExpr>(CE->getCallee()->IgnoreParens());
|
||||
const CXXMethodDecl *MD = cast<CXXMethodDecl>(ME->getMemberDecl());
|
||||
|
||||
if (MD->isStatic()) {
|
||||
// The method is static, emit it as we would a regular call.
|
||||
llvm::Value *Callee = CGM.GetAddrOfFunction(MD);
|
||||
return EmitCall(getContext().getPointerType(MD->getType()), Callee,
|
||||
ReturnValue, CE->arg_begin(), CE->arg_end());
|
||||
}
|
||||
|
||||
const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
|
||||
|
||||
const llvm::Type *Ty =
|
||||
CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
|
||||
FPT->isVariadic());
|
||||
llvm::Value *This;
|
||||
|
||||
if (ME->isArrow())
|
||||
This = EmitScalarExpr(ME->getBase());
|
||||
else {
|
||||
LValue BaseLV = EmitLValue(ME->getBase());
|
||||
This = BaseLV.getAddress();
|
||||
}
|
||||
|
||||
if (MD->isCopyAssignment() && MD->isTrivial()) {
|
||||
// We don't like to generate the trivial copy assignment operator when
|
||||
// it isn't necessary; just produce the proper effect here.
|
||||
llvm::Value *RHS = EmitLValue(*CE->arg_begin()).getAddress();
|
||||
EmitAggregateCopy(This, RHS, CE->getType());
|
||||
return RValue::get(This);
|
||||
}
|
||||
|
||||
// C++ [class.virtual]p12:
|
||||
// Explicit qualification with the scope operator (5.1) suppresses the
|
||||
// virtual call mechanism.
|
||||
//
|
||||
// We also don't emit a virtual call if the base expression has a record type
|
||||
// because then we know what the type is.
|
||||
llvm::Value *Callee;
|
||||
if (const CXXDestructorDecl *Destructor
|
||||
= dyn_cast<CXXDestructorDecl>(MD)) {
|
||||
if (Destructor->isTrivial())
|
||||
return RValue::get(0);
|
||||
if (MD->isVirtual() && !ME->hasQualifier() &&
|
||||
!canDevirtualizeMemberFunctionCalls(ME->getBase())) {
|
||||
Callee = BuildVirtualCall(Destructor, Dtor_Complete, This, Ty);
|
||||
} else {
|
||||
Callee = CGM.GetAddrOfFunction(GlobalDecl(Destructor, Dtor_Complete), Ty);
|
||||
}
|
||||
} else if (MD->isVirtual() && !ME->hasQualifier() &&
|
||||
!canDevirtualizeMemberFunctionCalls(ME->getBase())) {
|
||||
Callee = BuildVirtualCall(MD, This, Ty);
|
||||
} else {
|
||||
Callee = CGM.GetAddrOfFunction(MD, Ty);
|
||||
}
|
||||
|
||||
return EmitCXXMemberCall(MD, Callee, ReturnValue, This, /*VTT=*/0,
|
||||
CE->arg_begin(), CE->arg_end());
|
||||
}
|
||||
|
||||
RValue
|
||||
CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E,
|
||||
ReturnValueSlot ReturnValue) {
|
||||
const BinaryOperator *BO =
|
||||
cast<BinaryOperator>(E->getCallee()->IgnoreParens());
|
||||
const Expr *BaseExpr = BO->getLHS();
|
||||
const Expr *MemFnExpr = BO->getRHS();
|
||||
|
||||
const MemberPointerType *MPT =
|
||||
MemFnExpr->getType()->getAs<MemberPointerType>();
|
||||
const FunctionProtoType *FPT =
|
||||
MPT->getPointeeType()->getAs<FunctionProtoType>();
|
||||
const CXXRecordDecl *RD =
|
||||
cast<CXXRecordDecl>(MPT->getClass()->getAs<RecordType>()->getDecl());
|
||||
|
||||
const llvm::FunctionType *FTy =
|
||||
CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(RD, FPT),
|
||||
FPT->isVariadic());
|
||||
|
||||
const llvm::Type *Int8PtrTy =
|
||||
llvm::Type::getInt8Ty(VMContext)->getPointerTo();
|
||||
|
||||
// Get the member function pointer.
|
||||
llvm::Value *MemFnPtr =
|
||||
CreateTempAlloca(ConvertType(MemFnExpr->getType()), "mem.fn");
|
||||
EmitAggExpr(MemFnExpr, MemFnPtr, /*VolatileDest=*/false);
|
||||
|
||||
// Emit the 'this' pointer.
|
||||
llvm::Value *This;
|
||||
|
||||
if (BO->getOpcode() == BinaryOperator::PtrMemI)
|
||||
This = EmitScalarExpr(BaseExpr);
|
||||
else
|
||||
This = EmitLValue(BaseExpr).getAddress();
|
||||
|
||||
// Adjust it.
|
||||
llvm::Value *Adj = Builder.CreateStructGEP(MemFnPtr, 1);
|
||||
Adj = Builder.CreateLoad(Adj, "mem.fn.adj");
|
||||
|
||||
llvm::Value *Ptr = Builder.CreateBitCast(This, Int8PtrTy, "ptr");
|
||||
Ptr = Builder.CreateGEP(Ptr, Adj, "adj");
|
||||
|
||||
This = Builder.CreateBitCast(Ptr, This->getType(), "this");
|
||||
|
||||
llvm::Value *FnPtr = Builder.CreateStructGEP(MemFnPtr, 0, "mem.fn.ptr");
|
||||
|
||||
const llvm::Type *PtrDiffTy = ConvertType(getContext().getPointerDiffType());
|
||||
|
||||
llvm::Value *FnAsInt = Builder.CreateLoad(FnPtr, "fn");
|
||||
|
||||
// If the LSB in the function pointer is 1, the function pointer points to
|
||||
// a virtual function.
|
||||
llvm::Value *IsVirtual
|
||||
= Builder.CreateAnd(FnAsInt, llvm::ConstantInt::get(PtrDiffTy, 1),
|
||||
"and");
|
||||
|
||||
IsVirtual = Builder.CreateTrunc(IsVirtual,
|
||||
llvm::Type::getInt1Ty(VMContext));
|
||||
|
||||
llvm::BasicBlock *FnVirtual = createBasicBlock("fn.virtual");
|
||||
llvm::BasicBlock *FnNonVirtual = createBasicBlock("fn.nonvirtual");
|
||||
llvm::BasicBlock *FnEnd = createBasicBlock("fn.end");
|
||||
|
||||
Builder.CreateCondBr(IsVirtual, FnVirtual, FnNonVirtual);
|
||||
EmitBlock(FnVirtual);
|
||||
|
||||
const llvm::Type *VTableTy =
|
||||
FTy->getPointerTo()->getPointerTo()->getPointerTo();
|
||||
|
||||
llvm::Value *VTable = Builder.CreateBitCast(This, VTableTy);
|
||||
VTable = Builder.CreateLoad(VTable);
|
||||
|
||||
VTable = Builder.CreateGEP(VTable, FnAsInt, "fn");
|
||||
|
||||
// Since the function pointer is 1 plus the virtual table offset, we
|
||||
// subtract 1 by using a GEP.
|
||||
VTable = Builder.CreateConstGEP1_64(VTable, (uint64_t)-1);
|
||||
|
||||
llvm::Value *VirtualFn = Builder.CreateLoad(VTable, "virtualfn");
|
||||
|
||||
EmitBranch(FnEnd);
|
||||
EmitBlock(FnNonVirtual);
|
||||
|
||||
// If the function is not virtual, just load the pointer.
|
||||
llvm::Value *NonVirtualFn = Builder.CreateLoad(FnPtr, "fn");
|
||||
NonVirtualFn = Builder.CreateIntToPtr(NonVirtualFn, FTy->getPointerTo());
|
||||
|
||||
EmitBlock(FnEnd);
|
||||
|
||||
llvm::PHINode *Callee = Builder.CreatePHI(FTy->getPointerTo());
|
||||
Callee->reserveOperandSpace(2);
|
||||
Callee->addIncoming(VirtualFn, FnVirtual);
|
||||
Callee->addIncoming(NonVirtualFn, FnNonVirtual);
|
||||
|
||||
CallArgList Args;
|
||||
|
||||
QualType ThisType =
|
||||
getContext().getPointerType(getContext().getTagDeclType(RD));
|
||||
|
||||
// Push the this ptr.
|
||||
Args.push_back(std::make_pair(RValue::get(This), ThisType));
|
||||
|
||||
// And the rest of the call args
|
||||
EmitCallArgs(Args, FPT, E->arg_begin(), E->arg_end());
|
||||
QualType ResultType = BO->getType()->getAs<FunctionType>()->getResultType();
|
||||
return EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args), Callee,
|
||||
ReturnValue, Args);
|
||||
}
|
||||
|
||||
RValue
|
||||
CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E,
|
||||
const CXXMethodDecl *MD,
|
||||
ReturnValueSlot ReturnValue) {
|
||||
assert(MD->isInstance() &&
|
||||
"Trying to emit a member call expr on a static method!");
|
||||
|
||||
if (MD->isCopyAssignment()) {
|
||||
const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(MD->getDeclContext());
|
||||
if (ClassDecl->hasTrivialCopyAssignment()) {
|
||||
assert(!ClassDecl->hasUserDeclaredCopyAssignment() &&
|
||||
"EmitCXXOperatorMemberCallExpr - user declared copy assignment");
|
||||
llvm::Value *This = EmitLValue(E->getArg(0)).getAddress();
|
||||
llvm::Value *Src = EmitLValue(E->getArg(1)).getAddress();
|
||||
QualType Ty = E->getType();
|
||||
EmitAggregateCopy(This, Src, Ty);
|
||||
return RValue::get(This);
|
||||
}
|
||||
}
|
||||
|
||||
const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
|
||||
const llvm::Type *Ty =
|
||||
CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
|
||||
FPT->isVariadic());
|
||||
|
||||
llvm::Value *This = EmitLValue(E->getArg(0)).getAddress();
|
||||
|
||||
llvm::Value *Callee;
|
||||
if (MD->isVirtual() && !canDevirtualizeMemberFunctionCalls(E->getArg(0)))
|
||||
Callee = BuildVirtualCall(MD, This, Ty);
|
||||
else
|
||||
Callee = CGM.GetAddrOfFunction(MD, Ty);
|
||||
|
||||
return EmitCXXMemberCall(MD, Callee, ReturnValue, This, /*VTT=*/0,
|
||||
E->arg_begin() + 1, E->arg_end());
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest,
|
||||
const CXXConstructExpr *E) {
|
||||
assert(Dest && "Must have a destination!");
|
||||
const CXXConstructorDecl *CD = E->getConstructor();
|
||||
const ConstantArrayType *Array =
|
||||
getContext().getAsConstantArrayType(E->getType());
|
||||
// For a copy constructor, even if it is trivial, must fall thru so
|
||||
// its argument is code-gen'ed.
|
||||
if (!CD->isCopyConstructor()) {
|
||||
QualType InitType = E->getType();
|
||||
if (Array)
|
||||
InitType = getContext().getBaseElementType(Array);
|
||||
const CXXRecordDecl *RD =
|
||||
cast<CXXRecordDecl>(InitType->getAs<RecordType>()->getDecl());
|
||||
if (RD->hasTrivialConstructor())
|
||||
return;
|
||||
}
|
||||
// Code gen optimization to eliminate copy constructor and return
|
||||
// its first argument instead.
|
||||
if (getContext().getLangOptions().ElideConstructors && E->isElidable()) {
|
||||
const Expr *Arg = E->getArg(0);
|
||||
|
||||
if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) {
|
||||
assert((ICE->getCastKind() == CastExpr::CK_NoOp ||
|
||||
ICE->getCastKind() == CastExpr::CK_ConstructorConversion ||
|
||||
ICE->getCastKind() == CastExpr::CK_UserDefinedConversion) &&
|
||||
"Unknown implicit cast kind in constructor elision");
|
||||
Arg = ICE->getSubExpr();
|
||||
}
|
||||
|
||||
if (const CXXFunctionalCastExpr *FCE = dyn_cast<CXXFunctionalCastExpr>(Arg))
|
||||
Arg = FCE->getSubExpr();
|
||||
|
||||
if (const CXXBindTemporaryExpr *BindExpr =
|
||||
dyn_cast<CXXBindTemporaryExpr>(Arg))
|
||||
Arg = BindExpr->getSubExpr();
|
||||
|
||||
EmitAggExpr(Arg, Dest, false);
|
||||
return;
|
||||
}
|
||||
if (Array) {
|
||||
QualType BaseElementTy = getContext().getBaseElementType(Array);
|
||||
const llvm::Type *BasePtr = ConvertType(BaseElementTy);
|
||||
BasePtr = llvm::PointerType::getUnqual(BasePtr);
|
||||
llvm::Value *BaseAddrPtr =
|
||||
Builder.CreateBitCast(Dest, BasePtr);
|
||||
|
||||
EmitCXXAggrConstructorCall(CD, Array, BaseAddrPtr,
|
||||
E->arg_begin(), E->arg_end());
|
||||
}
|
||||
else
|
||||
// Call the constructor.
|
||||
EmitCXXConstructorCall(CD, Ctor_Complete, Dest,
|
||||
E->arg_begin(), E->arg_end());
|
||||
}
|
||||
|
||||
static uint64_t CalculateCookiePadding(ASTContext &Ctx, QualType ElementType) {
|
||||
const RecordType *RT = ElementType->getAs<RecordType>();
|
||||
if (!RT)
|
||||
@ -405,7 +733,8 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) {
|
||||
/*isVariadic=*/false);
|
||||
|
||||
llvm::Value *Callee = BuildVirtualCall(Dtor, Dtor_Deleting, Ptr, Ty);
|
||||
EmitCXXMemberCall(Dtor, Callee, ReturnValueSlot(), Ptr, 0, 0);
|
||||
EmitCXXMemberCall(Dtor, Callee, ReturnValueSlot(), Ptr, /*VTT=*/0,
|
||||
0, 0);
|
||||
|
||||
// The dtor took care of deleting the object.
|
||||
ShouldCallDelete = false;
|
||||
|
@ -145,7 +145,10 @@ public:
|
||||
|
||||
// Operators.
|
||||
ComplexPairTy VisitPrePostIncDec(const UnaryOperator *E,
|
||||
bool isInc, bool isPre);
|
||||
bool isInc, bool isPre) {
|
||||
LValue LV = CGF.EmitLValue(E->getSubExpr());
|
||||
return CGF.EmitComplexPrePostIncDec(E, LV, isInc, isPre);
|
||||
}
|
||||
ComplexPairTy VisitUnaryPostDec(const UnaryOperator *E) {
|
||||
return VisitPrePostIncDec(E, false, false);
|
||||
}
|
||||
@ -355,40 +358,6 @@ ComplexPairTy ComplexExprEmitter::EmitCast(Expr *Op, QualType DestTy) {
|
||||
return ComplexPairTy(Elt, llvm::Constant::getNullValue(Elt->getType()));
|
||||
}
|
||||
|
||||
ComplexPairTy ComplexExprEmitter::VisitPrePostIncDec(const UnaryOperator *E,
|
||||
bool isInc, bool isPre) {
|
||||
LValue LV = CGF.EmitLValue(E->getSubExpr());
|
||||
ComplexPairTy InVal = EmitLoadOfComplex(LV.getAddress(),
|
||||
LV.isVolatileQualified());
|
||||
|
||||
llvm::Value *NextVal;
|
||||
if (isa<llvm::IntegerType>(InVal.first->getType())) {
|
||||
uint64_t AmountVal = isInc ? 1 : -1;
|
||||
NextVal = llvm::ConstantInt::get(InVal.first->getType(), AmountVal, true);
|
||||
|
||||
// Add the inc/dec to the real part.
|
||||
NextVal = Builder.CreateAdd(InVal.first, NextVal, isInc ? "inc" : "dec");
|
||||
} else {
|
||||
QualType ElemTy = E->getType()->getAs<ComplexType>()->getElementType();
|
||||
llvm::APFloat FVal(CGF.getContext().getFloatTypeSemantics(ElemTy), 1);
|
||||
if (!isInc)
|
||||
FVal.changeSign();
|
||||
NextVal = llvm::ConstantFP::get(CGF.getLLVMContext(), FVal);
|
||||
|
||||
// Add the inc/dec to the real part.
|
||||
NextVal = Builder.CreateFAdd(InVal.first, NextVal, isInc ? "inc" : "dec");
|
||||
}
|
||||
|
||||
ComplexPairTy IncVal(NextVal, InVal.second);
|
||||
|
||||
// Store the updated result through the lvalue.
|
||||
EmitStoreOfComplex(IncVal, LV.getAddress(), LV.isVolatileQualified());
|
||||
|
||||
// If this is a postinc, return the value read from memory, otherwise use the
|
||||
// updated value.
|
||||
return isPre ? IncVal : InVal;
|
||||
}
|
||||
|
||||
ComplexPairTy ComplexExprEmitter::VisitUnaryMinus(const UnaryOperator *E) {
|
||||
TestAndClearIgnoreReal();
|
||||
TestAndClearIgnoreImag();
|
||||
|
@ -408,6 +408,8 @@ public:
|
||||
llvm::Constant *EmitMemberFunctionPointer(CXXMethodDecl *MD) {
|
||||
assert(MD->isInstance() && "Member function must not be static!");
|
||||
|
||||
MD = MD->getCanonicalDecl();
|
||||
|
||||
const llvm::Type *PtrDiffTy =
|
||||
CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType());
|
||||
|
||||
@ -633,32 +635,6 @@ public:
|
||||
return ConstStructBuilder::BuildStruct(CGM, CGF, ILE);
|
||||
}
|
||||
|
||||
llvm::Constant *EmitVectorInitialization(InitListExpr *ILE) {
|
||||
const llvm::VectorType *VType =
|
||||
cast<llvm::VectorType>(ConvertType(ILE->getType()));
|
||||
const llvm::Type *ElemTy = VType->getElementType();
|
||||
std::vector<llvm::Constant*> Elts;
|
||||
unsigned NumElements = VType->getNumElements();
|
||||
unsigned NumInitElements = ILE->getNumInits();
|
||||
|
||||
unsigned NumInitableElts = std::min(NumInitElements, NumElements);
|
||||
|
||||
// Copy initializer elements.
|
||||
unsigned i = 0;
|
||||
for (; i < NumInitableElts; ++i) {
|
||||
Expr *Init = ILE->getInit(i);
|
||||
llvm::Constant *C = CGM.EmitConstantExpr(Init, Init->getType(), CGF);
|
||||
if (!C)
|
||||
return 0;
|
||||
Elts.push_back(C);
|
||||
}
|
||||
|
||||
for (; i < NumElements; ++i)
|
||||
Elts.push_back(llvm::Constant::getNullValue(ElemTy));
|
||||
|
||||
return llvm::ConstantVector::get(VType, Elts);
|
||||
}
|
||||
|
||||
llvm::Constant *VisitImplicitValueInitExpr(ImplicitValueInitExpr* E) {
|
||||
return CGM.EmitNullConstant(E->getType());
|
||||
}
|
||||
@ -682,8 +658,9 @@ public:
|
||||
if (ILE->getType()->isUnionType())
|
||||
return EmitUnionInitialization(ILE);
|
||||
|
||||
// If ILE was a constant vector, we would have handled it already.
|
||||
if (ILE->getType()->isVectorType())
|
||||
return EmitVectorInitialization(ILE);
|
||||
return 0;
|
||||
|
||||
assert(0 && "Unable to handle InitListExpr");
|
||||
// Get rid of control reaches end of void function warning.
|
||||
@ -833,7 +810,7 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E,
|
||||
const llvm::Type *DestTy = getTypes().ConvertTypeForMem(DestType);
|
||||
llvm::Constant *Offset =
|
||||
llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
|
||||
Result.Val.getLValueOffset());
|
||||
Result.Val.getLValueOffset().getQuantity());
|
||||
|
||||
llvm::Constant *C;
|
||||
if (const Expr *LVBase = Result.Val.getLValueBase()) {
|
||||
|
@ -181,12 +181,6 @@ public:
|
||||
Value *VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
|
||||
return EmitLoadOfLValue(E);
|
||||
}
|
||||
Value *VisitStringLiteral(Expr *E) { return EmitLValue(E).getAddress(); }
|
||||
Value *VisitObjCEncodeExpr(const ObjCEncodeExpr *E) {
|
||||
return EmitLValue(E).getAddress();
|
||||
}
|
||||
|
||||
Value *VisitPredefinedExpr(Expr *E) { return EmitLValue(E).getAddress(); }
|
||||
|
||||
Value *VisitInitListExpr(InitListExpr *E);
|
||||
|
||||
@ -214,7 +208,10 @@ public:
|
||||
Value *VisitBlockDeclRefExpr(const BlockDeclRefExpr *E);
|
||||
|
||||
// Unary Operators.
|
||||
Value *VisitPrePostIncDec(const UnaryOperator *E, bool isInc, bool isPre);
|
||||
Value *VisitPrePostIncDec(const UnaryOperator *E, bool isInc, bool isPre) {
|
||||
LValue LV = EmitLValue(E->getSubExpr());
|
||||
return CGF.EmitScalarPrePostIncDec(E, LV, isInc, isPre);
|
||||
}
|
||||
Value *VisitUnaryPostDec(const UnaryOperator *E) {
|
||||
return VisitPrePostIncDec(E, false, false);
|
||||
}
|
||||
@ -1009,98 +1006,6 @@ Value *ScalarExprEmitter::VisitBlockDeclRefExpr(const BlockDeclRefExpr *E) {
|
||||
// Unary Operators
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
Value *ScalarExprEmitter::VisitPrePostIncDec(const UnaryOperator *E,
|
||||
bool isInc, bool isPre) {
|
||||
LValue LV = EmitLValue(E->getSubExpr());
|
||||
QualType ValTy = E->getSubExpr()->getType();
|
||||
Value *InVal = CGF.EmitLoadOfLValue(LV, ValTy).getScalarVal();
|
||||
|
||||
llvm::LLVMContext &VMContext = CGF.getLLVMContext();
|
||||
|
||||
int AmountVal = isInc ? 1 : -1;
|
||||
|
||||
if (ValTy->isPointerType() &&
|
||||
ValTy->getAs<PointerType>()->isVariableArrayType()) {
|
||||
// The amount of the addition/subtraction needs to account for the VLA size
|
||||
CGF.ErrorUnsupported(E, "VLA pointer inc/dec");
|
||||
}
|
||||
|
||||
Value *NextVal;
|
||||
if (const llvm::PointerType *PT =
|
||||
dyn_cast<llvm::PointerType>(InVal->getType())) {
|
||||
llvm::Constant *Inc =
|
||||
llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), AmountVal);
|
||||
if (!isa<llvm::FunctionType>(PT->getElementType())) {
|
||||
QualType PTEE = ValTy->getPointeeType();
|
||||
if (const ObjCInterfaceType *OIT =
|
||||
dyn_cast<ObjCInterfaceType>(PTEE)) {
|
||||
// Handle interface types, which are not represented with a concrete type.
|
||||
int size = CGF.getContext().getTypeSize(OIT) / 8;
|
||||
if (!isInc)
|
||||
size = -size;
|
||||
Inc = llvm::ConstantInt::get(Inc->getType(), size);
|
||||
const llvm::Type *i8Ty = llvm::Type::getInt8PtrTy(VMContext);
|
||||
InVal = Builder.CreateBitCast(InVal, i8Ty);
|
||||
NextVal = Builder.CreateGEP(InVal, Inc, "add.ptr");
|
||||
llvm::Value *lhs = LV.getAddress();
|
||||
lhs = Builder.CreateBitCast(lhs, llvm::PointerType::getUnqual(i8Ty));
|
||||
LV = LValue::MakeAddr(lhs, CGF.MakeQualifiers(ValTy));
|
||||
} else
|
||||
NextVal = Builder.CreateInBoundsGEP(InVal, Inc, "ptrincdec");
|
||||
} else {
|
||||
const llvm::Type *i8Ty = llvm::Type::getInt8PtrTy(VMContext);
|
||||
NextVal = Builder.CreateBitCast(InVal, i8Ty, "tmp");
|
||||
NextVal = Builder.CreateGEP(NextVal, Inc, "ptrincdec");
|
||||
NextVal = Builder.CreateBitCast(NextVal, InVal->getType());
|
||||
}
|
||||
} else if (InVal->getType() == llvm::Type::getInt1Ty(VMContext) && isInc) {
|
||||
// Bool++ is an interesting case, due to promotion rules, we get:
|
||||
// Bool++ -> Bool = Bool+1 -> Bool = (int)Bool+1 ->
|
||||
// Bool = ((int)Bool+1) != 0
|
||||
// An interesting aspect of this is that increment is always true.
|
||||
// Decrement does not have this property.
|
||||
NextVal = llvm::ConstantInt::getTrue(VMContext);
|
||||
} else if (isa<llvm::IntegerType>(InVal->getType())) {
|
||||
NextVal = llvm::ConstantInt::get(InVal->getType(), AmountVal);
|
||||
|
||||
// Signed integer overflow is undefined behavior.
|
||||
if (ValTy->isSignedIntegerType())
|
||||
NextVal = Builder.CreateNSWAdd(InVal, NextVal, isInc ? "inc" : "dec");
|
||||
else
|
||||
NextVal = Builder.CreateAdd(InVal, NextVal, isInc ? "inc" : "dec");
|
||||
} else {
|
||||
// Add the inc/dec to the real part.
|
||||
if (InVal->getType()->isFloatTy())
|
||||
NextVal =
|
||||
llvm::ConstantFP::get(VMContext,
|
||||
llvm::APFloat(static_cast<float>(AmountVal)));
|
||||
else if (InVal->getType()->isDoubleTy())
|
||||
NextVal =
|
||||
llvm::ConstantFP::get(VMContext,
|
||||
llvm::APFloat(static_cast<double>(AmountVal)));
|
||||
else {
|
||||
llvm::APFloat F(static_cast<float>(AmountVal));
|
||||
bool ignored;
|
||||
F.convert(CGF.Target.getLongDoubleFormat(), llvm::APFloat::rmTowardZero,
|
||||
&ignored);
|
||||
NextVal = llvm::ConstantFP::get(VMContext, F);
|
||||
}
|
||||
NextVal = Builder.CreateFAdd(InVal, NextVal, isInc ? "inc" : "dec");
|
||||
}
|
||||
|
||||
// Store the updated result through the lvalue.
|
||||
if (LV.isBitfield())
|
||||
CGF.EmitStoreThroughBitfieldLValue(RValue::get(NextVal), LV, ValTy,
|
||||
&NextVal);
|
||||
else
|
||||
CGF.EmitStoreThroughLValue(RValue::get(NextVal), LV, ValTy);
|
||||
|
||||
// If this is a postinc, return the value read from memory, otherwise use the
|
||||
// updated value.
|
||||
return isPre ? NextVal : InVal;
|
||||
}
|
||||
|
||||
|
||||
Value *ScalarExprEmitter::VisitUnaryMinus(const UnaryOperator *E) {
|
||||
TestAndClearIgnoreResultAssign();
|
||||
Value *Op = Visit(E->getSubExpr());
|
||||
@ -1405,7 +1310,7 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &Ops) {
|
||||
if (const ObjCInterfaceType *OIT = dyn_cast<ObjCInterfaceType>(ElementType)) {
|
||||
llvm::Value *InterfaceSize =
|
||||
llvm::ConstantInt::get(Idx->getType(),
|
||||
CGF.getContext().getTypeSize(OIT) / 8);
|
||||
CGF.getContext().getTypeSizeInChars(OIT).getQuantity());
|
||||
Idx = Builder.CreateMul(Idx, InterfaceSize);
|
||||
const llvm::Type *i8Ty = llvm::Type::getInt8PtrTy(VMContext);
|
||||
Value *Casted = Builder.CreateBitCast(Ptr, i8Ty);
|
||||
@ -1469,7 +1374,8 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) {
|
||||
dyn_cast<ObjCInterfaceType>(LHSElementType)) {
|
||||
llvm::Value *InterfaceSize =
|
||||
llvm::ConstantInt::get(Idx->getType(),
|
||||
CGF.getContext().getTypeSize(OIT) / 8);
|
||||
CGF.getContext().
|
||||
getTypeSizeInChars(OIT).getQuantity());
|
||||
Idx = Builder.CreateMul(Idx, InterfaceSize);
|
||||
const llvm::Type *i8Ty = llvm::Type::getInt8PtrTy(VMContext);
|
||||
Value *LHSCasted = Builder.CreateBitCast(Ops.LHS, i8Ty);
|
||||
@ -1493,14 +1399,14 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) {
|
||||
Value *LHS = Ops.LHS;
|
||||
Value *RHS = Ops.RHS;
|
||||
|
||||
uint64_t ElementSize;
|
||||
CharUnits ElementSize;
|
||||
|
||||
// Handle GCC extension for pointer arithmetic on void* and function pointer
|
||||
// types.
|
||||
if (LHSElementType->isVoidType() || LHSElementType->isFunctionType()) {
|
||||
ElementSize = 1;
|
||||
ElementSize = CharUnits::One();
|
||||
} else {
|
||||
ElementSize = CGF.getContext().getTypeSize(LHSElementType) / 8;
|
||||
ElementSize = CGF.getContext().getTypeSizeInChars(LHSElementType);
|
||||
}
|
||||
|
||||
const llvm::Type *ResultType = ConvertType(Ops.Ty);
|
||||
@ -1509,13 +1415,14 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &Ops) {
|
||||
Value *BytesBetween = Builder.CreateSub(LHS, RHS, "sub.ptr.sub");
|
||||
|
||||
// Optimize out the shift for element size of 1.
|
||||
if (ElementSize == 1)
|
||||
if (ElementSize.isOne())
|
||||
return BytesBetween;
|
||||
|
||||
// Otherwise, do a full sdiv. This uses the "exact" form of sdiv, since
|
||||
// pointer difference in C is only defined in the case where both operands
|
||||
// are pointing to elements of an array.
|
||||
Value *BytesPerElt = llvm::ConstantInt::get(ResultType, ElementSize);
|
||||
Value *BytesPerElt =
|
||||
llvm::ConstantInt::get(ResultType, ElementSize.getQuantity());
|
||||
return Builder.CreateExactSDiv(BytesBetween, BytesPerElt, "sub.ptr.div");
|
||||
}
|
||||
}
|
||||
@ -1971,47 +1878,6 @@ Value *CodeGenFunction::EmitComplexToScalarConversion(ComplexPairTy Src,
|
||||
DstTy);
|
||||
}
|
||||
|
||||
Value *CodeGenFunction::EmitShuffleVector(Value* V1, Value *V2, ...) {
|
||||
assert(V1->getType() == V2->getType() &&
|
||||
"Vector operands must be of the same type");
|
||||
unsigned NumElements =
|
||||
cast<llvm::VectorType>(V1->getType())->getNumElements();
|
||||
|
||||
va_list va;
|
||||
va_start(va, V2);
|
||||
|
||||
llvm::SmallVector<llvm::Constant*, 16> Args;
|
||||
for (unsigned i = 0; i < NumElements; i++) {
|
||||
int n = va_arg(va, int);
|
||||
assert(n >= 0 && n < (int)NumElements * 2 &&
|
||||
"Vector shuffle index out of bounds!");
|
||||
Args.push_back(llvm::ConstantInt::get(
|
||||
llvm::Type::getInt32Ty(VMContext), n));
|
||||
}
|
||||
|
||||
const char *Name = va_arg(va, const char *);
|
||||
va_end(va);
|
||||
|
||||
llvm::Constant *Mask = llvm::ConstantVector::get(&Args[0], NumElements);
|
||||
|
||||
return Builder.CreateShuffleVector(V1, V2, Mask, Name);
|
||||
}
|
||||
|
||||
llvm::Value *CodeGenFunction::EmitVector(llvm::Value * const *Vals,
|
||||
unsigned NumVals, bool isSplat) {
|
||||
llvm::Value *Vec
|
||||
= llvm::UndefValue::get(llvm::VectorType::get(Vals[0]->getType(), NumVals));
|
||||
|
||||
for (unsigned i = 0, e = NumVals; i != e; ++i) {
|
||||
llvm::Value *Val = isSplat ? Vals[0] : Vals[i];
|
||||
llvm::Value *Idx = llvm::ConstantInt::get(
|
||||
llvm::Type::getInt32Ty(VMContext), i);
|
||||
Vec = Builder.CreateInsertElement(Vec, Val, Idx, "tmp");
|
||||
}
|
||||
|
||||
return Vec;
|
||||
}
|
||||
|
||||
LValue CodeGenFunction::EmitObjCIsaExpr(const ObjCIsaExpr *E) {
|
||||
llvm::Value *V;
|
||||
// object->isa or (*object).isa
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user