Update clang to r93512.

This commit is contained in:
Roman Divacky 2010-01-15 15:39:40 +00:00
parent abe15e553e
commit ee791dde72
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/vendor/clang/dist/; revision=202379
390 changed files with 15120 additions and 6209 deletions

View File

@ -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:

View File

@ -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>

View File

@ -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>
<!-- ======================================================================= -->

View File

@ -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
--

View File

@ -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
};
/**

View File

@ -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 @@ class APValue {
ComplexAPFloat() : Real(0.0), Imag(0.0) {}
};
struct LV {
Expr* Base;
uint64_t Offset;
};
struct Vec {
APValue *Elts;
unsigned NumElts;
@ -88,9 +85,11 @@ class APValue {
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 @@ class APValue {
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 @@ class APValue {
((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 @@ class APValue {
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) {

View File

@ -699,8 +699,8 @@ class ASTContext {
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 @@ class ASTContext {
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 @@ class ASTContext {
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);

View File

@ -55,8 +55,6 @@ class Attr {
Cleanup,
Const,
Constructor,
DLLExport,
DLLImport,
Deprecated,
Destructor,
FastCall,
@ -93,7 +91,12 @@ class Attr {
Visibility,
WarnUnusedResult,
Weak,
WeakImport
WeakImport,
FIRST_TARGET_ATTRIBUTE,
DLLExport,
DLLImport,
MSP430Interrupt
};
private:
@ -158,7 +161,7 @@ class Attr {
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 @@ class PragmaPackAttr : public Attr {
/// 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 @@ class AlignedAttr : public Attr {
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 @@ class AnnotateAttr : public Attr {
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 @@ class AsmLabelAttr : public Attr {
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 @@ class AliasAttr : public Attr {
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 @@ class ConstructorAttr : public Attr {
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 @@ class DestructorAttr : public Attr {
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 @@ class SectionAttr : public Attr {
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 @@ class NonNullAttr : public Attr {
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 @@ class FormatAttr : public Attr {
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 @@ class FormatArgAttr : public Attr {
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 @@ class SentinelAttr : public Attr {
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 @@ class VisibilityAttr : public Attr {
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 @@ class OverloadableAttr : public Attr {
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 @@ class BlocksAttr : public Attr {
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 @@ class CleanupAttr : public Attr {
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 @@ class RegparmAttr : public Attr {
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 @@ class ReqdWorkGroupSizeAttr : public Attr {
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

View File

@ -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;
}

View File

@ -1184,6 +1184,8 @@ class FunctionDecl : public DeclaratorDecl, public DeclContext,
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.

View File

@ -393,6 +393,9 @@ class CXXRecordDecl : public RecordDecl {
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.

View File

@ -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 @@ class ObjCContainerDecl : public NamedDecl, public DeclContext {
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.

View File

@ -190,6 +190,14 @@ class DeclarationName {
/// 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

View File

@ -241,6 +241,11 @@ class Expr : public Stmt {
/// 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 @@ class DesignatedInitExpr : public Expr {
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 @@ class DesignatedInitExpr : public Expr {
protected:
virtual void DoDestroy(ASTContext &C);
void DestroyDesignators(ASTContext &C);
public:
/// A field designator, e.g., ".x".
struct FieldDesignator {
@ -2732,7 +2739,8 @@ class DesignatedInitExpr : public Expr {
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 @@ class DesignatedInitExpr : public Expr {
/// \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;

View File

@ -324,17 +324,21 @@ class CXXTypeidExpr : public Expr {
/// @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;
}

View File

@ -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 @@ class AsmStmt : public Stmt {
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 ---===//

View File

@ -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.

View File

@ -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 @@ class BugReport : public BugReporterVisitor {
// 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 @@ class DiagBugReport : public RangedBugReport {
// 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(); }

View File

@ -25,6 +25,7 @@ namespace clang {
class GRState;
class GRStateManager;
class GRSubEngine;
class SVal;
class ConstraintManager {
@ -64,8 +65,10 @@ class ConstraintManager {
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

View File

@ -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 @@ class GRExprEngine : public GRSubEngine {
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 @@ class GRExprEngine : public GRSubEngine {
/// 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 @@ class GRExprEngine : public GRSubEngine {
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.

View File

@ -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 @@ class GRState : public llvm::FoldingSetNode {
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 @@ class GRStateSet {
//===----------------------------------------------------------------------===//
class GRStateManager {
friend class GRExprEngine;
friend class GRState;
friend class GRExprEngine; // FIXME: Remove.
private:
EnvironmentManager EnvMgr;
llvm::OwningPtr<StoreManager> StoreMgr;
@ -416,27 +411,20 @@ class GRStateManager {
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 @@ class GRStateManager {
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>());

View File

@ -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 @@ class GRSubEngine {
/// 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

View File

@ -65,6 +65,7 @@ class MemRegion : public llvm::FoldingSetNode {
BlockTextRegionKind,
BlockDataRegionKind,
CompoundLiteralRegionKind,
CXXThisRegionKind,
StringRegionKind,
ElementRegionKind,
// Decl Regions.
@ -99,17 +100,13 @@ class MemRegion : public llvm::FoldingSetNode {
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 @@ class VarRegion : public DeclRegion {
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 @@ class ElementRegion : public TypedRegion {
}
};
// 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 @@ class MemRegionManager {
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 @@ class MemRegionManager {
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,

View File

@ -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:

View File

@ -103,9 +103,6 @@ class StoreManager {
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 @@ class StoreManager {
/// 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?

View File

@ -781,6 +781,11 @@ class DiagnosticInfo {
/// 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

View File

@ -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">;
}

View File

@ -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>">;

View File

@ -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<

View File

@ -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">;
}

View File

@ -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 @@ class PartialDiagnostic {
// 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 @@ class PartialDiagnostic {
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) {

View File

@ -162,6 +162,7 @@ class SourceRange {
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;

View File

@ -30,6 +30,7 @@ class StringRef;
namespace clang {
class Diagnostic;
class LangOptions;
class MacroBuilder;
class SourceLocation;
class SourceManager;
class TargetOptions;
@ -209,7 +210,7 @@ class TargetInfo {
/// 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

View File

@ -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">,

View File

@ -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>;

View File

@ -87,10 +87,6 @@ class ToolChain {
// 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; }

View File

@ -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")

View File

@ -32,6 +32,7 @@ class Diagnostic;
class DiagnosticClient;
class ExternalASTSource;
class FileManager;
class FrontendAction;
class Preprocessor;
class Source;
class SourceManager;
@ -103,6 +104,42 @@ class CompilerInstance {
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 @@ class CompilerInstance {
const HeaderSearchOptions &,
const DependencyOutputOptions &,
const TargetInfo &,
const FrontendOptions &,
SourceManager &, FileManager &);
/// Create the AST context.

View File

@ -35,6 +35,10 @@ class DiagnosticOptions {
/// 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 @@ class DiagnosticOptions {
public:
DiagnosticOptions() {
IgnoreWarnings = 0;
TabStop = DefaultTabStop;
MessageLength = 0;
NoRewriteMacros = 0;
Pedantic = 0;

View File

@ -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 @@ class PCHValidator : public PCHReaderListener {
/// 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 @@ class PCHReader
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 @@ class PCHReader
/// 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 @@ class PCHReader
/// \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; }

View File

@ -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.

View File

@ -16,6 +16,9 @@
#include "clang/Basic/SourceManager.h"
namespace llvm {
class StringRef;
}
namespace clang {
class HeaderMap;
class DirectoryEntry;
@ -118,12 +121,10 @@ class DirectoryLookup {
/// 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;
};

View 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

View File

@ -16,6 +16,7 @@
namespace llvm {
class MemoryBuffer;
class StringRef;
}
namespace clang {
class FileEntry;
@ -46,8 +47,7 @@ class HeaderMap {
/// 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;

View File

@ -150,8 +150,7 @@ class HeaderSearch {
/// 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 @@ class HeaderSearch {
/// 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

View File

@ -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 @@ class Preprocessor {
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 @@ class Preprocessor {
/// 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 @@ class Preprocessor {
/// 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

View File

@ -291,6 +291,42 @@ class Action : public ActionBase {
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 @@ class Action : public ActionBase {
MultiExprArg Exprs,
ExprArg AsmString,
MultiExprArg Clobbers,
SourceLocation RParenLoc) {
SourceLocation RParenLoc,
bool MSAsm = false) {
return StmtEmpty();
}
@ -2176,7 +2213,7 @@ class Action : public ActionBase {
// 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 @@ class Action : public ActionBase {
/// \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 @@ class Action : public ActionBase {
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) { }

View File

@ -194,6 +194,7 @@ class DeclSpec {
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 @@ class DeclSpec {
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 @@ class UnqualifiedId {
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 @@ class UnqualifiedId {
/// 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 @@ class UnqualifiedId {
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

View File

@ -784,7 +784,7 @@ class Parser {
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 @@ class Parser {
/// 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 @@ class Parser {
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 @@ class Parser {
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 {

View File

@ -146,13 +146,13 @@ class Rewriter {
/// 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

View File

@ -85,7 +85,18 @@ class CodeCompletionString {
/// \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 @@ class CodeCompleteConsumer {
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 @@ class CodeCompleteConsumer {
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) { }

View File

@ -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;
}

View File

@ -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
View 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);
}

View File

@ -4,6 +4,7 @@ add_clang_library(clangAST
APValue.cpp
ASTConsumer.cpp
ASTContext.cpp
AttrImpl.cpp
CXXInheritance.cpp
Decl.cpp
DeclBase.cpp

View File

@ -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());

View File

@ -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::

View File

@ -56,9 +56,14 @@ class CXXOperatorIdName : public DeclarationNameExtra {
/// 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);
}

View File

@ -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)

View File

@ -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 @@ class LValueExprEvaluator
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 @@ class PointerExprEvaluator
{ 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);

View File

@ -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;

View File

@ -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]);

View File

@ -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.
}

View File

@ -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());
}

View File

@ -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,

View File

@ -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");
}

View File

@ -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 @@ class BasicConstraintManager
} // 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*

View File

@ -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!");

View File

@ -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.

View File

@ -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.

View File

@ -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

View File

@ -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.
//===----------------------------------------------------------------------===//

View File

@ -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);

View File

@ -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());
}
//===----------------------------------------------------------------------===//

View File

@ -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);
}
}

View File

@ -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 @@ class RangeConstraintManager : public SimpleConstraintManager{
} // 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,

View File

@ -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 @@ class RegionStoreManager : public StoreManager {
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 @@ class RegionStoreManager : public StoreManager {
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 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc,
// 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))

View File

@ -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);

View File

@ -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;
}

View File

@ -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))

View File

@ -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,

View File

@ -20,8 +20,9 @@
namespace clang {
class SimpleConstraintManager : public ConstraintManager {
GRSubEngine &SU;
public:
SimpleConstraintManager() {}
SimpleConstraintManager(GRSubEngine &subengine) : SU(subengine) {}
virtual ~SimpleConstraintManager();
//===------------------------------------------------------------------===//

View File

@ -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()) {

View File

@ -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);
}

View File

@ -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;

View File

@ -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 @@ class FreeBSDTargetInfo : public OSTargetInfo<Target> {
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 @@ class PPCTargetInfo : public TargetInfo {
}
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 @@ class X86TargetInfo : public TargetInfo {
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 @@ class WindowsX86_32TargetInfo : public X86_32TargetInfo {
"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 @@ class VisualStudioWindowsX86_32TargetInfo : public WindowsX86_32TargetInfo {
: 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 @@ class MinGWX86_32TargetInfo : public WindowsX86_32TargetInfo {
: 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 @@ class CygwinX86_32TargetInfo : public X86_32TargetInfo {
"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 @@ class WindowsX86_64TargetInfo : public X86_64TargetInfo {
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 @@ class VisualStudioWindowsX86_64TargetInfo : public WindowsX86_64TargetInfo {
: 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 @@ class MinGWX86_64TargetInfo : public WindowsX86_64TargetInfo {
: 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 @@ class ARMTargetInfo : public TargetInfo {
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 @@ class SparcV8TargetInfo : public TargetInfo {
"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 @@ class MipsTargetInfo : public TargetInfo {
"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 @@ class MipselTargetInfo : public MipsTargetInfo {
}
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:

View File

@ -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);

View File

@ -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 @@ class BlockFunction : public BlockBase {
/// 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 @@ class BlockFunction : public BlockBase {
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; }

View File

@ -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);
}

View File

@ -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");
}

View File

@ -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.

View File

@ -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 @@ class CGDebugInfo {
/// 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 @@ class CGDebugInfo {
/// 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

View File

@ -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)

View File

@ -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();
}

View File

@ -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).

View File

@ -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());

View File

@ -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;

View File

@ -145,7 +145,10 @@ class ComplexExprEmitter
// 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();

View File

@ -408,6 +408,8 @@ class ConstExprEmitter :
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 @@ class ConstExprEmitter :
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 @@ class ConstExprEmitter :
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()) {

View File

@ -181,12 +181,6 @@ class ScalarExprEmitter
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 @@ class ScalarExprEmitter
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