Vendor import of clang release_31 branch r155985:
http://llvm.org/svn/llvm-project/cfe/branches/release_31@155985
This commit is contained in:
parent
dbe13110f5
commit
6b9a6e390f
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/vendor/clang/dist/; revision=234973 svn path=/vendor/clang/clang-release_31-r155985/; revision=234974; tag=vendor/clang/clang-release_31-r155985
@ -66,6 +66,10 @@ set(CLANG_RESOURCE_DIR "" CACHE STRING
|
||||
set(C_INCLUDE_DIRS "" CACHE STRING
|
||||
"Colon separated list of directories clang will search for headers.")
|
||||
|
||||
set(GCC_INSTALL_PREFIX "" CACHE PATH "Directory where gcc is installed." )
|
||||
set(DEFAULT_SYSROOT "" CACHE PATH
|
||||
"Default <path> to all compiler invocations for --sysroot=<path>." )
|
||||
|
||||
set(CLANG_VENDOR "" CACHE STRING
|
||||
"Vendor-specific text for showing with version information.")
|
||||
|
||||
|
@ -1079,6 +1079,11 @@ def name(self):
|
||||
self._name_map[value] = key
|
||||
return self._name_map[self]
|
||||
|
||||
@property
|
||||
def spelling(self):
|
||||
"""Retrieve the spelling of this TypeKind."""
|
||||
return TypeKind_spelling(self.value)
|
||||
|
||||
@staticmethod
|
||||
def from_id(id):
|
||||
if id >= len(TypeKind._kinds) or TypeKind._kinds[id] is None:
|
||||
@ -1088,6 +1093,10 @@ def from_id(id):
|
||||
def __repr__(self):
|
||||
return 'TypeKind.%s' % (self.name,)
|
||||
|
||||
TypeKind_spelling = lib.clang_getTypeKindSpelling
|
||||
TypeKind_spelling.argtypes = [c_uint]
|
||||
TypeKind_spelling.restype = _CXString
|
||||
TypeKind_spelling.errcheck = _CXString.from_result
|
||||
|
||||
|
||||
TypeKind.INVALID = TypeKind(0)
|
||||
|
@ -1,5 +1,4 @@
|
||||
from clang.cindex import CursorKind
|
||||
from clang.cindex import Index
|
||||
from clang.cindex import TypeKind
|
||||
from nose.tools import raises
|
||||
from .util import get_cursor
|
||||
@ -109,6 +108,14 @@ def test_equal():
|
||||
assert a.type != None
|
||||
assert a.type != 'foo'
|
||||
|
||||
def test_typekind_spelling():
|
||||
"""Ensure TypeKind.spelling works."""
|
||||
tu = get_tu('int a;')
|
||||
a = get_cursor(tu, 'a')
|
||||
|
||||
assert a is not None
|
||||
assert a.type.kind.spelling == 'Int'
|
||||
|
||||
def test_function_argument_types():
|
||||
"""Ensure that Type.argument_types() works as expected."""
|
||||
tu = get_tu('void f(int, int);')
|
||||
|
@ -7,7 +7,6 @@ set(LLVM_USED_LIBS
|
||||
clangStaticAnalyzerFrontend
|
||||
clangStaticAnalyzerCheckers
|
||||
clangStaticAnalyzerCore
|
||||
clangIndex
|
||||
clangAnalysis
|
||||
clangRewrite
|
||||
clangAST
|
||||
|
@ -64,6 +64,9 @@ class TypeSourceInfo {
|
||||
|
||||
/// \brief Return the TypeLoc wrapper for the type source info.
|
||||
TypeLoc getTypeLoc() const; // implemented in TypeLoc.h
|
||||
|
||||
/// \brief Override the type stored in this TypeSourceInfo. Use with caution!
|
||||
void overrideType(QualType T) { Ty = T; }
|
||||
};
|
||||
|
||||
/// TranslationUnitDecl - The top declaration context.
|
||||
@ -242,11 +245,7 @@ class NamedDecl : public Decl {
|
||||
bool visibilityExplicit() const { return explicit_; }
|
||||
|
||||
void setLinkage(Linkage L) { linkage_ = L; }
|
||||
void setVisibility(Visibility V) { visibility_ = V; }
|
||||
void setVisibility(Visibility V, bool E) { visibility_ = V; explicit_ = E; }
|
||||
void setVisibility(LinkageInfo Other) {
|
||||
setVisibility(Other.visibility(), Other.visibilityExplicit());
|
||||
}
|
||||
|
||||
void mergeLinkage(Linkage L) {
|
||||
setLinkage(minLinkage(linkage(), L));
|
||||
|
@ -861,7 +861,6 @@ class Decl {
|
||||
void dumpXML(raw_ostream &OS) const;
|
||||
|
||||
private:
|
||||
const Attr *getAttrsImpl() const;
|
||||
void setAttrsImpl(const AttrVec& Attrs, ASTContext &Ctx);
|
||||
void setDeclContextsImpl(DeclContext *SemaDC, DeclContext *LexicalDC,
|
||||
ASTContext &Ctx);
|
||||
|
@ -67,6 +67,8 @@ class DeclContext::all_lookups_iterator {
|
||||
|
||||
DeclContext::all_lookups_iterator DeclContext::lookups_begin() const {
|
||||
DeclContext *Primary = const_cast<DeclContext*>(this)->getPrimaryContext();
|
||||
if (hasExternalVisibleStorage())
|
||||
getParentASTContext().getExternalSource()->completeVisibleDeclsMap(Primary);
|
||||
if (StoredDeclsMap *Map = Primary->buildLookup())
|
||||
return all_lookups_iterator(Map->begin(), Map->end());
|
||||
return all_lookups_iterator();
|
||||
@ -74,6 +76,8 @@ DeclContext::all_lookups_iterator DeclContext::lookups_begin() const {
|
||||
|
||||
DeclContext::all_lookups_iterator DeclContext::lookups_end() const {
|
||||
DeclContext *Primary = const_cast<DeclContext*>(this)->getPrimaryContext();
|
||||
if (hasExternalVisibleStorage())
|
||||
getParentASTContext().getExternalSource()->completeVisibleDeclsMap(Primary);
|
||||
if (StoredDeclsMap *Map = Primary->buildLookup())
|
||||
return all_lookups_iterator(Map->end(), Map->end());
|
||||
return all_lookups_iterator();
|
||||
|
@ -581,16 +581,6 @@ class Expr : public Stmt {
|
||||
/// member expression.
|
||||
static QualType findBoundMemberType(const Expr *expr);
|
||||
|
||||
/// \brief Result type of CanThrow().
|
||||
enum CanThrowResult {
|
||||
CT_Cannot,
|
||||
CT_Dependent,
|
||||
CT_Can
|
||||
};
|
||||
/// \brief Test if this expression, if evaluated, might throw, according to
|
||||
/// the rules of C++ [expr.unary.noexcept].
|
||||
CanThrowResult CanThrow(ASTContext &C) const;
|
||||
|
||||
/// IgnoreImpCasts - Skip past any implicit casts which might
|
||||
/// surround this expression. Only skips ImplicitCastExprs.
|
||||
Expr *IgnoreImpCasts() LLVM_READONLY;
|
||||
@ -3608,6 +3598,10 @@ class InitListExpr : public Expr {
|
||||
return LBraceLoc.isValid() && RBraceLoc.isValid();
|
||||
}
|
||||
|
||||
// Is this an initializer for an array of characters, initialized by a string
|
||||
// literal or an @encode?
|
||||
bool isStringLiteralInit() const;
|
||||
|
||||
SourceLocation getLBraceLoc() const { return LBraceLoc; }
|
||||
void setLBraceLoc(SourceLocation Loc) { LBraceLoc = Loc; }
|
||||
SourceLocation getRBraceLoc() const { return RBraceLoc; }
|
||||
|
@ -126,6 +126,12 @@ class ExternalASTSource {
|
||||
virtual DeclContextLookupResult
|
||||
FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name);
|
||||
|
||||
/// \brief Ensures that the table of all visible declarations inside this
|
||||
/// context is up to date.
|
||||
///
|
||||
/// The default implementation of this functino is a no-op.
|
||||
virtual void completeVisibleDeclsMap(const DeclContext *DC);
|
||||
|
||||
/// \brief Finds all declarations lexically contained within the given
|
||||
/// DeclContext, after applying an optional filter predicate.
|
||||
///
|
||||
|
@ -1870,6 +1870,7 @@ DEF_TRAVERSE_STMT(GotoStmt, { })
|
||||
DEF_TRAVERSE_STMT(IfStmt, { })
|
||||
DEF_TRAVERSE_STMT(IndirectGotoStmt, { })
|
||||
DEF_TRAVERSE_STMT(LabelStmt, { })
|
||||
DEF_TRAVERSE_STMT(AttributedStmt, { })
|
||||
DEF_TRAVERSE_STMT(NullStmt, { })
|
||||
DEF_TRAVERSE_STMT(ObjCAtCatchStmt, { })
|
||||
DEF_TRAVERSE_STMT(ObjCAtFinallyStmt, { })
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "clang/AST/StmtIterator.h"
|
||||
#include "clang/AST/DeclGroup.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/Attr.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
@ -794,6 +795,47 @@ class LabelStmt : public Stmt {
|
||||
};
|
||||
|
||||
|
||||
/// \brief Represents an attribute applied to a statement.
|
||||
///
|
||||
/// Represents an attribute applied to a statement. For example:
|
||||
/// [[omp::for(...)]] for (...) { ... }
|
||||
///
|
||||
class AttributedStmt : public Stmt {
|
||||
Stmt *SubStmt;
|
||||
SourceLocation AttrLoc;
|
||||
AttrVec Attrs;
|
||||
// TODO: It can be done as Attr *Attrs[1]; and variable size array as in
|
||||
// StringLiteral
|
||||
|
||||
friend class ASTStmtReader;
|
||||
|
||||
public:
|
||||
AttributedStmt(SourceLocation loc, const AttrVec &attrs, Stmt *substmt)
|
||||
: Stmt(AttributedStmtClass), SubStmt(substmt), AttrLoc(loc), Attrs(attrs) {
|
||||
}
|
||||
|
||||
// \brief Build an empty attributed statement.
|
||||
explicit AttributedStmt(EmptyShell Empty)
|
||||
: Stmt(AttributedStmtClass, Empty) {
|
||||
}
|
||||
|
||||
SourceLocation getAttrLoc() const { return AttrLoc; }
|
||||
const AttrVec &getAttrs() const { return Attrs; }
|
||||
Stmt *getSubStmt() { return SubStmt; }
|
||||
const Stmt *getSubStmt() const { return SubStmt; }
|
||||
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange(AttrLoc, SubStmt->getLocEnd());
|
||||
}
|
||||
child_range children() { return child_range(&SubStmt, &SubStmt + 1); }
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == AttributedStmtClass;
|
||||
}
|
||||
static bool classof(const AttributedStmt *) { return true; }
|
||||
};
|
||||
|
||||
|
||||
/// IfStmt - This represents an if/then/else.
|
||||
///
|
||||
class IfStmt : public Stmt {
|
||||
|
@ -79,6 +79,7 @@ namespace clang {
|
||||
class CXXRecordDecl;
|
||||
class EnumDecl;
|
||||
class FieldDecl;
|
||||
class FunctionDecl;
|
||||
class ObjCInterfaceDecl;
|
||||
class ObjCProtocolDecl;
|
||||
class ObjCMethodDecl;
|
||||
@ -2700,7 +2701,9 @@ class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode {
|
||||
ExtProtoInfo() :
|
||||
Variadic(false), HasTrailingReturn(false), TypeQuals(0),
|
||||
ExceptionSpecType(EST_None), RefQualifier(RQ_None),
|
||||
NumExceptions(0), Exceptions(0), NoexceptExpr(0), ConsumedArguments(0) {}
|
||||
NumExceptions(0), Exceptions(0), NoexceptExpr(0),
|
||||
ExceptionSpecDecl(0), ExceptionSpecTemplate(0),
|
||||
ConsumedArguments(0) {}
|
||||
|
||||
FunctionType::ExtInfo ExtInfo;
|
||||
bool Variadic : 1;
|
||||
@ -2711,6 +2714,8 @@ class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode {
|
||||
unsigned NumExceptions;
|
||||
const QualType *Exceptions;
|
||||
Expr *NoexceptExpr;
|
||||
FunctionDecl *ExceptionSpecDecl;
|
||||
FunctionDecl *ExceptionSpecTemplate;
|
||||
const bool *ConsumedArguments;
|
||||
};
|
||||
|
||||
@ -2756,6 +2761,11 @@ class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode {
|
||||
// NoexceptExpr - Instead of Exceptions, there may be a single Expr* pointing
|
||||
// to the expression in the noexcept() specifier.
|
||||
|
||||
// ExceptionSpecDecl, ExceptionSpecTemplate - Instead of Exceptions, there may
|
||||
// be a pair of FunctionDecl* pointing to the function which should be used to
|
||||
// instantiate this function type's exception specification, and the function
|
||||
// from which it should be instantiated.
|
||||
|
||||
// ConsumedArgs - A variable size array, following Exceptions
|
||||
// and of length NumArgs, holding flags indicating which arguments
|
||||
// are consumed. This only appears if HasAnyConsumedArgs is true.
|
||||
@ -2795,6 +2805,9 @@ class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode {
|
||||
EPI.Exceptions = exception_begin();
|
||||
} else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) {
|
||||
EPI.NoexceptExpr = getNoexceptExpr();
|
||||
} else if (EPI.ExceptionSpecType == EST_Uninstantiated) {
|
||||
EPI.ExceptionSpecDecl = getExceptionSpecDecl();
|
||||
EPI.ExceptionSpecTemplate = getExceptionSpecTemplate();
|
||||
}
|
||||
if (hasAnyConsumedArgs())
|
||||
EPI.ConsumedArguments = getConsumedArgsBuffer();
|
||||
@ -2838,9 +2851,26 @@ class FunctionProtoType : public FunctionType, public llvm::FoldingSetNode {
|
||||
// NoexceptExpr sits where the arguments end.
|
||||
return *reinterpret_cast<Expr *const *>(arg_type_end());
|
||||
}
|
||||
/// \brief If this function type has an uninstantiated exception
|
||||
/// specification, this is the function whose exception specification
|
||||
/// is represented by this type.
|
||||
FunctionDecl *getExceptionSpecDecl() const {
|
||||
if (getExceptionSpecType() != EST_Uninstantiated)
|
||||
return 0;
|
||||
return reinterpret_cast<FunctionDecl * const *>(arg_type_end())[0];
|
||||
}
|
||||
/// \brief If this function type has an uninstantiated exception
|
||||
/// specification, this is the function whose exception specification
|
||||
/// should be instantiated to find the exception specification for
|
||||
/// this type.
|
||||
FunctionDecl *getExceptionSpecTemplate() const {
|
||||
if (getExceptionSpecType() != EST_Uninstantiated)
|
||||
return 0;
|
||||
return reinterpret_cast<FunctionDecl * const *>(arg_type_end())[1];
|
||||
}
|
||||
bool isNothrow(ASTContext &Ctx) const {
|
||||
ExceptionSpecificationType EST = getExceptionSpecType();
|
||||
assert(EST != EST_Delayed);
|
||||
assert(EST != EST_Delayed && EST != EST_Uninstantiated);
|
||||
if (EST == EST_DynamicNone || EST == EST_BasicNoexcept)
|
||||
return true;
|
||||
if (EST != EST_ComputedNoexcept)
|
||||
|
@ -205,11 +205,11 @@ class VTableLayout {
|
||||
typedef llvm::DenseMap<BaseSubobject, uint64_t> AddressPointsMapTy;
|
||||
private:
|
||||
uint64_t NumVTableComponents;
|
||||
VTableComponent *VTableComponents;
|
||||
llvm::OwningArrayPtr<VTableComponent> VTableComponents;
|
||||
|
||||
/// VTableThunks - Contains thunks needed by vtables.
|
||||
uint64_t NumVTableThunks;
|
||||
VTableThunkTy *VTableThunks;
|
||||
llvm::OwningArrayPtr<VTableThunkTy> VTableThunks;
|
||||
|
||||
/// Address points - Address points for all vtables.
|
||||
AddressPointsMapTy AddressPoints;
|
||||
@ -227,11 +227,11 @@ class VTableLayout {
|
||||
}
|
||||
|
||||
vtable_component_iterator vtable_component_begin() const {
|
||||
return VTableComponents;
|
||||
return VTableComponents.get();
|
||||
}
|
||||
|
||||
vtable_component_iterator vtable_component_end() const {
|
||||
return VTableComponents+NumVTableComponents;
|
||||
return VTableComponents.get()+NumVTableComponents;
|
||||
}
|
||||
|
||||
uint64_t getNumVTableThunks() const {
|
||||
@ -239,11 +239,11 @@ class VTableLayout {
|
||||
}
|
||||
|
||||
vtable_thunk_iterator vtable_thunk_begin() const {
|
||||
return VTableThunks;
|
||||
return VTableThunks.get();
|
||||
}
|
||||
|
||||
vtable_thunk_iterator vtable_thunk_end() const {
|
||||
return VTableThunks+NumVTableThunks;
|
||||
return VTableThunks.get()+NumVTableThunks;
|
||||
}
|
||||
|
||||
uint64_t getAddressPoint(BaseSubobject Base) const {
|
||||
|
@ -129,7 +129,7 @@ class ProgramPoint {
|
||||
static bool classof(const ProgramPoint*) { return true; }
|
||||
|
||||
bool operator==(const ProgramPoint & RHS) const {
|
||||
return Data1 == Data1 &&
|
||||
return Data1 == RHS.Data1 &&
|
||||
Data2 == RHS.Data2 &&
|
||||
L == RHS.L &&
|
||||
Tag == RHS.Tag;
|
||||
|
@ -412,6 +412,9 @@ BUILTIN(__builtin_ia32_cvtps2pd256, "V4dV4f", "")
|
||||
BUILTIN(__builtin_ia32_cvttpd2dq256, "V4iV4d", "")
|
||||
BUILTIN(__builtin_ia32_cvtpd2dq256, "V4iV4d", "")
|
||||
BUILTIN(__builtin_ia32_cvttps2dq256, "V8iV8f", "")
|
||||
BUILTIN(__builtin_ia32_vperm2f128_pd256, "V4dV4dV4dIc", "")
|
||||
BUILTIN(__builtin_ia32_vperm2f128_ps256, "V8fV8fV8fIc", "")
|
||||
BUILTIN(__builtin_ia32_vperm2f128_si256, "V8iV8iV8iIc", "")
|
||||
BUILTIN(__builtin_ia32_vinsertf128_pd256, "V4dV4dV2dIc", "")
|
||||
BUILTIN(__builtin_ia32_vinsertf128_ps256, "V8fV8fV4fIc", "")
|
||||
BUILTIN(__builtin_ia32_vinsertf128_si256, "V8iV8iV4iIc", "")
|
||||
@ -560,9 +563,8 @@ BUILTIN(__builtin_ia32_pbroadcastw128, "V8sV8s", "")
|
||||
BUILTIN(__builtin_ia32_pbroadcastd128, "V4iV4i", "")
|
||||
BUILTIN(__builtin_ia32_pbroadcastq128, "V2LLiV2LLi", "")
|
||||
BUILTIN(__builtin_ia32_permvarsi256, "V8iV8iV8i", "")
|
||||
BUILTIN(__builtin_ia32_permdf256, "V4dV4dIc", "")
|
||||
BUILTIN(__builtin_ia32_permvarsf256, "V8fV8fV8f", "")
|
||||
BUILTIN(__builtin_ia32_permdi256, "V4LLiV4LLiIc", "")
|
||||
BUILTIN(__builtin_ia32_permti256, "V4LLiV4LLiV4LLiIc", "")
|
||||
BUILTIN(__builtin_ia32_extract128i256, "V2LLiV4LLiIc", "")
|
||||
BUILTIN(__builtin_ia32_insert128i256, "V4LLiV4LLiV2LLiIc", "")
|
||||
BUILTIN(__builtin_ia32_maskloadd256, "V8iV8iC*V8i", "")
|
||||
|
@ -151,9 +151,9 @@ ConversionResult ConvertUTF16toUTF32 (
|
||||
ConversionResult ConvertUTF32toUTF16 (
|
||||
const UTF32** sourceStart, const UTF32* sourceEnd,
|
||||
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
|
||||
#endif
|
||||
|
||||
Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd);
|
||||
#endif
|
||||
|
||||
Boolean isLegalUTF8String(const UTF8 *source, const UTF8 *sourceEnd);
|
||||
|
||||
|
@ -1,110 +0,0 @@
|
||||
//=== DelayedCleanupPool.h - Delayed Clean-up Pool Implementation *- C++ -*===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines a facility to delay calling cleanup methods until specific
|
||||
// points.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_BASIC_DELAYEDCLEANUPPOOL_H
|
||||
#define LLVM_CLANG_BASIC_DELAYEDCLEANUPPOOL_H
|
||||
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
/// \brief Gathers pairs of pointer-to-object/pointer-to-cleanup-function
|
||||
/// allowing the cleanup functions to get called (with the pointer as parameter)
|
||||
/// at specific points.
|
||||
///
|
||||
/// The use case is to simplify clean-up of certain resources that, while their
|
||||
/// lifetime is well-known and restricted, cleaning them up manually is easy to
|
||||
/// miss and cause a leak.
|
||||
///
|
||||
/// The same pointer can be added multiple times; its clean-up function will
|
||||
/// only be called once.
|
||||
class DelayedCleanupPool {
|
||||
public:
|
||||
typedef void (*CleanupFn)(void *ptr);
|
||||
|
||||
/// \brief Adds a pointer and its associated cleanup function to be called
|
||||
/// at a later point.
|
||||
///
|
||||
/// \returns false if the pointer is already added, true otherwise.
|
||||
bool delayCleanup(void *ptr, CleanupFn fn) {
|
||||
assert(ptr && "Expected valid pointer to object");
|
||||
assert(fn && "Expected valid pointer to function");
|
||||
|
||||
CleanupFn &mapFn = Ptrs[ptr];
|
||||
assert((!mapFn || mapFn == fn) &&
|
||||
"Adding a pointer with different cleanup function!");
|
||||
|
||||
if (!mapFn) {
|
||||
mapFn = fn;
|
||||
Cleanups.push_back(std::make_pair(ptr, fn));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool delayDelete(T *ptr) {
|
||||
return delayCleanup(ptr, cleanupWithDelete<T>);
|
||||
}
|
||||
|
||||
template <typename T, void (T::*Fn)()>
|
||||
bool delayMemberFunc(T *ptr) {
|
||||
return delayCleanup(ptr, cleanupWithMemberFunc<T, Fn>);
|
||||
}
|
||||
|
||||
void doCleanup() {
|
||||
for (SmallVector<std::pair<void *, CleanupFn>, 8>::reverse_iterator
|
||||
I = Cleanups.rbegin(), E = Cleanups.rend(); I != E; ++I)
|
||||
I->second(I->first);
|
||||
Cleanups.clear();
|
||||
Ptrs.clear();
|
||||
}
|
||||
|
||||
~DelayedCleanupPool() {
|
||||
doCleanup();
|
||||
}
|
||||
|
||||
private:
|
||||
llvm::DenseMap<void *, CleanupFn> Ptrs;
|
||||
SmallVector<std::pair<void *, CleanupFn>, 8> Cleanups;
|
||||
|
||||
template <typename T>
|
||||
static void cleanupWithDelete(void *ptr) {
|
||||
delete static_cast<T *>(ptr);
|
||||
}
|
||||
|
||||
template <typename T, void (T::*Fn)()>
|
||||
static void cleanupWithMemberFunc(void *ptr) {
|
||||
(static_cast<T *>(ptr)->*Fn)();
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief RAII object for triggering a cleanup of a DelayedCleanupPool.
|
||||
class DelayedCleanupPoint {
|
||||
DelayedCleanupPool &Pool;
|
||||
|
||||
public:
|
||||
DelayedCleanupPoint(DelayedCleanupPool &pool) : Pool(pool) { }
|
||||
|
||||
~DelayedCleanupPoint() {
|
||||
Pool.doCleanup();
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
@ -410,6 +410,8 @@ def ext_ellipsis_exception_spec : Extension<
|
||||
"exception specification of '...' is a Microsoft extension">;
|
||||
def err_dynamic_and_noexcept_specification : Error<
|
||||
"cannot have both throw() and noexcept() clause on the same function">;
|
||||
def err_except_spec_unparsed : Error<
|
||||
"unexpected end of exception specification">;
|
||||
def warn_cxx98_compat_noexcept_decl : Warning<
|
||||
"noexcept specifications are incompatible with C++98">,
|
||||
InGroup<CXX98Compat>, DefaultIgnore;
|
||||
|
@ -231,9 +231,13 @@ def err_using_decl_can_not_refer_to_namespace : Error<
|
||||
"using declaration can not refer to namespace">;
|
||||
def err_using_decl_constructor : Error<
|
||||
"using declaration can not refer to a constructor">;
|
||||
def warn_cxx98_compat_using_decl_constructor : Warning<
|
||||
"inherited constructors are incompatible with C++98">,
|
||||
InGroup<CXX98Compat>, DefaultIgnore;
|
||||
def err_using_decl_constructor_unsupported : Error<
|
||||
"inheriting constructors are not supported">;
|
||||
// FIXME: Replace the above error with this warning if support for
|
||||
// inheriting constructors is implemented.
|
||||
//def warn_cxx98_compat_using_decl_constructor : Warning<
|
||||
// "inheriting constructors are incompatible with C++98">,
|
||||
// InGroup<CXX98Compat>, DefaultIgnore;
|
||||
def err_using_decl_destructor : Error<
|
||||
"using declaration can not refer to a destructor">;
|
||||
def err_using_decl_template_id : Error<
|
||||
@ -1547,9 +1551,6 @@ def warn_objc_redundant_literal_use : Warning<
|
||||
"using %0 with a literal is redundant">, InGroup<ObjCRedundantLiteralUse>;
|
||||
}
|
||||
|
||||
def warn_bool_for_boolean_literal : Warning<
|
||||
"BOOL of type %0 is non-intergal and unsuitable for a "
|
||||
"boolean literal - ignored">, InGroup<DiagGroup<"numeric-literals">>;
|
||||
def err_only_annotate_after_access_spec : Error<
|
||||
"access specifier can only have annotation attributes">;
|
||||
def err_attribute_section_invalid_for_target : Error<
|
||||
@ -1563,6 +1564,9 @@ def warn_redeclaration_without_attribute_prev_attribute_ignored : Warning<
|
||||
def warn_attribute_ignored : Warning<"%0 attribute ignored">;
|
||||
def warn_unknown_attribute_ignored : Warning<
|
||||
"unknown attribute %0 ignored">, InGroup<UnknownAttributes>;
|
||||
def warn_attribute_invalid_on_stmt : Warning<
|
||||
"attribute %0 cannot be specified on a statement">,
|
||||
InGroup<IgnoredAttributes>;
|
||||
def warn_declspec_attribute_ignored : Warning<
|
||||
"attribute %0 is ignored, place it after \"%select{class|struct|union|enum}1\" to apply attribute to type declaration">, InGroup<IgnoredAttributes>;
|
||||
def warn_attribute_precede_definition : Warning<
|
||||
@ -2583,6 +2587,8 @@ def note_template_enum_def_here : Note<
|
||||
"in instantiation of enumeration %q0 requested here">;
|
||||
def note_template_type_alias_instantiation_here : Note<
|
||||
"in instantiation of template type alias %0 requested here">;
|
||||
def note_template_exception_spec_instantiation_here : Note<
|
||||
"in instantiation of exception specification for %0 requested here">;
|
||||
|
||||
def note_default_arg_instantiation_here : Note<
|
||||
"in instantiation of default argument for '%0' required here">;
|
||||
@ -3798,6 +3804,9 @@ def warn_null_in_comparison_operation : Warning<
|
||||
|
||||
def err_invalid_this_use : Error<
|
||||
"invalid use of 'this' outside of a non-static member function">;
|
||||
def err_this_static_member_func : Error<
|
||||
"'this' cannot be%select{| implicitly}0 used in a static member function "
|
||||
"declaration">;
|
||||
def err_invalid_member_use_in_static_method : Error<
|
||||
"invalid use of member %0 in static member function">;
|
||||
def err_invalid_qualified_function_type : Error<
|
||||
@ -3907,7 +3916,7 @@ def err_nosetter_property_incdec : Error<
|
||||
def err_nogetter_property_compound_assignment : Error<
|
||||
"a getter method is needed to perform a compound assignment on a property">;
|
||||
def err_nogetter_property_incdec : Error<
|
||||
"no getter method %1 for %select{increment|decrement} of property">;
|
||||
"no getter method %1 for %select{increment|decrement}0 of property">;
|
||||
def error_no_subobject_property_setting : Error<
|
||||
"expression is not assignable">;
|
||||
def err_qualified_objc_access : Error<
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
namespace clang {
|
||||
|
||||
/// \brief The various types of exception specifications that exist in C++0x.
|
||||
/// \brief The various types of exception specifications that exist in C++11.
|
||||
enum ExceptionSpecificationType {
|
||||
EST_None, ///< no exception specification
|
||||
EST_DynamicNone, ///< throw()
|
||||
@ -24,7 +24,8 @@ enum ExceptionSpecificationType {
|
||||
EST_MSAny, ///< Microsoft throw(...) extension
|
||||
EST_BasicNoexcept, ///< noexcept
|
||||
EST_ComputedNoexcept, ///< noexcept(expression)
|
||||
EST_Delayed ///< not known yet
|
||||
EST_Delayed, ///< not known yet
|
||||
EST_Uninstantiated ///< not instantiated yet
|
||||
};
|
||||
|
||||
inline bool isDynamicExceptionSpec(ExceptionSpecificationType ESpecType) {
|
||||
@ -35,6 +36,19 @@ inline bool isNoexceptExceptionSpec(ExceptionSpecificationType ESpecType) {
|
||||
return ESpecType == EST_BasicNoexcept || ESpecType == EST_ComputedNoexcept;
|
||||
}
|
||||
|
||||
/// \brief Possible results from evaluation of a noexcept expression.
|
||||
enum CanThrowResult {
|
||||
CT_Cannot,
|
||||
CT_Dependent,
|
||||
CT_Can
|
||||
};
|
||||
|
||||
inline CanThrowResult mergeCanThrow(CanThrowResult CT1, CanThrowResult CT2) {
|
||||
// CanThrowResult constants are ordered so that the maximum is the correct
|
||||
// merge result.
|
||||
return CT1 > CT2 ? CT1 : CT2;
|
||||
}
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_BASIC_EXCEPTIONSPECIFICATIONTYPE_H
|
||||
|
@ -132,7 +132,7 @@ class OnDiskChainedHashTableGenerator {
|
||||
class Bucket {
|
||||
public:
|
||||
io::Offset off;
|
||||
Item* head;
|
||||
Item* head;
|
||||
unsigned length;
|
||||
|
||||
Bucket() {}
|
||||
@ -201,6 +201,7 @@ class OnDiskChainedHashTableGenerator {
|
||||
|
||||
// Write out the number of items in the bucket.
|
||||
Emit16(out, B.length);
|
||||
assert(B.length != 0 && "Bucket has a head but zero length?");
|
||||
|
||||
// Write out the entries in the bucket.
|
||||
for (Item *I = B.head; I ; I = I->next) {
|
||||
@ -398,31 +399,30 @@ class OnDiskChainedHashTable {
|
||||
}
|
||||
key_iterator key_end() { return key_iterator(); }
|
||||
|
||||
/// \brief Iterates over all the entries in the table, returning
|
||||
/// a key/data pair.
|
||||
class item_iterator {
|
||||
/// \brief Iterates over all the entries in the table, returning the data.
|
||||
class data_iterator {
|
||||
const unsigned char* Ptr;
|
||||
unsigned NumItemsInBucketLeft;
|
||||
unsigned NumEntriesLeft;
|
||||
Info *InfoObj;
|
||||
public:
|
||||
typedef std::pair<external_key_type, data_type> value_type;
|
||||
typedef data_type value_type;
|
||||
|
||||
item_iterator(const unsigned char* const Ptr, unsigned NumEntries,
|
||||
data_iterator(const unsigned char* const Ptr, unsigned NumEntries,
|
||||
Info *InfoObj)
|
||||
: Ptr(Ptr), NumItemsInBucketLeft(0), NumEntriesLeft(NumEntries),
|
||||
InfoObj(InfoObj) { }
|
||||
item_iterator()
|
||||
data_iterator()
|
||||
: Ptr(0), NumItemsInBucketLeft(0), NumEntriesLeft(0), InfoObj(0) { }
|
||||
|
||||
bool operator==(const item_iterator& X) const {
|
||||
bool operator==(const data_iterator& X) const {
|
||||
return X.NumEntriesLeft == NumEntriesLeft;
|
||||
}
|
||||
bool operator!=(const item_iterator& X) const {
|
||||
bool operator!=(const data_iterator& X) const {
|
||||
return X.NumEntriesLeft != NumEntriesLeft;
|
||||
}
|
||||
|
||||
item_iterator& operator++() { // Preincrement
|
||||
data_iterator& operator++() { // Preincrement
|
||||
if (!NumItemsInBucketLeft) {
|
||||
// 'Items' starts with a 16-bit unsigned integer representing the
|
||||
// number of items in this bucket.
|
||||
@ -438,8 +438,8 @@ class OnDiskChainedHashTable {
|
||||
--NumEntriesLeft;
|
||||
return *this;
|
||||
}
|
||||
item_iterator operator++(int) { // Postincrement
|
||||
item_iterator tmp = *this; ++*this; return tmp;
|
||||
data_iterator operator++(int) { // Postincrement
|
||||
data_iterator tmp = *this; ++*this; return tmp;
|
||||
}
|
||||
|
||||
value_type operator*() const {
|
||||
@ -454,15 +454,14 @@ class OnDiskChainedHashTable {
|
||||
// Read the key.
|
||||
const internal_key_type& Key =
|
||||
InfoObj->ReadKey(LocalPtr, L.first);
|
||||
return std::make_pair(InfoObj->GetExternalKey(Key),
|
||||
InfoObj->ReadData(Key, LocalPtr + L.first, L.second));
|
||||
return InfoObj->ReadData(Key, LocalPtr + L.first, L.second);
|
||||
}
|
||||
};
|
||||
|
||||
item_iterator item_begin() {
|
||||
return item_iterator(Base + 4, getNumEntries(), &InfoObj);
|
||||
data_iterator data_begin() {
|
||||
return data_iterator(Base + 4, getNumEntries(), &InfoObj);
|
||||
}
|
||||
item_iterator item_end() { return item_iterator(); }
|
||||
data_iterator data_end() { return data_iterator(); }
|
||||
|
||||
Info &getInfoObj() { return InfoObj; }
|
||||
|
||||
|
@ -12,6 +12,7 @@ class DStmt<Stmt base, bit abstract = 0> : Stmt<abstract> {
|
||||
def NullStmt : Stmt;
|
||||
def CompoundStmt : Stmt;
|
||||
def LabelStmt : Stmt;
|
||||
def AttributedStmt : Stmt;
|
||||
def IfStmt : Stmt;
|
||||
def SwitchStmt : Stmt;
|
||||
def WhileStmt : Stmt;
|
||||
|
@ -132,6 +132,11 @@ class TargetInfo : public RefCountedBase<TargetInfo> {
|
||||
IntType SizeType, IntMaxType, UIntMaxType, PtrDiffType, IntPtrType, WCharType,
|
||||
WIntType, Char16Type, Char32Type, Int64Type, SigAtomicType;
|
||||
|
||||
/// Flag whether the Objective-C built-in boolean type should be signed char.
|
||||
/// Otherwise, when this flag is not set, the normal built-in boolean type is
|
||||
/// used.
|
||||
unsigned UseSignedCharForObjCBool : 1;
|
||||
|
||||
/// Control whether the alignment of bit-field types is respected when laying
|
||||
/// out structures. If true, then the alignment of the bit-field type will be
|
||||
/// used to (a) impact the alignment of the containing structure, and (b)
|
||||
@ -299,6 +304,16 @@ class TargetInfo : public RefCountedBase<TargetInfo> {
|
||||
return MCountName;
|
||||
}
|
||||
|
||||
/// useSignedCharForObjCBool - Check if the Objective-C built-in boolean
|
||||
/// type should be signed char. Otherwise, if this returns false, the
|
||||
/// normal built-in boolean type should also be used for Objective-C.
|
||||
bool useSignedCharForObjCBool() const {
|
||||
return UseSignedCharForObjCBool;
|
||||
}
|
||||
void noSignedCharForObjCBool() {
|
||||
UseSignedCharForObjCBool = false;
|
||||
}
|
||||
|
||||
/// useBitFieldTypeAlignment() - Check whether the alignment of bit-field
|
||||
/// types is respected when laying out structures.
|
||||
bool useBitFieldTypeAlignment() const {
|
||||
|
@ -105,6 +105,7 @@ TOK(eod) // End of preprocessing directive (end of line inside a
|
||||
// directive).
|
||||
TOK(code_completion) // Code completion marker
|
||||
TOK(cxx_defaultarg_end) // C++ default argument end marker
|
||||
TOK(cxx_exceptspec_end) // C++ exception-specification end marker
|
||||
|
||||
// C99 6.4.9: Comments.
|
||||
TOK(comment) // Comment (only in -E -C[C] mode)
|
||||
|
@ -4,8 +4,11 @@
|
||||
/* Relative directory for resource files */
|
||||
#define CLANG_RESOURCE_DIR "${CLANG_RESOURCE_DIR}"
|
||||
|
||||
/* Directory where gcc is installed. */
|
||||
#define GCC_INSTALL_PREFIX "${GCC_INSTALL_PREFIX}"
|
||||
|
||||
/* Directories clang will search for headers */
|
||||
#define C_INCLUDE_DIRS "${C_INCLUDE_DIRS}"
|
||||
|
||||
/* Default <path> to all compiler invocations for --sysroot=<path>. */
|
||||
#define DEFAULT_SYSROOT "${DEFAULT_SYSROOT}"
|
||||
|
||||
/* Directory where gcc is installed. */
|
||||
#define GCC_INSTALL_PREFIX "${GCC_INSTALL_PREFIX}"
|
||||
|
@ -9,13 +9,16 @@
|
||||
/* Relative directory for resource files */
|
||||
#undef CLANG_RESOURCE_DIR
|
||||
|
||||
/* Directory where gcc is installed. */
|
||||
#undef GCC_INSTALL_PREFIX
|
||||
|
||||
/* Directories clang will search for headers */
|
||||
#undef C_INCLUDE_DIRS
|
||||
|
||||
/* Linker version detected at compile time. */
|
||||
#undef HOST_LINK_VERSION
|
||||
|
||||
/* Default <path> to all compiler invocations for --sysroot=<path>. */
|
||||
#undef DEFAULT_SYSROOT
|
||||
|
||||
/* Directory where gcc is installed. */
|
||||
#undef GCC_INSTALL_PREFIX
|
||||
|
||||
#endif
|
||||
|
@ -428,9 +428,6 @@ def ast_view : Flag<"-ast-view">,
|
||||
HelpText<"Build ASTs and view them with GraphViz">;
|
||||
def print_decl_contexts : Flag<"-print-decl-contexts">,
|
||||
HelpText<"Print DeclContexts and their Decls">;
|
||||
def pubnames_dump : Flag<"-pubnames-dump">,
|
||||
HelpText<"Print all of the public (global) names in the source, e.g., the "
|
||||
"names of all global declarations and macros">;
|
||||
def emit_module : Flag<"-emit-module">,
|
||||
HelpText<"Generate pre-compiled module file from a module map">;
|
||||
def emit_pth : Flag<"-emit-pth">,
|
||||
|
@ -92,6 +92,9 @@ class Compilation {
|
||||
return FailureResultFiles;
|
||||
}
|
||||
|
||||
/// Returns the sysroot path.
|
||||
StringRef getSysRoot() const;
|
||||
|
||||
/// getArgsForToolChain - Return the derived argument list for the
|
||||
/// tool chain \arg TC (or the default tool chain, if TC is not
|
||||
/// specified).
|
||||
|
@ -14,7 +14,6 @@
|
||||
#ifndef LLVM_CLANG_FRONTEND_ASTUNIT_H
|
||||
#define LLVM_CLANG_FRONTEND_ASTUNIT_H
|
||||
|
||||
#include "clang/Index/ASTLocation.h"
|
||||
#include "clang/Serialization/ASTBitCodes.h"
|
||||
#include "clang/Sema/Sema.h"
|
||||
#include "clang/Sema/CodeCompleteConsumer.h"
|
||||
@ -57,8 +56,6 @@ class SourceManager;
|
||||
class TargetInfo;
|
||||
class ASTFrontendAction;
|
||||
|
||||
using namespace idx;
|
||||
|
||||
/// \brief Utility class for loading a ASTContext from an AST file.
|
||||
///
|
||||
class ASTUnit : public ModuleLoader {
|
||||
@ -134,9 +131,6 @@ class ASTUnit : public ModuleLoader {
|
||||
/// The name of the original source file used to generate this ASTUnit.
|
||||
std::string OriginalSourceFile;
|
||||
|
||||
// Critical optimization when using clang_getCursor().
|
||||
ASTLocation LastLoc;
|
||||
|
||||
/// \brief The set of diagnostics produced when creating the preamble.
|
||||
SmallVector<StoredDiagnostic, 4> PreambleDiagnostics;
|
||||
|
||||
@ -474,10 +468,6 @@ class ASTUnit : public ModuleLoader {
|
||||
bool getOwnsRemappedFileBuffers() const { return OwnsRemappedFileBuffers; }
|
||||
void setOwnsRemappedFileBuffers(bool val) { OwnsRemappedFileBuffers = val; }
|
||||
|
||||
void setLastASTLocation(ASTLocation ALoc) { LastLoc = ALoc; }
|
||||
ASTLocation getLastASTLocation() const { return LastLoc; }
|
||||
|
||||
|
||||
StringRef getMainFileName() const;
|
||||
|
||||
typedef std::vector<Decl *>::iterator top_level_iterator;
|
||||
|
@ -173,15 +173,6 @@ class PrintPreambleAction : public FrontendAction {
|
||||
virtual bool usesPreprocessorOnly() const { return true; }
|
||||
};
|
||||
|
||||
class PubnamesDumpAction : public ASTFrontendAction {
|
||||
protected:
|
||||
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
|
||||
StringRef InFile);
|
||||
|
||||
public:
|
||||
virtual bool hasCodeCompletionSupport() const { return false; }
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Preprocessor Actions
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -42,7 +42,6 @@ namespace frontend {
|
||||
PrintDeclContext, ///< Print DeclContext and their Decls.
|
||||
PrintPreamble, ///< Print the "preamble" of the input file
|
||||
PrintPreprocessedInput, ///< -E mode.
|
||||
PubnamesDump, ///< Print all of the "public" names in the source.
|
||||
RewriteMacros, ///< Expand macros but not #includes.
|
||||
RewriteObjC, ///< ObjC->C Rewriter.
|
||||
RewriteTest, ///< Rewriter playground
|
||||
|
@ -18,6 +18,8 @@
|
||||
|
||||
#include "clang/Frontend/DiagnosticRenderer.h"
|
||||
|
||||
struct SourceColumnMap;
|
||||
|
||||
namespace clang {
|
||||
|
||||
/// \brief Class to encapsulate the logic for formatting and printing a textual
|
||||
@ -103,15 +105,16 @@ class TextDiagnostic : public DiagnosticRenderer {
|
||||
SmallVectorImpl<CharSourceRange>& Ranges,
|
||||
ArrayRef<FixItHint> Hints);
|
||||
|
||||
void emitSnippet(StringRef SourceLine);
|
||||
|
||||
void highlightRange(const CharSourceRange &R,
|
||||
unsigned LineNo, FileID FID,
|
||||
const std::string &SourceLine,
|
||||
const SourceColumnMap &map,
|
||||
std::string &CaretLine);
|
||||
|
||||
std::string buildFixItInsertionLine(unsigned LineNo,
|
||||
const char *LineStart,
|
||||
const char *LineEnd,
|
||||
const SourceColumnMap &map,
|
||||
ArrayRef<FixItHint> Hints);
|
||||
void expandTabs(std::string &SourceLine, std::string &CaretLine);
|
||||
void emitParseableFixits(ArrayRef<FixItHint> Hints);
|
||||
};
|
||||
|
||||
|
@ -1,173 +0,0 @@
|
||||
//===--- ASTLocation.h - A <Decl, Stmt> pair --------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// ASTLocation is Decl or a Stmt and its immediate Decl parent.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_INDEX_ASTLOCATION_H
|
||||
#define LLVM_CLANG_INDEX_ASTLOCATION_H
|
||||
|
||||
#include "clang/AST/TypeLoc.h"
|
||||
#include "llvm/ADT/PointerIntPair.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
|
||||
namespace clang {
|
||||
class Decl;
|
||||
class Stmt;
|
||||
class NamedDecl;
|
||||
|
||||
namespace idx {
|
||||
class TranslationUnit;
|
||||
|
||||
/// \brief Represents a Decl or a Stmt and its immediate Decl parent. It's
|
||||
/// immutable.
|
||||
///
|
||||
/// ASTLocation is intended to be used as a "pointer" into the AST. It is either
|
||||
/// just a Decl, or a Stmt and its Decl parent. Since a single Stmt is devoid
|
||||
/// of context, its parent Decl provides all the additional missing information
|
||||
/// like the declaration context, ASTContext, etc.
|
||||
///
|
||||
class ASTLocation {
|
||||
public:
|
||||
enum NodeKind {
|
||||
N_Decl, N_NamedRef, N_Stmt, N_Type
|
||||
};
|
||||
|
||||
struct NamedRef {
|
||||
NamedDecl *ND;
|
||||
SourceLocation Loc;
|
||||
|
||||
NamedRef() : ND(0) { }
|
||||
NamedRef(NamedDecl *nd, SourceLocation loc) : ND(nd), Loc(loc) { }
|
||||
};
|
||||
|
||||
private:
|
||||
llvm::PointerIntPair<Decl *, 2, NodeKind> ParentDecl;
|
||||
|
||||
union {
|
||||
Decl *D;
|
||||
Stmt *Stm;
|
||||
struct {
|
||||
NamedDecl *ND;
|
||||
unsigned RawLoc;
|
||||
} NDRef;
|
||||
struct {
|
||||
void *TyPtr;
|
||||
void *Data;
|
||||
} Ty;
|
||||
};
|
||||
|
||||
public:
|
||||
ASTLocation() { }
|
||||
|
||||
explicit ASTLocation(const Decl *d)
|
||||
: ParentDecl(const_cast<Decl*>(d), N_Decl), D(const_cast<Decl*>(d)) { }
|
||||
|
||||
ASTLocation(const Decl *parentDecl, const Stmt *stm)
|
||||
: ParentDecl(const_cast<Decl*>(parentDecl), N_Stmt),
|
||||
Stm(const_cast<Stmt*>(stm)) {
|
||||
if (!stm) ParentDecl.setPointer(0);
|
||||
}
|
||||
|
||||
ASTLocation(const Decl *parentDecl, NamedDecl *ndRef, SourceLocation loc)
|
||||
: ParentDecl(const_cast<Decl*>(parentDecl), N_NamedRef) {
|
||||
if (ndRef) {
|
||||
NDRef.ND = ndRef;
|
||||
NDRef.RawLoc = loc.getRawEncoding();
|
||||
} else
|
||||
ParentDecl.setPointer(0);
|
||||
}
|
||||
|
||||
ASTLocation(const Decl *parentDecl, TypeLoc tyLoc)
|
||||
: ParentDecl(const_cast<Decl*>(parentDecl), N_Type) {
|
||||
if (tyLoc) {
|
||||
Ty.TyPtr = tyLoc.getType().getAsOpaquePtr();
|
||||
Ty.Data = tyLoc.getOpaqueData();
|
||||
} else
|
||||
ParentDecl.setPointer(0);
|
||||
}
|
||||
|
||||
bool isValid() const { return ParentDecl.getPointer() != 0; }
|
||||
bool isInvalid() const { return !isValid(); }
|
||||
|
||||
NodeKind getKind() const {
|
||||
assert(isValid());
|
||||
return (NodeKind)ParentDecl.getInt();
|
||||
}
|
||||
|
||||
Decl *getParentDecl() const { return ParentDecl.getPointer(); }
|
||||
|
||||
Decl *AsDecl() const {
|
||||
assert(getKind() == N_Decl);
|
||||
return D;
|
||||
}
|
||||
Stmt *AsStmt() const {
|
||||
assert(getKind() == N_Stmt);
|
||||
return Stm;
|
||||
}
|
||||
NamedRef AsNamedRef() const {
|
||||
assert(getKind() == N_NamedRef);
|
||||
return NamedRef(NDRef.ND, SourceLocation::getFromRawEncoding(NDRef.RawLoc));
|
||||
}
|
||||
TypeLoc AsTypeLoc() const {
|
||||
assert(getKind() == N_Type);
|
||||
return TypeLoc(QualType::getFromOpaquePtr(Ty.TyPtr), Ty.Data);
|
||||
}
|
||||
|
||||
Decl *dyn_AsDecl() const { return isValid() && getKind() == N_Decl ? D : 0; }
|
||||
Stmt *dyn_AsStmt() const {
|
||||
return isValid() && getKind() == N_Stmt ? Stm : 0;
|
||||
}
|
||||
NamedRef dyn_AsNamedRef() const {
|
||||
return getKind() == N_Type ? AsNamedRef() : NamedRef();
|
||||
}
|
||||
TypeLoc dyn_AsTypeLoc() const {
|
||||
return getKind() == N_Type ? AsTypeLoc() : TypeLoc();
|
||||
}
|
||||
|
||||
bool isDecl() const { return isValid() && getKind() == N_Decl; }
|
||||
bool isStmt() const { return isValid() && getKind() == N_Stmt; }
|
||||
bool isNamedRef() const { return isValid() && getKind() == N_NamedRef; }
|
||||
bool isType() const { return isValid() && getKind() == N_Type; }
|
||||
|
||||
/// \brief Returns the declaration that this ASTLocation references.
|
||||
///
|
||||
/// If this points to a Decl, that Decl is returned.
|
||||
/// If this points to an Expr that references a Decl, that Decl is returned,
|
||||
/// otherwise it returns NULL.
|
||||
Decl *getReferencedDecl();
|
||||
const Decl *getReferencedDecl() const {
|
||||
return const_cast<ASTLocation*>(this)->getReferencedDecl();
|
||||
}
|
||||
|
||||
SourceRange getSourceRange() const LLVM_READONLY;
|
||||
|
||||
void print(raw_ostream &OS) const;
|
||||
};
|
||||
|
||||
/// \brief Like ASTLocation but also contains the TranslationUnit that the
|
||||
/// ASTLocation originated from.
|
||||
class TULocation : public ASTLocation {
|
||||
TranslationUnit *TU;
|
||||
|
||||
public:
|
||||
TULocation(TranslationUnit *tu, ASTLocation astLoc)
|
||||
: ASTLocation(astLoc), TU(tu) {
|
||||
assert(tu && "Passed null translation unit");
|
||||
}
|
||||
|
||||
TranslationUnit *getTU() const { return TU; }
|
||||
};
|
||||
|
||||
} // namespace idx
|
||||
|
||||
} // namespace clang
|
||||
|
||||
#endif
|
@ -1,56 +0,0 @@
|
||||
//===--- Analyzer.h - Analysis for indexing information ---------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file declares the Analyzer interface.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_INDEX_ANALYZER_H
|
||||
#define LLVM_CLANG_INDEX_ANALYZER_H
|
||||
|
||||
namespace clang {
|
||||
class Decl;
|
||||
class ObjCMessageExpr;
|
||||
|
||||
namespace idx {
|
||||
class Program;
|
||||
class IndexProvider;
|
||||
class TULocationHandler;
|
||||
|
||||
/// \brief Provides indexing information, like finding all references of an
|
||||
/// Entity across translation units.
|
||||
class Analyzer {
|
||||
Program &Prog;
|
||||
IndexProvider &Idxer;
|
||||
|
||||
Analyzer(const Analyzer&); // do not implement
|
||||
Analyzer &operator=(const Analyzer &); // do not implement
|
||||
|
||||
public:
|
||||
explicit Analyzer(Program &prog, IndexProvider &idxer)
|
||||
: Prog(prog), Idxer(idxer) { }
|
||||
|
||||
/// \brief Find all TULocations for declarations of the given Decl and pass
|
||||
/// them to Handler.
|
||||
void FindDeclarations(Decl *D, TULocationHandler &Handler);
|
||||
|
||||
/// \brief Find all TULocations for references of the given Decl and pass
|
||||
/// them to Handler.
|
||||
void FindReferences(Decl *D, TULocationHandler &Handler);
|
||||
|
||||
/// \brief Find methods that may respond to the given message and pass them
|
||||
/// to Handler.
|
||||
void FindObjCMethods(ObjCMessageExpr *MsgE, TULocationHandler &Handler);
|
||||
};
|
||||
|
||||
} // namespace idx
|
||||
|
||||
} // namespace clang
|
||||
|
||||
#endif
|
@ -1,50 +0,0 @@
|
||||
//===--- DeclReferenceMap.h - Map Decls to their references -----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// DeclReferenceMap creates a mapping from Decls to the ASTLocations that
|
||||
// reference them.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_INDEX_DECLREFERENCEMAP_H
|
||||
#define LLVM_CLANG_INDEX_DECLREFERENCEMAP_H
|
||||
|
||||
#include "clang/Index/ASTLocation.h"
|
||||
#include "clang/Index/STLExtras.h"
|
||||
#include <map>
|
||||
|
||||
namespace clang {
|
||||
class ASTContext;
|
||||
class NamedDecl;
|
||||
|
||||
namespace idx {
|
||||
|
||||
/// \brief Maps NamedDecls with the ASTLocations that reference them.
|
||||
///
|
||||
/// References are mapped and retrieved using the canonical decls.
|
||||
class DeclReferenceMap {
|
||||
public:
|
||||
explicit DeclReferenceMap(ASTContext &Ctx);
|
||||
|
||||
typedef std::multimap<NamedDecl*, ASTLocation> MapTy;
|
||||
typedef pair_value_iterator<MapTy::iterator> astlocation_iterator;
|
||||
|
||||
astlocation_iterator refs_begin(NamedDecl *D) const;
|
||||
astlocation_iterator refs_end(NamedDecl *D) const;
|
||||
bool refs_empty(NamedDecl *D) const;
|
||||
|
||||
private:
|
||||
mutable MapTy Map;
|
||||
};
|
||||
|
||||
} // end idx namespace
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
@ -1,149 +0,0 @@
|
||||
//===--- Entity.h - Cross-translation-unit "token" for decls ----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Entity is a ASTContext-independent way to refer to declarations that are
|
||||
// visible across translation units.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_INDEX_ENTITY_H
|
||||
#define LLVM_CLANG_INDEX_ENTITY_H
|
||||
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "llvm/ADT/PointerUnion.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include <string>
|
||||
|
||||
namespace clang {
|
||||
class ASTContext;
|
||||
class Decl;
|
||||
|
||||
namespace idx {
|
||||
class Program;
|
||||
class EntityImpl;
|
||||
|
||||
/// \brief A ASTContext-independent way to refer to declarations.
|
||||
///
|
||||
/// Entity is basically the link for declarations that are semantically the same
|
||||
/// in multiple ASTContexts. A client will convert a Decl into an Entity and
|
||||
/// later use that Entity to find the "same" Decl into another ASTContext.
|
||||
/// Declarations that are semantically the same and visible across translation
|
||||
/// units will be associated with the same Entity.
|
||||
///
|
||||
/// An Entity may also refer to declarations that cannot be visible across
|
||||
/// translation units, e.g. static functions with the same name in multiple
|
||||
/// translation units will be associated with different Entities.
|
||||
///
|
||||
/// Entities can be checked for equality but note that the same Program object
|
||||
/// should be used when getting Entities.
|
||||
///
|
||||
class Entity {
|
||||
/// \brief Stores the Decl directly if it is not visible outside of its own
|
||||
/// translation unit, otherwise it stores the associated EntityImpl.
|
||||
llvm::PointerUnion<Decl *, EntityImpl *> Val;
|
||||
|
||||
explicit Entity(Decl *D);
|
||||
explicit Entity(EntityImpl *impl) : Val(impl) { }
|
||||
friend class EntityGetter;
|
||||
|
||||
public:
|
||||
Entity() { }
|
||||
|
||||
/// \brief Find the Decl that can be referred to by this entity.
|
||||
Decl *getDecl(ASTContext &AST) const;
|
||||
|
||||
/// \brief If this Entity represents a declaration that is internal to its
|
||||
/// translation unit, getInternalDecl() returns it.
|
||||
Decl *getInternalDecl() const {
|
||||
assert(isInternalToTU() && "This Entity is not internal!");
|
||||
return Val.get<Decl *>();
|
||||
}
|
||||
|
||||
/// \brief Get a printable name for debugging purpose.
|
||||
std::string getPrintableName() const;
|
||||
|
||||
/// \brief Get an Entity associated with the given Decl.
|
||||
/// \returns invalid Entity if an Entity cannot refer to this Decl.
|
||||
static Entity get(Decl *D, Program &Prog);
|
||||
|
||||
/// \brief Get an Entity associated with a name in the global namespace.
|
||||
static Entity get(StringRef Name, Program &Prog);
|
||||
|
||||
/// \brief true if the Entity is not visible outside the trasnlation unit.
|
||||
bool isInternalToTU() const {
|
||||
assert(isValid() && "This Entity is not valid!");
|
||||
return Val.is<Decl *>();
|
||||
}
|
||||
|
||||
bool isValid() const { return !Val.isNull(); }
|
||||
bool isInvalid() const { return !isValid(); }
|
||||
|
||||
void *getAsOpaquePtr() const { return Val.getOpaqueValue(); }
|
||||
static Entity getFromOpaquePtr(void *Ptr) {
|
||||
Entity Ent;
|
||||
Ent.Val = llvm::PointerUnion<Decl *, EntityImpl *>::getFromOpaqueValue(Ptr);
|
||||
return Ent;
|
||||
}
|
||||
|
||||
friend bool operator==(const Entity &LHS, const Entity &RHS) {
|
||||
return LHS.getAsOpaquePtr() == RHS.getAsOpaquePtr();
|
||||
}
|
||||
|
||||
// For use in a std::map.
|
||||
friend bool operator < (const Entity &LHS, const Entity &RHS) {
|
||||
return LHS.getAsOpaquePtr() < RHS.getAsOpaquePtr();
|
||||
}
|
||||
|
||||
// For use in DenseMap/DenseSet.
|
||||
static Entity getEmptyMarker() {
|
||||
Entity Ent;
|
||||
Ent.Val =
|
||||
llvm::PointerUnion<Decl *, EntityImpl *>::getFromOpaqueValue((void*)-1);
|
||||
return Ent;
|
||||
}
|
||||
static Entity getTombstoneMarker() {
|
||||
Entity Ent;
|
||||
Ent.Val =
|
||||
llvm::PointerUnion<Decl *, EntityImpl *>::getFromOpaqueValue((void*)-2);
|
||||
return Ent;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace idx
|
||||
|
||||
} // namespace clang
|
||||
|
||||
namespace llvm {
|
||||
/// Define DenseMapInfo so that Entities can be used as keys in DenseMap and
|
||||
/// DenseSets.
|
||||
template<>
|
||||
struct DenseMapInfo<clang::idx::Entity> {
|
||||
static inline clang::idx::Entity getEmptyKey() {
|
||||
return clang::idx::Entity::getEmptyMarker();
|
||||
}
|
||||
|
||||
static inline clang::idx::Entity getTombstoneKey() {
|
||||
return clang::idx::Entity::getTombstoneMarker();
|
||||
}
|
||||
|
||||
static unsigned getHashValue(clang::idx::Entity);
|
||||
|
||||
static inline bool
|
||||
isEqual(clang::idx::Entity LHS, clang::idx::Entity RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct isPodLike<clang::idx::Entity> { static const bool value = true; };
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
@ -1,149 +0,0 @@
|
||||
//== GlobalCallGraph.h - Call graph building --------------------*- C++ -*--==//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defined the CallGraph and CallGraphNode classes.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_INDEX_CALLGRAPH
|
||||
#define LLVM_CLANG_INDEX_CALLGRAPH
|
||||
|
||||
#include "clang/Index/ASTLocation.h"
|
||||
#include "clang/Index/Entity.h"
|
||||
#include "clang/Index/Program.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/GraphTraits.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
using namespace clang;
|
||||
|
||||
namespace clang {
|
||||
namespace idx {
|
||||
|
||||
class CallGraphNode {
|
||||
Entity F;
|
||||
typedef std::pair<ASTLocation, CallGraphNode*> CallRecord;
|
||||
std::vector<CallRecord> CalledFunctions;
|
||||
|
||||
public:
|
||||
CallGraphNode(Entity f) : F(f) {}
|
||||
|
||||
typedef std::vector<CallRecord>::iterator iterator;
|
||||
typedef std::vector<CallRecord>::const_iterator const_iterator;
|
||||
|
||||
iterator begin() { return CalledFunctions.begin(); }
|
||||
iterator end() { return CalledFunctions.end(); }
|
||||
const_iterator begin() const { return CalledFunctions.begin(); }
|
||||
const_iterator end() const { return CalledFunctions.end(); }
|
||||
|
||||
void addCallee(ASTLocation L, CallGraphNode *Node) {
|
||||
CalledFunctions.push_back(std::make_pair(L, Node));
|
||||
}
|
||||
|
||||
bool hasCallee() const { return begin() != end(); }
|
||||
|
||||
std::string getName() const { return F.getPrintableName(); }
|
||||
|
||||
Decl *getDecl(ASTContext &Ctx) const { return F.getDecl(Ctx); }
|
||||
};
|
||||
|
||||
class CallGraph {
|
||||
/// Program manages all Entities.
|
||||
Program &Prog;
|
||||
|
||||
typedef std::map<Entity, CallGraphNode *> FunctionMapTy;
|
||||
|
||||
/// FunctionMap owns all CallGraphNodes.
|
||||
FunctionMapTy FunctionMap;
|
||||
|
||||
/// CallerCtx maps a caller to its ASTContext.
|
||||
llvm::DenseMap<CallGraphNode *, ASTContext *> CallerCtx;
|
||||
|
||||
/// Root node is the 'main' function or 0.
|
||||
CallGraphNode *Root;
|
||||
|
||||
/// ExternalCallingNode has edges to all external functions.
|
||||
CallGraphNode *ExternalCallingNode;
|
||||
|
||||
public:
|
||||
CallGraph(Program &P);
|
||||
~CallGraph();
|
||||
|
||||
typedef FunctionMapTy::iterator iterator;
|
||||
typedef FunctionMapTy::const_iterator const_iterator;
|
||||
|
||||
iterator begin() { return FunctionMap.begin(); }
|
||||
iterator end() { return FunctionMap.end(); }
|
||||
const_iterator begin() const { return FunctionMap.begin(); }
|
||||
const_iterator end() const { return FunctionMap.end(); }
|
||||
|
||||
CallGraphNode *getRoot() { return Root; }
|
||||
|
||||
CallGraphNode *getExternalCallingNode() { return ExternalCallingNode; }
|
||||
|
||||
void addTU(ASTContext &AST);
|
||||
|
||||
Program &getProgram() { return Prog; }
|
||||
|
||||
CallGraphNode *getOrInsertFunction(idx::Entity F);
|
||||
|
||||
Decl *getDecl(CallGraphNode *Node);
|
||||
|
||||
void print(raw_ostream &os);
|
||||
void dump();
|
||||
|
||||
void ViewCallGraph() const;
|
||||
};
|
||||
|
||||
}} // end clang idx namespace
|
||||
|
||||
namespace llvm {
|
||||
|
||||
template <> struct GraphTraits<clang::idx::CallGraph> {
|
||||
typedef clang::idx::CallGraph GraphType;
|
||||
typedef clang::idx::CallGraphNode NodeType;
|
||||
|
||||
typedef std::pair<clang::idx::ASTLocation, NodeType*> CGNPairTy;
|
||||
typedef std::pointer_to_unary_function<CGNPairTy, NodeType*> CGNDerefFun;
|
||||
|
||||
typedef mapped_iterator<NodeType::iterator, CGNDerefFun> ChildIteratorType;
|
||||
|
||||
static NodeType *getEntryNode(GraphType *CG) {
|
||||
return CG->getExternalCallingNode();
|
||||
}
|
||||
|
||||
static ChildIteratorType child_begin(NodeType *N) {
|
||||
return map_iterator(N->begin(), CGNDerefFun(CGNDeref));
|
||||
}
|
||||
static ChildIteratorType child_end(NodeType *N) {
|
||||
return map_iterator(N->end(), CGNDerefFun(CGNDeref));
|
||||
}
|
||||
|
||||
typedef std::pair<clang::idx::Entity, NodeType*> PairTy;
|
||||
typedef std::pointer_to_unary_function<PairTy, NodeType*> DerefFun;
|
||||
|
||||
typedef mapped_iterator<GraphType::const_iterator, DerefFun> nodes_iterator;
|
||||
|
||||
static nodes_iterator nodes_begin(const GraphType &CG) {
|
||||
return map_iterator(CG.begin(), DerefFun(CGDeref));
|
||||
}
|
||||
static nodes_iterator nodes_end(const GraphType &CG) {
|
||||
return map_iterator(CG.end(), DerefFun(CGDeref));
|
||||
}
|
||||
|
||||
static NodeType *CGNDeref(CGNPairTy P) { return P.second; }
|
||||
|
||||
static NodeType *CGDeref(PairTy P) { return P.second; }
|
||||
};
|
||||
|
||||
} // end llvm namespace
|
||||
|
||||
#endif
|
@ -1,100 +0,0 @@
|
||||
//===--- GlobalSelector.h - Cross-translation-unit "token" for selectors --===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// GlobalSelector is a ASTContext-independent way to refer to selectors.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_INDEX_GLOBALSELECTOR_H
|
||||
#define LLVM_CLANG_INDEX_GLOBALSELECTOR_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include <string>
|
||||
|
||||
namespace clang {
|
||||
class ASTContext;
|
||||
class Selector;
|
||||
|
||||
namespace idx {
|
||||
class Program;
|
||||
|
||||
/// \brief A ASTContext-independent way to refer to selectors.
|
||||
class GlobalSelector {
|
||||
void *Val;
|
||||
|
||||
explicit GlobalSelector(void *val) : Val(val) { }
|
||||
|
||||
public:
|
||||
GlobalSelector() : Val(0) { }
|
||||
|
||||
/// \brief Get the ASTContext-specific selector.
|
||||
Selector getSelector(ASTContext &AST) const;
|
||||
|
||||
bool isValid() const { return Val != 0; }
|
||||
bool isInvalid() const { return !isValid(); }
|
||||
|
||||
/// \brief Get a printable name for debugging purpose.
|
||||
std::string getPrintableName() const;
|
||||
|
||||
/// \brief Get a GlobalSelector for the ASTContext-specific selector.
|
||||
static GlobalSelector get(Selector Sel, Program &Prog);
|
||||
|
||||
void *getAsOpaquePtr() const { return Val; }
|
||||
|
||||
static GlobalSelector getFromOpaquePtr(void *Ptr) {
|
||||
return GlobalSelector(Ptr);
|
||||
}
|
||||
|
||||
friend bool operator==(const GlobalSelector &LHS, const GlobalSelector &RHS) {
|
||||
return LHS.getAsOpaquePtr() == RHS.getAsOpaquePtr();
|
||||
}
|
||||
|
||||
// For use in a std::map.
|
||||
friend bool operator< (const GlobalSelector &LHS, const GlobalSelector &RHS) {
|
||||
return LHS.getAsOpaquePtr() < RHS.getAsOpaquePtr();
|
||||
}
|
||||
|
||||
// For use in DenseMap/DenseSet.
|
||||
static GlobalSelector getEmptyMarker() { return GlobalSelector((void*)-1); }
|
||||
static GlobalSelector getTombstoneMarker() {
|
||||
return GlobalSelector((void*)-2);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace idx
|
||||
|
||||
} // namespace clang
|
||||
|
||||
namespace llvm {
|
||||
/// Define DenseMapInfo so that GlobalSelectors can be used as keys in DenseMap
|
||||
/// and DenseSets.
|
||||
template<>
|
||||
struct DenseMapInfo<clang::idx::GlobalSelector> {
|
||||
static inline clang::idx::GlobalSelector getEmptyKey() {
|
||||
return clang::idx::GlobalSelector::getEmptyMarker();
|
||||
}
|
||||
|
||||
static inline clang::idx::GlobalSelector getTombstoneKey() {
|
||||
return clang::idx::GlobalSelector::getTombstoneMarker();
|
||||
}
|
||||
|
||||
static unsigned getHashValue(clang::idx::GlobalSelector);
|
||||
|
||||
static inline bool
|
||||
isEqual(clang::idx::GlobalSelector LHS, clang::idx::GlobalSelector RHS) {
|
||||
return LHS == RHS;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct isPodLike<clang::idx::GlobalSelector> { static const bool value = true;};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
@ -1,82 +0,0 @@
|
||||
//===--- Handlers.h - Interfaces for receiving information ------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Abstract interfaces for receiving information.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_INDEX_HANDLERS_H
|
||||
#define LLVM_CLANG_INDEX_HANDLERS_H
|
||||
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
namespace idx {
|
||||
class Entity;
|
||||
class TranslationUnit;
|
||||
class TULocation;
|
||||
|
||||
/// \brief Abstract interface for receiving Entities.
|
||||
class EntityHandler {
|
||||
public:
|
||||
typedef Entity receiving_type;
|
||||
|
||||
virtual ~EntityHandler();
|
||||
virtual void Handle(Entity Ent) = 0;
|
||||
};
|
||||
|
||||
/// \brief Abstract interface for receiving TranslationUnits.
|
||||
class TranslationUnitHandler {
|
||||
public:
|
||||
typedef TranslationUnit* receiving_type;
|
||||
|
||||
virtual ~TranslationUnitHandler();
|
||||
virtual void Handle(TranslationUnit *TU) = 0;
|
||||
};
|
||||
|
||||
/// \brief Abstract interface for receiving TULocations.
|
||||
class TULocationHandler {
|
||||
public:
|
||||
typedef TULocation receiving_type;
|
||||
|
||||
virtual ~TULocationHandler();
|
||||
virtual void Handle(TULocation TULoc) = 0;
|
||||
};
|
||||
|
||||
/// \brief Helper for the Handler classes. Stores the objects into a vector.
|
||||
/// example:
|
||||
/// @code
|
||||
/// Storing<TranslationUnitHandler> TURes;
|
||||
/// IndexProvider.GetTranslationUnitsFor(Entity, TURes);
|
||||
/// for (Storing<TranslationUnitHandler>::iterator
|
||||
/// I = TURes.begin(), E = TURes.end(); I != E; ++I) { ....
|
||||
/// @endcode
|
||||
template <typename handler_type>
|
||||
class Storing : public handler_type {
|
||||
typedef typename handler_type::receiving_type receiving_type;
|
||||
typedef SmallVector<receiving_type, 8> StoreTy;
|
||||
StoreTy Store;
|
||||
|
||||
public:
|
||||
virtual void Handle(receiving_type Obj) {
|
||||
Store.push_back(Obj);
|
||||
}
|
||||
|
||||
typedef typename StoreTy::const_iterator iterator;
|
||||
iterator begin() const { return Store.begin(); }
|
||||
iterator end() const { return Store.end(); }
|
||||
};
|
||||
|
||||
} // namespace idx
|
||||
|
||||
} // namespace clang
|
||||
|
||||
#endif
|
@ -1,38 +0,0 @@
|
||||
//===--- IndexProvider.h - Maps information to translation units -*- C++ -*-==//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Maps information to TranslationUnits.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_INDEX_INDEXPROVIDER_H
|
||||
#define LLVM_CLANG_INDEX_INDEXPROVIDER_H
|
||||
|
||||
namespace clang {
|
||||
|
||||
namespace idx {
|
||||
class Entity;
|
||||
class TranslationUnitHandler;
|
||||
class GlobalSelector;
|
||||
|
||||
/// \brief Maps information to TranslationUnits.
|
||||
class IndexProvider {
|
||||
public:
|
||||
virtual ~IndexProvider();
|
||||
virtual void GetTranslationUnitsFor(Entity Ent,
|
||||
TranslationUnitHandler &Handler) = 0;
|
||||
virtual void GetTranslationUnitsFor(GlobalSelector Sel,
|
||||
TranslationUnitHandler &Handler) = 0;
|
||||
};
|
||||
|
||||
} // namespace idx
|
||||
|
||||
} // namespace clang
|
||||
|
||||
#endif
|
@ -1,71 +0,0 @@
|
||||
//===--- Indexer.h - IndexProvider implementation ---------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// IndexProvider implementation.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_INDEX_INDEXER_H
|
||||
#define LLVM_CLANG_INDEX_INDEXER_H
|
||||
|
||||
#include "clang/Index/IndexProvider.h"
|
||||
#include "clang/Index/Entity.h"
|
||||
#include "clang/Index/GlobalSelector.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include <map>
|
||||
|
||||
namespace clang {
|
||||
class ASTContext;
|
||||
class FunctionDecl;
|
||||
|
||||
namespace idx {
|
||||
class Program;
|
||||
class TranslationUnit;
|
||||
|
||||
/// \brief Maps information to TranslationUnits.
|
||||
class Indexer : public IndexProvider {
|
||||
public:
|
||||
typedef llvm::SmallPtrSet<TranslationUnit *, 4> TUSetTy;
|
||||
typedef llvm::DenseMap<ASTContext *, TranslationUnit *> CtxTUMapTy;
|
||||
typedef std::map<Entity, TUSetTy> MapTy;
|
||||
typedef std::map<GlobalSelector, TUSetTy> SelMapTy;
|
||||
typedef std::map<Entity, std::pair<FunctionDecl*,TranslationUnit*> > DefMapTy;
|
||||
|
||||
explicit Indexer(Program &prog) :
|
||||
Prog(prog) { }
|
||||
|
||||
Program &getProgram() const { return Prog; }
|
||||
|
||||
/// \brief Find all Entities and map them to the given translation unit.
|
||||
void IndexAST(TranslationUnit *TU);
|
||||
|
||||
virtual void GetTranslationUnitsFor(Entity Ent,
|
||||
TranslationUnitHandler &Handler);
|
||||
virtual void GetTranslationUnitsFor(GlobalSelector Sel,
|
||||
TranslationUnitHandler &Handler);
|
||||
|
||||
std::pair<FunctionDecl*, TranslationUnit*> getDefinitionFor(Entity Ent);
|
||||
|
||||
private:
|
||||
Program &Prog;
|
||||
|
||||
MapTy Map;
|
||||
// Map a function Entity to the its definition.
|
||||
DefMapTy DefMap;
|
||||
|
||||
CtxTUMapTy CtxTUMap;
|
||||
SelMapTy SelMap;
|
||||
};
|
||||
|
||||
} // namespace idx
|
||||
|
||||
} // namespace clang
|
||||
|
||||
#endif
|
@ -1,45 +0,0 @@
|
||||
//===--- Program.h - Cross-translation unit information ---------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file declares the idx::Program interface.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_INDEX_PROGRAM_H
|
||||
#define LLVM_CLANG_INDEX_PROGRAM_H
|
||||
|
||||
namespace clang {
|
||||
class ASTContext;
|
||||
|
||||
namespace idx {
|
||||
class EntityHandler;
|
||||
|
||||
/// \brief Top level object that owns and maintains information
|
||||
/// that is common across translation units.
|
||||
class Program {
|
||||
void *Impl;
|
||||
|
||||
Program(const Program&); // do not implement
|
||||
Program &operator=(const Program &); // do not implement
|
||||
friend class Entity;
|
||||
friend class GlobalSelector;
|
||||
|
||||
public:
|
||||
Program();
|
||||
~Program();
|
||||
|
||||
/// \brief Traverses the AST and passes all the entities to the Handler.
|
||||
void FindEntities(ASTContext &Ctx, EntityHandler &Handler);
|
||||
};
|
||||
|
||||
} // namespace idx
|
||||
|
||||
} // namespace clang
|
||||
|
||||
#endif
|
@ -1,63 +0,0 @@
|
||||
//===--- STLExtras.h - Helper STL related templates -------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Helper templates for using with the STL.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_INDEX_STLEXTRAS_H
|
||||
#define LLVM_CLANG_INDEX_STLEXTRAS_H
|
||||
|
||||
namespace clang {
|
||||
|
||||
namespace idx {
|
||||
|
||||
/// \brief Wraps an iterator whose value_type is a pair, and provides
|
||||
/// pair's second object as the value.
|
||||
template <typename iter_type>
|
||||
class pair_value_iterator {
|
||||
iter_type I;
|
||||
|
||||
public:
|
||||
typedef typename iter_type::value_type::second_type value_type;
|
||||
typedef value_type& reference;
|
||||
typedef value_type* pointer;
|
||||
typedef typename iter_type::iterator_category iterator_category;
|
||||
typedef typename iter_type::difference_type difference_type;
|
||||
|
||||
pair_value_iterator() { }
|
||||
pair_value_iterator(iter_type i) : I(i) { }
|
||||
|
||||
reference operator*() const { return I->second; }
|
||||
pointer operator->() const { return &I->second; }
|
||||
|
||||
pair_value_iterator& operator++() {
|
||||
++I;
|
||||
return *this;
|
||||
}
|
||||
|
||||
pair_value_iterator operator++(int) {
|
||||
pair_value_iterator tmp(*this);
|
||||
++(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
friend bool operator==(pair_value_iterator L, pair_value_iterator R) {
|
||||
return L.I == R.I;
|
||||
}
|
||||
friend bool operator!=(pair_value_iterator L, pair_value_iterator R) {
|
||||
return L.I != R.I;
|
||||
}
|
||||
};
|
||||
|
||||
} // end idx namespace
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
@ -1,57 +0,0 @@
|
||||
//===--- SelectorMap.h - Maps selectors to methods and messages -*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// SelectorMap creates a mapping from selectors to ObjC method declarations
|
||||
// and ObjC message expressions.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_INDEX_SELECTORMAP_H
|
||||
#define LLVM_CLANG_INDEX_SELECTORMAP_H
|
||||
|
||||
#include "clang/Index/ASTLocation.h"
|
||||
#include "clang/Index/STLExtras.h"
|
||||
#include "clang/Basic/IdentifierTable.h"
|
||||
#include <map>
|
||||
|
||||
namespace clang {
|
||||
class ASTContext;
|
||||
class ObjCMethodDecl;
|
||||
|
||||
namespace idx {
|
||||
|
||||
/// \brief Maps NamedDecls with the ASTLocations that reference them.
|
||||
///
|
||||
/// References are mapped and retrieved using the canonical decls.
|
||||
class SelectorMap {
|
||||
public:
|
||||
explicit SelectorMap(ASTContext &Ctx);
|
||||
|
||||
typedef std::multimap<Selector, ObjCMethodDecl *> SelMethMapTy;
|
||||
typedef std::multimap<Selector, ASTLocation> SelRefMapTy;
|
||||
|
||||
typedef pair_value_iterator<SelMethMapTy::iterator> method_iterator;
|
||||
typedef pair_value_iterator<SelRefMapTy::iterator> astlocation_iterator;
|
||||
|
||||
method_iterator methods_begin(Selector Sel) const;
|
||||
method_iterator methods_end(Selector Sel) const;
|
||||
|
||||
astlocation_iterator refs_begin(Selector Sel) const;
|
||||
astlocation_iterator refs_end(Selector Sel) const;
|
||||
|
||||
private:
|
||||
mutable SelMethMapTy SelMethMap;
|
||||
mutable SelRefMapTy SelRefMap;
|
||||
};
|
||||
|
||||
} // end idx namespace
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
@ -1,41 +0,0 @@
|
||||
//===--- TranslationUnit.h - Interface for a translation unit ---*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Abstract interface for a translation unit.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_INDEX_TRANSLATIONUNIT_H
|
||||
#define LLVM_CLANG_INDEX_TRANSLATIONUNIT_H
|
||||
|
||||
namespace clang {
|
||||
class ASTContext;
|
||||
class DiagnosticsEngine;
|
||||
class Preprocessor;
|
||||
|
||||
namespace idx {
|
||||
class DeclReferenceMap;
|
||||
class SelectorMap;
|
||||
|
||||
/// \brief Abstract interface for a translation unit.
|
||||
class TranslationUnit {
|
||||
public:
|
||||
virtual ~TranslationUnit();
|
||||
virtual ASTContext &getASTContext() = 0;
|
||||
virtual Preprocessor &getPreprocessor() = 0;
|
||||
virtual DiagnosticsEngine &getDiagnostic() = 0;
|
||||
virtual DeclReferenceMap &getDeclReferenceMap() = 0;
|
||||
virtual SelectorMap &getSelectorMap() = 0;
|
||||
};
|
||||
|
||||
} // namespace idx
|
||||
|
||||
} // namespace clang
|
||||
|
||||
#endif
|
@ -15,7 +15,6 @@
|
||||
#define LLVM_CLANG_PARSE_PARSER_H
|
||||
|
||||
#include "clang/Basic/Specifiers.h"
|
||||
#include "clang/Basic/DelayedCleanupPool.h"
|
||||
#include "clang/Lex/Preprocessor.h"
|
||||
#include "clang/Lex/CodeCompletionHandler.h"
|
||||
#include "clang/Sema/Sema.h"
|
||||
@ -192,9 +191,9 @@ class Parser : public CodeCompletionHandler {
|
||||
/// Factory object for creating AttributeList objects.
|
||||
AttributeFactory AttrFactory;
|
||||
|
||||
/// \brief Gathers and cleans up objects when parsing of a top-level
|
||||
/// declaration is finished.
|
||||
DelayedCleanupPool TopLevelDeclCleanupPool;
|
||||
/// \brief Gathers and cleans up TemplateIdAnnotations when parsing of a
|
||||
/// top-level declaration is finished.
|
||||
SmallVector<TemplateIdAnnotation *, 16> TemplateIds;
|
||||
|
||||
IdentifierInfo *getSEHExceptKeyword();
|
||||
|
||||
@ -568,9 +567,7 @@ class Parser : public CodeCompletionHandler {
|
||||
const char *&PrevSpec, unsigned &DiagID,
|
||||
bool &isInvalid);
|
||||
|
||||
/// \brief Get the TemplateIdAnnotation from the token and put it in the
|
||||
/// cleanup pool so that it gets destroyed when parsing the current top level
|
||||
/// declaration is finished.
|
||||
/// \brief Get the TemplateIdAnnotation from the token.
|
||||
TemplateIdAnnotation *takeTemplateIdAnnotation(const Token &tok);
|
||||
|
||||
/// TentativeParsingAction - An object that is used as a kind of "tentative
|
||||
@ -858,7 +855,7 @@ class Parser : public CodeCompletionHandler {
|
||||
/// argument (C++ [class.mem]p2).
|
||||
struct LateParsedMethodDeclaration : public LateParsedDeclaration {
|
||||
explicit LateParsedMethodDeclaration(Parser *P, Decl *M)
|
||||
: Self(P), Method(M), TemplateScope(false) { }
|
||||
: Self(P), Method(M), TemplateScope(false), ExceptionSpecTokens(0) { }
|
||||
|
||||
virtual void ParseLexedMethodDeclarations();
|
||||
|
||||
@ -878,6 +875,10 @@ class Parser : public CodeCompletionHandler {
|
||||
/// method will be stored so that they can be reintroduced into
|
||||
/// scope at the appropriate times.
|
||||
SmallVector<LateParsedDefaultArgument, 8> DefaultArgs;
|
||||
|
||||
/// \brief The set of tokens that make up an exception-specification that
|
||||
/// has not yet been parsed.
|
||||
CachedTokens *ExceptionSpecTokens;
|
||||
};
|
||||
|
||||
/// LateParsedMemberInitializer - An initializer for a non-static class data
|
||||
@ -1420,11 +1421,13 @@ class Parser : public CodeCompletionHandler {
|
||||
// C++ 15: C++ Throw Expression
|
||||
ExprResult ParseThrowExpression();
|
||||
|
||||
ExceptionSpecificationType MaybeParseExceptionSpecification(
|
||||
ExceptionSpecificationType tryParseExceptionSpecification(
|
||||
bool Delayed,
|
||||
SourceRange &SpecificationRange,
|
||||
SmallVectorImpl<ParsedType> &DynamicExceptions,
|
||||
SmallVectorImpl<SourceRange> &DynamicExceptionRanges,
|
||||
ExprResult &NoexceptExpr);
|
||||
ExprResult &NoexceptExpr,
|
||||
CachedTokens *&ExceptionSpecTokens);
|
||||
|
||||
// EndLoc is filled with the location of the last token of the specification.
|
||||
ExceptionSpecificationType ParseDynamicExceptionSpecification(
|
||||
@ -1517,42 +1520,40 @@ class Parser : public CodeCompletionHandler {
|
||||
//===--------------------------------------------------------------------===//
|
||||
// C99 6.8: Statements and Blocks.
|
||||
|
||||
StmtResult ParseStatement(SourceLocation *TrailingElseLoc = NULL) {
|
||||
StmtResult ParseStatement(SourceLocation *TrailingElseLoc = 0) {
|
||||
StmtVector Stmts(Actions);
|
||||
return ParseStatementOrDeclaration(Stmts, true, TrailingElseLoc);
|
||||
}
|
||||
StmtResult ParseStatementOrDeclaration(StmtVector& Stmts,
|
||||
StmtResult ParseStatementOrDeclaration(StmtVector &Stmts,
|
||||
bool OnlyStatement,
|
||||
SourceLocation *TrailingElseLoc = NULL);
|
||||
StmtResult ParseExprStatement(ParsedAttributes &Attrs);
|
||||
StmtResult ParseLabeledStatement(ParsedAttributes &Attr);
|
||||
StmtResult ParseCaseStatement(ParsedAttributes &Attr,
|
||||
bool MissingCase = false,
|
||||
SourceLocation *TrailingElseLoc = 0);
|
||||
StmtResult ParseStatementOrDeclarationAfterAttributes(
|
||||
StmtVector &Stmts,
|
||||
bool OnlyStatement,
|
||||
SourceLocation *TrailingElseLoc,
|
||||
ParsedAttributesWithRange &Attrs);
|
||||
StmtResult ParseExprStatement();
|
||||
StmtResult ParseLabeledStatement(ParsedAttributesWithRange &attrs);
|
||||
StmtResult ParseCaseStatement(bool MissingCase = false,
|
||||
ExprResult Expr = ExprResult());
|
||||
StmtResult ParseDefaultStatement(ParsedAttributes &Attr);
|
||||
StmtResult ParseCompoundStatement(ParsedAttributes &Attr,
|
||||
bool isStmtExpr = false);
|
||||
StmtResult ParseCompoundStatement(ParsedAttributes &Attr,
|
||||
bool isStmtExpr,
|
||||
StmtResult ParseDefaultStatement();
|
||||
StmtResult ParseCompoundStatement(bool isStmtExpr = false);
|
||||
StmtResult ParseCompoundStatement(bool isStmtExpr,
|
||||
unsigned ScopeFlags);
|
||||
StmtResult ParseCompoundStatementBody(bool isStmtExpr = false);
|
||||
bool ParseParenExprOrCondition(ExprResult &ExprResult,
|
||||
Decl *&DeclResult,
|
||||
SourceLocation Loc,
|
||||
bool ConvertToBoolean);
|
||||
StmtResult ParseIfStatement(ParsedAttributes &Attr,
|
||||
SourceLocation *TrailingElseLoc);
|
||||
StmtResult ParseSwitchStatement(ParsedAttributes &Attr,
|
||||
SourceLocation *TrailingElseLoc);
|
||||
StmtResult ParseWhileStatement(ParsedAttributes &Attr,
|
||||
SourceLocation *TrailingElseLoc);
|
||||
StmtResult ParseDoStatement(ParsedAttributes &Attr);
|
||||
StmtResult ParseForStatement(ParsedAttributes &Attr,
|
||||
SourceLocation *TrailingElseLoc);
|
||||
StmtResult ParseGotoStatement(ParsedAttributes &Attr);
|
||||
StmtResult ParseContinueStatement(ParsedAttributes &Attr);
|
||||
StmtResult ParseBreakStatement(ParsedAttributes &Attr);
|
||||
StmtResult ParseReturnStatement(ParsedAttributes &Attr);
|
||||
StmtResult ParseIfStatement(SourceLocation *TrailingElseLoc);
|
||||
StmtResult ParseSwitchStatement(SourceLocation *TrailingElseLoc);
|
||||
StmtResult ParseWhileStatement(SourceLocation *TrailingElseLoc);
|
||||
StmtResult ParseDoStatement();
|
||||
StmtResult ParseForStatement(SourceLocation *TrailingElseLoc);
|
||||
StmtResult ParseGotoStatement();
|
||||
StmtResult ParseContinueStatement();
|
||||
StmtResult ParseBreakStatement();
|
||||
StmtResult ParseReturnStatement();
|
||||
StmtResult ParseAsmStatement(bool &msAsm);
|
||||
StmtResult ParseMicrosoftAsmStatement(SourceLocation AsmLoc);
|
||||
|
||||
@ -1586,7 +1587,7 @@ class Parser : public CodeCompletionHandler {
|
||||
/// \brief The behavior of this __if_exists or __if_not_exists block
|
||||
/// should.
|
||||
IfExistsBehavior Behavior;
|
||||
};
|
||||
};
|
||||
|
||||
bool ParseMicrosoftIfExistsCondition(IfExistsCondition& Result);
|
||||
void ParseMicrosoftIfExistsStatement(StmtVector &Stmts);
|
||||
@ -1602,14 +1603,14 @@ class Parser : public CodeCompletionHandler {
|
||||
//===--------------------------------------------------------------------===//
|
||||
// C++ 6: Statements and Blocks
|
||||
|
||||
StmtResult ParseCXXTryBlock(ParsedAttributes &Attr);
|
||||
StmtResult ParseCXXTryBlock();
|
||||
StmtResult ParseCXXTryBlockCommon(SourceLocation TryLoc);
|
||||
StmtResult ParseCXXCatchBlock();
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// MS: SEH Statements and Blocks
|
||||
|
||||
StmtResult ParseSEHTryBlock(ParsedAttributes &Attr);
|
||||
StmtResult ParseSEHTryBlock();
|
||||
StmtResult ParseSEHTryBlockCommon(SourceLocation Loc);
|
||||
StmtResult ParseSEHExceptBlock(SourceLocation Loc);
|
||||
StmtResult ParseSEHFinallyBlock(SourceLocation Loc);
|
||||
@ -1883,6 +1884,7 @@ class Parser : public CodeCompletionHandler {
|
||||
void ProhibitAttributes(ParsedAttributesWithRange &attrs) {
|
||||
if (!attrs.Range.isValid()) return;
|
||||
DiagnoseProhibitedAttributes(attrs);
|
||||
attrs.clear();
|
||||
}
|
||||
void DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs);
|
||||
|
||||
@ -2106,8 +2108,8 @@ class Parser : public CodeCompletionHandler {
|
||||
ParsingDeclRAIIObject *DiagsFromTParams = 0);
|
||||
void ParseConstructorInitializer(Decl *ConstructorDecl);
|
||||
MemInitResult ParseMemInitializer(Decl *ConstructorDecl);
|
||||
void HandleMemberFunctionDefaultArgs(Declarator& DeclaratorInfo,
|
||||
Decl *ThisDecl);
|
||||
void HandleMemberFunctionDeclDelays(Declarator& DeclaratorInfo,
|
||||
Decl *ThisDecl);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// C++ 10: Derived classes [class.derived]
|
||||
|
@ -1150,6 +1150,10 @@ struct DeclaratorChunk {
|
||||
/// \brief Pointer to the expression in the noexcept-specifier of this
|
||||
/// function, if it has one.
|
||||
Expr *NoexceptExpr;
|
||||
|
||||
/// \brief Pointer to the cached tokens for an exception-specification
|
||||
/// that has not yet been parsed.
|
||||
CachedTokens *ExceptionSpecTokens;
|
||||
};
|
||||
|
||||
/// TrailingReturnType - If this isn't null, it's the trailing return type
|
||||
@ -1172,6 +1176,8 @@ struct DeclaratorChunk {
|
||||
delete[] ArgInfo;
|
||||
if (getExceptionSpecType() == EST_Dynamic)
|
||||
delete[] Exceptions;
|
||||
else if (getExceptionSpecType() == EST_Delayed)
|
||||
delete ExceptionSpecTokens;
|
||||
}
|
||||
|
||||
/// isKNRPrototype - Return true if this is a K&R style identifier list,
|
||||
@ -1347,6 +1353,7 @@ struct DeclaratorChunk {
|
||||
SourceRange *ExceptionRanges,
|
||||
unsigned NumExceptions,
|
||||
Expr *NoexceptExpr,
|
||||
CachedTokens *ExceptionSpecTokens,
|
||||
SourceLocation LocalRangeBegin,
|
||||
SourceLocation LocalRangeEnd,
|
||||
Declarator &TheDeclarator,
|
||||
|
@ -179,7 +179,10 @@ namespace clang {
|
||||
return reinterpret_cast<ParsedTemplateArgument *>(this + 1);
|
||||
}
|
||||
|
||||
static TemplateIdAnnotation* Allocate(unsigned NumArgs) {
|
||||
/// \brief Creates a new TemplateIdAnnotation with NumArgs arguments and
|
||||
/// appends it to List.
|
||||
static TemplateIdAnnotation *
|
||||
Allocate(unsigned NumArgs, SmallVectorImpl<TemplateIdAnnotation*> &List) {
|
||||
TemplateIdAnnotation *TemplateId
|
||||
= (TemplateIdAnnotation *)std::malloc(sizeof(TemplateIdAnnotation) +
|
||||
sizeof(ParsedTemplateArgument) * NumArgs);
|
||||
@ -193,6 +196,7 @@ namespace clang {
|
||||
for (unsigned I = 0; I != NumArgs; ++I)
|
||||
new (TemplateArgs + I) ParsedTemplateArgument();
|
||||
|
||||
List.push_back(TemplateId);
|
||||
return TemplateId;
|
||||
}
|
||||
|
||||
|
@ -81,13 +81,8 @@ class Scope {
|
||||
/// SwitchScope - This is a scope that corresponds to a switch statement.
|
||||
SwitchScope = 0x800,
|
||||
|
||||
/// ThisScope - This is the scope of a struct/union/class definition,
|
||||
/// outside of any member function definition, where 'this' is nonetheless
|
||||
/// usable.
|
||||
ThisScope = 0x1000,
|
||||
|
||||
/// TryScope - This is the scope of a C++ try statement.
|
||||
TryScope = 0x2000
|
||||
TryScope = 0x1000
|
||||
};
|
||||
private:
|
||||
/// The parent scope for this scope. This is null for the translation-unit
|
||||
|
@ -446,11 +446,13 @@ class Sema {
|
||||
Sema &S;
|
||||
DeclContext *SavedContext;
|
||||
ProcessingContextState SavedContextState;
|
||||
QualType SavedCXXThisTypeOverride;
|
||||
|
||||
public:
|
||||
ContextRAII(Sema &S, DeclContext *ContextToPush)
|
||||
: S(S), SavedContext(S.CurContext),
|
||||
SavedContextState(S.DelayedDiagnostics.pushContext())
|
||||
SavedContextState(S.DelayedDiagnostics.pushContext()),
|
||||
SavedCXXThisTypeOverride(S.CXXThisTypeOverride)
|
||||
{
|
||||
assert(ContextToPush && "pushing null context");
|
||||
S.CurContext = ContextToPush;
|
||||
@ -460,6 +462,7 @@ class Sema {
|
||||
if (!SavedContext) return;
|
||||
S.CurContext = SavedContext;
|
||||
S.DelayedDiagnostics.popContext(SavedContextState);
|
||||
S.CXXThisTypeOverride = SavedCXXThisTypeOverride;
|
||||
SavedContext = 0;
|
||||
}
|
||||
|
||||
@ -898,11 +901,15 @@ class Sema {
|
||||
TypeSourceInfo *GetTypeForDeclaratorCast(Declarator &D, QualType FromTy);
|
||||
TypeSourceInfo *GetTypeSourceInfoForDeclarator(Declarator &D, QualType T,
|
||||
TypeSourceInfo *ReturnTypeInfo);
|
||||
|
||||
/// \brief Package the given type and TSI into a ParsedType.
|
||||
ParsedType CreateParsedType(QualType T, TypeSourceInfo *TInfo);
|
||||
DeclarationNameInfo GetNameForDeclarator(Declarator &D);
|
||||
DeclarationNameInfo GetNameFromUnqualifiedId(const UnqualifiedId &Name);
|
||||
static QualType GetTypeFromParser(ParsedType Ty, TypeSourceInfo **TInfo = 0);
|
||||
CanThrowResult canThrow(const Expr *E);
|
||||
const FunctionProtoType *ResolveExceptionSpec(SourceLocation Loc,
|
||||
const FunctionProtoType *FPT);
|
||||
bool CheckSpecifiedExceptionType(QualType T, const SourceRange &Range);
|
||||
bool CheckDistantExceptionSpec(QualType T);
|
||||
bool CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New);
|
||||
@ -1974,6 +1981,10 @@ class Sema {
|
||||
bool CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC);
|
||||
bool CheckNoReturnAttr(const AttributeList &attr);
|
||||
|
||||
/// \brief Stmt attributes - this routine is the top level dispatcher.
|
||||
StmtResult ProcessStmtAttributes(Stmt *Stmt, AttributeList *Attrs,
|
||||
SourceRange Range);
|
||||
|
||||
void WarnUndefinedMethod(SourceLocation ImpLoc, ObjCMethodDecl *method,
|
||||
bool &IncompleteImpl, unsigned DiagID);
|
||||
void WarnConflictingTypedMethods(ObjCMethodDecl *Method,
|
||||
@ -2251,6 +2262,9 @@ class Sema {
|
||||
StmtResult ActOnLabelStmt(SourceLocation IdentLoc, LabelDecl *TheDecl,
|
||||
SourceLocation ColonLoc, Stmt *SubStmt);
|
||||
|
||||
StmtResult ActOnAttributedStmt(SourceLocation AttrLoc, const AttrVec &Attrs,
|
||||
Stmt *SubStmt);
|
||||
|
||||
StmtResult ActOnIfStmt(SourceLocation IfLoc,
|
||||
FullExprArg CondVal, Decl *CondVar,
|
||||
Stmt *ThenVal,
|
||||
@ -3039,7 +3053,7 @@ class Sema {
|
||||
/// implicitly-declared special member functions.
|
||||
class ImplicitExceptionSpecification {
|
||||
// Pointer to allow copying
|
||||
ASTContext *Context;
|
||||
Sema *Self;
|
||||
// We order exception specifications thus:
|
||||
// noexcept is the most restrictive, but is only used in C++0x.
|
||||
// throw() comes next.
|
||||
@ -3063,9 +3077,9 @@ class Sema {
|
||||
}
|
||||
|
||||
public:
|
||||
explicit ImplicitExceptionSpecification(ASTContext &Context)
|
||||
: Context(&Context), ComputedEST(EST_BasicNoexcept) {
|
||||
if (!Context.getLangOpts().CPlusPlus0x)
|
||||
explicit ImplicitExceptionSpecification(Sema &Self)
|
||||
: Self(&Self), ComputedEST(EST_BasicNoexcept) {
|
||||
if (!Self.Context.getLangOpts().CPlusPlus0x)
|
||||
ComputedEST = EST_DynamicNone;
|
||||
}
|
||||
|
||||
@ -3083,7 +3097,7 @@ class Sema {
|
||||
const QualType *data() const { return Exceptions.data(); }
|
||||
|
||||
/// \brief Integrate another called method into the collected data.
|
||||
void CalledDecl(CXXMethodDecl *Method);
|
||||
void CalledDecl(SourceLocation CallLoc, CXXMethodDecl *Method);
|
||||
|
||||
/// \brief Integrate an invoked expression into the collected data.
|
||||
void CalledExpr(Expr *E);
|
||||
@ -3135,6 +3149,25 @@ class Sema {
|
||||
ImplicitExceptionSpecification
|
||||
ComputeDefaultedDtorExceptionSpec(CXXRecordDecl *ClassDecl);
|
||||
|
||||
/// \brief Check the given exception-specification and update the
|
||||
/// extended prototype information with the results.
|
||||
void checkExceptionSpecification(ExceptionSpecificationType EST,
|
||||
ArrayRef<ParsedType> DynamicExceptions,
|
||||
ArrayRef<SourceRange> DynamicExceptionRanges,
|
||||
Expr *NoexceptExpr,
|
||||
llvm::SmallVectorImpl<QualType> &Exceptions,
|
||||
FunctionProtoType::ExtProtoInfo &EPI);
|
||||
|
||||
/// \brief Add an exception-specification to the given member function
|
||||
/// (or member function template). The exception-specification was parsed
|
||||
/// after the method itself was declared.
|
||||
void actOnDelayedExceptionSpecification(Decl *Method,
|
||||
ExceptionSpecificationType EST,
|
||||
SourceRange SpecificationRange,
|
||||
ArrayRef<ParsedType> DynamicExceptions,
|
||||
ArrayRef<SourceRange> DynamicExceptionRanges,
|
||||
Expr *NoexceptExpr);
|
||||
|
||||
/// \brief Determine if a special member function should have a deleted
|
||||
/// definition when it is defaulted.
|
||||
bool ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM,
|
||||
@ -3240,6 +3273,22 @@ class Sema {
|
||||
/// special member function.
|
||||
bool isImplicitlyDeleted(FunctionDecl *FD);
|
||||
|
||||
/// \brief Check whether 'this' shows up in the type of a static member
|
||||
/// function after the (naturally empty) cv-qualifier-seq would be.
|
||||
///
|
||||
/// \returns true if an error occurred.
|
||||
bool checkThisInStaticMemberFunctionType(CXXMethodDecl *Method);
|
||||
|
||||
/// \brief Whether this' shows up in the exception specification of a static
|
||||
/// member function.
|
||||
bool checkThisInStaticMemberFunctionExceptionSpec(CXXMethodDecl *Method);
|
||||
|
||||
/// \brief Check whether 'this' shows up in the attributes of the given
|
||||
/// static member function.
|
||||
///
|
||||
/// \returns true if an error occurred.
|
||||
bool checkThisInStaticMemberFunctionAttributes(CXXMethodDecl *Method);
|
||||
|
||||
/// MaybeBindToTemporary - If the passed in expression has a record type with
|
||||
/// a non-trivial destructor, this will return CXXBindTemporaryExpr. Otherwise
|
||||
/// it simply returns the passed in expression.
|
||||
@ -3321,6 +3370,29 @@ class Sema {
|
||||
/// \returns The type of 'this', if possible. Otherwise, returns a NULL type.
|
||||
QualType getCurrentThisType();
|
||||
|
||||
/// \brief When non-NULL, the C++ 'this' expression is allowed despite the
|
||||
/// current context not being a non-static member function. In such cases,
|
||||
/// this provides the type used for 'this'.
|
||||
QualType CXXThisTypeOverride;
|
||||
|
||||
/// \brief RAII object used to temporarily allow the C++ 'this' expression
|
||||
/// to be used, with the given qualifiers on the current class type.
|
||||
class CXXThisScopeRAII {
|
||||
Sema &S;
|
||||
QualType OldCXXThisTypeOverride;
|
||||
bool Enabled;
|
||||
|
||||
public:
|
||||
/// \brief Introduce a new scope where 'this' may be allowed (when enabled),
|
||||
/// using the given declaration (which is either a class template or a
|
||||
/// class) along with the given qualifiers.
|
||||
/// along with the qualifiers placed on '*this'.
|
||||
CXXThisScopeRAII(Sema &S, Decl *ContextDecl, unsigned CXXThisTypeQuals,
|
||||
bool Enabled = true);
|
||||
|
||||
~CXXThisScopeRAII();
|
||||
};
|
||||
|
||||
/// \brief Make sure the value of 'this' is actually available in the current
|
||||
/// context, if it is a potentially evaluated context.
|
||||
///
|
||||
@ -3330,6 +3402,11 @@ class Sema {
|
||||
/// capture list.
|
||||
void CheckCXXThisCapture(SourceLocation Loc, bool Explicit = false);
|
||||
|
||||
/// \brief Determine whether the given type is the type of *this that is used
|
||||
/// outside of the body of a member function for a type that is currently
|
||||
/// being defined.
|
||||
bool isThisOutsideMemberFunctionBody(QualType BaseType);
|
||||
|
||||
/// ActOnCXXBoolLiteral - Parse {true,false} literals.
|
||||
ExprResult ActOnCXXBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind);
|
||||
|
||||
@ -5120,7 +5197,11 @@ class Sema {
|
||||
|
||||
/// We are checking the validity of a default template argument that
|
||||
/// has been used when naming a template-id.
|
||||
DefaultTemplateArgumentChecking
|
||||
DefaultTemplateArgumentChecking,
|
||||
|
||||
/// We are instantiating the exception specification for a function
|
||||
/// template which was deferred until it was needed.
|
||||
ExceptionSpecInstantiation
|
||||
} Kind;
|
||||
|
||||
/// \brief The point of instantiation within the source code.
|
||||
@ -5168,6 +5249,7 @@ class Sema {
|
||||
|
||||
switch (X.Kind) {
|
||||
case TemplateInstantiation:
|
||||
case ExceptionSpecInstantiation:
|
||||
return true;
|
||||
|
||||
case PriorTemplateArgumentSubstitution:
|
||||
@ -5285,6 +5367,13 @@ class Sema {
|
||||
Decl *Entity,
|
||||
SourceRange InstantiationRange = SourceRange());
|
||||
|
||||
struct ExceptionSpecification {};
|
||||
/// \brief Note that we are instantiating an exception specification
|
||||
/// of a function template.
|
||||
InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
|
||||
FunctionDecl *Entity, ExceptionSpecification,
|
||||
SourceRange InstantiationRange = SourceRange());
|
||||
|
||||
/// \brief Note that we are instantiating a default argument in a
|
||||
/// template-id.
|
||||
InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
|
||||
@ -5474,7 +5563,9 @@ class Sema {
|
||||
TypeSourceInfo *SubstFunctionDeclType(TypeSourceInfo *T,
|
||||
const MultiLevelTemplateArgumentList &TemplateArgs,
|
||||
SourceLocation Loc,
|
||||
DeclarationName Entity);
|
||||
DeclarationName Entity,
|
||||
CXXRecordDecl *ThisContext,
|
||||
unsigned ThisTypeQuals);
|
||||
ParmVarDecl *SubstParmVarDecl(ParmVarDecl *D,
|
||||
const MultiLevelTemplateArgumentList &TemplateArgs,
|
||||
int indexAdjustment,
|
||||
@ -5582,6 +5673,8 @@ class Sema {
|
||||
TemplateArgumentListInfo &Result,
|
||||
const MultiLevelTemplateArgumentList &TemplateArgs);
|
||||
|
||||
void InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
|
||||
FunctionDecl *Function);
|
||||
void InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
|
||||
FunctionDecl *Function,
|
||||
bool Recursive = false,
|
||||
@ -6463,11 +6556,11 @@ class Sema {
|
||||
/// and reports the appropriate diagnostics. Returns false on success.
|
||||
/// Can optionally return the value of the expression.
|
||||
ExprResult VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result,
|
||||
PartialDiagnostic Diag,
|
||||
const PartialDiagnostic &Diag,
|
||||
bool AllowFold,
|
||||
PartialDiagnostic FoldDiag);
|
||||
const PartialDiagnostic &FoldDiag);
|
||||
ExprResult VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result,
|
||||
PartialDiagnostic Diag,
|
||||
const PartialDiagnostic &Diag,
|
||||
bool AllowFold = true) {
|
||||
return VerifyIntegerConstantExpression(E, Result, Diag, AllowFold,
|
||||
PDiag(0));
|
||||
|
@ -964,6 +964,8 @@ namespace clang {
|
||||
STMT_DEFAULT,
|
||||
/// \brief A LabelStmt record.
|
||||
STMT_LABEL,
|
||||
/// \brief An AttributedStmt record.
|
||||
STMT_ATTRIBUTED,
|
||||
/// \brief An IfStmt record.
|
||||
STMT_IF,
|
||||
/// \brief A SwitchStmt record.
|
||||
|
@ -170,6 +170,9 @@ class ReadMethodPoolVisitor;
|
||||
|
||||
namespace reader {
|
||||
class ASTIdentifierLookupTrait;
|
||||
/// \brief The on-disk hash table used for the DeclContext's Name lookup table.
|
||||
typedef OnDiskChainedHashTable<ASTDeclContextNameLookupTrait>
|
||||
ASTDeclContextNameLookupTable;
|
||||
}
|
||||
|
||||
} // end namespace serialization
|
||||
@ -323,7 +326,9 @@ class ASTReader
|
||||
// TU, and when we read those update records, the actual context will not
|
||||
// be available yet (unless it's the TU), so have this pending map using the
|
||||
// ID as a key. It will be realized when the context is actually loaded.
|
||||
typedef SmallVector<std::pair<void *, ModuleFile*>, 1> DeclContextVisibleUpdates;
|
||||
typedef
|
||||
SmallVector<std::pair<serialization::reader::ASTDeclContextNameLookupTable *,
|
||||
ModuleFile*>, 1> DeclContextVisibleUpdates;
|
||||
typedef llvm::DenseMap<serialization::DeclID, DeclContextVisibleUpdates>
|
||||
DeclContextVisibleUpdatesPending;
|
||||
|
||||
@ -1467,7 +1472,7 @@ class ASTReader
|
||||
llvm::DenseMap<IdentifierInfo *, uint64_t>::iterator Pos);
|
||||
|
||||
/// \brief Load all external visible decls in the given DeclContext.
|
||||
void completeVisibleDeclsMap(DeclContext *DC);
|
||||
void completeVisibleDeclsMap(const DeclContext *DC);
|
||||
|
||||
/// \brief Retrieve the AST context that this AST reader supplements.
|
||||
ASTContext &getContext() { return Context; }
|
||||
|
@ -76,6 +76,7 @@ class ASTWriter : public ASTDeserializationListener,
|
||||
typedef SmallVectorImpl<uint64_t> RecordDataImpl;
|
||||
|
||||
friend class ASTDeclWriter;
|
||||
friend class ASTStmtWriter;
|
||||
private:
|
||||
/// \brief Map that provides the ID numbers of each type within the
|
||||
/// output stream, plus those deserialized from a chained PCH.
|
||||
|
@ -27,9 +27,14 @@ namespace clang {
|
||||
|
||||
class DeclContext;
|
||||
class Module;
|
||||
template<typename Info> class OnDiskChainedHashTable;
|
||||
|
||||
namespace serialization {
|
||||
|
||||
namespace reader {
|
||||
class ASTDeclContextNameLookupTrait;
|
||||
}
|
||||
|
||||
/// \brief Specifies the kind of module that has been loaded.
|
||||
enum ModuleKind {
|
||||
MK_Module, ///< File is a module proper.
|
||||
@ -43,7 +48,8 @@ struct DeclContextInfo {
|
||||
DeclContextInfo()
|
||||
: NameLookupTableData(), LexicalDecls(), NumLexicalDecls() {}
|
||||
|
||||
void *NameLookupTableData; // an ASTDeclContextNameLookupTable.
|
||||
OnDiskChainedHashTable<reader::ASTDeclContextNameLookupTrait>
|
||||
*NameLookupTableData; // an ASTDeclContextNameLookupTable.
|
||||
const KindDeclIDPair *LexicalDecls;
|
||||
unsigned NumLexicalDecls;
|
||||
};
|
||||
|
@ -22,11 +22,6 @@
|
||||
|
||||
namespace clang {
|
||||
|
||||
namespace idx {
|
||||
class Indexer;
|
||||
class TranslationUnit;
|
||||
}
|
||||
|
||||
namespace ento {
|
||||
class CheckerManager;
|
||||
|
||||
@ -46,11 +41,6 @@ class AnalysisManager : public BugReporterData {
|
||||
|
||||
CheckerManager *CheckerMgr;
|
||||
|
||||
/// \brief Provide function definitions in other translation units. This is
|
||||
/// NULL if we don't have multiple translation units. AnalysisManager does
|
||||
/// not own the Indexer.
|
||||
idx::Indexer *Idxer;
|
||||
|
||||
enum AnalysisScope { ScopeTU, ScopeDecl } AScope;
|
||||
|
||||
/// \brief The maximum number of exploded nodes the analyzer will generate.
|
||||
@ -99,7 +89,6 @@ class AnalysisManager : public BugReporterData {
|
||||
StoreManagerCreator storemgr,
|
||||
ConstraintManagerCreator constraintmgr,
|
||||
CheckerManager *checkerMgr,
|
||||
idx::Indexer *idxer,
|
||||
unsigned maxnodes, unsigned maxvisit,
|
||||
bool vizdot, bool vizubi, AnalysisPurgeMode purge,
|
||||
bool eager, bool trim,
|
||||
@ -137,8 +126,6 @@ class AnalysisManager : public BugReporterData {
|
||||
|
||||
CheckerManager *getCheckerManager() const { return CheckerMgr; }
|
||||
|
||||
idx::Indexer *getIndexer() const { return Idxer; }
|
||||
|
||||
virtual ASTContext &getASTContext() {
|
||||
return Ctx;
|
||||
}
|
||||
@ -186,10 +173,6 @@ class AnalysisManager : public BugReporterData {
|
||||
|
||||
bool shouldInlineCall() const { return (IPAMode == Inlining); }
|
||||
|
||||
bool hasIndexer() const { return Idxer != 0; }
|
||||
|
||||
AnalysisDeclContext *getAnalysisDeclContextInAnotherTU(const Decl *D);
|
||||
|
||||
CFG *getCFG(Decl const *D) {
|
||||
return AnaCtxMgr.getContext(D)->getCFG();
|
||||
}
|
||||
|
@ -425,10 +425,12 @@ class MemRegionVal : public Loc {
|
||||
public:
|
||||
explicit MemRegionVal(const MemRegion* r) : Loc(MemRegionKind, r) {}
|
||||
|
||||
/// \brief Get the underlining region.
|
||||
const MemRegion* getRegion() const {
|
||||
return static_cast<const MemRegion*>(Data);
|
||||
}
|
||||
|
||||
/// \brief Get the underlining region and strip casts.
|
||||
const MemRegion* stripCasts() const;
|
||||
|
||||
template <typename REGION>
|
||||
|
@ -33,22 +33,21 @@
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/Twine.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/SourceMgr.h"
|
||||
#include "llvm/Support/YAMLParser.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
class MemoryBuffer;
|
||||
} // end namespace llvm
|
||||
|
||||
namespace clang {
|
||||
namespace tooling {
|
||||
|
||||
/// \brief Specifies the working directory and command of a compilation.
|
||||
struct CompileCommand {
|
||||
CompileCommand() {}
|
||||
CompileCommand(StringRef Directory, ArrayRef<std::string> CommandLine)
|
||||
: Directory(Directory), CommandLine(CommandLine) {}
|
||||
CompileCommand(Twine Directory, ArrayRef<std::string> CommandLine)
|
||||
: Directory(Directory.str()), CommandLine(CommandLine) {}
|
||||
|
||||
/// \brief The working directory the command was executed from.
|
||||
std::string Directory;
|
||||
@ -95,6 +94,59 @@ class CompilationDatabase {
|
||||
StringRef FilePath) const = 0;
|
||||
};
|
||||
|
||||
/// \brief A compilation database that returns a single compile command line.
|
||||
///
|
||||
/// Useful when we want a tool to behave more like a compiler invocation.
|
||||
class FixedCompilationDatabase : public CompilationDatabase {
|
||||
public:
|
||||
/// \brief Creates a FixedCompilationDatabase from the arguments after "--".
|
||||
///
|
||||
/// Parses the given command line for "--". If "--" is found, the rest of
|
||||
/// the arguments will make up the command line in the returned
|
||||
/// FixedCompilationDatabase.
|
||||
/// The arguments after "--" must not include positional parameters or the
|
||||
/// argv[0] of the tool. Those will be added by the FixedCompilationDatabase
|
||||
/// when a CompileCommand is requested. The argv[0] of the returned command
|
||||
/// line will be "clang-tool".
|
||||
///
|
||||
/// Returns NULL in case "--" is not found.
|
||||
///
|
||||
/// The argument list is meant to be compatible with normal llvm command line
|
||||
/// parsing in main methods.
|
||||
/// int main(int argc, char **argv) {
|
||||
/// llvm::OwningPtr<FixedCompilationDatabase> Compilations(
|
||||
/// FixedCompilationDatabase::loadFromCommandLine(argc, argv));
|
||||
/// cl::ParseCommandLineOptions(argc, argv);
|
||||
/// ...
|
||||
/// }
|
||||
///
|
||||
/// \param Argc The number of command line arguments - will be changed to
|
||||
/// the number of arguments before "--", if "--" was found in the argument
|
||||
/// list.
|
||||
/// \param Argv Points to the command line arguments.
|
||||
/// \param Directory The base directory used in the FixedCompilationDatabase.
|
||||
static FixedCompilationDatabase *loadFromCommandLine(int &Argc,
|
||||
const char **Argv,
|
||||
Twine Directory = ".");
|
||||
|
||||
/// \brief Constructs a compilation data base from a specified directory
|
||||
/// and command line.
|
||||
FixedCompilationDatabase(Twine Directory, ArrayRef<std::string> CommandLine);
|
||||
|
||||
/// \brief Returns the given compile command.
|
||||
///
|
||||
/// Will always return a vector with one entry that contains the directory
|
||||
/// and command line specified at construction with "clang-tool" as argv[0]
|
||||
/// and 'FilePath' as positional argument.
|
||||
virtual std::vector<CompileCommand> getCompileCommands(
|
||||
StringRef FilePath) const;
|
||||
|
||||
private:
|
||||
/// This is built up to contain a single entry vector to be returned from
|
||||
/// getCompileCommands after adding the positional argument.
|
||||
std::vector<CompileCommand> CompileCommands;
|
||||
};
|
||||
|
||||
/// \brief A JSON based compilation database.
|
||||
///
|
||||
/// JSON compilation database files must contain a list of JSON objects which
|
||||
@ -114,7 +166,6 @@ class CompilationDatabase {
|
||||
/// by setting the flag -DCMAKE_EXPORT_COMPILE_COMMANDS.
|
||||
class JSONCompilationDatabase : public CompilationDatabase {
|
||||
public:
|
||||
|
||||
/// \brief Loads a JSON compilation database from the specified file.
|
||||
///
|
||||
/// Returns NULL and sets ErrorMessage if the database could not be
|
||||
@ -139,7 +190,7 @@ class JSONCompilationDatabase : public CompilationDatabase {
|
||||
private:
|
||||
/// \brief Constructs a JSON compilation database on a memory buffer.
|
||||
JSONCompilationDatabase(llvm::MemoryBuffer *Database)
|
||||
: Database(Database) {}
|
||||
: Database(Database), YAMLStream(Database->getBuffer(), SM) {}
|
||||
|
||||
/// \brief Parses the database file and creates the index.
|
||||
///
|
||||
@ -147,14 +198,17 @@ class JSONCompilationDatabase : public CompilationDatabase {
|
||||
/// failed.
|
||||
bool parse(std::string &ErrorMessage);
|
||||
|
||||
// Tuple (directory, commandline) where 'commandline' is a JSON escaped bash
|
||||
// escaped command line.
|
||||
typedef std::pair<StringRef, StringRef> CompileCommandRef;
|
||||
// Tuple (directory, commandline) where 'commandline' pointing to the
|
||||
// corresponding nodes in the YAML stream.
|
||||
typedef std::pair<llvm::yaml::ScalarNode*,
|
||||
llvm::yaml::ScalarNode*> CompileCommandRef;
|
||||
|
||||
// Maps file paths to the compile command lines for that file.
|
||||
llvm::StringMap< std::vector<CompileCommandRef> > IndexByFile;
|
||||
|
||||
llvm::OwningPtr<llvm::MemoryBuffer> Database;
|
||||
llvm::SourceMgr SM;
|
||||
llvm::yaml::Stream YAMLStream;
|
||||
};
|
||||
|
||||
} // end namespace tooling
|
||||
|
@ -481,7 +481,8 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target) {
|
||||
InitBuiltinType(ObjCBuiltinSelTy, BuiltinType::ObjCSel);
|
||||
|
||||
// Builtin type for __objc_yes and __objc_no
|
||||
ObjCBuiltinBoolTy = SignedCharTy;
|
||||
ObjCBuiltinBoolTy = (Target.useSignedCharForObjCBool() ?
|
||||
SignedCharTy : BoolTy);
|
||||
|
||||
ObjCConstantStringType = QualType();
|
||||
|
||||
@ -2193,6 +2194,8 @@ ASTContext::getFunctionType(QualType ResultTy,
|
||||
Size += EPI.NumExceptions * sizeof(QualType);
|
||||
else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) {
|
||||
Size += sizeof(Expr*);
|
||||
} else if (EPI.ExceptionSpecType == EST_Uninstantiated) {
|
||||
Size += 2 * sizeof(FunctionDecl*);
|
||||
}
|
||||
if (EPI.ConsumedArguments)
|
||||
Size += NumArgs * sizeof(bool);
|
||||
|
119
lib/AST/Decl.cpp
119
lib/AST/Decl.cpp
@ -69,33 +69,25 @@ typedef NamedDecl::LinkageInfo LinkageInfo;
|
||||
namespace {
|
||||
/// Flags controlling the computation of linkage and visibility.
|
||||
struct LVFlags {
|
||||
bool ConsiderGlobalVisibility;
|
||||
bool ConsiderVisibilityAttributes;
|
||||
bool ConsiderTemplateParameterTypes;
|
||||
const bool ConsiderGlobalVisibility;
|
||||
const bool ConsiderVisibilityAttributes;
|
||||
const bool ConsiderTemplateParameterTypes;
|
||||
|
||||
LVFlags() : ConsiderGlobalVisibility(true),
|
||||
ConsiderVisibilityAttributes(true),
|
||||
ConsiderTemplateParameterTypes(true) {
|
||||
}
|
||||
|
||||
LVFlags(bool Global, bool Attributes, bool Parameters) :
|
||||
ConsiderGlobalVisibility(Global),
|
||||
ConsiderVisibilityAttributes(Attributes),
|
||||
ConsiderTemplateParameterTypes(Parameters) {
|
||||
}
|
||||
|
||||
/// \brief Returns a set of flags that is only useful for computing the
|
||||
/// linkage, not the visibility, of a declaration.
|
||||
static LVFlags CreateOnlyDeclLinkage() {
|
||||
LVFlags F;
|
||||
F.ConsiderGlobalVisibility = false;
|
||||
F.ConsiderVisibilityAttributes = false;
|
||||
F.ConsiderTemplateParameterTypes = false;
|
||||
return F;
|
||||
}
|
||||
|
||||
/// Returns a set of flags, otherwise based on these, which ignores
|
||||
/// off all sources of visibility except template arguments.
|
||||
LVFlags onlyTemplateVisibility() const {
|
||||
LVFlags F = *this;
|
||||
F.ConsiderGlobalVisibility = false;
|
||||
F.ConsiderVisibilityAttributes = false;
|
||||
F.ConsiderTemplateParameterTypes = false;
|
||||
return F;
|
||||
return LVFlags(false, false, false);
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace
|
||||
@ -284,7 +276,6 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) {
|
||||
if (F.ConsiderVisibilityAttributes) {
|
||||
if (llvm::Optional<Visibility> Vis = D->getExplicitVisibility()) {
|
||||
LV.setVisibility(*Vis, true);
|
||||
F.ConsiderGlobalVisibility = false;
|
||||
} else {
|
||||
// If we're declared in a namespace with a visibility attribute,
|
||||
// use that namespace's visibility, but don't call it explicit.
|
||||
@ -295,7 +286,6 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) {
|
||||
if (!ND) continue;
|
||||
if (llvm::Optional<Visibility> Vis = ND->getExplicitVisibility()) {
|
||||
LV.setVisibility(*Vis, true);
|
||||
F.ConsiderGlobalVisibility = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -335,8 +325,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) {
|
||||
LinkageInfo TypeLV = getLVForType(Var->getType());
|
||||
if (TypeLV.linkage() != ExternalLinkage)
|
||||
return LinkageInfo::uniqueExternal();
|
||||
LV.mergeVisibilityWithMin(TypeLV.visibility(),
|
||||
TypeLV.visibilityExplicit());
|
||||
LV.mergeVisibilityWithMin(TypeLV);
|
||||
}
|
||||
|
||||
if (Var->getStorageClass() == SC_PrivateExtern)
|
||||
@ -412,7 +401,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) {
|
||||
= Function->getTemplateSpecializationInfo()) {
|
||||
if (shouldConsiderTemplateLV(Function, specInfo)) {
|
||||
LV.merge(getLVForDecl(specInfo->getTemplate(),
|
||||
F.onlyTemplateVisibility()));
|
||||
LVFlags::CreateOnlyDeclLinkage()));
|
||||
const TemplateArgumentList &templateArgs = *specInfo->TemplateArguments;
|
||||
LV.mergeWithMin(getLVForTemplateArgumentList(templateArgs, F));
|
||||
}
|
||||
@ -436,7 +425,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) {
|
||||
if (shouldConsiderTemplateLV(spec)) {
|
||||
// From the template.
|
||||
LV.merge(getLVForDecl(spec->getSpecializedTemplate(),
|
||||
F.onlyTemplateVisibility()));
|
||||
LVFlags::CreateOnlyDeclLinkage()));
|
||||
|
||||
// The arguments at which the template was instantiated.
|
||||
const TemplateArgumentList &TemplateArgs = spec->getTemplateArgs();
|
||||
@ -444,12 +433,6 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) {
|
||||
}
|
||||
}
|
||||
|
||||
// Consider -fvisibility unless the type has C linkage.
|
||||
if (F.ConsiderGlobalVisibility)
|
||||
F.ConsiderGlobalVisibility =
|
||||
(Context.getLangOpts().CPlusPlus &&
|
||||
!Tag->getDeclContext()->isExternCContext());
|
||||
|
||||
// - an enumerator belonging to an enumeration with external linkage;
|
||||
} else if (isa<EnumConstantDecl>(D)) {
|
||||
LinkageInfo EnumLV = getLVForDecl(cast<NamedDecl>(D->getDeclContext()), F);
|
||||
@ -501,22 +484,47 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, LVFlags F) {
|
||||
LinkageInfo LV;
|
||||
LV.mergeVisibility(D->getASTContext().getLangOpts().getVisibilityMode());
|
||||
|
||||
// The flags we're going to use to compute the class's visibility.
|
||||
LVFlags ClassF = F;
|
||||
|
||||
bool DHasExplicitVisibility = false;
|
||||
// If we have an explicit visibility attribute, merge that in.
|
||||
if (F.ConsiderVisibilityAttributes) {
|
||||
if (llvm::Optional<Visibility> Vis = D->getExplicitVisibility()) {
|
||||
LV.mergeVisibility(*Vis, true);
|
||||
|
||||
// Ignore global visibility later, but not this attribute.
|
||||
F.ConsiderGlobalVisibility = false;
|
||||
|
||||
// Ignore both global visibility and attributes when computing our
|
||||
// parent's visibility.
|
||||
ClassF = F.onlyTemplateVisibility();
|
||||
DHasExplicitVisibility = true;
|
||||
}
|
||||
}
|
||||
// Ignore both global visibility and attributes when computing our
|
||||
// parent's visibility if we already have an explicit one.
|
||||
LVFlags ClassF = DHasExplicitVisibility ?
|
||||
LVFlags::CreateOnlyDeclLinkage() : F;
|
||||
|
||||
// If we're paying attention to global visibility, apply
|
||||
// -finline-visibility-hidden if this is an inline method.
|
||||
//
|
||||
// Note that we do this before merging information about
|
||||
// the class visibility.
|
||||
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
|
||||
TemplateSpecializationKind TSK = TSK_Undeclared;
|
||||
if (FunctionTemplateSpecializationInfo *spec
|
||||
= MD->getTemplateSpecializationInfo()) {
|
||||
TSK = spec->getTemplateSpecializationKind();
|
||||
} else if (MemberSpecializationInfo *MSI =
|
||||
MD->getMemberSpecializationInfo()) {
|
||||
TSK = MSI->getTemplateSpecializationKind();
|
||||
}
|
||||
|
||||
const FunctionDecl *Def = 0;
|
||||
// InlineVisibilityHidden only applies to definitions, and
|
||||
// isInlined() only gives meaningful answers on definitions
|
||||
// anyway.
|
||||
if (TSK != TSK_ExplicitInstantiationDeclaration &&
|
||||
TSK != TSK_ExplicitInstantiationDefinition &&
|
||||
F.ConsiderGlobalVisibility &&
|
||||
!LV.visibilityExplicit() &&
|
||||
MD->getASTContext().getLangOpts().InlineVisibilityHidden &&
|
||||
MD->hasBody(Def) && Def->isInlined())
|
||||
LV.mergeVisibility(HiddenVisibility, true);
|
||||
}
|
||||
|
||||
// Class members only have linkage if their class has external
|
||||
// linkage.
|
||||
@ -534,8 +542,6 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, LVFlags F) {
|
||||
if (MD->getType()->getLinkage() == UniqueExternalLinkage)
|
||||
return LinkageInfo::uniqueExternal();
|
||||
|
||||
TemplateSpecializationKind TSK = TSK_Undeclared;
|
||||
|
||||
// If this is a method template specialization, use the linkage for
|
||||
// the template parameters and arguments.
|
||||
if (FunctionTemplateSpecializationInfo *spec
|
||||
@ -547,29 +553,6 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, LVFlags F) {
|
||||
LV.merge(getLVForTemplateParameterList(
|
||||
spec->getTemplate()->getTemplateParameters()));
|
||||
}
|
||||
|
||||
TSK = spec->getTemplateSpecializationKind();
|
||||
} else if (MemberSpecializationInfo *MSI =
|
||||
MD->getMemberSpecializationInfo()) {
|
||||
TSK = MSI->getTemplateSpecializationKind();
|
||||
}
|
||||
|
||||
// If we're paying attention to global visibility, apply
|
||||
// -finline-visibility-hidden if this is an inline method.
|
||||
//
|
||||
// Note that ConsiderGlobalVisibility doesn't yet have information
|
||||
// about whether containing classes have visibility attributes,
|
||||
// and that's intentional.
|
||||
if (TSK != TSK_ExplicitInstantiationDeclaration &&
|
||||
TSK != TSK_ExplicitInstantiationDefinition &&
|
||||
F.ConsiderGlobalVisibility &&
|
||||
MD->getASTContext().getLangOpts().InlineVisibilityHidden) {
|
||||
// InlineVisibilityHidden only applies to definitions, and
|
||||
// isInlined() only gives meaningful answers on definitions
|
||||
// anyway.
|
||||
const FunctionDecl *Def = 0;
|
||||
if (MD->hasBody(Def) && Def->isInlined())
|
||||
LV.setVisibility(HiddenVisibility);
|
||||
}
|
||||
|
||||
// Note that in contrast to basically every other situation, we
|
||||
@ -597,7 +580,7 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, LVFlags F) {
|
||||
if (TypeLV.linkage() != ExternalLinkage)
|
||||
LV.mergeLinkage(UniqueExternalLinkage);
|
||||
if (!LV.visibilityExplicit())
|
||||
LV.mergeVisibility(TypeLV.visibility(), TypeLV.visibilityExplicit());
|
||||
LV.mergeVisibility(TypeLV);
|
||||
}
|
||||
|
||||
return LV;
|
||||
@ -802,7 +785,7 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, LVFlags Flags) {
|
||||
LinkageInfo LV;
|
||||
if (Flags.ConsiderVisibilityAttributes) {
|
||||
if (llvm::Optional<Visibility> Vis = Function->getExplicitVisibility())
|
||||
LV.setVisibility(*Vis);
|
||||
LV.setVisibility(*Vis, true);
|
||||
}
|
||||
|
||||
if (const FunctionDecl *Prev = Function->getPreviousDecl()) {
|
||||
@ -823,10 +806,10 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, LVFlags Flags) {
|
||||
|
||||
LinkageInfo LV;
|
||||
if (Var->getStorageClass() == SC_PrivateExtern)
|
||||
LV.setVisibility(HiddenVisibility);
|
||||
LV.setVisibility(HiddenVisibility, true);
|
||||
else if (Flags.ConsiderVisibilityAttributes) {
|
||||
if (llvm::Optional<Visibility> Vis = Var->getExplicitVisibility())
|
||||
LV.setVisibility(*Vis);
|
||||
LV.setVisibility(*Vis, true);
|
||||
}
|
||||
|
||||
if (const VarDecl *Prev = Var->getPreviousDecl()) {
|
||||
|
335
lib/AST/Expr.cpp
335
lib/AST/Expr.cpp
@ -1590,6 +1590,16 @@ void InitListExpr::setArrayFiller(Expr *filler) {
|
||||
inits[i] = filler;
|
||||
}
|
||||
|
||||
bool InitListExpr::isStringLiteralInit() const {
|
||||
if (getNumInits() != 1)
|
||||
return false;
|
||||
const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(getType());
|
||||
if (!CAT || !CAT->getElementType()->isIntegerType())
|
||||
return false;
|
||||
const Expr *Init = getInit(0)->IgnoreParenImpCasts();
|
||||
return isa<StringLiteral>(Init) || isa<ObjCEncodeExpr>(Init);
|
||||
}
|
||||
|
||||
SourceRange InitListExpr::getSourceRange() const {
|
||||
if (SyntacticForm)
|
||||
return SyntacticForm->getSourceRange();
|
||||
@ -1986,331 +1996,6 @@ QualType Expr::findBoundMemberType(const Expr *expr) {
|
||||
return QualType();
|
||||
}
|
||||
|
||||
static Expr::CanThrowResult MergeCanThrow(Expr::CanThrowResult CT1,
|
||||
Expr::CanThrowResult CT2) {
|
||||
// CanThrowResult constants are ordered so that the maximum is the correct
|
||||
// merge result.
|
||||
return CT1 > CT2 ? CT1 : CT2;
|
||||
}
|
||||
|
||||
static Expr::CanThrowResult CanSubExprsThrow(ASTContext &C, const Expr *CE) {
|
||||
Expr *E = const_cast<Expr*>(CE);
|
||||
Expr::CanThrowResult R = Expr::CT_Cannot;
|
||||
for (Expr::child_range I = E->children(); I && R != Expr::CT_Can; ++I) {
|
||||
R = MergeCanThrow(R, cast<Expr>(*I)->CanThrow(C));
|
||||
}
|
||||
return R;
|
||||
}
|
||||
|
||||
static Expr::CanThrowResult CanCalleeThrow(ASTContext &Ctx, const Expr *E,
|
||||
const Decl *D,
|
||||
bool NullThrows = true) {
|
||||
if (!D)
|
||||
return NullThrows ? Expr::CT_Can : Expr::CT_Cannot;
|
||||
|
||||
// See if we can get a function type from the decl somehow.
|
||||
const ValueDecl *VD = dyn_cast<ValueDecl>(D);
|
||||
if (!VD) // If we have no clue what we're calling, assume the worst.
|
||||
return Expr::CT_Can;
|
||||
|
||||
// As an extension, we assume that __attribute__((nothrow)) functions don't
|
||||
// throw.
|
||||
if (isa<FunctionDecl>(D) && D->hasAttr<NoThrowAttr>())
|
||||
return Expr::CT_Cannot;
|
||||
|
||||
QualType T = VD->getType();
|
||||
const FunctionProtoType *FT;
|
||||
if ((FT = T->getAs<FunctionProtoType>())) {
|
||||
} else if (const PointerType *PT = T->getAs<PointerType>())
|
||||
FT = PT->getPointeeType()->getAs<FunctionProtoType>();
|
||||
else if (const ReferenceType *RT = T->getAs<ReferenceType>())
|
||||
FT = RT->getPointeeType()->getAs<FunctionProtoType>();
|
||||
else if (const MemberPointerType *MT = T->getAs<MemberPointerType>())
|
||||
FT = MT->getPointeeType()->getAs<FunctionProtoType>();
|
||||
else if (const BlockPointerType *BT = T->getAs<BlockPointerType>())
|
||||
FT = BT->getPointeeType()->getAs<FunctionProtoType>();
|
||||
|
||||
if (!FT)
|
||||
return Expr::CT_Can;
|
||||
|
||||
if (FT->getExceptionSpecType() == EST_Delayed) {
|
||||
assert(isa<CXXConstructorDecl>(D) &&
|
||||
"only constructor exception specs can be unknown");
|
||||
Ctx.getDiagnostics().Report(E->getLocStart(),
|
||||
diag::err_exception_spec_unknown)
|
||||
<< E->getSourceRange();
|
||||
return Expr::CT_Can;
|
||||
}
|
||||
|
||||
return FT->isNothrow(Ctx) ? Expr::CT_Cannot : Expr::CT_Can;
|
||||
}
|
||||
|
||||
static Expr::CanThrowResult CanDynamicCastThrow(const CXXDynamicCastExpr *DC) {
|
||||
if (DC->isTypeDependent())
|
||||
return Expr::CT_Dependent;
|
||||
|
||||
if (!DC->getTypeAsWritten()->isReferenceType())
|
||||
return Expr::CT_Cannot;
|
||||
|
||||
if (DC->getSubExpr()->isTypeDependent())
|
||||
return Expr::CT_Dependent;
|
||||
|
||||
return DC->getCastKind() == clang::CK_Dynamic? Expr::CT_Can : Expr::CT_Cannot;
|
||||
}
|
||||
|
||||
static Expr::CanThrowResult CanTypeidThrow(ASTContext &C,
|
||||
const CXXTypeidExpr *DC) {
|
||||
if (DC->isTypeOperand())
|
||||
return Expr::CT_Cannot;
|
||||
|
||||
Expr *Op = DC->getExprOperand();
|
||||
if (Op->isTypeDependent())
|
||||
return Expr::CT_Dependent;
|
||||
|
||||
const RecordType *RT = Op->getType()->getAs<RecordType>();
|
||||
if (!RT)
|
||||
return Expr::CT_Cannot;
|
||||
|
||||
if (!cast<CXXRecordDecl>(RT->getDecl())->isPolymorphic())
|
||||
return Expr::CT_Cannot;
|
||||
|
||||
if (Op->Classify(C).isPRValue())
|
||||
return Expr::CT_Cannot;
|
||||
|
||||
return Expr::CT_Can;
|
||||
}
|
||||
|
||||
Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const {
|
||||
// C++ [expr.unary.noexcept]p3:
|
||||
// [Can throw] if in a potentially-evaluated context the expression would
|
||||
// contain:
|
||||
switch (getStmtClass()) {
|
||||
case CXXThrowExprClass:
|
||||
// - a potentially evaluated throw-expression
|
||||
return CT_Can;
|
||||
|
||||
case CXXDynamicCastExprClass: {
|
||||
// - a potentially evaluated dynamic_cast expression dynamic_cast<T>(v),
|
||||
// where T is a reference type, that requires a run-time check
|
||||
CanThrowResult CT = CanDynamicCastThrow(cast<CXXDynamicCastExpr>(this));
|
||||
if (CT == CT_Can)
|
||||
return CT;
|
||||
return MergeCanThrow(CT, CanSubExprsThrow(C, this));
|
||||
}
|
||||
|
||||
case CXXTypeidExprClass:
|
||||
// - a potentially evaluated typeid expression applied to a glvalue
|
||||
// expression whose type is a polymorphic class type
|
||||
return CanTypeidThrow(C, cast<CXXTypeidExpr>(this));
|
||||
|
||||
// - a potentially evaluated call to a function, member function, function
|
||||
// pointer, or member function pointer that does not have a non-throwing
|
||||
// exception-specification
|
||||
case CallExprClass:
|
||||
case CXXMemberCallExprClass:
|
||||
case CXXOperatorCallExprClass:
|
||||
case UserDefinedLiteralClass: {
|
||||
const CallExpr *CE = cast<CallExpr>(this);
|
||||
CanThrowResult CT;
|
||||
if (isTypeDependent())
|
||||
CT = CT_Dependent;
|
||||
else if (isa<CXXPseudoDestructorExpr>(CE->getCallee()->IgnoreParens()))
|
||||
CT = CT_Cannot;
|
||||
else
|
||||
CT = CanCalleeThrow(C, this, CE->getCalleeDecl());
|
||||
if (CT == CT_Can)
|
||||
return CT;
|
||||
return MergeCanThrow(CT, CanSubExprsThrow(C, this));
|
||||
}
|
||||
|
||||
case CXXConstructExprClass:
|
||||
case CXXTemporaryObjectExprClass: {
|
||||
CanThrowResult CT = CanCalleeThrow(C, this,
|
||||
cast<CXXConstructExpr>(this)->getConstructor());
|
||||
if (CT == CT_Can)
|
||||
return CT;
|
||||
return MergeCanThrow(CT, CanSubExprsThrow(C, this));
|
||||
}
|
||||
|
||||
case LambdaExprClass: {
|
||||
const LambdaExpr *Lambda = cast<LambdaExpr>(this);
|
||||
CanThrowResult CT = Expr::CT_Cannot;
|
||||
for (LambdaExpr::capture_init_iterator Cap = Lambda->capture_init_begin(),
|
||||
CapEnd = Lambda->capture_init_end();
|
||||
Cap != CapEnd; ++Cap)
|
||||
CT = MergeCanThrow(CT, (*Cap)->CanThrow(C));
|
||||
return CT;
|
||||
}
|
||||
|
||||
case CXXNewExprClass: {
|
||||
CanThrowResult CT;
|
||||
if (isTypeDependent())
|
||||
CT = CT_Dependent;
|
||||
else
|
||||
CT = CanCalleeThrow(C, this, cast<CXXNewExpr>(this)->getOperatorNew());
|
||||
if (CT == CT_Can)
|
||||
return CT;
|
||||
return MergeCanThrow(CT, CanSubExprsThrow(C, this));
|
||||
}
|
||||
|
||||
case CXXDeleteExprClass: {
|
||||
CanThrowResult CT;
|
||||
QualType DTy = cast<CXXDeleteExpr>(this)->getDestroyedType();
|
||||
if (DTy.isNull() || DTy->isDependentType()) {
|
||||
CT = CT_Dependent;
|
||||
} else {
|
||||
CT = CanCalleeThrow(C, this,
|
||||
cast<CXXDeleteExpr>(this)->getOperatorDelete());
|
||||
if (const RecordType *RT = DTy->getAs<RecordType>()) {
|
||||
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
|
||||
CT = MergeCanThrow(CT, CanCalleeThrow(C, this, RD->getDestructor()));
|
||||
}
|
||||
if (CT == CT_Can)
|
||||
return CT;
|
||||
}
|
||||
return MergeCanThrow(CT, CanSubExprsThrow(C, this));
|
||||
}
|
||||
|
||||
case CXXBindTemporaryExprClass: {
|
||||
// The bound temporary has to be destroyed again, which might throw.
|
||||
CanThrowResult CT = CanCalleeThrow(C, this,
|
||||
cast<CXXBindTemporaryExpr>(this)->getTemporary()->getDestructor());
|
||||
if (CT == CT_Can)
|
||||
return CT;
|
||||
return MergeCanThrow(CT, CanSubExprsThrow(C, this));
|
||||
}
|
||||
|
||||
// ObjC message sends are like function calls, but never have exception
|
||||
// specs.
|
||||
case ObjCMessageExprClass:
|
||||
case ObjCPropertyRefExprClass:
|
||||
case ObjCSubscriptRefExprClass:
|
||||
return CT_Can;
|
||||
|
||||
// All the ObjC literals that are implemented as calls are
|
||||
// potentially throwing unless we decide to close off that
|
||||
// possibility.
|
||||
case ObjCArrayLiteralClass:
|
||||
case ObjCDictionaryLiteralClass:
|
||||
case ObjCNumericLiteralClass:
|
||||
return CT_Can;
|
||||
|
||||
// Many other things have subexpressions, so we have to test those.
|
||||
// Some are simple:
|
||||
case ConditionalOperatorClass:
|
||||
case CompoundLiteralExprClass:
|
||||
case CXXConstCastExprClass:
|
||||
case CXXDefaultArgExprClass:
|
||||
case CXXReinterpretCastExprClass:
|
||||
case DesignatedInitExprClass:
|
||||
case ExprWithCleanupsClass:
|
||||
case ExtVectorElementExprClass:
|
||||
case InitListExprClass:
|
||||
case MemberExprClass:
|
||||
case ObjCIsaExprClass:
|
||||
case ObjCIvarRefExprClass:
|
||||
case ParenExprClass:
|
||||
case ParenListExprClass:
|
||||
case ShuffleVectorExprClass:
|
||||
case VAArgExprClass:
|
||||
return CanSubExprsThrow(C, this);
|
||||
|
||||
// Some might be dependent for other reasons.
|
||||
case ArraySubscriptExprClass:
|
||||
case BinaryOperatorClass:
|
||||
case CompoundAssignOperatorClass:
|
||||
case CStyleCastExprClass:
|
||||
case CXXStaticCastExprClass:
|
||||
case CXXFunctionalCastExprClass:
|
||||
case ImplicitCastExprClass:
|
||||
case MaterializeTemporaryExprClass:
|
||||
case UnaryOperatorClass: {
|
||||
CanThrowResult CT = isTypeDependent() ? CT_Dependent : CT_Cannot;
|
||||
return MergeCanThrow(CT, CanSubExprsThrow(C, this));
|
||||
}
|
||||
|
||||
// FIXME: We should handle StmtExpr, but that opens a MASSIVE can of worms.
|
||||
case StmtExprClass:
|
||||
return CT_Can;
|
||||
|
||||
case ChooseExprClass:
|
||||
if (isTypeDependent() || isValueDependent())
|
||||
return CT_Dependent;
|
||||
return cast<ChooseExpr>(this)->getChosenSubExpr(C)->CanThrow(C);
|
||||
|
||||
case GenericSelectionExprClass:
|
||||
if (cast<GenericSelectionExpr>(this)->isResultDependent())
|
||||
return CT_Dependent;
|
||||
return cast<GenericSelectionExpr>(this)->getResultExpr()->CanThrow(C);
|
||||
|
||||
// Some expressions are always dependent.
|
||||
case CXXDependentScopeMemberExprClass:
|
||||
case CXXUnresolvedConstructExprClass:
|
||||
case DependentScopeDeclRefExprClass:
|
||||
return CT_Dependent;
|
||||
|
||||
case AtomicExprClass:
|
||||
case AsTypeExprClass:
|
||||
case BinaryConditionalOperatorClass:
|
||||
case BlockExprClass:
|
||||
case CUDAKernelCallExprClass:
|
||||
case DeclRefExprClass:
|
||||
case ObjCBridgedCastExprClass:
|
||||
case ObjCIndirectCopyRestoreExprClass:
|
||||
case ObjCProtocolExprClass:
|
||||
case ObjCSelectorExprClass:
|
||||
case OffsetOfExprClass:
|
||||
case PackExpansionExprClass:
|
||||
case PseudoObjectExprClass:
|
||||
case SubstNonTypeTemplateParmExprClass:
|
||||
case SubstNonTypeTemplateParmPackExprClass:
|
||||
case UnaryExprOrTypeTraitExprClass:
|
||||
case UnresolvedLookupExprClass:
|
||||
case UnresolvedMemberExprClass:
|
||||
// FIXME: Can any of the above throw? If so, when?
|
||||
return CT_Cannot;
|
||||
|
||||
case AddrLabelExprClass:
|
||||
case ArrayTypeTraitExprClass:
|
||||
case BinaryTypeTraitExprClass:
|
||||
case TypeTraitExprClass:
|
||||
case CXXBoolLiteralExprClass:
|
||||
case CXXNoexceptExprClass:
|
||||
case CXXNullPtrLiteralExprClass:
|
||||
case CXXPseudoDestructorExprClass:
|
||||
case CXXScalarValueInitExprClass:
|
||||
case CXXThisExprClass:
|
||||
case CXXUuidofExprClass:
|
||||
case CharacterLiteralClass:
|
||||
case ExpressionTraitExprClass:
|
||||
case FloatingLiteralClass:
|
||||
case GNUNullExprClass:
|
||||
case ImaginaryLiteralClass:
|
||||
case ImplicitValueInitExprClass:
|
||||
case IntegerLiteralClass:
|
||||
case ObjCEncodeExprClass:
|
||||
case ObjCStringLiteralClass:
|
||||
case ObjCBoolLiteralExprClass:
|
||||
case OpaqueValueExprClass:
|
||||
case PredefinedExprClass:
|
||||
case SizeOfPackExprClass:
|
||||
case StringLiteralClass:
|
||||
case UnaryTypeTraitExprClass:
|
||||
// These expressions can never throw.
|
||||
return CT_Cannot;
|
||||
|
||||
#define STMT(CLASS, PARENT) case CLASS##Class:
|
||||
#define STMT_RANGE(Base, First, Last)
|
||||
#define LAST_STMT_RANGE(BASE, FIRST, LAST)
|
||||
#define EXPR(CLASS, PARENT)
|
||||
#define ABSTRACT_STMT(STMT)
|
||||
#include "clang/AST/StmtNodes.inc"
|
||||
case NoStmtClass:
|
||||
llvm_unreachable("Invalid class for expression");
|
||||
}
|
||||
llvm_unreachable("Bogus StmtClass");
|
||||
}
|
||||
|
||||
Expr* Expr::IgnoreParens() {
|
||||
Expr* E = this;
|
||||
while (true) {
|
||||
|
@ -934,6 +934,7 @@ static bool IsGlobalLValue(APValue::LValueBase B) {
|
||||
case Expr::ObjCStringLiteralClass:
|
||||
case Expr::ObjCEncodeExprClass:
|
||||
case Expr::CXXTypeidExprClass:
|
||||
case Expr::CXXUuidofExprClass:
|
||||
return true;
|
||||
case Expr::CallExprClass:
|
||||
return IsStringLiteralCall(cast<CallExpr>(E));
|
||||
@ -1491,15 +1492,19 @@ static unsigned getBaseIndex(const CXXRecordDecl *Derived,
|
||||
llvm_unreachable("base class missing from derived class's bases list");
|
||||
}
|
||||
|
||||
/// Extract the value of a character from a string literal.
|
||||
/// Extract the value of a character from a string literal. CharType is used to
|
||||
/// determine the expected signedness of the result -- a string literal used to
|
||||
/// initialize an array of 'signed char' or 'unsigned char' might contain chars
|
||||
/// of the wrong signedness.
|
||||
static APSInt ExtractStringLiteralCharacter(EvalInfo &Info, const Expr *Lit,
|
||||
uint64_t Index) {
|
||||
uint64_t Index, QualType CharType) {
|
||||
// FIXME: Support PredefinedExpr, ObjCEncodeExpr, MakeStringConstant
|
||||
const StringLiteral *S = dyn_cast<StringLiteral>(Lit);
|
||||
assert(S && "unexpected string literal expression kind");
|
||||
assert(CharType->isIntegerType() && "unexpected character type");
|
||||
|
||||
APSInt Value(S->getCharByteWidth() * Info.Ctx.getCharWidth(),
|
||||
Lit->getType()->getArrayElementTypeNoTypeQual()->isUnsignedIntegerType());
|
||||
CharType->isUnsignedIntegerType());
|
||||
if (Index < S->getLength())
|
||||
Value = S->getCodeUnit(Index);
|
||||
return Value;
|
||||
@ -1546,7 +1551,7 @@ static bool ExtractSubobject(EvalInfo &Info, const Expr *E,
|
||||
assert(I == N - 1 && "extracting subobject of character?");
|
||||
assert(!O->hasLValuePath() || O->getLValuePath().empty());
|
||||
Obj = APValue(ExtractStringLiteralCharacter(
|
||||
Info, O->getLValueBase().get<const Expr*>(), Index));
|
||||
Info, O->getLValueBase().get<const Expr*>(), Index, SubType));
|
||||
return true;
|
||||
} else if (O->getArrayInitializedElts() > Index)
|
||||
O = &O->getArrayInitializedElt(Index);
|
||||
@ -2868,6 +2873,7 @@ class LValueExprEvaluator
|
||||
bool VisitStringLiteral(const StringLiteral *E) { return Success(E); }
|
||||
bool VisitObjCEncodeExpr(const ObjCEncodeExpr *E) { return Success(E); }
|
||||
bool VisitCXXTypeidExpr(const CXXTypeidExpr *E);
|
||||
bool VisitCXXUuidofExpr(const CXXUuidofExpr *E);
|
||||
bool VisitArraySubscriptExpr(const ArraySubscriptExpr *E);
|
||||
bool VisitUnaryDeref(const UnaryOperator *E);
|
||||
bool VisitUnaryReal(const UnaryOperator *E);
|
||||
@ -2973,6 +2979,10 @@ bool LValueExprEvaluator::VisitCXXTypeidExpr(const CXXTypeidExpr *E) {
|
||||
return Success(E);
|
||||
}
|
||||
|
||||
bool LValueExprEvaluator::VisitCXXUuidofExpr(const CXXUuidofExpr *E) {
|
||||
return Success(E);
|
||||
}
|
||||
|
||||
bool LValueExprEvaluator::VisitMemberExpr(const MemberExpr *E) {
|
||||
// Handle static data members.
|
||||
if (const VarDecl *VD = dyn_cast<VarDecl>(E->getMemberDecl())) {
|
||||
@ -3849,8 +3859,7 @@ bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
|
||||
|
||||
// C++11 [dcl.init.string]p1: A char array [...] can be initialized by [...]
|
||||
// an appropriately-typed string literal enclosed in braces.
|
||||
if (E->getNumInits() == 1 && E->getInit(0)->isGLValue() &&
|
||||
Info.Ctx.hasSameUnqualifiedType(E->getType(), E->getInit(0)->getType())) {
|
||||
if (E->isStringLiteralInit()) {
|
||||
LValue LV;
|
||||
if (!EvaluateLValue(E->getInit(0), LV, Info))
|
||||
return false;
|
||||
@ -5079,14 +5088,37 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
|
||||
}
|
||||
}
|
||||
|
||||
// The comparison here must be unsigned, and performed with the same
|
||||
// width as the pointer.
|
||||
unsigned PtrSize = Info.Ctx.getTypeSize(LHSTy);
|
||||
uint64_t CompareLHS = LHSOffset.getQuantity();
|
||||
uint64_t CompareRHS = RHSOffset.getQuantity();
|
||||
assert(PtrSize <= 64 && "Unexpected pointer width");
|
||||
uint64_t Mask = ~0ULL >> (64 - PtrSize);
|
||||
CompareLHS &= Mask;
|
||||
CompareRHS &= Mask;
|
||||
|
||||
// If there is a base and this is a relational operator, we can only
|
||||
// compare pointers within the object in question; otherwise, the result
|
||||
// depends on where the object is located in memory.
|
||||
if (!LHSValue.Base.isNull() && E->isRelationalOp()) {
|
||||
QualType BaseTy = getType(LHSValue.Base);
|
||||
if (BaseTy->isIncompleteType())
|
||||
return Error(E);
|
||||
CharUnits Size = Info.Ctx.getTypeSizeInChars(BaseTy);
|
||||
uint64_t OffsetLimit = Size.getQuantity();
|
||||
if (CompareLHS > OffsetLimit || CompareRHS > OffsetLimit)
|
||||
return Error(E);
|
||||
}
|
||||
|
||||
switch (E->getOpcode()) {
|
||||
default: llvm_unreachable("missing comparison operator");
|
||||
case BO_LT: return Success(LHSOffset < RHSOffset, E);
|
||||
case BO_GT: return Success(LHSOffset > RHSOffset, E);
|
||||
case BO_LE: return Success(LHSOffset <= RHSOffset, E);
|
||||
case BO_GE: return Success(LHSOffset >= RHSOffset, E);
|
||||
case BO_EQ: return Success(LHSOffset == RHSOffset, E);
|
||||
case BO_NE: return Success(LHSOffset != RHSOffset, E);
|
||||
case BO_LT: return Success(CompareLHS < CompareRHS, E);
|
||||
case BO_GT: return Success(CompareLHS > CompareRHS, E);
|
||||
case BO_LE: return Success(CompareLHS <= CompareRHS, E);
|
||||
case BO_GE: return Success(CompareLHS >= CompareRHS, E);
|
||||
case BO_EQ: return Success(CompareLHS == CompareRHS, E);
|
||||
case BO_NE: return Success(CompareLHS != CompareRHS, E);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -49,6 +49,9 @@ ExternalASTSource::FindExternalVisibleDeclsByName(const DeclContext *DC,
|
||||
return DeclContext::lookup_result();
|
||||
}
|
||||
|
||||
void ExternalASTSource::completeVisibleDeclsMap(const DeclContext *DC) {
|
||||
}
|
||||
|
||||
ExternalLoadResult
|
||||
ExternalASTSource::FindExternalLexicalDecls(const DeclContext *DC,
|
||||
bool (*isKindWeWant)(Decl::Kind),
|
||||
|
@ -2280,9 +2280,7 @@ void CXXNameMangler::mangleIntegerLiteral(QualType T,
|
||||
|
||||
}
|
||||
|
||||
/// Mangles a member expression. Implicit accesses are not handled,
|
||||
/// but that should be okay, because you shouldn't be able to
|
||||
/// make an implicit access in a function template declaration.
|
||||
/// Mangles a member expression.
|
||||
void CXXNameMangler::mangleMemberExpr(const Expr *base,
|
||||
bool isArrow,
|
||||
NestedNameSpecifier *qualifier,
|
||||
@ -2291,8 +2289,17 @@ void CXXNameMangler::mangleMemberExpr(const Expr *base,
|
||||
unsigned arity) {
|
||||
// <expression> ::= dt <expression> <unresolved-name>
|
||||
// ::= pt <expression> <unresolved-name>
|
||||
Out << (isArrow ? "pt" : "dt");
|
||||
mangleExpression(base);
|
||||
if (base) {
|
||||
if (base->isImplicitCXXThis()) {
|
||||
// Note: GCC mangles member expressions to the implicit 'this' as
|
||||
// *this., whereas we represent them as this->. The Itanium C++ ABI
|
||||
// does not specify anything here, so we follow GCC.
|
||||
Out << "dtdefpT";
|
||||
} else {
|
||||
Out << (isArrow ? "pt" : "dt");
|
||||
mangleExpression(base);
|
||||
}
|
||||
}
|
||||
mangleUnresolvedName(qualifier, firstQualifierLookup, member, arity);
|
||||
}
|
||||
|
||||
@ -2346,6 +2353,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
|
||||
// <expr-primary> ::= L <type> <value number> E # integer literal
|
||||
// ::= L <type <value float> E # floating literal
|
||||
// ::= L <mangled-name> E # external name
|
||||
// ::= fpT # 'this' expression
|
||||
QualType ImplicitlyConvertedToType;
|
||||
|
||||
recurse:
|
||||
@ -2361,7 +2369,6 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
|
||||
// These all can only appear in local or variable-initialization
|
||||
// contexts and so should never appear in a mangling.
|
||||
case Expr::AddrLabelExprClass:
|
||||
case Expr::CXXThisExprClass:
|
||||
case Expr::DesignatedInitExprClass:
|
||||
case Expr::ImplicitValueInitExprClass:
|
||||
case Expr::ParenListExprClass:
|
||||
@ -2919,6 +2926,10 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
|
||||
mangleExpression(cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr());
|
||||
break;
|
||||
}
|
||||
|
||||
case Expr::CXXThisExprClass:
|
||||
Out << "fpT";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -97,8 +97,8 @@ Stmt *Stmt::IgnoreImplicit() {
|
||||
|
||||
/// \brief Strip off all label-like statements.
|
||||
///
|
||||
/// This will strip off label statements, case statements, and default
|
||||
/// statements recursively.
|
||||
/// This will strip off label statements, case statements, attributed
|
||||
/// statements and default statements recursively.
|
||||
const Stmt *Stmt::stripLabelLikeStatements() const {
|
||||
const Stmt *S = this;
|
||||
while (true) {
|
||||
@ -106,6 +106,8 @@ const Stmt *Stmt::stripLabelLikeStatements() const {
|
||||
S = LS->getSubStmt();
|
||||
else if (const SwitchCase *SC = dyn_cast<SwitchCase>(S))
|
||||
S = SC->getSubStmt();
|
||||
else if (const AttributedStmt *AS = dyn_cast<AttributedStmt>(S))
|
||||
S = AS->getSubStmt();
|
||||
else
|
||||
return S;
|
||||
}
|
||||
|
@ -169,6 +169,23 @@ void StmtPrinter::VisitLabelStmt(LabelStmt *Node) {
|
||||
PrintStmt(Node->getSubStmt(), 0);
|
||||
}
|
||||
|
||||
void StmtPrinter::VisitAttributedStmt(AttributedStmt *Node) {
|
||||
OS << "[[";
|
||||
bool first = true;
|
||||
for (AttrVec::const_iterator it = Node->getAttrs().begin(),
|
||||
end = Node->getAttrs().end();
|
||||
it != end; ++it) {
|
||||
if (!first) {
|
||||
OS << ", ";
|
||||
first = false;
|
||||
}
|
||||
// TODO: check this
|
||||
(*it)->printPretty(OS, Context);
|
||||
}
|
||||
OS << "]] ";
|
||||
PrintStmt(Node->getSubStmt(), 0);
|
||||
}
|
||||
|
||||
void StmtPrinter::PrintRawIfStmt(IfStmt *If) {
|
||||
OS << "if (";
|
||||
PrintExpr(If->getCond());
|
||||
|
@ -109,6 +109,11 @@ void StmtProfiler::VisitLabelStmt(const LabelStmt *S) {
|
||||
VisitDecl(S->getDecl());
|
||||
}
|
||||
|
||||
void StmtProfiler::VisitAttributedStmt(const AttributedStmt *S) {
|
||||
VisitStmt(S);
|
||||
// TODO: maybe visit attributes?
|
||||
}
|
||||
|
||||
void StmtProfiler::VisitIfStmt(const IfStmt *S) {
|
||||
VisitStmt(S);
|
||||
VisitDecl(S->getConditionVariable());
|
||||
@ -758,6 +763,7 @@ void StmtProfiler::VisitCXXUuidofExpr(const CXXUuidofExpr *S) {
|
||||
|
||||
void StmtProfiler::VisitCXXThisExpr(const CXXThisExpr *S) {
|
||||
VisitExpr(S);
|
||||
ID.AddBoolean(S->isImplicit());
|
||||
}
|
||||
|
||||
void StmtProfiler::VisitCXXThrowExpr(const CXXThrowExpr *S) {
|
||||
|
@ -1546,6 +1546,14 @@ FunctionProtoType::FunctionProtoType(QualType result, const QualType *args,
|
||||
else if (epi.NoexceptExpr->isInstantiationDependent())
|
||||
setInstantiationDependent();
|
||||
}
|
||||
} else if (getExceptionSpecType() == EST_Uninstantiated) {
|
||||
// Store the function decl from which we will resolve our
|
||||
// exception specification.
|
||||
FunctionDecl **slot = reinterpret_cast<FunctionDecl**>(argSlot + numArgs);
|
||||
slot[0] = epi.ExceptionSpecDecl;
|
||||
slot[1] = epi.ExceptionSpecTemplate;
|
||||
// This exception specification doesn't make the type dependent, because
|
||||
// it's not instantiated as part of instantiating the type.
|
||||
}
|
||||
|
||||
if (epi.ConsumedArguments) {
|
||||
@ -1629,6 +1637,8 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
|
||||
ID.AddPointer(epi.Exceptions[i].getAsOpaquePtr());
|
||||
} else if (epi.ExceptionSpecType == EST_ComputedNoexcept && epi.NoexceptExpr){
|
||||
epi.NoexceptExpr->Profile(ID, Context, false);
|
||||
} else if (epi.ExceptionSpecType == EST_Uninstantiated) {
|
||||
ID.AddPointer(epi.ExceptionSpecDecl->getCanonicalDecl());
|
||||
}
|
||||
if (epi.ConsumedArguments) {
|
||||
for (unsigned i = 0; i != NumArgs; ++i)
|
||||
|
@ -2157,13 +2157,12 @@ VTableLayout::VTableLayout(uint64_t NumVTableComponents,
|
||||
VTableThunks(new VTableThunkTy[NumVTableThunks]),
|
||||
AddressPoints(AddressPoints) {
|
||||
std::copy(VTableComponents, VTableComponents+NumVTableComponents,
|
||||
this->VTableComponents);
|
||||
std::copy(VTableThunks, VTableThunks+NumVTableThunks, this->VTableThunks);
|
||||
this->VTableComponents.get());
|
||||
std::copy(VTableThunks, VTableThunks+NumVTableThunks,
|
||||
this->VTableThunks.get());
|
||||
}
|
||||
|
||||
VTableLayout::~VTableLayout() {
|
||||
delete[] VTableComponents;
|
||||
}
|
||||
VTableLayout::~VTableLayout() { }
|
||||
|
||||
VTableContext::~VTableContext() {
|
||||
llvm::DeleteContainerSeconds(VTableLayouts);
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "clang/AST/StmtVisitor.h"
|
||||
#include "clang/AST/PrettyPrinter.h"
|
||||
#include "clang/AST/CharUnits.h"
|
||||
#include "clang/Basic/AttrKinds.h"
|
||||
#include "llvm/Support/GraphWriter.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/Support/Format.h"
|
||||
@ -1069,6 +1070,9 @@ CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) {
|
||||
case Stmt::LambdaExprClass:
|
||||
return VisitLambdaExpr(cast<LambdaExpr>(S), asc);
|
||||
|
||||
case Stmt::AttributedStmtClass:
|
||||
return Visit(cast<AttributedStmt>(S)->getSubStmt(), asc);
|
||||
|
||||
case Stmt::MemberExprClass:
|
||||
return VisitMemberExpr(cast<MemberExpr>(S), asc);
|
||||
|
||||
@ -1280,7 +1284,8 @@ static bool CanThrow(Expr *E, ASTContext &Ctx) {
|
||||
const FunctionType *FT = Ty->getAs<FunctionType>();
|
||||
if (FT) {
|
||||
if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FT))
|
||||
if (Proto->isNothrow(Ctx))
|
||||
if (Proto->getExceptionSpecType() != EST_Uninstantiated &&
|
||||
Proto->isNothrow(Ctx))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -1,4 +1,4 @@
|
||||
set(LLVM_USED_LIBS clangBasic clangAST clangIndex)
|
||||
set(LLVM_USED_LIBS clangBasic clangAST)
|
||||
|
||||
add_clang_library(clangAnalysis
|
||||
AnalysisDeclContext.cpp
|
||||
|
@ -58,6 +58,7 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) {
|
||||
Char32Type = UnsignedInt;
|
||||
Int64Type = SignedLongLong;
|
||||
SigAtomicType = SignedInt;
|
||||
UseSignedCharForObjCBool = true;
|
||||
UseBitFieldTypeAlignment = true;
|
||||
UseZeroLengthBitfieldAlignment = false;
|
||||
ZeroLengthBitfieldBoundary = 0;
|
||||
|
@ -365,7 +365,7 @@ class OpenBSDTargetInfo : public OSTargetInfo<Target> {
|
||||
DefineStd(Builder, "unix", Opts);
|
||||
Builder.defineMacro("__ELF__");
|
||||
if (Opts.POSIXThreads)
|
||||
Builder.defineMacro("_POSIX_THREADS");
|
||||
Builder.defineMacro("_REENTRANT");
|
||||
}
|
||||
public:
|
||||
OpenBSDTargetInfo(const std::string &triple)
|
||||
@ -3546,7 +3546,10 @@ class MipsTargetInfoBase : public TargetInfo {
|
||||
virtual bool setFeatureEnabled(llvm::StringMap<bool> &Features,
|
||||
StringRef Name,
|
||||
bool Enabled) const {
|
||||
if (Name == "soft-float" || Name == "single-float") {
|
||||
if (Name == "soft-float" || Name == "single-float" ||
|
||||
Name == "o32" || Name == "n32" || Name == "n64" || Name == "eabi" ||
|
||||
Name == "mips32" || Name == "mips32r2" ||
|
||||
Name == "mips64" || Name == "mips64r2") {
|
||||
Features[Name] = Enabled;
|
||||
return true;
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ std::string getClangRepositoryPath() {
|
||||
|
||||
// If the SVN_REPOSITORY is empty, try to use the SVN keyword. This helps us
|
||||
// pick up a tag in an SVN export, for example.
|
||||
static StringRef SVNRepository("$URL: http://llvm.org/svn/llvm-project/cfe/trunk/lib/Basic/Version.cpp $");
|
||||
static StringRef SVNRepository("$URL: http://llvm.org/svn/llvm-project/cfe/branches/release_31/lib/Basic/Version.cpp $");
|
||||
if (URL.empty()) {
|
||||
URL = SVNRepository.slice(SVNRepository.find(':'),
|
||||
SVNRepository.find("/lib/Basic"));
|
||||
|
@ -14,5 +14,4 @@ add_subdirectory(Serialization)
|
||||
add_subdirectory(Frontend)
|
||||
add_subdirectory(FrontendTool)
|
||||
add_subdirectory(Tooling)
|
||||
add_subdirectory(Index)
|
||||
add_subdirectory(StaticAnalyzer)
|
||||
|
@ -491,6 +491,8 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF,
|
||||
/// a full-expression so that the block's cleanups are pushed at the
|
||||
/// right place in the stack.
|
||||
static void enterBlockScope(CodeGenFunction &CGF, BlockDecl *block) {
|
||||
assert(CGF.HaveInsertPoint());
|
||||
|
||||
// Allocate the block info and place it at the head of the list.
|
||||
CGBlockInfo &blockInfo =
|
||||
*new CGBlockInfo(block, CGF.CurFn->getName());
|
||||
|
@ -419,16 +419,37 @@ void CodeGenTypes::GetExpandedTypes(QualType type,
|
||||
uint64_t NumElts = AT->getSize().getZExtValue();
|
||||
for (uint64_t Elt = 0; Elt < NumElts; ++Elt)
|
||||
GetExpandedTypes(AT->getElementType(), expandedTypes);
|
||||
} else if (const RecordType *RT = type->getAsStructureType()) {
|
||||
} else if (const RecordType *RT = type->getAs<RecordType>()) {
|
||||
const RecordDecl *RD = RT->getDecl();
|
||||
assert(!RD->hasFlexibleArrayMember() &&
|
||||
"Cannot expand structure with flexible array.");
|
||||
for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
|
||||
i != e; ++i) {
|
||||
const FieldDecl *FD = *i;
|
||||
assert(!FD->isBitField() &&
|
||||
"Cannot expand structure with bit-field members.");
|
||||
GetExpandedTypes(FD->getType(), expandedTypes);
|
||||
if (RD->isUnion()) {
|
||||
// Unions can be here only in degenerative cases - all the fields are same
|
||||
// after flattening. Thus we have to use the "largest" field.
|
||||
const FieldDecl *LargestFD = 0;
|
||||
CharUnits UnionSize = CharUnits::Zero();
|
||||
|
||||
for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
|
||||
i != e; ++i) {
|
||||
const FieldDecl *FD = *i;
|
||||
assert(!FD->isBitField() &&
|
||||
"Cannot expand structure with bit-field members.");
|
||||
CharUnits FieldSize = getContext().getTypeSizeInChars(FD->getType());
|
||||
if (UnionSize < FieldSize) {
|
||||
UnionSize = FieldSize;
|
||||
LargestFD = FD;
|
||||
}
|
||||
}
|
||||
if (LargestFD)
|
||||
GetExpandedTypes(LargestFD->getType(), expandedTypes);
|
||||
} else {
|
||||
for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
|
||||
i != e; ++i) {
|
||||
const FieldDecl *FD = *i;
|
||||
assert(!FD->isBitField() &&
|
||||
"Cannot expand structure with bit-field members.");
|
||||
GetExpandedTypes(FD->getType(), expandedTypes);
|
||||
}
|
||||
}
|
||||
} else if (const ComplexType *CT = type->getAs<ComplexType>()) {
|
||||
llvm::Type *EltTy = ConvertType(CT->getElementType());
|
||||
@ -443,32 +464,55 @@ CodeGenFunction::ExpandTypeFromArgs(QualType Ty, LValue LV,
|
||||
llvm::Function::arg_iterator AI) {
|
||||
assert(LV.isSimple() &&
|
||||
"Unexpected non-simple lvalue during struct expansion.");
|
||||
llvm::Value *Addr = LV.getAddress();
|
||||
|
||||
if (const ConstantArrayType *AT = getContext().getAsConstantArrayType(Ty)) {
|
||||
unsigned NumElts = AT->getSize().getZExtValue();
|
||||
QualType EltTy = AT->getElementType();
|
||||
for (unsigned Elt = 0; Elt < NumElts; ++Elt) {
|
||||
llvm::Value *EltAddr = Builder.CreateConstGEP2_32(Addr, 0, Elt);
|
||||
llvm::Value *EltAddr = Builder.CreateConstGEP2_32(LV.getAddress(), 0, Elt);
|
||||
LValue LV = MakeAddrLValue(EltAddr, EltTy);
|
||||
AI = ExpandTypeFromArgs(EltTy, LV, AI);
|
||||
}
|
||||
} else if (const RecordType *RT = Ty->getAsStructureType()) {
|
||||
} else if (const RecordType *RT = Ty->getAs<RecordType>()) {
|
||||
RecordDecl *RD = RT->getDecl();
|
||||
for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
|
||||
i != e; ++i) {
|
||||
FieldDecl *FD = *i;
|
||||
QualType FT = FD->getType();
|
||||
if (RD->isUnion()) {
|
||||
// Unions can be here only in degenerative cases - all the fields are same
|
||||
// after flattening. Thus we have to use the "largest" field.
|
||||
const FieldDecl *LargestFD = 0;
|
||||
CharUnits UnionSize = CharUnits::Zero();
|
||||
|
||||
// FIXME: What are the right qualifiers here?
|
||||
LValue LV = EmitLValueForField(Addr, FD, 0);
|
||||
AI = ExpandTypeFromArgs(FT, LV, AI);
|
||||
for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
|
||||
i != e; ++i) {
|
||||
const FieldDecl *FD = *i;
|
||||
assert(!FD->isBitField() &&
|
||||
"Cannot expand structure with bit-field members.");
|
||||
CharUnits FieldSize = getContext().getTypeSizeInChars(FD->getType());
|
||||
if (UnionSize < FieldSize) {
|
||||
UnionSize = FieldSize;
|
||||
LargestFD = FD;
|
||||
}
|
||||
}
|
||||
if (LargestFD) {
|
||||
// FIXME: What are the right qualifiers here?
|
||||
LValue SubLV = EmitLValueForField(LV, LargestFD);
|
||||
AI = ExpandTypeFromArgs(LargestFD->getType(), SubLV, AI);
|
||||
}
|
||||
} else {
|
||||
for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
|
||||
i != e; ++i) {
|
||||
FieldDecl *FD = *i;
|
||||
QualType FT = FD->getType();
|
||||
|
||||
// FIXME: What are the right qualifiers here?
|
||||
LValue SubLV = EmitLValueForField(LV, FD);
|
||||
AI = ExpandTypeFromArgs(FT, SubLV, AI);
|
||||
}
|
||||
}
|
||||
} else if (const ComplexType *CT = Ty->getAs<ComplexType>()) {
|
||||
QualType EltTy = CT->getElementType();
|
||||
llvm::Value *RealAddr = Builder.CreateStructGEP(Addr, 0, "real");
|
||||
llvm::Value *RealAddr = Builder.CreateStructGEP(LV.getAddress(), 0, "real");
|
||||
EmitStoreThroughLValue(RValue::get(AI++), MakeAddrLValue(RealAddr, EltTy));
|
||||
llvm::Value *ImagAddr = Builder.CreateStructGEP(Addr, 1, "imag");
|
||||
llvm::Value *ImagAddr = Builder.CreateStructGEP(LV.getAddress(), 1, "imag");
|
||||
EmitStoreThroughLValue(RValue::get(AI++), MakeAddrLValue(ImagAddr, EltTy));
|
||||
} else {
|
||||
EmitStoreThroughLValue(RValue::get(AI), LV);
|
||||
@ -1760,26 +1804,38 @@ void CodeGenFunction::ExpandTypeToArgs(QualType Ty, RValue RV,
|
||||
EltRV = EmitLoadOfLValue(LV);
|
||||
ExpandTypeToArgs(EltTy, EltRV, Args, IRFuncTy);
|
||||
}
|
||||
} else if (const RecordType *RT = Ty->getAsStructureType()) {
|
||||
} else if (const RecordType *RT = Ty->getAs<RecordType>()) {
|
||||
RecordDecl *RD = RT->getDecl();
|
||||
assert(RV.isAggregate() && "Unexpected rvalue during struct expansion");
|
||||
llvm::Value *Addr = RV.getAggregateAddr();
|
||||
for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
|
||||
i != e; ++i) {
|
||||
FieldDecl *FD = *i;
|
||||
QualType FT = FD->getType();
|
||||
LValue LV = MakeAddrLValue(RV.getAggregateAddr(), Ty);
|
||||
|
||||
// FIXME: What are the right qualifiers here?
|
||||
LValue LV = EmitLValueForField(Addr, FD, 0);
|
||||
RValue FldRV;
|
||||
if (FT->isAnyComplexType())
|
||||
// FIXME: Volatile?
|
||||
FldRV = RValue::getComplex(LoadComplexFromAddr(LV.getAddress(), false));
|
||||
else if (CodeGenFunction::hasAggregateLLVMType(FT))
|
||||
FldRV = LV.asAggregateRValue();
|
||||
else
|
||||
FldRV = EmitLoadOfLValue(LV);
|
||||
ExpandTypeToArgs(FT, FldRV, Args, IRFuncTy);
|
||||
if (RD->isUnion()) {
|
||||
const FieldDecl *LargestFD = 0;
|
||||
CharUnits UnionSize = CharUnits::Zero();
|
||||
|
||||
for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
|
||||
i != e; ++i) {
|
||||
const FieldDecl *FD = *i;
|
||||
assert(!FD->isBitField() &&
|
||||
"Cannot expand structure with bit-field members.");
|
||||
CharUnits FieldSize = getContext().getTypeSizeInChars(FD->getType());
|
||||
if (UnionSize < FieldSize) {
|
||||
UnionSize = FieldSize;
|
||||
LargestFD = FD;
|
||||
}
|
||||
}
|
||||
if (LargestFD) {
|
||||
RValue FldRV = EmitRValueForField(LV, LargestFD);
|
||||
ExpandTypeToArgs(LargestFD->getType(), FldRV, Args, IRFuncTy);
|
||||
}
|
||||
} else {
|
||||
for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
|
||||
i != e; ++i) {
|
||||
FieldDecl *FD = *i;
|
||||
|
||||
RValue FldRV = EmitRValueForField(LV, FD);
|
||||
ExpandTypeToArgs(FD->getType(), FldRV, Args, IRFuncTy);
|
||||
}
|
||||
}
|
||||
} else if (Ty->isAnyComplexType()) {
|
||||
ComplexPairTy CV = RV.getComplexVal();
|
||||
|
@ -555,6 +555,7 @@ static void EmitMemberInitializer(CodeGenFunction &CGF,
|
||||
QualType FieldType = Field->getType();
|
||||
|
||||
llvm::Value *ThisPtr = CGF.LoadCXXThis();
|
||||
QualType RecordTy = CGF.getContext().getTypeDeclType(ClassDecl);
|
||||
LValue LHS;
|
||||
|
||||
// If we are initializing an anonymous union field, drill down to the field.
|
||||
@ -563,7 +564,8 @@ static void EmitMemberInitializer(CodeGenFunction &CGF,
|
||||
MemberInit->getIndirectMember(), 0);
|
||||
FieldType = MemberInit->getIndirectMember()->getAnonField()->getType();
|
||||
} else {
|
||||
LHS = CGF.EmitLValueForFieldInitialization(ThisPtr, Field, 0);
|
||||
LValue ThisLHSLV = CGF.MakeNaturalAlignAddrLValue(ThisPtr, RecordTy);
|
||||
LHS = CGF.EmitLValueForFieldInitialization(ThisLHSLV, Field);
|
||||
}
|
||||
|
||||
// Special case: if we are in a copy or move constructor, and we are copying
|
||||
@ -585,7 +587,8 @@ static void EmitMemberInitializer(CodeGenFunction &CGF,
|
||||
unsigned SrcArgIndex = Args.size() - 1;
|
||||
llvm::Value *SrcPtr
|
||||
= CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(Args[SrcArgIndex]));
|
||||
LValue Src = CGF.EmitLValueForFieldInitialization(SrcPtr, Field, 0);
|
||||
LValue ThisRHSLV = CGF.MakeNaturalAlignAddrLValue(SrcPtr, RecordTy);
|
||||
LValue Src = CGF.EmitLValueForFieldInitialization(ThisRHSLV, Field);
|
||||
|
||||
// Copy the aggregate.
|
||||
CGF.EmitAggregateCopy(LHS.getAddress(), Src.getAddress(), FieldType,
|
||||
@ -978,7 +981,9 @@ namespace {
|
||||
void Emit(CodeGenFunction &CGF, Flags flags) {
|
||||
// Find the address of the field.
|
||||
llvm::Value *thisValue = CGF.LoadCXXThis();
|
||||
LValue LV = CGF.EmitLValueForField(thisValue, field, /*CVRQualifiers=*/0);
|
||||
QualType RecordTy = CGF.getContext().getTagDeclType(field->getParent());
|
||||
LValue ThisLV = CGF.MakeAddrLValue(thisValue, RecordTy);
|
||||
LValue LV = CGF.EmitLValueForField(ThisLV, field);
|
||||
assert(LV.isSimple());
|
||||
|
||||
CGF.emitDestroy(LV.getAddress(), field->getType(), destroyer,
|
||||
|
@ -184,7 +184,6 @@ CGDebugInfo::getClassName(const RecordDecl *RD) {
|
||||
|
||||
const TemplateArgument *Args;
|
||||
unsigned NumArgs;
|
||||
std::string Buffer;
|
||||
if (TypeSourceInfo *TAW = Spec->getTypeAsWritten()) {
|
||||
const TemplateSpecializationType *TST =
|
||||
cast<TemplateSpecializationType>(TAW->getType());
|
||||
@ -195,16 +194,17 @@ CGDebugInfo::getClassName(const RecordDecl *RD) {
|
||||
Args = TemplateArgs.data();
|
||||
NumArgs = TemplateArgs.size();
|
||||
}
|
||||
Buffer = RD->getIdentifier()->getNameStart();
|
||||
StringRef Name = RD->getIdentifier()->getName();
|
||||
PrintingPolicy Policy(CGM.getLangOpts());
|
||||
Buffer += TemplateSpecializationType::PrintTemplateArgumentList(Args,
|
||||
NumArgs,
|
||||
Policy);
|
||||
std::string TemplateArgList =
|
||||
TemplateSpecializationType::PrintTemplateArgumentList(Args, NumArgs, Policy);
|
||||
|
||||
// Copy this name on the side and use its reference.
|
||||
char *StrPtr = DebugInfoNames.Allocate<char>(Buffer.length());
|
||||
memcpy(StrPtr, Buffer.data(), Buffer.length());
|
||||
return StringRef(StrPtr, Buffer.length());
|
||||
size_t Length = Name.size() + TemplateArgList.size();
|
||||
char *StrPtr = DebugInfoNames.Allocate<char>(Length);
|
||||
memcpy(StrPtr, Name.data(), Name.size());
|
||||
memcpy(StrPtr + Name.size(), TemplateArgList.data(), TemplateArgList.size());
|
||||
return StringRef(StrPtr, Length);
|
||||
}
|
||||
|
||||
/// getOrCreateFile - Get the file debug info descriptor for the input location.
|
||||
|
@ -1171,6 +1171,10 @@ void CodeGenFunction::EmitAutoVarCleanups(const AutoVarEmission &emission) {
|
||||
// If this was emitted as a global constant, we're done.
|
||||
if (emission.wasEmittedAsGlobal()) return;
|
||||
|
||||
// If we don't have an insertion point, we're done. Sema prevents
|
||||
// us from jumping into any of these scopes anyway.
|
||||
if (!HaveInsertPoint()) return;
|
||||
|
||||
const VarDecl &D = *emission.Variable;
|
||||
|
||||
// Check the type for a cleanup.
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "clang/Frontend/CodeGenOptions.h"
|
||||
#include "llvm/Intrinsics.h"
|
||||
#include "llvm/LLVMContext.h"
|
||||
#include "llvm/Support/MDBuilder.h"
|
||||
#include "llvm/Target/TargetData.h"
|
||||
using namespace clang;
|
||||
using namespace CodeGen;
|
||||
@ -398,8 +399,8 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E,
|
||||
break;
|
||||
|
||||
case SubobjectAdjustment::FieldAdjustment: {
|
||||
LValue LV =
|
||||
CGF.EmitLValueForField(Object, Adjustment.Field, 0);
|
||||
LValue LV = CGF.MakeAddrLValue(Object, E->getType());
|
||||
LV = CGF.EmitLValueForField(LV, Adjustment.Field);
|
||||
if (LV.isSimple()) {
|
||||
Object = LV.getAddress();
|
||||
break;
|
||||
@ -908,16 +909,8 @@ llvm::MDNode *CodeGenFunction::getRangeForLoadFromType(QualType Ty) {
|
||||
}
|
||||
}
|
||||
|
||||
if (End == Min)
|
||||
return NULL;
|
||||
|
||||
llvm::Value *LowAndHigh[2];
|
||||
LowAndHigh[0] = llvm::ConstantInt::get(LTy, Min);
|
||||
LowAndHigh[1] = llvm::ConstantInt::get(LTy, End);
|
||||
|
||||
llvm::LLVMContext &C = getLLVMContext();
|
||||
llvm::MDNode *Range = llvm::MDNode::get(C, LowAndHigh);
|
||||
return Range;
|
||||
llvm::MDBuilder MDHelper(getLLVMContext());
|
||||
return MDHelper.createRange(Min, End);
|
||||
}
|
||||
|
||||
llvm::Value *CodeGenFunction::EmitLoadOfScalar(llvm::Value *Addr, bool Volatile,
|
||||
@ -1577,8 +1570,12 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
|
||||
|
||||
// Use special handling for lambdas.
|
||||
if (!V) {
|
||||
if (FieldDecl *FD = LambdaCaptureFields.lookup(VD))
|
||||
return EmitLValueForField(CXXABIThisValue, FD, 0);
|
||||
if (FieldDecl *FD = LambdaCaptureFields.lookup(VD)) {
|
||||
QualType LambdaTagType = getContext().getTagDeclType(FD->getParent());
|
||||
LValue LambdaLV = MakeNaturalAlignAddrLValue(CXXABIThisValue,
|
||||
LambdaTagType);
|
||||
return EmitLValueForField(LambdaLV, FD);
|
||||
}
|
||||
|
||||
assert(isa<BlockDecl>(CurCodeDecl) && E->refersToEnclosingLocal());
|
||||
CharUnits alignment = getContext().getDeclAlign(VD);
|
||||
@ -1973,32 +1970,19 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) {
|
||||
}
|
||||
|
||||
LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) {
|
||||
bool isNonGC = false;
|
||||
Expr *BaseExpr = E->getBase();
|
||||
llvm::Value *BaseValue = NULL;
|
||||
Qualifiers BaseQuals;
|
||||
|
||||
// If this is s.x, emit s as an lvalue. If it is s->x, emit s as a scalar.
|
||||
if (E->isArrow()) {
|
||||
BaseValue = EmitScalarExpr(BaseExpr);
|
||||
const PointerType *PTy =
|
||||
BaseExpr->getType()->getAs<PointerType>();
|
||||
BaseQuals = PTy->getPointeeType().getQualifiers();
|
||||
} else {
|
||||
LValue BaseLV = EmitLValue(BaseExpr);
|
||||
if (BaseLV.isNonGC())
|
||||
isNonGC = true;
|
||||
// FIXME: this isn't right for bitfields.
|
||||
BaseValue = BaseLV.getAddress();
|
||||
QualType BaseTy = BaseExpr->getType();
|
||||
BaseQuals = BaseTy.getQualifiers();
|
||||
}
|
||||
LValue BaseLV;
|
||||
if (E->isArrow())
|
||||
BaseLV = MakeNaturalAlignAddrLValue(EmitScalarExpr(BaseExpr),
|
||||
BaseExpr->getType()->getPointeeType());
|
||||
else
|
||||
BaseLV = EmitLValue(BaseExpr);
|
||||
|
||||
NamedDecl *ND = E->getMemberDecl();
|
||||
if (FieldDecl *Field = dyn_cast<FieldDecl>(ND)) {
|
||||
LValue LV = EmitLValueForField(BaseValue, Field,
|
||||
BaseQuals.getCVRQualifiers());
|
||||
LV.setNonGC(isNonGC);
|
||||
LValue LV = EmitLValueForField(BaseLV, Field);
|
||||
setObjCGCLValueClass(getContext(), E, LV);
|
||||
return LV;
|
||||
}
|
||||
@ -2032,8 +2016,10 @@ LValue CodeGenFunction::EmitLValueForAnonRecordField(llvm::Value *BaseValue,
|
||||
IndirectFieldDecl::chain_iterator I = Field->chain_begin(),
|
||||
IEnd = Field->chain_end();
|
||||
while (true) {
|
||||
LValue LV = EmitLValueForField(BaseValue, cast<FieldDecl>(*I),
|
||||
CVRQualifiers);
|
||||
QualType RecordTy =
|
||||
getContext().getTypeDeclType(cast<FieldDecl>(*I)->getParent());
|
||||
LValue LV = EmitLValueForField(MakeAddrLValue(BaseValue, RecordTy),
|
||||
cast<FieldDecl>(*I));
|
||||
if (++I == IEnd) return LV;
|
||||
|
||||
assert(LV.isSimple());
|
||||
@ -2042,19 +2028,25 @@ LValue CodeGenFunction::EmitLValueForAnonRecordField(llvm::Value *BaseValue,
|
||||
}
|
||||
}
|
||||
|
||||
LValue CodeGenFunction::EmitLValueForField(llvm::Value *baseAddr,
|
||||
const FieldDecl *field,
|
||||
unsigned cvr) {
|
||||
LValue CodeGenFunction::EmitLValueForField(LValue base,
|
||||
const FieldDecl *field) {
|
||||
if (field->isBitField())
|
||||
return EmitLValueForBitfield(baseAddr, field, cvr);
|
||||
return EmitLValueForBitfield(base.getAddress(), field,
|
||||
base.getVRQualifiers());
|
||||
|
||||
const RecordDecl *rec = field->getParent();
|
||||
QualType type = field->getType();
|
||||
CharUnits alignment = getContext().getDeclAlign(field);
|
||||
|
||||
// FIXME: It should be impossible to have an LValue without alignment for a
|
||||
// complete type.
|
||||
if (!base.getAlignment().isZero())
|
||||
alignment = std::min(alignment, base.getAlignment());
|
||||
|
||||
bool mayAlias = rec->hasAttr<MayAliasAttr>();
|
||||
|
||||
llvm::Value *addr = baseAddr;
|
||||
llvm::Value *addr = base.getAddress();
|
||||
unsigned cvr = base.getVRQualifiers();
|
||||
if (rec->isUnion()) {
|
||||
// For unions, there is no pointer adjustment.
|
||||
assert(!type->isReferenceType() && "union has reference member");
|
||||
@ -2117,30 +2109,33 @@ LValue CodeGenFunction::EmitLValueForField(llvm::Value *baseAddr,
|
||||
}
|
||||
|
||||
LValue
|
||||
CodeGenFunction::EmitLValueForFieldInitialization(llvm::Value *BaseValue,
|
||||
const FieldDecl *Field,
|
||||
unsigned CVRQualifiers) {
|
||||
CodeGenFunction::EmitLValueForFieldInitialization(LValue Base,
|
||||
const FieldDecl *Field) {
|
||||
QualType FieldType = Field->getType();
|
||||
|
||||
if (!FieldType->isReferenceType())
|
||||
return EmitLValueForField(BaseValue, Field, CVRQualifiers);
|
||||
return EmitLValueForField(Base, Field);
|
||||
|
||||
const CGRecordLayout &RL =
|
||||
CGM.getTypes().getCGRecordLayout(Field->getParent());
|
||||
unsigned idx = RL.getLLVMFieldNo(Field);
|
||||
llvm::Value *V = Builder.CreateStructGEP(BaseValue, idx);
|
||||
llvm::Value *V = Builder.CreateStructGEP(Base.getAddress(), idx);
|
||||
assert(!FieldType.getObjCGCAttr() && "fields cannot have GC attrs");
|
||||
|
||||
|
||||
// Make sure that the address is pointing to the right type. This is critical
|
||||
// for both unions and structs. A union needs a bitcast, a struct element
|
||||
// will need a bitcast if the LLVM type laid out doesn't match the desired
|
||||
// type.
|
||||
llvm::Type *llvmType = ConvertTypeForMem(FieldType);
|
||||
unsigned AS = cast<llvm::PointerType>(V->getType())->getAddressSpace();
|
||||
V = Builder.CreateBitCast(V, llvmType->getPointerTo(AS));
|
||||
V = EmitBitCastOfLValueToProperType(*this, V, llvmType, Field->getName());
|
||||
|
||||
CharUnits Alignment = getContext().getDeclAlign(Field);
|
||||
|
||||
// FIXME: It should be impossible to have an LValue without alignment for a
|
||||
// complete type.
|
||||
if (!Base.getAlignment().isZero())
|
||||
Alignment = std::min(Alignment, Base.getAlignment());
|
||||
|
||||
return MakeAddrLValue(V, FieldType, Alignment);
|
||||
}
|
||||
|
||||
@ -2378,6 +2373,19 @@ LValue CodeGenFunction::EmitMaterializeTemporaryExpr(
|
||||
return MakeAddrLValue(RV.getScalarVal(), E->getType());
|
||||
}
|
||||
|
||||
RValue CodeGenFunction::EmitRValueForField(LValue LV,
|
||||
const FieldDecl *FD) {
|
||||
QualType FT = FD->getType();
|
||||
LValue FieldLV = EmitLValueForField(LV, FD);
|
||||
if (FT->isAnyComplexType())
|
||||
return RValue::getComplex(
|
||||
LoadComplexFromAddr(FieldLV.getAddress(),
|
||||
FieldLV.isVolatileQualified()));
|
||||
else if (CodeGenFunction::hasAggregateLLVMType(FT))
|
||||
return FieldLV.asAggregateRValue();
|
||||
|
||||
return EmitLoadOfLValue(FieldLV);
|
||||
}
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Expression Emission
|
||||
@ -3158,11 +3166,10 @@ void CodeGenFunction::SetFPAccuracy(llvm::Value *Val, float Accuracy) {
|
||||
if (Accuracy == 0.0 || !isa<llvm::Instruction>(Val))
|
||||
return;
|
||||
|
||||
llvm::Value *ULPs = llvm::ConstantFP::get(Builder.getFloatTy(), Accuracy);
|
||||
llvm::MDNode *Node = llvm::MDNode::get(getLLVMContext(), ULPs);
|
||||
llvm::MDBuilder MDHelper(getLLVMContext());
|
||||
llvm::MDNode *Node = MDHelper.createFPMath(Accuracy);
|
||||
|
||||
cast<llvm::Instruction>(Val)->setMetadata(llvm::LLVMContext::MD_fpaccuracy,
|
||||
Node);
|
||||
cast<llvm::Instruction>(Val)->setMetadata(llvm::LLVMContext::MD_fpmath, Node);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
@ -238,7 +238,10 @@ void AggExprEmitter::EmitMoveFromReturnSlot(const Expr *E, RValue Src) {
|
||||
|
||||
// Otherwise, do a final copy,
|
||||
assert(Dest.getAddr() != Src.getAggregateAddr());
|
||||
EmitFinalDestCopy(E, Src, /*Ignore*/ true);
|
||||
std::pair<CharUnits, CharUnits> TypeInfo =
|
||||
CGF.getContext().getTypeInfoInChars(E->getType());
|
||||
CharUnits Alignment = std::min(TypeInfo.second, Dest.getAlignment());
|
||||
EmitFinalDestCopy(E, Src, /*Ignore*/ true, Alignment.getQuantity());
|
||||
}
|
||||
|
||||
/// EmitFinalDestCopy - Perform the final copy to DestPtr, if desired.
|
||||
@ -348,7 +351,8 @@ void AggExprEmitter::EmitStdInitializerList(llvm::Value *destPtr,
|
||||
CGF.ErrorUnsupported(initList, "weird std::initializer_list");
|
||||
return;
|
||||
}
|
||||
LValue start = CGF.EmitLValueForFieldInitialization(destPtr, *field, 0);
|
||||
LValue DestLV = CGF.MakeNaturalAlignAddrLValue(destPtr, initList->getType());
|
||||
LValue start = CGF.EmitLValueForFieldInitialization(DestLV, *field);
|
||||
llvm::Value *arrayStart = Builder.CreateStructGEP(alloc, 0, "arraystart");
|
||||
CGF.EmitStoreThroughLValue(RValue::get(arrayStart), start);
|
||||
++field;
|
||||
@ -357,7 +361,7 @@ void AggExprEmitter::EmitStdInitializerList(llvm::Value *destPtr,
|
||||
CGF.ErrorUnsupported(initList, "weird std::initializer_list");
|
||||
return;
|
||||
}
|
||||
LValue endOrLength = CGF.EmitLValueForFieldInitialization(destPtr, *field, 0);
|
||||
LValue endOrLength = CGF.EmitLValueForFieldInitialization(DestLV, *field);
|
||||
if (ctx.hasSameType(field->getType(), elementPtr)) {
|
||||
// End pointer.
|
||||
llvm::Value *arrayEnd = Builder.CreateStructGEP(alloc,numInits, "arrayend");
|
||||
@ -912,28 +916,24 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
|
||||
return;
|
||||
}
|
||||
|
||||
llvm::Value *DestPtr = EnsureSlot(E->getType()).getAddr();
|
||||
AggValueSlot Dest = EnsureSlot(E->getType());
|
||||
LValue DestLV = CGF.MakeAddrLValue(Dest.getAddr(), E->getType(),
|
||||
Dest.getAlignment());
|
||||
|
||||
// Handle initialization of an array.
|
||||
if (E->getType()->isArrayType()) {
|
||||
if (E->getNumInits() > 0) {
|
||||
QualType T1 = E->getType();
|
||||
QualType T2 = E->getInit(0)->getType();
|
||||
if (CGF.getContext().hasSameUnqualifiedType(T1, T2)) {
|
||||
EmitAggLoadOfLValue(E->getInit(0));
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (E->isStringLiteralInit())
|
||||
return Visit(E->getInit(0));
|
||||
|
||||
QualType elementType =
|
||||
CGF.getContext().getAsArrayType(E->getType())->getElementType();
|
||||
|
||||
llvm::PointerType *APType =
|
||||
cast<llvm::PointerType>(DestPtr->getType());
|
||||
cast<llvm::PointerType>(Dest.getAddr()->getType());
|
||||
llvm::ArrayType *AType =
|
||||
cast<llvm::ArrayType>(APType->getElementType());
|
||||
|
||||
EmitArrayInit(DestPtr, AType, elementType, E);
|
||||
EmitArrayInit(Dest.getAddr(), AType, elementType, E);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -966,7 +966,7 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
|
||||
// FIXME: volatility
|
||||
FieldDecl *Field = E->getInitializedFieldInUnion();
|
||||
|
||||
LValue FieldLoc = CGF.EmitLValueForFieldInitialization(DestPtr, Field, 0);
|
||||
LValue FieldLoc = CGF.EmitLValueForFieldInitialization(DestLV, Field);
|
||||
if (NumInitElements) {
|
||||
// Store the initializer into the field
|
||||
EmitInitializationToLValue(E->getInit(0), FieldLoc);
|
||||
@ -1004,8 +1004,8 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
|
||||
CGF.getTypes().isZeroInitializable(E->getType()))
|
||||
break;
|
||||
|
||||
// FIXME: volatility
|
||||
LValue LV = CGF.EmitLValueForFieldInitialization(DestPtr, *field, 0);
|
||||
|
||||
LValue LV = CGF.EmitLValueForFieldInitialization(DestLV, *field);
|
||||
// We never generate write-barries for initialized fields.
|
||||
LV.setNonGC(true);
|
||||
|
||||
|
@ -1815,13 +1815,16 @@ llvm::Value *CodeGenFunction::EmitDynamicCast(llvm::Value *Value,
|
||||
|
||||
void CodeGenFunction::EmitLambdaExpr(const LambdaExpr *E, AggValueSlot Slot) {
|
||||
RunCleanupsScope Scope(*this);
|
||||
LValue SlotLV = MakeAddrLValue(Slot.getAddr(), E->getType(),
|
||||
Slot.getAlignment());
|
||||
|
||||
CXXRecordDecl::field_iterator CurField = E->getLambdaClass()->field_begin();
|
||||
for (LambdaExpr::capture_init_iterator i = E->capture_init_begin(),
|
||||
e = E->capture_init_end();
|
||||
i != e; ++i, ++CurField) {
|
||||
// Emit initialization
|
||||
LValue LV = EmitLValueForFieldInitialization(Slot.getAddr(), *CurField, 0);
|
||||
|
||||
LValue LV = EmitLValueForFieldInitialization(SlotLV, *CurField);
|
||||
ArrayRef<VarDecl *> ArrayIndexes;
|
||||
if (CurField->getType()->isArrayType())
|
||||
ArrayIndexes = E->getCaptureInitIndexVars(i);
|
||||
|
@ -758,17 +758,13 @@ class ConstExprEmitter :
|
||||
}
|
||||
|
||||
llvm::Constant *EmitArrayInitialization(InitListExpr *ILE) {
|
||||
unsigned NumInitElements = ILE->getNumInits();
|
||||
if (NumInitElements == 1 &&
|
||||
CGM.getContext().hasSameUnqualifiedType(ILE->getType(),
|
||||
ILE->getInit(0)->getType()) &&
|
||||
(isa<StringLiteral>(ILE->getInit(0)) ||
|
||||
isa<ObjCEncodeExpr>(ILE->getInit(0))))
|
||||
if (ILE->isStringLiteralInit())
|
||||
return Visit(ILE->getInit(0));
|
||||
|
||||
llvm::ArrayType *AType =
|
||||
cast<llvm::ArrayType>(ConvertType(ILE->getType()));
|
||||
llvm::Type *ElemTy = AType->getElementType();
|
||||
unsigned NumInitElements = ILE->getNumInits();
|
||||
unsigned NumElements = AType->getNumElements();
|
||||
|
||||
// Initialising an array requires us to automatically
|
||||
|
@ -79,6 +79,7 @@ void CodeGenFunction::EmitStmt(const Stmt *S) {
|
||||
case Stmt::CompoundStmtClass:
|
||||
case Stmt::DeclStmtClass:
|
||||
case Stmt::LabelStmtClass:
|
||||
case Stmt::AttributedStmtClass:
|
||||
case Stmt::GotoStmtClass:
|
||||
case Stmt::BreakStmtClass:
|
||||
case Stmt::ContinueStmtClass:
|
||||
@ -173,6 +174,8 @@ bool CodeGenFunction::EmitSimpleStmt(const Stmt *S) {
|
||||
case Stmt::CompoundStmtClass: EmitCompoundStmt(cast<CompoundStmt>(*S)); break;
|
||||
case Stmt::DeclStmtClass: EmitDeclStmt(cast<DeclStmt>(*S)); break;
|
||||
case Stmt::LabelStmtClass: EmitLabelStmt(cast<LabelStmt>(*S)); break;
|
||||
case Stmt::AttributedStmtClass:
|
||||
EmitAttributedStmt(cast<AttributedStmt>(*S)); break;
|
||||
case Stmt::GotoStmtClass: EmitGotoStmt(cast<GotoStmt>(*S)); break;
|
||||
case Stmt::BreakStmtClass: EmitBreakStmt(cast<BreakStmt>(*S)); break;
|
||||
case Stmt::ContinueStmtClass: EmitContinueStmt(cast<ContinueStmt>(*S)); break;
|
||||
@ -332,6 +335,10 @@ void CodeGenFunction::EmitLabelStmt(const LabelStmt &S) {
|
||||
EmitStmt(S.getSubStmt());
|
||||
}
|
||||
|
||||
void CodeGenFunction::EmitAttributedStmt(const AttributedStmt &S) {
|
||||
EmitStmt(S.getSubStmt());
|
||||
}
|
||||
|
||||
void CodeGenFunction::EmitGotoStmt(const GotoStmt &S) {
|
||||
// If this code is reachable then emit a stop point (if generating
|
||||
// debug info). We have to do this ourselves because we are on the
|
||||
|
@ -22,8 +22,9 @@
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "clang/AST/StmtCXX.h"
|
||||
#include "clang/Frontend/CodeGenOptions.h"
|
||||
#include "llvm/Target/TargetData.h"
|
||||
#include "llvm/Intrinsics.h"
|
||||
#include "llvm/Support/MDBuilder.h"
|
||||
#include "llvm/Target/TargetData.h"
|
||||
using namespace clang;
|
||||
using namespace CodeGen;
|
||||
|
||||
@ -362,8 +363,12 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
|
||||
LambdaThisCaptureField);
|
||||
if (LambdaThisCaptureField) {
|
||||
// If this lambda captures this, load it.
|
||||
LValue ThisLValue = EmitLValueForField(CXXABIThisValue,
|
||||
LambdaThisCaptureField, 0);
|
||||
QualType LambdaTagType =
|
||||
getContext().getTagDeclType(LambdaThisCaptureField->getParent());
|
||||
LValue LambdaLV = MakeNaturalAlignAddrLValue(CXXABIThisValue,
|
||||
LambdaTagType);
|
||||
LValue ThisLValue = EmitLValueForField(LambdaLV,
|
||||
LambdaThisCaptureField);
|
||||
CXXThisValue = EmitLoadOfLValue(ThisLValue).getScalarVal();
|
||||
}
|
||||
} else {
|
||||
|
@ -1948,6 +1948,7 @@ class CodeGenFunction : public CodeGenTypeCache {
|
||||
void EmitLabel(const LabelDecl *D); // helper for EmitLabelStmt.
|
||||
|
||||
void EmitLabelStmt(const LabelStmt &S);
|
||||
void EmitAttributedStmt(const AttributedStmt &S);
|
||||
void EmitGotoStmt(const GotoStmt &S);
|
||||
void EmitIndirectGotoStmt(const IndirectGotoStmt &S);
|
||||
void EmitIfStmt(const IfStmt &S);
|
||||
@ -2104,6 +2105,8 @@ class CodeGenFunction : public CodeGenTypeCache {
|
||||
LValue EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *E);
|
||||
LValue EmitOpaqueValueLValue(const OpaqueValueExpr *e);
|
||||
|
||||
RValue EmitRValueForField(LValue LV, const FieldDecl *FD);
|
||||
|
||||
class ConstantEmission {
|
||||
llvm::PointerIntPair<llvm::Constant*, 1, bool> ValueAndIsReference;
|
||||
ConstantEmission(llvm::Constant *C, bool isReference)
|
||||
@ -2143,15 +2146,13 @@ class CodeGenFunction : public CodeGenTypeCache {
|
||||
LValue EmitLValueForAnonRecordField(llvm::Value* Base,
|
||||
const IndirectFieldDecl* Field,
|
||||
unsigned CVRQualifiers);
|
||||
LValue EmitLValueForField(llvm::Value* Base, const FieldDecl* Field,
|
||||
unsigned CVRQualifiers);
|
||||
LValue EmitLValueForField(LValue Base, const FieldDecl* Field);
|
||||
|
||||
/// EmitLValueForFieldInitialization - Like EmitLValueForField, except that
|
||||
/// if the Field is a reference, this will return the address of the reference
|
||||
/// and not the address of the value stored in the reference.
|
||||
LValue EmitLValueForFieldInitialization(llvm::Value* Base,
|
||||
const FieldDecl* Field,
|
||||
unsigned CVRQualifiers);
|
||||
LValue EmitLValueForFieldInitialization(LValue Base,
|
||||
const FieldDecl* Field);
|
||||
|
||||
LValue EmitLValueForIvar(QualType ObjectTy,
|
||||
llvm::Value* Base, const ObjCIvarDecl *Ivar,
|
||||
|
@ -1241,7 +1241,7 @@ CodeGenModule::CreateOrReplaceCXXRuntimeVariable(StringRef Name,
|
||||
|
||||
/// GetAddrOfGlobalVar - Return the llvm::Constant for the address of the
|
||||
/// given global variable. If Ty is non-null and if the global doesn't exist,
|
||||
/// then it will be greated with the specified type instead of whatever the
|
||||
/// then it will be created with the specified type instead of whatever the
|
||||
/// normal requested type would be.
|
||||
llvm::Constant *CodeGenModule::GetAddrOfGlobalVar(const VarDecl *D,
|
||||
llvm::Type *Ty) {
|
||||
|
@ -28,7 +28,7 @@ using namespace CodeGen;
|
||||
CodeGenTBAA::CodeGenTBAA(ASTContext &Ctx, llvm::LLVMContext& VMContext,
|
||||
const LangOptions &Features, MangleContext &MContext)
|
||||
: Context(Ctx), VMContext(VMContext), Features(Features), MContext(MContext),
|
||||
Root(0), Char(0) {
|
||||
MDHelper(VMContext), Root(0), Char(0) {
|
||||
}
|
||||
|
||||
CodeGenTBAA::~CodeGenTBAA() {
|
||||
@ -40,7 +40,7 @@ llvm::MDNode *CodeGenTBAA::getRoot() {
|
||||
// (or a different version of this front-end), their TBAA trees will
|
||||
// remain distinct, and the optimizer will treat them conservatively.
|
||||
if (!Root)
|
||||
Root = getTBAAInfoForNamedType("Simple C/C++ TBAA", 0);
|
||||
Root = MDHelper.createTBAARoot("Simple C/C++ TBAA");
|
||||
|
||||
return Root;
|
||||
}
|
||||
@ -51,33 +51,11 @@ llvm::MDNode *CodeGenTBAA::getChar() {
|
||||
// these special powers only cover user-accessible memory, and doesn't
|
||||
// include things like vtables.
|
||||
if (!Char)
|
||||
Char = getTBAAInfoForNamedType("omnipotent char", getRoot());
|
||||
Char = MDHelper.createTBAANode("omnipotent char", getRoot());
|
||||
|
||||
return Char;
|
||||
}
|
||||
|
||||
/// getTBAAInfoForNamedType - Create a TBAA tree node with the given string
|
||||
/// as its identifier, and the given Parent node as its tree parent.
|
||||
llvm::MDNode *CodeGenTBAA::getTBAAInfoForNamedType(StringRef NameStr,
|
||||
llvm::MDNode *Parent,
|
||||
bool Readonly) {
|
||||
// Currently there is only one flag defined - the readonly flag.
|
||||
llvm::Value *Flags = 0;
|
||||
if (Readonly)
|
||||
Flags = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), true);
|
||||
|
||||
// Set up the mdnode operand list.
|
||||
llvm::Value *Ops[] = {
|
||||
llvm::MDString::get(VMContext, NameStr),
|
||||
Parent,
|
||||
Flags
|
||||
};
|
||||
|
||||
// Create the mdnode.
|
||||
unsigned Len = llvm::array_lengthof(Ops) - !Flags;
|
||||
return llvm::MDNode::get(VMContext, llvm::makeArrayRef(Ops, Len));
|
||||
}
|
||||
|
||||
static bool TypeHasMayAlias(QualType QTy) {
|
||||
// Tagged types have declarations, and therefore may have attributes.
|
||||
if (const TagType *TTy = dyn_cast<TagType>(QTy))
|
||||
@ -137,7 +115,7 @@ CodeGenTBAA::getTBAAInfo(QualType QTy) {
|
||||
// "underlying types".
|
||||
default:
|
||||
return MetadataCache[Ty] =
|
||||
getTBAAInfoForNamedType(BTy->getName(Features), getChar());
|
||||
MDHelper.createTBAANode(BTy->getName(Features), getChar());
|
||||
}
|
||||
}
|
||||
|
||||
@ -145,7 +123,7 @@ CodeGenTBAA::getTBAAInfo(QualType QTy) {
|
||||
// TODO: Implement C++'s type "similarity" and consider dis-"similar"
|
||||
// pointers distinct.
|
||||
if (Ty->isPointerType())
|
||||
return MetadataCache[Ty] = getTBAAInfoForNamedType("any pointer",
|
||||
return MetadataCache[Ty] = MDHelper.createTBAANode("any pointer",
|
||||
getChar());
|
||||
|
||||
// Enum types are distinct types. In C++ they have "underlying types",
|
||||
@ -173,7 +151,7 @@ CodeGenTBAA::getTBAAInfo(QualType QTy) {
|
||||
llvm::raw_svector_ostream Out(OutName);
|
||||
MContext.mangleCXXRTTIName(QualType(ETy, 0), Out);
|
||||
Out.flush();
|
||||
return MetadataCache[Ty] = getTBAAInfoForNamedType(OutName, getChar());
|
||||
return MetadataCache[Ty] = MDHelper.createTBAANode(OutName, getChar());
|
||||
}
|
||||
|
||||
// For now, handle any other kind of type conservatively.
|
||||
@ -181,5 +159,5 @@ CodeGenTBAA::getTBAAInfo(QualType QTy) {
|
||||
}
|
||||
|
||||
llvm::MDNode *CodeGenTBAA::getTBAAInfoForVTablePtr() {
|
||||
return getTBAAInfoForNamedType("vtable pointer", getRoot());
|
||||
return MDHelper.createTBAANode("vtable pointer", getRoot());
|
||||
}
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/Support/MDBuilder.h"
|
||||
|
||||
namespace llvm {
|
||||
class LLVMContext;
|
||||
@ -41,6 +42,9 @@ class CodeGenTBAA {
|
||||
const LangOptions &Features;
|
||||
MangleContext &MContext;
|
||||
|
||||
// MDHelper - Helper for creating metadata.
|
||||
llvm::MDBuilder MDHelper;
|
||||
|
||||
/// MetadataCache - This maps clang::Types to llvm::MDNodes describing them.
|
||||
llvm::DenseMap<const Type *, llvm::MDNode *> MetadataCache;
|
||||
|
||||
@ -55,10 +59,6 @@ class CodeGenTBAA {
|
||||
/// considered to be equivalent to it.
|
||||
llvm::MDNode *getChar();
|
||||
|
||||
llvm::MDNode *getTBAAInfoForNamedType(StringRef NameStr,
|
||||
llvm::MDNode *Parent,
|
||||
bool Readonly = false);
|
||||
|
||||
public:
|
||||
CodeGenTBAA(ASTContext &Ctx, llvm::LLVMContext &VMContext,
|
||||
const LangOptions &Features,
|
||||
|
@ -2527,19 +2527,16 @@ void ARMABIInfo::computeInfo(CGFunctionInfo &FI) const {
|
||||
static bool isHomogeneousAggregate(QualType Ty, const Type *&Base,
|
||||
ASTContext &Context,
|
||||
uint64_t *HAMembers = 0) {
|
||||
uint64_t Members;
|
||||
uint64_t Members = 0;
|
||||
if (const ConstantArrayType *AT = Context.getAsConstantArrayType(Ty)) {
|
||||
if (!isHomogeneousAggregate(AT->getElementType(), Base, Context, &Members))
|
||||
return false;
|
||||
Members *= AT->getSize().getZExtValue();
|
||||
} else if (const RecordType *RT = Ty->getAs<RecordType>()) {
|
||||
const RecordDecl *RD = RT->getDecl();
|
||||
if (RD->isUnion() || RD->hasFlexibleArrayMember())
|
||||
if (RD->hasFlexibleArrayMember())
|
||||
return false;
|
||||
if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
|
||||
if (!CXXRD->isAggregate())
|
||||
return false;
|
||||
}
|
||||
|
||||
Members = 0;
|
||||
for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
|
||||
i != e; ++i) {
|
||||
@ -2547,7 +2544,9 @@ static bool isHomogeneousAggregate(QualType Ty, const Type *&Base,
|
||||
uint64_t FldMembers;
|
||||
if (!isHomogeneousAggregate(FD->getType(), Base, Context, &FldMembers))
|
||||
return false;
|
||||
Members += FldMembers;
|
||||
|
||||
Members = (RD->isUnion() ?
|
||||
std::max(Members, FldMembers) : Members + FldMembers);
|
||||
}
|
||||
} else {
|
||||
Members = 1;
|
||||
@ -2584,7 +2583,8 @@ static bool isHomogeneousAggregate(QualType Ty, const Type *&Base,
|
||||
// Homogeneous Aggregates can have at most 4 members of the base type.
|
||||
if (HAMembers)
|
||||
*HAMembers = Members;
|
||||
return (Members <= 4);
|
||||
|
||||
return (Members > 0 && Members <= 4);
|
||||
}
|
||||
|
||||
ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty) const {
|
||||
@ -2609,8 +2609,10 @@ ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty) const {
|
||||
if (getABIKind() == ARMABIInfo::AAPCS_VFP) {
|
||||
// Homogeneous Aggregates need to be expanded.
|
||||
const Type *Base = 0;
|
||||
if (isHomogeneousAggregate(Ty, Base, getContext()))
|
||||
if (isHomogeneousAggregate(Ty, Base, getContext())) {
|
||||
assert(Base && "Base class should be set for homogeneous aggregate");
|
||||
return ABIArgInfo::getExpand();
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, pass by coercing to a structure of the appropriate size.
|
||||
@ -2776,9 +2778,11 @@ ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy) const {
|
||||
// Check for homogeneous aggregates with AAPCS-VFP.
|
||||
if (getABIKind() == AAPCS_VFP) {
|
||||
const Type *Base = 0;
|
||||
if (isHomogeneousAggregate(RetTy, Base, getContext()))
|
||||
if (isHomogeneousAggregate(RetTy, Base, getContext())) {
|
||||
assert(Base && "Base class should be set for homogeneous aggregate");
|
||||
// Homogeneous Aggregates are returned directly.
|
||||
return ABIArgInfo::getDirect();
|
||||
}
|
||||
}
|
||||
|
||||
// Aggregates <= 4 bytes are returned in r0; other aggregates
|
||||
|
@ -230,3 +230,7 @@ void Compilation::initCompilationForDiagnostics(void) {
|
||||
Redirects[1] = new const llvm::sys::Path();
|
||||
Redirects[2] = new const llvm::sys::Path();
|
||||
}
|
||||
|
||||
StringRef Compilation::getSysRoot(void) const {
|
||||
return getDriver().SysRoot;
|
||||
}
|
||||
|
@ -49,8 +49,8 @@ Driver::Driver(StringRef ClangExecutable,
|
||||
bool IsProduction,
|
||||
DiagnosticsEngine &Diags)
|
||||
: Opts(createDriverOptTable()), Diags(Diags),
|
||||
ClangExecutable(ClangExecutable), UseStdLib(true),
|
||||
DefaultTargetTriple(DefaultTargetTriple),
|
||||
ClangExecutable(ClangExecutable), SysRoot(DEFAULT_SYSROOT),
|
||||
UseStdLib(true), DefaultTargetTriple(DefaultTargetTriple),
|
||||
DefaultImageName(DefaultImageName),
|
||||
DriverTitle("clang \"gcc-compatible\" driver"),
|
||||
CCPrintOptionsFilename(0), CCPrintHeadersFilename(0),
|
||||
@ -660,9 +660,7 @@ bool Driver::HandleImmediateArgs(const Compilation &C) {
|
||||
llvm::outs() << "\n";
|
||||
llvm::outs() << "libraries: =" << ResourceDir;
|
||||
|
||||
std::string sysroot;
|
||||
if (Arg *A = C.getArgs().getLastArg(options::OPT__sysroot_EQ))
|
||||
sysroot = A->getValue(C.getArgs());
|
||||
StringRef sysroot = C.getSysRoot();
|
||||
|
||||
for (ToolChain::path_list::const_iterator it = TC.getFilePaths().begin(),
|
||||
ie = TC.getFilePaths().end(); it != ie; ++it) {
|
||||
@ -872,30 +870,30 @@ void Driver::BuildUniversalActions(const ToolChain &TC,
|
||||
|
||||
// Handle debug info queries.
|
||||
Arg *A = Args.getLastArg(options::OPT_g_Group);
|
||||
if (A && !A->getOption().matches(options::OPT_g0) &&
|
||||
!A->getOption().matches(options::OPT_gstabs) &&
|
||||
ContainsCompileOrAssembleAction(Actions.back())) {
|
||||
if (A && !A->getOption().matches(options::OPT_g0) &&
|
||||
!A->getOption().matches(options::OPT_gstabs) &&
|
||||
ContainsCompileOrAssembleAction(Actions.back())) {
|
||||
|
||||
// Add a 'dsymutil' step if necessary, when debug info is enabled and we
|
||||
// have a compile input. We need to run 'dsymutil' ourselves in such cases
|
||||
// because the debug info will refer to a temporary object file which is
|
||||
// will be removed at the end of the compilation process.
|
||||
if (Act->getType() == types::TY_Image) {
|
||||
ActionList Inputs;
|
||||
Inputs.push_back(Actions.back());
|
||||
Actions.pop_back();
|
||||
Actions.push_back(new DsymutilJobAction(Inputs, types::TY_dSYM));
|
||||
}
|
||||
|
||||
// Verify the output (debug information only) if we passed '-verify'.
|
||||
if (Args.hasArg(options::OPT_verify)) {
|
||||
ActionList VerifyInputs;
|
||||
VerifyInputs.push_back(Actions.back());
|
||||
Actions.pop_back();
|
||||
Actions.push_back(new VerifyJobAction(VerifyInputs,
|
||||
types::TY_Nothing));
|
||||
}
|
||||
// Add a 'dsymutil' step if necessary, when debug info is enabled and we
|
||||
// have a compile input. We need to run 'dsymutil' ourselves in such cases
|
||||
// because the debug info will refer to a temporary object file which is
|
||||
// will be removed at the end of the compilation process.
|
||||
if (Act->getType() == types::TY_Image) {
|
||||
ActionList Inputs;
|
||||
Inputs.push_back(Actions.back());
|
||||
Actions.pop_back();
|
||||
Actions.push_back(new DsymutilJobAction(Inputs, types::TY_dSYM));
|
||||
}
|
||||
|
||||
// Verify the output (debug information only) if we passed '-verify'.
|
||||
if (Args.hasArg(options::OPT_verify)) {
|
||||
ActionList VerifyInputs;
|
||||
VerifyInputs.push_back(Actions.back());
|
||||
Actions.pop_back();
|
||||
Actions.push_back(new VerifyJobAction(VerifyInputs,
|
||||
types::TY_Nothing));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -580,7 +580,7 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
|
||||
|
||||
// If no '-miphoneos-version-min' specified on the command line and
|
||||
// IPHONEOS_DEPLOYMENT_TARGET is not defined, see if we can set the default
|
||||
// based on isysroot.
|
||||
// based on -isysroot.
|
||||
if (iOSTarget.empty()) {
|
||||
if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) {
|
||||
StringRef first, second;
|
||||
@ -1086,6 +1086,7 @@ bool Generic_GCC::GCCVersion::operator<(const GCCVersion &RHS) const {
|
||||
// a patch.
|
||||
if (RHS.Patch == -1) return true; if (Patch == -1) return false;
|
||||
if (Patch < RHS.Patch) return true; if (Patch > RHS.Patch) return false;
|
||||
if (PatchSuffix == RHS.PatchSuffix) return false;
|
||||
|
||||
// Finally, between completely tied version numbers, the version with the
|
||||
// suffix loses as we prefer full releases.
|
||||
@ -1103,7 +1104,7 @@ static StringRef getGCCToolchainDir(const ArgList &Args) {
|
||||
/// \brief Construct a GCCInstallationDetector from the driver.
|
||||
///
|
||||
/// This performs all of the autodetection and sets up the various paths.
|
||||
/// Once constructed, a GCCInstallation is esentially immutable.
|
||||
/// Once constructed, a GCCInstallationDetector is essentially immutable.
|
||||
///
|
||||
/// FIXME: We shouldn't need an explicit TargetTriple parameter here, and
|
||||
/// should instead pull the target out of the driver. This is currently
|
||||
@ -2063,7 +2064,7 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
|
||||
// If the GCC installation we found is inside of the sysroot, we want to
|
||||
// prefer libraries installed in the parent prefix of the GCC installation.
|
||||
// It is important to *not* use these paths when the GCC installation is
|
||||
// outside of the system root as that can pick up un-intented libraries.
|
||||
// outside of the system root as that can pick up unintended libraries.
|
||||
// This usually happens when there is an external cross compiler on the
|
||||
// host system, and a more minimal sysroot available that is the target of
|
||||
// the cross.
|
||||
|
@ -377,10 +377,11 @@ void Clang::AddPreprocessingOptions(Compilation &C,
|
||||
|
||||
// If we have a --sysroot, and don't have an explicit -isysroot flag, add an
|
||||
// -isysroot to the CC1 invocation.
|
||||
if (Arg *A = Args.getLastArg(options::OPT__sysroot_EQ)) {
|
||||
StringRef sysroot = C.getSysRoot();
|
||||
if (sysroot != "") {
|
||||
if (!Args.hasArg(options::OPT_isysroot)) {
|
||||
CmdArgs.push_back("-isysroot");
|
||||
CmdArgs.push_back(A->getValue(Args));
|
||||
CmdArgs.push_back(C.getArgs().MakeArgString(sysroot));
|
||||
}
|
||||
}
|
||||
|
||||
@ -4016,9 +4017,10 @@ void darwin::Link::AddLinkArgs(Compilation &C,
|
||||
|
||||
// Give --sysroot= preference, over the Apple specific behavior to also use
|
||||
// --isysroot as the syslibroot.
|
||||
if (const Arg *A = Args.getLastArg(options::OPT__sysroot_EQ)) {
|
||||
StringRef sysroot = C.getSysRoot();
|
||||
if (sysroot != "") {
|
||||
CmdArgs.push_back("-syslibroot");
|
||||
CmdArgs.push_back(A->getValue(Args));
|
||||
CmdArgs.push_back(C.getArgs().MakeArgString(sysroot));
|
||||
} else if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) {
|
||||
CmdArgs.push_back("-syslibroot");
|
||||
CmdArgs.push_back(A->getValue(Args));
|
||||
|
@ -643,8 +643,10 @@ void ASTUnit::ConfigureDiags(IntrusiveRefCntPtr<DiagnosticsEngine> &Diags,
|
||||
DiagnosticConsumer *Client = 0;
|
||||
if (CaptureDiagnostics)
|
||||
Client = new StoredDiagnosticConsumer(AST.StoredDiagnostics);
|
||||
Diags = CompilerInstance::createDiagnostics(DiagOpts, ArgEnd- ArgBegin,
|
||||
ArgBegin, Client);
|
||||
Diags = CompilerInstance::createDiagnostics(DiagOpts, ArgEnd-ArgBegin,
|
||||
ArgBegin, Client,
|
||||
/*ShouldOwnClient=*/true,
|
||||
/*ShouldCloneClient=*/false);
|
||||
} else if (CaptureDiagnostics) {
|
||||
Diags->setClient(new StoredDiagnosticConsumer(AST.StoredDiagnostics));
|
||||
}
|
||||
|
@ -651,6 +651,10 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
|
||||
// created. This complexity should be lifted elsewhere.
|
||||
getTarget().setForcedLangOptions(getLangOpts());
|
||||
|
||||
// rewriter project will change target built-in bool type from its default.
|
||||
if (getFrontendOpts().ProgramAction == frontend::RewriteObjC)
|
||||
getTarget().noSignedCharForObjCBool();
|
||||
|
||||
// Validate/process some options.
|
||||
if (getHeaderSearchOpts().Verbose)
|
||||
OS << "clang -cc1 version " CLANG_VERSION_STRING
|
||||
|
@ -429,7 +429,6 @@ static const char *getActionName(frontend::ActionKind Kind) {
|
||||
case frontend::PrintDeclContext: return "-print-decl-contexts";
|
||||
case frontend::PrintPreamble: return "-print-preamble";
|
||||
case frontend::PrintPreprocessedInput: return "-E";
|
||||
case frontend::PubnamesDump: return "-pubnames-dump";
|
||||
case frontend::RewriteMacros: return "-rewrite-macros";
|
||||
case frontend::RewriteObjC: return "-rewrite-objc";
|
||||
case frontend::RewriteTest: return "-rewrite-test";
|
||||
@ -1369,8 +1368,6 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
|
||||
Opts.ProgramAction = frontend::PrintPreamble; break;
|
||||
case OPT_E:
|
||||
Opts.ProgramAction = frontend::PrintPreprocessedInput; break;
|
||||
case OPT_pubnames_dump:
|
||||
Opts.ProgramAction = frontend::PubnamesDump; break;
|
||||
case OPT_rewrite_macros:
|
||||
Opts.ProgramAction = frontend::RewriteMacros; break;
|
||||
case OPT_rewrite_objc:
|
||||
|
@ -25,7 +25,6 @@
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Support/system_error.h"
|
||||
#include <set>
|
||||
|
||||
using namespace clang;
|
||||
|
||||
@ -355,77 +354,6 @@ ASTConsumer *SyntaxOnlyAction::CreateASTConsumer(CompilerInstance &CI,
|
||||
return new ASTConsumer();
|
||||
}
|
||||
|
||||
namespace {
|
||||
class PubnamesDumpConsumer : public ASTConsumer {
|
||||
Preprocessor &PP;
|
||||
|
||||
/// \brief Determine whether the given identifier provides a 'public' name.
|
||||
bool isPublicName(IdentifierInfo *II) {
|
||||
// If there are any top-level declarations associated with this
|
||||
// identifier, it is a public name.
|
||||
if (II->getFETokenInfo<void>())
|
||||
return true;
|
||||
|
||||
// If this identifier is the name of a non-builtin macro that isn't
|
||||
// defined on the command line or implicitly by the front end, it is a
|
||||
// public name.
|
||||
if (II->hasMacroDefinition()) {
|
||||
if (MacroInfo *M = PP.getMacroInfo(II))
|
||||
if (!M->isBuiltinMacro()) {
|
||||
SourceLocation Loc = M->getDefinitionLoc();
|
||||
FileID File = PP.getSourceManager().getFileID(Loc);
|
||||
if (PP.getSourceManager().getFileEntryForID(File))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public:
|
||||
PubnamesDumpConsumer(Preprocessor &PP) : PP(PP) { }
|
||||
|
||||
virtual void HandleTranslationUnit(ASTContext &Ctx) {
|
||||
std::set<StringRef> Pubnames;
|
||||
|
||||
// Add the names of any non-builtin macros.
|
||||
for (IdentifierTable::iterator I = Ctx.Idents.begin(),
|
||||
IEnd = Ctx.Idents.end();
|
||||
I != IEnd; ++I) {
|
||||
if (isPublicName(I->second))
|
||||
Pubnames.insert(I->first());
|
||||
}
|
||||
|
||||
// If there is an external identifier lookup source, consider those
|
||||
// identifiers as well.
|
||||
if (IdentifierInfoLookup *External
|
||||
= Ctx.Idents.getExternalIdentifierLookup()) {
|
||||
OwningPtr<IdentifierIterator> Iter(External->getIdentifiers());
|
||||
do {
|
||||
StringRef Name = Iter->Next();
|
||||
if (Name.empty())
|
||||
break;
|
||||
|
||||
if (isPublicName(PP.getIdentifierInfo(Name)))
|
||||
Pubnames.insert(Name);
|
||||
} while (true);
|
||||
}
|
||||
|
||||
// Print the names, in lexicographical order.
|
||||
for (std::set<StringRef>::iterator N = Pubnames.begin(),
|
||||
NEnd = Pubnames.end();
|
||||
N != NEnd; ++N) {
|
||||
llvm::outs() << *N << '\n';
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
ASTConsumer *PubnamesDumpAction::CreateASTConsumer(CompilerInstance &CI,
|
||||
StringRef InFile) {
|
||||
return new PubnamesDumpConsumer(CI.getPreprocessor());
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Preprocessor Actions
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -10,13 +10,17 @@
|
||||
#include "clang/Frontend/TextDiagnostic.h"
|
||||
#include "clang/Basic/FileManager.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
#include "clang/Basic/ConvertUTF.h"
|
||||
#include "clang/Frontend/DiagnosticOptions.h"
|
||||
#include "clang/Lex/Lexer.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/Locale.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include <algorithm>
|
||||
|
||||
using namespace clang;
|
||||
|
||||
static const enum raw_ostream::Colors noteColor =
|
||||
@ -36,22 +40,268 @@ static const enum raw_ostream::Colors savedColor =
|
||||
/// \brief Number of spaces to indent when word-wrapping.
|
||||
const unsigned WordWrapIndentation = 6;
|
||||
|
||||
int bytesSincePreviousTabOrLineBegin(StringRef SourceLine, size_t i) {
|
||||
int bytes = 0;
|
||||
while (0<i) {
|
||||
if (SourceLine[--i]=='\t')
|
||||
break;
|
||||
++bytes;
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/// \brief returns a printable representation of first item from input range
|
||||
///
|
||||
/// This function returns a printable representation of the next item in a line
|
||||
/// of source. If the next byte begins a valid and printable character, that
|
||||
/// character is returned along with 'true'.
|
||||
///
|
||||
/// Otherwise, if the next byte begins a valid, but unprintable character, a
|
||||
/// printable, escaped representation of the character is returned, along with
|
||||
/// 'false'. Otherwise a printable, escaped representation of the next byte
|
||||
/// is returned along with 'false'.
|
||||
///
|
||||
/// \note The index is updated to be used with a subsequent call to
|
||||
/// printableTextForNextCharacter.
|
||||
///
|
||||
/// \param SourceLine The line of source
|
||||
/// \param i Pointer to byte index,
|
||||
/// \param TabStop used to expand tabs
|
||||
/// \return pair(printable text, 'true' iff original text was printable)
|
||||
///
|
||||
std::pair<SmallString<16>,bool>
|
||||
printableTextForNextCharacter(StringRef SourceLine, size_t *i,
|
||||
unsigned TabStop) {
|
||||
assert(i && "i must not be null");
|
||||
assert(*i<SourceLine.size() && "must point to a valid index");
|
||||
|
||||
if (SourceLine[*i]=='\t') {
|
||||
assert(0 < TabStop && TabStop <= DiagnosticOptions::MaxTabStop &&
|
||||
"Invalid -ftabstop value");
|
||||
unsigned col = bytesSincePreviousTabOrLineBegin(SourceLine, *i);
|
||||
unsigned NumSpaces = TabStop - col%TabStop;
|
||||
assert(0 < NumSpaces && NumSpaces <= TabStop
|
||||
&& "Invalid computation of space amt");
|
||||
++(*i);
|
||||
|
||||
SmallString<16> expandedTab;
|
||||
expandedTab.assign(NumSpaces, ' ');
|
||||
return std::make_pair(expandedTab, true);
|
||||
}
|
||||
|
||||
// FIXME: this data is copied from the private implementation of ConvertUTF.h
|
||||
static const char trailingBytesForUTF8[256] = {
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
|
||||
};
|
||||
|
||||
unsigned char const *begin, *end;
|
||||
begin = reinterpret_cast<unsigned char const *>(&*(SourceLine.begin() + *i));
|
||||
end = begin + SourceLine.size();
|
||||
|
||||
if (isLegalUTF8Sequence(begin, end)) {
|
||||
UTF32 c;
|
||||
UTF32 *cptr = &c;
|
||||
unsigned char const *original_begin = begin;
|
||||
char trailingBytes = trailingBytesForUTF8[(unsigned char)SourceLine[*i]];
|
||||
unsigned char const *cp_end = begin+trailingBytes+1;
|
||||
|
||||
ConversionResult res = ConvertUTF8toUTF32(&begin, cp_end, &cptr, cptr+1,
|
||||
strictConversion);
|
||||
(void)res;
|
||||
assert(conversionOK==res);
|
||||
assert(0 < begin-original_begin
|
||||
&& "we must be further along in the string now");
|
||||
*i += begin-original_begin;
|
||||
|
||||
if (!llvm::sys::locale::isPrint(c)) {
|
||||
// If next character is valid UTF-8, but not printable
|
||||
SmallString<16> expandedCP("<U+>");
|
||||
while (c) {
|
||||
expandedCP.insert(expandedCP.begin()+3, llvm::hexdigit(c%16));
|
||||
c/=16;
|
||||
}
|
||||
while (expandedCP.size() < 8)
|
||||
expandedCP.insert(expandedCP.begin()+3, llvm::hexdigit(0));
|
||||
return std::make_pair(expandedCP, false);
|
||||
}
|
||||
|
||||
// If next character is valid UTF-8, and printable
|
||||
return std::make_pair(SmallString<16>(original_begin, cp_end), true);
|
||||
|
||||
}
|
||||
|
||||
// If next byte is not valid UTF-8 (and therefore not printable)
|
||||
SmallString<16> expandedByte("<XX>");
|
||||
unsigned char byte = SourceLine[*i];
|
||||
expandedByte[1] = llvm::hexdigit(byte / 16);
|
||||
expandedByte[2] = llvm::hexdigit(byte % 16);
|
||||
++(*i);
|
||||
return std::make_pair(expandedByte, false);
|
||||
}
|
||||
|
||||
void expandTabs(std::string &SourceLine, unsigned TabStop) {
|
||||
size_t i = SourceLine.size();
|
||||
while (i>0) {
|
||||
i--;
|
||||
if (SourceLine[i]!='\t')
|
||||
continue;
|
||||
size_t tmp_i = i;
|
||||
std::pair<SmallString<16>,bool> res
|
||||
= printableTextForNextCharacter(SourceLine, &tmp_i, TabStop);
|
||||
SourceLine.replace(i, 1, res.first.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
/// This function takes a raw source line and produces a mapping from the bytes
|
||||
/// of the printable representation of the line to the columns those printable
|
||||
/// characters will appear at (numbering the first column as 0).
|
||||
///
|
||||
/// If a byte 'i' corresponds to muliple columns (e.g. the byte contains a tab
|
||||
/// character) then the the array will map that byte to the first column the
|
||||
/// tab appears at and the next value in the map will have been incremented
|
||||
/// more than once.
|
||||
///
|
||||
/// If a byte is the first in a sequence of bytes that together map to a single
|
||||
/// entity in the output, then the array will map that byte to the appropriate
|
||||
/// column while the subsequent bytes will be -1.
|
||||
///
|
||||
/// The last element in the array does not correspond to any byte in the input
|
||||
/// and instead is the number of columns needed to display the source
|
||||
///
|
||||
/// example: (given a tabstop of 8)
|
||||
///
|
||||
/// "a \t \u3042" -> {0,1,2,8,9,-1,-1,11}
|
||||
///
|
||||
/// (\u3042 is represented in UTF-8 by three bytes and takes two columns to
|
||||
/// display)
|
||||
void byteToColumn(StringRef SourceLine, unsigned TabStop,
|
||||
SmallVectorImpl<int> &out) {
|
||||
out.clear();
|
||||
|
||||
if (SourceLine.empty()) {
|
||||
out.resize(1u,0);
|
||||
return;
|
||||
}
|
||||
|
||||
out.resize(SourceLine.size()+1, -1);
|
||||
|
||||
int columns = 0;
|
||||
size_t i = 0;
|
||||
while (i<SourceLine.size()) {
|
||||
out[i] = columns;
|
||||
std::pair<SmallString<16>,bool> res
|
||||
= printableTextForNextCharacter(SourceLine, &i, TabStop);
|
||||
columns += llvm::sys::locale::columnWidth(res.first);
|
||||
}
|
||||
out.back() = columns;
|
||||
}
|
||||
|
||||
/// This function takes a raw source line and produces a mapping from columns
|
||||
/// to the byte of the source line that produced the character displaying at
|
||||
/// that column. This is the inverse of the mapping produced by byteToColumn()
|
||||
///
|
||||
/// The last element in the array is the number of bytes in the source string
|
||||
///
|
||||
/// example: (given a tabstop of 8)
|
||||
///
|
||||
/// "a \t \u3042" -> {0,1,2,-1,-1,-1,-1,-1,3,4,-1,7}
|
||||
///
|
||||
/// (\u3042 is represented in UTF-8 by three bytes and takes two columns to
|
||||
/// display)
|
||||
void columnToByte(StringRef SourceLine, unsigned TabStop,
|
||||
SmallVectorImpl<int> &out) {
|
||||
out.clear();
|
||||
|
||||
if (SourceLine.empty()) {
|
||||
out.resize(1u, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
int columns = 0;
|
||||
size_t i = 0;
|
||||
while (i<SourceLine.size()) {
|
||||
out.resize(columns+1, -1);
|
||||
out.back() = i;
|
||||
std::pair<SmallString<16>,bool> res
|
||||
= printableTextForNextCharacter(SourceLine, &i, TabStop);
|
||||
columns += llvm::sys::locale::columnWidth(res.first);
|
||||
}
|
||||
out.resize(columns+1, -1);
|
||||
out.back() = i;
|
||||
}
|
||||
|
||||
struct SourceColumnMap {
|
||||
SourceColumnMap(StringRef SourceLine, unsigned TabStop)
|
||||
: m_SourceLine(SourceLine) {
|
||||
|
||||
::byteToColumn(SourceLine, TabStop, m_byteToColumn);
|
||||
::columnToByte(SourceLine, TabStop, m_columnToByte);
|
||||
|
||||
assert(m_byteToColumn.size()==SourceLine.size()+1);
|
||||
assert(0 < m_byteToColumn.size() && 0 < m_columnToByte.size());
|
||||
assert(m_byteToColumn.size()
|
||||
== static_cast<unsigned>(m_columnToByte.back()+1));
|
||||
assert(static_cast<unsigned>(m_byteToColumn.back()+1)
|
||||
== m_columnToByte.size());
|
||||
}
|
||||
int columns() const { return m_byteToColumn.back(); }
|
||||
int bytes() const { return m_columnToByte.back(); }
|
||||
int byteToColumn(int n) const {
|
||||
assert(0<=n && n<static_cast<int>(m_byteToColumn.size()));
|
||||
return m_byteToColumn[n];
|
||||
}
|
||||
int columnToByte(int n) const {
|
||||
assert(0<=n && n<static_cast<int>(m_columnToByte.size()));
|
||||
return m_columnToByte[n];
|
||||
}
|
||||
StringRef getSourceLine() const {
|
||||
return m_SourceLine;
|
||||
}
|
||||
|
||||
private:
|
||||
const std::string m_SourceLine;
|
||||
SmallVector<int,200> m_byteToColumn;
|
||||
SmallVector<int,200> m_columnToByte;
|
||||
};
|
||||
|
||||
// used in assert in selectInterestingSourceRegion()
|
||||
namespace {
|
||||
struct char_out_of_range {
|
||||
const char lower,upper;
|
||||
char_out_of_range(char lower, char upper) :
|
||||
lower(lower), upper(upper) {}
|
||||
bool operator()(char c) { return c < lower || upper < c; }
|
||||
};
|
||||
}
|
||||
|
||||
/// \brief When the source code line we want to print is too long for
|
||||
/// the terminal, select the "interesting" region.
|
||||
static void selectInterestingSourceRegion(std::string &SourceLine,
|
||||
std::string &CaretLine,
|
||||
std::string &FixItInsertionLine,
|
||||
unsigned EndOfCaretToken,
|
||||
unsigned Columns) {
|
||||
unsigned MaxSize = std::max(SourceLine.size(),
|
||||
std::max(CaretLine.size(),
|
||||
FixItInsertionLine.size()));
|
||||
if (MaxSize > SourceLine.size())
|
||||
SourceLine.resize(MaxSize, ' ');
|
||||
if (MaxSize > CaretLine.size())
|
||||
CaretLine.resize(MaxSize, ' ');
|
||||
if (!FixItInsertionLine.empty() && MaxSize > FixItInsertionLine.size())
|
||||
FixItInsertionLine.resize(MaxSize, ' ');
|
||||
unsigned Columns,
|
||||
const SourceColumnMap &map) {
|
||||
unsigned MaxColumns = std::max<unsigned>(map.columns(),
|
||||
std::max(CaretLine.size(),
|
||||
FixItInsertionLine.size()));
|
||||
// if the number of columns is less than the desired number we're done
|
||||
if (MaxColumns <= Columns)
|
||||
return;
|
||||
|
||||
// no special characters allowed in CaretLine or FixItInsertionLine
|
||||
assert(CaretLine.end() ==
|
||||
std::find_if(CaretLine.begin(), CaretLine.end(),
|
||||
char_out_of_range(' ','~')));
|
||||
assert(FixItInsertionLine.end() ==
|
||||
std::find_if(FixItInsertionLine.begin(), FixItInsertionLine.end(),
|
||||
char_out_of_range(' ','~')));
|
||||
|
||||
// Find the slice that we need to display the full caret line
|
||||
// correctly.
|
||||
@ -64,10 +314,8 @@ static void selectInterestingSourceRegion(std::string &SourceLine,
|
||||
if (!isspace(CaretLine[CaretEnd - 1]))
|
||||
break;
|
||||
|
||||
// Make sure we don't chop the string shorter than the caret token
|
||||
// itself.
|
||||
if (CaretEnd < EndOfCaretToken)
|
||||
CaretEnd = EndOfCaretToken;
|
||||
// caret has already been inserted into CaretLine so the above whitespace
|
||||
// check is guaranteed to include the caret
|
||||
|
||||
// If we have a fix-it line, make sure the slice includes all of the
|
||||
// fix-it information.
|
||||
@ -81,10 +329,8 @@ static void selectInterestingSourceRegion(std::string &SourceLine,
|
||||
if (!isspace(FixItInsertionLine[FixItEnd - 1]))
|
||||
break;
|
||||
|
||||
if (FixItStart < CaretStart)
|
||||
CaretStart = FixItStart;
|
||||
if (FixItEnd > CaretEnd)
|
||||
CaretEnd = FixItEnd;
|
||||
CaretStart = std::min(FixItStart, CaretStart);
|
||||
CaretEnd = std::max(FixItEnd, CaretEnd);
|
||||
}
|
||||
|
||||
// CaretLine[CaretStart, CaretEnd) contains all of the interesting
|
||||
@ -92,62 +338,72 @@ static void selectInterestingSourceRegion(std::string &SourceLine,
|
||||
// number of columns we have, try to grow the slice to encompass
|
||||
// more context.
|
||||
|
||||
// If the end of the interesting region comes before we run out of
|
||||
// space in the terminal, start at the beginning of the line.
|
||||
if (Columns > 3 && CaretEnd < Columns - 3)
|
||||
CaretStart = 0;
|
||||
unsigned SourceStart = map.columnToByte(std::min<unsigned>(CaretStart,
|
||||
map.columns()));
|
||||
unsigned SourceEnd = map.columnToByte(std::min<unsigned>(CaretEnd,
|
||||
map.columns()));
|
||||
|
||||
unsigned CaretColumnsOutsideSource = CaretEnd-CaretStart
|
||||
- (map.byteToColumn(SourceEnd)-map.byteToColumn(SourceStart));
|
||||
|
||||
char const *front_ellipse = " ...";
|
||||
char const *front_space = " ";
|
||||
char const *back_ellipse = "...";
|
||||
unsigned ellipses_space = strlen(front_ellipse) + strlen(back_ellipse);
|
||||
|
||||
unsigned TargetColumns = Columns;
|
||||
if (TargetColumns > 8)
|
||||
TargetColumns -= 8; // Give us extra room for the ellipses.
|
||||
unsigned SourceLength = SourceLine.size();
|
||||
while ((CaretEnd - CaretStart) < TargetColumns) {
|
||||
// Give us extra room for the ellipses
|
||||
// and any of the caret line that extends past the source
|
||||
if (TargetColumns > ellipses_space+CaretColumnsOutsideSource)
|
||||
TargetColumns -= ellipses_space+CaretColumnsOutsideSource;
|
||||
|
||||
while (SourceStart>0 || SourceEnd<SourceLine.size()) {
|
||||
bool ExpandedRegion = false;
|
||||
// Move the start of the interesting region left until we've
|
||||
// pulled in something else interesting.
|
||||
if (CaretStart == 1)
|
||||
CaretStart = 0;
|
||||
else if (CaretStart > 1) {
|
||||
unsigned NewStart = CaretStart - 1;
|
||||
|
||||
if (SourceStart>0) {
|
||||
unsigned NewStart = SourceStart-1;
|
||||
|
||||
// Skip over any whitespace we see here; we're looking for
|
||||
// another bit of interesting text.
|
||||
while (NewStart && isspace(SourceLine[NewStart]))
|
||||
while (NewStart &&
|
||||
(map.byteToColumn(NewStart)==-1 || isspace(SourceLine[NewStart])))
|
||||
--NewStart;
|
||||
|
||||
// Skip over this bit of "interesting" text.
|
||||
while (NewStart && !isspace(SourceLine[NewStart]))
|
||||
while (NewStart &&
|
||||
(map.byteToColumn(NewStart)!=-1 && !isspace(SourceLine[NewStart])))
|
||||
--NewStart;
|
||||
|
||||
// Move up to the non-whitespace character we just saw.
|
||||
if (NewStart)
|
||||
++NewStart;
|
||||
|
||||
// If we're still within our limit, update the starting
|
||||
// position within the source/caret line.
|
||||
if (CaretEnd - NewStart <= TargetColumns) {
|
||||
CaretStart = NewStart;
|
||||
unsigned NewColumns = map.byteToColumn(SourceEnd) -
|
||||
map.byteToColumn(NewStart);
|
||||
if (NewColumns <= TargetColumns) {
|
||||
SourceStart = NewStart;
|
||||
ExpandedRegion = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Move the end of the interesting region right until we've
|
||||
// pulled in something else interesting.
|
||||
if (CaretEnd != SourceLength) {
|
||||
assert(CaretEnd < SourceLength && "Unexpected caret position!");
|
||||
unsigned NewEnd = CaretEnd;
|
||||
if (SourceEnd<SourceLine.size()) {
|
||||
unsigned NewEnd = SourceEnd+1;
|
||||
|
||||
// Skip over any whitespace we see here; we're looking for
|
||||
// another bit of interesting text.
|
||||
while (NewEnd != SourceLength && isspace(SourceLine[NewEnd - 1]))
|
||||
while (NewEnd<SourceLine.size() &&
|
||||
(map.byteToColumn(NewEnd)==-1 || isspace(SourceLine[NewEnd])))
|
||||
++NewEnd;
|
||||
|
||||
// Skip over this bit of "interesting" text.
|
||||
while (NewEnd != SourceLength && !isspace(SourceLine[NewEnd - 1]))
|
||||
while (NewEnd<SourceLine.size() &&
|
||||
(map.byteToColumn(NewEnd)!=-1 && !isspace(SourceLine[NewEnd])))
|
||||
++NewEnd;
|
||||
|
||||
if (NewEnd - CaretStart <= TargetColumns) {
|
||||
CaretEnd = NewEnd;
|
||||
unsigned NewColumns = map.byteToColumn(NewEnd) -
|
||||
map.byteToColumn(SourceStart);
|
||||
if (NewColumns <= TargetColumns) {
|
||||
SourceEnd = NewEnd;
|
||||
ExpandedRegion = true;
|
||||
}
|
||||
}
|
||||
@ -156,21 +412,41 @@ static void selectInterestingSourceRegion(std::string &SourceLine,
|
||||
break;
|
||||
}
|
||||
|
||||
CaretStart = map.byteToColumn(SourceStart);
|
||||
CaretEnd = map.byteToColumn(SourceEnd) + CaretColumnsOutsideSource;
|
||||
|
||||
// [CaretStart, CaretEnd) is the slice we want. Update the various
|
||||
// output lines to show only this slice, with two-space padding
|
||||
// before the lines so that it looks nicer.
|
||||
if (CaretEnd < SourceLine.size())
|
||||
SourceLine.replace(CaretEnd, std::string::npos, "...");
|
||||
if (CaretEnd < CaretLine.size())
|
||||
CaretLine.erase(CaretEnd, std::string::npos);
|
||||
if (FixItInsertionLine.size() > CaretEnd)
|
||||
FixItInsertionLine.erase(CaretEnd, std::string::npos);
|
||||
|
||||
if (CaretStart > 2) {
|
||||
SourceLine.replace(0, CaretStart, " ...");
|
||||
CaretLine.replace(0, CaretStart, " ");
|
||||
if (FixItInsertionLine.size() >= CaretStart)
|
||||
FixItInsertionLine.replace(0, CaretStart, " ");
|
||||
assert(CaretStart!=(unsigned)-1 && CaretEnd!=(unsigned)-1 &&
|
||||
SourceStart!=(unsigned)-1 && SourceEnd!=(unsigned)-1);
|
||||
assert(SourceStart <= SourceEnd);
|
||||
assert(CaretStart <= CaretEnd);
|
||||
|
||||
unsigned BackColumnsRemoved
|
||||
= map.byteToColumn(SourceLine.size())-map.byteToColumn(SourceEnd);
|
||||
unsigned FrontColumnsRemoved = CaretStart;
|
||||
unsigned ColumnsKept = CaretEnd-CaretStart;
|
||||
|
||||
// We checked up front that the line needed truncation
|
||||
assert(FrontColumnsRemoved+ColumnsKept+BackColumnsRemoved > Columns);
|
||||
|
||||
// The line needs some trunctiona, and we'd prefer to keep the front
|
||||
// if possible, so remove the back
|
||||
if (BackColumnsRemoved)
|
||||
SourceLine.replace(SourceEnd, std::string::npos, back_ellipse);
|
||||
|
||||
// If that's enough then we're done
|
||||
if (FrontColumnsRemoved+ColumnsKept <= Columns)
|
||||
return;
|
||||
|
||||
// Otherwise remove the front as well
|
||||
if (FrontColumnsRemoved) {
|
||||
SourceLine.replace(0, SourceStart, front_ellipse);
|
||||
CaretLine.replace(0, CaretStart, front_space);
|
||||
if (!FixItInsertionLine.empty())
|
||||
FixItInsertionLine.replace(0, CaretStart, front_space);
|
||||
}
|
||||
}
|
||||
|
||||
@ -564,10 +840,13 @@ void TextDiagnostic::emitSnippetAndCaret(
|
||||
|
||||
// Get information about the buffer it points into.
|
||||
bool Invalid = false;
|
||||
const char *BufStart = SM.getBufferData(FID, &Invalid).data();
|
||||
StringRef BufData = SM.getBufferData(FID, &Invalid);
|
||||
if (Invalid)
|
||||
return;
|
||||
|
||||
const char *BufStart = BufData.data();
|
||||
const char *BufEnd = BufStart + BufData.size();
|
||||
|
||||
unsigned LineNo = SM.getLineNumber(FID, FileOffset);
|
||||
unsigned ColNo = SM.getColumnNumber(FID, FileOffset);
|
||||
unsigned CaretEndColNo
|
||||
@ -581,7 +860,7 @@ void TextDiagnostic::emitSnippetAndCaret(
|
||||
// Compute the line end. Scan forward from the error position to the end of
|
||||
// the line.
|
||||
const char *LineEnd = TokPtr;
|
||||
while (*LineEnd != '\n' && *LineEnd != '\r' && *LineEnd != '\0')
|
||||
while (*LineEnd != '\n' && *LineEnd != '\r' && LineEnd!=BufEnd)
|
||||
++LineEnd;
|
||||
|
||||
// FIXME: This shouldn't be necessary, but the CaretEndColNo can extend past
|
||||
@ -596,19 +875,30 @@ void TextDiagnostic::emitSnippetAndCaret(
|
||||
// length as the line of source code.
|
||||
std::string CaretLine(LineEnd-LineStart, ' ');
|
||||
|
||||
const SourceColumnMap sourceColMap(SourceLine, DiagOpts.TabStop);
|
||||
|
||||
// Highlight all of the characters covered by Ranges with ~ characters.
|
||||
for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(),
|
||||
E = Ranges.end();
|
||||
I != E; ++I)
|
||||
highlightRange(*I, LineNo, FID, SourceLine, CaretLine);
|
||||
highlightRange(*I, LineNo, FID, sourceColMap, CaretLine);
|
||||
|
||||
// Next, insert the caret itself.
|
||||
if (ColNo-1 < CaretLine.size())
|
||||
CaretLine[ColNo-1] = '^';
|
||||
else
|
||||
CaretLine.push_back('^');
|
||||
ColNo = sourceColMap.byteToColumn(ColNo-1);
|
||||
if (CaretLine.size()<ColNo+1)
|
||||
CaretLine.resize(ColNo+1, ' ');
|
||||
CaretLine[ColNo] = '^';
|
||||
|
||||
expandTabs(SourceLine, CaretLine);
|
||||
std::string FixItInsertionLine = buildFixItInsertionLine(LineNo,
|
||||
sourceColMap,
|
||||
Hints);
|
||||
|
||||
// If the source line is too long for our terminal, select only the
|
||||
// "interesting" source region within that line.
|
||||
unsigned Columns = DiagOpts.MessageLength;
|
||||
if (Columns)
|
||||
selectInterestingSourceRegion(SourceLine, CaretLine, FixItInsertionLine,
|
||||
Columns, sourceColMap);
|
||||
|
||||
// If we are in -fdiagnostics-print-source-range-info mode, we are trying
|
||||
// to produce easily machine parsable output. Add a space before the
|
||||
@ -619,23 +909,12 @@ void TextDiagnostic::emitSnippetAndCaret(
|
||||
CaretLine = ' ' + CaretLine;
|
||||
}
|
||||
|
||||
std::string FixItInsertionLine = buildFixItInsertionLine(LineNo,
|
||||
LineStart, LineEnd,
|
||||
Hints);
|
||||
|
||||
// If the source line is too long for our terminal, select only the
|
||||
// "interesting" source region within that line.
|
||||
unsigned Columns = DiagOpts.MessageLength;
|
||||
if (Columns && SourceLine.size() > Columns)
|
||||
selectInterestingSourceRegion(SourceLine, CaretLine, FixItInsertionLine,
|
||||
CaretEndColNo, Columns);
|
||||
|
||||
// Finally, remove any blank spaces from the end of CaretLine.
|
||||
while (CaretLine[CaretLine.size()-1] == ' ')
|
||||
CaretLine.erase(CaretLine.end()-1);
|
||||
|
||||
// Emit what we have computed.
|
||||
OS << SourceLine << '\n';
|
||||
emitSnippet(SourceLine);
|
||||
|
||||
if (DiagOpts.ShowColors)
|
||||
OS.changeColor(caretColor, true);
|
||||
@ -658,13 +937,49 @@ void TextDiagnostic::emitSnippetAndCaret(
|
||||
emitParseableFixits(Hints);
|
||||
}
|
||||
|
||||
void TextDiagnostic::emitSnippet(StringRef line)
|
||||
{
|
||||
if (line.empty())
|
||||
return;
|
||||
|
||||
size_t i = 0;
|
||||
|
||||
std::string to_print;
|
||||
bool print_reversed = false;
|
||||
|
||||
while (i<line.size()) {
|
||||
std::pair<SmallString<16>,bool> res
|
||||
= printableTextForNextCharacter(line, &i, DiagOpts.TabStop);
|
||||
bool was_printable = res.second;
|
||||
|
||||
if (DiagOpts.ShowColors
|
||||
&& was_printable==print_reversed) {
|
||||
if (print_reversed)
|
||||
OS.reverseColor();
|
||||
OS << to_print;
|
||||
to_print.clear();
|
||||
if (DiagOpts.ShowColors)
|
||||
OS.resetColor();
|
||||
}
|
||||
|
||||
print_reversed = !was_printable;
|
||||
to_print += res.first.str();
|
||||
}
|
||||
|
||||
if (print_reversed && DiagOpts.ShowColors)
|
||||
OS.reverseColor();
|
||||
OS << to_print;
|
||||
if (print_reversed && DiagOpts.ShowColors)
|
||||
OS.resetColor();
|
||||
|
||||
OS << '\n';
|
||||
}
|
||||
|
||||
/// \brief Highlight a SourceRange (with ~'s) for any characters on LineNo.
|
||||
void TextDiagnostic::highlightRange(const CharSourceRange &R,
|
||||
unsigned LineNo, FileID FID,
|
||||
const std::string &SourceLine,
|
||||
const SourceColumnMap &map,
|
||||
std::string &CaretLine) {
|
||||
assert(CaretLine.size() == SourceLine.size() &&
|
||||
"Expect a correspondence between source and caret line!");
|
||||
if (!R.isValid()) return;
|
||||
|
||||
SourceLocation Begin = SM.getExpansionLoc(R.getBegin());
|
||||
@ -694,7 +1009,7 @@ void TextDiagnostic::highlightRange(const CharSourceRange &R,
|
||||
}
|
||||
|
||||
// Compute the column number of the end.
|
||||
unsigned EndColNo = CaretLine.size();
|
||||
unsigned EndColNo = map.getSourceLine().size();
|
||||
if (EndLineNo == LineNo) {
|
||||
EndColNo = SM.getExpansionColumnNumber(End);
|
||||
if (EndColNo) {
|
||||
@ -714,15 +1029,17 @@ void TextDiagnostic::highlightRange(const CharSourceRange &R,
|
||||
// Check that a token range does not highlight only whitespace.
|
||||
if (R.isTokenRange()) {
|
||||
// Pick the first non-whitespace column.
|
||||
while (StartColNo < SourceLine.size() &&
|
||||
(SourceLine[StartColNo] == ' ' || SourceLine[StartColNo] == '\t'))
|
||||
while (StartColNo < map.getSourceLine().size() &&
|
||||
(map.getSourceLine()[StartColNo] == ' ' ||
|
||||
map.getSourceLine()[StartColNo] == '\t'))
|
||||
++StartColNo;
|
||||
|
||||
// Pick the last non-whitespace column.
|
||||
if (EndColNo > SourceLine.size())
|
||||
EndColNo = SourceLine.size();
|
||||
if (EndColNo > map.getSourceLine().size())
|
||||
EndColNo = map.getSourceLine().size();
|
||||
while (EndColNo-1 &&
|
||||
(SourceLine[EndColNo-1] == ' ' || SourceLine[EndColNo-1] == '\t'))
|
||||
(map.getSourceLine()[EndColNo-1] == ' ' ||
|
||||
map.getSourceLine()[EndColNo-1] == '\t'))
|
||||
--EndColNo;
|
||||
|
||||
// If the start/end passed each other, then we are trying to highlight a
|
||||
@ -731,15 +1048,24 @@ void TextDiagnostic::highlightRange(const CharSourceRange &R,
|
||||
assert(StartColNo <= EndColNo && "Trying to highlight whitespace??");
|
||||
}
|
||||
|
||||
assert(StartColNo <= map.getSourceLine().size() && "Invalid range!");
|
||||
assert(EndColNo <= map.getSourceLine().size() && "Invalid range!");
|
||||
|
||||
// Fill the range with ~'s.
|
||||
for (unsigned i = StartColNo; i < EndColNo; ++i)
|
||||
CaretLine[i] = '~';
|
||||
StartColNo = map.byteToColumn(StartColNo);
|
||||
EndColNo = map.byteToColumn(EndColNo);
|
||||
|
||||
assert(StartColNo <= EndColNo && "Invalid range!");
|
||||
if (CaretLine.size() < EndColNo)
|
||||
CaretLine.resize(EndColNo,' ');
|
||||
std::fill(CaretLine.begin()+StartColNo,CaretLine.begin()+EndColNo,'~');
|
||||
}
|
||||
|
||||
std::string TextDiagnostic::buildFixItInsertionLine(unsigned LineNo,
|
||||
const char *LineStart,
|
||||
const char *LineEnd,
|
||||
ArrayRef<FixItHint> Hints) {
|
||||
std::string TextDiagnostic::buildFixItInsertionLine(
|
||||
unsigned LineNo,
|
||||
const SourceColumnMap &map,
|
||||
ArrayRef<FixItHint> Hints) {
|
||||
|
||||
std::string FixItInsertionLine;
|
||||
if (Hints.empty() || !DiagOpts.ShowFixits)
|
||||
return FixItInsertionLine;
|
||||
@ -755,13 +1081,32 @@ std::string TextDiagnostic::buildFixItInsertionLine(unsigned LineNo,
|
||||
// Insert the new code into the line just below the code
|
||||
// that the user wrote.
|
||||
unsigned HintColNo
|
||||
= SM.getColumnNumber(HintLocInfo.first, HintLocInfo.second);
|
||||
= SM.getColumnNumber(HintLocInfo.first, HintLocInfo.second) - 1;
|
||||
// hint must start inside the source or right at the end
|
||||
assert(HintColNo<static_cast<unsigned>(map.bytes())+1);
|
||||
HintColNo = map.byteToColumn(HintColNo);
|
||||
|
||||
// FIXME: if the fixit includes tabs or other characters that do not
|
||||
// take up a single column per byte when displayed then
|
||||
// I->CodeToInsert.size() is not a column number and we're mixing
|
||||
// units (columns + bytes). We should get printable versions
|
||||
// of each fixit before using them.
|
||||
unsigned LastColumnModified
|
||||
= HintColNo - 1 + I->CodeToInsert.size();
|
||||
= HintColNo + I->CodeToInsert.size();
|
||||
|
||||
if (LastColumnModified > static_cast<unsigned>(map.bytes())) {
|
||||
unsigned LastExistingColumn = map.byteToColumn(map.bytes());
|
||||
unsigned AddedColumns = LastColumnModified-LastExistingColumn;
|
||||
LastColumnModified = LastExistingColumn + AddedColumns;
|
||||
} else {
|
||||
LastColumnModified = map.byteToColumn(LastColumnModified);
|
||||
}
|
||||
|
||||
if (LastColumnModified > FixItInsertionLine.size())
|
||||
FixItInsertionLine.resize(LastColumnModified, ' ');
|
||||
assert(HintColNo+I->CodeToInsert.size() <= FixItInsertionLine.size());
|
||||
std::copy(I->CodeToInsert.begin(), I->CodeToInsert.end(),
|
||||
FixItInsertionLine.begin() + HintColNo - 1);
|
||||
FixItInsertionLine.begin() + HintColNo);
|
||||
} else {
|
||||
FixItInsertionLine.clear();
|
||||
break;
|
||||
@ -769,72 +1114,11 @@ std::string TextDiagnostic::buildFixItInsertionLine(unsigned LineNo,
|
||||
}
|
||||
}
|
||||
|
||||
if (FixItInsertionLine.empty())
|
||||
return FixItInsertionLine;
|
||||
|
||||
// Now that we have the entire fixit line, expand the tabs in it.
|
||||
// Since we don't want to insert spaces in the middle of a word,
|
||||
// find each word and the column it should line up with and insert
|
||||
// spaces until they match.
|
||||
unsigned FixItPos = 0;
|
||||
unsigned LinePos = 0;
|
||||
unsigned TabExpandedCol = 0;
|
||||
unsigned LineLength = LineEnd - LineStart;
|
||||
|
||||
while (FixItPos < FixItInsertionLine.size() && LinePos < LineLength) {
|
||||
// Find the next word in the FixIt line.
|
||||
while (FixItPos < FixItInsertionLine.size() &&
|
||||
FixItInsertionLine[FixItPos] == ' ')
|
||||
++FixItPos;
|
||||
unsigned CharDistance = FixItPos - TabExpandedCol;
|
||||
|
||||
// Walk forward in the source line, keeping track of
|
||||
// the tab-expanded column.
|
||||
for (unsigned I = 0; I < CharDistance; ++I, ++LinePos)
|
||||
if (LinePos >= LineLength || LineStart[LinePos] != '\t')
|
||||
++TabExpandedCol;
|
||||
else
|
||||
TabExpandedCol =
|
||||
(TabExpandedCol/DiagOpts.TabStop + 1) * DiagOpts.TabStop;
|
||||
|
||||
// Adjust the fixit line to match this column.
|
||||
FixItInsertionLine.insert(FixItPos, TabExpandedCol-FixItPos, ' ');
|
||||
FixItPos = TabExpandedCol;
|
||||
|
||||
// Walk to the end of the word.
|
||||
while (FixItPos < FixItInsertionLine.size() &&
|
||||
FixItInsertionLine[FixItPos] != ' ')
|
||||
++FixItPos;
|
||||
}
|
||||
expandTabs(FixItInsertionLine, DiagOpts.TabStop);
|
||||
|
||||
return FixItInsertionLine;
|
||||
}
|
||||
|
||||
void TextDiagnostic::expandTabs(std::string &SourceLine,
|
||||
std::string &CaretLine) {
|
||||
// Scan the source line, looking for tabs. If we find any, manually expand
|
||||
// them to spaces and update the CaretLine to match.
|
||||
for (unsigned i = 0; i != SourceLine.size(); ++i) {
|
||||
if (SourceLine[i] != '\t') continue;
|
||||
|
||||
// Replace this tab with at least one space.
|
||||
SourceLine[i] = ' ';
|
||||
|
||||
// Compute the number of spaces we need to insert.
|
||||
unsigned TabStop = DiagOpts.TabStop;
|
||||
assert(0 < TabStop && TabStop <= DiagnosticOptions::MaxTabStop &&
|
||||
"Invalid -ftabstop value");
|
||||
unsigned NumSpaces = ((i+TabStop)/TabStop * TabStop) - (i+1);
|
||||
assert(NumSpaces < TabStop && "Invalid computation of space amt");
|
||||
|
||||
// Insert spaces into the SourceLine.
|
||||
SourceLine.insert(i+1, NumSpaces, ' ');
|
||||
|
||||
// Insert spaces or ~'s into CaretLine.
|
||||
CaretLine.insert(i+1, NumSpaces, CaretLine[i] == '~' ? '~' : ' ');
|
||||
}
|
||||
}
|
||||
|
||||
void TextDiagnostic::emitParseableFixits(ArrayRef<FixItHint> Hints) {
|
||||
if (!DiagOpts.ShowParseableFixits)
|
||||
return;
|
||||
@ -878,4 +1162,3 @@ void TextDiagnostic::emitParseableFixits(ArrayRef<FixItHint> Hints) {
|
||||
OS << "\"\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,7 +72,6 @@ static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) {
|
||||
case PrintDeclContext: return new DeclContextPrintAction();
|
||||
case PrintPreamble: return new PrintPreambleAction();
|
||||
case PrintPreprocessedInput: return new PrintPreprocessedAction();
|
||||
case PubnamesDump: return new PubnamesDumpAction();
|
||||
case RewriteMacros: return new RewriteMacrosAction();
|
||||
case RewriteObjC: return new RewriteObjCAction();
|
||||
case RewriteTest: return new RewriteTestAction();
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user