summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorrdivacky <rdivacky@FreeBSD.org>2010-01-23 11:10:26 +0000
committerrdivacky <rdivacky@FreeBSD.org>2010-01-23 11:10:26 +0000
commit2fce988e86bc01829142e4362d4eff1af0925147 (patch)
treec69d3f4f13d508570bb5257a6aea735f88bdf09c /lib
parenta3fa5c7f1b5e2ba4d6ec033dc0e2376326b05824 (diff)
downloadFreeBSD-src-2fce988e86bc01829142e4362d4eff1af0925147.zip
FreeBSD-src-2fce988e86bc01829142e4362d4eff1af0925147.tar.gz
Update clang to r94309.
Diffstat (limited to 'lib')
-rw-r--r--lib/AST/ASTContext.cpp104
-rw-r--r--lib/AST/CXXInheritance.cpp36
-rw-r--r--lib/AST/Decl.cpp8
-rw-r--r--lib/AST/DeclBase.cpp20
-rw-r--r--lib/AST/DeclCXX.cpp12
-rw-r--r--lib/AST/DeclObjC.cpp48
-rw-r--r--lib/AST/Expr.cpp10
-rw-r--r--lib/AST/ExprCXX.cpp9
-rw-r--r--lib/AST/ExprConstant.cpp9
-rw-r--r--lib/AST/RecordLayoutBuilder.cpp5
-rw-r--r--lib/AST/Type.cpp39
-rw-r--r--lib/AST/TypeLoc.cpp54
-rw-r--r--lib/Analysis/AnalysisContext.cpp2
-rw-r--r--lib/Analysis/ArrayBoundChecker.cpp3
-rw-r--r--lib/Analysis/CFG.cpp292
-rw-r--r--lib/Analysis/CastToStructChecker.cpp2
-rw-r--r--lib/Analysis/GRExprEngine.cpp76
-rw-r--r--lib/Analysis/MallocChecker.cpp22
-rw-r--r--lib/Analysis/RegionStore.cpp25
-rw-r--r--lib/Analysis/ReturnPointerRangeChecker.cpp3
-rw-r--r--lib/Basic/Makefile5
-rw-r--r--lib/Basic/Targets.cpp2
-rw-r--r--lib/Basic/Version.cpp42
-rw-r--r--lib/CodeGen/CGBlocks.cpp26
-rw-r--r--lib/CodeGen/CGBuiltin.cpp13
-rw-r--r--lib/CodeGen/CGClass.cpp24
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp193
-rw-r--r--lib/CodeGen/CGDebugInfo.h8
-rw-r--r--lib/CodeGen/CGExprConstant.cpp14
-rw-r--r--lib/CodeGen/CGObjC.cpp3
-rw-r--r--lib/CodeGen/CGObjCGNU.cpp25
-rw-r--r--lib/CodeGen/CGObjCMac.cpp6
-rw-r--r--lib/CodeGen/CGObjCRuntime.h2
-rw-r--r--lib/CodeGen/CGVTT.cpp398
-rw-r--r--lib/CodeGen/CGVtable.cpp444
-rw-r--r--lib/CodeGen/CMakeLists.txt1
-rw-r--r--lib/CodeGen/CodeGenModule.cpp9
-rw-r--r--lib/CodeGen/CodeGenModule.h5
-rw-r--r--lib/CodeGen/TargetABIInfo.cpp1821
-rw-r--r--lib/CodeGen/TargetInfo.cpp14
-rw-r--r--lib/CodeGen/TargetInfo.h4
-rw-r--r--lib/Driver/Driver.cpp28
-rw-r--r--lib/Driver/Makefile3
-rw-r--r--lib/Driver/ToolChains.cpp145
-rw-r--r--lib/Driver/ToolChains.h5
-rw-r--r--lib/Driver/Tools.cpp104
-rw-r--r--lib/Driver/Tools.h1
-rw-r--r--lib/Frontend/ASTConsumers.cpp5
-rw-r--r--lib/Frontend/ASTUnit.cpp32
-rw-r--r--lib/Frontend/AnalysisConsumer.cpp98
-rw-r--r--lib/Frontend/CacheTokens.cpp38
-rw-r--r--lib/Frontend/DeclXML.cpp4
-rw-r--r--lib/Frontend/HTMLDiagnostics.cpp24
-rw-r--r--lib/Frontend/InitHeaderSearch.cpp26
-rw-r--r--lib/Frontend/InitPreprocessor.cpp47
-rw-r--r--lib/Frontend/PCHReader.cpp33
-rw-r--r--lib/Frontend/PCHReaderDecl.cpp38
-rw-r--r--lib/Frontend/PCHReaderStmt.cpp60
-rw-r--r--lib/Frontend/PCHWriter.cpp31
-rw-r--r--lib/Frontend/PCHWriterDecl.cpp24
-rw-r--r--lib/Frontend/PCHWriterStmt.cpp41
-rw-r--r--lib/Frontend/PlistDiagnostics.cpp56
-rw-r--r--lib/Frontend/PrintParserCallbacks.cpp4
-rw-r--r--lib/Frontend/PrintPreprocessedOutput.cpp24
-rw-r--r--lib/Frontend/RewriteObjC.cpp262
-rw-r--r--lib/Frontend/StmtXML.cpp34
-rw-r--r--lib/Frontend/TextDiagnosticPrinter.cpp36
-rw-r--r--lib/Frontend/TypeXML.cpp4
-rw-r--r--lib/Index/ResolveLocation.cpp2
-rw-r--r--lib/Lex/Lexer.cpp42
-rw-r--r--lib/Lex/LiteralSupport.cpp2
-rw-r--r--lib/Lex/PPDirectives.cpp20
-rw-r--r--lib/Lex/PPMacroExpansion.cpp4
-rw-r--r--lib/Lex/Pragma.cpp3
-rw-r--r--lib/Lex/Preprocessor.cpp31
-rwxr-xr-xlib/Makefile4
-rw-r--r--lib/Parse/DeclSpec.cpp19
-rw-r--r--lib/Parse/MinimalAction.cpp1
-rw-r--r--lib/Parse/ParseDeclCXX.cpp38
-rw-r--r--lib/Parse/ParseObjc.cpp3
-rw-r--r--lib/Parse/Parser.cpp3
-rw-r--r--lib/Rewrite/DeltaTree.cpp2
-rw-r--r--lib/Sema/CodeCompleteConsumer.cpp4
-rw-r--r--lib/Sema/Lookup.h104
-rw-r--r--lib/Sema/Sema.h69
-rw-r--r--lib/Sema/SemaAccess.cpp99
-rw-r--r--lib/Sema/SemaCXXCast.cpp31
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp26
-rw-r--r--lib/Sema/SemaChecking.cpp527
-rw-r--r--lib/Sema/SemaCodeComplete.cpp36
-rw-r--r--lib/Sema/SemaDecl.cpp418
-rw-r--r--lib/Sema/SemaDeclCXX.cpp59
-rw-r--r--lib/Sema/SemaDeclObjC.cpp214
-rw-r--r--lib/Sema/SemaExpr.cpp112
-rw-r--r--lib/Sema/SemaExprCXX.cpp20
-rw-r--r--lib/Sema/SemaExprObjC.cpp12
-rw-r--r--lib/Sema/SemaInit.cpp38
-rw-r--r--lib/Sema/SemaInit.h15
-rw-r--r--lib/Sema/SemaLookup.cpp42
-rw-r--r--lib/Sema/SemaOverload.cpp269
-rw-r--r--lib/Sema/SemaOverload.h11
-rw-r--r--lib/Sema/SemaStmt.cpp8
-rw-r--r--lib/Sema/SemaTemplate.cpp25
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp57
-rw-r--r--lib/Sema/SemaType.cpp15
-rw-r--r--lib/Sema/TreeTransform.h133
106 files changed, 3755 insertions, 3808 deletions
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 76ec852..c1bc709 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -1200,43 +1200,58 @@ QualType ASTContext::getObjCGCQualType(QualType T,
return getExtQualType(TypeNode, Quals);
}
-QualType ASTContext::getNoReturnType(QualType T, bool AddNoReturn) {
+static QualType getNoReturnCallConvType(ASTContext& Context, QualType T,
+ bool AddNoReturn,
+ CallingConv CallConv) {
QualType ResultType;
if (const PointerType *Pointer = T->getAs<PointerType>()) {
QualType Pointee = Pointer->getPointeeType();
- ResultType = getNoReturnType(Pointee, AddNoReturn);
+ ResultType = getNoReturnCallConvType(Context, Pointee, AddNoReturn,
+ CallConv);
if (ResultType == Pointee)
return T;
-
- ResultType = getPointerType(ResultType);
+
+ ResultType = Context.getPointerType(ResultType);
} else if (const BlockPointerType *BlockPointer
= T->getAs<BlockPointerType>()) {
QualType Pointee = BlockPointer->getPointeeType();
- ResultType = getNoReturnType(Pointee, AddNoReturn);
+ ResultType = getNoReturnCallConvType(Context, Pointee, AddNoReturn,
+ CallConv);
if (ResultType == Pointee)
return T;
-
- ResultType = getBlockPointerType(ResultType);
- } else if (const FunctionType *F = T->getAs<FunctionType>()) {
- if (F->getNoReturnAttr() == AddNoReturn)
+
+ ResultType = Context.getBlockPointerType(ResultType);
+ } else if (const FunctionType *F = T->getAs<FunctionType>()) {
+ if (F->getNoReturnAttr() == AddNoReturn && F->getCallConv() == CallConv)
return T;
-
+
if (const FunctionNoProtoType *FNPT = dyn_cast<FunctionNoProtoType>(F)) {
- ResultType = getFunctionNoProtoType(FNPT->getResultType(), AddNoReturn);
+ ResultType = Context.getFunctionNoProtoType(FNPT->getResultType(),
+ AddNoReturn, CallConv);
} else {
const FunctionProtoType *FPT = cast<FunctionProtoType>(F);
ResultType
- = getFunctionType(FPT->getResultType(), FPT->arg_type_begin(),
- FPT->getNumArgs(), FPT->isVariadic(),
- FPT->getTypeQuals(),
- FPT->hasExceptionSpec(), FPT->hasAnyExceptionSpec(),
- FPT->getNumExceptions(), FPT->exception_begin(),
- AddNoReturn);
+ = Context.getFunctionType(FPT->getResultType(), FPT->arg_type_begin(),
+ FPT->getNumArgs(), FPT->isVariadic(),
+ FPT->getTypeQuals(),
+ FPT->hasExceptionSpec(),
+ FPT->hasAnyExceptionSpec(),
+ FPT->getNumExceptions(),
+ FPT->exception_begin(),
+ AddNoReturn, CallConv);
}
} else
return T;
-
- return getQualifiedType(ResultType, T.getLocalQualifiers());
+
+ return Context.getQualifiedType(ResultType, T.getLocalQualifiers());
+}
+
+QualType ASTContext::getNoReturnType(QualType T, bool AddNoReturn) {
+ return getNoReturnCallConvType(*this, T, AddNoReturn, T.getCallConv());
+}
+
+QualType ASTContext::getCallConvType(QualType T, CallingConv CallConv) {
+ return getNoReturnCallConvType(*this, T, T.getNoReturnAttr(), CallConv);
}
/// getComplexType - Return the uniqued reference to the type for a complex
@@ -1679,9 +1694,16 @@ QualType ASTContext::getDependentSizedExtVectorType(QualType vecType,
return QualType(New, 0);
}
+static CallingConv getCanonicalCallingConv(CallingConv CC) {
+ if (CC == CC_C)
+ return CC_Default;
+ return CC;
+}
+
/// getFunctionNoProtoType - Return a K&R style C function type like 'int()'.
///
-QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn) {
+QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn,
+ CallingConv CallConv) {
// Unique functions, to guarantee there is only one function of a particular
// structure.
llvm::FoldingSetNodeID ID;
@@ -1693,8 +1715,10 @@ QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, bool NoReturn) {
return QualType(FT, 0);
QualType Canonical;
- if (!ResultTy.isCanonical()) {
- Canonical = getFunctionNoProtoType(getCanonicalType(ResultTy), NoReturn);
+ if (!ResultTy.isCanonical() ||
+ getCanonicalCallingConv(CallConv) != CallConv) {
+ Canonical = getFunctionNoProtoType(getCanonicalType(ResultTy), NoReturn,
+ getCanonicalCallingConv(CallConv));
// Get the new insert position for the node we care about.
FunctionNoProtoType *NewIP =
@@ -1715,7 +1739,8 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray,
unsigned NumArgs, bool isVariadic,
unsigned TypeQuals, bool hasExceptionSpec,
bool hasAnyExceptionSpec, unsigned NumExs,
- const QualType *ExArray, bool NoReturn) {
+ const QualType *ExArray, bool NoReturn,
+ CallingConv CallConv) {
// Unique functions, to guarantee there is only one function of a particular
// structure.
llvm::FoldingSetNodeID ID;
@@ -1737,7 +1762,7 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray,
// If this type isn't canonical, get the canonical version of it.
// The exception spec is not part of the canonical type.
QualType Canonical;
- if (!isCanonical) {
+ if (!isCanonical || getCanonicalCallingConv(CallConv) != CallConv) {
llvm::SmallVector<QualType, 16> CanonicalArgs;
CanonicalArgs.reserve(NumArgs);
for (unsigned i = 0; i != NumArgs; ++i)
@@ -1746,7 +1771,8 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray,
Canonical = getFunctionType(getCanonicalType(ResultTy),
CanonicalArgs.data(), NumArgs,
isVariadic, TypeQuals, false,
- false, 0, 0, NoReturn);
+ false, 0, 0, NoReturn,
+ getCanonicalCallingConv(CallConv));
// Get the new insert position for the node we care about.
FunctionProtoType *NewIP =
@@ -1763,7 +1789,7 @@ QualType ASTContext::getFunctionType(QualType ResultTy,const QualType *ArgArray,
NumExs*sizeof(QualType), TypeAlignment);
new (FTP) FunctionProtoType(ResultTy, ArgArray, NumArgs, isVariadic,
TypeQuals, hasExceptionSpec, hasAnyExceptionSpec,
- ExArray, NumExs, Canonical, NoReturn);
+ ExArray, NumExs, Canonical, NoReturn, CallConv);
Types.push_back(FTP);
FunctionProtoTypes.InsertNode(FTP, InsertPos);
return QualType(FTP, 0);
@@ -2101,7 +2127,8 @@ QualType ASTContext::getObjCObjectPointerType(QualType InterfaceT,
// No Match;
ObjCObjectPointerType *QType = new (*this, TypeAlignment)
- ObjCObjectPointerType(Canonical, InterfaceT, Protocols, NumProtocols);
+ ObjCObjectPointerType(*this, Canonical, InterfaceT, Protocols,
+ NumProtocols);
Types.push_back(QType);
ObjCObjectPointerTypes.InsertNode(QType, InsertPos);
@@ -2135,7 +2162,7 @@ QualType ASTContext::getObjCInterfaceType(const ObjCInterfaceDecl *Decl,
}
ObjCInterfaceType *QType = new (*this, TypeAlignment)
- ObjCInterfaceType(Canonical, const_cast<ObjCInterfaceDecl*>(Decl),
+ ObjCInterfaceType(*this, Canonical, const_cast<ObjCInterfaceDecl*>(Decl),
Protocols, NumProtocols);
Types.push_back(QType);
@@ -3733,8 +3760,8 @@ void ASTContext::setObjCConstantStringInterface(ObjCInterfaceDecl *Decl) {
/// \brief Retrieve the template name that corresponds to a non-empty
/// lookup.
-TemplateName ASTContext::getOverloadedTemplateName(NamedDecl * const *Begin,
- NamedDecl * const *End) {
+TemplateName ASTContext::getOverloadedTemplateName(UnresolvedSetIterator Begin,
+ UnresolvedSetIterator End) {
unsigned size = End - Begin;
assert(size > 1 && "set is not overloaded!");
@@ -3743,7 +3770,7 @@ TemplateName ASTContext::getOverloadedTemplateName(NamedDecl * const *Begin,
OverloadedTemplateStorage *OT = new(memory) OverloadedTemplateStorage(size);
NamedDecl **Storage = OT->getStorage();
- for (NamedDecl * const *I = Begin; I != End; ++I) {
+ for (UnresolvedSetIterator I = Begin; I != End; ++I) {
NamedDecl *D = *I;
assert(isa<FunctionTemplateDecl>(D) ||
(isa<UsingShadowDecl>(D) &&
@@ -4211,6 +4238,10 @@ bool ASTContext::typesAreCompatible(QualType LHS, QualType RHS) {
return !mergeTypes(LHS, RHS).isNull();
}
+static bool isSameCallingConvention(CallingConv lcc, CallingConv rcc) {
+ return (getCanonicalCallingConv(lcc) == getCanonicalCallingConv(rcc));
+}
+
QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) {
const FunctionType *lbase = lhs->getAs<FunctionType>();
const FunctionType *rbase = rhs->getAs<FunctionType>();
@@ -4232,6 +4263,11 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) {
allLTypes = false;
if (NoReturn != rbase->getNoReturnAttr())
allRTypes = false;
+ CallingConv lcc = lbase->getCallConv();
+ CallingConv rcc = rbase->getCallConv();
+ // Compatible functions must have compatible calling conventions
+ if (!isSameCallingConvention(lcc, rcc))
+ return QualType();
if (lproto && rproto) { // two C99 style function prototypes
assert(!lproto->hasExceptionSpec() && !rproto->hasExceptionSpec() &&
@@ -4267,7 +4303,7 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) {
if (allRTypes) return rhs;
return getFunctionType(retType, types.begin(), types.size(),
lproto->isVariadic(), lproto->getTypeQuals(),
- NoReturn);
+ NoReturn, lcc);
}
if (lproto) allRTypes = false;
@@ -4294,12 +4330,12 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) {
if (allRTypes) return rhs;
return getFunctionType(retType, proto->arg_type_begin(),
proto->getNumArgs(), proto->isVariadic(),
- proto->getTypeQuals(), NoReturn);
+ proto->getTypeQuals(), NoReturn, lcc);
}
if (allLTypes) return lhs;
if (allRTypes) return rhs;
- return getFunctionNoProtoType(retType, NoReturn);
+ return getFunctionNoProtoType(retType, NoReturn, lcc);
}
QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) {
diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp
index 92a58b7..7208328 100644
--- a/lib/AST/CXXInheritance.cpp
+++ b/lib/AST/CXXInheritance.cpp
@@ -145,7 +145,11 @@ bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches,
void *UserData,
CXXBasePaths &Paths) const {
bool FoundPath = false;
-
+
+ // The access of the path down to this record.
+ AccessSpecifier AccessToHere = Paths.ScratchPath.Access;
+ bool IsFirstStep = Paths.ScratchPath.empty();
+
ASTContext &Context = getASTContext();
for (base_class_const_iterator BaseSpec = bases_begin(),
BaseSpecEnd = bases_end(); BaseSpec != BaseSpecEnd; ++BaseSpec) {
@@ -189,10 +193,31 @@ bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches,
else
Element.SubobjectNumber = Subobjects.second;
Paths.ScratchPath.push_back(Element);
+
+ // Calculate the "top-down" access to this base class.
+ // The spec actually describes this bottom-up, but top-down is
+ // equivalent because the definition works out as follows:
+ // 1. Write down the access along each step in the inheritance
+ // chain, followed by the access of the decl itself.
+ // For example, in
+ // class A { public: int foo; };
+ // class B : protected A {};
+ // class C : public B {};
+ // class D : private C {};
+ // we would write:
+ // private public protected public
+ // 2. If 'private' appears anywhere except far-left, access is denied.
+ // 3. Otherwise, overall access is determined by the most restrictive
+ // access in the sequence.
+ if (IsFirstStep)
+ Paths.ScratchPath.Access = BaseSpec->getAccessSpecifier();
+ else
+ Paths.ScratchPath.Access
+ = MergeAccess(AccessToHere, BaseSpec->getAccessSpecifier());
}
if (BaseMatches(BaseSpec, Paths.ScratchPath, UserData)) {
- // We've found a path that terminates that this base.
+ // We've found a path that terminates at this base.
FoundPath = true;
if (Paths.isRecordingPaths()) {
// We have a path. Make a copy of it before moving on.
@@ -223,13 +248,18 @@ bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches,
// Pop this base specifier off the current path (if we're
// collecting paths).
- if (Paths.isRecordingPaths())
+ if (Paths.isRecordingPaths()) {
Paths.ScratchPath.pop_back();
+ }
+
// If we set a virtual earlier, and this isn't a path, forget it again.
if (SetVirtual && !FoundPath) {
Paths.DetectedVirtual = 0;
}
}
+
+ // Reset the scratch path access.
+ Paths.ScratchPath.Access = AccessToHere;
return FoundPath;
}
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index e77661a..794b14a 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -629,9 +629,13 @@ VarDecl::~VarDecl() {
}
SourceRange VarDecl::getSourceRange() const {
+ SourceLocation Start = getTypeSpecStartLoc();
+ if (Start.isInvalid())
+ Start = getLocation();
+
if (getInit())
- return SourceRange(getLocation(), getInit()->getLocEnd());
- return SourceRange(getLocation(), getLocation());
+ return SourceRange(Start, getInit()->getLocEnd());
+ return SourceRange(Start, getLocation());
}
bool VarDecl::isOutOfLine() const {
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 3afb4e4..84aa81c 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -102,6 +102,17 @@ bool Decl::isFunctionOrFunctionTemplate() const {
return isa<FunctionDecl>(this) || isa<FunctionTemplateDecl>(this);
}
+bool Decl::isDefinedOutsideFunctionOrMethod() const {
+ for (const DeclContext *DC = getDeclContext();
+ DC && !DC->isTranslationUnit();
+ DC = DC->getParent())
+ if (DC->isFunctionOrMethod())
+ return false;
+
+ return true;
+}
+
+
//===----------------------------------------------------------------------===//
// PrettyStackTraceDecl Implementation
//===----------------------------------------------------------------------===//
@@ -399,8 +410,13 @@ SourceLocation Decl::getBodyRBrace() const {
#ifndef NDEBUG
void Decl::CheckAccessDeclContext() const {
- // If the decl is the toplevel translation unit or if we're not in a
- // record decl context, we don't need to check anything.
+ // Suppress this check if any of the following hold:
+ // 1. this is the translation unit (and thus has no parent)
+ // 2. this is a template parameter (and thus doesn't belong to its context)
+ // 3. this is a ParmVarDecl (which can be in a record context during
+ // the brief period between its creation and the creation of the
+ // FunctionDecl)
+ // 4. the context is not a record
if (isa<TranslationUnitDecl>(this) ||
!isa<CXXRecordDecl>(getDeclContext()))
return;
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 1cce35c..fe6064d 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -312,8 +312,9 @@ void
CXXRecordDecl::collectConversionFunctions(
llvm::SmallPtrSet<CanQualType, 8>& ConversionsTypeSet) const
{
- const UnresolvedSet *Cs = getConversionFunctions();
- for (UnresolvedSet::iterator I = Cs->begin(), E = Cs->end(); I != E; ++I) {
+ const UnresolvedSetImpl *Cs = getConversionFunctions();
+ for (UnresolvedSetImpl::iterator I = Cs->begin(), E = Cs->end();
+ I != E; ++I) {
NamedDecl *TopConv = *I;
CanQualType TConvType;
if (FunctionTemplateDecl *TConversionTemplate =
@@ -344,10 +345,11 @@ CXXRecordDecl::getNestedVisibleConversionFunctions(CXXRecordDecl *RD,
bool inTopClass = (RD == this);
QualType ClassType = getASTContext().getTypeDeclType(this);
if (const RecordType *Record = ClassType->getAs<RecordType>()) {
- const UnresolvedSet *Cs
+ const UnresolvedSetImpl *Cs
= cast<CXXRecordDecl>(Record->getDecl())->getConversionFunctions();
- for (UnresolvedSet::iterator I = Cs->begin(), E = Cs->end(); I != E; ++I) {
+ for (UnresolvedSetImpl::iterator I = Cs->begin(), E = Cs->end();
+ I != E; ++I) {
NamedDecl *Conv = *I;
// Only those conversions not exact match of conversions in current
// class are candidateconversion routines.
@@ -410,7 +412,7 @@ CXXRecordDecl::getNestedVisibleConversionFunctions(CXXRecordDecl *RD,
/// getVisibleConversionFunctions - get all conversion functions visible
/// in current class; including conversion function templates.
-const UnresolvedSet *CXXRecordDecl::getVisibleConversionFunctions() {
+const UnresolvedSetImpl *CXXRecordDecl::getVisibleConversionFunctions() {
// If root class, all conversions are visible.
if (bases_begin() == bases_end())
return &Conversions;
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index 2506f27..ffda505 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -37,6 +37,21 @@ void ObjCListBase::set(void *const* InList, unsigned Elts, ASTContext &Ctx) {
memcpy(List, InList, sizeof(void*)*Elts);
}
+void ObjCProtocolList::set(ObjCProtocolDecl* const* InList, unsigned Elts,
+ const SourceLocation *Locs, ASTContext &Ctx) {
+ if (Elts == 0)
+ return;
+
+ Locations = new (Ctx) SourceLocation[Elts];
+ memcpy(Locations, Locs, sizeof(SourceLocation) * Elts);
+ set(InList, Elts, Ctx);
+}
+
+void ObjCProtocolList::Destroy(ASTContext &Ctx) {
+ Ctx.Deallocate(Locations);
+ Locations = 0;
+ ObjCList<ObjCProtocolDecl>::Destroy(Ctx);
+}
//===----------------------------------------------------------------------===//
// ObjCInterfaceDecl
@@ -141,16 +156,18 @@ ObjCContainerDecl::FindPropertyVisibleInPrimaryClass(
void ObjCInterfaceDecl::mergeClassExtensionProtocolList(
ObjCProtocolDecl *const* ExtList, unsigned ExtNum,
+ const SourceLocation *Locs,
ASTContext &C)
{
if (ReferencedProtocols.empty()) {
- ReferencedProtocols.set(ExtList, ExtNum, C);
+ ReferencedProtocols.set(ExtList, ExtNum, Locs, C);
return;
}
// Check for duplicate protocol in class's protocol list.
// This is (O)2. But it is extremely rare and number of protocols in
// class or its extension are very few.
llvm::SmallVector<ObjCProtocolDecl*, 8> ProtocolRefs;
+ llvm::SmallVector<SourceLocation, 8> ProtocolLocs;
for (unsigned i = 0; i < ExtNum; i++) {
bool protocolExists = false;
ObjCProtocolDecl *ProtoInExtension = ExtList[i];
@@ -164,18 +181,23 @@ void ObjCInterfaceDecl::mergeClassExtensionProtocolList(
}
// Do we want to warn on a protocol in extension class which
// already exist in the class? Probably not.
- if (!protocolExists)
+ if (!protocolExists) {
ProtocolRefs.push_back(ProtoInExtension);
+ ProtocolLocs.push_back(Locs[i]);
+ }
}
if (ProtocolRefs.empty())
return;
// Merge ProtocolRefs into class's protocol list;
+ protocol_loc_iterator pl = protocol_loc_begin();
for (protocol_iterator p = protocol_begin(), e = protocol_end();
- p != e; p++)
+ p != e; ++p, ++pl) {
ProtocolRefs.push_back(*p);
+ ProtocolLocs.push_back(*pl);
+ }
ReferencedProtocols.Destroy(C);
unsigned NumProtoRefs = ProtocolRefs.size();
- setProtocolList((ObjCProtocolDecl**)&ProtocolRefs[0], NumProtoRefs, C);
+ setProtocolList(ProtocolRefs.data(), NumProtoRefs, ProtocolLocs.data(), C);
}
ObjCIvarDecl *ObjCInterfaceDecl::lookupInstanceVariable(IdentifierInfo *ID,
@@ -627,9 +649,9 @@ SourceRange ObjCClassDecl::getSourceRange() const {
ObjCForwardProtocolDecl::
ObjCForwardProtocolDecl(DeclContext *DC, SourceLocation L,
ObjCProtocolDecl *const *Elts, unsigned nElts,
- ASTContext &C)
+ const SourceLocation *Locs, ASTContext &C)
: Decl(ObjCForwardProtocol, DC, L) {
- ReferencedProtocols.set(Elts, nElts, C);
+ ReferencedProtocols.set(Elts, nElts, Locs, C);
}
@@ -637,8 +659,9 @@ ObjCForwardProtocolDecl *
ObjCForwardProtocolDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation L,
ObjCProtocolDecl *const *Elts,
- unsigned NumElts) {
- return new (C) ObjCForwardProtocolDecl(DC, L, Elts, NumElts, C);
+ unsigned NumElts,
+ const SourceLocation *Locs) {
+ return new (C) ObjCForwardProtocolDecl(DC, L, Elts, NumElts, Locs, C);
}
void ObjCForwardProtocolDecl::Destroy(ASTContext &C) {
@@ -651,9 +674,11 @@ void ObjCForwardProtocolDecl::Destroy(ASTContext &C) {
//===----------------------------------------------------------------------===//
ObjCCategoryDecl *ObjCCategoryDecl::Create(ASTContext &C, DeclContext *DC,
- SourceLocation L,
+ SourceLocation AtLoc,
+ SourceLocation ClassNameLoc,
+ SourceLocation CategoryNameLoc,
IdentifierInfo *Id) {
- return new (C) ObjCCategoryDecl(DC, L, Id);
+ return new (C) ObjCCategoryDecl(DC, AtLoc, ClassNameLoc, CategoryNameLoc, Id);
}
ObjCCategoryImplDecl *ObjCCategoryDecl::getImplementation() const {
@@ -765,9 +790,10 @@ ObjCCompatibleAliasDecl::Create(ASTContext &C, DeclContext *DC,
ObjCPropertyDecl *ObjCPropertyDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation L,
IdentifierInfo *Id,
+ SourceLocation AtLoc,
QualType T,
PropertyControl propControl) {
- return new (C) ObjCPropertyDecl(DC, L, Id, T);
+ return new (C) ObjCPropertyDecl(DC, L, Id, AtLoc, T);
}
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 4c3046b..fa44b51 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -98,10 +98,12 @@ void DeclRefExpr::computeDependence() {
// initialized with an expression that is value-dependent.
else if (VarDecl *Var = dyn_cast<VarDecl>(D)) {
if (Var->getType()->isIntegralType() &&
- Var->getType().getCVRQualifiers() == Qualifiers::Const &&
- Var->getInit() &&
- Var->getInit()->isValueDependent())
- ValueDependent = true;
+ Var->getType().getCVRQualifiers() == Qualifiers::Const) {
+ const VarDecl *Def = 0;
+ if (const Expr *Init = Var->getDefinition(Def))
+ if (Init->isValueDependent())
+ ValueDependent = true;
+ }
}
// (TD) - a nested-name-specifier or a qualified-id that names a
// member of an unknown specialization.
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index 81584b7..a6574ef 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -135,10 +135,11 @@ UnresolvedLookupExpr::Create(ASTContext &C, bool Dependent,
return ULE;
}
-bool UnresolvedLookupExpr::ComputeDependence(NamedDecl * const *Begin,
- NamedDecl * const *End,
- const TemplateArgumentListInfo *Args) {
- for (NamedDecl * const *I = Begin; I != End; ++I)
+bool UnresolvedLookupExpr::
+ ComputeDependence(UnresolvedSetImpl::const_iterator Begin,
+ UnresolvedSetImpl::const_iterator End,
+ const TemplateArgumentListInfo *Args) {
+ for (UnresolvedSetImpl::const_iterator I = Begin; I != End; ++I)
if ((*I)->getDeclContext()->isDependentContext())
return true;
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index dfff209..086249c 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -506,7 +506,9 @@ APValue PointerExprEvaluator::VisitCastExpr(CastExpr* E) {
APValue PointerExprEvaluator::VisitCallExpr(CallExpr *E) {
if (E->isBuiltinCall(Info.Ctx) ==
- Builtin::BI__builtin___CFStringMakeConstantString)
+ Builtin::BI__builtin___CFStringMakeConstantString ||
+ E->isBuiltinCall(Info.Ctx) ==
+ Builtin::BI__builtin___NSStringMakeConstantString)
return APValue(E);
return APValue();
}
@@ -971,6 +973,8 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
case Builtin::BI__builtin_object_size: {
const Expr *Arg = E->getArg(0)->IgnoreParens();
Expr::EvalResult Base;
+
+ // TODO: Perhaps we should let LLVM lower this?
if (Arg->EvaluateAsAny(Base, Info.Ctx)
&& Base.Val.getKind() == APValue::LValue
&& !Base.HasSideEffects)
@@ -992,7 +996,8 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
}
}
- // TODO: Perhaps we should let LLVM lower this?
+ // If evaluating the argument has side-effects we can't determine
+ // the size of the object and lower it to unknown now.
if (E->getArg(0)->HasSideEffects(Info.Ctx)) {
if (E->getArg(1)->EvaluateAsInt(Info.Ctx).getZExtValue() <= 1)
return Success(-1ULL, E);
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index cfd89ea..0aa0180 100644
--- a/lib/AST/RecordLayoutBuilder.cpp
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -119,6 +119,11 @@ ASTRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD,
return;
}
}
+ if (i->isVirtual()) {
+ SelectPrimaryVBase(Base, FirstPrimary);
+ if (PrimaryBase.getBase())
+ return;
+ }
}
}
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index e0055f1..edfb580 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -339,6 +339,25 @@ const RecordType *Type::getAsUnionType() const {
return 0;
}
+ObjCInterfaceType::ObjCInterfaceType(ASTContext &Ctx, QualType Canonical,
+ ObjCInterfaceDecl *D,
+ ObjCProtocolDecl **Protos, unsigned NumP) :
+ Type(ObjCInterface, Canonical, /*Dependent=*/false),
+ Decl(D), Protocols(0), NumProtocols(NumP)
+{
+ if (NumProtocols) {
+ Protocols = new (Ctx) ObjCProtocolDecl*[NumProtocols];
+ memcpy(Protocols, Protos, NumProtocols * sizeof(*Protocols));
+ }
+}
+
+void ObjCInterfaceType::Destroy(ASTContext& C) {
+ if (Protocols)
+ C.Deallocate(Protocols);
+ this->~ObjCInterfaceType();
+ C.Deallocate(this);
+}
+
const ObjCInterfaceType *Type::getAsObjCQualifiedInterfaceType() const {
// There is no sugar for ObjCInterfaceType's, just return the canonical
// type pointer if it is the right class. There is no typedef information to
@@ -353,6 +372,26 @@ bool Type::isObjCQualifiedInterfaceType() const {
return getAsObjCQualifiedInterfaceType() != 0;
}
+ObjCObjectPointerType::ObjCObjectPointerType(ASTContext &Ctx,
+ QualType Canonical, QualType T,
+ ObjCProtocolDecl **Protos,
+ unsigned NumP) :
+ Type(ObjCObjectPointer, Canonical, /*Dependent=*/false),
+ PointeeType(T), Protocols(NULL), NumProtocols(NumP)
+{
+ if (NumProtocols) {
+ Protocols = new (Ctx) ObjCProtocolDecl*[NumProtocols];
+ memcpy(Protocols, Protos, NumProtocols * sizeof(*Protocols));
+ }
+}
+
+void ObjCObjectPointerType::Destroy(ASTContext& C) {
+ if (Protocols)
+ C.Deallocate(Protocols);
+ this->~ObjCObjectPointerType();
+ C.Deallocate(this);
+}
+
const ObjCObjectPointerType *Type::getAsObjCQualifiedIdType() const {
// There is no sugar for ObjCQualifiedIdType's, just return the canonical
// type pointer if it is the right class.
diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp
index 0840c52..fd9fbc1 100644
--- a/lib/AST/TypeLoc.cpp
+++ b/lib/AST/TypeLoc.cpp
@@ -14,6 +14,7 @@
#include "llvm/Support/raw_ostream.h"
#include "clang/AST/TypeLocVisitor.h"
#include "clang/AST/Expr.h"
+#include "llvm/Support/ErrorHandling.h"
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -135,3 +136,56 @@ SourceRange TypeOfExprTypeLoc::getSourceRange() const {
return SourceRange(getTypeofLoc(),
getUnderlyingExpr()->getSourceRange().getEnd());
}
+
+
+TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const {
+ if (needsExtraLocalData())
+ return static_cast<TypeSpecifierType>(getWrittenBuiltinSpecs().Type);
+ else {
+ switch (getTypePtr()->getKind()) {
+ case BuiltinType::Void:
+ return TST_void;
+ case BuiltinType::Bool:
+ return TST_bool;
+ case BuiltinType::Char_U:
+ case BuiltinType::Char_S:
+ return TST_char;
+ case BuiltinType::Char16:
+ return TST_char16;
+ case BuiltinType::Char32:
+ return TST_char32;
+ case BuiltinType::WChar:
+ return TST_wchar;
+ case BuiltinType::UndeducedAuto:
+ return TST_auto;
+
+ case BuiltinType::UChar:
+ case BuiltinType::UShort:
+ case BuiltinType::UInt:
+ case BuiltinType::ULong:
+ case BuiltinType::ULongLong:
+ case BuiltinType::UInt128:
+ case BuiltinType::SChar:
+ case BuiltinType::Short:
+ case BuiltinType::Int:
+ case BuiltinType::Long:
+ case BuiltinType::LongLong:
+ case BuiltinType::Int128:
+ case BuiltinType::Float:
+ case BuiltinType::Double:
+ case BuiltinType::LongDouble:
+ llvm_unreachable("Builtin type needs extra local data!");
+ // Fall through, if the impossible happens.
+
+ case BuiltinType::NullPtr:
+ case BuiltinType::Overload:
+ case BuiltinType::Dependent:
+ case BuiltinType::ObjCId:
+ case BuiltinType::ObjCClass:
+ case BuiltinType::ObjCSel:
+ return TST_unspecified;
+ }
+ }
+
+ return TST_unspecified;
+}
diff --git a/lib/Analysis/AnalysisContext.cpp b/lib/Analysis/AnalysisContext.cpp
index 2093b5e..ad9f6dd 100644
--- a/lib/Analysis/AnalysisContext.cpp
+++ b/lib/Analysis/AnalysisContext.cpp
@@ -55,7 +55,7 @@ const ImplicitParamDecl *AnalysisContext::getSelfDecl() const {
CFG *AnalysisContext::getCFG() {
if (!cfg)
- cfg = CFG::buildCFG(getBody(), &D->getASTContext());
+ cfg = CFG::buildCFG(D, getBody(), &D->getASTContext(), AddEHEdges);
return cfg;
}
diff --git a/lib/Analysis/ArrayBoundChecker.cpp b/lib/Analysis/ArrayBoundChecker.cpp
index 3d95ab1..49c8606 100644
--- a/lib/Analysis/ArrayBoundChecker.cpp
+++ b/lib/Analysis/ArrayBoundChecker.cpp
@@ -57,7 +57,8 @@ void ArrayBoundChecker::VisitLocation(CheckerContext &C, const Stmt *S, SVal l){
// Get the size of the array.
DefinedOrUnknownSVal NumElements
- = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion());
+ = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion(),
+ ER->getValueType(C.getASTContext()));
const GRState *StInBound = state->AssumeInBound(Idx, NumElements, true);
const GRState *StOutBound = state->AssumeInBound(Idx, NumElements, false);
diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp
index eab7da7..5b8aeae 100644
--- a/lib/Analysis/CFG.cpp
+++ b/lib/Analysis/CFG.cpp
@@ -14,6 +14,7 @@
#include "clang/Analysis/Support/SaveAndRestore.h"
#include "clang/Analysis/CFG.h"
+#include "clang/AST/DeclCXX.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/PrettyPrinter.h"
#include "llvm/Support/GraphWriter.h"
@@ -70,6 +71,7 @@ class CFGBuilder {
CFGBlock* BreakTargetBlock;
CFGBlock* SwitchTerminatedBlock;
CFGBlock* DefaultCaseBlock;
+ CFGBlock* TryTerminatedBlock;
// LabelMap records the mapping from Label expressions to their blocks.
typedef llvm::DenseMap<LabelStmt*,CFGBlock*> LabelMapTy;
@@ -88,10 +90,12 @@ public:
explicit CFGBuilder() : cfg(new CFG()), // crew a new CFG
Block(NULL), Succ(NULL),
ContinueTargetBlock(NULL), BreakTargetBlock(NULL),
- SwitchTerminatedBlock(NULL), DefaultCaseBlock(NULL) {}
+ SwitchTerminatedBlock(NULL), DefaultCaseBlock(NULL),
+ TryTerminatedBlock(NULL) {}
// buildCFG - Used by external clients to construct the CFG.
- CFG* buildCFG(Stmt *Statement, ASTContext *C);
+ CFG* buildCFG(const Decl *D, Stmt *Statement, ASTContext *C, bool AddEHEdges,
+ bool AddScopes);
private:
// Visitors to walk an AST and construct the CFG.
@@ -106,9 +110,9 @@ private:
CFGBlock *VisitConditionalOperator(ConditionalOperator *C,
AddStmtChoice asc);
CFGBlock *VisitContinueStmt(ContinueStmt *C);
- CFGBlock *VisitCXXCatchStmt(CXXCatchStmt *S) { return NYS(); }
+ CFGBlock *VisitCXXCatchStmt(CXXCatchStmt *S);
CFGBlock *VisitCXXThrowExpr(CXXThrowExpr *T);
- CFGBlock *VisitCXXTryStmt(CXXTryStmt *S) { return NYS(); }
+ CFGBlock *VisitCXXTryStmt(CXXTryStmt *S);
CFGBlock *VisitDeclStmt(DeclStmt *DS);
CFGBlock *VisitDeclSubExpr(Decl* D);
CFGBlock *VisitDefaultStmt(DefaultStmt *D);
@@ -139,6 +143,25 @@ private:
return Block;
}
+ CFGBlock *StartScope(Stmt *S, CFGBlock *B) {
+ if (!AddScopes)
+ return B;
+
+ if (B == 0)
+ B = createBlock();
+ B->StartScope(S, cfg->getBumpVectorContext());
+ return B;
+ }
+
+ void EndScope(Stmt *S) {
+ if (!AddScopes)
+ return;
+
+ if (Block == 0)
+ Block = createBlock();
+ Block->EndScope(S, cfg->getBumpVectorContext());
+ }
+
void autoCreateBlock() { if (!Block) Block = createBlock(); }
CFGBlock *createBlock(bool add_successor = true);
bool FinishBlock(CFGBlock* B);
@@ -186,6 +209,12 @@ private:
}
bool badCFG;
+
+ // True iff EH edges on CallExprs should be added to the CFG.
+ bool AddEHEdges;
+
+ // True iff scope start and scope end notes should be added to the CFG.
+ bool AddScopes;
};
// FIXME: Add support for dependent-sized array types in C++?
@@ -207,12 +236,15 @@ static VariableArrayType* FindVA(Type* t) {
/// body (compound statement). The ownership of the returned CFG is
/// transferred to the caller. If CFG construction fails, this method returns
/// NULL.
-CFG* CFGBuilder::buildCFG(Stmt* Statement, ASTContext* C) {
+CFG* CFGBuilder::buildCFG(const Decl *D, Stmt* Statement, ASTContext* C,
+ bool addehedges, bool AddScopes) {
+ AddEHEdges = addehedges;
Context = C;
assert(cfg.get());
if (!Statement)
return NULL;
+ this->AddScopes = AddScopes;
badCFG = false;
// Create an empty block that will serve as the exit block for the CFG. Since
@@ -224,6 +256,11 @@ CFG* CFGBuilder::buildCFG(Stmt* Statement, ASTContext* C) {
// Visit the statements and create the CFG.
CFGBlock* B = addStmt(Statement);
+
+ if (const CXXConstructorDecl *CD = dyn_cast_or_null<CXXConstructorDecl>(D)) {
+ // FIXME: Add code for base initializers and member initializers.
+ (void)CD;
+ }
if (!B)
B = Succ;
@@ -329,6 +366,15 @@ tryAgain:
case Stmt::ContinueStmtClass:
return VisitContinueStmt(cast<ContinueStmt>(S));
+ case Stmt::CXXCatchStmtClass:
+ return VisitCXXCatchStmt(cast<CXXCatchStmt>(S));
+
+ case Stmt::CXXThrowExprClass:
+ return VisitCXXThrowExpr(cast<CXXThrowExpr>(S));
+
+ case Stmt::CXXTryStmtClass:
+ return VisitCXXTryStmt(cast<CXXTryStmt>(S));
+
case Stmt::DeclStmtClass:
return VisitDeclStmt(cast<DeclStmt>(S));
@@ -356,9 +402,6 @@ tryAgain:
case Stmt::ObjCAtCatchStmtClass:
return VisitObjCAtCatchStmt(cast<ObjCAtCatchStmt>(S));
- case Stmt::CXXThrowExprClass:
- return VisitCXXThrowExpr(cast<CXXThrowExpr>(S));
-
case Stmt::ObjCAtSynchronizedStmtClass:
return VisitObjCAtSynchronizedStmt(cast<ObjCAtSynchronizedStmt>(S));
@@ -456,7 +499,7 @@ CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B,
AddSuccessor(LHSBlock, KnownVal.isTrue() ? NULL : ConfluenceBlock);
AddSuccessor(LHSBlock, KnownVal.isFalse() ? NULL : RHSBlock);
} else {
- assert (B->getOpcode() == BinaryOperator::LAnd);
+ assert(B->getOpcode() == BinaryOperator::LAnd);
AddSuccessor(LHSBlock, KnownVal.isFalse() ? NULL : RHSBlock);
AddSuccessor(LHSBlock, KnownVal.isTrue() ? NULL : ConfluenceBlock);
}
@@ -504,6 +547,22 @@ CFGBlock *CFGBuilder::VisitBreakStmt(BreakStmt *B) {
return Block;
}
+static bool CanThrow(Expr *E) {
+ QualType Ty = E->getType();
+ if (Ty->isFunctionPointerType())
+ Ty = Ty->getAs<PointerType>()->getPointeeType();
+ else if (Ty->isBlockPointerType())
+ Ty = Ty->getAs<BlockPointerType>()->getPointeeType();
+
+ const FunctionType *FT = Ty->getAs<FunctionType>();
+ if (FT) {
+ if (const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FT))
+ if (Proto->hasEmptyExceptionSpec())
+ return false;
+ }
+ return true;
+}
+
CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, AddStmtChoice asc) {
// If this is a call to a no-return function, this stops the block here.
bool NoReturn = false;
@@ -511,22 +570,47 @@ CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, AddStmtChoice asc) {
NoReturn = true;
}
- if (FunctionDecl *FD = C->getDirectCallee())
+ bool AddEHEdge = false;
+
+ // Languages without exceptions are assumed to not throw.
+ if (Context->getLangOptions().Exceptions) {
+ if (AddEHEdges)
+ AddEHEdge = true;
+ }
+
+ if (FunctionDecl *FD = C->getDirectCallee()) {
if (FD->hasAttr<NoReturnAttr>())
NoReturn = true;
+ if (FD->hasAttr<NoThrowAttr>())
+ AddEHEdge = false;
+ }
- if (!NoReturn)
+ if (!CanThrow(C->getCallee()))
+ AddEHEdge = false;
+
+ if (!NoReturn && !AddEHEdge)
return VisitStmt(C, asc);
- if (Block && !FinishBlock(Block))
- return 0;
+ if (Block) {
+ Succ = Block;
+ if (!FinishBlock(Block))
+ return 0;
+ }
- // Create new block with no successor for the remaining pieces.
- Block = createBlock(false);
+ Block = createBlock(!NoReturn);
AppendStmt(Block, C, asc);
- // Wire this to the exit block directly.
- AddSuccessor(Block, &cfg->getExit());
+ if (NoReturn) {
+ // Wire this to the exit block directly.
+ AddSuccessor(Block, &cfg->getExit());
+ }
+ if (AddEHEdge) {
+ // Add exceptional edges.
+ if (TryTerminatedBlock)
+ AddSuccessor(Block, TryTerminatedBlock);
+ else
+ AddSuccessor(Block, &cfg->getExit());
+ }
return VisitChildren(C);
}
@@ -561,6 +645,8 @@ CFGBlock *CFGBuilder::VisitChooseExpr(ChooseExpr *C,
CFGBlock* CFGBuilder::VisitCompoundStmt(CompoundStmt* C) {
+ EndScope(C);
+
CFGBlock* LastBlock = Block;
for (CompoundStmt::reverse_body_iterator I=C->body_rbegin(), E=C->body_rend();
@@ -570,6 +656,9 @@ CFGBlock* CFGBuilder::VisitCompoundStmt(CompoundStmt* C) {
if (badCFG)
return NULL;
}
+
+ LastBlock = StartScope(C, LastBlock);
+
return LastBlock;
}
@@ -743,7 +832,7 @@ CFGBlock* CFGBuilder::VisitIfStmt(IfStmt* I) {
CFGBlock* ThenBlock;
{
Stmt* Then = I->getThen();
- assert (Then);
+ assert(Then);
SaveAndRestore<CFGBlock*> sv(Succ);
Block = NULL;
ThenBlock = addStmt(Then);
@@ -919,12 +1008,12 @@ CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) {
// Now create the loop body.
{
- assert (F->getBody());
+ assert(F->getBody());
// Save the current values for Block, Succ, and continue and break targets
SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ),
- save_continue(ContinueTargetBlock),
- save_break(BreakTargetBlock);
+ save_continue(ContinueTargetBlock),
+ save_break(BreakTargetBlock);
// Create a new block to contain the (bottom) of the loop body.
Block = NULL;
@@ -1252,8 +1341,12 @@ CFGBlock* CFGBuilder::VisitCXXThrowExpr(CXXThrowExpr* T) {
// Create the new block.
Block = createBlock(false);
- // The Exit block is the only successor.
- AddSuccessor(Block, &cfg->getExit());
+ if (TryTerminatedBlock)
+ // The current try statement is the only successor.
+ AddSuccessor(Block, TryTerminatedBlock);
+ else
+ // otherwise the Exit block is the only successor.
+ AddSuccessor(Block, &cfg->getExit());
// Add the statement to the block. This may create new blocks if S contains
// control-flow (short-circuit operations).
@@ -1301,12 +1394,12 @@ CFGBlock *CFGBuilder::VisitDoStmt(DoStmt* D) {
// Process the loop body.
CFGBlock* BodyBlock = NULL;
{
- assert (D->getBody());
+ assert(D->getBody());
// Save the current values for Block, Succ, and continue and break targets
SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ),
- save_continue(ContinueTargetBlock),
- save_break(BreakTargetBlock);
+ save_continue(ContinueTargetBlock),
+ save_break(BreakTargetBlock);
// All continues within this loop should go to the condition block
ContinueTargetBlock = EntryConditionBlock;
@@ -1434,7 +1527,7 @@ CFGBlock* CFGBuilder::VisitSwitchStmt(SwitchStmt* Terminator) {
// When visiting the body, the case statements should automatically get linked
// up to the switch. We also don't keep a pointer to the body, since all
// control-flow from the switch goes to case/default statements.
- assert (Terminator->getBody() && "switch must contain a non-NULL body");
+ assert(Terminator->getBody() && "switch must contain a non-NULL body");
Block = NULL;
CFGBlock *BodyBlock = addStmt(Terminator->getBody());
if (Block) {
@@ -1448,7 +1541,7 @@ CFGBlock* CFGBuilder::VisitSwitchStmt(SwitchStmt* Terminator) {
// Add the terminator and condition in the switch block.
SwitchTerminatedBlock->setTerminator(Terminator);
- assert (Terminator->getCond() && "switch condition must be non-NULL");
+ assert(Terminator->getCond() && "switch condition must be non-NULL");
Block = SwitchTerminatedBlock;
Block = addStmt(Terminator->getCond());
@@ -1528,6 +1621,82 @@ CFGBlock* CFGBuilder::VisitDefaultStmt(DefaultStmt* Terminator) {
return DefaultCaseBlock;
}
+CFGBlock *CFGBuilder::VisitCXXTryStmt(CXXTryStmt *Terminator) {
+ // "try"/"catch" is a control-flow statement. Thus we stop processing the
+ // current block.
+ CFGBlock* TrySuccessor = NULL;
+
+ if (Block) {
+ if (!FinishBlock(Block))
+ return 0;
+ TrySuccessor = Block;
+ } else TrySuccessor = Succ;
+
+ CFGBlock *PrevTryTerminatedBlock = TryTerminatedBlock;
+
+ // Create a new block that will contain the try statement.
+ CFGBlock *NewTryTerminatedBlock = createBlock(false);
+ // Add the terminator in the try block.
+ NewTryTerminatedBlock->setTerminator(Terminator);
+
+ bool HasCatchAll = false;
+ for (unsigned h = 0; h <Terminator->getNumHandlers(); ++h) {
+ // The code after the try is the implicit successor.
+ Succ = TrySuccessor;
+ CXXCatchStmt *CS = Terminator->getHandler(h);
+ if (CS->getExceptionDecl() == 0) {
+ HasCatchAll = true;
+ }
+ Block = NULL;
+ CFGBlock *CatchBlock = VisitCXXCatchStmt(CS);
+ if (CatchBlock == 0)
+ return 0;
+ // Add this block to the list of successors for the block with the try
+ // statement.
+ AddSuccessor(NewTryTerminatedBlock, CatchBlock);
+ }
+ if (!HasCatchAll) {
+ if (PrevTryTerminatedBlock)
+ AddSuccessor(NewTryTerminatedBlock, PrevTryTerminatedBlock);
+ else
+ AddSuccessor(NewTryTerminatedBlock, &cfg->getExit());
+ }
+
+ // The code after the try is the implicit successor.
+ Succ = TrySuccessor;
+
+ // Save the current "try" context.
+ SaveAndRestore<CFGBlock*> save_try(TryTerminatedBlock);
+ TryTerminatedBlock = NewTryTerminatedBlock;
+
+ assert(Terminator->getTryBlock() && "try must contain a non-NULL body");
+ Block = NULL;
+ Block = addStmt(Terminator->getTryBlock());
+ return Block;
+}
+
+CFGBlock* CFGBuilder::VisitCXXCatchStmt(CXXCatchStmt* CS) {
+ // CXXCatchStmt are treated like labels, so they are the first statement in a
+ // block.
+
+ if (CS->getHandlerBlock())
+ addStmt(CS->getHandlerBlock());
+
+ CFGBlock* CatchBlock = Block;
+ if (!CatchBlock)
+ CatchBlock = createBlock();
+
+ CatchBlock->setLabel(CS);
+
+ if (!FinishBlock(CatchBlock))
+ return 0;
+
+ // We set Block to NULL to allow lazy creation of a new block (if necessary)
+ Block = NULL;
+
+ return CatchBlock;
+}
+
CFGBlock* CFGBuilder::VisitIndirectGotoStmt(IndirectGotoStmt* I) {
// Lazily create the indirect-goto dispatch block if there isn't one already.
CFGBlock* IBlock = cfg->getIndirectGotoBlock();
@@ -1571,9 +1740,10 @@ CFGBlock* CFG::createBlock() {
/// buildCFG - Constructs a CFG from an AST. Ownership of the returned
/// CFG is returned to the caller.
-CFG* CFG::buildCFG(Stmt* Statement, ASTContext *C) {
+CFG* CFG::buildCFG(const Decl *D, Stmt* Statement, ASTContext *C,
+ bool AddEHEdges, bool AddScopes) {
CFGBuilder Builder;
- return Builder.buildCFG(Statement, C);
+ return Builder.buildCFG(D, Statement, C, AddEHEdges, AddScopes);
}
//===----------------------------------------------------------------------===//
@@ -1661,9 +1831,7 @@ CFG::BlkExprNumTy CFG::getBlkExprNum(const Stmt* S) {
BlkExprMapTy* M = reinterpret_cast<BlkExprMapTy*>(BlkExprMap);
BlkExprMapTy::iterator I = M->find(S);
-
- if (I == M->end()) return CFG::BlkExprNumTy();
- else return CFG::BlkExprNumTy(I->second);
+ return (I == M->end()) ? CFG::BlkExprNumTy() : CFG::BlkExprNumTy(I->second);
}
unsigned CFG::getNumBlkExprs() {
@@ -1692,7 +1860,6 @@ CFG::~CFG() {
namespace {
class StmtPrinterHelper : public PrinterHelper {
-
typedef llvm::DenseMap<Stmt*,std::pair<unsigned,unsigned> > StmtMapTy;
StmtMapTy StmtMap;
signed CurrentBlock;
@@ -1724,10 +1891,11 @@ public:
return false;
if (CurrentBlock >= 0 && I->second.first == (unsigned) CurrentBlock
- && I->second.second == CurrentStmt)
+ && I->second.second == CurrentStmt) {
return false;
+ }
- OS << "[B" << I->second.first << "." << I->second.second << "]";
+ OS << "[B" << I->second.first << "." << I->second.second << "]";
return true;
}
};
@@ -1741,7 +1909,6 @@ class CFGBlockTerminatorPrint
llvm::raw_ostream& OS;
StmtPrinterHelper* Helper;
PrintingPolicy Policy;
-
public:
CFGBlockTerminatorPrint(llvm::raw_ostream& os, StmtPrinterHelper* helper,
const PrintingPolicy &Policy)
@@ -1759,22 +1926,27 @@ public:
void VisitForStmt(ForStmt* F) {
OS << "for (" ;
- if (F->getInit()) OS << "...";
+ if (F->getInit())
+ OS << "...";
OS << "; ";
- if (Stmt* C = F->getCond()) C->printPretty(OS, Helper, Policy);
+ if (Stmt* C = F->getCond())
+ C->printPretty(OS, Helper, Policy);
OS << "; ";
- if (F->getInc()) OS << "...";
+ if (F->getInc())
+ OS << "...";
OS << ")";
}
void VisitWhileStmt(WhileStmt* W) {
OS << "while " ;
- if (Stmt* C = W->getCond()) C->printPretty(OS, Helper, Policy);
+ if (Stmt* C = W->getCond())
+ C->printPretty(OS, Helper, Policy);
}
void VisitDoStmt(DoStmt* D) {
OS << "do ... while ";
- if (Stmt* C = D->getCond()) C->printPretty(OS, Helper, Policy);
+ if (Stmt* C = D->getCond())
+ C->printPretty(OS, Helper, Policy);
}
void VisitSwitchStmt(SwitchStmt* Terminator) {
@@ -1782,6 +1954,10 @@ public:
Terminator->getCond()->printPretty(OS, Helper, Policy);
}
+ void VisitCXXTryStmt(CXXTryStmt* CS) {
+ OS << "try ...";
+ }
+
void VisitConditionalOperator(ConditionalOperator* C) {
C->getCond()->printPretty(OS, Helper, Policy);
OS << " ? ... : ...";
@@ -1826,7 +2002,18 @@ public:
static void print_stmt(llvm::raw_ostream &OS, StmtPrinterHelper* Helper,
- Stmt* Terminator) {
+ const CFGElement &E) {
+ Stmt *Terminator = E;
+
+ if (E.asStartScope()) {
+ OS << "start scope\n";
+ return;
+ }
+ if (E.asEndScope()) {
+ OS << "end scope\n";
+ return;
+ }
+
if (Helper) {
// special printing for statement-expressions.
if (StmtExpr* SE = dyn_cast<StmtExpr>(Terminator)) {
@@ -1876,14 +2063,14 @@ static void print_block(llvm::raw_ostream& OS, const CFG* cfg,
OS << " ]\n";
// Print the label of this block.
- if (Stmt* Terminator = const_cast<Stmt*>(B.getLabel())) {
+ if (Stmt* Label = const_cast<Stmt*>(B.getLabel())) {
if (print_edges)
OS << " ";
- if (LabelStmt* L = dyn_cast<LabelStmt>(Terminator))
+ if (LabelStmt* L = dyn_cast<LabelStmt>(Label))
OS << L->getName();
- else if (CaseStmt* C = dyn_cast<CaseStmt>(Terminator)) {
+ else if (CaseStmt* C = dyn_cast<CaseStmt>(Label)) {
OS << "case ";
C->getLHS()->printPretty(OS, Helper,
PrintingPolicy(Helper->getLangOpts()));
@@ -1892,9 +2079,18 @@ static void print_block(llvm::raw_ostream& OS, const CFG* cfg,
C->getRHS()->printPretty(OS, Helper,
PrintingPolicy(Helper->getLangOpts()));
}
- } else if (isa<DefaultStmt>(Terminator))
+ } else if (isa<DefaultStmt>(Label))
OS << "default";
- else
+ else if (CXXCatchStmt *CS = dyn_cast<CXXCatchStmt>(Label)) {
+ OS << "catch (";
+ if (CS->getExceptionDecl())
+ CS->getExceptionDecl()->print(OS, PrintingPolicy(Helper->getLangOpts()),
+ 0);
+ else
+ OS << "...";
+ OS << ")";
+
+ } else
assert(false && "Invalid label statement in CFGBlock.");
OS << ":\n";
diff --git a/lib/Analysis/CastToStructChecker.cpp b/lib/Analysis/CastToStructChecker.cpp
index a366342..219c09f 100644
--- a/lib/Analysis/CastToStructChecker.cpp
+++ b/lib/Analysis/CastToStructChecker.cpp
@@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===//
//
// This files defines CastToStructChecker, a builtin checker that checks for
-// assignment of a fixed address to a pointer.
+// cast from non-struct pointer to struct pointer.
// This check corresponds to CWE-588.
//
//===----------------------------------------------------------------------===//
diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp
index 40c12c9..8f8d859 100644
--- a/lib/Analysis/GRExprEngine.cpp
+++ b/lib/Analysis/GRExprEngine.cpp
@@ -2173,8 +2173,8 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME,
// Transfer functions: Miscellaneous statements.
//===----------------------------------------------------------------------===//
-void GRExprEngine::VisitCast(Expr* CastE, Expr* Ex, ExplodedNode* Pred,
- ExplodedNodeSet& Dst, bool asLValue){
+void GRExprEngine::VisitCast(CastExpr *CastE, Expr *Ex, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst, bool asLValue) {
ExplodedNodeSet S1;
QualType T = CastE->getType();
QualType ExTy = Ex->getType();
@@ -2191,14 +2191,6 @@ void GRExprEngine::VisitCast(Expr* CastE, Expr* Ex, ExplodedNode* Pred,
ExplodedNodeSet S2;
CheckerVisit(CastE, S2, S1, true);
- // Check for casting to "void".
- if (T->isVoidType()) {
- assert(!asLValue);
- for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I)
- Dst.Add(*I);
- return;
- }
-
// If we are evaluating the cast in an lvalue context, we implicitly want
// the cast to evaluate to a location.
if (asLValue) {
@@ -2207,13 +2199,51 @@ void GRExprEngine::VisitCast(Expr* CastE, Expr* Ex, ExplodedNode* Pred,
ExTy = Ctx.getPointerType(Ctx.getCanonicalType(ExTy));
}
- for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) {
- ExplodedNode* N = *I;
- const GRState* state = GetState(N);
- SVal V = state->getSVal(Ex);
- const SValuator::CastResult &Res = SVator.EvalCast(V, state, T, ExTy);
- state = Res.getState()->BindExpr(CastE, Res.getSVal());
- MakeNode(Dst, CastE, N, state);
+ switch (CastE->getCastKind()) {
+ case CastExpr::CK_ToVoid:
+ assert(!asLValue);
+ for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I)
+ Dst.Add(*I);
+ return;
+
+ case CastExpr::CK_NoOp:
+ case CastExpr::CK_FunctionToPointerDecay:
+ for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) {
+ // Copy the SVal of Ex to CastE.
+ ExplodedNode *N = *I;
+ const GRState *state = GetState(N);
+ SVal V = state->getSVal(Ex);
+ state = state->BindExpr(CastE, V);
+ MakeNode(Dst, CastE, N, state);
+ }
+ return;
+
+ case CastExpr::CK_Unknown:
+ case CastExpr::CK_ArrayToPointerDecay:
+ case CastExpr::CK_BitCast:
+ case CastExpr::CK_IntegralCast:
+ case CastExpr::CK_IntegralToPointer:
+ case CastExpr::CK_PointerToIntegral:
+ case CastExpr::CK_IntegralToFloating:
+ case CastExpr::CK_FloatingToIntegral:
+ case CastExpr::CK_FloatingCast:
+ case CastExpr::CK_AnyPointerToObjCPointerCast:
+ case CastExpr::CK_AnyPointerToBlockPointerCast:
+ case CastExpr::CK_DerivedToBase:
+ // Delegate to SValuator to process.
+ for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) {
+ ExplodedNode* N = *I;
+ const GRState* state = GetState(N);
+ SVal V = state->getSVal(Ex);
+ const SValuator::CastResult &Res = SVator.EvalCast(V, state, T, ExTy);
+ state = Res.getState()->BindExpr(CastE, Res.getSVal());
+ MakeNode(Dst, CastE, N, state);
+ }
+ return;
+
+ default:
+ llvm::errs() << "Cast kind " << CastE->getCastKind() << " not handled.\n";
+ assert(0);
}
}
@@ -2952,13 +2982,13 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
// Perform a load (the LHS). This performs the checks for
// null dereferences, and so on.
- ExplodedNodeSet Tmp3;
+ ExplodedNodeSet Tmp4;
SVal location = state->getSVal(LHS);
- EvalLoad(Tmp3, LHS, *I2, state, location);
+ EvalLoad(Tmp4, LHS, *I2, state, location);
- for (ExplodedNodeSet::iterator I3=Tmp3.begin(), E3=Tmp3.end(); I3!=E3;
- ++I3) {
- state = GetState(*I3);
+ for (ExplodedNodeSet::iterator I4=Tmp4.begin(), E4=Tmp4.end(); I4!=E4;
+ ++I4) {
+ state = GetState(*I4);
SVal V = state->getSVal(LHS);
// Get the computation type.
@@ -3008,7 +3038,7 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
llvm::tie(state, LHSVal) = SVator.EvalCast(Result, state, LTy, CTy);
}
- EvalStore(Tmp3, B, LHS, *I3, state->BindExpr(B, Result),
+ EvalStore(Tmp3, B, LHS, *I4, state->BindExpr(B, Result),
location, LHSVal);
}
}
diff --git a/lib/Analysis/MallocChecker.cpp b/lib/Analysis/MallocChecker.cpp
index fab73ee..28f4db7 100644
--- a/lib/Analysis/MallocChecker.cpp
+++ b/lib/Analysis/MallocChecker.cpp
@@ -72,7 +72,7 @@ public:
private:
void MallocMem(CheckerContext &C, const CallExpr *CE);
const GRState *MallocMemAux(CheckerContext &C, const CallExpr *CE,
- const GRState *state);
+ const Expr *SizeEx, const GRState *state);
void FreeMem(CheckerContext &C, const CallExpr *CE);
const GRState *FreeMemAux(CheckerContext &C, const CallExpr *CE,
const GRState *state);
@@ -136,18 +136,24 @@ bool MallocChecker::EvalCallExpr(CheckerContext &C, const CallExpr *CE) {
}
void MallocChecker::MallocMem(CheckerContext &C, const CallExpr *CE) {
- const GRState *state = MallocMemAux(C, CE, C.getState());
+ const GRState *state = MallocMemAux(C, CE, CE->getArg(0), C.getState());
C.addTransition(state);
}
const GRState *MallocChecker::MallocMemAux(CheckerContext &C,
const CallExpr *CE,
+ const Expr *SizeEx,
const GRState *state) {
unsigned Count = C.getNodeBuilder().getCurrentBlockCount();
ValueManager &ValMgr = C.getValueManager();
SVal RetVal = ValMgr.getConjuredSymbolVal(NULL, CE, CE->getType(), Count);
+ SVal Size = state->getSVal(SizeEx);
+
+ state = C.getEngine().getStoreManager().setExtent(state, RetVal.getAsRegion(),
+ Size);
+
state = state->BindExpr(CE, RetVal);
SymbolRef Sym = RetVal.getAsLocSymbol();
@@ -170,7 +176,12 @@ const GRState *MallocChecker::FreeMemAux(CheckerContext &C, const CallExpr *CE,
assert(Sym);
const RefState *RS = state->get<RegionState>(Sym);
- assert(RS);
+
+ // If the symbol has not been tracked, return. This is possible when free() is
+ // called on a pointer that does not get its pointee directly from malloc().
+ // Full support of this requires inter-procedural analysis.
+ if (!RS)
+ return state;
// Check double free.
if (RS->isReleased()) {
@@ -211,7 +222,7 @@ void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) {
if (Sym)
stateEqual = stateEqual->set<RegionState>(Sym, RefState::getReleased(CE));
- const GRState *stateMalloc = MallocMemAux(C, CE, stateEqual);
+ const GRState *stateMalloc = MallocMemAux(C, CE, CE->getArg(1), stateEqual);
C.addTransition(stateMalloc);
}
@@ -232,7 +243,8 @@ void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) {
const GRState *stateFree = FreeMemAux(C, CE, stateSizeNotZero);
if (stateFree) {
// FIXME: We should copy the content of the original buffer.
- const GRState *stateRealloc = MallocMemAux(C, CE, stateFree);
+ const GRState *stateRealloc = MallocMemAux(C, CE, CE->getArg(1),
+ stateFree);
C.addTransition(stateRealloc);
}
}
diff --git a/lib/Analysis/RegionStore.cpp b/lib/Analysis/RegionStore.cpp
index 9b5b44b..a735ed9 100644
--- a/lib/Analysis/RegionStore.cpp
+++ b/lib/Analysis/RegionStore.cpp
@@ -21,6 +21,7 @@
#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Analysis/Support/Optional.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/AST/CharUnits.h"
#include "llvm/ADT/ImmutableMap.h"
#include "llvm/ADT/ImmutableList.h"
@@ -423,9 +424,9 @@ public:
// Region "extents".
//===------------------------------------------------------------------===//
- const GRState *setExtent(const GRState *state, const MemRegion* R, SVal Extent);
+ const GRState *setExtent(const GRState *state,const MemRegion* R,SVal Extent);
DefinedOrUnknownSVal getSizeInElements(const GRState *state,
- const MemRegion* R);
+ const MemRegion* R, QualType EleTy);
//===------------------------------------------------------------------===//
// Utility methods.
@@ -767,7 +768,8 @@ SVal RegionStoreManager::getLValueElement(QualType elementType, SVal Offset,
//===----------------------------------------------------------------------===//
DefinedOrUnknownSVal RegionStoreManager::getSizeInElements(const GRState *state,
- const MemRegion *R) {
+ const MemRegion *R,
+ QualType EleTy) {
switch (R->getKind()) {
case MemRegion::CXXThisRegionKind:
@@ -793,10 +795,25 @@ DefinedOrUnknownSVal RegionStoreManager::getSizeInElements(const GRState *state,
case MemRegion::ElementRegionKind:
case MemRegion::FieldRegionKind:
case MemRegion::ObjCIvarRegionKind:
- case MemRegion::SymbolicRegionKind:
case MemRegion::CXXObjectRegionKind:
return UnknownVal();
+ case MemRegion::SymbolicRegionKind: {
+ const SVal *Size = state->get<RegionExtents>(R);
+ if (!Size)
+ return UnknownVal();
+ const nonloc::ConcreteInt *CI = dyn_cast<nonloc::ConcreteInt>(Size);
+ if (!CI)
+ return UnknownVal();
+
+ CharUnits RegionSize =
+ CharUnits::fromQuantity(CI->getValue().getSExtValue());
+ CharUnits EleSize = getContext().getTypeSizeInChars(EleTy);
+ assert(RegionSize % EleSize == 0);
+
+ return ValMgr.makeIntVal(RegionSize / EleSize, false);
+ }
+
case MemRegion::StringRegionKind: {
const StringLiteral* Str = cast<StringRegion>(R)->getStringLiteral();
// We intentionally made the size value signed because it participates in
diff --git a/lib/Analysis/ReturnPointerRangeChecker.cpp b/lib/Analysis/ReturnPointerRangeChecker.cpp
index ab0fcab..b0350cb 100644
--- a/lib/Analysis/ReturnPointerRangeChecker.cpp
+++ b/lib/Analysis/ReturnPointerRangeChecker.cpp
@@ -65,7 +65,8 @@ void ReturnPointerRangeChecker::PreVisitReturnStmt(CheckerContext &C,
// into a common place.
DefinedOrUnknownSVal NumElements
- = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion());
+ = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion(),
+ ER->getValueType(C.getASTContext()));
const GRState *StInBound = state->AssumeInBound(Idx, NumElements, true);
const GRState *StOutBound = state->AssumeInBound(Idx, NumElements, false);
diff --git a/lib/Basic/Makefile b/lib/Basic/Makefile
index 5bd4314..f733578 100644
--- a/lib/Basic/Makefile
+++ b/lib/Basic/Makefile
@@ -17,10 +17,13 @@ BUILD_ARCHIVE = 1
CXXFLAGS = -fno-rtti
CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
+ifdef CLANG_VENDOR
+CPPFLAGS += -DCLANG_VENDOR='"$(CLANG_VENDOR) "'
+endif
include $(LEVEL)/Makefile.common
-SVN_REVISION := $(shell cd $(PROJ_SRC_DIR)/../.. && svnversion)
+SVN_REVISION := $(shell $(LLVM_SRC_ROOT)/utils/GetSourceVersion $(PROJ_SRC_DIR)/../..)
CPP.Defines += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include \
-DSVN_REVISION='"$(SVN_REVISION)"'
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index bba2c3f..ea076ae 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -16,9 +16,9 @@
#include "clang/Basic/Builtins.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/MacroBuilder.h"
#include "clang/Basic/TargetBuiltins.h"
#include "clang/Basic/TargetOptions.h"
-#include "clang/Frontend/Utils.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/STLExtras.h"
diff --git a/lib/Basic/Version.cpp b/lib/Basic/Version.cpp
index ba31544..b1b250f 100644
--- a/lib/Basic/Version.cpp
+++ b/lib/Basic/Version.cpp
@@ -10,13 +10,17 @@
// This file defines several version-related utility functions for Clang.
//
//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/Version.h"
+#include "llvm/Support/raw_ostream.h"
#include <cstring>
#include <cstdlib>
+
using namespace std;
namespace clang {
-const char *getClangSubversionPath() {
+llvm::StringRef getClangRepositoryPath() {
static const char *Path = 0;
if (Path)
return Path;
@@ -41,13 +45,43 @@ const char *getClangSubversionPath() {
}
-unsigned getClangSubversionRevision() {
+llvm::StringRef getClangRevision() {
#ifndef SVN_REVISION
// Subversion was not available at build time?
- return 0;
+ return llvm::StringRef();
#else
- return strtol(SVN_REVISION, 0, 10);
+ static std::string revision;
+ if (revision.empty()) {
+ llvm::raw_string_ostream OS(revision);
+ OS << strtol(SVN_REVISION, 0, 10);
+ }
+ return revision;
#endif
}
+llvm::StringRef getClangFullRepositoryVersion() {
+ static std::string buf;
+ if (buf.empty()) {
+ llvm::raw_string_ostream OS(buf);
+ OS << getClangRepositoryPath();
+ llvm::StringRef Revision = getClangRevision();
+ if (!Revision.empty())
+ OS << ' ' << Revision;
+ }
+ return buf;
+}
+
+const char *getClangFullVersion() {
+ static std::string buf;
+ if (buf.empty()) {
+ llvm::raw_string_ostream OS(buf);
+#ifdef CLANG_VENDOR
+ OS << CLANG_VENDOR;
+#endif
+ OS << "clang version " CLANG_VERSION_STRING " ("
+ << getClangFullRepositoryVersion() << ')';
+ }
+ return buf.c_str();
+}
+
} // end namespace clang
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index 1fa422f..ca5b6fa 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -18,7 +18,6 @@
#include "llvm/Module.h"
#include "llvm/Target/TargetData.h"
#include <algorithm>
-#include <cstdio>
using namespace clang;
using namespace CodeGen;
@@ -221,11 +220,10 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
C = llvm::ConstantStruct::get(VMContext, Elts, false);
- char Name[32];
- sprintf(Name, "__block_holder_tmp_%d", CGM.getGlobalUniqueCount());
C = new llvm::GlobalVariable(CGM.getModule(), C->getType(), true,
- llvm::GlobalValue::InternalLinkage,
- C, Name);
+ llvm::GlobalValue::InternalLinkage, C,
+ "__block_holder_tmp_" +
+ llvm::Twine(CGM.getGlobalUniqueCount()));
QualType BPT = BE->getType();
C = llvm::ConstantExpr::getBitCast(C, ConvertType(BPT));
return C;
@@ -747,13 +745,12 @@ CodeGenFunction::GenerateBlockFunction(const BlockExpr *BExpr,
const CGFunctionInfo &FI =
CGM.getTypes().getFunctionInfo(ResultType, Args);
- std::string Name = std::string("__") + Info.Name + "_block_invoke_";
CodeGenTypes &Types = CGM.getTypes();
const llvm::FunctionType *LTy = Types.GetFunctionType(FI, IsVariadic);
llvm::Function *Fn =
llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage,
- Name,
+ llvm::Twine("__") + Info.Name + "_block_invoke_",
&CGM.getModule());
CGM.SetInternalFunctionAttributes(BD, Fn, FI);
@@ -875,14 +872,12 @@ GenerateCopyHelperFunction(bool BlockHasCopyDispose, const llvm::StructType *T,
// FIXME: We'd like to put these into a mergable by content, with
// internal linkage.
- std::string Name = std::string("__copy_helper_block_");
CodeGenTypes &Types = CGM.getTypes();
const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false);
llvm::Function *Fn =
llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage,
- Name,
- &CGM.getModule());
+ "__copy_helper_block_", &CGM.getModule());
IdentifierInfo *II
= &CGM.getContext().Idents.get("__copy_helper_block_");
@@ -958,14 +953,12 @@ GenerateDestroyHelperFunction(bool BlockHasCopyDispose,
// FIXME: We'd like to put these into a mergable by content, with
// internal linkage.
- std::string Name = std::string("__destroy_helper_block_");
CodeGenTypes &Types = CGM.getTypes();
const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false);
llvm::Function *Fn =
llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage,
- Name,
- &CGM.getModule());
+ "__destroy_helper_block_", &CGM.getModule());
IdentifierInfo *II
= &CGM.getContext().Idents.get("__destroy_helper_block_");
@@ -1042,7 +1035,6 @@ GeneratebyrefCopyHelperFunction(const llvm::Type *T, int flag) {
const CGFunctionInfo &FI =
CGM.getTypes().getFunctionInfo(R, Args);
- std::string Name = std::string("__Block_byref_id_object_copy_");
CodeGenTypes &Types = CGM.getTypes();
const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false);
@@ -1050,8 +1042,7 @@ GeneratebyrefCopyHelperFunction(const llvm::Type *T, int flag) {
// internal linkage.
llvm::Function *Fn =
llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage,
- Name,
- &CGM.getModule());
+ "__Block_byref_id_object_copy_", &CGM.getModule());
IdentifierInfo *II
= &CGM.getContext().Idents.get("__Block_byref_id_object_copy_");
@@ -1107,7 +1098,6 @@ BlockFunction::GeneratebyrefDestroyHelperFunction(const llvm::Type *T,
const CGFunctionInfo &FI =
CGM.getTypes().getFunctionInfo(R, Args);
- std::string Name = std::string("__Block_byref_id_object_dispose_");
CodeGenTypes &Types = CGM.getTypes();
const llvm::FunctionType *LTy = Types.GetFunctionType(FI, false);
@@ -1115,7 +1105,7 @@ BlockFunction::GeneratebyrefDestroyHelperFunction(const llvm::Type *T,
// internal linkage.
llvm::Function *Fn =
llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage,
- Name,
+ "__Block_byref_id_object_dispose_",
&CGM.getModule());
IdentifierInfo *II
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
index 866c587..f11d52e 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -72,6 +72,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
switch (BuiltinID) {
default: break; // Handle intrinsics and libm functions below.
case Builtin::BI__builtin___CFStringMakeConstantString:
+ case Builtin::BI__builtin___NSStringMakeConstantString:
return RValue::get(CGM.EmitConstantExpr(E, E->getType(), 0));
case Builtin::BI__builtin_stdarg_start:
case Builtin::BI__builtin_va_start:
@@ -556,6 +557,18 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
return RValue::get(0);
}
+ case Builtin::BI__builtin_llvm_memory_barrier: {
+ Value *C[5] = {
+ EmitScalarExpr(E->getArg(0)),
+ EmitScalarExpr(E->getArg(1)),
+ EmitScalarExpr(E->getArg(2)),
+ EmitScalarExpr(E->getArg(3)),
+ EmitScalarExpr(E->getArg(4))
+ };
+ Builder.CreateCall(CGM.getIntrinsic(Intrinsic::memory_barrier), C, C + 5);
+ return RValue::get(0);
+ }
+
// Library functions with special handling.
case Builtin::BIsqrt:
case Builtin::BIsqrtf:
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp
index ab3fece..a822ca2 100644
--- a/lib/CodeGen/CGClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -394,10 +394,8 @@ void CodeGenFunction::EmitClassAggrCopyAssignment(llvm::Value *Dest,
if (BitwiseAssign)
EmitAggregateCopy(Dest, Src, Ty);
else {
- bool hasCopyAssign = BaseClassDecl->hasConstCopyAssignment(getContext(),
- MD);
- assert(hasCopyAssign && "EmitClassAggrCopyAssignment - No user assign");
- (void)hasCopyAssign;
+ BaseClassDecl->hasConstCopyAssignment(getContext(), MD);
+ assert(MD && "EmitClassAggrCopyAssignment - No user assign");
const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
const llvm::Type *LTy =
CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
@@ -410,8 +408,10 @@ void CodeGenFunction::EmitClassAggrCopyAssignment(llvm::Value *Dest,
MD->getThisType(getContext())));
// Push the Src ptr.
- CallArgs.push_back(std::make_pair(RValue::get(Src),
- MD->getParamDecl(0)->getType()));
+ QualType SrcTy = MD->getParamDecl(0)->getType();
+ RValue SrcValue = SrcTy->isReferenceType() ? RValue::get(Src) :
+ RValue::getAggregate(Src);
+ CallArgs.push_back(std::make_pair(SrcValue, SrcTy));
QualType ResultType = MD->getType()->getAs<FunctionType>()->getResultType();
EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs),
Callee, ReturnValueSlot(), CallArgs, MD);
@@ -531,10 +531,8 @@ void CodeGenFunction::EmitClassCopyAssignment(
}
const CXXMethodDecl *MD = 0;
- bool ConstCopyAssignOp = BaseClassDecl->hasConstCopyAssignment(getContext(),
- MD);
- assert(ConstCopyAssignOp && "EmitClassCopyAssignment - missing copy assign");
- (void)ConstCopyAssignOp;
+ BaseClassDecl->hasConstCopyAssignment(getContext(), MD);
+ assert(MD && "EmitClassCopyAssignment - missing copy assign");
const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
const llvm::Type *LTy =
@@ -548,8 +546,10 @@ void CodeGenFunction::EmitClassCopyAssignment(
MD->getThisType(getContext())));
// Push the Src ptr.
- CallArgs.push_back(std::make_pair(RValue::get(Src),
- MD->getParamDecl(0)->getType()));
+ QualType SrcTy = MD->getParamDecl(0)->getType();
+ RValue SrcValue = SrcTy->isReferenceType() ? RValue::get(Src) :
+ RValue::getAggregate(Src);
+ CallArgs.push_back(std::make_pair(SrcValue, SrcTy));
QualType ResultType =
MD->getType()->getAs<FunctionType>()->getResultType();
EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs),
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index ab8f663..1ffad3e 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -460,58 +460,15 @@ llvm::DIType CGDebugInfo::CreateType(const FunctionType *Ty,
return DbgTy;
}
-/// CreateType - get structure or union type.
-llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty,
- llvm::DICompileUnit Unit) {
- RecordDecl *Decl = Ty->getDecl();
-
- unsigned Tag;
- if (Decl->isStruct())
- Tag = llvm::dwarf::DW_TAG_structure_type;
- else if (Decl->isUnion())
- Tag = llvm::dwarf::DW_TAG_union_type;
- else {
- assert(Decl->isClass() && "Unknown RecordType!");
- Tag = llvm::dwarf::DW_TAG_class_type;
- }
-
+/// CollectRecordFields - A helper function to collect debug info for
+/// record fields. This is used while creating debug info entry for a Record.
+void CGDebugInfo::
+CollectRecordFields(const RecordDecl *Decl,
+ llvm::DICompileUnit Unit,
+ llvm::SmallVectorImpl<llvm::DIDescriptor> &EltTys) {
+ unsigned FieldNo = 0;
SourceManager &SM = CGM.getContext().getSourceManager();
-
- // Get overall information about the record type for the debug info.
- PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation());
- llvm::DICompileUnit DefUnit;
- unsigned Line = 0;
- if (!PLoc.isInvalid()) {
- DefUnit = getOrCreateCompileUnit(Decl->getLocation());
- Line = PLoc.getLine();
- }
-
- // Records and classes and unions can all be recursive. To handle them, we
- // first generate a debug descriptor for the struct as a forward declaration.
- // Then (if it is a definition) we go through and get debug info for all of
- // its members. Finally, we create a descriptor for the complete type (which
- // may refer to the forward decl if the struct is recursive) and replace all
- // uses of the forward declaration with the final definition.
- llvm::DICompositeType FwdDecl =
- DebugFactory.CreateCompositeType(Tag, Unit, Decl->getName(),
- DefUnit, Line, 0, 0, 0, 0,
- llvm::DIType(), llvm::DIArray());
-
- // If this is just a forward declaration, return it.
- if (!Decl->getDefinition(CGM.getContext()))
- return FwdDecl;
-
- llvm::TrackingVH<llvm::MDNode> FwdDeclNode = FwdDecl.getNode();
- // Otherwise, insert it into the TypeCache so that recursive uses will find
- // it.
- TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl.getNode();
-
- // Convert all the elements.
- llvm::SmallVector<llvm::DIDescriptor, 16> EltTys;
-
const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(Decl);
-
- unsigned FieldNo = 0;
for (RecordDecl::field_iterator I = Decl->field_begin(),
E = Decl->field_end();
I != E; ++I, ++FieldNo) {
@@ -560,6 +517,125 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty,
FieldOffset, 0, FieldTy);
EltTys.push_back(FieldTy);
}
+}
+
+/// CollectCXXMemberFunctions - A helper function to collect debug info for
+/// C++ member functions.This is used while creating debug info entry for
+/// a Record.
+void CGDebugInfo::
+CollectCXXMemberFunctions(const CXXRecordDecl *Decl,
+ llvm::DICompileUnit Unit,
+ llvm::SmallVectorImpl<llvm::DIDescriptor> &EltTys,
+ llvm::DICompositeType &RecordTy) {
+ SourceManager &SM = CGM.getContext().getSourceManager();
+ for(CXXRecordDecl::method_iterator I = Decl->method_begin(),
+ E = Decl->method_end(); I != E; ++I) {
+ CXXMethodDecl *Method = *I;
+ llvm::StringRef MethodName;
+ llvm::StringRef MethodLinkageName;
+ llvm::DIType MethodTy = getOrCreateType(Method->getType(), Unit);
+ if (CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(Method)) {
+ if (CDecl->isImplicit())
+ continue;
+ MethodName = Decl->getName();
+ // FIXME : Find linkage name.
+ } else if (CXXDestructorDecl *DDecl = dyn_cast<CXXDestructorDecl>(Method)) {
+ if (DDecl->isImplicit())
+ continue;
+ MethodName = getFunctionName(Method);
+ // FIXME : Find linkage name.
+ } else {
+ if (Method->isImplicit())
+ continue;
+ // regular method
+ MethodName = getFunctionName(Method);
+ MethodLinkageName = CGM.getMangledName(Method);
+ }
+
+ // Get the location for the method.
+ SourceLocation MethodDefLoc = Method->getLocation();
+ PresumedLoc PLoc = SM.getPresumedLoc(MethodDefLoc);
+ llvm::DICompileUnit MethodDefUnit;
+ unsigned MethodLine = 0;
+
+ if (!PLoc.isInvalid()) {
+ MethodDefUnit = getOrCreateCompileUnit(MethodDefLoc);
+ MethodLine = PLoc.getLine();
+ }
+
+ llvm::DISubprogram SP =
+ DebugFactory.CreateSubprogram(RecordTy , MethodName, MethodName,
+ MethodLinkageName,
+ MethodDefUnit, MethodLine,
+ MethodTy, false,
+ Method->isThisDeclarationADefinition(),
+ 0 /*Virtuality*/, 0 /*VIndex*/,
+ llvm::DIType() /*ContainingType*/);
+ if (Method->isThisDeclarationADefinition())
+ SPCache[cast<FunctionDecl>(Method)] = llvm::WeakVH(SP.getNode());
+ EltTys.push_back(SP);
+ }
+}
+
+/// CreateType - get structure or union type.
+llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty,
+ llvm::DICompileUnit Unit) {
+ RecordDecl *Decl = Ty->getDecl();
+
+ unsigned Tag;
+ if (Decl->isStruct())
+ Tag = llvm::dwarf::DW_TAG_structure_type;
+ else if (Decl->isUnion())
+ Tag = llvm::dwarf::DW_TAG_union_type;
+ else {
+ assert(Decl->isClass() && "Unknown RecordType!");
+ Tag = llvm::dwarf::DW_TAG_class_type;
+ }
+
+ SourceManager &SM = CGM.getContext().getSourceManager();
+
+ // Get overall information about the record type for the debug info.
+ PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation());
+ llvm::DICompileUnit DefUnit;
+ unsigned Line = 0;
+ if (!PLoc.isInvalid()) {
+ DefUnit = getOrCreateCompileUnit(Decl->getLocation());
+ Line = PLoc.getLine();
+ }
+
+ // Records and classes and unions can all be recursive. To handle them, we
+ // first generate a debug descriptor for the struct as a forward declaration.
+ // Then (if it is a definition) we go through and get debug info for all of
+ // its members. Finally, we create a descriptor for the complete type (which
+ // may refer to the forward decl if the struct is recursive) and replace all
+ // uses of the forward declaration with the final definition.
+
+ // A Decl->getName() is not unique. However, the debug info descriptors
+ // are uniqued. The debug info descriptor describing record's context is
+ // necessary to keep two Decl's descriptor unique if their name match.
+ // FIXME : Use RecordDecl's DeclContext's descriptor. As a temp. step
+ // use type's name in FwdDecl.
+ std::string STy = QualType(Ty, 0).getAsString();
+ llvm::DICompositeType FwdDecl =
+ DebugFactory.CreateCompositeType(Tag, Unit, STy.c_str(),
+ DefUnit, Line, 0, 0, 0, 0,
+ llvm::DIType(), llvm::DIArray());
+
+ // If this is just a forward declaration, return it.
+ if (!Decl->getDefinition(CGM.getContext()))
+ return FwdDecl;
+
+ llvm::TrackingVH<llvm::MDNode> FwdDeclNode = FwdDecl.getNode();
+ // Otherwise, insert it into the TypeCache so that recursive uses will find
+ // it.
+ TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = FwdDecl.getNode();
+
+ // Convert all the elements.
+ llvm::SmallVector<llvm::DIDescriptor, 16> EltTys;
+
+ CollectRecordFields(Decl, Unit, EltTys);
+ if (CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(Decl))
+ CollectCXXMemberFunctions(CXXDecl, Unit, EltTys, FwdDecl);
llvm::DIArray Elements =
DebugFactory.GetOrCreateArray(EltTys.data(), EltTys.size());
@@ -1000,18 +1076,27 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType,
const Decl *D = GD.getDecl();
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ // If there is a DISubprogram for this function available then use it.
+ llvm::DenseMap<const FunctionDecl *, llvm::WeakVH>::iterator
+ FI = SPCache.find(FD);
+ if (FI != SPCache.end()) {
+ llvm::DISubprogram SP(dyn_cast_or_null<llvm::MDNode>(FI->second));
+ if (!SP.isNull() && SP.isSubprogram() && SP.isDefinition()) {
+ RegionStack.push_back(SP.getNode());
+ return;
+ }
+ }
Name = getFunctionName(FD);
- if (Name[0] == '\01')
+ if (!Name.empty() && Name[0] == '\01')
Name = Name.substr(1);
// Use mangled name as linkage name for c/c++ functions.
LinkageName = CGM.getMangledName(GD);
} else {
// Use llvm function name as linkage name.
Name = Fn->getName();
- // Skip the asm prefix if it exists.
- if (Name[0] == '\01')
- Name = Name.substr(1);
LinkageName = Name;
+ if (!Name.empty() && Name[0] == '\01')
+ Name = Name.substr(1);
}
// It is expected that CurLoc is set before using EmitFunctionStart.
diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h
index 8e88988..fddd23b 100644
--- a/lib/CodeGen/CGDebugInfo.h
+++ b/lib/CodeGen/CGDebugInfo.h
@@ -64,6 +64,8 @@ class CGDebugInfo {
/// constructed on demand. For example, C++ destructors, C++ operators etc..
llvm::BumpPtrAllocator FunctionNames;
+ llvm::DenseMap<const FunctionDecl *, llvm::WeakVH> SPCache;
+
/// Helper functions for getOrCreateType.
llvm::DIType CreateType(const BuiltinType *Ty, llvm::DICompileUnit U);
llvm::DIType CreateType(const ComplexType *Ty, llvm::DICompileUnit U);
@@ -85,6 +87,12 @@ class CGDebugInfo {
llvm::DIType CreatePointerLikeType(unsigned Tag,
const Type *Ty, QualType PointeeTy,
llvm::DICompileUnit U);
+ void CollectCXXMemberFunctions(const CXXRecordDecl *Decl,
+ llvm::DICompileUnit U,
+ llvm::SmallVectorImpl<llvm::DIDescriptor> &E,
+ llvm::DICompositeType &T);
+ void CollectRecordFields(const RecordDecl *Decl, llvm::DICompileUnit U,
+ llvm::SmallVectorImpl<llvm::DIDescriptor> &E);
public:
CGDebugInfo(CodeGenModule &CGM);
~CGDebugInfo();
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp
index dec06e2..7d5b3da 100644
--- a/lib/CodeGen/CGExprConstant.cpp
+++ b/lib/CodeGen/CGExprConstant.cpp
@@ -742,7 +742,8 @@ public:
return CGM.GetAddrOfConstantStringFromObjCEncode(cast<ObjCEncodeExpr>(E));
case Expr::ObjCStringLiteralClass: {
ObjCStringLiteral* SL = cast<ObjCStringLiteral>(E);
- llvm::Constant *C = CGM.getObjCRuntime().GenerateConstantString(SL);
+ llvm::Constant *C =
+ CGM.getObjCRuntime().GenerateConstantString(SL->getString());
return llvm::ConstantExpr::getBitCast(C, ConvertType(E->getType()));
}
case Expr::PredefinedExprClass: {
@@ -764,11 +765,18 @@ public:
}
case Expr::CallExprClass: {
CallExpr* CE = cast<CallExpr>(E);
- if (CE->isBuiltinCall(CGM.getContext()) !=
- Builtin::BI__builtin___CFStringMakeConstantString)
+ unsigned builtin = CE->isBuiltinCall(CGM.getContext());
+ if (builtin !=
+ Builtin::BI__builtin___CFStringMakeConstantString &&
+ builtin !=
+ Builtin::BI__builtin___NSStringMakeConstantString)
break;
const Expr *Arg = CE->getArg(0)->IgnoreParenCasts();
const StringLiteral *Literal = cast<StringLiteral>(Arg);
+ if (builtin ==
+ Builtin::BI__builtin___NSStringMakeConstantString) {
+ return CGM.getObjCRuntime().GenerateConstantString(Literal);
+ }
// FIXME: need to deal with UCN conversion issues.
return CGM.GetAddrOfConstantCFString(Literal);
}
diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp
index ac391d9..896d220 100644
--- a/lib/CodeGen/CGObjC.cpp
+++ b/lib/CodeGen/CGObjC.cpp
@@ -26,7 +26,8 @@ using namespace CodeGen;
/// Emits an instance of NSConstantString representing the object.
llvm::Value *CodeGenFunction::EmitObjCStringLiteral(const ObjCStringLiteral *E)
{
- llvm::Constant *C = CGM.getObjCRuntime().GenerateConstantString(E);
+ llvm::Constant *C =
+ CGM.getObjCRuntime().GenerateConstantString(E->getString());
// FIXME: This bitcast should just be made an invariant on the Runtime.
return llvm::ConstantExpr::getBitCast(C, ConvertType(E->getType()));
}
diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp
index e7a2093..77be9fb 100644
--- a/lib/CodeGen/CGObjCGNU.cpp
+++ b/lib/CodeGen/CGObjCGNU.cpp
@@ -124,7 +124,7 @@ private:
void EmitClassRef(const std::string &className);
public:
CGObjCGNU(CodeGen::CodeGenModule &cgm);
- virtual llvm::Constant *GenerateConstantString(const ObjCStringLiteral *);
+ virtual llvm::Constant *GenerateConstantString(const StringLiteral *);
virtual CodeGen::RValue
GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
QualType ResultType,
@@ -240,15 +240,23 @@ CGObjCGNU::CGObjCGNU(CodeGen::CodeGenModule &cgm)
Zeros[1] = Zeros[0];
NULLPtr = llvm::ConstantPointerNull::get(PtrToInt8Ty);
// Get the selector Type.
- SelectorTy = cast<llvm::PointerType>(
- CGM.getTypes().ConvertType(CGM.getContext().getObjCSelType()));
+ QualType selTy = CGM.getContext().getObjCSelType();
+ if (QualType() == selTy) {
+ SelectorTy = PtrToInt8Ty;
+ } else {
+ SelectorTy = cast<llvm::PointerType>(CGM.getTypes().ConvertType(selTy));
+ }
PtrToIntTy = llvm::PointerType::getUnqual(IntTy);
PtrTy = PtrToInt8Ty;
// Object type
ASTIdTy = CGM.getContext().getObjCIdType();
- IdTy = cast<llvm::PointerType>(CGM.getTypes().ConvertType(ASTIdTy));
+ if (QualType() == ASTIdTy) {
+ IdTy = PtrToInt8Ty;
+ } else {
+ IdTy = cast<llvm::PointerType>(CGM.getTypes().ConvertType(ASTIdTy));
+ }
// IMP type
std::vector<const llvm::Type*> IMPArgs;
@@ -348,12 +356,9 @@ llvm::Constant *CGObjCGNU::MakeGlobal(const llvm::ArrayType *Ty,
}
/// Generate an NSConstantString object.
-//TODO: In case there are any crazy people still using the GNU runtime without
-//an OpenStep implementation, this should let them select their own class for
-//constant strings.
-llvm::Constant *CGObjCGNU::GenerateConstantString(const ObjCStringLiteral *SL) {
- std::string Str(SL->getString()->getStrData(),
- SL->getString()->getByteLength());
+llvm::Constant *CGObjCGNU::GenerateConstantString(const StringLiteral *SL) {
+ std::string Str(SL->getStrData(), SL->getByteLength());
+
std::vector<llvm::Constant*> Ivars;
Ivars.push_back(NULLPtr);
Ivars.push_back(MakeConstantString(Str));
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index 727746f..137ea51 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -952,7 +952,7 @@ public:
CGObjCCommonMac(CodeGen::CodeGenModule &cgm) :
CGM(cgm), VMContext(cgm.getLLVMContext()) { }
- virtual llvm::Constant *GenerateConstantString(const ObjCStringLiteral *SL);
+ virtual llvm::Constant *GenerateConstantString(const StringLiteral *SL);
virtual llvm::Function *GenerateMethod(const ObjCMethodDecl *OMD,
const ObjCContainerDecl *CD=0);
@@ -1454,8 +1454,8 @@ llvm::Value *CGObjCMac::GetSelector(CGBuilderTy &Builder, const ObjCMethodDecl
*/
llvm::Constant *CGObjCCommonMac::GenerateConstantString(
- const ObjCStringLiteral *SL) {
- return CGM.GetAddrOfConstantCFString(SL->getString());
+ const StringLiteral *SL) {
+ return CGM.GetAddrOfConstantCFString(SL);
}
/// Generates a message send where the super is the receiver. This is
diff --git a/lib/CodeGen/CGObjCRuntime.h b/lib/CodeGen/CGObjCRuntime.h
index 6b45562..ff5d40b 100644
--- a/lib/CodeGen/CGObjCRuntime.h
+++ b/lib/CodeGen/CGObjCRuntime.h
@@ -106,7 +106,7 @@ public:
const ObjCMethodDecl *Method) = 0;
/// Generate a constant string object.
- virtual llvm::Constant *GenerateConstantString(const ObjCStringLiteral *) = 0;
+ virtual llvm::Constant *GenerateConstantString(const StringLiteral *) = 0;
/// Generate a category. A category contains a list of methods (and
/// accompanying metadata) and a list of protocols.
diff --git a/lib/CodeGen/CGVTT.cpp b/lib/CodeGen/CGVTT.cpp
new file mode 100644
index 0000000..9714bd9
--- /dev/null
+++ b/lib/CodeGen/CGVTT.cpp
@@ -0,0 +1,398 @@
+//===--- CGVTT.cpp - Emit LLVM Code for C++ VTTs --------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This contains code dealing with C++ code generation of VTTs (vtable tables).
+//
+//===----------------------------------------------------------------------===//
+
+#include "CodeGenModule.h"
+#include "clang/AST/RecordLayout.h"
+using namespace clang;
+using namespace CodeGen;
+
+#define D1(x)
+
+namespace {
+class VTTBuilder {
+ /// Inits - The list of values built for the VTT.
+ std::vector<llvm::Constant *> &Inits;
+ /// Class - The most derived class that this vtable is being built for.
+ const CXXRecordDecl *Class;
+ CodeGenModule &CGM; // Per-module state.
+ llvm::SmallSet<const CXXRecordDecl *, 32> SeenVBase;
+ /// BLayout - Layout for the most derived class that this vtable is being
+ /// built for.
+ const ASTRecordLayout &BLayout;
+ CGVtableInfo::AddrMap_t &AddressPoints;
+ // vtbl - A pointer to the vtable for Class.
+ llvm::Constant *ClassVtbl;
+ llvm::LLVMContext &VMContext;
+
+ /// SeenVBasesInSecondary - The seen virtual bases when building the
+ /// secondary virtual pointers.
+ llvm::SmallPtrSet<const CXXRecordDecl *, 32> SeenVBasesInSecondary;
+
+ llvm::DenseMap<const CXXRecordDecl *, uint64_t> SubVTTIndicies;
+
+ bool GenerateDefinition;
+
+ llvm::DenseMap<BaseSubobject, llvm::Constant *> CtorVtables;
+ llvm::DenseMap<std::pair<const CXXRecordDecl *, BaseSubobject>, uint64_t>
+ CtorVtableAddressPoints;
+
+ llvm::Constant *getCtorVtable(const BaseSubobject &Base) {
+ if (!GenerateDefinition)
+ return 0;
+
+ llvm::Constant *&CtorVtable = CtorVtables[Base];
+ if (!CtorVtable) {
+ // Build the vtable.
+ CGVtableInfo::CtorVtableInfo Info
+ = CGM.getVtableInfo().getCtorVtable(Class, Base);
+
+ CtorVtable = Info.Vtable;
+
+ // Add the address points for this base.
+ for (CGVtableInfo::AddressPointsMapTy::const_iterator I =
+ Info.AddressPoints.begin(), E = Info.AddressPoints.end();
+ I != E; ++I) {
+ uint64_t &AddressPoint =
+ CtorVtableAddressPoints[std::make_pair(Base.getBase(), I->first)];
+
+ // Check if we already have the address points for this base.
+ if (AddressPoint)
+ break;
+
+ // Otherwise, insert it.
+ AddressPoint = I->second;
+ }
+ }
+
+ return CtorVtable;
+ }
+
+
+ /// BuildVtablePtr - Build up a referene to the given secondary vtable
+ llvm::Constant *BuildVtablePtr(llvm::Constant *Vtable,
+ const CXXRecordDecl *VtableClass,
+ const CXXRecordDecl *RD,
+ uint64_t Offset) {
+ if (!GenerateDefinition)
+ return 0;
+
+ uint64_t AddressPoint;
+
+ if (VtableClass != Class) {
+ // We have a ctor vtable, look for the address point in the ctor vtable
+ // address points.
+ AddressPoint =
+ CtorVtableAddressPoints[std::make_pair(VtableClass,
+ BaseSubobject(RD, Offset))];
+ } else {
+ AddressPoint =
+ (*AddressPoints[VtableClass])[std::make_pair(RD, Offset)];
+ }
+
+ // FIXME: We can never have 0 address point. Do this for now so gepping
+ // retains the same structure. Later we'll just assert.
+ if (AddressPoint == 0)
+ AddressPoint = 1;
+ D1(printf("XXX address point for %s in %s layout %s at offset %d was %d\n",
+ RD->getNameAsCString(), VtblClass->getNameAsCString(),
+ Class->getNameAsCString(), (int)Offset, (int)AddressPoint));
+
+ llvm::Value *Idxs[] = {
+ llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), 0),
+ llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), AddressPoint)
+ };
+
+ llvm::Constant *Init =
+ llvm::ConstantExpr::getInBoundsGetElementPtr(Vtable, Idxs, 2);
+
+ const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext);
+ return llvm::ConstantExpr::getBitCast(Init, Int8PtrTy);
+ }
+
+ /// Secondary - Add the secondary vtable pointers to Inits. Offset is the
+ /// current offset in bits to the object we're working on.
+ void Secondary(const CXXRecordDecl *RD, llvm::Constant *vtbl,
+ const CXXRecordDecl *VtblClass, uint64_t Offset=0,
+ bool MorallyVirtual=false) {
+ if (RD->getNumVBases() == 0 && ! MorallyVirtual)
+ return;
+
+ for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
+ e = RD->bases_end(); i != e; ++i) {
+ const CXXRecordDecl *Base =
+ cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
+
+ // We only want to visit each virtual base once.
+ if (i->isVirtual() && SeenVBasesInSecondary.count(Base))
+ continue;
+
+ // Itanium C++ ABI 2.6.2:
+ // Secondary virtual pointers are present for all bases with either
+ // virtual bases or virtual function declarations overridden along a
+ // virtual path.
+ //
+ // If the base class is not dynamic, we don't want to add it, nor any
+ // of its base classes.
+ if (!Base->isDynamicClass())
+ continue;
+
+ const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
+ const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
+ const bool PrimaryBaseWasVirtual = Layout.getPrimaryBaseWasVirtual();
+ bool NonVirtualPrimaryBase;
+ NonVirtualPrimaryBase = !PrimaryBaseWasVirtual && Base == PrimaryBase;
+ bool BaseMorallyVirtual = MorallyVirtual | i->isVirtual();
+ uint64_t BaseOffset;
+ if (!i->isVirtual()) {
+ const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
+ BaseOffset = Offset + Layout.getBaseClassOffset(Base);
+ } else
+ BaseOffset = BLayout.getVBaseClassOffset(Base);
+ llvm::Constant *subvtbl = vtbl;
+ const CXXRecordDecl *subVtblClass = VtblClass;
+ if ((Base->getNumVBases() || BaseMorallyVirtual)
+ && !NonVirtualPrimaryBase) {
+ llvm::Constant *init;
+ if (BaseMorallyVirtual || VtblClass == Class)
+ init = BuildVtablePtr(vtbl, VtblClass, Base, BaseOffset);
+ else {
+ init = getCtorVtable(BaseSubobject(Base, BaseOffset));
+
+ subvtbl = init;
+ subVtblClass = Base;
+
+ init = BuildVtablePtr(init, Class, Base, BaseOffset);
+ }
+
+ Inits.push_back(init);
+ }
+
+ if (i->isVirtual())
+ SeenVBasesInSecondary.insert(Base);
+
+ Secondary(Base, subvtbl, subVtblClass, BaseOffset, BaseMorallyVirtual);
+ }
+ }
+
+ /// BuiltVTT - Add the VTT to Inits. Offset is the offset in bits to the
+ /// currnet object we're working on.
+ void BuildVTT(const CXXRecordDecl *RD, uint64_t Offset, bool MorallyVirtual) {
+ // Itanium C++ ABI 2.6.2:
+ // An array of virtual table addresses, called the VTT, is declared for
+ // each class type that has indirect or direct virtual base classes.
+ if (RD->getNumVBases() == 0)
+ return;
+
+ // Remember the sub-VTT index.
+ SubVTTIndicies[RD] = Inits.size();
+
+ llvm::Constant *Vtable;
+ const CXXRecordDecl *VtableClass;
+
+ // First comes the primary virtual table pointer...
+ if (MorallyVirtual) {
+ Vtable = ClassVtbl;
+ VtableClass = Class;
+ } else {
+ Vtable = getCtorVtable(BaseSubobject(RD, Offset));
+ VtableClass = RD;
+ }
+
+ llvm::Constant *Init = BuildVtablePtr(Vtable, VtableClass, RD, Offset);
+ Inits.push_back(Init);
+
+ // then the secondary VTTs....
+ SecondaryVTTs(RD, Offset, MorallyVirtual);
+
+ // Make sure to clear the set of seen virtual bases.
+ SeenVBasesInSecondary.clear();
+
+ // and last the secondary vtable pointers.
+ Secondary(RD, Vtable, VtableClass, Offset, MorallyVirtual);
+ }
+
+ /// SecondaryVTTs - Add the secondary VTTs to Inits. The secondary VTTs are
+ /// built from each direct non-virtual proper base that requires a VTT in
+ /// declaration order.
+ void SecondaryVTTs(const CXXRecordDecl *RD, uint64_t Offset=0,
+ bool MorallyVirtual=false) {
+ for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
+ e = RD->bases_end(); i != e; ++i) {
+ const CXXRecordDecl *Base =
+ cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
+ if (i->isVirtual())
+ continue;
+ const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
+ uint64_t BaseOffset = Offset + Layout.getBaseClassOffset(Base);
+
+ BuildVTT(Base, BaseOffset, MorallyVirtual);
+ }
+ }
+
+ /// VirtualVTTs - Add the VTT for each proper virtual base in inheritance
+ /// graph preorder.
+ void VirtualVTTs(const CXXRecordDecl *RD) {
+ for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
+ e = RD->bases_end(); i != e; ++i) {
+ const CXXRecordDecl *Base =
+ cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
+ if (i->isVirtual() && !SeenVBase.count(Base)) {
+ SeenVBase.insert(Base);
+ uint64_t BaseOffset = BLayout.getVBaseClassOffset(Base);
+ BuildVTT(Base, BaseOffset, false);
+ }
+ VirtualVTTs(Base);
+ }
+ }
+
+public:
+ VTTBuilder(std::vector<llvm::Constant *> &inits, const CXXRecordDecl *c,
+ CodeGenModule &cgm, bool GenerateDefinition)
+ : Inits(inits), Class(c), CGM(cgm),
+ BLayout(cgm.getContext().getASTRecordLayout(c)),
+ AddressPoints(*cgm.getVtableInfo().AddressPoints[c]),
+ VMContext(cgm.getModule().getContext()),
+ GenerateDefinition(GenerateDefinition) {
+
+ // First comes the primary virtual table pointer for the complete class...
+ ClassVtbl = GenerateDefinition ? CGM.getVtableInfo().getVtable(Class) : 0;
+
+ llvm::Constant *Init = BuildVtablePtr(ClassVtbl, Class, Class, 0);
+ Inits.push_back(Init);
+
+ // then the secondary VTTs...
+ SecondaryVTTs(Class);
+
+ // Make sure to clear the set of seen virtual bases.
+ SeenVBasesInSecondary.clear();
+
+ // then the secondary vtable pointers...
+ Secondary(Class, ClassVtbl, Class);
+
+ // and last, the virtual VTTs.
+ VirtualVTTs(Class);
+ }
+
+ llvm::DenseMap<const CXXRecordDecl *, uint64_t> &getSubVTTIndicies() {
+ return SubVTTIndicies;
+ }
+};
+}
+
+llvm::GlobalVariable *
+CGVtableInfo::GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage,
+ bool GenerateDefinition,
+ const CXXRecordDecl *RD) {
+ // Only classes that have virtual bases need a VTT.
+ if (RD->getNumVBases() == 0)
+ return 0;
+
+ llvm::SmallString<256> OutName;
+ CGM.getMangleContext().mangleCXXVTT(RD, OutName);
+ llvm::StringRef Name = OutName.str();
+
+ D1(printf("vtt %s\n", RD->getNameAsCString()));
+
+ llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name);
+ if (GV == 0 || GV->isDeclaration()) {
+ const llvm::Type *Int8PtrTy =
+ llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
+
+ std::vector<llvm::Constant *> inits;
+ VTTBuilder b(inits, RD, CGM, GenerateDefinition);
+
+ const llvm::ArrayType *Type = llvm::ArrayType::get(Int8PtrTy, inits.size());
+ llvm::Constant *Init = 0;
+ if (GenerateDefinition)
+ Init = llvm::ConstantArray::get(Type, inits);
+
+ llvm::GlobalVariable *OldGV = GV;
+ GV = new llvm::GlobalVariable(CGM.getModule(), Type, /*isConstant=*/true,
+ Linkage, Init, Name);
+ CGM.setGlobalVisibility(GV, RD);
+
+ if (OldGV) {
+ GV->takeName(OldGV);
+ llvm::Constant *NewPtr =
+ llvm::ConstantExpr::getBitCast(GV, OldGV->getType());
+ OldGV->replaceAllUsesWith(NewPtr);
+ OldGV->eraseFromParent();
+ }
+ }
+
+ return GV;
+}
+
+CGVtableInfo::CtorVtableInfo
+CGVtableInfo::getCtorVtable(const CXXRecordDecl *RD,
+ const BaseSubobject &Base) {
+ CtorVtableInfo Info;
+
+ Info.Vtable = GenerateVtable(llvm::GlobalValue::InternalLinkage,
+ /*GenerateDefinition=*/true,
+ RD, Base.getBase(), Base.getBaseOffset(),
+ Info.AddressPoints);
+ return Info;
+}
+
+llvm::GlobalVariable *CGVtableInfo::getVTT(const CXXRecordDecl *RD) {
+ return GenerateVTT(llvm::GlobalValue::ExternalLinkage,
+ /*GenerateDefinition=*/false, RD);
+
+}
+
+
+bool CGVtableInfo::needsVTTParameter(GlobalDecl GD) {
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
+
+ // We don't have any virtual bases, just return early.
+ if (!MD->getParent()->getNumVBases())
+ return false;
+
+ // Check if we have a base constructor.
+ if (isa<CXXConstructorDecl>(MD) && GD.getCtorType() == Ctor_Base)
+ return true;
+
+ // Check if we have a base destructor.
+ if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() == Dtor_Base)
+ return true;
+
+ return false;
+}
+
+uint64_t CGVtableInfo::getSubVTTIndex(const CXXRecordDecl *RD,
+ const CXXRecordDecl *Base) {
+ ClassPairTy ClassPair(RD, Base);
+
+ SubVTTIndiciesTy::iterator I =
+ SubVTTIndicies.find(ClassPair);
+ if (I != SubVTTIndicies.end())
+ return I->second;
+
+ std::vector<llvm::Constant *> inits;
+ VTTBuilder Builder(inits, RD, CGM, /*GenerateDefinition=*/false);
+
+ for (llvm::DenseMap<const CXXRecordDecl *, uint64_t>::iterator I =
+ Builder.getSubVTTIndicies().begin(),
+ E = Builder.getSubVTTIndicies().end(); I != E; ++I) {
+ // Insert all indices.
+ ClassPairTy ClassPair(RD, I->first);
+
+ SubVTTIndicies.insert(std::make_pair(ClassPair, I->second));
+ }
+
+ I = SubVTTIndicies.find(ClassPair);
+ assert(I != SubVTTIndicies.end() && "Did not find index!");
+
+ return I->second;
+}
diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp
index ae900d6..e5abfc6 100644
--- a/lib/CodeGen/CGVtable.cpp
+++ b/lib/CodeGen/CGVtable.cpp
@@ -232,8 +232,8 @@ public:
return llvm::ConstantExpr::getBitCast(m, Ptr8Ty);
}
-#define D1(x)
-//#define D1(X) do { if (getenv("DEBUG")) { X; } } while (0)
+//#define D1(x)
+#define D1(X) do { if (getenv("DEBUG")) { X; } } while (0)
void GenerateVBaseOffsets(const CXXRecordDecl *RD, uint64_t Offset,
bool updateVBIndex, Index_t current_vbindex) {
@@ -254,7 +254,7 @@ public:
D1(printf(" vbase for %s at %d delta %d most derived %s\n",
Base->getNameAsCString(),
(int)-VCalls.size()-3, (int)BaseOffset,
- Class->getNameAsCString()));
+ MostDerivedClass->getNameAsCString()));
}
// We also record offsets for non-virtual bases to closest enclosing
// virtual base. We do this so that we don't have to search
@@ -376,13 +376,14 @@ public:
CurrentVBaseOffset))
return;
+ D1(printf(" vfn for %s at %d\n",
+ dyn_cast<CXXMethodDecl>(GD.getDecl())->getNameAsCString(),
+ (int)Methods.size()));
+
// We didn't find an entry in the vtable that we could use, add a new
// entry.
Methods.AddMethod(GD);
- D1(printf(" vfn for %s at %d\n", MD->getNameAsString().c_str(),
- (int)Index[GD]));
-
VCallOffset[GD] = Offset/8;
if (MorallyVirtual) {
Index_t &idx = VCall[GD];
@@ -392,7 +393,8 @@ public:
idx = VCalls.size()+1;
VCalls.push_back(0);
D1(printf(" vcall for %s at %d with delta %d\n",
- MD->getNameAsString().c_str(), (int)-VCalls.size()-3, 0));
+ dyn_cast<CXXMethodDecl>(GD.getDecl())->getNameAsCString(),
+ (int)-VCalls.size()-3, 0));
}
}
}
@@ -429,12 +431,11 @@ public:
continue;
const CXXRecordDecl *Base =
cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
- if (Base != PrimaryBase || PrimaryBaseWasVirtual) {
- uint64_t o = Offset + Layout.getBaseClassOffset(Base);
- StartNewTable();
- GenerateVtableForBase(Base, o, MorallyVirtual, false,
- CurrentVBaseOffset, Path);
- }
+ uint64_t o = Offset + Layout.getBaseClassOffset(Base);
+ StartNewTable();
+ GenerateVtableForBase(Base, o, MorallyVirtual, false,
+ true, Base == PrimaryBase && !PrimaryBaseWasVirtual,
+ CurrentVBaseOffset, Path);
}
Path->pop_back();
}
@@ -463,7 +464,7 @@ public:
void AddAddressPoints(const CXXRecordDecl *RD, uint64_t Offset,
Index_t AddressPoint) {
D1(printf("XXX address point for %s in %s layout %s at offset %d is %d\n",
- RD->getNameAsCString(), Class->getNameAsCString(),
+ RD->getNameAsCString(), MostDerivedClass->getNameAsCString(),
LayoutClass->getNameAsCString(), (int)Offset, (int)AddressPoint));
subAddressPoints[std::make_pair(RD, Offset)] = AddressPoint;
AddressPoints[BaseSubobject(RD, Offset)] = AddressPoint;
@@ -480,7 +481,7 @@ public:
BLayout.getVBaseClassOffset(RD) != Offset)
break;
D1(printf("XXX address point for %s in %s layout %s at offset %d is %d\n",
- RD->getNameAsCString(), Class->getNameAsCString(),
+ RD->getNameAsCString(), MostDerivedClass->getNameAsCString(),
LayoutClass->getNameAsCString(), (int)Offset, (int)AddressPoint));
subAddressPoints[std::make_pair(RD, Offset)] = AddressPoint;
AddressPoints[BaseSubobject(RD, Offset)] = AddressPoint;
@@ -491,6 +492,7 @@ public:
void FinishGenerateVtable(const CXXRecordDecl *RD,
const ASTRecordLayout &Layout,
const CXXRecordDecl *PrimaryBase,
+ bool ForNPNVBases, bool WasPrimaryBase,
bool PrimaryBaseWasVirtual,
bool MorallyVirtual, int64_t Offset,
bool ForVirtualBase, int64_t CurrentVBaseOffset,
@@ -503,23 +505,27 @@ public:
StartNewTable();
extra = 0;
- bool DeferVCalls = MorallyVirtual || ForVirtualBase;
- int VCallInsertionPoint = VtableComponents.size();
- if (!DeferVCalls) {
- insertVCalls(VCallInsertionPoint);
- } else
- // FIXME: just for extra, or for all uses of VCalls.size post this?
- extra = -VCalls.size();
+ Index_t AddressPoint = 0;
+ int VCallInsertionPoint = 0;
+ if (!ForNPNVBases || !WasPrimaryBase) {
+ bool DeferVCalls = MorallyVirtual || ForVirtualBase;
+ VCallInsertionPoint = VtableComponents.size();
+ if (!DeferVCalls) {
+ insertVCalls(VCallInsertionPoint);
+ } else
+ // FIXME: just for extra, or for all uses of VCalls.size post this?
+ extra = -VCalls.size();
- // Add the offset to top.
- VtableComponents.push_back(BuildVtable ? wrap(-((Offset-LayoutOffset)/8)) : 0);
+ // Add the offset to top.
+ VtableComponents.push_back(BuildVtable ? wrap(-((Offset-LayoutOffset)/8)) : 0);
- // Add the RTTI information.
- VtableComponents.push_back(rtti);
+ // Add the RTTI information.
+ VtableComponents.push_back(rtti);
- Index_t AddressPoint = VtableComponents.size();
+ AddressPoint = VtableComponents.size();
- AppendMethodsToVtable();
+ AppendMethodsToVtable();
+ }
// and then the non-virtual bases.
NonVirtualBases(RD, Layout, PrimaryBase, PrimaryBaseWasVirtual,
@@ -537,7 +543,8 @@ public:
insertVCalls(VCallInsertionPoint);
}
- AddAddressPoints(RD, Offset, AddressPoint);
+ if (!ForNPNVBases || !WasPrimaryBase)
+ AddAddressPoints(RD, Offset, AddressPoint);
if (alloc) {
delete Path;
@@ -557,13 +564,13 @@ public:
// vtables are composed from the chain of primaries.
if (PrimaryBase && !PrimaryBaseWasVirtual) {
D1(printf(" doing primaries for %s most derived %s\n",
- RD->getNameAsCString(), Class->getNameAsCString()));
+ RD->getNameAsCString(), MostDerivedClass->getNameAsCString()));
Primaries(PrimaryBase, PrimaryBaseWasVirtual|MorallyVirtual, Offset,
updateVBIndex, current_vbindex, CurrentVBaseOffset);
}
D1(printf(" doing vcall entries for %s most derived %s\n",
- RD->getNameAsCString(), Class->getNameAsCString()));
+ RD->getNameAsCString(), MostDerivedClass->getNameAsCString()));
// And add the virtuals for the class to the primary vtable.
AddMethods(RD, MorallyVirtual, Offset, CurrentVBaseOffset);
@@ -589,7 +596,7 @@ public:
}
D1(printf(" doing primaries for %s most derived %s\n",
- RD->getNameAsCString(), Class->getNameAsCString()));
+ RD->getNameAsCString(), MostDerivedClass->getNameAsCString()));
VBPrimaries(PrimaryBase, PrimaryBaseWasVirtual|MorallyVirtual, Offset,
updateVBIndex, current_vbindex, PrimaryBaseWasVirtual,
@@ -597,7 +604,7 @@ public:
}
D1(printf(" doing vbase entries for %s most derived %s\n",
- RD->getNameAsCString(), Class->getNameAsCString()));
+ RD->getNameAsCString(), MostDerivedClass->getNameAsCString()));
GenerateVBaseOffsets(RD, Offset, updateVBIndex, current_vbindex);
if (RDisVirtualBase || bottom) {
@@ -609,6 +616,8 @@ public:
void GenerateVtableForBase(const CXXRecordDecl *RD, int64_t Offset = 0,
bool MorallyVirtual = false,
bool ForVirtualBase = false,
+ bool ForNPNVBases = false,
+ bool WasPrimaryBase = true,
int CurrentVBaseOffset = 0,
Path_t *Path = 0) {
if (!RD->isDynamicClass())
@@ -626,20 +635,22 @@ public:
extra = 0;
D1(printf("building entries for base %s most derived %s\n",
- RD->getNameAsCString(), Class->getNameAsCString()));
+ RD->getNameAsCString(), MostDerivedClass->getNameAsCString()));
if (ForVirtualBase)
extra = VCalls.size();
- VBPrimaries(RD, MorallyVirtual, Offset, !ForVirtualBase, 0, ForVirtualBase,
- CurrentVBaseOffset, true);
+ if (!ForNPNVBases || !WasPrimaryBase) {
+ VBPrimaries(RD, MorallyVirtual, Offset, !ForVirtualBase, 0,
+ ForVirtualBase, CurrentVBaseOffset, true);
- if (Path)
- OverrideMethods(Path, MorallyVirtual, Offset, CurrentVBaseOffset);
+ if (Path)
+ OverrideMethods(Path, MorallyVirtual, Offset, CurrentVBaseOffset);
+ }
- FinishGenerateVtable(RD, Layout, PrimaryBase, PrimaryBaseWasVirtual,
- MorallyVirtual, Offset, ForVirtualBase,
- CurrentVBaseOffset, Path);
+ FinishGenerateVtable(RD, Layout, PrimaryBase, ForNPNVBases, WasPrimaryBase,
+ PrimaryBaseWasVirtual, MorallyVirtual, Offset,
+ ForVirtualBase, CurrentVBaseOffset, Path);
}
void GenerateVtableForVBases(const CXXRecordDecl *RD,
@@ -665,9 +676,9 @@ public:
int64_t BaseOffset = BLayout.getVBaseClassOffset(Base);
int64_t CurrentVBaseOffset = BaseOffset;
D1(printf("vtable %s virtual base %s\n",
- Class->getNameAsCString(), Base->getNameAsCString()));
- GenerateVtableForBase(Base, BaseOffset, true, true, CurrentVBaseOffset,
- Path);
+ MostDerivedClass->getNameAsCString(), Base->getNameAsCString()));
+ GenerateVtableForBase(Base, BaseOffset, true, true, false,
+ true, CurrentVBaseOffset, Path);
}
int64_t BaseOffset;
if (i->isVirtual())
@@ -823,14 +834,14 @@ bool VtableBuilder::OverrideMethod(GlobalDecl GD, bool MorallyVirtual,
VCalls.push_back(0);
D1(printf(" vcall for %s at %d with delta %d most derived %s\n",
MD->getNameAsString().c_str(), (int)-idx-3,
- (int)VCalls[idx-1], Class->getNameAsCString()));
+ (int)VCalls[idx-1], MostDerivedClass->getNameAsCString()));
} else {
NonVirtualOffset[GD] = NonVirtualOffset[OGD];
VCallOffset[GD] = VCallOffset[OGD];
VCalls[idx-1] = -VCallOffset[OGD] + OverrideOffset/8;
D1(printf(" vcall patch for %s at %d with delta %d most derived %s\n",
MD->getNameAsString().c_str(), (int)-idx-3,
- (int)VCalls[idx-1], Class->getNameAsCString()));
+ (int)VCalls[idx-1], MostDerivedClass->getNameAsCString()));
}
int64_t NonVirtualAdjustment = NonVirtualOffset[GD];
int64_t VirtualAdjustment =
@@ -1205,284 +1216,6 @@ CGVtableInfo::GenerateVtable(llvm::GlobalVariable::LinkageTypes Linkage,
return GV;
}
-namespace {
-class VTTBuilder {
- /// Inits - The list of values built for the VTT.
- std::vector<llvm::Constant *> &Inits;
- /// Class - The most derived class that this vtable is being built for.
- const CXXRecordDecl *Class;
- CodeGenModule &CGM; // Per-module state.
- llvm::SmallSet<const CXXRecordDecl *, 32> SeenVBase;
- /// BLayout - Layout for the most derived class that this vtable is being
- /// built for.
- const ASTRecordLayout &BLayout;
- CGVtableInfo::AddrMap_t &AddressPoints;
- // vtbl - A pointer to the vtable for Class.
- llvm::Constant *ClassVtbl;
- llvm::LLVMContext &VMContext;
-
- llvm::DenseMap<const CXXRecordDecl *, uint64_t> SubVTTIndicies;
-
- bool GenerateDefinition;
-
- llvm::DenseMap<BaseSubobject, llvm::Constant *> CtorVtables;
- llvm::DenseMap<std::pair<const CXXRecordDecl *, BaseSubobject>, uint64_t>
- CtorVtableAddressPoints;
-
- llvm::Constant *getCtorVtable(const BaseSubobject &Base) {
- if (!GenerateDefinition)
- return 0;
-
- llvm::Constant *&CtorVtable = CtorVtables[Base];
- if (!CtorVtable) {
- // Build the vtable.
- CGVtableInfo::CtorVtableInfo Info
- = CGM.getVtableInfo().getCtorVtable(Class, Base);
-
- CtorVtable = Info.Vtable;
-
- // Add the address points for this base.
- for (CGVtableInfo::AddressPointsMapTy::const_iterator I =
- Info.AddressPoints.begin(), E = Info.AddressPoints.end();
- I != E; ++I) {
- uint64_t &AddressPoint =
- CtorVtableAddressPoints[std::make_pair(Base.getBase(), I->first)];
-
- // Check if we already have the address points for this base.
- if (AddressPoint)
- break;
-
- // Otherwise, insert it.
- AddressPoint = I->second;
- }
- }
-
- return CtorVtable;
- }
-
-
- /// BuildVtablePtr - Build up a referene to the given secondary vtable
- llvm::Constant *BuildVtablePtr(llvm::Constant *Vtable,
- const CXXRecordDecl *VtableClass,
- const CXXRecordDecl *RD,
- uint64_t Offset) {
- int64_t AddressPoint =
- (*AddressPoints[VtableClass])[std::make_pair(RD, Offset)];
-
- // FIXME: We can never have 0 address point. Do this for now so gepping
- // retains the same structure. Later we'll just assert.
- if (AddressPoint == 0)
- AddressPoint = 1;
- D1(printf("XXX address point for %s in %s layout %s at offset %d was %d\n",
- RD->getNameAsCString(), VtblClass->getNameAsCString(),
- Class->getNameAsCString(), (int)Offset, (int)AddressPoint));
-
- llvm::Value *Idxs[] = {
- llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), 0),
- llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), AddressPoint)
- };
-
- llvm::Constant *Init =
- llvm::ConstantExpr::getInBoundsGetElementPtr(Vtable, Idxs, 2);
-
- const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext);
- return llvm::ConstantExpr::getBitCast(Init, Int8PtrTy);
- }
-
- /// Secondary - Add the secondary vtable pointers to Inits. Offset is the
- /// current offset in bits to the object we're working on.
- void Secondary(const CXXRecordDecl *RD, llvm::Constant *vtbl,
- const CXXRecordDecl *VtblClass, uint64_t Offset=0,
- bool MorallyVirtual=false) {
- if (RD->getNumVBases() == 0 && ! MorallyVirtual)
- return;
-
- for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
- e = RD->bases_end(); i != e; ++i) {
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
- const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
- const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
- const bool PrimaryBaseWasVirtual = Layout.getPrimaryBaseWasVirtual();
- bool NonVirtualPrimaryBase;
- NonVirtualPrimaryBase = !PrimaryBaseWasVirtual && Base == PrimaryBase;
- bool BaseMorallyVirtual = MorallyVirtual | i->isVirtual();
- uint64_t BaseOffset;
- if (!i->isVirtual()) {
- const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
- BaseOffset = Offset + Layout.getBaseClassOffset(Base);
- } else
- BaseOffset = BLayout.getVBaseClassOffset(Base);
- llvm::Constant *subvtbl = vtbl;
- const CXXRecordDecl *subVtblClass = VtblClass;
- if ((Base->getNumVBases() || BaseMorallyVirtual)
- && !NonVirtualPrimaryBase) {
- // FIXME: Slightly too many of these for __ZTT8test8_B2
- llvm::Constant *init;
- if (BaseMorallyVirtual)
- init = GenerateDefinition ?
- BuildVtablePtr(vtbl, VtblClass, RD, Offset) : 0;
- else {
- init = GenerateDefinition ?
- getCtorVtable(BaseSubobject(Base, BaseOffset)) : 0;
-
- subvtbl = init;
- subVtblClass = Base;
-
- init = GenerateDefinition ?
- BuildVtablePtr(init, Class, Base, BaseOffset) : 0;
- }
- Inits.push_back(init);
- }
- Secondary(Base, subvtbl, subVtblClass, BaseOffset, BaseMorallyVirtual);
- }
- }
-
- /// BuiltVTT - Add the VTT to Inits. Offset is the offset in bits to the
- /// currnet object we're working on.
- void BuildVTT(const CXXRecordDecl *RD, uint64_t Offset, bool MorallyVirtual) {
- if (RD->getNumVBases() == 0 && !MorallyVirtual)
- return;
-
- llvm::Constant *Vtable;
- const CXXRecordDecl *VtableClass;
-
- // First comes the primary virtual table pointer...
- if (MorallyVirtual) {
- Vtable = GenerateDefinition ? ClassVtbl : 0;
- VtableClass = Class;
- } else {
- Vtable = GenerateDefinition ?
- getCtorVtable(BaseSubobject(RD, Offset)) : 0;
- VtableClass = RD;
- }
-
- llvm::Constant *Init = GenerateDefinition ?
- BuildVtablePtr(Vtable, VtableClass, RD, Offset) : 0;
- Inits.push_back(Init);
-
- // then the secondary VTTs....
- SecondaryVTTs(RD, Offset, MorallyVirtual);
-
- // and last the secondary vtable pointers.
- Secondary(RD, Vtable, VtableClass, Offset, MorallyVirtual);
- }
-
- /// SecondaryVTTs - Add the secondary VTTs to Inits. The secondary VTTs are
- /// built from each direct non-virtual proper base that requires a VTT in
- /// declaration order.
- void SecondaryVTTs(const CXXRecordDecl *RD, uint64_t Offset=0,
- bool MorallyVirtual=false) {
- for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
- e = RD->bases_end(); i != e; ++i) {
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
- if (i->isVirtual())
- continue;
- const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
- uint64_t BaseOffset = Offset + Layout.getBaseClassOffset(Base);
-
- // Remember the sub-VTT index.
- SubVTTIndicies[Base] = Inits.size();
-
- BuildVTT(Base, BaseOffset, MorallyVirtual);
- }
- }
-
- /// VirtualVTTs - Add the VTT for each proper virtual base in inheritance
- /// graph preorder.
- void VirtualVTTs(const CXXRecordDecl *RD) {
- for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
- e = RD->bases_end(); i != e; ++i) {
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
- if (i->isVirtual() && !SeenVBase.count(Base)) {
- // Remember the sub-VTT index.
- SubVTTIndicies[Base] = Inits.size();
-
- SeenVBase.insert(Base);
- uint64_t BaseOffset = BLayout.getVBaseClassOffset(Base);
- BuildVTT(Base, BaseOffset, true);
- }
- VirtualVTTs(Base);
- }
- }
-
-public:
- VTTBuilder(std::vector<llvm::Constant *> &inits, const CXXRecordDecl *c,
- CodeGenModule &cgm, bool GenerateDefinition)
- : Inits(inits), Class(c), CGM(cgm),
- BLayout(cgm.getContext().getASTRecordLayout(c)),
- AddressPoints(*cgm.getVtableInfo().AddressPoints[c]),
- VMContext(cgm.getModule().getContext()),
- GenerateDefinition(GenerateDefinition) {
-
- // First comes the primary virtual table pointer for the complete class...
- ClassVtbl = CGM.getVtableInfo().getVtable(Class);
- llvm::Constant *Init = GenerateDefinition ?
- BuildVtablePtr(ClassVtbl, Class, Class, 0) : 0;
- Inits.push_back(Init);
-
- // then the secondary VTTs...
- SecondaryVTTs(Class);
-
- // then the secondary vtable pointers...
- Secondary(Class, ClassVtbl, Class);
-
- // and last, the virtual VTTs.
- VirtualVTTs(Class);
- }
-
- llvm::DenseMap<const CXXRecordDecl *, uint64_t> &getSubVTTIndicies() {
- return SubVTTIndicies;
- }
-};
-}
-
-llvm::GlobalVariable *
-CGVtableInfo::GenerateVTT(llvm::GlobalVariable::LinkageTypes Linkage,
- bool GenerateDefinition,
- const CXXRecordDecl *RD) {
- // Only classes that have virtual bases need a VTT.
- if (RD->getNumVBases() == 0)
- return 0;
-
- llvm::SmallString<256> OutName;
- CGM.getMangleContext().mangleCXXVTT(RD, OutName);
- llvm::StringRef Name = OutName.str();
-
- D1(printf("vtt %s\n", RD->getNameAsCString()));
-
- llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name);
- if (GV == 0 || GV->isDeclaration()) {
- const llvm::Type *Int8PtrTy =
- llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
-
- std::vector<llvm::Constant *> inits;
- VTTBuilder b(inits, RD, CGM, GenerateDefinition);
-
- const llvm::ArrayType *Type = llvm::ArrayType::get(Int8PtrTy, inits.size());
- llvm::Constant *Init = 0;
- if (GenerateDefinition)
- Init = llvm::ConstantArray::get(Type, inits);
-
- llvm::GlobalVariable *OldGV = GV;
- GV = new llvm::GlobalVariable(CGM.getModule(), Type, /*isConstant=*/true,
- Linkage, Init, Name);
- CGM.setGlobalVisibility(GV, RD);
-
- if (OldGV) {
- GV->takeName(OldGV);
- llvm::Constant *NewPtr =
- llvm::ConstantExpr::getBitCast(GV, OldGV->getType());
- OldGV->replaceAllUsesWith(NewPtr);
- OldGV->eraseFromParent();
- }
- }
-
- return GV;
-}
-
void CGVtableInfo::GenerateClassData(llvm::GlobalVariable::LinkageTypes Linkage,
const CXXRecordDecl *RD) {
llvm::GlobalVariable *&Vtable = Vtables[RD];
@@ -1510,25 +1243,6 @@ llvm::GlobalVariable *CGVtableInfo::getVtable(const CXXRecordDecl *RD) {
return Vtable;
}
-CGVtableInfo::CtorVtableInfo
-CGVtableInfo::getCtorVtable(const CXXRecordDecl *RD,
- const BaseSubobject &Base) {
- CtorVtableInfo Info;
-
- Info.Vtable = GenerateVtable(llvm::GlobalValue::InternalLinkage,
- /*GenerateDefinition=*/true,
- RD, Base.getBase(), Base.getBaseOffset(),
- Info.AddressPoints);
- return Info;
-}
-
-llvm::GlobalVariable *CGVtableInfo::getVTT(const CXXRecordDecl *RD) {
- return GenerateVTT(llvm::GlobalValue::ExternalLinkage,
- /*GenerateDefinition=*/false, RD);
-
-}
-
-
void CGVtableInfo::MaybeEmitVtable(GlobalDecl GD) {
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
const CXXRecordDecl *RD = MD->getParent();
@@ -1562,47 +1276,3 @@ void CGVtableInfo::MaybeEmitVtable(GlobalDecl GD) {
}
}
-bool CGVtableInfo::needsVTTParameter(GlobalDecl GD) {
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
-
- // We don't have any virtual bases, just return early.
- if (!MD->getParent()->getNumVBases())
- return false;
-
- // Check if we have a base constructor.
- if (isa<CXXConstructorDecl>(MD) && GD.getCtorType() == Ctor_Base)
- return true;
-
- // Check if we have a base destructor.
- if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() == Dtor_Base)
- return true;
-
- return false;
-}
-
-uint64_t CGVtableInfo::getSubVTTIndex(const CXXRecordDecl *RD,
- const CXXRecordDecl *Base) {
- ClassPairTy ClassPair(RD, Base);
-
- SubVTTIndiciesTy::iterator I =
- SubVTTIndicies.find(ClassPair);
- if (I != SubVTTIndicies.end())
- return I->second;
-
- std::vector<llvm::Constant *> inits;
- VTTBuilder Builder(inits, RD, CGM, /*GenerateDefinition=*/false);
-
- for (llvm::DenseMap<const CXXRecordDecl *, uint64_t>::iterator I =
- Builder.getSubVTTIndicies().begin(),
- E = Builder.getSubVTTIndicies().end(); I != E; ++I) {
- // Insert all indices.
- ClassPairTy ClassPair(RD, I->first);
-
- SubVTTIndicies.insert(std::make_pair(ClassPair, I->second));
- }
-
- I = SubVTTIndicies.find(ClassPair);
- assert(I != SubVTTIndicies.end() && "Did not find index!");
-
- return I->second;
-}
diff --git a/lib/CodeGen/CMakeLists.txt b/lib/CodeGen/CMakeLists.txt
index 45469d3..e72a1d9 100644
--- a/lib/CodeGen/CMakeLists.txt
+++ b/lib/CodeGen/CMakeLists.txt
@@ -24,6 +24,7 @@ add_clang_library(clangCodeGen
CGStmt.cpp
CGTemporaries.cpp
CGVtable.cpp
+ CGVTT.cpp
CodeGenFunction.cpp
CodeGenModule.cpp
CodeGenTypes.cpp
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 5ecc30e..cf504a7 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -67,6 +67,15 @@ CodeGenModule::~CodeGenModule() {
delete DebugInfo;
}
+void CodeGenModule::createObjCRuntime() {
+ if (!Features.NeXTRuntime)
+ Runtime = CreateGNUObjCRuntime(*this);
+ else if (Features.ObjCNonFragileABI)
+ Runtime = CreateMacNonFragileABIObjCRuntime(*this);
+ else
+ Runtime = CreateMacObjCRuntime(*this);
+}
+
void CodeGenModule::Release() {
EmitDeferred();
EmitCXXGlobalInitFunc();
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index c7aa7a4..81f3979 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -161,6 +161,9 @@ class CodeGenModule : public BlockModule {
/// strings. This value has type int * but is actually an Obj-C class pointer.
llvm::Constant *CFConstantStringClassRef;
+ /// Lazily create the Objective-C runtime
+ void createObjCRuntime();
+
llvm::LLVMContext &VMContext;
public:
CodeGenModule(ASTContext &C, const CodeGenOptions &CodeGenOpts,
@@ -174,7 +177,7 @@ public:
/// getObjCRuntime() - Return a reference to the configured
/// Objective-C runtime.
CGObjCRuntime &getObjCRuntime() {
- assert(Runtime && "No Objective-C runtime has been configured.");
+ if (!Runtime) createObjCRuntime();
return *Runtime;
}
diff --git a/lib/CodeGen/TargetABIInfo.cpp b/lib/CodeGen/TargetABIInfo.cpp
deleted file mode 100644
index 863a297..0000000
--- a/lib/CodeGen/TargetABIInfo.cpp
+++ /dev/null
@@ -1,1821 +0,0 @@
-//===---- TargetABIInfo.cpp - Encapsulate target ABI details ----*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// These classes wrap the information about a call or function
-// definition used to handle ABI compliancy.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ABIInfo.h"
-#include "CodeGenFunction.h"
-#include "clang/AST/RecordLayout.h"
-#include "llvm/Type.h"
-#include "llvm/ADT/Triple.h"
-#include "llvm/Support/raw_ostream.h"
-using namespace clang;
-using namespace CodeGen;
-
-ABIInfo::~ABIInfo() {}
-
-void ABIArgInfo::dump() const {
- llvm::raw_ostream &OS = llvm::errs();
- OS << "(ABIArgInfo Kind=";
- switch (TheKind) {
- case Direct:
- OS << "Direct";
- break;
- case Extend:
- OS << "Extend";
- break;
- case Ignore:
- OS << "Ignore";
- break;
- case Coerce:
- OS << "Coerce Type=";
- getCoerceToType()->print(OS);
- break;
- case Indirect:
- OS << "Indirect Align=" << getIndirectAlign();
- break;
- case Expand:
- OS << "Expand";
- break;
- }
- OS << ")\n";
-}
-
-static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays);
-
-/// isEmptyField - Return true iff a the field is "empty", that is it
-/// is an unnamed bit-field or an (array of) empty record(s).
-static bool isEmptyField(ASTContext &Context, const FieldDecl *FD,
- bool AllowArrays) {
- if (FD->isUnnamedBitfield())
- return true;
-
- QualType FT = FD->getType();
-
- // Constant arrays of empty records count as empty, strip them off.
- if (AllowArrays)
- while (const ConstantArrayType *AT = Context.getAsConstantArrayType(FT))
- FT = AT->getElementType();
-
- return isEmptyRecord(Context, FT, AllowArrays);
-}
-
-/// isEmptyRecord - Return true iff a structure contains only empty
-/// fields. Note that a structure with a flexible array member is not
-/// considered empty.
-static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays) {
- const RecordType *RT = T->getAs<RecordType>();
- if (!RT)
- return 0;
- const RecordDecl *RD = RT->getDecl();
- if (RD->hasFlexibleArrayMember())
- return false;
- for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
- i != e; ++i)
- if (!isEmptyField(Context, *i, AllowArrays))
- return false;
- return true;
-}
-
-/// hasNonTrivialDestructorOrCopyConstructor - Determine if a type has either
-/// a non-trivial destructor or a non-trivial copy constructor.
-static bool hasNonTrivialDestructorOrCopyConstructor(const RecordType *RT) {
- const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl());
- if (!RD)
- return false;
-
- return !RD->hasTrivialDestructor() || !RD->hasTrivialCopyConstructor();
-}
-
-/// isRecordWithNonTrivialDestructorOrCopyConstructor - Determine if a type is
-/// a record type with either a non-trivial destructor or a non-trivial copy
-/// constructor.
-static bool isRecordWithNonTrivialDestructorOrCopyConstructor(QualType T) {
- const RecordType *RT = T->getAs<RecordType>();
- if (!RT)
- return false;
-
- return hasNonTrivialDestructorOrCopyConstructor(RT);
-}
-
-/// isSingleElementStruct - Determine if a structure is a "single
-/// element struct", i.e. it has exactly one non-empty field or
-/// exactly one field which is itself a single element
-/// struct. Structures with flexible array members are never
-/// considered single element structs.
-///
-/// \return The field declaration for the single non-empty field, if
-/// it exists.
-static const Type *isSingleElementStruct(QualType T, ASTContext &Context) {
- const RecordType *RT = T->getAsStructureType();
- if (!RT)
- return 0;
-
- const RecordDecl *RD = RT->getDecl();
- if (RD->hasFlexibleArrayMember())
- return 0;
-
- const Type *Found = 0;
- for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
- i != e; ++i) {
- const FieldDecl *FD = *i;
- QualType FT = FD->getType();
-
- // Ignore empty fields.
- if (isEmptyField(Context, FD, true))
- continue;
-
- // If we already found an element then this isn't a single-element
- // struct.
- if (Found)
- return 0;
-
- // Treat single element arrays as the element.
- while (const ConstantArrayType *AT = Context.getAsConstantArrayType(FT)) {
- if (AT->getSize().getZExtValue() != 1)
- break;
- FT = AT->getElementType();
- }
-
- if (!CodeGenFunction::hasAggregateLLVMType(FT)) {
- Found = FT.getTypePtr();
- } else {
- Found = isSingleElementStruct(FT, Context);
- if (!Found)
- return 0;
- }
- }
-
- return Found;
-}
-
-static bool is32Or64BitBasicType(QualType Ty, ASTContext &Context) {
- if (!Ty->getAs<BuiltinType>() && !Ty->isAnyPointerType() &&
- !Ty->isAnyComplexType() && !Ty->isEnumeralType() &&
- !Ty->isBlockPointerType())
- return false;
-
- uint64_t Size = Context.getTypeSize(Ty);
- return Size == 32 || Size == 64;
-}
-
-/// canExpandIndirectArgument - Test whether an argument type which is to be
-/// passed indirectly (on the stack) would have the equivalent layout if it was
-/// expanded into separate arguments. If so, we prefer to do the latter to avoid
-/// inhibiting optimizations.
-///
-// FIXME: This predicate is missing many cases, currently it just follows
-// llvm-gcc (checks that all fields are 32-bit or 64-bit primitive types). We
-// should probably make this smarter, or better yet make the LLVM backend
-// capable of handling it.
-static bool canExpandIndirectArgument(QualType Ty, ASTContext &Context) {
- // We can only expand structure types.
- const RecordType *RT = Ty->getAs<RecordType>();
- if (!RT)
- return false;
-
- // We can only expand (C) structures.
- //
- // FIXME: This needs to be generalized to handle classes as well.
- const RecordDecl *RD = RT->getDecl();
- if (!RD->isStruct() || isa<CXXRecordDecl>(RD))
- return false;
-
- for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
- i != e; ++i) {
- const FieldDecl *FD = *i;
-
- if (!is32Or64BitBasicType(FD->getType(), Context))
- return false;
-
- // FIXME: Reject bit-fields wholesale; there are two problems, we don't know
- // how to expand them yet, and the predicate for telling if a bitfield still
- // counts as "basic" is more complicated than what we were doing previously.
- if (FD->isBitField())
- return false;
- }
-
- return true;
-}
-
-static bool typeContainsSSEVector(const RecordDecl *RD, ASTContext &Context) {
- for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
- i != e; ++i) {
- const FieldDecl *FD = *i;
-
- if (FD->getType()->isVectorType() &&
- Context.getTypeSize(FD->getType()) >= 128)
- return true;
-
- if (const RecordType* RT = FD->getType()->getAs<RecordType>())
- if (typeContainsSSEVector(RT->getDecl(), Context))
- return true;
- }
-
- return false;
-}
-
-namespace {
-/// DefaultABIInfo - The default implementation for ABI specific
-/// details. This implementation provides information which results in
-/// self-consistent and sensible LLVM IR generation, but does not
-/// conform to any particular ABI.
-class DefaultABIInfo : public ABIInfo {
- ABIArgInfo classifyReturnType(QualType RetTy,
- ASTContext &Context,
- llvm::LLVMContext &VMContext) const;
-
- ABIArgInfo classifyArgumentType(QualType RetTy,
- ASTContext &Context,
- llvm::LLVMContext &VMContext) const;
-
- virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context,
- llvm::LLVMContext &VMContext) const {
- FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), Context,
- VMContext);
- for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
- it != ie; ++it)
- it->info = classifyArgumentType(it->type, Context, VMContext);
- }
-
- virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
- CodeGenFunction &CGF) const;
-};
-
-/// X86_32ABIInfo - The X86-32 ABI information.
-class X86_32ABIInfo : public ABIInfo {
- ASTContext &Context;
- bool IsDarwinVectorABI;
- bool IsSmallStructInRegABI;
-
- static bool isRegisterSize(unsigned Size) {
- return (Size == 8 || Size == 16 || Size == 32 || Size == 64);
- }
-
- static bool shouldReturnTypeInRegister(QualType Ty, ASTContext &Context);
-
- static unsigned getIndirectArgumentAlignment(QualType Ty,
- ASTContext &Context);
-
-public:
- ABIArgInfo classifyReturnType(QualType RetTy,
- ASTContext &Context,
- llvm::LLVMContext &VMContext) const;
-
- ABIArgInfo classifyArgumentType(QualType RetTy,
- ASTContext &Context,
- llvm::LLVMContext &VMContext) const;
-
- virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context,
- llvm::LLVMContext &VMContext) const {
- FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), Context,
- VMContext);
- for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
- it != ie; ++it)
- it->info = classifyArgumentType(it->type, Context, VMContext);
- }
-
- virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
- CodeGenFunction &CGF) const;
-
- X86_32ABIInfo(ASTContext &Context, bool d, bool p)
- : ABIInfo(), Context(Context), IsDarwinVectorABI(d),
- IsSmallStructInRegABI(p) {}
-};
-}
-
-
-/// shouldReturnTypeInRegister - Determine if the given type should be
-/// passed in a register (for the Darwin ABI).
-bool X86_32ABIInfo::shouldReturnTypeInRegister(QualType Ty,
- ASTContext &Context) {
- uint64_t Size = Context.getTypeSize(Ty);
-
- // Type must be register sized.
- if (!isRegisterSize(Size))
- return false;
-
- if (Ty->isVectorType()) {
- // 64- and 128- bit vectors inside structures are not returned in
- // registers.
- if (Size == 64 || Size == 128)
- return false;
-
- return true;
- }
-
- // If this is a builtin, pointer, enum, or complex type, it is ok.
- if (Ty->getAs<BuiltinType>() || Ty->isAnyPointerType() ||
- Ty->isAnyComplexType() || Ty->isEnumeralType() ||
- Ty->isBlockPointerType())
- return true;
-
- // Arrays are treated like records.
- if (const ConstantArrayType *AT = Context.getAsConstantArrayType(Ty))
- return shouldReturnTypeInRegister(AT->getElementType(), Context);
-
- // Otherwise, it must be a record type.
- const RecordType *RT = Ty->getAs<RecordType>();
- if (!RT) return false;
-
- // Structure types are passed in register if all fields would be
- // passed in a register.
- for (RecordDecl::field_iterator i = RT->getDecl()->field_begin(),
- e = RT->getDecl()->field_end(); i != e; ++i) {
- const FieldDecl *FD = *i;
-
- // Empty fields are ignored.
- if (isEmptyField(Context, FD, true))
- continue;
-
- // Check fields recursively.
- if (!shouldReturnTypeInRegister(FD->getType(), Context))
- return false;
- }
-
- return true;
-}
-
-ABIArgInfo X86_32ABIInfo::classifyReturnType(QualType RetTy,
- ASTContext &Context,
- llvm::LLVMContext &VMContext) const {
- if (RetTy->isVoidType()) {
- return ABIArgInfo::getIgnore();
- } else if (const VectorType *VT = RetTy->getAs<VectorType>()) {
- // On Darwin, some vectors are returned in registers.
- if (IsDarwinVectorABI) {
- uint64_t Size = Context.getTypeSize(RetTy);
-
- // 128-bit vectors are a special case; they are returned in
- // registers and we need to make sure to pick a type the LLVM
- // backend will like.
- if (Size == 128)
- return ABIArgInfo::getCoerce(llvm::VectorType::get(
- llvm::Type::getInt64Ty(VMContext), 2));
-
- // Always return in register if it fits in a general purpose
- // register, or if it is 64 bits and has a single element.
- if ((Size == 8 || Size == 16 || Size == 32) ||
- (Size == 64 && VT->getNumElements() == 1))
- return ABIArgInfo::getCoerce(llvm::IntegerType::get(VMContext, Size));
-
- return ABIArgInfo::getIndirect(0);
- }
-
- return ABIArgInfo::getDirect();
- } else if (CodeGenFunction::hasAggregateLLVMType(RetTy)) {
- if (const RecordType *RT = RetTy->getAsStructureType()) {
- // Structures with either a non-trivial destructor or a non-trivial
- // copy constructor are always indirect.
- if (hasNonTrivialDestructorOrCopyConstructor(RT))
- return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
-
- // Structures with flexible arrays are always indirect.
- if (RT->getDecl()->hasFlexibleArrayMember())
- return ABIArgInfo::getIndirect(0);
- }
-
- // If specified, structs and unions are always indirect.
- if (!IsSmallStructInRegABI && !RetTy->isAnyComplexType())
- return ABIArgInfo::getIndirect(0);
-
- // Classify "single element" structs as their element type.
- if (const Type *SeltTy = isSingleElementStruct(RetTy, Context)) {
- if (const BuiltinType *BT = SeltTy->getAs<BuiltinType>()) {
- if (BT->isIntegerType()) {
- // We need to use the size of the structure, padding
- // bit-fields can adjust that to be larger than the single
- // element type.
- uint64_t Size = Context.getTypeSize(RetTy);
- return ABIArgInfo::getCoerce(
- llvm::IntegerType::get(VMContext, (unsigned) Size));
- } else if (BT->getKind() == BuiltinType::Float) {
- assert(Context.getTypeSize(RetTy) == Context.getTypeSize(SeltTy) &&
- "Unexpect single element structure size!");
- return ABIArgInfo::getCoerce(llvm::Type::getFloatTy(VMContext));
- } else if (BT->getKind() == BuiltinType::Double) {
- assert(Context.getTypeSize(RetTy) == Context.getTypeSize(SeltTy) &&
- "Unexpect single element structure size!");
- return ABIArgInfo::getCoerce(llvm::Type::getDoubleTy(VMContext));
- }
- } else if (SeltTy->isPointerType()) {
- // FIXME: It would be really nice if this could come out as the proper
- // pointer type.
- const llvm::Type *PtrTy = llvm::Type::getInt8PtrTy(VMContext);
- return ABIArgInfo::getCoerce(PtrTy);
- } else if (SeltTy->isVectorType()) {
- // 64- and 128-bit vectors are never returned in a
- // register when inside a structure.
- uint64_t Size = Context.getTypeSize(RetTy);
- if (Size == 64 || Size == 128)
- return ABIArgInfo::getIndirect(0);
-
- return classifyReturnType(QualType(SeltTy, 0), Context, VMContext);
- }
- }
-
- // Small structures which are register sized are generally returned
- // in a register.
- if (X86_32ABIInfo::shouldReturnTypeInRegister(RetTy, Context)) {
- uint64_t Size = Context.getTypeSize(RetTy);
- return ABIArgInfo::getCoerce(llvm::IntegerType::get(VMContext, Size));
- }
-
- return ABIArgInfo::getIndirect(0);
- } else {
- return (RetTy->isPromotableIntegerType() ?
- ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
- }
-}
-
-unsigned X86_32ABIInfo::getIndirectArgumentAlignment(QualType Ty,
- ASTContext &Context) {
- unsigned Align = Context.getTypeAlign(Ty);
- if (Align < 128) return 0;
- if (const RecordType* RT = Ty->getAs<RecordType>())
- if (typeContainsSSEVector(RT->getDecl(), Context))
- return 16;
- return 0;
-}
-
-ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
- ASTContext &Context,
- llvm::LLVMContext &VMContext) const {
- // FIXME: Set alignment on indirect arguments.
- if (CodeGenFunction::hasAggregateLLVMType(Ty)) {
- // Structures with flexible arrays are always indirect.
- if (const RecordType *RT = Ty->getAsStructureType())
- if (RT->getDecl()->hasFlexibleArrayMember())
- return ABIArgInfo::getIndirect(getIndirectArgumentAlignment(Ty,
- Context));
-
- // Ignore empty structs.
- if (Ty->isStructureType() && Context.getTypeSize(Ty) == 0)
- return ABIArgInfo::getIgnore();
-
- // Expand small (<= 128-bit) record types when we know that the stack layout
- // of those arguments will match the struct. This is important because the
- // LLVM backend isn't smart enough to remove byval, which inhibits many
- // optimizations.
- if (Context.getTypeSize(Ty) <= 4*32 &&
- canExpandIndirectArgument(Ty, Context))
- return ABIArgInfo::getExpand();
-
- return ABIArgInfo::getIndirect(getIndirectArgumentAlignment(Ty, Context));
- } else {
- return (Ty->isPromotableIntegerType() ?
- ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
- }
-}
-
-llvm::Value *X86_32ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
- CodeGenFunction &CGF) const {
- const llvm::Type *BP = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
- const llvm::Type *BPP = llvm::PointerType::getUnqual(BP);
-
- CGBuilderTy &Builder = CGF.Builder;
- llvm::Value *VAListAddrAsBPP = Builder.CreateBitCast(VAListAddr, BPP,
- "ap");
- llvm::Value *Addr = Builder.CreateLoad(VAListAddrAsBPP, "ap.cur");
- llvm::Type *PTy =
- llvm::PointerType::getUnqual(CGF.ConvertType(Ty));
- llvm::Value *AddrTyped = Builder.CreateBitCast(Addr, PTy);
-
- uint64_t Offset =
- llvm::RoundUpToAlignment(CGF.getContext().getTypeSize(Ty) / 8, 4);
- llvm::Value *NextAddr =
- Builder.CreateGEP(Addr, llvm::ConstantInt::get(
- llvm::Type::getInt32Ty(CGF.getLLVMContext()), Offset),
- "ap.next");
- Builder.CreateStore(NextAddr, VAListAddrAsBPP);
-
- return AddrTyped;
-}
-
-namespace {
-/// X86_64ABIInfo - The X86_64 ABI information.
-class X86_64ABIInfo : public ABIInfo {
- enum Class {
- Integer = 0,
- SSE,
- SSEUp,
- X87,
- X87Up,
- ComplexX87,
- NoClass,
- Memory
- };
-
- /// merge - Implement the X86_64 ABI merging algorithm.
- ///
- /// Merge an accumulating classification \arg Accum with a field
- /// classification \arg Field.
- ///
- /// \param Accum - The accumulating classification. This should
- /// always be either NoClass or the result of a previous merge
- /// call. In addition, this should never be Memory (the caller
- /// should just return Memory for the aggregate).
- Class merge(Class Accum, Class Field) const;
-
- /// classify - Determine the x86_64 register classes in which the
- /// given type T should be passed.
- ///
- /// \param Lo - The classification for the parts of the type
- /// residing in the low word of the containing object.
- ///
- /// \param Hi - The classification for the parts of the type
- /// residing in the high word of the containing object.
- ///
- /// \param OffsetBase - The bit offset of this type in the
- /// containing object. Some parameters are classified different
- /// depending on whether they straddle an eightbyte boundary.
- ///
- /// If a word is unused its result will be NoClass; if a type should
- /// be passed in Memory then at least the classification of \arg Lo
- /// will be Memory.
- ///
- /// The \arg Lo class will be NoClass iff the argument is ignored.
- ///
- /// If the \arg Lo class is ComplexX87, then the \arg Hi class will
- /// also be ComplexX87.
- void classify(QualType T, ASTContext &Context, uint64_t OffsetBase,
- Class &Lo, Class &Hi) const;
-
- /// getCoerceResult - Given a source type \arg Ty and an LLVM type
- /// to coerce to, chose the best way to pass Ty in the same place
- /// that \arg CoerceTo would be passed, but while keeping the
- /// emitted code as simple as possible.
- ///
- /// FIXME: Note, this should be cleaned up to just take an enumeration of all
- /// the ways we might want to pass things, instead of constructing an LLVM
- /// type. This makes this code more explicit, and it makes it clearer that we
- /// are also doing this for correctness in the case of passing scalar types.
- ABIArgInfo getCoerceResult(QualType Ty,
- const llvm::Type *CoerceTo,
- ASTContext &Context) const;
-
- /// getIndirectResult - Give a source type \arg Ty, return a suitable result
- /// such that the argument will be passed in memory.
- ABIArgInfo getIndirectResult(QualType Ty,
- ASTContext &Context) const;
-
- ABIArgInfo classifyReturnType(QualType RetTy,
- ASTContext &Context,
- llvm::LLVMContext &VMContext) const;
-
- ABIArgInfo classifyArgumentType(QualType Ty,
- ASTContext &Context,
- llvm::LLVMContext &VMContext,
- unsigned &neededInt,
- unsigned &neededSSE) const;
-
-public:
- virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context,
- llvm::LLVMContext &VMContext) const;
-
- virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
- CodeGenFunction &CGF) const;
-};
-}
-
-X86_64ABIInfo::Class X86_64ABIInfo::merge(Class Accum,
- Class Field) const {
- // AMD64-ABI 3.2.3p2: Rule 4. Each field of an object is
- // classified recursively so that always two fields are
- // considered. The resulting class is calculated according to
- // the classes of the fields in the eightbyte:
- //
- // (a) If both classes are equal, this is the resulting class.
- //
- // (b) If one of the classes is NO_CLASS, the resulting class is
- // the other class.
- //
- // (c) If one of the classes is MEMORY, the result is the MEMORY
- // class.
- //
- // (d) If one of the classes is INTEGER, the result is the
- // INTEGER.
- //
- // (e) If one of the classes is X87, X87UP, COMPLEX_X87 class,
- // MEMORY is used as class.
- //
- // (f) Otherwise class SSE is used.
-
- // Accum should never be memory (we should have returned) or
- // ComplexX87 (because this cannot be passed in a structure).
- assert((Accum != Memory && Accum != ComplexX87) &&
- "Invalid accumulated classification during merge.");
- if (Accum == Field || Field == NoClass)
- return Accum;
- else if (Field == Memory)
- return Memory;
- else if (Accum == NoClass)
- return Field;
- else if (Accum == Integer || Field == Integer)
- return Integer;
- else if (Field == X87 || Field == X87Up || Field == ComplexX87 ||
- Accum == X87 || Accum == X87Up)
- return Memory;
- else
- return SSE;
-}
-
-void X86_64ABIInfo::classify(QualType Ty,
- ASTContext &Context,
- uint64_t OffsetBase,
- Class &Lo, Class &Hi) const {
- // FIXME: This code can be simplified by introducing a simple value class for
- // Class pairs with appropriate constructor methods for the various
- // situations.
-
- // FIXME: Some of the split computations are wrong; unaligned vectors
- // shouldn't be passed in registers for example, so there is no chance they
- // can straddle an eightbyte. Verify & simplify.
-
- Lo = Hi = NoClass;
-
- Class &Current = OffsetBase < 64 ? Lo : Hi;
- Current = Memory;
-
- if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) {
- BuiltinType::Kind k = BT->getKind();
-
- if (k == BuiltinType::Void) {
- Current = NoClass;
- } else if (k == BuiltinType::Int128 || k == BuiltinType::UInt128) {
- Lo = Integer;
- Hi = Integer;
- } else if (k >= BuiltinType::Bool && k <= BuiltinType::LongLong) {
- Current = Integer;
- } else if (k == BuiltinType::Float || k == BuiltinType::Double) {
- Current = SSE;
- } else if (k == BuiltinType::LongDouble) {
- Lo = X87;
- Hi = X87Up;
- }
- // FIXME: _Decimal32 and _Decimal64 are SSE.
- // FIXME: _float128 and _Decimal128 are (SSE, SSEUp).
- } else if (const EnumType *ET = Ty->getAs<EnumType>()) {
- // Classify the underlying integer type.
- classify(ET->getDecl()->getIntegerType(), Context, OffsetBase, Lo, Hi);
- } else if (Ty->hasPointerRepresentation()) {
- Current = Integer;
- } else if (const VectorType *VT = Ty->getAs<VectorType>()) {
- uint64_t Size = Context.getTypeSize(VT);
- if (Size == 32) {
- // gcc passes all <4 x char>, <2 x short>, <1 x int>, <1 x
- // float> as integer.
- Current = Integer;
-
- // If this type crosses an eightbyte boundary, it should be
- // split.
- uint64_t EB_Real = (OffsetBase) / 64;
- uint64_t EB_Imag = (OffsetBase + Size - 1) / 64;
- if (EB_Real != EB_Imag)
- Hi = Lo;
- } else if (Size == 64) {
- // gcc passes <1 x double> in memory. :(
- if (VT->getElementType()->isSpecificBuiltinType(BuiltinType::Double))
- return;
-
- // gcc passes <1 x long long> as INTEGER.
- if (VT->getElementType()->isSpecificBuiltinType(BuiltinType::LongLong))
- Current = Integer;
- else
- Current = SSE;
-
- // If this type crosses an eightbyte boundary, it should be
- // split.
- if (OffsetBase && OffsetBase != 64)
- Hi = Lo;
- } else if (Size == 128) {
- Lo = SSE;
- Hi = SSEUp;
- }
- } else if (const ComplexType *CT = Ty->getAs<ComplexType>()) {
- QualType ET = Context.getCanonicalType(CT->getElementType());
-
- uint64_t Size = Context.getTypeSize(Ty);
- if (ET->isIntegralType()) {
- if (Size <= 64)
- Current = Integer;
- else if (Size <= 128)
- Lo = Hi = Integer;
- } else if (ET == Context.FloatTy)
- Current = SSE;
- else if (ET == Context.DoubleTy)
- Lo = Hi = SSE;
- else if (ET == Context.LongDoubleTy)
- Current = ComplexX87;
-
- // If this complex type crosses an eightbyte boundary then it
- // should be split.
- uint64_t EB_Real = (OffsetBase) / 64;
- uint64_t EB_Imag = (OffsetBase + Context.getTypeSize(ET)) / 64;
- if (Hi == NoClass && EB_Real != EB_Imag)
- Hi = Lo;
- } else if (const ConstantArrayType *AT = Context.getAsConstantArrayType(Ty)) {
- // Arrays are treated like structures.
-
- uint64_t Size = Context.getTypeSize(Ty);
-
- // AMD64-ABI 3.2.3p2: Rule 1. If the size of an object is larger
- // than two eightbytes, ..., it has class MEMORY.
- if (Size > 128)
- return;
-
- // AMD64-ABI 3.2.3p2: Rule 1. If ..., or it contains unaligned
- // fields, it has class MEMORY.
- //
- // Only need to check alignment of array base.
- if (OffsetBase % Context.getTypeAlign(AT->getElementType()))
- return;
-
- // Otherwise implement simplified merge. We could be smarter about
- // this, but it isn't worth it and would be harder to verify.
- Current = NoClass;
- uint64_t EltSize = Context.getTypeSize(AT->getElementType());
- uint64_t ArraySize = AT->getSize().getZExtValue();
- for (uint64_t i=0, Offset=OffsetBase; i<ArraySize; ++i, Offset += EltSize) {
- Class FieldLo, FieldHi;
- classify(AT->getElementType(), Context, Offset, FieldLo, FieldHi);
- Lo = merge(Lo, FieldLo);
- Hi = merge(Hi, FieldHi);
- if (Lo == Memory || Hi == Memory)
- break;
- }
-
- // Do post merger cleanup (see below). Only case we worry about is Memory.
- if (Hi == Memory)
- Lo = Memory;
- assert((Hi != SSEUp || Lo == SSE) && "Invalid SSEUp array classification.");
- } else if (const RecordType *RT = Ty->getAs<RecordType>()) {
- uint64_t Size = Context.getTypeSize(Ty);
-
- // AMD64-ABI 3.2.3p2: Rule 1. If the size of an object is larger
- // than two eightbytes, ..., it has class MEMORY.
- if (Size > 128)
- return;
-
- // AMD64-ABI 3.2.3p2: Rule 2. If a C++ object has either a non-trivial
- // copy constructor or a non-trivial destructor, it is passed by invisible
- // reference.
- if (hasNonTrivialDestructorOrCopyConstructor(RT))
- return;
-
- const RecordDecl *RD = RT->getDecl();
-
- // Assume variable sized types are passed in memory.
- if (RD->hasFlexibleArrayMember())
- return;
-
- const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
-
- // Reset Lo class, this will be recomputed.
- Current = NoClass;
-
- // If this is a C++ record, classify the bases first.
- if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
- for (CXXRecordDecl::base_class_const_iterator i = CXXRD->bases_begin(),
- e = CXXRD->bases_end(); i != e; ++i) {
- assert(!i->isVirtual() && !i->getType()->isDependentType() &&
- "Unexpected base class!");
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
-
- // Classify this field.
- //
- // AMD64-ABI 3.2.3p2: Rule 3. If the size of the aggregate exceeds a
- // single eightbyte, each is classified separately. Each eightbyte gets
- // initialized to class NO_CLASS.
- Class FieldLo, FieldHi;
- uint64_t Offset = OffsetBase + Layout.getBaseClassOffset(Base);
- classify(i->getType(), Context, Offset, FieldLo, FieldHi);
- Lo = merge(Lo, FieldLo);
- Hi = merge(Hi, FieldHi);
- if (Lo == Memory || Hi == Memory)
- break;
- }
-
- // If this record has no fields but isn't empty, classify as INTEGER.
- if (RD->field_empty() && Size)
- Current = Integer;
- }
-
- // Classify the fields one at a time, merging the results.
- unsigned idx = 0;
- for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
- i != e; ++i, ++idx) {
- uint64_t Offset = OffsetBase + Layout.getFieldOffset(idx);
- bool BitField = i->isBitField();
-
- // AMD64-ABI 3.2.3p2: Rule 1. If ..., or it contains unaligned
- // fields, it has class MEMORY.
- //
- // Note, skip this test for bit-fields, see below.
- if (!BitField && Offset % Context.getTypeAlign(i->getType())) {
- Lo = Memory;
- return;
- }
-
- // Classify this field.
- //
- // AMD64-ABI 3.2.3p2: Rule 3. If the size of the aggregate
- // exceeds a single eightbyte, each is classified
- // separately. Each eightbyte gets initialized to class
- // NO_CLASS.
- Class FieldLo, FieldHi;
-
- // Bit-fields require special handling, they do not force the
- // structure to be passed in memory even if unaligned, and
- // therefore they can straddle an eightbyte.
- if (BitField) {
- // Ignore padding bit-fields.
- if (i->isUnnamedBitfield())
- continue;
-
- uint64_t Offset = OffsetBase + Layout.getFieldOffset(idx);
- uint64_t Size = i->getBitWidth()->EvaluateAsInt(Context).getZExtValue();
-
- uint64_t EB_Lo = Offset / 64;
- uint64_t EB_Hi = (Offset + Size - 1) / 64;
- FieldLo = FieldHi = NoClass;
- if (EB_Lo) {
- assert(EB_Hi == EB_Lo && "Invalid classification, type > 16 bytes.");
- FieldLo = NoClass;
- FieldHi = Integer;
- } else {
- FieldLo = Integer;
- FieldHi = EB_Hi ? Integer : NoClass;
- }
- } else
- classify(i->getType(), Context, Offset, FieldLo, FieldHi);
- Lo = merge(Lo, FieldLo);
- Hi = merge(Hi, FieldHi);
- if (Lo == Memory || Hi == Memory)
- break;
- }
-
- // AMD64-ABI 3.2.3p2: Rule 5. Then a post merger cleanup is done:
- //
- // (a) If one of the classes is MEMORY, the whole argument is
- // passed in memory.
- //
- // (b) If SSEUP is not preceeded by SSE, it is converted to SSE.
-
- // The first of these conditions is guaranteed by how we implement
- // the merge (just bail).
- //
- // The second condition occurs in the case of unions; for example
- // union { _Complex double; unsigned; }.
- if (Hi == Memory)
- Lo = Memory;
- if (Hi == SSEUp && Lo != SSE)
- Hi = SSE;
- }
-}
-
-ABIArgInfo X86_64ABIInfo::getCoerceResult(QualType Ty,
- const llvm::Type *CoerceTo,
- ASTContext &Context) const {
- if (CoerceTo == llvm::Type::getInt64Ty(CoerceTo->getContext())) {
- // Integer and pointer types will end up in a general purpose
- // register.
- if (Ty->isIntegralType() || Ty->hasPointerRepresentation())
- return (Ty->isPromotableIntegerType() ?
- ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
- } else if (CoerceTo == llvm::Type::getDoubleTy(CoerceTo->getContext())) {
- // FIXME: It would probably be better to make CGFunctionInfo only map using
- // canonical types than to canonize here.
- QualType CTy = Context.getCanonicalType(Ty);
-
- // Float and double end up in a single SSE reg.
- if (CTy == Context.FloatTy || CTy == Context.DoubleTy)
- return ABIArgInfo::getDirect();
-
- }
-
- return ABIArgInfo::getCoerce(CoerceTo);
-}
-
-ABIArgInfo X86_64ABIInfo::getIndirectResult(QualType Ty,
- ASTContext &Context) const {
- // If this is a scalar LLVM value then assume LLVM will pass it in the right
- // place naturally.
- if (!CodeGenFunction::hasAggregateLLVMType(Ty))
- return (Ty->isPromotableIntegerType() ?
- ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
-
- bool ByVal = !isRecordWithNonTrivialDestructorOrCopyConstructor(Ty);
-
- // FIXME: Set alignment correctly.
- return ABIArgInfo::getIndirect(0, ByVal);
-}
-
-ABIArgInfo X86_64ABIInfo::classifyReturnType(QualType RetTy,
- ASTContext &Context,
- llvm::LLVMContext &VMContext) const {
- // AMD64-ABI 3.2.3p4: Rule 1. Classify the return type with the
- // classification algorithm.
- X86_64ABIInfo::Class Lo, Hi;
- classify(RetTy, Context, 0, Lo, Hi);
-
- // Check some invariants.
- assert((Hi != Memory || Lo == Memory) && "Invalid memory classification.");
- assert((Lo != NoClass || Hi == NoClass) && "Invalid null classification.");
- assert((Hi != SSEUp || Lo == SSE) && "Invalid SSEUp classification.");
-
- const llvm::Type *ResType = 0;
- switch (Lo) {
- case NoClass:
- return ABIArgInfo::getIgnore();
-
- case SSEUp:
- case X87Up:
- assert(0 && "Invalid classification for lo word.");
-
- // AMD64-ABI 3.2.3p4: Rule 2. Types of class memory are returned via
- // hidden argument.
- case Memory:
- return getIndirectResult(RetTy, Context);
-
- // AMD64-ABI 3.2.3p4: Rule 3. If the class is INTEGER, the next
- // available register of the sequence %rax, %rdx is used.
- case Integer:
- ResType = llvm::Type::getInt64Ty(VMContext); break;
-
- // AMD64-ABI 3.2.3p4: Rule 4. If the class is SSE, the next
- // available SSE register of the sequence %xmm0, %xmm1 is used.
- case SSE:
- ResType = llvm::Type::getDoubleTy(VMContext); break;
-
- // AMD64-ABI 3.2.3p4: Rule 6. If the class is X87, the value is
- // returned on the X87 stack in %st0 as 80-bit x87 number.
- case X87:
- ResType = llvm::Type::getX86_FP80Ty(VMContext); break;
-
- // AMD64-ABI 3.2.3p4: Rule 8. If the class is COMPLEX_X87, the real
- // part of the value is returned in %st0 and the imaginary part in
- // %st1.
- case ComplexX87:
- assert(Hi == ComplexX87 && "Unexpected ComplexX87 classification.");
- ResType = llvm::StructType::get(VMContext, llvm::Type::getX86_FP80Ty(VMContext),
- llvm::Type::getX86_FP80Ty(VMContext),
- NULL);
- break;
- }
-
- switch (Hi) {
- // Memory was handled previously and X87 should
- // never occur as a hi class.
- case Memory:
- case X87:
- assert(0 && "Invalid classification for hi word.");
-
- case ComplexX87: // Previously handled.
- case NoClass: break;
-
- case Integer:
- ResType = llvm::StructType::get(VMContext, ResType,
- llvm::Type::getInt64Ty(VMContext), NULL);
- break;
- case SSE:
- ResType = llvm::StructType::get(VMContext, ResType,
- llvm::Type::getDoubleTy(VMContext), NULL);
- break;
-
- // AMD64-ABI 3.2.3p4: Rule 5. If the class is SSEUP, the eightbyte
- // is passed in the upper half of the last used SSE register.
- //
- // SSEUP should always be preceeded by SSE, just widen.
- case SSEUp:
- assert(Lo == SSE && "Unexpected SSEUp classification.");
- ResType = llvm::VectorType::get(llvm::Type::getDoubleTy(VMContext), 2);
- break;
-
- // AMD64-ABI 3.2.3p4: Rule 7. If the class is X87UP, the value is
- // returned together with the previous X87 value in %st0.
- case X87Up:
- // If X87Up is preceeded by X87, we don't need to do
- // anything. However, in some cases with unions it may not be
- // preceeded by X87. In such situations we follow gcc and pass the
- // extra bits in an SSE reg.
- if (Lo != X87)
- ResType = llvm::StructType::get(VMContext, ResType,
- llvm::Type::getDoubleTy(VMContext), NULL);
- break;
- }
-
- return getCoerceResult(RetTy, ResType, Context);
-}
-
-ABIArgInfo X86_64ABIInfo::classifyArgumentType(QualType Ty, ASTContext &Context,
- llvm::LLVMContext &VMContext,
- unsigned &neededInt,
- unsigned &neededSSE) const {
- X86_64ABIInfo::Class Lo, Hi;
- classify(Ty, Context, 0, Lo, Hi);
-
- // Check some invariants.
- // FIXME: Enforce these by construction.
- assert((Hi != Memory || Lo == Memory) && "Invalid memory classification.");
- assert((Lo != NoClass || Hi == NoClass) && "Invalid null classification.");
- assert((Hi != SSEUp || Lo == SSE) && "Invalid SSEUp classification.");
-
- neededInt = 0;
- neededSSE = 0;
- const llvm::Type *ResType = 0;
- switch (Lo) {
- case NoClass:
- return ABIArgInfo::getIgnore();
-
- // AMD64-ABI 3.2.3p3: Rule 1. If the class is MEMORY, pass the argument
- // on the stack.
- case Memory:
-
- // AMD64-ABI 3.2.3p3: Rule 5. If the class is X87, X87UP or
- // COMPLEX_X87, it is passed in memory.
- case X87:
- case ComplexX87:
- return getIndirectResult(Ty, Context);
-
- case SSEUp:
- case X87Up:
- assert(0 && "Invalid classification for lo word.");
-
- // AMD64-ABI 3.2.3p3: Rule 2. If the class is INTEGER, the next
- // available register of the sequence %rdi, %rsi, %rdx, %rcx, %r8
- // and %r9 is used.
- case Integer:
- ++neededInt;
- ResType = llvm::Type::getInt64Ty(VMContext);
- break;
-
- // AMD64-ABI 3.2.3p3: Rule 3. If the class is SSE, the next
- // available SSE register is used, the registers are taken in the
- // order from %xmm0 to %xmm7.
- case SSE:
- ++neededSSE;
- ResType = llvm::Type::getDoubleTy(VMContext);
- break;
- }
-
- switch (Hi) {
- // Memory was handled previously, ComplexX87 and X87 should
- // never occur as hi classes, and X87Up must be preceed by X87,
- // which is passed in memory.
- case Memory:
- case X87:
- case ComplexX87:
- assert(0 && "Invalid classification for hi word.");
- break;
-
- case NoClass: break;
- case Integer:
- ResType = llvm::StructType::get(VMContext, ResType,
- llvm::Type::getInt64Ty(VMContext), NULL);
- ++neededInt;
- break;
-
- // X87Up generally doesn't occur here (long double is passed in
- // memory), except in situations involving unions.
- case X87Up:
- case SSE:
- ResType = llvm::StructType::get(VMContext, ResType,
- llvm::Type::getDoubleTy(VMContext), NULL);
- ++neededSSE;
- break;
-
- // AMD64-ABI 3.2.3p3: Rule 4. If the class is SSEUP, the
- // eightbyte is passed in the upper half of the last used SSE
- // register.
- case SSEUp:
- assert(Lo == SSE && "Unexpected SSEUp classification.");
- ResType = llvm::VectorType::get(llvm::Type::getDoubleTy(VMContext), 2);
- break;
- }
-
- return getCoerceResult(Ty, ResType, Context);
-}
-
-void X86_64ABIInfo::computeInfo(CGFunctionInfo &FI, ASTContext &Context,
- llvm::LLVMContext &VMContext) const {
- FI.getReturnInfo() = classifyReturnType(FI.getReturnType(),
- Context, VMContext);
-
- // Keep track of the number of assigned registers.
- unsigned freeIntRegs = 6, freeSSERegs = 8;
-
- // If the return value is indirect, then the hidden argument is consuming one
- // integer register.
- if (FI.getReturnInfo().isIndirect())
- --freeIntRegs;
-
- // AMD64-ABI 3.2.3p3: Once arguments are classified, the registers
- // get assigned (in left-to-right order) for passing as follows...
- for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
- it != ie; ++it) {
- unsigned neededInt, neededSSE;
- it->info = classifyArgumentType(it->type, Context, VMContext,
- neededInt, neededSSE);
-
- // AMD64-ABI 3.2.3p3: If there are no registers available for any
- // eightbyte of an argument, the whole argument is passed on the
- // stack. If registers have already been assigned for some
- // eightbytes of such an argument, the assignments get reverted.
- if (freeIntRegs >= neededInt && freeSSERegs >= neededSSE) {
- freeIntRegs -= neededInt;
- freeSSERegs -= neededSSE;
- } else {
- it->info = getIndirectResult(it->type, Context);
- }
- }
-}
-
-static llvm::Value *EmitVAArgFromMemory(llvm::Value *VAListAddr,
- QualType Ty,
- CodeGenFunction &CGF) {
- llvm::Value *overflow_arg_area_p =
- CGF.Builder.CreateStructGEP(VAListAddr, 2, "overflow_arg_area_p");
- llvm::Value *overflow_arg_area =
- CGF.Builder.CreateLoad(overflow_arg_area_p, "overflow_arg_area");
-
- // AMD64-ABI 3.5.7p5: Step 7. Align l->overflow_arg_area upwards to a 16
- // byte boundary if alignment needed by type exceeds 8 byte boundary.
- uint64_t Align = CGF.getContext().getTypeAlign(Ty) / 8;
- if (Align > 8) {
- // Note that we follow the ABI & gcc here, even though the type
- // could in theory have an alignment greater than 16. This case
- // shouldn't ever matter in practice.
-
- // overflow_arg_area = (overflow_arg_area + 15) & ~15;
- llvm::Value *Offset =
- llvm::ConstantInt::get(llvm::Type::getInt32Ty(CGF.getLLVMContext()), 15);
- overflow_arg_area = CGF.Builder.CreateGEP(overflow_arg_area, Offset);
- llvm::Value *AsInt = CGF.Builder.CreatePtrToInt(overflow_arg_area,
- llvm::Type::getInt64Ty(CGF.getLLVMContext()));
- llvm::Value *Mask = llvm::ConstantInt::get(
- llvm::Type::getInt64Ty(CGF.getLLVMContext()), ~15LL);
- overflow_arg_area =
- CGF.Builder.CreateIntToPtr(CGF.Builder.CreateAnd(AsInt, Mask),
- overflow_arg_area->getType(),
- "overflow_arg_area.align");
- }
-
- // AMD64-ABI 3.5.7p5: Step 8. Fetch type from l->overflow_arg_area.
- const llvm::Type *LTy = CGF.ConvertTypeForMem(Ty);
- llvm::Value *Res =
- CGF.Builder.CreateBitCast(overflow_arg_area,
- llvm::PointerType::getUnqual(LTy));
-
- // AMD64-ABI 3.5.7p5: Step 9. Set l->overflow_arg_area to:
- // l->overflow_arg_area + sizeof(type).
- // AMD64-ABI 3.5.7p5: Step 10. Align l->overflow_arg_area upwards to
- // an 8 byte boundary.
-
- uint64_t SizeInBytes = (CGF.getContext().getTypeSize(Ty) + 7) / 8;
- llvm::Value *Offset =
- llvm::ConstantInt::get(llvm::Type::getInt32Ty(CGF.getLLVMContext()),
- (SizeInBytes + 7) & ~7);
- overflow_arg_area = CGF.Builder.CreateGEP(overflow_arg_area, Offset,
- "overflow_arg_area.next");
- CGF.Builder.CreateStore(overflow_arg_area, overflow_arg_area_p);
-
- // AMD64-ABI 3.5.7p5: Step 11. Return the fetched type.
- return Res;
-}
-
-llvm::Value *X86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
- CodeGenFunction &CGF) const {
- llvm::LLVMContext &VMContext = CGF.getLLVMContext();
- const llvm::Type *i32Ty = llvm::Type::getInt32Ty(VMContext);
- const llvm::Type *DoubleTy = llvm::Type::getDoubleTy(VMContext);
-
- // Assume that va_list type is correct; should be pointer to LLVM type:
- // struct {
- // i32 gp_offset;
- // i32 fp_offset;
- // i8* overflow_arg_area;
- // i8* reg_save_area;
- // };
- unsigned neededInt, neededSSE;
- ABIArgInfo AI = classifyArgumentType(Ty, CGF.getContext(), VMContext,
- neededInt, neededSSE);
-
- // AMD64-ABI 3.5.7p5: Step 1. Determine whether type may be passed
- // in the registers. If not go to step 7.
- if (!neededInt && !neededSSE)
- return EmitVAArgFromMemory(VAListAddr, Ty, CGF);
-
- // AMD64-ABI 3.5.7p5: Step 2. Compute num_gp to hold the number of
- // general purpose registers needed to pass type and num_fp to hold
- // the number of floating point registers needed.
-
- // AMD64-ABI 3.5.7p5: Step 3. Verify whether arguments fit into
- // registers. In the case: l->gp_offset > 48 - num_gp * 8 or
- // l->fp_offset > 304 - num_fp * 16 go to step 7.
- //
- // NOTE: 304 is a typo, there are (6 * 8 + 8 * 16) = 176 bytes of
- // register save space).
-
- llvm::Value *InRegs = 0;
- llvm::Value *gp_offset_p = 0, *gp_offset = 0;
- llvm::Value *fp_offset_p = 0, *fp_offset = 0;
- if (neededInt) {
- gp_offset_p = CGF.Builder.CreateStructGEP(VAListAddr, 0, "gp_offset_p");
- gp_offset = CGF.Builder.CreateLoad(gp_offset_p, "gp_offset");
- InRegs =
- CGF.Builder.CreateICmpULE(gp_offset,
- llvm::ConstantInt::get(i32Ty,
- 48 - neededInt * 8),
- "fits_in_gp");
- }
-
- if (neededSSE) {
- fp_offset_p = CGF.Builder.CreateStructGEP(VAListAddr, 1, "fp_offset_p");
- fp_offset = CGF.Builder.CreateLoad(fp_offset_p, "fp_offset");
- llvm::Value *FitsInFP =
- CGF.Builder.CreateICmpULE(fp_offset,
- llvm::ConstantInt::get(i32Ty,
- 176 - neededSSE * 16),
- "fits_in_fp");
- InRegs = InRegs ? CGF.Builder.CreateAnd(InRegs, FitsInFP) : FitsInFP;
- }
-
- llvm::BasicBlock *InRegBlock = CGF.createBasicBlock("vaarg.in_reg");
- llvm::BasicBlock *InMemBlock = CGF.createBasicBlock("vaarg.in_mem");
- llvm::BasicBlock *ContBlock = CGF.createBasicBlock("vaarg.end");
- CGF.Builder.CreateCondBr(InRegs, InRegBlock, InMemBlock);
-
- // Emit code to load the value if it was passed in registers.
-
- CGF.EmitBlock(InRegBlock);
-
- // AMD64-ABI 3.5.7p5: Step 4. Fetch type from l->reg_save_area with
- // an offset of l->gp_offset and/or l->fp_offset. This may require
- // copying to a temporary location in case the parameter is passed
- // in different register classes or requires an alignment greater
- // than 8 for general purpose registers and 16 for XMM registers.
- //
- // FIXME: This really results in shameful code when we end up needing to
- // collect arguments from different places; often what should result in a
- // simple assembling of a structure from scattered addresses has many more
- // loads than necessary. Can we clean this up?
- const llvm::Type *LTy = CGF.ConvertTypeForMem(Ty);
- llvm::Value *RegAddr =
- CGF.Builder.CreateLoad(CGF.Builder.CreateStructGEP(VAListAddr, 3),
- "reg_save_area");
- if (neededInt && neededSSE) {
- // FIXME: Cleanup.
- assert(AI.isCoerce() && "Unexpected ABI info for mixed regs");
- const llvm::StructType *ST = cast<llvm::StructType>(AI.getCoerceToType());
- llvm::Value *Tmp = CGF.CreateTempAlloca(ST);
- assert(ST->getNumElements() == 2 && "Unexpected ABI info for mixed regs");
- const llvm::Type *TyLo = ST->getElementType(0);
- const llvm::Type *TyHi = ST->getElementType(1);
- assert((TyLo->isFloatingPoint() ^ TyHi->isFloatingPoint()) &&
- "Unexpected ABI info for mixed regs");
- const llvm::Type *PTyLo = llvm::PointerType::getUnqual(TyLo);
- const llvm::Type *PTyHi = llvm::PointerType::getUnqual(TyHi);
- llvm::Value *GPAddr = CGF.Builder.CreateGEP(RegAddr, gp_offset);
- llvm::Value *FPAddr = CGF.Builder.CreateGEP(RegAddr, fp_offset);
- llvm::Value *RegLoAddr = TyLo->isFloatingPoint() ? FPAddr : GPAddr;
- llvm::Value *RegHiAddr = TyLo->isFloatingPoint() ? GPAddr : FPAddr;
- llvm::Value *V =
- CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegLoAddr, PTyLo));
- CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 0));
- V = CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegHiAddr, PTyHi));
- CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 1));
-
- RegAddr = CGF.Builder.CreateBitCast(Tmp,
- llvm::PointerType::getUnqual(LTy));
- } else if (neededInt) {
- RegAddr = CGF.Builder.CreateGEP(RegAddr, gp_offset);
- RegAddr = CGF.Builder.CreateBitCast(RegAddr,
- llvm::PointerType::getUnqual(LTy));
- } else {
- if (neededSSE == 1) {
- RegAddr = CGF.Builder.CreateGEP(RegAddr, fp_offset);
- RegAddr = CGF.Builder.CreateBitCast(RegAddr,
- llvm::PointerType::getUnqual(LTy));
- } else {
- assert(neededSSE == 2 && "Invalid number of needed registers!");
- // SSE registers are spaced 16 bytes apart in the register save
- // area, we need to collect the two eightbytes together.
- llvm::Value *RegAddrLo = CGF.Builder.CreateGEP(RegAddr, fp_offset);
- llvm::Value *RegAddrHi =
- CGF.Builder.CreateGEP(RegAddrLo,
- llvm::ConstantInt::get(i32Ty, 16));
- const llvm::Type *DblPtrTy =
- llvm::PointerType::getUnqual(DoubleTy);
- const llvm::StructType *ST = llvm::StructType::get(VMContext, DoubleTy,
- DoubleTy, NULL);
- llvm::Value *V, *Tmp = CGF.CreateTempAlloca(ST);
- V = CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegAddrLo,
- DblPtrTy));
- CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 0));
- V = CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegAddrHi,
- DblPtrTy));
- CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 1));
- RegAddr = CGF.Builder.CreateBitCast(Tmp,
- llvm::PointerType::getUnqual(LTy));
- }
- }
-
- // AMD64-ABI 3.5.7p5: Step 5. Set:
- // l->gp_offset = l->gp_offset + num_gp * 8
- // l->fp_offset = l->fp_offset + num_fp * 16.
- if (neededInt) {
- llvm::Value *Offset = llvm::ConstantInt::get(i32Ty, neededInt * 8);
- CGF.Builder.CreateStore(CGF.Builder.CreateAdd(gp_offset, Offset),
- gp_offset_p);
- }
- if (neededSSE) {
- llvm::Value *Offset = llvm::ConstantInt::get(i32Ty, neededSSE * 16);
- CGF.Builder.CreateStore(CGF.Builder.CreateAdd(fp_offset, Offset),
- fp_offset_p);
- }
- CGF.EmitBranch(ContBlock);
-
- // Emit code to load the value if it was passed in memory.
-
- CGF.EmitBlock(InMemBlock);
- llvm::Value *MemAddr = EmitVAArgFromMemory(VAListAddr, Ty, CGF);
-
- // Return the appropriate result.
-
- CGF.EmitBlock(ContBlock);
- llvm::PHINode *ResAddr = CGF.Builder.CreatePHI(RegAddr->getType(),
- "vaarg.addr");
- ResAddr->reserveOperandSpace(2);
- ResAddr->addIncoming(RegAddr, InRegBlock);
- ResAddr->addIncoming(MemAddr, InMemBlock);
-
- return ResAddr;
-}
-
-// PIC16 ABI Implementation
-
-namespace {
-
-class PIC16ABIInfo : public ABIInfo {
- ABIArgInfo classifyReturnType(QualType RetTy,
- ASTContext &Context,
- llvm::LLVMContext &VMContext) const;
-
- ABIArgInfo classifyArgumentType(QualType RetTy,
- ASTContext &Context,
- llvm::LLVMContext &VMContext) const;
-
- virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context,
- llvm::LLVMContext &VMContext) const {
- FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), Context,
- VMContext);
- for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
- it != ie; ++it)
- it->info = classifyArgumentType(it->type, Context, VMContext);
- }
-
- virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
- CodeGenFunction &CGF) const;
-};
-
-}
-
-ABIArgInfo PIC16ABIInfo::classifyReturnType(QualType RetTy,
- ASTContext &Context,
- llvm::LLVMContext &VMContext) const {
- if (RetTy->isVoidType()) {
- return ABIArgInfo::getIgnore();
- } else {
- return ABIArgInfo::getDirect();
- }
-}
-
-ABIArgInfo PIC16ABIInfo::classifyArgumentType(QualType Ty,
- ASTContext &Context,
- llvm::LLVMContext &VMContext) const {
- return ABIArgInfo::getDirect();
-}
-
-llvm::Value *PIC16ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
- CodeGenFunction &CGF) const {
- return 0;
-}
-
-// ARM ABI Implementation
-
-namespace {
-
-class ARMABIInfo : public ABIInfo {
-public:
- enum ABIKind {
- APCS = 0,
- AAPCS = 1,
- AAPCS_VFP
- };
-
-private:
- ABIKind Kind;
-
-public:
- ARMABIInfo(ABIKind _Kind) : Kind(_Kind) {}
-
-private:
- ABIKind getABIKind() const { return Kind; }
-
- ABIArgInfo classifyReturnType(QualType RetTy,
- ASTContext &Context,
- llvm::LLVMContext &VMCOntext) const;
-
- ABIArgInfo classifyArgumentType(QualType RetTy,
- ASTContext &Context,
- llvm::LLVMContext &VMContext) const;
-
- virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context,
- llvm::LLVMContext &VMContext) const;
-
- virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
- CodeGenFunction &CGF) const;
-};
-
-}
-
-void ARMABIInfo::computeInfo(CGFunctionInfo &FI, ASTContext &Context,
- llvm::LLVMContext &VMContext) const {
- FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), Context,
- VMContext);
- for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
- it != ie; ++it) {
- it->info = classifyArgumentType(it->type, Context, VMContext);
- }
-
- // ARM always overrides the calling convention.
- switch (getABIKind()) {
- case APCS:
- FI.setEffectiveCallingConvention(llvm::CallingConv::ARM_APCS);
- break;
-
- case AAPCS:
- FI.setEffectiveCallingConvention(llvm::CallingConv::ARM_AAPCS);
- break;
-
- case AAPCS_VFP:
- FI.setEffectiveCallingConvention(llvm::CallingConv::ARM_AAPCS_VFP);
- break;
- }
-}
-
-ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty,
- ASTContext &Context,
- llvm::LLVMContext &VMContext) const {
- if (!CodeGenFunction::hasAggregateLLVMType(Ty))
- return (Ty->isPromotableIntegerType() ?
- ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
-
- // Ignore empty records.
- if (isEmptyRecord(Context, Ty, true))
- return ABIArgInfo::getIgnore();
-
- // FIXME: This is kind of nasty... but there isn't much choice because the ARM
- // backend doesn't support byval.
- // FIXME: This doesn't handle alignment > 64 bits.
- const llvm::Type* ElemTy;
- unsigned SizeRegs;
- if (Context.getTypeAlign(Ty) > 32) {
- ElemTy = llvm::Type::getInt64Ty(VMContext);
- SizeRegs = (Context.getTypeSize(Ty) + 63) / 64;
- } else {
- ElemTy = llvm::Type::getInt32Ty(VMContext);
- SizeRegs = (Context.getTypeSize(Ty) + 31) / 32;
- }
- std::vector<const llvm::Type*> LLVMFields;
- LLVMFields.push_back(llvm::ArrayType::get(ElemTy, SizeRegs));
- const llvm::Type* STy = llvm::StructType::get(VMContext, LLVMFields, true);
- return ABIArgInfo::getCoerce(STy);
-}
-
-static bool isIntegerLikeType(QualType Ty,
- ASTContext &Context,
- llvm::LLVMContext &VMContext) {
- // APCS, C Language Calling Conventions, Non-Simple Return Values: A structure
- // is called integer-like if its size is less than or equal to one word, and
- // the offset of each of its addressable sub-fields is zero.
-
- uint64_t Size = Context.getTypeSize(Ty);
-
- // Check that the type fits in a word.
- if (Size > 32)
- return false;
-
- // FIXME: Handle vector types!
- if (Ty->isVectorType())
- return false;
-
- // Float types are never treated as "integer like".
- if (Ty->isRealFloatingType())
- return false;
-
- // If this is a builtin or pointer type then it is ok.
- if (Ty->getAs<BuiltinType>() || Ty->isPointerType())
- return true;
-
- // Complex types "should" be ok by the definition above, but they are not.
- if (Ty->isAnyComplexType())
- return false;
-
- // Single element and zero sized arrays should be allowed, by the definition
- // above, but they are not.
-
- // Otherwise, it must be a record type.
- const RecordType *RT = Ty->getAs<RecordType>();
- if (!RT) return false;
-
- // Ignore records with flexible arrays.
- const RecordDecl *RD = RT->getDecl();
- if (RD->hasFlexibleArrayMember())
- return false;
-
- // Check that all sub-fields are at offset 0, and are themselves "integer
- // like".
- const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
-
- bool HadField = false;
- unsigned idx = 0;
- for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
- i != e; ++i, ++idx) {
- const FieldDecl *FD = *i;
-
- // Check if this field is at offset 0.
- uint64_t Offset = Layout.getFieldOffset(idx);
- if (Offset != 0) {
- // Allow padding bit-fields, but only if they are all at the end of the
- // structure (despite the wording above, this matches gcc).
- if (FD->isBitField() &&
- !FD->getBitWidth()->EvaluateAsInt(Context).getZExtValue()) {
- for (; i != e; ++i)
- if (!i->isBitField() ||
- i->getBitWidth()->EvaluateAsInt(Context).getZExtValue())
- return false;
-
- // All remaining fields are padding, allow this.
- return true;
- }
-
- return false;
- }
-
- if (!isIntegerLikeType(FD->getType(), Context, VMContext))
- return false;
-
- // Only allow at most one field in a structure. Again this doesn't match the
- // wording above, but follows gcc.
- if (!RD->isUnion()) {
- if (HadField)
- return false;
-
- HadField = true;
- }
- }
-
- return true;
-}
-
-ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy,
- ASTContext &Context,
- llvm::LLVMContext &VMContext) const {
- if (RetTy->isVoidType())
- return ABIArgInfo::getIgnore();
-
- if (!CodeGenFunction::hasAggregateLLVMType(RetTy))
- return (RetTy->isPromotableIntegerType() ?
- ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
-
- // Are we following APCS?
- if (getABIKind() == APCS) {
- if (isEmptyRecord(Context, RetTy, false))
- return ABIArgInfo::getIgnore();
-
- // Integer like structures are returned in r0.
- if (isIntegerLikeType(RetTy, Context, VMContext)) {
- // Return in the smallest viable integer type.
- uint64_t Size = Context.getTypeSize(RetTy);
- if (Size <= 8)
- return ABIArgInfo::getCoerce(llvm::Type::getInt8Ty(VMContext));
- if (Size <= 16)
- return ABIArgInfo::getCoerce(llvm::Type::getInt16Ty(VMContext));
- return ABIArgInfo::getCoerce(llvm::Type::getInt32Ty(VMContext));
- }
-
- // Otherwise return in memory.
- return ABIArgInfo::getIndirect(0);
- }
-
- // Otherwise this is an AAPCS variant.
-
- if (isEmptyRecord(Context, RetTy, true))
- return ABIArgInfo::getIgnore();
-
- // Aggregates <= 4 bytes are returned in r0; other aggregates
- // are returned indirectly.
- uint64_t Size = Context.getTypeSize(RetTy);
- if (Size <= 32) {
- // Return in the smallest viable integer type.
- if (Size <= 8)
- return ABIArgInfo::getCoerce(llvm::Type::getInt8Ty(VMContext));
- if (Size <= 16)
- return ABIArgInfo::getCoerce(llvm::Type::getInt16Ty(VMContext));
- return ABIArgInfo::getCoerce(llvm::Type::getInt32Ty(VMContext));
- }
-
- return ABIArgInfo::getIndirect(0);
-}
-
-llvm::Value *ARMABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
- CodeGenFunction &CGF) const {
- // FIXME: Need to handle alignment
- const llvm::Type *BP = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
- const llvm::Type *BPP = llvm::PointerType::getUnqual(BP);
-
- CGBuilderTy &Builder = CGF.Builder;
- llvm::Value *VAListAddrAsBPP = Builder.CreateBitCast(VAListAddr, BPP,
- "ap");
- llvm::Value *Addr = Builder.CreateLoad(VAListAddrAsBPP, "ap.cur");
- llvm::Type *PTy =
- llvm::PointerType::getUnqual(CGF.ConvertType(Ty));
- llvm::Value *AddrTyped = Builder.CreateBitCast(Addr, PTy);
-
- uint64_t Offset =
- llvm::RoundUpToAlignment(CGF.getContext().getTypeSize(Ty) / 8, 4);
- llvm::Value *NextAddr =
- Builder.CreateGEP(Addr, llvm::ConstantInt::get(
- llvm::Type::getInt32Ty(CGF.getLLVMContext()), Offset),
- "ap.next");
- Builder.CreateStore(NextAddr, VAListAddrAsBPP);
-
- return AddrTyped;
-}
-
-ABIArgInfo DefaultABIInfo::classifyReturnType(QualType RetTy,
- ASTContext &Context,
- llvm::LLVMContext &VMContext) const {
- if (RetTy->isVoidType()) {
- return ABIArgInfo::getIgnore();
- } else if (CodeGenFunction::hasAggregateLLVMType(RetTy)) {
- return ABIArgInfo::getIndirect(0);
- } else {
- return (RetTy->isPromotableIntegerType() ?
- ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
- }
-}
-
-// SystemZ ABI Implementation
-
-namespace {
-
-class SystemZABIInfo : public ABIInfo {
- bool isPromotableIntegerType(QualType Ty) const;
-
- ABIArgInfo classifyReturnType(QualType RetTy, ASTContext &Context,
- llvm::LLVMContext &VMContext) const;
-
- ABIArgInfo classifyArgumentType(QualType RetTy, ASTContext &Context,
- llvm::LLVMContext &VMContext) const;
-
- virtual void computeInfo(CGFunctionInfo &FI, ASTContext &Context,
- llvm::LLVMContext &VMContext) const {
- FI.getReturnInfo() = classifyReturnType(FI.getReturnType(),
- Context, VMContext);
- for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end();
- it != ie; ++it)
- it->info = classifyArgumentType(it->type, Context, VMContext);
- }
-
- virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
- CodeGenFunction &CGF) const;
-};
-
-}
-
-bool SystemZABIInfo::isPromotableIntegerType(QualType Ty) const {
- // SystemZ ABI requires all 8, 16 and 32 bit quantities to be extended.
- if (const BuiltinType *BT = Ty->getAs<BuiltinType>())
- switch (BT->getKind()) {
- case BuiltinType::Bool:
- case BuiltinType::Char_S:
- case BuiltinType::Char_U:
- case BuiltinType::SChar:
- case BuiltinType::UChar:
- case BuiltinType::Short:
- case BuiltinType::UShort:
- case BuiltinType::Int:
- case BuiltinType::UInt:
- return true;
- default:
- return false;
- }
- return false;
-}
-
-llvm::Value *SystemZABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
- CodeGenFunction &CGF) const {
- // FIXME: Implement
- return 0;
-}
-
-
-ABIArgInfo SystemZABIInfo::classifyReturnType(QualType RetTy,
- ASTContext &Context,
- llvm::LLVMContext &VMContext) const {
- if (RetTy->isVoidType()) {
- return ABIArgInfo::getIgnore();
- } else if (CodeGenFunction::hasAggregateLLVMType(RetTy)) {
- return ABIArgInfo::getIndirect(0);
- } else {
- return (isPromotableIntegerType(RetTy) ?
- ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
- }
-}
-
-ABIArgInfo SystemZABIInfo::classifyArgumentType(QualType Ty,
- ASTContext &Context,
- llvm::LLVMContext &VMContext) const {
- if (CodeGenFunction::hasAggregateLLVMType(Ty)) {
- return ABIArgInfo::getIndirect(0);
- } else {
- return (isPromotableIntegerType(Ty) ?
- ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
- }
-}
-
-ABIArgInfo DefaultABIInfo::classifyArgumentType(QualType Ty,
- ASTContext &Context,
- llvm::LLVMContext &VMContext) const {
- if (CodeGenFunction::hasAggregateLLVMType(Ty)) {
- return ABIArgInfo::getIndirect(0);
- } else {
- return (Ty->isPromotableIntegerType() ?
- ABIArgInfo::getExtend() : ABIArgInfo::getDirect());
- }
-}
-
-llvm::Value *DefaultABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
- CodeGenFunction &CGF) const {
- return 0;
-}
-
-const ABIInfo &CodeGenTypes::getABIInfo() const {
- if (TheABIInfo)
- return *TheABIInfo;
-
- // For now we just cache the ABIInfo in CodeGenTypes and don't free it.
-
- const llvm::Triple &Triple(getContext().Target.getTriple());
- switch (Triple.getArch()) {
- default:
- return *(TheABIInfo = new DefaultABIInfo);
-
- case llvm::Triple::arm:
- case llvm::Triple::thumb:
- // FIXME: We want to know the float calling convention as well.
- if (strcmp(getContext().Target.getABI(), "apcs-gnu") == 0)
- return *(TheABIInfo = new ARMABIInfo(ARMABIInfo::APCS));
-
- return *(TheABIInfo = new ARMABIInfo(ARMABIInfo::AAPCS));
-
- case llvm::Triple::pic16:
- return *(TheABIInfo = new PIC16ABIInfo());
-
- case llvm::Triple::systemz:
- return *(TheABIInfo = new SystemZABIInfo());
-
- case llvm::Triple::x86:
- switch (Triple.getOS()) {
- case llvm::Triple::Darwin:
- return *(TheABIInfo = new X86_32ABIInfo(Context, true, true));
- case llvm::Triple::Cygwin:
- case llvm::Triple::MinGW32:
- case llvm::Triple::MinGW64:
- case llvm::Triple::AuroraUX:
- case llvm::Triple::DragonFly:
- case llvm::Triple::FreeBSD:
- case llvm::Triple::OpenBSD:
- return *(TheABIInfo = new X86_32ABIInfo(Context, false, true));
-
- default:
- return *(TheABIInfo = new X86_32ABIInfo(Context, false, false));
- }
-
- case llvm::Triple::x86_64:
- return *(TheABIInfo = new X86_64ABIInfo());
- }
-}
diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp
index e5fd47e..4454662 100644
--- a/lib/CodeGen/TargetInfo.cpp
+++ b/lib/CodeGen/TargetInfo.cpp
@@ -257,7 +257,7 @@ class DefaultABIInfo : public ABIInfo {
class DefaultTargetCodeGenInfo : public TargetCodeGenInfo {
public:
- DefaultTargetCodeGenInfo():TargetCodeGenInfo(new DefaultABIInfo()) {};
+ DefaultTargetCodeGenInfo():TargetCodeGenInfo(new DefaultABIInfo()) {}
};
llvm::Value *DefaultABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
@@ -320,7 +320,7 @@ public:
class X86_32TargetCodeGenInfo : public TargetCodeGenInfo {
public:
X86_32TargetCodeGenInfo(ASTContext &Context, bool d, bool p)
- :TargetCodeGenInfo(new X86_32ABIInfo(Context, d, p)) {};
+ :TargetCodeGenInfo(new X86_32ABIInfo(Context, d, p)) {}
};
}
@@ -619,7 +619,7 @@ public:
class X86_64TargetCodeGenInfo : public TargetCodeGenInfo {
public:
- X86_64TargetCodeGenInfo():TargetCodeGenInfo(new X86_64ABIInfo()) {};
+ X86_64TargetCodeGenInfo():TargetCodeGenInfo(new X86_64ABIInfo()) {}
};
}
@@ -1428,7 +1428,7 @@ class PIC16ABIInfo : public ABIInfo {
class PIC16TargetCodeGenInfo : public TargetCodeGenInfo {
public:
- PIC16TargetCodeGenInfo():TargetCodeGenInfo(new PIC16ABIInfo()) {};
+ PIC16TargetCodeGenInfo():TargetCodeGenInfo(new PIC16ABIInfo()) {}
};
}
@@ -1493,7 +1493,7 @@ private:
class ARMTargetCodeGenInfo : public TargetCodeGenInfo {
public:
ARMTargetCodeGenInfo(ARMABIInfo::ABIKind K)
- :TargetCodeGenInfo(new ARMABIInfo(K)) {};
+ :TargetCodeGenInfo(new ARMABIInfo(K)) {}
};
}
@@ -1754,7 +1754,7 @@ class SystemZABIInfo : public ABIInfo {
class SystemZTargetCodeGenInfo : public TargetCodeGenInfo {
public:
- SystemZTargetCodeGenInfo():TargetCodeGenInfo(new SystemZABIInfo()) {};
+ SystemZTargetCodeGenInfo():TargetCodeGenInfo(new SystemZABIInfo()) {}
};
}
@@ -1816,7 +1816,7 @@ namespace {
class MSP430TargetCodeGenInfo : public TargetCodeGenInfo {
public:
- MSP430TargetCodeGenInfo():TargetCodeGenInfo(new DefaultABIInfo()) {};
+ MSP430TargetCodeGenInfo():TargetCodeGenInfo(new DefaultABIInfo()) {}
void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
CodeGen::CodeGenModule &M) const;
};
diff --git a/lib/CodeGen/TargetInfo.h b/lib/CodeGen/TargetInfo.h
index 495b22f..58b7b79 100644
--- a/lib/CodeGen/TargetInfo.h
+++ b/lib/CodeGen/TargetInfo.h
@@ -34,7 +34,7 @@ namespace clang {
ABIInfo *Info;
public:
// WARNING: Acquires the ownership of ABIInfo.
- TargetCodeGenInfo(ABIInfo *info = 0):Info(info) { };
+ TargetCodeGenInfo(ABIInfo *info = 0):Info(info) { }
virtual ~TargetCodeGenInfo();
/// getABIInfo() - Returns ABI info helper for the target.
@@ -43,7 +43,7 @@ namespace clang {
/// SetTargetAttributes - Provides a convenient hook to handle extra
/// target-specific attributes for the given global.
virtual void SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
- CodeGen::CodeGenModule &M) const { };
+ CodeGen::CodeGenModule &M) const { }
};
}
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index ab4bd49..852a018 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -26,6 +26,7 @@
#include "clang/Basic/Version.h"
#include "llvm/ADT/StringSet.h"
+#include "llvm/ADT/OwningPtr.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/System/Path.h"
@@ -66,6 +67,14 @@ Driver::Driver(llvm::StringRef _Name, llvm::StringRef _Dir,
CCCUseClangCXX = false;
}
+
+ // Compute the path to the resource directory.
+ llvm::sys::Path P(Dir);
+ P.eraseComponent(); // Remove /bin from foo/bin
+ P.appendComponent("lib");
+ P.appendComponent("clang");
+ P.appendComponent(CLANG_VERSION_STRING);
+ ResourceDir = P.str();
}
Driver::~Driver() {
@@ -273,15 +282,7 @@ void Driver::PrintHelp(bool ShowHidden) const {
void Driver::PrintVersion(const Compilation &C, llvm::raw_ostream &OS) const {
// FIXME: The following handlers should use a callback mechanism, we don't
// know what the client would like to do.
-#ifdef CLANG_VENDOR
- OS << CLANG_VENDOR;
-#endif
- OS << "clang version " CLANG_VERSION_STRING " ("
- << getClangSubversionPath();
- if (unsigned Revision = getClangSubversionRevision())
- OS << " " << Revision;
- OS << ")" << '\n';
-
+ OS << getClangFullVersion() << '\n';
const ToolChain &TC = C.getDefaultToolChain();
OS << "Target: " << TC.getTripleString() << '\n';
@@ -675,7 +676,7 @@ void Driver::BuildActions(const ArgList &Args, ActionList &Actions) const {
}
// Build the pipeline for this file.
- Action *Current = new InputAction(*InputArg, InputType);
+ llvm::OwningPtr<Action> Current(new InputAction(*InputArg, InputType));
for (unsigned i = 0; i != NumSteps; ++i) {
phases::ID Phase = types::getCompilationPhase(InputType, i);
@@ -686,8 +687,7 @@ void Driver::BuildActions(const ArgList &Args, ActionList &Actions) const {
// Queue linker inputs.
if (Phase == phases::Link) {
assert(i + 1 == NumSteps && "linking must be final compilation step.");
- LinkerInputs.push_back(Current);
- Current = 0;
+ LinkerInputs.push_back(Current.take());
break;
}
@@ -698,14 +698,14 @@ void Driver::BuildActions(const ArgList &Args, ActionList &Actions) const {
continue;
// Otherwise construct the appropriate action.
- Current = ConstructPhaseAction(Args, Phase, Current);
+ Current.reset(ConstructPhaseAction(Args, Phase, Current.take()));
if (Current->getType() == types::TY_Nothing)
break;
}
// If we ended with something, add to the output list.
if (Current)
- Actions.push_back(Current);
+ Actions.push_back(Current.take());
}
// Add a link action if necessary.
diff --git a/lib/Driver/Makefile b/lib/Driver/Makefile
index 4c3ca5c..dbacf8b 100644
--- a/lib/Driver/Makefile
+++ b/lib/Driver/Makefile
@@ -13,8 +13,5 @@ BUILD_ARCHIVE = 1
CXXFLAGS = -fno-rtti
CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
-ifdef CLANG_VENDOR
-CPPFLAGS += -DCLANG_VENDOR='"$(CLANG_VENDOR) "'
-endif
include $(LEVEL)/Makefile.common
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index 42657d9..a9c6a68 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -47,6 +47,69 @@ Darwin::Darwin(const HostInfo &Host, const llvm::Triple& Triple,
IPhoneOSVersionMin = "3.0";
}
+// FIXME: Can we tablegen this?
+static const char *GetArmArchForMArch(llvm::StringRef Value) {
+ if (Value == "armv6k")
+ return "armv6";
+
+ if (Value == "armv5tej")
+ return "armv5";
+
+ if (Value == "xscale")
+ return "xscale";
+
+ if (Value == "armv4t")
+ return "armv4t";
+
+ if (Value == "armv7" || Value == "armv7-a" || Value == "armv7-r" ||
+ Value == "armv7-m" || Value == "armv7a" || Value == "armv7r" ||
+ Value == "armv7m")
+ return "armv7";
+
+ return 0;
+}
+
+// FIXME: Can we tablegen this?
+static const char *GetArmArchForMCpu(llvm::StringRef Value) {
+ if (Value == "arm10tdmi" || Value == "arm1020t" || Value == "arm9e" ||
+ Value == "arm946e-s" || Value == "arm966e-s" ||
+ Value == "arm968e-s" || Value == "arm10e" ||
+ Value == "arm1020e" || Value == "arm1022e" || Value == "arm926ej-s" ||
+ Value == "arm1026ej-s")
+ return "armv5";
+
+ if (Value == "xscale")
+ return "xscale";
+
+ if (Value == "arm1136j-s" || Value == "arm1136jf-s" ||
+ Value == "arm1176jz-s" || Value == "arm1176jzf-s")
+ return "armv6";
+
+ if (Value == "cortex-a8" || Value == "cortex-r4" || Value == "cortex-m3")
+ return "armv7";
+
+ return 0;
+}
+
+llvm::StringRef Darwin::getDarwinArchName(const ArgList &Args) const {
+ switch (getTriple().getArch()) {
+ default:
+ return getArchName();
+
+ case llvm::Triple::arm: {
+ if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
+ if (const char *Arch = GetArmArchForMArch(A->getValue(Args)))
+ return Arch;
+
+ if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
+ if (const char *Arch = GetArmArchForMCpu(A->getValue(Args)))
+ return Arch;
+
+ return "arm";
+ }
+ }
+}
+
DarwinGCC::DarwinGCC(const HostInfo &Host, const llvm::Triple& Triple,
const unsigned (&DarwinVersion)[3],
const unsigned (&_GCCVersion)[3], bool IsIPhoneOS)
@@ -118,10 +181,6 @@ DarwinGCC::DarwinGCC(const HostInfo &Host, const llvm::Triple& Triple,
Path += ToolChainDir;
getProgramPaths().push_back(Path);
- Path = getDriver().Dir;
- Path += "/../libexec";
- getProgramPaths().push_back(Path);
-
getProgramPaths().push_back(getDriver().Dir);
}
@@ -235,13 +294,6 @@ DarwinClang::DarwinClang(const HostInfo &Host, const llvm::Triple& Triple,
bool IsIPhoneOS)
: Darwin(Host, Triple, DarwinVersion, IsIPhoneOS)
{
- // Add the relative libexec dir (for clang-cc).
- //
- // FIXME: We should sink clang-cc into libexec/clang/<version>/.
- std::string Path = getDriver().Dir;
- Path += "/../libexec";
- getProgramPaths().push_back(Path);
-
// We expect 'as', 'ld', etc. to be adjacent to our install dir.
getProgramPaths().push_back(getDriver().Dir);
}
@@ -253,12 +305,10 @@ void DarwinClang::AddLinkSearchPathArgs(const ArgList &Args,
void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
- // Check for static linking.
- if (Args.hasArg(options::OPT_static)) {
- // FIXME: We need to have compiler-rt available (perhaps as
- // libclang_static.a) to link against.
+ // Darwin doesn't support real static executables, don't link any runtime
+ // libraries with -static.
+ if (Args.hasArg(options::OPT_static))
return;
- }
// Reject -static-libgcc for now, we can deal with this when and if someone
// cares. This is useful in situations where someone wants to statically link
@@ -269,12 +319,52 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
return;
}
- // Otherwise link libSystem, which should have the support routines.
- //
- // FIXME: This is only true for 10.6 and beyond. Legacy support isn't
- // critical, but it should work... we should just link in the static
- // compiler-rt library.
+ // Otherwise link libSystem, then the dynamic runtime library, and finally any
+ // target specific static runtime library.
CmdArgs.push_back("-lSystem");
+
+ // Select the dynamic runtime library and the target specific static library.
+ const char *DarwinStaticLib = 0;
+ if (isIPhoneOS()) {
+ CmdArgs.push_back("-lgcc_s.1");
+
+ // We may need some static functions for armv6/thumb which are required to
+ // be in the same linkage unit as their caller.
+ if (getDarwinArchName(Args) == "armv6")
+ DarwinStaticLib = "libclang_rt.armv6.a";
+ } else {
+ unsigned MacosxVersionMin[3];
+ getMacosxVersionMin(Args, MacosxVersionMin);
+
+ // The dynamic runtime library was merged with libSystem for 10.6 and
+ // beyond; only 10.4 and 10.5 need an additional runtime library.
+ if (isMacosxVersionLT(MacosxVersionMin, 10, 5))
+ CmdArgs.push_back("-lgcc_s.10.4");
+ else if (isMacosxVersionLT(MacosxVersionMin, 10, 6))
+ CmdArgs.push_back("-lgcc_s.10.5");
+
+ // For OS X, we only need a static runtime library when targetting 10.4, to
+ // provide versions of the static functions which were omitted from
+ // 10.4.dylib.
+ if (isMacosxVersionLT(MacosxVersionMin, 10, 5))
+ DarwinStaticLib = "libclang_rt.10.4.a";
+ }
+
+ /// Add the target specific static library, if needed.
+ if (DarwinStaticLib) {
+ llvm::sys::Path P(getDriver().ResourceDir);
+ P.appendComponent("lib");
+ P.appendComponent("darwin");
+ P.appendComponent(DarwinStaticLib);
+
+ // For now, allow missing resource libraries to support developers who may
+ // not have compiler-rt checked out or integrated into their build.
+ if (!P.exists())
+ getDriver().Diag(clang::diag::warn_drv_missing_resource_library)
+ << P.str();
+ else
+ CmdArgs.push_back(Args.MakeArgString(P.str()));
+ }
}
void Darwin::getMacosxVersionMin(const ArgList &Args,
@@ -544,10 +634,6 @@ const char *Darwin::GetForcedPicModel() const {
Generic_GCC::Generic_GCC(const HostInfo &Host, const llvm::Triple& Triple)
: ToolChain(Host, Triple) {
- std::string Path(getDriver().Dir);
- Path += "/../libexec";
- getProgramPaths().push_back(Path);
-
getProgramPaths().push_back(getDriver().Dir);
}
@@ -684,11 +770,6 @@ Tool &FreeBSD::SelectTool(const Compilation &C, const JobAction &JA) const {
AuroraUX::AuroraUX(const HostInfo &Host, const llvm::Triple& Triple)
: Generic_GCC(Host, Triple) {
- // Path mangling to find libexec
- std::string Path(getDriver().Dir);
-
- Path += "/../libexec";
- getProgramPaths().push_back(Path);
getProgramPaths().push_back(getDriver().Dir);
getFilePaths().push_back(getDriver().Dir + "/../lib");
@@ -753,10 +834,6 @@ DragonFly::DragonFly(const HostInfo &Host, const llvm::Triple& Triple)
: Generic_GCC(Host, Triple) {
// Path mangling to find libexec
- std::string Path(getDriver().Dir);
-
- Path += "/../libexec";
- getProgramPaths().push_back(Path);
getProgramPaths().push_back(getDriver().Dir);
getFilePaths().push_back(getDriver().Dir + "/../lib");
diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h
index 374ad8c..3ca6ad8 100644
--- a/lib/Driver/ToolChains.h
+++ b/lib/Driver/ToolChains.h
@@ -85,6 +85,11 @@ public:
Res[2] = DarwinVersion[1];
}
+ /// getDarwinArchName - Get the "Darwin" arch name for a particular compiler
+ /// invocation. For example, Darwin treats different ARM variations as
+ /// distinct architectures.
+ llvm::StringRef getDarwinArchName(const ArgList &Args) const;
+
/// getMacosxVersionMin - Get the effective -mmacosx-version-min, which is
/// either the -mmacosx-version-min, or the current version if unspecified.
void getMacosxVersionMin(const ArgList &Args, unsigned (&Res)[3]) const;
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 010953d..afb22a2 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -9,7 +9,6 @@
#include "Tools.h"
-#include "clang/Basic/Version.h"
#include "clang/Driver/Action.h"
#include "clang/Driver/Arg.h"
#include "clang/Driver/ArgList.h"
@@ -864,15 +863,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_nobuiltininc);
// Pass the path to compiler resource files.
- //
- // FIXME: Get this from a configuration object.
- llvm::sys::Path P(D.Dir);
- P.eraseComponent(); // Remove /bin from foo/bin
- P.appendComponent("lib");
- P.appendComponent("clang");
- P.appendComponent(CLANG_VERSION_STRING);
CmdArgs.push_back("-resource-dir");
- CmdArgs.push_back(Args.MakeArgString(P.str()));
+ CmdArgs.push_back(D.ResourceDir.c_str());
// Add preprocessing options like -I, -D, etc. if we are using the
// preprocessor.
@@ -1857,87 +1849,17 @@ static bool isSourceSuffix(const char *Str) {
.Default(false);
}
-// FIXME: Can we tablegen this?
-static const char *GetArmArchForMArch(llvm::StringRef Value) {
- if (Value == "armv6k")
- return "armv6";
-
- if (Value == "armv5tej")
- return "armv5";
-
- if (Value == "xscale")
- return "xscale";
-
- if (Value == "armv4t")
- return "armv4t";
-
- if (Value == "armv7" || Value == "armv7-a" || Value == "armv7-r" ||
- Value == "armv7-m" || Value == "armv7a" || Value == "armv7r" ||
- Value == "armv7m")
- return "armv7";
-
- return 0;
-}
-
-// FIXME: Can we tablegen this?
-static const char *GetArmArchForMCpu(llvm::StringRef Value) {
- if (Value == "arm10tdmi" || Value == "arm1020t" || Value == "arm9e" ||
- Value == "arm946e-s" || Value == "arm966e-s" ||
- Value == "arm968e-s" || Value == "arm10e" ||
- Value == "arm1020e" || Value == "arm1022e" || Value == "arm926ej-s" ||
- Value == "arm1026ej-s")
- return "armv5";
-
- if (Value == "xscale")
- return "xscale";
-
- if (Value == "arm1136j-s" || Value == "arm1136jf-s" ||
- Value == "arm1176jz-s" || Value == "arm1176jzf-s")
- return "armv6";
-
- if (Value == "cortex-a8" || Value == "cortex-r4" || Value == "cortex-m3")
- return "armv7";
-
- return 0;
-}
-
void darwin::DarwinTool::AddDarwinArch(const ArgList &Args,
ArgStringList &CmdArgs) const {
+ llvm::StringRef ArchName = getDarwinToolChain().getDarwinArchName(Args);
+
// Derived from darwin_arch spec.
CmdArgs.push_back("-arch");
+ CmdArgs.push_back(Args.MakeArgString(ArchName));
- switch (getToolChain().getTriple().getArch()) {
- default:
- CmdArgs.push_back(Args.MakeArgString(getToolChain().getArchName()));
- break;
-
- case llvm::Triple::arm: {
- if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
- if (const char *Arch = GetArmArchForMArch(A->getValue(Args))) {
- CmdArgs.push_back(Arch);
- return;
- }
- }
-
- if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
- if (const char *Arch = GetArmArchForMCpu(A->getValue(Args))) {
- CmdArgs.push_back(Arch);
- return;
- }
- }
-
- CmdArgs.push_back("arm");
+ // FIXME: Is this needed anymore?
+ if (ArchName == "arm")
CmdArgs.push_back("-force_cpusubtype_ALL");
- return;
- }
- }
-}
-
-void darwin::DarwinTool::AddDarwinSubArch(const ArgList &Args,
- ArgStringList &CmdArgs) const {
- // Derived from darwin_subarch spec, not sure what the distinction
- // exists for but at least for this chain it is the same.
- AddDarwinArch(Args, CmdArgs);
}
void darwin::Link::AddLinkArgs(const ArgList &Args,
@@ -1954,11 +1876,9 @@ void darwin::Link::AddLinkArgs(const ArgList &Args,
}
if (!Args.hasArg(options::OPT_dynamiclib)) {
- if (Args.hasArg(options::OPT_force__cpusubtype__ALL)) {
- AddDarwinArch(Args, CmdArgs);
- CmdArgs.push_back("-force_cpusubtype_ALL");
- } else
- AddDarwinSubArch(Args, CmdArgs);
+ AddDarwinArch(Args, CmdArgs);
+ // FIXME: Why do this only on this path?
+ Args.AddLastArg(CmdArgs, options::OPT_force__cpusubtype__ALL);
Args.AddLastArg(CmdArgs, options::OPT_bundle);
Args.AddAllArgs(CmdArgs, options::OPT_bundle__loader);
@@ -1992,11 +1912,7 @@ void darwin::Link::AddLinkArgs(const ArgList &Args,
Args.AddAllArgsTranslated(CmdArgs, options::OPT_current__version,
"-dylib_current_version");
- if (Args.hasArg(options::OPT_force__cpusubtype__ALL)) {
- AddDarwinArch(Args, CmdArgs);
- // NOTE: We don't add -force_cpusubtype_ALL on this path. Ok.
- } else
- AddDarwinSubArch(Args, CmdArgs);
+ AddDarwinArch(Args, CmdArgs);
Args.AddAllArgsTranslated(CmdArgs, options::OPT_install__name,
"-dylib_install_name");
diff --git a/lib/Driver/Tools.h b/lib/Driver/Tools.h
index 8f7da52..abd8cfc 100644
--- a/lib/Driver/Tools.h
+++ b/lib/Driver/Tools.h
@@ -130,7 +130,6 @@ namespace darwin {
class VISIBILITY_HIDDEN DarwinTool : public Tool {
protected:
void AddDarwinArch(const ArgList &Args, ArgStringList &CmdArgs) const;
- void AddDarwinSubArch(const ArgList &Args, ArgStringList &CmdArgs) const;
const toolchains::Darwin &getDarwinToolChain() const {
return reinterpret_cast<const toolchains::Darwin&>(getToolChain());
diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp
index 52b597e..33cb94e 100644
--- a/lib/Frontend/ASTConsumers.cpp
+++ b/lib/Frontend/ASTConsumers.cpp
@@ -421,6 +421,11 @@ void DeclContextPrinter::PrintDeclContext(const DeclContext* DC,
Out << "<namespace alias> " << NAD->getNameAsString() << "\n";
break;
}
+ case Decl::ClassTemplate: {
+ ClassTemplateDecl *CTD = cast<ClassTemplateDecl>(*I);
+ Out << "<class template> " << CTD->getNameAsString() << '\n';
+ break;
+ }
default:
Out << "DeclKind: " << DK << '"' << I->getDeclKindName() << "\"\n";
assert(0 && "decl unhandled");
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index 48296c7..2fb47cb 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -30,6 +30,7 @@
#include "clang/Basic/TargetOptions.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/Diagnostic.h"
+#include "llvm/Support/MemoryBuffer.h"
#include "llvm/System/Host.h"
#include "llvm/System/Path.h"
using namespace clang;
@@ -103,11 +104,31 @@ const std::string &ASTUnit::getPCHFileName() {
ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename,
Diagnostic &Diags,
bool OnlyLocalDecls,
- bool UseBumpAllocator) {
+ bool UseBumpAllocator,
+ RemappedFile *RemappedFiles,
+ unsigned NumRemappedFiles) {
llvm::OwningPtr<ASTUnit> AST(new ASTUnit(true));
AST->OnlyLocalDecls = OnlyLocalDecls;
AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager()));
+ for (unsigned I = 0; I != NumRemappedFiles; ++I) {
+ // Create the file entry for the file that we're mapping from.
+ const FileEntry *FromFile
+ = AST->getFileManager().getVirtualFile(RemappedFiles[I].first,
+ RemappedFiles[I].second->getBufferSize(),
+ 0);
+ if (!FromFile) {
+ Diags.Report(diag::err_fe_remap_missing_from_file)
+ << RemappedFiles[I].first;
+ continue;
+ }
+
+ // Override the contents of the "from" file with the contents of
+ // the "to" file.
+ AST->getSourceManager().overrideFileContents(FromFile,
+ RemappedFiles[I].second);
+ }
+
// Gather Info for preprocessor construction later on.
LangOptions LangInfo;
@@ -289,7 +310,9 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
Diagnostic &Diags,
llvm::StringRef ResourceFilesPath,
bool OnlyLocalDecls,
- bool UseBumpAllocator) {
+ bool UseBumpAllocator,
+ RemappedFile *RemappedFiles,
+ unsigned NumRemappedFiles) {
llvm::SmallVector<const char *, 16> Args;
Args.push_back("<clang>"); // FIXME: Remove dummy argument.
Args.insert(Args.end(), ArgBegin, ArgEnd);
@@ -327,6 +350,11 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
(const char**) CCArgs.data()+CCArgs.size(),
Diags);
+ // Override any files that need remapping
+ for (unsigned I = 0; I != NumRemappedFiles; ++I)
+ CI.getPreprocessorOpts().addRemappedFile(RemappedFiles[I].first,
+ RemappedFiles[I].second);
+
// Override the resources path.
CI.getHeaderSearchOpts().ResourceDir = ResourceFilesPath;
diff --git a/lib/Frontend/AnalysisConsumer.cpp b/lib/Frontend/AnalysisConsumer.cpp
index ad152d3..45a3b15 100644
--- a/lib/Frontend/AnalysisConsumer.cpp
+++ b/lib/Frontend/AnalysisConsumer.cpp
@@ -204,45 +204,47 @@ namespace llvm {
void AnalysisConsumer::HandleTopLevelSingleDecl(Decl *D) {
switch (D->getKind()) {
- case Decl::Function: {
- FunctionDecl* FD = cast<FunctionDecl>(D);
+ case Decl::Function: {
+ FunctionDecl* FD = cast<FunctionDecl>(D);
- if (!Opts.AnalyzeSpecificFunction.empty() &&
- Opts.AnalyzeSpecificFunction != FD->getIdentifier()->getName())
- break;
-
- Stmt* Body = FD->getBody();
- if (Body) HandleCode(FD, Body, FunctionActions);
+ if (!Opts.AnalyzeSpecificFunction.empty() &&
+ Opts.AnalyzeSpecificFunction != FD->getIdentifier()->getName())
break;
- }
- case Decl::ObjCMethod: {
- ObjCMethodDecl* MD = cast<ObjCMethodDecl>(D);
+ Stmt* Body = FD->getBody();
+ if (Body) HandleCode(FD, Body, FunctionActions);
+ break;
+ }
- if (Opts.AnalyzeSpecificFunction.size() > 0 &&
- Opts.AnalyzeSpecificFunction != MD->getSelector().getAsString())
- return;
+ case Decl::ObjCMethod: {
+ ObjCMethodDecl* MD = cast<ObjCMethodDecl>(D);
- Stmt* Body = MD->getBody();
- if (Body) HandleCode(MD, Body, ObjCMethodActions);
- break;
- }
+ if (Opts.AnalyzeSpecificFunction.size() > 0 &&
+ Opts.AnalyzeSpecificFunction != MD->getSelector().getAsString())
+ return;
+
+ Stmt* Body = MD->getBody();
+ if (Body) HandleCode(MD, Body, ObjCMethodActions);
+ break;
+ }
- case Decl::CXXMethod: {
- CXXMethodDecl *CXXMD = cast<CXXMethodDecl>(D);
+ case Decl::CXXConstructor:
+ case Decl::CXXDestructor:
+ case Decl::CXXConversion:
+ case Decl::CXXMethod: {
+ CXXMethodDecl *CXXMD = cast<CXXMethodDecl>(D);
- if (Opts.AnalyzeSpecificFunction.size() > 0 &&
- Opts.AnalyzeSpecificFunction != CXXMD->getName())
- return;
+ if (Opts.AnalyzeSpecificFunction.size() > 0 &&
+ Opts.AnalyzeSpecificFunction != CXXMD->getName())
+ return;
- Stmt *Body = CXXMD->getBody();
- if (Body)
- HandleCode(CXXMD, Body, FunctionActions);
- break;
- }
+ Stmt *Body = CXXMD->getBody();
+ if (Body) HandleCode(CXXMD, Body, FunctionActions);
+ break;
+ }
- default:
- break;
+ default:
+ break;
}
}
@@ -409,20 +411,20 @@ static void ActionCheckerCFRef(AnalysisConsumer &C, AnalysisManager& mgr,
Decl *D) {
switch (mgr.getLangOptions().getGCMode()) {
- default:
- assert (false && "Invalid GC mode.");
- case LangOptions::NonGC:
- ActionCheckerCFRefAux(C, mgr, D, false);
- break;
-
- case LangOptions::GCOnly:
- ActionCheckerCFRefAux(C, mgr, D, true);
- break;
-
- case LangOptions::HybridGC:
- ActionCheckerCFRefAux(C, mgr, D, false);
- ActionCheckerCFRefAux(C, mgr, D, true);
- break;
+ default:
+ assert (false && "Invalid GC mode.");
+ case LangOptions::NonGC:
+ ActionCheckerCFRefAux(C, mgr, D, false);
+ break;
+
+ case LangOptions::GCOnly:
+ ActionCheckerCFRefAux(C, mgr, D, true);
+ break;
+
+ case LangOptions::HybridGC:
+ ActionCheckerCFRefAux(C, mgr, D, false);
+ ActionCheckerCFRefAux(C, mgr, D, true);
+ break;
}
}
@@ -530,11 +532,11 @@ ASTConsumer* clang::CreateAnalysisConsumer(const Preprocessor& pp,
for (unsigned i = 0; i < Opts.AnalysisList.size(); ++i)
switch (Opts.AnalysisList[i]) {
#define ANALYSIS(NAME, CMD, DESC, SCOPE)\
- case NAME:\
- C->add ## SCOPE ## Action(&Action ## NAME);\
- break;
+ case NAME:\
+ C->add ## SCOPE ## Action(&Action ## NAME);\
+ break;
#include "clang/Frontend/Analyses.def"
- default: break;
+ default: break;
}
// Last, disable the effects of '-Werror' when using the AnalysisConsumer.
diff --git a/lib/Frontend/CacheTokens.cpp b/lib/Frontend/CacheTokens.cpp
index 7296246..7326937 100644
--- a/lib/Frontend/CacheTokens.cpp
+++ b/lib/Frontend/CacheTokens.cpp
@@ -77,25 +77,25 @@ public:
void EmitData(llvm::raw_ostream& Out) {
switch (Kind) {
- case IsFE:
- // Emit stat information.
- ::Emit32(Out, FE->getInode());
- ::Emit32(Out, FE->getDevice());
- ::Emit16(Out, FE->getFileMode());
- ::Emit64(Out, FE->getModificationTime());
- ::Emit64(Out, FE->getSize());
- break;
- case IsDE:
- // Emit stat information.
- ::Emit32(Out, (uint32_t) StatBuf->st_ino);
- ::Emit32(Out, (uint32_t) StatBuf->st_dev);
- ::Emit16(Out, (uint16_t) StatBuf->st_mode);
- ::Emit64(Out, (uint64_t) StatBuf->st_mtime);
- ::Emit64(Out, (uint64_t) StatBuf->st_size);
- delete StatBuf;
- break;
- default:
- break;
+ case IsFE:
+ // Emit stat information.
+ ::Emit32(Out, FE->getInode());
+ ::Emit32(Out, FE->getDevice());
+ ::Emit16(Out, FE->getFileMode());
+ ::Emit64(Out, FE->getModificationTime());
+ ::Emit64(Out, FE->getSize());
+ break;
+ case IsDE:
+ // Emit stat information.
+ ::Emit32(Out, (uint32_t) StatBuf->st_ino);
+ ::Emit32(Out, (uint32_t) StatBuf->st_dev);
+ ::Emit16(Out, (uint16_t) StatBuf->st_mode);
+ ::Emit64(Out, (uint64_t) StatBuf->st_mtime);
+ ::Emit64(Out, (uint64_t) StatBuf->st_size);
+ delete StatBuf;
+ break;
+ default:
+ break;
}
}
diff --git a/lib/Frontend/DeclXML.cpp b/lib/Frontend/DeclXML.cpp
index b981fc4..d7470d9 100644
--- a/lib/Frontend/DeclXML.cpp
+++ b/lib/Frontend/DeclXML.cpp
@@ -98,14 +98,14 @@ public:
const char* pAttributeName = NAME; \
const bool optional = false; \
switch (T->FN) { \
- default: assert(0 && "unknown enum value");
+ default: assert(0 && "unknown enum value");
#define ATTRIBUTE_ENUM_OPT_XML( FN, NAME ) \
{ \
const char* pAttributeName = NAME; \
const bool optional = true; \
switch (T->FN) { \
- default: assert(0 && "unknown enum value");
+ default: assert(0 && "unknown enum value");
#define ENUM_XML( VALUE, NAME ) case VALUE: if ((!optional) || NAME[0]) Doc.addAttribute(pAttributeName, NAME); break;
#define END_ENUM_XML } }
diff --git a/lib/Frontend/HTMLDiagnostics.cpp b/lib/Frontend/HTMLDiagnostics.cpp
index 93421ca..b163e26 100644
--- a/lib/Frontend/HTMLDiagnostics.cpp
+++ b/lib/Frontend/HTMLDiagnostics.cpp
@@ -349,10 +349,10 @@ void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID,
const char *Kind = 0;
switch (P.getKind()) {
- case PathDiagnosticPiece::Event: Kind = "Event"; break;
- case PathDiagnosticPiece::ControlFlow: Kind = "Control"; break;
- // Setting Kind to "Control" is intentional.
- case PathDiagnosticPiece::Macro: Kind = "Control"; break;
+ case PathDiagnosticPiece::Event: Kind = "Event"; break;
+ case PathDiagnosticPiece::ControlFlow: Kind = "Control"; break;
+ // Setting Kind to "Control" is intentional.
+ case PathDiagnosticPiece::Macro: Kind = "Control"; break;
}
std::string sbuf;
@@ -380,14 +380,14 @@ void HTMLDiagnostics::HandlePiece(Rewriter& R, FileID BugFileID,
for (std::string::const_iterator I=Msg.begin(), E=Msg.end(); I!=E; ++I)
switch (*I) {
- default:
- ++cnt;
- continue;
- case ' ':
- case '\t':
- case '\n':
- if (cnt > max_token) max_token = cnt;
- cnt = 0;
+ default:
+ ++cnt;
+ continue;
+ case ' ':
+ case '\t':
+ case '\n':
+ if (cnt > max_token) max_token = cnt;
+ cnt = 0;
}
if (cnt > max_token)
diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp
index 6fceb98..6102760 100644
--- a/lib/Frontend/InitHeaderSearch.cpp
+++ b/lib/Frontend/InitHeaderSearch.cpp
@@ -189,10 +189,12 @@ void InitHeaderSearch::AddGnuCPlusPlusIncludePaths(llvm::StringRef Base,
void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(llvm::StringRef Base,
llvm::StringRef Arch,
llvm::StringRef Version) {
- llvm::Twine localBase = Base + "/" + Arch + "/" + Version + "/include";
- AddPath(localBase, System, true, false, false);
- AddPath(localBase + "/c++", System, true, false, false);
- AddPath(localBase + "/c++/backward", System, true, false, false);
+ AddPath(Base + "/" + Arch + "/" + Version + "/include",
+ System, true, false, false);
+ AddPath(Base + "/" + Arch + "/" + Version + "/include/c++",
+ System, true, false, false);
+ AddPath(Base + "/" + Arch + "/" + Version + "/include/c++/backward",
+ System, true, false, false);
}
// FIXME: This probably should goto to some platform utils place.
@@ -206,8 +208,8 @@ void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(llvm::StringRef Base,
// I.e. "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\$VERSION".
// There can be additional characters in the component. Only the numberic
// characters are compared.
-bool getSystemRegistryString(const char *keyPath, const char *valueName,
- char *value, size_t maxLength) {
+static bool getSystemRegistryString(const char *keyPath, const char *valueName,
+ char *value, size_t maxLength) {
HKEY hRootKey = NULL;
HKEY hKey = NULL;
const char* subKey = NULL;
@@ -312,13 +314,13 @@ bool getSystemRegistryString(const char *keyPath, const char *valueName,
}
#else // _MSC_VER
// Read registry string.
-bool getSystemRegistryString(const char *, const char *, char *, size_t) {
+static bool getSystemRegistryString(const char*, const char*, char*, size_t) {
return(false);
}
#endif // _MSC_VER
// Get Visual Studio installation directory.
-bool getVisualStudioDir(std::string &path) {
+static bool getVisualStudioDir(std::string &path) {
char vsIDEInstallDir[256];
// Try the Windows registry first.
bool hasVCDir = getSystemRegistryString(
@@ -365,7 +367,7 @@ bool getVisualStudioDir(std::string &path) {
}
// Get Windows SDK installation directory.
-bool getWindowsSDKDir(std::string &path) {
+static bool getWindowsSDKDir(std::string &path) {
char windowsSDKInstallDir[256];
// Try the Windows registry.
bool hasSDKDir = getSystemRegistryString(
@@ -508,6 +510,10 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &tripl
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.2",
"i386-redhat-linux","", "", triple);
+ // Fedora 10 x86_64
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.2",
+ "x86_64-redhat-linux", "32", "", triple);
+
// Fedora 11
AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4.1",
"i586-redhat-linux","", "", triple);
@@ -556,7 +562,7 @@ void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(const llvm::Triple &tripl
"i686-pc-linux-gnu", "", "", triple);
break;
case llvm::Triple::FreeBSD:
- AddPath("/usr/include/c++/4.2", System, true, false, false);
+ AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2", "", "", "", triple);
break;
case llvm::Triple::Solaris:
// Solaris - Fall though..
diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp
index e4c380a..9aaf132 100644
--- a/lib/Frontend/InitPreprocessor.cpp
+++ b/lib/Frontend/InitPreprocessor.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/Utils.h"
+#include "clang/Basic/MacroBuilder.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/FrontendOptions.h"
@@ -137,7 +138,10 @@ static void DefineFloatMacros(MacroBuilder &Builder, llvm::StringRef Prefix,
"1.79769313486231580793728971405301e+308L",
"1.18973149535723176508575932662800702e+4932L");
- llvm::Twine DefPrefix = "__" + Prefix + "_";
+ llvm::SmallString<32> DefPrefix;
+ DefPrefix = "__";
+ DefPrefix += Prefix;
+ DefPrefix += "_";
Builder.defineMacro(DefPrefix + "DENORM_MIN__", DenormMin);
Builder.defineMacro(DefPrefix + "HAS_DENORM__");
@@ -420,40 +424,61 @@ static void InitializeFileRemapping(Diagnostic &Diags,
SourceManager &SourceMgr,
FileManager &FileMgr,
const PreprocessorOptions &InitOpts) {
- // Remap files in the source manager.
+ // Remap files in the source manager (with buffers).
+ for (PreprocessorOptions::remapped_file_buffer_iterator
+ Remap = InitOpts.remapped_file_buffer_begin(),
+ RemapEnd = InitOpts.remapped_file_buffer_end();
+ Remap != RemapEnd;
+ ++Remap) {
+ // Create the file entry for the file that we're mapping from.
+ const FileEntry *FromFile = FileMgr.getVirtualFile(Remap->first,
+ Remap->second->getBufferSize(),
+ 0);
+ if (!FromFile) {
+ Diags.Report(diag::err_fe_remap_missing_from_file)
+ << Remap->first;
+ continue;
+ }
+
+ // Override the contents of the "from" file with the contents of
+ // the "to" file.
+ SourceMgr.overrideFileContents(FromFile, Remap->second);
+ }
+
+ // Remap files in the source manager (with other files).
for (PreprocessorOptions::remapped_file_iterator
- Remap = InitOpts.remapped_file_begin(),
- RemapEnd = InitOpts.remapped_file_end();
+ Remap = InitOpts.remapped_file_begin(),
+ RemapEnd = InitOpts.remapped_file_end();
Remap != RemapEnd;
++Remap) {
// Find the file that we're mapping to.
const FileEntry *ToFile = FileMgr.getFile(Remap->second);
if (!ToFile) {
Diags.Report(diag::err_fe_remap_missing_to_file)
- << Remap->first << Remap->second;
+ << Remap->first << Remap->second;
continue;
}
-
+
// Create the file entry for the file that we're mapping from.
const FileEntry *FromFile = FileMgr.getVirtualFile(Remap->first,
ToFile->getSize(),
0);
if (!FromFile) {
Diags.Report(diag::err_fe_remap_missing_from_file)
- << Remap->first;
+ << Remap->first;
continue;
}
-
+
// Load the contents of the file we're mapping to.
std::string ErrorStr;
const llvm::MemoryBuffer *Buffer
- = llvm::MemoryBuffer::getFile(ToFile->getName(), &ErrorStr);
+ = llvm::MemoryBuffer::getFile(ToFile->getName(), &ErrorStr);
if (!Buffer) {
Diags.Report(diag::err_fe_error_opening)
- << Remap->second << ErrorStr;
+ << Remap->second << ErrorStr;
continue;
}
-
+
// Override the contents of the "from" file with the contents of
// the "to" file.
SourceMgr.overrideFileContents(FromFile, Buffer);
diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp
index 07d5a78..2593551 100644
--- a/lib/Frontend/PCHReader.cpp
+++ b/lib/Frontend/PCHReader.cpp
@@ -1399,17 +1399,10 @@ PCHReader::ReadPCHBlock() {
NumComments = BlobLen / sizeof(SourceRange);
break;
- case pch::SVN_BRANCH_REVISION: {
- unsigned CurRevision = getClangSubversionRevision();
- if (Record[0] && CurRevision && Record[0] != CurRevision) {
- Diag(Record[0] < CurRevision? diag::warn_pch_version_too_old
- : diag::warn_pch_version_too_new);
- return IgnorePCH;
- }
-
- const char *CurBranch = getClangSubversionPath();
- if (strncmp(CurBranch, BlobStart, BlobLen)) {
- std::string PCHBranch(BlobStart, BlobLen);
+ case pch::VERSION_CONTROL_BRANCH_REVISION: {
+ llvm::StringRef CurBranch = getClangFullRepositoryVersion();
+ llvm::StringRef PCHBranch(BlobStart, BlobLen);
+ if (CurBranch != PCHBranch) {
Diag(diag::warn_pch_different_branch) << PCHBranch << CurBranch;
return IgnorePCH;
}
@@ -1909,18 +1902,20 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) {
}
case pch::TYPE_FUNCTION_NO_PROTO: {
- if (Record.size() != 2) {
+ if (Record.size() != 3) {
Error("incorrect encoding of no-proto function type");
return QualType();
}
QualType ResultType = GetType(Record[0]);
- return Context->getFunctionNoProtoType(ResultType, Record[1]);
+ return Context->getFunctionNoProtoType(ResultType, Record[1],
+ (CallingConv)Record[2]);
}
case pch::TYPE_FUNCTION_PROTO: {
QualType ResultType = GetType(Record[0]);
bool NoReturn = Record[1];
- unsigned Idx = 2;
+ CallingConv CallConv = (CallingConv)Record[2];
+ unsigned Idx = 3;
unsigned NumParams = Record[Idx++];
llvm::SmallVector<QualType, 16> ParamTypes;
for (unsigned I = 0; I != NumParams; ++I)
@@ -1936,7 +1931,7 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) {
return Context->getFunctionType(ResultType, ParamTypes.data(), NumParams,
isVariadic, Quals, hasExceptionSpec,
hasAnyExceptionSpec, NumExceptions,
- Exceptions.data(), NoReturn);
+ Exceptions.data(), NoReturn, CallConv);
}
case pch::TYPE_UNRESOLVED_USING:
@@ -2040,7 +2035,13 @@ void TypeLocReader::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) {
// nothing to do
}
void TypeLocReader::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) {
- TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ TL.setBuiltinLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ if (TL.needsExtraLocalData()) {
+ TL.setWrittenTypeSpec(static_cast<DeclSpec::TST>(Record[Idx++]));
+ TL.setWrittenSignSpec(static_cast<DeclSpec::TSS>(Record[Idx++]));
+ TL.setWrittenWidthSpec(static_cast<DeclSpec::TSW>(Record[Idx++]));
+ TL.setModeAttr(Record[Idx++]);
+ }
}
void TypeLocReader::VisitComplexTypeLoc(ComplexTypeLoc TL) {
TL.setNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp
index 69343ed..4dc1318 100644
--- a/lib/Frontend/PCHReaderDecl.cpp
+++ b/lib/Frontend/PCHReaderDecl.cpp
@@ -223,7 +223,12 @@ void PCHDeclReader::VisitObjCInterfaceDecl(ObjCInterfaceDecl *ID) {
Protocols.reserve(NumProtocols);
for (unsigned I = 0; I != NumProtocols; ++I)
Protocols.push_back(cast<ObjCProtocolDecl>(Reader.GetDecl(Record[Idx++])));
- ID->setProtocolList(Protocols.data(), NumProtocols, *Reader.getContext());
+ llvm::SmallVector<SourceLocation, 16> ProtoLocs;
+ ProtoLocs.reserve(NumProtocols);
+ for (unsigned I = 0; I != NumProtocols; ++I)
+ ProtoLocs.push_back(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ ID->setProtocolList(Protocols.data(), NumProtocols, ProtoLocs.data(),
+ *Reader.getContext());
unsigned NumIvars = Record[Idx++];
llvm::SmallVector<ObjCIvarDecl *, 16> IVars;
IVars.reserve(NumIvars);
@@ -253,7 +258,12 @@ void PCHDeclReader::VisitObjCProtocolDecl(ObjCProtocolDecl *PD) {
ProtoRefs.reserve(NumProtoRefs);
for (unsigned I = 0; I != NumProtoRefs; ++I)
ProtoRefs.push_back(cast<ObjCProtocolDecl>(Reader.GetDecl(Record[Idx++])));
- PD->setProtocolList(ProtoRefs.data(), NumProtoRefs, *Reader.getContext());
+ llvm::SmallVector<SourceLocation, 16> ProtoLocs;
+ ProtoLocs.reserve(NumProtoRefs);
+ for (unsigned I = 0; I != NumProtoRefs; ++I)
+ ProtoLocs.push_back(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ PD->setProtocolList(ProtoRefs.data(), NumProtoRefs, ProtoLocs.data(),
+ *Reader.getContext());
}
void PCHDeclReader::VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *FD) {
@@ -282,7 +292,12 @@ void PCHDeclReader::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *FPD) {
ProtoRefs.reserve(NumProtoRefs);
for (unsigned I = 0; I != NumProtoRefs; ++I)
ProtoRefs.push_back(cast<ObjCProtocolDecl>(Reader.GetDecl(Record[Idx++])));
- FPD->setProtocolList(ProtoRefs.data(), NumProtoRefs, *Reader.getContext());
+ llvm::SmallVector<SourceLocation, 16> ProtoLocs;
+ ProtoLocs.reserve(NumProtoRefs);
+ for (unsigned I = 0; I != NumProtoRefs; ++I)
+ ProtoLocs.push_back(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ FPD->setProtocolList(ProtoRefs.data(), NumProtoRefs, ProtoLocs.data(),
+ *Reader.getContext());
}
void PCHDeclReader::VisitObjCCategoryDecl(ObjCCategoryDecl *CD) {
@@ -293,9 +308,15 @@ void PCHDeclReader::VisitObjCCategoryDecl(ObjCCategoryDecl *CD) {
ProtoRefs.reserve(NumProtoRefs);
for (unsigned I = 0; I != NumProtoRefs; ++I)
ProtoRefs.push_back(cast<ObjCProtocolDecl>(Reader.GetDecl(Record[Idx++])));
- CD->setProtocolList(ProtoRefs.data(), NumProtoRefs, *Reader.getContext());
+ llvm::SmallVector<SourceLocation, 16> ProtoLocs;
+ ProtoLocs.reserve(NumProtoRefs);
+ for (unsigned I = 0; I != NumProtoRefs; ++I)
+ ProtoLocs.push_back(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ CD->setProtocolList(ProtoRefs.data(), NumProtoRefs, ProtoLocs.data(),
+ *Reader.getContext());
CD->setNextClassCategory(cast_or_null<ObjCCategoryDecl>(Reader.GetDecl(Record[Idx++])));
- CD->setLocEnd(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ CD->setAtLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ CD->setCategoryNameLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
}
void PCHDeclReader::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *CAD) {
@@ -305,6 +326,7 @@ void PCHDeclReader::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *CAD) {
void PCHDeclReader::VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
VisitNamedDecl(D);
+ D->setAtLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
D->setType(Reader.GetType(Record[Idx++]));
// FIXME: stable encoding
D->setPropertyAttributes(
@@ -671,7 +693,8 @@ Decl *PCHReader::ReadDeclRecord(uint64_t Offset, unsigned Index) {
D = ObjCForwardProtocolDecl::Create(*Context, 0, SourceLocation());
break;
case pch::DECL_OBJC_CATEGORY:
- D = ObjCCategoryDecl::Create(*Context, 0, SourceLocation(), 0);
+ D = ObjCCategoryDecl::Create(*Context, 0, SourceLocation(),
+ SourceLocation(), SourceLocation(), 0);
break;
case pch::DECL_OBJC_CATEGORY_IMPL:
D = ObjCCategoryImplDecl::Create(*Context, 0, SourceLocation(), 0, 0);
@@ -683,7 +706,8 @@ Decl *PCHReader::ReadDeclRecord(uint64_t Offset, unsigned Index) {
D = ObjCCompatibleAliasDecl::Create(*Context, 0, SourceLocation(), 0, 0);
break;
case pch::DECL_OBJC_PROPERTY:
- D = ObjCPropertyDecl::Create(*Context, 0, SourceLocation(), 0, QualType());
+ D = ObjCPropertyDecl::Create(*Context, 0, SourceLocation(), 0, SourceLocation(),
+ QualType());
break;
case pch::DECL_OBJC_PROPERTY_IMPL:
D = ObjCPropertyImplDecl::Create(*Context, 0, SourceLocation(),
diff --git a/lib/Frontend/PCHReaderStmt.cpp b/lib/Frontend/PCHReaderStmt.cpp
index 138f1e1..21c9cbf 100644
--- a/lib/Frontend/PCHReaderStmt.cpp
+++ b/lib/Frontend/PCHReaderStmt.cpp
@@ -117,6 +117,12 @@ namespace {
unsigned VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E);
unsigned VisitCXXConstructExpr(CXXConstructExpr *E);
+ unsigned VisitCXXNamedCastExpr(CXXNamedCastExpr *E);
+ unsigned VisitCXXStaticCastExpr(CXXStaticCastExpr *E);
+ unsigned VisitCXXDynamicCastExpr(CXXDynamicCastExpr *E);
+ unsigned VisitCXXReinterpretCastExpr(CXXReinterpretCastExpr *E);
+ unsigned VisitCXXConstCastExpr(CXXConstCastExpr *E);
+ unsigned VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E);
};
}
@@ -513,7 +519,7 @@ unsigned PCHStmtReader::VisitImplicitCastExpr(ImplicitCastExpr *E) {
unsigned PCHStmtReader::VisitExplicitCastExpr(ExplicitCastExpr *E) {
VisitCastExpr(E);
- E->setTypeAsWritten(Reader.GetType(Record[Idx++]));
+ E->setTypeInfoAsWritten(Reader.GetTypeSourceInfo(Record, Idx));
return 1;
}
@@ -527,6 +533,7 @@ unsigned PCHStmtReader::VisitCStyleCastExpr(CStyleCastExpr *E) {
unsigned PCHStmtReader::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
VisitExpr(E);
E->setLParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setTypeSourceInfo(Reader.GetTypeSourceInfo(Record, Idx));
E->setInitializer(cast<Expr>(StmtStack.back()));
E->setFileScope(Record[Idx++]);
return 1;
@@ -868,6 +875,35 @@ unsigned PCHStmtReader::VisitCXXConstructExpr(CXXConstructExpr *E) {
return E->getNumArgs();
}
+unsigned PCHStmtReader::VisitCXXNamedCastExpr(CXXNamedCastExpr *E) {
+ unsigned num = VisitExplicitCastExpr(E);
+ E->setOperatorLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ return num;
+}
+
+unsigned PCHStmtReader::VisitCXXStaticCastExpr(CXXStaticCastExpr *E) {
+ return VisitCXXNamedCastExpr(E);
+}
+
+unsigned PCHStmtReader::VisitCXXDynamicCastExpr(CXXDynamicCastExpr *E) {
+ return VisitCXXNamedCastExpr(E);
+}
+
+unsigned PCHStmtReader::VisitCXXReinterpretCastExpr(CXXReinterpretCastExpr *E) {
+ return VisitCXXNamedCastExpr(E);
+}
+
+unsigned PCHStmtReader::VisitCXXConstCastExpr(CXXConstCastExpr *E) {
+ return VisitCXXNamedCastExpr(E);
+}
+
+unsigned PCHStmtReader::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E) {
+ unsigned num = VisitExplicitCastExpr(E);
+ E->setTypeBeginLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ E->setRParenLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
+ return num;
+}
+
// Within the bitstream, expressions are stored in Reverse Polish
// Notation, with each of the subexpressions preceding the
// expression they are stored in. To evaluate expressions, we
@@ -1176,6 +1212,28 @@ Stmt *PCHReader::ReadStmt(llvm::BitstreamCursor &Cursor) {
S = new (Context) CXXConstructExpr(Empty, *Context,
Record[PCHStmtReader::NumExprFields + 2]);
break;
+
+ case pch::EXPR_CXX_STATIC_CAST:
+ S = new (Context) CXXStaticCastExpr(Empty);
+ break;
+
+ case pch::EXPR_CXX_DYNAMIC_CAST:
+ S = new (Context) CXXDynamicCastExpr(Empty);
+ break;
+
+ case pch::EXPR_CXX_REINTERPRET_CAST:
+ S = new (Context) CXXReinterpretCastExpr(Empty);
+ break;
+
+ case pch::EXPR_CXX_CONST_CAST:
+ S = new (Context) CXXConstCastExpr(Empty);
+ break;
+
+ case pch::EXPR_CXX_FUNCTIONAL_CAST:
+ S = new (Context) CXXFunctionalCastExpr(Empty);
+ break;
+
+
}
// We hit a STMT_STOP, so we're done with this expression.
diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp
index 3f6841b..9909c95 100644
--- a/lib/Frontend/PCHWriter.cpp
+++ b/lib/Frontend/PCHWriter.cpp
@@ -139,6 +139,8 @@ void PCHTypeWriter::VisitExtVectorType(const ExtVectorType *T) {
void PCHTypeWriter::VisitFunctionType(const FunctionType *T) {
Writer.AddTypeRef(T->getResultType(), Record);
Record.push_back(T->getNoReturnAttr());
+ // FIXME: need to stabilize encoding of calling convention...
+ Record.push_back(T->getCallConv());
}
void PCHTypeWriter::VisitFunctionNoProtoType(const FunctionNoProtoType *T) {
@@ -275,7 +277,13 @@ void TypeLocWriter::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) {
// nothing to do
}
void TypeLocWriter::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) {
- Writer.AddSourceLocation(TL.getNameLoc(), Record);
+ Writer.AddSourceLocation(TL.getBuiltinLoc(), Record);
+ if (TL.needsExtraLocalData()) {
+ Record.push_back(TL.getWrittenTypeSpec());
+ Record.push_back(TL.getWrittenSignSpec());
+ Record.push_back(TL.getWrittenWidthSpec());
+ Record.push_back(TL.hasModeAttr());
+ }
}
void TypeLocWriter::VisitComplexTypeLoc(ComplexTypeLoc TL) {
Writer.AddSourceLocation(TL.getNameLoc(), Record);
@@ -535,7 +543,7 @@ void PCHWriter::WriteBlockInfoBlock() {
RECORD(STAT_CACHE);
RECORD(EXT_VECTOR_DECLS);
RECORD(COMMENT_RANGES);
- RECORD(SVN_BRANCH_REVISION);
+ RECORD(VERSION_CONTROL_BRANCH_REVISION);
// SourceManager Block.
BLOCK(SOURCE_MANAGER_BLOCK);
@@ -699,16 +707,15 @@ void PCHWriter::WriteMetadata(ASTContext &Context, const char *isysroot) {
Stream.EmitRecordWithBlob(FileAbbrevCode, Record, MainFileNameStr);
}
- // Subversion branch/version information.
- BitCodeAbbrev *SvnAbbrev = new BitCodeAbbrev();
- SvnAbbrev->Add(BitCodeAbbrevOp(pch::SVN_BRANCH_REVISION));
- SvnAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // SVN revision
- SvnAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // SVN branch/tag
- unsigned SvnAbbrevCode = Stream.EmitAbbrev(SvnAbbrev);
+ // Repository branch/version information.
+ BitCodeAbbrev *RepoAbbrev = new BitCodeAbbrev();
+ RepoAbbrev->Add(BitCodeAbbrevOp(pch::VERSION_CONTROL_BRANCH_REVISION));
+ RepoAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // SVN branch/tag
+ unsigned RepoAbbrevCode = Stream.EmitAbbrev(RepoAbbrev);
Record.clear();
- Record.push_back(pch::SVN_BRANCH_REVISION);
- Record.push_back(getClangSubversionRevision());
- Stream.EmitRecordWithBlob(SvnAbbrevCode, Record, getClangSubversionPath());
+ Record.push_back(pch::VERSION_CONTROL_BRANCH_REVISION);
+ Stream.EmitRecordWithBlob(RepoAbbrevCode, Record,
+ getClangFullRepositoryVersion());
}
/// \brief Write the LangOptions structure.
@@ -1263,7 +1270,7 @@ void PCHWriter::WriteType(QualType T) {
// For all of the concrete, non-dependent types, call the
// appropriate visitor function.
#define TYPE(Class, Base) \
- case Type::Class: W.Visit##Class##Type(cast<Class##Type>(T)); break;
+ case Type::Class: W.Visit##Class##Type(cast<Class##Type>(T)); break;
#define ABSTRACT_TYPE(Class, Base)
#define DEPENDENT_TYPE(Class, Base)
#include "clang/AST/TypeNodes.def"
diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp
index 2dbcc27..020f69b 100644
--- a/lib/Frontend/PCHWriterDecl.cpp
+++ b/lib/Frontend/PCHWriterDecl.cpp
@@ -223,6 +223,10 @@ void PCHDeclWriter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) {
PEnd = D->protocol_end();
P != PEnd; ++P)
Writer.AddDeclRef(*P, Record);
+ for (ObjCInterfaceDecl::protocol_loc_iterator PL = D->protocol_loc_begin(),
+ PLEnd = D->protocol_loc_end();
+ PL != PLEnd; ++PL)
+ Writer.AddSourceLocation(*PL, Record);
Record.push_back(D->ivar_size());
for (ObjCInterfaceDecl::ivar_iterator I = D->ivar_begin(),
IEnd = D->ivar_end(); I != IEnd; ++I)
@@ -251,6 +255,10 @@ void PCHDeclWriter::VisitObjCProtocolDecl(ObjCProtocolDecl *D) {
for (ObjCProtocolDecl::protocol_iterator
I = D->protocol_begin(), IEnd = D->protocol_end(); I != IEnd; ++I)
Writer.AddDeclRef(*I, Record);
+ for (ObjCProtocolDecl::protocol_loc_iterator PL = D->protocol_loc_begin(),
+ PLEnd = D->protocol_loc_end();
+ PL != PLEnd; ++PL)
+ Writer.AddSourceLocation(*PL, Record);
Code = pch::DECL_OBJC_PROTOCOL;
}
@@ -272,9 +280,13 @@ void PCHDeclWriter::VisitObjCClassDecl(ObjCClassDecl *D) {
void PCHDeclWriter::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D) {
VisitDecl(D);
Record.push_back(D->protocol_size());
- for (ObjCProtocolDecl::protocol_iterator
+ for (ObjCForwardProtocolDecl::protocol_iterator
I = D->protocol_begin(), IEnd = D->protocol_end(); I != IEnd; ++I)
Writer.AddDeclRef(*I, Record);
+ for (ObjCForwardProtocolDecl::protocol_loc_iterator
+ PL = D->protocol_loc_begin(), PLEnd = D->protocol_loc_end();
+ PL != PLEnd; ++PL)
+ Writer.AddSourceLocation(*PL, Record);
Code = pch::DECL_OBJC_FORWARD_PROTOCOL;
}
@@ -282,11 +294,16 @@ void PCHDeclWriter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) {
VisitObjCContainerDecl(D);
Writer.AddDeclRef(D->getClassInterface(), Record);
Record.push_back(D->protocol_size());
- for (ObjCProtocolDecl::protocol_iterator
+ for (ObjCCategoryDecl::protocol_iterator
I = D->protocol_begin(), IEnd = D->protocol_end(); I != IEnd; ++I)
Writer.AddDeclRef(*I, Record);
+ for (ObjCCategoryDecl::protocol_loc_iterator
+ PL = D->protocol_loc_begin(), PLEnd = D->protocol_loc_end();
+ PL != PLEnd; ++PL)
+ Writer.AddSourceLocation(*PL, Record);
Writer.AddDeclRef(D->getNextClassCategory(), Record);
- Writer.AddSourceLocation(D->getLocEnd(), Record);
+ Writer.AddSourceLocation(D->getAtLoc(), Record);
+ Writer.AddSourceLocation(D->getCategoryNameLoc(), Record);
Code = pch::DECL_OBJC_CATEGORY;
}
@@ -298,6 +315,7 @@ void PCHDeclWriter::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D) {
void PCHDeclWriter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
VisitNamedDecl(D);
+ Writer.AddSourceLocation(D->getAtLoc(), Record);
Writer.AddTypeRef(D->getType(), Record);
// FIXME: stable encoding
Record.push_back((unsigned)D->getPropertyAttributes());
diff --git a/lib/Frontend/PCHWriterStmt.cpp b/lib/Frontend/PCHWriterStmt.cpp
index 4be9b81..fdfdfef 100644
--- a/lib/Frontend/PCHWriterStmt.cpp
+++ b/lib/Frontend/PCHWriterStmt.cpp
@@ -112,6 +112,12 @@ namespace {
// C++ Statements
void VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E);
void VisitCXXConstructExpr(CXXConstructExpr *E);
+ void VisitCXXNamedCastExpr(CXXNamedCastExpr *E);
+ void VisitCXXStaticCastExpr(CXXStaticCastExpr *E);
+ void VisitCXXDynamicCastExpr(CXXDynamicCastExpr *E);
+ void VisitCXXReinterpretCastExpr(CXXReinterpretCastExpr *E);
+ void VisitCXXConstCastExpr(CXXConstCastExpr *E);
+ void VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E);
};
}
@@ -477,7 +483,7 @@ void PCHStmtWriter::VisitImplicitCastExpr(ImplicitCastExpr *E) {
void PCHStmtWriter::VisitExplicitCastExpr(ExplicitCastExpr *E) {
VisitCastExpr(E);
- Writer.AddTypeRef(E->getTypeAsWritten(), Record);
+ Writer.AddTypeSourceInfo(E->getTypeInfoAsWritten(), Record);
}
void PCHStmtWriter::VisitCStyleCastExpr(CStyleCastExpr *E) {
@@ -490,6 +496,7 @@ void PCHStmtWriter::VisitCStyleCastExpr(CStyleCastExpr *E) {
void PCHStmtWriter::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
VisitExpr(E);
Writer.AddSourceLocation(E->getLParenLoc(), Record);
+ Writer.AddTypeSourceInfo(E->getTypeSourceInfo(), Record);
Writer.WriteSubStmt(E->getInitializer());
Record.push_back(E->isFileScope());
Code = pch::EXPR_COMPOUND_LITERAL;
@@ -795,6 +802,38 @@ void PCHStmtWriter::VisitCXXConstructExpr(CXXConstructExpr *E) {
Code = pch::EXPR_CXX_CONSTRUCT;
}
+void PCHStmtWriter::VisitCXXNamedCastExpr(CXXNamedCastExpr *E) {
+ VisitExplicitCastExpr(E);
+ Writer.AddSourceLocation(E->getOperatorLoc(), Record);
+}
+
+void PCHStmtWriter::VisitCXXStaticCastExpr(CXXStaticCastExpr *E) {
+ VisitCXXNamedCastExpr(E);
+ Code = pch::EXPR_CXX_STATIC_CAST;
+}
+
+void PCHStmtWriter::VisitCXXDynamicCastExpr(CXXDynamicCastExpr *E) {
+ VisitCXXNamedCastExpr(E);
+ Code = pch::EXPR_CXX_DYNAMIC_CAST;
+}
+
+void PCHStmtWriter::VisitCXXReinterpretCastExpr(CXXReinterpretCastExpr *E) {
+ VisitCXXNamedCastExpr(E);
+ Code = pch::EXPR_CXX_REINTERPRET_CAST;
+}
+
+void PCHStmtWriter::VisitCXXConstCastExpr(CXXConstCastExpr *E) {
+ VisitCXXNamedCastExpr(E);
+ Code = pch::EXPR_CXX_CONST_CAST;
+}
+
+void PCHStmtWriter::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E) {
+ VisitExplicitCastExpr(E);
+ Writer.AddSourceLocation(E->getTypeBeginLoc(), Record);
+ Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Code = pch::EXPR_CXX_FUNCTIONAL_CAST;
+}
+
//===----------------------------------------------------------------------===//
// PCHWriter Implementation
//===----------------------------------------------------------------------===//
diff --git a/lib/Frontend/PlistDiagnostics.cpp b/lib/Frontend/PlistDiagnostics.cpp
index 92cafe6..98be869 100644
--- a/lib/Frontend/PlistDiagnostics.cpp
+++ b/lib/Frontend/PlistDiagnostics.cpp
@@ -177,12 +177,12 @@ static llvm::raw_ostream& EmitString(llvm::raw_ostream& o,
for (std::string::const_iterator I=s.begin(), E=s.end(); I!=E; ++I) {
char c = *I;
switch (c) {
- default: o << c; break;
- case '&': o << "&amp;"; break;
- case '<': o << "&lt;"; break;
- case '>': o << "&gt;"; break;
- case '\'': o << "&apos;"; break;
- case '\"': o << "&quot;"; break;
+ default: o << c; break;
+ case '&': o << "&amp;"; break;
+ case '<': o << "&lt;"; break;
+ case '>': o << "&gt;"; break;
+ case '\'': o << "&apos;"; break;
+ case '\"': o << "&quot;"; break;
}
}
o << "</string>";
@@ -289,16 +289,16 @@ static void ReportMacro(llvm::raw_ostream& o,
I!=E; ++I) {
switch ((*I)->getKind()) {
- default:
- break;
- case PathDiagnosticPiece::Event:
- ReportEvent(o, cast<PathDiagnosticEventPiece>(**I), FM, SM, LangOpts,
- indent);
- break;
- case PathDiagnosticPiece::Macro:
- ReportMacro(o, cast<PathDiagnosticMacroPiece>(**I), FM, SM, LangOpts,
- indent);
- break;
+ default:
+ break;
+ case PathDiagnosticPiece::Event:
+ ReportEvent(o, cast<PathDiagnosticEventPiece>(**I), FM, SM, LangOpts,
+ indent);
+ break;
+ case PathDiagnosticPiece::Macro:
+ ReportMacro(o, cast<PathDiagnosticMacroPiece>(**I), FM, SM, LangOpts,
+ indent);
+ break;
}
}
}
@@ -310,18 +310,18 @@ static void ReportDiag(llvm::raw_ostream& o, const PathDiagnosticPiece& P,
unsigned indent = 4;
switch (P.getKind()) {
- case PathDiagnosticPiece::ControlFlow:
- ReportControlFlow(o, cast<PathDiagnosticControlFlowPiece>(P), FM, SM,
- LangOpts, indent);
- break;
- case PathDiagnosticPiece::Event:
- ReportEvent(o, cast<PathDiagnosticEventPiece>(P), FM, SM, LangOpts,
- indent);
- break;
- case PathDiagnosticPiece::Macro:
- ReportMacro(o, cast<PathDiagnosticMacroPiece>(P), FM, SM, LangOpts,
- indent);
- break;
+ case PathDiagnosticPiece::ControlFlow:
+ ReportControlFlow(o, cast<PathDiagnosticControlFlowPiece>(P), FM, SM,
+ LangOpts, indent);
+ break;
+ case PathDiagnosticPiece::Event:
+ ReportEvent(o, cast<PathDiagnosticEventPiece>(P), FM, SM, LangOpts,
+ indent);
+ break;
+ case PathDiagnosticPiece::Macro:
+ ReportMacro(o, cast<PathDiagnosticMacroPiece>(P), FM, SM, LangOpts,
+ indent);
+ break;
}
}
diff --git a/lib/Frontend/PrintParserCallbacks.cpp b/lib/Frontend/PrintParserCallbacks.cpp
index 95afb90..a91dd8d 100644
--- a/lib/Frontend/PrintParserCallbacks.cpp
+++ b/lib/Frontend/PrintParserCallbacks.cpp
@@ -65,6 +65,7 @@ namespace {
SourceLocation SuperLoc,
const DeclPtrTy *ProtoRefs,
unsigned NumProtocols,
+ const SourceLocation *ProtoLocs,
SourceLocation EndProtoLoc,
AttributeList *AttrList) {
Out << __FUNCTION__ << "\n";
@@ -72,7 +73,8 @@ namespace {
ClassName, ClassLoc,
SuperName, SuperLoc,
ProtoRefs, NumProtocols,
- EndProtoLoc, AttrList);
+ ProtoLocs, EndProtoLoc,
+ AttrList);
}
/// ActOnForwardClassDeclaration -
diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp
index d9708d8..43deaee 100644
--- a/lib/Frontend/PrintPreprocessedOutput.cpp
+++ b/lib/Frontend/PrintPreprocessedOutput.cpp
@@ -22,7 +22,7 @@
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/TokenConcatenation.h"
#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/Config/config.h"
#include "llvm/Support/raw_ostream.h"
#include <cstdio>
@@ -443,13 +443,11 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok,
}
}
-namespace {
- struct SortMacrosByID {
- typedef std::pair<IdentifierInfo*, MacroInfo*> id_macro_pair;
- bool operator()(const id_macro_pair &LHS, const id_macro_pair &RHS) const {
- return LHS.first->getName() < RHS.first->getName();
- }
- };
+typedef std::pair<IdentifierInfo*, MacroInfo*> id_macro_pair;
+static int MacroIDCompare(const void* a, const void* b) {
+ const id_macro_pair *LHS = static_cast<const id_macro_pair*>(a);
+ const id_macro_pair *RHS = static_cast<const id_macro_pair*>(b);
+ return LHS->first->getName().compare(RHS->first->getName());
}
static void DoPrintMacros(Preprocessor &PP, llvm::raw_ostream *OS) {
@@ -461,11 +459,9 @@ static void DoPrintMacros(Preprocessor &PP, llvm::raw_ostream *OS) {
do PP.Lex(Tok);
while (Tok.isNot(tok::eof));
- std::vector<std::pair<IdentifierInfo*, MacroInfo*> > MacrosByID;
- for (Preprocessor::macro_iterator I = PP.macro_begin(), E = PP.macro_end();
- I != E; ++I)
- MacrosByID.push_back(*I);
- std::sort(MacrosByID.begin(), MacrosByID.end(), SortMacrosByID());
+ llvm::SmallVector<id_macro_pair, 128>
+ MacrosByID(PP.macro_begin(), PP.macro_end());
+ llvm::array_pod_sort(MacrosByID.begin(), MacrosByID.end(), MacroIDCompare);
for (unsigned i = 0, e = MacrosByID.size(); i != e; ++i) {
MacroInfo &MI = *MacrosByID[i].second;
@@ -473,7 +469,7 @@ static void DoPrintMacros(Preprocessor &PP, llvm::raw_ostream *OS) {
if (MI.isBuiltinMacro()) continue;
PrintMacroDefinition(*MacrosByID[i].first, MI, PP, *OS);
- *OS << "\n";
+ *OS << '\n';
}
}
diff --git a/lib/Frontend/RewriteObjC.cpp b/lib/Frontend/RewriteObjC.cpp
index fc9401d..35d8dde 100644
--- a/lib/Frontend/RewriteObjC.cpp
+++ b/lib/Frontend/RewriteObjC.cpp
@@ -420,6 +420,14 @@ namespace {
}
}
};
+
+ // Helper function: create a CStyleCastExpr with trivial type source info.
+ CStyleCastExpr* NoTypeInfoCStyleCastExpr(ASTContext *Ctx, QualType Ty,
+ CastExpr::CastKind Kind, Expr *E) {
+ TypeSourceInfo *TInfo = Ctx->getTrivialTypeSourceInfo(Ty, SourceLocation());
+ return new (Ctx) CStyleCastExpr(Ty, Kind, E, TInfo,
+ SourceLocation(), SourceLocation());
+ }
}
void RewriteObjC::RewriteBlocksInFunctionProtoType(QualType funcType,
@@ -610,6 +618,7 @@ void RewriteObjC::Initialize(ASTContext &context) {
Preamble += "#undef __OBJC_RW_DLLIMPORT\n";
Preamble += "#undef __OBJC_RW_STATICIMPORT\n";
Preamble += "#define __attribute__(X)\n";
+ Preamble += "#define __weak\n";
}
else {
Preamble += "#define __block\n";
@@ -824,6 +833,10 @@ void RewriteObjC::RewriteForwardClassDecl(ObjCClassDecl *ClassDecl) {
}
void RewriteObjC::RewriteMethodDeclaration(ObjCMethodDecl *Method) {
+ // When method is a synthesized one, such as a getter/setter there is
+ // nothing to rewrite.
+ if (Method->isSynthesized())
+ return;
SourceLocation LocStart = Method->getLocStart();
SourceLocation LocEnd = Method->getLocEnd();
@@ -837,10 +850,9 @@ void RewriteObjC::RewriteMethodDeclaration(ObjCMethodDecl *Method) {
}
void RewriteObjC::RewriteProperty(ObjCPropertyDecl *prop) {
- SourceLocation Loc = prop->getLocation();
+ SourceLocation Loc = prop->getAtLoc();
ReplaceText(Loc, 0, "// ", 3);
-
// FIXME: handle properties that are declared across multiple lines.
}
@@ -1219,11 +1231,9 @@ Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV,
SourceLocation(), II);
assert(RD && "RewriteObjCIvarRefExpr(): Can't find RecordDecl");
QualType castT = Context->getPointerType(Context->getTagDeclType(RD));
- CastExpr *castExpr = new (Context) CStyleCastExpr(castT,
- CastExpr::CK_Unknown,
- IV->getBase(),
- castT,SourceLocation(),
- SourceLocation());
+ CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, castT,
+ CastExpr::CK_Unknown,
+ IV->getBase());
// Don't forget the parens to enforce the proper binding.
ParenExpr *PE = new (Context) ParenExpr(IV->getBase()->getLocStart(),
IV->getBase()->getLocEnd(),
@@ -1267,11 +1277,9 @@ Stmt *RewriteObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV,
SourceLocation(), II);
assert(RD && "RewriteObjCIvarRefExpr(): Can't find RecordDecl");
QualType castT = Context->getPointerType(Context->getTagDeclType(RD));
- CastExpr *castExpr = new (Context) CStyleCastExpr(castT,
- CastExpr::CK_Unknown,
- IV->getBase(),
- castT, SourceLocation(),
- SourceLocation());
+ CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, castT,
+ CastExpr::CK_Unknown,
+ IV->getBase());
// Don't forget the parens to enforce the proper binding.
ParenExpr *PE = new (Context) ParenExpr(IV->getBase()->getLocStart(),
IV->getBase()->getLocEnd(), castExpr);
@@ -1584,12 +1592,9 @@ Stmt *RewriteObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S) {
std::string syncBuf;
syncBuf += " objc_sync_exit(";
- Expr *syncExpr = new (Context) CStyleCastExpr(Context->getObjCIdType(),
- CastExpr::CK_Unknown,
- S->getSynchExpr(),
- Context->getObjCIdType(),
- SourceLocation(),
- SourceLocation());
+ Expr *syncExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),
+ CastExpr::CK_Unknown,
+ S->getSynchExpr());
std::string syncExprBufS;
llvm::raw_string_ostream syncExprBuf(syncExprBufS);
syncExpr->printPretty(syncExprBuf, *Context, 0,
@@ -2332,11 +2337,8 @@ Stmt *RewriteObjC::RewriteObjCStringLiteral(ObjCStringLiteral *Exp) {
Context->getPointerType(DRE->getType()),
SourceLocation());
// cast to NSConstantString *
- CastExpr *cast = new (Context) CStyleCastExpr(Exp->getType(),
- CastExpr::CK_Unknown,
- Unop, Exp->getType(),
- SourceLocation(),
- SourceLocation());
+ CastExpr *cast = NoTypeInfoCStyleCastExpr(Context, Exp->getType(),
+ CastExpr::CK_Unknown, Unop);
ReplaceStmt(Exp, cast);
// delete Exp; leak for now, see RewritePropertySetter() usage for more info.
return cast;
@@ -2465,13 +2467,12 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) {
// set the receiver to self, the first argument to all methods.
InitExprs.push_back(
- new (Context) CStyleCastExpr(Context->getObjCIdType(),
- CastExpr::CK_Unknown,
+ NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),
+ CastExpr::CK_Unknown,
new (Context) DeclRefExpr(CurMethodDef->getSelfDecl(),
Context->getObjCIdType(),
- SourceLocation()),
- Context->getObjCIdType(),
- SourceLocation(), SourceLocation())); // set the 'receiver'.
+ SourceLocation()))
+ ); // set the 'receiver'.
llvm::SmallVector<Expr*, 8> ClsExprs;
QualType argType = Context->getPointerType(Context->CharTy);
@@ -2484,10 +2485,9 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) {
ClsExprs.size());
// To turn off a warning, type-cast to 'id'
InitExprs.push_back( // set 'super class', using objc_getClass().
- new (Context) CStyleCastExpr(Context->getObjCIdType(),
- CastExpr::CK_Unknown,
- Cls, Context->getObjCIdType(),
- SourceLocation(), SourceLocation()));
+ NoTypeInfoCStyleCastExpr(Context,
+ Context->getObjCIdType(),
+ CastExpr::CK_Unknown, Cls));
// struct objc_super
QualType superType = getSuperStructType();
Expr *SuperRep;
@@ -2509,17 +2509,18 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) {
SuperRep = new (Context) UnaryOperator(SuperRep, UnaryOperator::AddrOf,
Context->getPointerType(SuperRep->getType()),
SourceLocation());
- SuperRep = new (Context) CStyleCastExpr(Context->getPointerType(superType),
- CastExpr::CK_Unknown, SuperRep,
- Context->getPointerType(superType),
- SourceLocation(), SourceLocation());
+ SuperRep = NoTypeInfoCStyleCastExpr(Context,
+ Context->getPointerType(superType),
+ CastExpr::CK_Unknown, SuperRep);
} else {
// (struct objc_super) { <exprs from above> }
InitListExpr *ILE = new (Context) InitListExpr(SourceLocation(),
&InitExprs[0], InitExprs.size(),
SourceLocation());
- SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superType, ILE,
- false);
+ TypeSourceInfo *superTInfo
+ = Context->getTrivialTypeSourceInfo(superType);
+ SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superTInfo,
+ superType, ILE, false);
// struct objc_super *
SuperRep = new (Context) UnaryOperator(SuperRep, UnaryOperator::AddrOf,
Context->getPointerType(SuperRep->getType()),
@@ -2551,13 +2552,12 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) {
llvm::SmallVector<Expr*, 4> InitExprs;
InitExprs.push_back(
- new (Context) CStyleCastExpr(Context->getObjCIdType(),
- CastExpr::CK_Unknown,
+ NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),
+ CastExpr::CK_Unknown,
new (Context) DeclRefExpr(CurMethodDef->getSelfDecl(),
Context->getObjCIdType(),
- SourceLocation()),
- Context->getObjCIdType(),
- SourceLocation(), SourceLocation())); // set the 'receiver'.
+ SourceLocation()))
+ ); // set the 'receiver'.
llvm::SmallVector<Expr*, 8> ClsExprs;
QualType argType = Context->getPointerType(Context->CharTy);
@@ -2571,9 +2571,8 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) {
// To turn off a warning, type-cast to 'id'
InitExprs.push_back(
// set 'super class', using objc_getClass().
- new (Context) CStyleCastExpr(Context->getObjCIdType(),
- CastExpr::CK_Unknown,
- Cls, Context->getObjCIdType(), SourceLocation(), SourceLocation()));
+ NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),
+ CastExpr::CK_Unknown, Cls));
// struct objc_super
QualType superType = getSuperStructType();
Expr *SuperRep;
@@ -2595,16 +2594,18 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) {
SuperRep = new (Context) UnaryOperator(SuperRep, UnaryOperator::AddrOf,
Context->getPointerType(SuperRep->getType()),
SourceLocation());
- SuperRep = new (Context) CStyleCastExpr(Context->getPointerType(superType),
- CastExpr::CK_Unknown,
- SuperRep, Context->getPointerType(superType),
- SourceLocation(), SourceLocation());
+ SuperRep = NoTypeInfoCStyleCastExpr(Context,
+ Context->getPointerType(superType),
+ CastExpr::CK_Unknown, SuperRep);
} else {
// (struct objc_super) { <exprs from above> }
InitListExpr *ILE = new (Context) InitListExpr(SourceLocation(),
&InitExprs[0], InitExprs.size(),
SourceLocation());
- SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superType, ILE, false);
+ TypeSourceInfo *superTInfo
+ = Context->getTrivialTypeSourceInfo(superType);
+ SuperRep = new (Context) CompoundLiteralExpr(SourceLocation(), superTInfo,
+ superType, ILE, false);
}
MsgExprs.push_back(SuperRep);
} else {
@@ -2612,10 +2613,8 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) {
// Foo<Proto> *.
while (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(recExpr))
recExpr = CE->getSubExpr();
- recExpr = new (Context) CStyleCastExpr(Context->getObjCIdType(),
- CastExpr::CK_Unknown, recExpr,
- Context->getObjCIdType(),
- SourceLocation(), SourceLocation());
+ recExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),
+ CastExpr::CK_Unknown, recExpr);
MsgExprs.push_back(recExpr);
}
}
@@ -2639,19 +2638,16 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) {
QualType type = ICE->getType()->isObjCQualifiedIdType()
? Context->getObjCIdType()
: ICE->getType();
- userExpr = new (Context) CStyleCastExpr(type, CastExpr::CK_Unknown,
- userExpr, type, SourceLocation(),
- SourceLocation());
+ userExpr = NoTypeInfoCStyleCastExpr(Context, type, CastExpr::CK_Unknown,
+ userExpr);
}
// Make id<P...> cast into an 'id' cast.
else if (CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(userExpr)) {
if (CE->getType()->isObjCQualifiedIdType()) {
while ((CE = dyn_cast<CStyleCastExpr>(userExpr)))
userExpr = CE->getSubExpr();
- userExpr = new (Context) CStyleCastExpr(Context->getObjCIdType(),
- CastExpr::CK_Unknown,
- userExpr, Context->getObjCIdType(),
- SourceLocation(), SourceLocation());
+ userExpr = NoTypeInfoCStyleCastExpr(Context, Context->getObjCIdType(),
+ CastExpr::CK_Unknown, userExpr);
}
}
MsgExprs.push_back(userExpr);
@@ -2701,10 +2697,9 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) {
// If we don't do this cast, we get the following bizarre warning/note:
// xx.m:13: warning: function called through a non-compatible type
// xx.m:13: note: if this code is reached, the program will abort
- cast = new (Context) CStyleCastExpr(Context->getPointerType(Context->VoidTy),
- CastExpr::CK_Unknown, DRE,
- Context->getPointerType(Context->VoidTy),
- SourceLocation(), SourceLocation());
+ cast = NoTypeInfoCStyleCastExpr(Context,
+ Context->getPointerType(Context->VoidTy),
+ CastExpr::CK_Unknown, DRE);
// Now do the "normal" pointer to function cast.
QualType castType = Context->getFunctionType(returnType,
@@ -2712,9 +2707,8 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) {
// If we don't have a method decl, force a variadic cast.
Exp->getMethodDecl() ? Exp->getMethodDecl()->isVariadic() : true, 0);
castType = Context->getPointerType(castType);
- cast = new (Context) CStyleCastExpr(castType, CastExpr::CK_Unknown, cast,
- castType, SourceLocation(),
- SourceLocation());
+ cast = NoTypeInfoCStyleCastExpr(Context, castType, CastExpr::CK_Unknown,
+ cast);
// Don't forget the parens to enforce the proper binding.
ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), cast);
@@ -2734,17 +2728,16 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp) {
DeclRefExpr *STDRE = new (Context) DeclRefExpr(MsgSendStretFlavor, msgSendType,
SourceLocation());
// Need to cast objc_msgSend_stret to "void *" (see above comment).
- cast = new (Context) CStyleCastExpr(Context->getPointerType(Context->VoidTy),
- CastExpr::CK_Unknown, STDRE,
- Context->getPointerType(Context->VoidTy),
- SourceLocation(), SourceLocation());
+ cast = NoTypeInfoCStyleCastExpr(Context,
+ Context->getPointerType(Context->VoidTy),
+ CastExpr::CK_Unknown, STDRE);
// Now do the "normal" pointer to function cast.
castType = Context->getFunctionType(returnType,
&ArgTypes[0], ArgTypes.size(),
Exp->getMethodDecl() ? Exp->getMethodDecl()->isVariadic() : false, 0);
castType = Context->getPointerType(castType);
- cast = new (Context) CStyleCastExpr(castType, CastExpr::CK_Unknown,
- cast, castType, SourceLocation(), SourceLocation());
+ cast = NoTypeInfoCStyleCastExpr(Context, castType, CastExpr::CK_Unknown,
+ cast);
// Don't forget the parens to enforce the proper binding.
PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), cast);
@@ -2819,10 +2812,9 @@ Stmt *RewriteObjC::RewriteObjCProtocolExpr(ObjCProtocolExpr *Exp) {
Expr *DerefExpr = new (Context) UnaryOperator(DRE, UnaryOperator::AddrOf,
Context->getPointerType(DRE->getType()),
SourceLocation());
- CastExpr *castExpr = new (Context) CStyleCastExpr(DerefExpr->getType(),
- CastExpr::CK_Unknown,
- DerefExpr, DerefExpr->getType(),
- SourceLocation(), SourceLocation());
+ CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, DerefExpr->getType(),
+ CastExpr::CK_Unknown,
+ DerefExpr);
ReplaceStmt(Exp, castExpr);
ProtocolExprDecls.insert(Exp->getProtocol());
// delete Exp; leak for now, see RewritePropertySetter() usage for more info.
@@ -4043,7 +4035,7 @@ std::string RewriteObjC::SynthesizeBlockDescriptor(std::string DescTag,
void RewriteObjC::SynthesizeBlockLiterals(SourceLocation FunLocStart,
const char *FunName) {
// Insert declaration for the function in which block literal is used.
- if (CurFunctionDeclToDeclareForBlock)
+ if (CurFunctionDeclToDeclareForBlock && !Blocks.empty())
RewriteBlockLiteralFunctionDecl(CurFunctionDeclToDeclareForBlock);
// Insert closures that were part of the function.
for (unsigned i = 0; i < Blocks.size(); i++) {
@@ -4204,11 +4196,9 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) {
PtrToFuncCastType = Context->getPointerType(PtrToFuncCastType);
- CastExpr *BlkCast = new (Context) CStyleCastExpr(PtrBlock,
- CastExpr::CK_Unknown,
- const_cast<Expr*>(BlockExp),
- PtrBlock, SourceLocation(),
- SourceLocation());
+ CastExpr *BlkCast = NoTypeInfoCStyleCastExpr(Context, PtrBlock,
+ CastExpr::CK_Unknown,
+ const_cast<Expr*>(BlockExp));
// Don't forget the parens to enforce the proper binding.
ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(),
BlkCast);
@@ -4220,11 +4210,8 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) {
MemberExpr *ME = new (Context) MemberExpr(PE, true, FD, SourceLocation(),
FD->getType());
- CastExpr *FunkCast = new (Context) CStyleCastExpr(PtrToFuncCastType,
- CastExpr::CK_Unknown, ME,
- PtrToFuncCastType,
- SourceLocation(),
- SourceLocation());
+ CastExpr *FunkCast = NoTypeInfoCStyleCastExpr(Context, PtrToFuncCastType,
+ CastExpr::CK_Unknown, ME);
PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), FunkCast);
llvm::SmallVector<Expr*, 8> BlkExprs;
@@ -4309,17 +4296,29 @@ void RewriteObjC::RewriteCastExpr(CStyleCastExpr *CE) {
const char *startBuf = SM->getCharacterData(LocStart);
const char *endBuf = SM->getCharacterData(LocEnd);
-
+ QualType QT = CE->getType();
+ const Type* TypePtr = QT->getAs<Type>();
+ if (isa<TypeOfExprType>(TypePtr)) {
+ const TypeOfExprType *TypeOfExprTypePtr = cast<TypeOfExprType>(TypePtr);
+ QT = TypeOfExprTypePtr->getUnderlyingExpr()->getType();
+ std::string TypeAsString = "(";
+ TypeAsString += QT.getAsString();
+ TypeAsString += ")";
+ ReplaceText(LocStart, endBuf-startBuf+1,
+ TypeAsString.c_str(), TypeAsString.size());
+ return;
+ }
+
// advance the location to startArgList.
const char *argPtr = startBuf;
while (*argPtr++ && (argPtr < endBuf)) {
switch (*argPtr) {
- case '^':
- // Replace the '^' with '*'.
- LocStart = LocStart.getFileLocWithOffset(argPtr-startBuf);
- ReplaceText(LocStart, 1, "*", 1);
- break;
+ case '^':
+ // Replace the '^' with '*'.
+ LocStart = LocStart.getFileLocWithOffset(argPtr-startBuf);
+ ReplaceText(LocStart, 1, "*", 1);
+ break;
}
}
return;
@@ -4344,17 +4343,17 @@ void RewriteObjC::RewriteBlockPointerFunctionArgs(FunctionDecl *FD) {
while (*argPtr++ && parenCount) {
switch (*argPtr) {
- case '^':
- // Replace the '^' with '*'.
- DeclLoc = DeclLoc.getFileLocWithOffset(argPtr-startArgList);
- ReplaceText(DeclLoc, 1, "*", 1);
- break;
- case '(':
- parenCount++;
- break;
- case ')':
- parenCount--;
- break;
+ case '^':
+ // Replace the '^' with '*'.
+ DeclLoc = DeclLoc.getFileLocWithOffset(argPtr-startArgList);
+ ReplaceText(DeclLoc, 1, "*", 1);
+ break;
+ case '(':
+ parenCount++;
+ break;
+ case ')':
+ parenCount--;
+ break;
}
}
return;
@@ -4390,9 +4389,9 @@ void RewriteObjC::GetExtentOfArgList(const char *Name, const char *&LParen,
while (*argPtr && parenCount) {
switch (*argPtr) {
- case '(': parenCount++; break;
- case ')': parenCount--; break;
- default: break;
+ case '(': parenCount++; break;
+ case ')': parenCount--; break;
+ default: break;
}
if (parenCount) argPtr++;
}
@@ -4557,8 +4556,13 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) {
ByrefType += " " + Name + ";\n";
ByrefType += "};\n";
// Insert this type in global scope. It is needed by helper function.
- assert(CurFunctionDef && "RewriteByRefVar - CurFunctionDef is null");
- SourceLocation FunLocStart = CurFunctionDef->getTypeSpecStartLoc();
+ SourceLocation FunLocStart;
+ if (CurFunctionDef)
+ FunLocStart = CurFunctionDef->getTypeSpecStartLoc();
+ else {
+ assert(CurMethodDef && "RewriteByRefVar - CurMethodDef is null");
+ FunLocStart = CurMethodDef->getLocStart();
+ }
InsertText(FunLocStart, ByrefType.c_str(), ByrefType.size());
if (Ty.isObjCGCWeak()) {
flag |= BLOCK_FIELD_IS_WEAK;
@@ -4608,12 +4612,17 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) {
ByrefType.c_str(), ByrefType.size());
}
else {
- SourceLocation startLoc = ND->getInit()->getLocStart();
+ SourceLocation startLoc;
+ Expr *E = ND->getInit();
+ if (const CStyleCastExpr *ECE = dyn_cast<CStyleCastExpr>(E))
+ startLoc = ECE->getLParenLoc();
+ else
+ startLoc = E->getLocStart();
startLoc = SM->getInstantiationLoc(startLoc);
+ endBuf = SM->getCharacterData(startLoc);
+
ByrefType += " " + Name;
- ReplaceText(DeclLoc, endBuf-startBuf,
- ByrefType.c_str(), ByrefType.size());
- ByrefType = " = {(void*)";
+ ByrefType += " = {(void*)";
ByrefType += utostr(isa);
ByrefType += ", &" + Name + ", ";
ByrefType += utostr(flags);
@@ -4628,7 +4637,8 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) {
ByrefType += utostr(flag);
ByrefType += ", ";
}
- InsertText(startLoc, ByrefType.c_str(), ByrefType.size());
+ ReplaceText(DeclLoc, endBuf-startBuf,
+ ByrefType.c_str(), ByrefType.size());
// Complete the newly synthesized compound expression by inserting a right
// curly brace before the end of the declaration.
@@ -4719,10 +4729,8 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp) {
FD = SynthBlockInitFunctionDecl(Func.c_str());
DeclRefExpr *Arg = new (Context) DeclRefExpr(FD, FD->getType(),
SourceLocation());
- CastExpr *castExpr = new (Context) CStyleCastExpr(Context->VoidPtrTy,
- CastExpr::CK_Unknown, Arg,
- Context->VoidPtrTy, SourceLocation(),
- SourceLocation());
+ CastExpr *castExpr = NoTypeInfoCStyleCastExpr(Context, Context->VoidPtrTy,
+ CastExpr::CK_Unknown, Arg);
InitExprs.push_back(castExpr);
// Initialize the block descriptor.
@@ -4753,11 +4761,8 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp) {
} else if (isTopLevelBlockPointerType((*I)->getType())) {
FD = SynthBlockInitFunctionDecl((*I)->getNameAsCString());
Arg = new (Context) DeclRefExpr(FD, FD->getType(), SourceLocation());
- Exp = new (Context) CStyleCastExpr(Context->VoidPtrTy,
- CastExpr::CK_Unknown, Arg,
- Context->VoidPtrTy,
- SourceLocation(),
- SourceLocation());
+ Exp = NoTypeInfoCStyleCastExpr(Context, Context->VoidPtrTy,
+ CastExpr::CK_Unknown, Arg);
} else {
FD = SynthBlockInitFunctionDecl((*I)->getNameAsCString());
Exp = new (Context) DeclRefExpr(FD, FD->getType(), SourceLocation());
@@ -4789,9 +4794,8 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp) {
NewRep = new (Context) UnaryOperator(NewRep, UnaryOperator::AddrOf,
Context->getPointerType(NewRep->getType()),
SourceLocation());
- NewRep = new (Context) CStyleCastExpr(FType, CastExpr::CK_Unknown, NewRep,
- FType, SourceLocation(),
- SourceLocation());
+ NewRep = NoTypeInfoCStyleCastExpr(Context, FType, CastExpr::CK_Unknown,
+ NewRep);
BlockDeclRefs.clear();
BlockByRefDecls.clear();
BlockByCopyDecls.clear();
diff --git a/lib/Frontend/StmtXML.cpp b/lib/Frontend/StmtXML.cpp
index c0977b5..ce474d3 100644
--- a/lib/Frontend/StmtXML.cpp
+++ b/lib/Frontend/StmtXML.cpp
@@ -89,14 +89,14 @@ namespace {
const char* pAttributeName = NAME; \
const bool optional = false; \
switch (S->FN) { \
- default: assert(0 && "unknown enum value");
+ default: assert(0 && "unknown enum value");
#define ATTRIBUTE_ENUM_OPT_XML( FN, NAME ) \
{ \
const char* pAttributeName = NAME; \
const bool optional = true; \
switch (S->FN) { \
- default: assert(0 && "unknown enum value");
+ default: assert(0 && "unknown enum value");
#define ENUM_XML( VALUE, NAME ) case VALUE: if ((!optional) || NAME[0]) Doc.addAttribute(pAttributeName, NAME); break;
#define END_ENUM_XML } }
@@ -189,17 +189,17 @@ void StmtXML::VisitDeclRefExpr(DeclRefExpr *Node) {
const char* pKind;
switch (Node->getDecl()->getKind()) {
- case Decl::Function: pKind = "FunctionDecl"; break;
- case Decl::Var: pKind = "Var"; break;
- case Decl::ParmVar: pKind = "ParmVar"; break;
- case Decl::EnumConstant: pKind = "EnumConstant"; break;
- case Decl::Typedef: pKind = "Typedef"; break;
- case Decl::Record: pKind = "Record"; break;
- case Decl::Enum: pKind = "Enum"; break;
- case Decl::CXXRecord: pKind = "CXXRecord"; break;
- case Decl::ObjCInterface: pKind = "ObjCInterface"; break;
- case Decl::ObjCClass: pKind = "ObjCClass"; break;
- default: pKind = "Decl"; break;
+ case Decl::Function: pKind = "FunctionDecl"; break;
+ case Decl::Var: pKind = "Var"; break;
+ case Decl::ParmVar: pKind = "ParmVar"; break;
+ case Decl::EnumConstant: pKind = "EnumConstant"; break;
+ case Decl::Typedef: pKind = "Typedef"; break;
+ case Decl::Record: pKind = "Record"; break;
+ case Decl::Enum: pKind = "Enum"; break;
+ case Decl::CXXRecord: pKind = "CXXRecord"; break;
+ case Decl::ObjCInterface: pKind = "ObjCInterface"; break;
+ case Decl::ObjCClass: pKind = "ObjCClass"; break;
+ default: pKind = "Decl"; break;
}
Doc.addAttribute("kind", pKind);
@@ -210,10 +210,10 @@ void StmtXML::VisitDeclRefExpr(DeclRefExpr *Node) {
void StmtXML::VisitPredefinedExpr(PredefinedExpr *Node) {
DumpExpr(Node);
switch (Node->getIdentType()) {
- default: assert(0 && "unknown case");
- case PredefinedExpr::Func: Doc.addAttribute("predefined", " __func__"); break;
- case PredefinedExpr::Function: Doc.addAttribute("predefined", " __FUNCTION__"); break;
- case PredefinedExpr::PrettyFunction: Doc.addAttribute("predefined", " __PRETTY_FUNCTION__");break;
+ default: assert(0 && "unknown case");
+ case PredefinedExpr::Func: Doc.addAttribute("predefined", " __func__"); break;
+ case PredefinedExpr::Function: Doc.addAttribute("predefined", " __FUNCTION__"); break;
+ case PredefinedExpr::PrettyFunction: Doc.addAttribute("predefined", " __PRETTY_FUNCTION__");break;
}
}
diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp
index fcefd4e..83b4542 100644
--- a/lib/Frontend/TextDiagnosticPrinter.cpp
+++ b/lib/Frontend/TextDiagnosticPrinter.cpp
@@ -428,6 +428,42 @@ void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc,
}
}
}
+ // 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.
+ if (!FixItInsertionLine.empty()) {
+ 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;
+ }
+ }
}
// If the source line is too long for our terminal, select only the
diff --git a/lib/Frontend/TypeXML.cpp b/lib/Frontend/TypeXML.cpp
index 8bd0544..be9db42 100644
--- a/lib/Frontend/TypeXML.cpp
+++ b/lib/Frontend/TypeXML.cpp
@@ -43,14 +43,14 @@ public:
const char* pAttributeName = NAME; \
const bool optional = false; \
switch (T->FN) { \
- default: assert(0 && "unknown enum value");
+ default: assert(0 && "unknown enum value");
#define ATTRIBUTE_ENUM_OPT_XML( FN, NAME ) \
{ \
const char* pAttributeName = NAME; \
const bool optional = true; \
switch (T->FN) { \
- default: assert(0 && "unknown enum value");
+ default: assert(0 && "unknown enum value");
#define ENUM_XML( VALUE, NAME ) case VALUE: if ((!optional) || NAME[0]) Doc.addAttribute(pAttributeName, NAME); break;
#define END_ENUM_XML } }
diff --git a/lib/Index/ResolveLocation.cpp b/lib/Index/ResolveLocation.cpp
index 81a5de4..4bb1594 100644
--- a/lib/Index/ResolveLocation.cpp
+++ b/lib/Index/ResolveLocation.cpp
@@ -264,7 +264,7 @@ ASTLocation DeclLocResolver::VisitFunctionDecl(FunctionDecl *D) {
return ASTLocation(D);
// Second, search through the declarations that are part of the function.
- // If we find he location there, we won't have to search through its body.
+ // If we find the location there, we won't have to search through its body.
for (DeclContext::decl_iterator
I = D->decls_begin(), E = D->decls_end(); I != E; ++I) {
diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp
index 0a74b26..afd1ba8 100644
--- a/lib/Lex/Lexer.cpp
+++ b/lib/Lex/Lexer.cpp
@@ -210,6 +210,7 @@ void Lexer::Stringify(llvm::SmallVectorImpl<char> &Str) {
}
}
+static bool isWhitespace(unsigned char c);
/// MeasureTokenLength - Relex the token at the specified location and return
/// its length in bytes in the input file. If the token needs cleaning (e.g.
@@ -231,6 +232,9 @@ unsigned Lexer::MeasureTokenLength(SourceLocation Loc,
std::pair<const char *,const char *> Buffer = SM.getBufferData(LocInfo.first);
const char *StrData = Buffer.first+LocInfo.second;
+ if (isWhitespace(StrData[0]))
+ return 0;
+
// Create a lexer starting at the beginning of this token.
Lexer TheLexer(Loc, LangOpts, Buffer.first, StrData, Buffer.second);
TheLexer.SetCommentRetentionState(true);
@@ -902,8 +906,10 @@ bool Lexer::SkipWhitespace(Token &Result, const char *CurPtr) {
// SkipBCPLComment - We have just read the // characters from input. Skip until
// we find the newline character thats terminate the comment. Then update
-/// BufferPtr and return. If we're in KeepCommentMode, this will form the token
-/// and return true.
+/// BufferPtr and return.
+///
+/// If we're in KeepCommentMode or any CommentHandler has inserted
+/// some tokens, this will store the first token and return true.
bool Lexer::SkipBCPLComment(Token &Result, const char *CurPtr) {
// If BCPL comments aren't explicitly enabled for this language, emit an
// extension warning.
@@ -980,9 +986,12 @@ bool Lexer::SkipBCPLComment(Token &Result, const char *CurPtr) {
} while (C != '\n' && C != '\r');
// Found but did not consume the newline.
- if (PP)
- PP->HandleComment(SourceRange(getSourceLocation(BufferPtr),
- getSourceLocation(CurPtr)));
+ if (PP && PP->HandleComment(Result,
+ SourceRange(getSourceLocation(BufferPtr),
+ getSourceLocation(CurPtr)))) {
+ BufferPtr = CurPtr;
+ return true; // A token has to be returned.
+ }
// If we are returning comments as tokens, return this comment as a token.
if (inKeepCommentMode())
@@ -1108,8 +1117,8 @@ static bool isEndOfBlockCommentWithEscapedNewLine(const char *CurPtr,
/// happen is the comment could end with an escaped newline between the */ end
/// of comment.
///
-/// If KeepCommentMode is enabled, this forms a token from the comment and
-/// returns true.
+/// If we're in KeepCommentMode or any CommentHandler has inserted
+/// some tokens, this will store the first token and return true.
bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr) {
// Scan one character past where we should, looking for a '/' character. Once
// we find it, check to see if it was preceeded by a *. This common
@@ -1226,9 +1235,12 @@ bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr) {
C = *CurPtr++;
}
- if (PP)
- PP->HandleComment(SourceRange(getSourceLocation(BufferPtr),
- getSourceLocation(CurPtr)));
+ if (PP && PP->HandleComment(Result,
+ SourceRange(getSourceLocation(BufferPtr),
+ getSourceLocation(CurPtr)))) {
+ BufferPtr = CurPtr;
+ return true; // A token has to be returned.
+ }
// If we are returning comments as tokens, return this comment as a token.
if (inKeepCommentMode()) {
@@ -1606,10 +1618,12 @@ LexNextToken:
// too (without going through the big switch stmt).
if (CurPtr[0] == '/' && CurPtr[1] == '/' && !inKeepCommentMode() &&
Features.BCPLComment) {
- SkipBCPLComment(Result, CurPtr+2);
+ if (SkipBCPLComment(Result, CurPtr+2))
+ return; // There is a token to return.
goto SkipIgnoredUnits;
} else if (CurPtr[0] == '/' && CurPtr[1] == '*' && !inKeepCommentMode()) {
- SkipBlockComment(Result, CurPtr+2);
+ if (SkipBlockComment(Result, CurPtr+2))
+ return; // There is a token to return.
goto SkipIgnoredUnits;
} else if (isHorizontalWhitespace(*CurPtr)) {
goto SkipHorizontalWhitespace;
@@ -1795,7 +1809,7 @@ LexNextToken:
if (Features.BCPLComment ||
getCharAndSize(CurPtr+SizeTmp, SizeTmp2) != '*') {
if (SkipBCPLComment(Result, ConsumeChar(CurPtr, SizeTmp, Result)))
- return; // KeepCommentMode
+ return; // There is a token to return.
// It is common for the tokens immediately after a // comment to be
// whitespace (indentation for the next line). Instead of going through
@@ -1806,7 +1820,7 @@ LexNextToken:
if (Char == '*') { // /**/ comment.
if (SkipBlockComment(Result, ConsumeChar(CurPtr, SizeTmp, Result)))
- return; // KeepCommentMode
+ return; // There is a token to return.
goto LexNextToken; // GCC isn't tail call eliminating.
}
diff --git a/lib/Lex/LiteralSupport.cpp b/lib/Lex/LiteralSupport.cpp
index 5cd5497..004e675 100644
--- a/lib/Lex/LiteralSupport.cpp
+++ b/lib/Lex/LiteralSupport.cpp
@@ -375,7 +375,7 @@ NumericLiteralParser(const char *begin, const char *end,
continue; // Success.
case 'i':
if (PP.getLangOptions().Microsoft) {
- if (isFPConstant || isUnsigned || isLong || isLongLong) break;
+ if (isFPConstant || isLong || isLongLong) break;
// Allow i8, i16, i32, i64, and i128.
if (s + 1 != ThisTokEnd) {
diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp
index aa807f8..b0e784b 100644
--- a/lib/Lex/PPDirectives.cpp
+++ b/lib/Lex/PPDirectives.cpp
@@ -160,10 +160,7 @@ void Preprocessor::SkipExcludedConditionalBlock(SourceLocation IfTokenLoc,
CurPPLexer->LexingRawMode = true;
Token Tok;
while (1) {
- if (CurLexer)
- CurLexer->Lex(Tok);
- else
- CurPTHLexer->Lex(Tok);
+ CurLexer->Lex(Tok);
// If this is the end of the buffer, we have an error.
if (Tok.is(tok::eof)) {
@@ -405,7 +402,6 @@ void Preprocessor::PTHSkipExcludedConditionalBlock() {
/// return null on failure. isAngled indicates whether the file reference is
/// for system #include's or not (i.e. using <> instead of "").
const FileEntry *Preprocessor::LookupFile(llvm::StringRef Filename,
- SourceLocation FilenameTokLoc,
bool isAngled,
const DirectoryLookup *FromDir,
const DirectoryLookup *&CurDir) {
@@ -432,16 +428,7 @@ const FileEntry *Preprocessor::LookupFile(llvm::StringRef Filename,
CurDir = CurDirLookup;
const FileEntry *FE =
HeaderInfo.LookupFile(Filename, isAngled, FromDir, CurDir, CurFileEnt);
- if (FE) {
- // Warn about normal quoted #include from framework headers. Since
- // framework headers are published (both public and private ones) they
- // should not do relative searches, they should do an include with the
- // framework path included.
- if (!isAngled && CurDir && FilenameTokLoc.isValid() &&
- CurDir->isFramework() && CurDir == CurDirLookup)
- Diag(FilenameTokLoc, diag::warn_pp_relative_include_from_framework);
- return FE;
- }
+ if (FE) return FE;
// Otherwise, see if this is a subframework header. If so, this is relative
// to one of the headers on the #include stack. Walk the list of the current
@@ -1082,8 +1069,7 @@ void Preprocessor::HandleIncludeDirective(Token &IncludeTok,
// Search include directories.
const DirectoryLookup *CurDir;
- const FileEntry *File = LookupFile(Filename, FilenameTok.getLocation(),
- isAngled, LookupFrom, CurDir);
+ const FileEntry *File = LookupFile(Filename, isAngled, LookupFrom, CurDir);
if (File == 0) {
Diag(FilenameTok, diag::err_pp_file_not_found) << Filename;
return;
diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp
index 3792782..13aeb88 100644
--- a/lib/Lex/PPMacroExpansion.cpp
+++ b/lib/Lex/PPMacroExpansion.cpp
@@ -567,9 +567,7 @@ static bool EvaluateHasIncludeCommon(bool &Result, Token &Tok,
// Search include directories.
const DirectoryLookup *CurDir;
- const FileEntry *File = PP.LookupFile(Filename,
- SourceLocation(),// produce no warnings.
- isAngled, LookupFrom, CurDir);
+ const FileEntry *File = PP.LookupFile(Filename, isAngled, LookupFrom, CurDir);
// Get the result value. Result = true means the file exists.
Result = File != 0;
diff --git a/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp
index 856b3bd..63b23b6 100644
--- a/lib/Lex/Pragma.cpp
+++ b/lib/Lex/Pragma.cpp
@@ -301,8 +301,7 @@ void Preprocessor::HandlePragmaDependency(Token &DependencyTok) {
// Search include directories for this file.
const DirectoryLookup *CurDir;
- const FileEntry *File = LookupFile(Filename, FilenameTok.getLocation(),
- isAngled, 0, CurDir);
+ const FileEntry *File = LookupFile(Filename, isAngled, 0, CurDir);
if (File == 0) {
Diag(FilenameTok, diag::err_pp_file_not_found) << Filename;
return;
diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp
index 26bb3a9..5689baa 100644
--- a/lib/Lex/Preprocessor.cpp
+++ b/lib/Lex/Preprocessor.cpp
@@ -429,21 +429,17 @@ SourceLocation Preprocessor::AdvanceToTokenCharacter(SourceLocation TokStart,
return TokStart.getFileLocWithOffset(PhysOffset);
}
-/// \brief Computes the source location just past the end of the
-/// token at this source location.
-///
-/// This routine can be used to produce a source location that
-/// points just past the end of the token referenced by \p Loc, and
-/// is generally used when a diagnostic needs to point just after a
-/// token where it expected something different that it received. If
-/// the returned source location would not be meaningful (e.g., if
-/// it points into a macro), this routine returns an invalid
-/// source location.
-SourceLocation Preprocessor::getLocForEndOfToken(SourceLocation Loc) {
+SourceLocation Preprocessor::getLocForEndOfToken(SourceLocation Loc,
+ unsigned Offset) {
if (Loc.isInvalid() || !Loc.isFileID())
return SourceLocation();
unsigned Len = Lexer::MeasureTokenLength(Loc, getSourceManager(), Features);
+ if (Len > Offset)
+ Len = Len - Offset;
+ else
+ return Loc;
+
return AdvanceToTokenCharacter(Loc, Len);
}
@@ -583,11 +579,18 @@ void Preprocessor::RemoveCommentHandler(CommentHandler *Handler) {
CommentHandlers.erase(Pos);
}
-void Preprocessor::HandleComment(SourceRange Comment) {
+bool Preprocessor::HandleComment(Token &result, SourceRange Comment) {
+ bool AnyPendingTokens = false;
for (std::vector<CommentHandler *>::iterator H = CommentHandlers.begin(),
HEnd = CommentHandlers.end();
- H != HEnd; ++H)
- (*H)->HandleComment(*this, Comment);
+ H != HEnd; ++H) {
+ if ((*H)->HandleComment(*this, Comment))
+ AnyPendingTokens = true;
+ }
+ if (!AnyPendingTokens || getCommentRetentionState())
+ return false;
+ Lex(result);
+ return true;
}
CommentHandler::~CommentHandler() { }
diff --git a/lib/Makefile b/lib/Makefile
index adf9474..d499ee5 100755
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -8,8 +8,8 @@
##===----------------------------------------------------------------------===##
LEVEL = ../../..
-PARALLEL_DIRS = Headers Basic Lex Parse AST Sema CodeGen Analysis Rewrite \
- Frontend Index Driver
+PARALLEL_DIRS = Headers Runtime Basic Lex Parse AST Sema CodeGen Analysis \
+ Rewrite Frontend Index Driver
include $(LEVEL)/Makefile.common
diff --git a/lib/Parse/DeclSpec.cpp b/lib/Parse/DeclSpec.cpp
index f52d8b9..9e5f5a2 100644
--- a/lib/Parse/DeclSpec.cpp
+++ b/lib/Parse/DeclSpec.cpp
@@ -373,11 +373,30 @@ void DeclSpec::setProtocolQualifiers(const ActionBase::DeclPtrTy *Protos,
ProtocolLAngleLoc = LAngleLoc;
}
+void DeclSpec::SaveWrittenBuiltinSpecs() {
+ writtenBS.Sign = getTypeSpecSign();
+ writtenBS.Width = getTypeSpecWidth();
+ writtenBS.Type = getTypeSpecType();
+ // Search the list of attributes for the presence of a mode attribute.
+ writtenBS.ModeAttr = false;
+ AttributeList* attrs = getAttributes();
+ while (attrs) {
+ if (attrs->getKind() == AttributeList::AT_mode) {
+ writtenBS.ModeAttr = true;
+ break;
+ }
+ attrs = attrs->getNext();
+ }
+}
+
/// Finish - This does final analysis of the declspec, rejecting things like
/// "_Imaginary" (lacking an FP type). This returns a diagnostic to issue or
/// diag::NUM_DIAGNOSTICS if there is no error. After calling this method,
/// DeclSpec is guaranteed self-consistent, even if an error occurred.
void DeclSpec::Finish(Diagnostic &D, Preprocessor &PP) {
+ // Before possibly changing their values, save specs as written.
+ SaveWrittenBuiltinSpecs();
+
// Check the type specifier components first.
SourceManager &SrcMgr = PP.getSourceManager();
diff --git a/lib/Parse/MinimalAction.cpp b/lib/Parse/MinimalAction.cpp
index 8b207fa..5f48897 100644
--- a/lib/Parse/MinimalAction.cpp
+++ b/lib/Parse/MinimalAction.cpp
@@ -204,6 +204,7 @@ MinimalAction::ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
SourceLocation SuperLoc,
const DeclPtrTy *ProtoRefs,
unsigned NumProtocols,
+ const SourceLocation *ProtoLocs,
SourceLocation EndProtoLoc,
AttributeList *AttrList) {
// Allocate and add the 'TypeNameInfo' "decl".
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 90040c5..efaf8ee 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -983,7 +983,7 @@ Parser::BaseResult Parser::ParseBaseSpecifier(DeclPtrTy ClassDecl) {
// Parse an (optional) access specifier.
AccessSpecifier Access = getAccessSpecifierIfPresent();
- if (Access)
+ if (Access != AS_none)
ConsumeToken();
// Parse the 'virtual' keyword (again!), in case it came after the
@@ -1398,15 +1398,35 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
PP.getSourceManager(),
"parsing struct/union/class body");
- // Determine whether this is a top-level (non-nested) class.
- bool TopLevelClass = ClassStack.empty() ||
- CurScope->isInCXXInlineMethodScope();
+ // Determine whether this is a non-nested class. Note that local
+ // classes are *not* considered to be nested classes.
+ bool NonNestedClass = true;
+ if (!ClassStack.empty()) {
+ for (const Scope *S = CurScope; S; S = S->getParent()) {
+ if (S->isClassScope()) {
+ // We're inside a class scope, so this is a nested class.
+ NonNestedClass = false;
+ break;
+ }
+
+ if ((S->getFlags() & Scope::FnScope)) {
+ // If we're in a function or function template declared in the
+ // body of a class, then this is a local class rather than a
+ // nested class.
+ const Scope *Parent = S->getParent();
+ if (Parent->isTemplateParamScope())
+ Parent = Parent->getParent();
+ if (Parent->isClassScope())
+ break;
+ }
+ }
+ }
// Enter a scope for the class.
ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope);
// Note that we are parsing a new (potentially-nested) class definition.
- ParsingClassDefinition ParsingDef(*this, TagDecl, TopLevelClass);
+ ParsingClassDefinition ParsingDef(*this, TagDecl, NonNestedClass);
if (TagDecl)
Actions.ActOnTagStartDefinition(CurScope, TagDecl);
@@ -1484,7 +1504,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
//
// FIXME: Only function bodies and constructor ctor-initializers are
// parsed correctly, fix the rest.
- if (TopLevelClass) {
+ if (NonNestedClass) {
// We are not inside a nested class. This class and its nested classes
// are complete and we can parse the delayed portions of method
// declarations and the lexed inline method definitions.
@@ -1666,10 +1686,10 @@ bool Parser::ParseExceptionSpecification(SourceLocation &EndLoc,
/// \brief We have just started parsing the definition of a new class,
/// so push that class onto our stack of classes that is currently
/// being parsed.
-void Parser::PushParsingClass(DeclPtrTy ClassDecl, bool TopLevelClass) {
- assert((TopLevelClass || !ClassStack.empty()) &&
+void Parser::PushParsingClass(DeclPtrTy ClassDecl, bool NonNestedClass) {
+ assert((NonNestedClass || !ClassStack.empty()) &&
"Nested class without outer class");
- ClassStack.push(new ParsingClass(ClassDecl, TopLevelClass));
+ ClassStack.push(new ParsingClass(ClassDecl, NonNestedClass));
}
/// \brief Deallocate the given parsed class and all of its nested
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index 5e23635..ae85aa3 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -186,6 +186,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration(
categoryId, categoryLoc,
ProtocolRefs.data(),
ProtocolRefs.size(),
+ ProtocolLocs.data(),
EndProtoLoc);
ParseObjCInterfaceDeclList(CategoryType, tok::objc_not_keyword);
@@ -224,6 +225,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtInterfaceDeclaration(
Actions.ActOnStartClassInterface(atLoc, nameId, nameLoc,
superClassId, superClassLoc,
ProtocolRefs.data(), ProtocolRefs.size(),
+ ProtocolLocs.data(),
EndProtoLoc, attrList);
if (Tok.is(tok::l_brace))
@@ -1127,6 +1129,7 @@ Parser::DeclPtrTy Parser::ParseObjCAtProtocolDeclaration(SourceLocation AtLoc,
Actions.ActOnStartProtocolInterface(AtLoc, protocolName, nameLoc,
ProtocolRefs.data(),
ProtocolRefs.size(),
+ ProtocolLocs.data(),
EndProtoLoc, attrList);
ParseObjCInterfaceDeclList(ProtoType, tok::objc_protocol);
return ProtoType;
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 0aecac9..f2bc303 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -29,8 +29,9 @@ class ActionCommentHandler : public CommentHandler {
public:
explicit ActionCommentHandler(Action &Actions) : Actions(Actions) { }
- virtual void HandleComment(Preprocessor &PP, SourceRange Comment) {
+ virtual bool HandleComment(Preprocessor &PP, SourceRange Comment) {
Actions.ActOnComment(Comment);
+ return false;
}
};
diff --git a/lib/Rewrite/DeltaTree.cpp b/lib/Rewrite/DeltaTree.cpp
index 101cf93..35e888b 100644
--- a/lib/Rewrite/DeltaTree.cpp
+++ b/lib/Rewrite/DeltaTree.cpp
@@ -20,7 +20,7 @@ using llvm::cast;
using llvm::dyn_cast;
/// The DeltaTree class is a multiway search tree (BTree) structure with some
-/// fancy features. B-Trees are are generally more memory and cache efficient
+/// fancy features. B-Trees are generally more memory and cache efficient
/// than binary trees, because they store multiple keys/values in each node.
///
/// DeltaTree implements a key/value mapping from FileIndex to Delta, allowing
diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp
index fbd1450..8c4caaf 100644
--- a/lib/Sema/CodeCompleteConsumer.cpp
+++ b/lib/Sema/CodeCompleteConsumer.cpp
@@ -572,11 +572,11 @@ CIndexCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef,
break;
case Decl::ObjCImplementation:
- Kind = CXCursor_ObjCClassDefn;
+ Kind = CXCursor_ObjCImplementationDecl;
break;
case Decl::ObjCCategoryImpl:
- Kind = CXCursor_ObjCCategoryDefn;
+ Kind = CXCursor_ObjCCategoryImplDecl;
break;
default:
diff --git a/lib/Sema/Lookup.h b/lib/Sema/Lookup.h
index 9064de6..f4cea2e 100644
--- a/lib/Sema/Lookup.h
+++ b/lib/Sema/Lookup.h
@@ -123,9 +123,7 @@ public:
Temporary
};
- typedef llvm::SmallVector<NamedDecl*, 4> DeclsTy;
- typedef DeclsTy::const_iterator iterator;
-
+ typedef UnresolvedSetImpl::iterator iterator;
typedef bool (*ResultFilter)(NamedDecl*, unsigned IDNS);
LookupResult(Sema &SemaRef, DeclarationName Name, SourceLocation NameLoc,
@@ -133,6 +131,7 @@ public:
Sema::RedeclarationKind Redecl = Sema::NotForRedeclaration)
: ResultKind(NotFound),
Paths(0),
+ NamingClass(0),
SemaRef(SemaRef),
Name(Name),
NameLoc(NameLoc),
@@ -152,6 +151,7 @@ public:
LookupResult(TemporaryToken _, const LookupResult &Other)
: ResultKind(NotFound),
Paths(0),
+ NamingClass(0),
SemaRef(Other.SemaRef),
Name(Other.Name),
NameLoc(Other.NameLoc),
@@ -224,8 +224,8 @@ public:
return Ambiguity;
}
- iterator begin() const { return Decls.begin(); }
- iterator end() const { return Decls.end(); }
+ iterator begin() const { return iterator(Decls.begin()); }
+ iterator end() const { return iterator(Decls.end()); }
/// \brief Return true if no decls were found
bool empty() const { return Decls.empty(); }
@@ -247,32 +247,57 @@ public:
return IDNS;
}
- /// \brief Add a declaration to these results. Does not test the
- /// acceptance criteria.
+ /// \brief Returns whether these results arose from performing a
+ /// lookup into a class.
+ bool isClassLookup() const {
+ return NamingClass != 0;
+ }
+
+ /// \brief Returns the 'naming class' for this lookup, i.e. the
+ /// class which was looked into to find these results.
+ ///
+ /// C++0x [class.access.base]p5:
+ /// The access to a member is affected by the class in which the
+ /// member is named. This naming class is the class in which the
+ /// member name was looked up and found. [Note: this class can be
+ /// explicit, e.g., when a qualified-id is used, or implicit,
+ /// e.g., when a class member access operator (5.2.5) is used
+ /// (including cases where an implicit "this->" is added). If both
+ /// a class member access operator and a qualified-id are used to
+ /// name the member (as in p->T::m), the class naming the member
+ /// is the class named by the nested-name-specifier of the
+ /// qualified-id (that is, T). -- end note ]
+ ///
+ /// This is set by the lookup routines when they find results in a class.
+ CXXRecordDecl *getNamingClass() const {
+ return NamingClass;
+ }
+
+ /// \brief Sets the 'naming class' for this lookup.
+ void setNamingClass(CXXRecordDecl *Record) {
+ NamingClass = Record;
+ }
+
+ /// \brief Add a declaration to these results with its natural access.
+ /// Does not test the acceptance criteria.
void addDecl(NamedDecl *D) {
- Decls.push_back(D);
+ addDecl(D, D->getAccess());
+ }
+
+ /// \brief Add a declaration to these results with the given access.
+ /// Does not test the acceptance criteria.
+ void addDecl(NamedDecl *D, AccessSpecifier AS) {
+ Decls.addDecl(D, AS);
ResultKind = Found;
}
/// \brief Add all the declarations from another set of lookup
/// results.
void addAllDecls(const LookupResult &Other) {
- Decls.append(Other.begin(), Other.end());
+ Decls.append(Other.Decls.begin(), Other.Decls.end());
ResultKind = Found;
}
- /// \brief Hides a set of declarations.
- template <class NamedDeclSet> void hideDecls(const NamedDeclSet &Set) {
- unsigned I = 0, N = Decls.size();
- while (I < N) {
- if (Set.count(Decls[I]))
- Decls[I] = Decls[--N];
- else
- I++;
- }
- Decls.set_size(N);
- }
-
/// \brief Determine whether no result was found because we could not
/// search into dependent base classes of the current instantiation.
bool wasNotFoundInCurrentInstantiation() const {
@@ -319,13 +344,13 @@ public:
NamedDecl *getFoundDecl() const {
assert(getResultKind() == Found
&& "getFoundDecl called on non-unique result");
- return Decls[0]->getUnderlyingDecl();
+ return (*begin())->getUnderlyingDecl();
}
/// Fetches a representative decl. Useful for lazy diagnostics.
NamedDecl *getRepresentativeDecl() const {
assert(!Decls.empty() && "cannot get representative of empty set");
- return Decls[0];
+ return *begin();
}
/// \brief Asks if the result is a single tag decl.
@@ -403,7 +428,7 @@ public:
/// sugared.
class Filter {
LookupResult &Results;
- unsigned I;
+ LookupResult::iterator I;
bool Changed;
#ifndef NDEBUG
bool CalledDone;
@@ -411,7 +436,7 @@ public:
friend class LookupResult;
Filter(LookupResult &Results)
- : Results(Results), I(0), Changed(false)
+ : Results(Results), I(Results.begin()), Changed(false)
#ifndef NDEBUG
, CalledDone(false)
#endif
@@ -426,23 +451,30 @@ public:
#endif
bool hasNext() const {
- return I != Results.Decls.size();
+ return I != Results.end();
}
NamedDecl *next() {
- assert(I < Results.Decls.size() && "next() called on empty filter");
- return Results.Decls[I++];
+ assert(I != Results.end() && "next() called on empty filter");
+ return *I++;
}
/// Erase the last element returned from this iterator.
void erase() {
- Results.Decls[--I] = Results.Decls.back();
- Results.Decls.pop_back();
+ Results.Decls.erase(--I);
Changed = true;
}
+ /// Replaces the current entry with the given one, preserving the
+ /// access bits.
void replace(NamedDecl *D) {
- Results.Decls[I-1] = D;
+ Results.Decls.replace(I-1, D);
+ Changed = true;
+ }
+
+ /// Replaces the current entry with the given one.
+ void replace(NamedDecl *D, AccessSpecifier AS) {
+ Results.Decls.replace(I-1, D, AS);
Changed = true;
}
@@ -466,6 +498,8 @@ private:
void diagnose() {
if (isAmbiguous())
SemaRef.DiagnoseAmbiguousLookup(*this);
+ else if (isClassLookup() && SemaRef.getLangOptions().AccessControl)
+ SemaRef.CheckAccess(*this);
}
void setAmbiguous(AmbiguityKind AK) {
@@ -482,7 +516,7 @@ private:
assert(ResultKind != Found || Decls.size() == 1);
assert(ResultKind != FoundOverloaded || Decls.size() > 1 ||
(Decls.size() == 1 &&
- isa<FunctionTemplateDecl>(Decls[0]->getUnderlyingDecl())));
+ isa<FunctionTemplateDecl>((*begin())->getUnderlyingDecl())));
assert(ResultKind != FoundUnresolvedValue || sanityCheckUnresolved());
assert(ResultKind != Ambiguous || Decls.size() > 1 ||
(Decls.size() == 1 && Ambiguity == AmbiguousBaseSubobjects));
@@ -492,8 +526,7 @@ private:
}
bool sanityCheckUnresolved() const {
- for (DeclsTy::const_iterator I = Decls.begin(), E = Decls.end();
- I != E; ++I)
+ for (iterator I = begin(), E = end(); I != E; ++I)
if (isa<UnresolvedUsingValueDecl>(*I))
return true;
return false;
@@ -504,8 +537,9 @@ private:
// Results.
LookupResultKind ResultKind;
AmbiguityKind Ambiguity; // ill-defined unless ambiguous
- DeclsTy Decls;
+ UnresolvedSet<8> Decls;
CXXBasePaths *Paths;
+ CXXRecordDecl *NamingClass;
// Parameters.
Sema &SemaRef;
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index fab7292..06e9e3a 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -1291,6 +1291,17 @@ public:
ObjCContainerDecl* IDecl,
bool IncompleteImpl = false);
+ /// DiagnoseUnimplementedProperties - This routine warns on those properties
+ /// which must be implemented by this implementation.
+ void DiagnoseUnimplementedProperties(ObjCImplDecl* IMPDecl,
+ ObjCContainerDecl *CDecl,
+ const llvm::DenseSet<Selector>& InsMap);
+
+ /// CollectImmediateProperties - This routine collects all properties in
+ /// the class and its conforming protocols; but not those it its super class.
+ void CollectImmediateProperties(ObjCContainerDecl *CDecl,
+ llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& PropMap);
+
/// AtomicPropertySetterGetterRules - This routine enforces the rule (via
/// warning) when atomic property has one but not the other user-declared
/// setter or getter.
@@ -1651,6 +1662,11 @@ public:
virtual OwningExprResult ActOnCastExpr(Scope *S, SourceLocation LParenLoc,
TypeTy *Ty, SourceLocation RParenLoc,
ExprArg Op);
+ OwningExprResult BuildCStyleCastExpr(SourceLocation LParenLoc,
+ TypeSourceInfo *Ty,
+ SourceLocation RParenLoc,
+ ExprArg Op);
+
virtual bool TypeIsVectorType(TypeTy *Ty) {
return GetTypeFromParser(Ty)->isVectorType();
}
@@ -1658,13 +1674,18 @@ public:
OwningExprResult MaybeConvertParenListExprToParenExpr(Scope *S, ExprArg ME);
OwningExprResult ActOnCastOfParenListExpr(Scope *S, SourceLocation LParenLoc,
SourceLocation RParenLoc, ExprArg E,
- QualType Ty);
+ TypeSourceInfo *TInfo);
virtual OwningExprResult ActOnCompoundLiteral(SourceLocation LParenLoc,
TypeTy *Ty,
SourceLocation RParenLoc,
ExprArg Op);
+ OwningExprResult BuildCompoundLiteralExpr(SourceLocation LParenLoc,
+ TypeSourceInfo *TInfo,
+ SourceLocation RParenLoc,
+ ExprArg InitExpr);
+
virtual OwningExprResult ActOnInitList(SourceLocation LParenLoc,
MultiExprArg InitList,
SourceLocation RParenLoc);
@@ -1920,6 +1941,13 @@ public:
ExprArg E,
SourceLocation RParenLoc);
+ OwningExprResult BuildCXXNamedCast(SourceLocation OpLoc,
+ tok::TokenKind Kind,
+ TypeSourceInfo *Ty,
+ ExprArg E,
+ SourceRange AngleBrackets,
+ SourceRange Parens);
+
/// ActOnCXXTypeid - Parse typeid( something ).
virtual OwningExprResult ActOnCXXTypeid(SourceLocation OpLoc,
SourceLocation LParenLoc, bool isType,
@@ -2033,7 +2061,6 @@ public:
bool isDependentScopeSpecifier(const CXXScopeSpec &SS);
CXXRecordDecl *getCurrentInstantiationOf(NestedNameSpecifier *NNS);
bool isUnknownSpecialization(const CXXScopeSpec &SS);
- bool isCurrentInstantiationWithDependentBases(const CXXScopeSpec &SS);
/// ActOnCXXGlobalScopeSpecifier - Return the object that represents the
/// global scope ('::').
@@ -2334,6 +2361,9 @@ public:
CXXBasePaths &Paths,
bool NoPrivileges = false);
+ void CheckAccess(const LookupResult &R);
+ bool CheckAccess(const LookupResult &R, NamedDecl *D, AccessSpecifier Access);
+
bool CheckBaseClassAccess(QualType Derived, QualType Base,
unsigned InaccessibleBaseID,
CXXBasePaths& Paths, SourceLocation AccessLoc,
@@ -3153,13 +3183,17 @@ public:
/// relevant to this particular scope).
LocalInstantiationScope *Outer;
+ /// \brief Whether we have already exited this scope.
+ bool Exited;
+
// This class is non-copyable
LocalInstantiationScope(const LocalInstantiationScope &);
LocalInstantiationScope &operator=(const LocalInstantiationScope &);
public:
LocalInstantiationScope(Sema &SemaRef, bool CombineWithOuterScope = false)
- : SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope) {
+ : SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope),
+ Exited(false) {
if (!CombineWithOuterScope)
SemaRef.CurrentInstantiationScope = this;
else
@@ -3168,7 +3202,15 @@ public:
}
~LocalInstantiationScope() {
+ if (!Exited)
+ SemaRef.CurrentInstantiationScope = Outer;
+ }
+
+ /// \brief Exit this local instantiation scope early.
+ void Exit() {
SemaRef.CurrentInstantiationScope = Outer;
+ LocalDecls.clear();
+ Exited = true;
}
Decl *getInstantiationOf(const Decl *D) {
@@ -3215,7 +3257,16 @@ public:
/// but have not yet been performed.
std::deque<PendingImplicitInstantiation> PendingImplicitInstantiations;
- void PerformPendingImplicitInstantiations();
+ /// \brief The queue of implicit template instantiations that are required
+ /// and must be performed within the current local scope.
+ ///
+ /// This queue is only used for member functions of local classes in
+ /// templates, which must be instantiated in the same scope as their
+ /// enclosing function, so that they can reference function-local
+ /// types, static variables, enumerators, etc.
+ std::deque<PendingImplicitInstantiation> PendingLocalImplicitInstantiations;
+
+ void PerformPendingImplicitInstantiations(bool LocalOnly = false);
TypeSourceInfo *SubstType(TypeSourceInfo *T,
const MultiLevelTemplateArgumentList &TemplateArgs,
@@ -3300,6 +3351,7 @@ public:
SourceLocation SuperLoc,
const DeclPtrTy *ProtoRefs,
unsigned NumProtoRefs,
+ const SourceLocation *ProtoLocs,
SourceLocation EndProtoLoc,
AttributeList *AttrList);
@@ -3317,6 +3369,7 @@ public:
SourceLocation AtProtoInterfaceLoc,
IdentifierInfo *ProtocolName, SourceLocation ProtocolLoc,
const DeclPtrTy *ProtoRefNames, unsigned NumProtoRefs,
+ const SourceLocation *ProtoLocs,
SourceLocation EndProtoLoc,
AttributeList *AttrList);
@@ -3327,6 +3380,7 @@ public:
SourceLocation CategoryLoc,
const DeclPtrTy *ProtoRefs,
unsigned NumProtoRefs,
+ const SourceLocation *ProtoLocs,
SourceLocation EndProtoLoc);
virtual DeclPtrTy ActOnStartClassImplementation(
@@ -3373,14 +3427,13 @@ public:
ObjCMethodDecl *MethodDecl,
bool IsInstance);
- void MergeProtocolPropertiesIntoClass(Decl *CDecl,
- DeclPtrTy MergeProtocols);
+ void CompareProperties(Decl *CDecl, DeclPtrTy MergeProtocols);
void DiagnoseClassExtensionDupMethods(ObjCCategoryDecl *CAT,
ObjCInterfaceDecl *ID);
- void MergeOneProtocolPropertiesIntoClass(Decl *CDecl,
- ObjCProtocolDecl *PDecl);
+ void MatchOneProtocolPropertiesInClass(Decl *CDecl,
+ ObjCProtocolDecl *PDecl);
virtual void ActOnAtEnd(SourceRange AtEnd,
DeclPtrTy classDecl,
diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp
index b7cc37b..51f9e30 100644
--- a/lib/Sema/SemaAccess.cpp
+++ b/lib/Sema/SemaAccess.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "Sema.h"
+#include "Lookup.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclCXX.h"
@@ -137,3 +138,101 @@ bool Sema::CheckBaseClassAccess(QualType Derived, QualType Base,
return false;
}
+
+/// Diagnose the path which caused the given declaration to become
+/// inaccessible.
+static void DiagnoseAccessPath(Sema &S, const LookupResult &R, NamedDecl *D,
+ AccessSpecifier Access) {
+ // Easy case: the decl's natural access determined its path access.
+ if (Access == D->getAccess() || D->getAccess() == AS_private) {
+ S.Diag(D->getLocation(), diag::note_access_natural)
+ << (unsigned) (Access == AS_protected);
+ return;
+ }
+
+ // TODO: flesh this out
+ S.Diag(D->getLocation(), diag::note_access_constrained_by_path)
+ << (unsigned) (Access == AS_protected);
+}
+
+/// Checks access to the given declaration in the current context.
+///
+/// \param R the means via which the access was made; must have a naming
+/// class set
+/// \param D the declaration accessed
+/// \param Access the best access along any inheritance path from the
+/// naming class to the declaration. AS_none means the path is impossible
+bool Sema::CheckAccess(const LookupResult &R, NamedDecl *D,
+ AccessSpecifier Access) {
+ assert(R.getNamingClass() && "performing access check without naming class");
+
+ // If the access path is public, it's accessible everywhere.
+ if (Access == AS_public)
+ return false;
+
+ // Otherwise, derive the current class context.
+ DeclContext *DC = CurContext;
+ while (isa<CXXRecordDecl>(DC) &&
+ cast<CXXRecordDecl>(DC)->isAnonymousStructOrUnion())
+ DC = DC->getParent();
+
+ CXXRecordDecl *CurRecord;
+ if (isa<CXXRecordDecl>(DC))
+ CurRecord = cast<CXXRecordDecl>(DC);
+ else if (isa<CXXMethodDecl>(DC))
+ CurRecord = cast<CXXMethodDecl>(DC)->getParent();
+ else {
+ Diag(R.getNameLoc(), diag::err_access_outside_class)
+ << (Access == AS_protected);
+ DiagnoseAccessPath(*this, R, D, Access);
+ return true;
+ }
+
+ CXXRecordDecl *NamingClass = R.getNamingClass();
+ while (NamingClass->isAnonymousStructOrUnion())
+ // This should be guaranteed by the fact that the decl has
+ // non-public access. If not, we should make it guaranteed!
+ NamingClass = cast<CXXRecordDecl>(NamingClass);
+
+ // White-list accesses from within the declaring class.
+ if (Access != AS_none &&
+ CurRecord->getCanonicalDecl() == NamingClass->getCanonicalDecl())
+ return false;
+
+ // Protected access.
+ if (Access == AS_protected) {
+ // FIXME: implement [class.protected]p1
+ if (CurRecord->isDerivedFrom(NamingClass))
+ return false;
+
+ // FIXME: dependent classes
+ }
+
+ // FIXME: friends
+
+ // Okay, it's a bad access, reject it.
+
+
+ CXXRecordDecl *DeclaringClass = cast<CXXRecordDecl>(D->getDeclContext());
+
+ if (Access == AS_protected) {
+ Diag(R.getNameLoc(), diag::err_access_protected)
+ << Context.getTypeDeclType(DeclaringClass)
+ << Context.getTypeDeclType(CurRecord);
+ DiagnoseAccessPath(*this, R, D, Access);
+ return true;
+ }
+
+ assert(Access == AS_private || Access == AS_none);
+ Diag(R.getNameLoc(), diag::err_access_private)
+ << Context.getTypeDeclType(DeclaringClass)
+ << Context.getTypeDeclType(CurRecord);
+ DiagnoseAccessPath(*this, R, D, Access);
+ return true;
+}
+
+/// Checks access to all the declarations in the given result set.
+void Sema::CheckAccess(const LookupResult &R) {
+ for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I)
+ CheckAccess(R, *I, I.getAccess());
+}
diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp
index f924bd3..57c4f9b 100644
--- a/lib/Sema/SemaCXXCast.cpp
+++ b/lib/Sema/SemaCXXCast.cpp
@@ -116,11 +116,26 @@ Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
SourceLocation RAngleBracketLoc,
SourceLocation LParenLoc, ExprArg E,
SourceLocation RParenLoc) {
+
+ TypeSourceInfo *DestTInfo;
+ QualType DestType = GetTypeFromParser(Ty, &DestTInfo);
+ if (!DestTInfo)
+ DestTInfo = Context.getTrivialTypeSourceInfo(DestType, SourceLocation());
+
+ return BuildCXXNamedCast(OpLoc, Kind, DestTInfo, move(E),
+ SourceRange(LAngleBracketLoc, RAngleBracketLoc),
+ SourceRange(LParenLoc, RParenLoc));
+}
+
+Action::OwningExprResult
+Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
+ TypeSourceInfo *DestTInfo, ExprArg E,
+ SourceRange AngleBrackets, SourceRange Parens) {
Expr *Ex = E.takeAs<Expr>();
- // FIXME: Preserve type source info.
- QualType DestType = GetTypeFromParser(Ty);
- SourceRange OpRange(OpLoc, RParenLoc);
- SourceRange DestRange(LAngleBracketLoc, RAngleBracketLoc);
+ QualType DestType = DestTInfo->getType();
+
+ SourceRange OpRange(OpLoc, Parens.getEnd());
+ SourceRange DestRange = AngleBrackets;
// If the type is dependent, we won't do the semantic analysis now.
// FIXME: should we check this in a more fine-grained manner?
@@ -133,14 +148,14 @@ Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
if (!TypeDependent)
CheckConstCast(*this, Ex, DestType, OpRange, DestRange);
return Owned(new (Context) CXXConstCastExpr(DestType.getNonReferenceType(),
- Ex, DestType, OpLoc));
+ Ex, DestTInfo, OpLoc));
case tok::kw_dynamic_cast: {
CastExpr::CastKind Kind = CastExpr::CK_Unknown;
if (!TypeDependent)
CheckDynamicCast(*this, Ex, DestType, OpRange, DestRange, Kind);
return Owned(new (Context)CXXDynamicCastExpr(DestType.getNonReferenceType(),
- Kind, Ex, DestType, OpLoc));
+ Kind, Ex, DestTInfo, OpLoc));
}
case tok::kw_reinterpret_cast: {
CastExpr::CastKind Kind = CastExpr::CK_Unknown;
@@ -148,7 +163,7 @@ Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
CheckReinterpretCast(*this, Ex, DestType, OpRange, DestRange, Kind);
return Owned(new (Context) CXXReinterpretCastExpr(
DestType.getNonReferenceType(),
- Kind, Ex, DestType, OpLoc));
+ Kind, Ex, DestTInfo, OpLoc));
}
case tok::kw_static_cast: {
CastExpr::CastKind Kind = CastExpr::CK_Unknown;
@@ -169,7 +184,7 @@ Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind,
}
return Owned(new (Context) CXXStaticCastExpr(DestType.getNonReferenceType(),
- Kind, Ex, DestType, OpLoc));
+ Kind, Ex, DestTInfo, OpLoc));
}
}
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index 8594583..7a0b625 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -30,9 +30,9 @@ getCurrentInstantiationOf(ASTContext &Context, DeclContext *CurContext,
if (T.isNull())
return 0;
- T = Context.getCanonicalType(T);
+ T = Context.getCanonicalType(T).getUnqualifiedType();
- for (DeclContext *Ctx = CurContext; Ctx; Ctx = Ctx->getParent()) {
+ for (DeclContext *Ctx = CurContext; Ctx; Ctx = Ctx->getLookupParent()) {
// If we've hit a namespace or the global scope, then the
// nested-name-specifier can't refer to the current instantiation.
if (Ctx->isFileContext())
@@ -210,28 +210,6 @@ bool Sema::isUnknownSpecialization(const CXXScopeSpec &SS) {
return getCurrentInstantiationOf(NNS) == 0;
}
-/// \brief Determine whether the given scope specifier refers to a
-/// current instantiation that has any dependent base clases.
-///
-/// This check is typically used when we've performed lookup into the
-/// current instantiation of a template, but that lookup failed. When
-/// there are dependent bases present, however, the lookup needs to be
-/// delayed until template instantiation time.
-bool Sema::isCurrentInstantiationWithDependentBases(const CXXScopeSpec &SS) {
- if (!SS.isSet())
- return false;
-
- NestedNameSpecifier *NNS = (NestedNameSpecifier*)SS.getScopeRep();
- if (!NNS->isDependent())
- return false;
-
- CXXRecordDecl *CurrentInstantiation = getCurrentInstantiationOf(NNS);
- if (!CurrentInstantiation)
- return false;
-
- return CurrentInstantiation->hasAnyDependentBases();
-}
-
/// \brief If the given nested name specifier refers to the current
/// instantiation, return the declaration that corresponds to that
/// current instantiation (C++0x [temp.dep.type]p1).
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 5f124e4..6ff8b1d 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -13,14 +13,22 @@
//===----------------------------------------------------------------------===//
#include "Sema.h"
+#include "clang/Analysis/CFG.h"
+#include "clang/Analysis/PathSensitive/AnalysisContext.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/StmtCXX.h"
+#include "clang/AST/StmtObjC.h"
#include "clang/Lex/LiteralSupport.h"
#include "clang/Lex/Preprocessor.h"
+#include "llvm/ADT/BitVector.h"
+#include "llvm/ADT/STLExtras.h"
#include <limits>
+#include <queue>
using namespace clang;
/// getLocationOfStringLiteralByte - Return a source location that points to the
@@ -2029,3 +2037,522 @@ void Sema::CheckImplicitConversion(Expr *E, QualType T) {
return;
}
+// MarkLive - Mark all the blocks reachable from e as live. Returns the total
+// number of blocks just marked live.
+static unsigned MarkLive(CFGBlock *e, llvm::BitVector &live) {
+ unsigned count = 0;
+ std::queue<CFGBlock*> workq;
+ // Prep work queue
+ live.set(e->getBlockID());
+ ++count;
+ workq.push(e);
+ // Solve
+ while (!workq.empty()) {
+ CFGBlock *item = workq.front();
+ workq.pop();
+ for (CFGBlock::succ_iterator I=item->succ_begin(),
+ E=item->succ_end();
+ I != E;
+ ++I) {
+ if ((*I) && !live[(*I)->getBlockID()]) {
+ live.set((*I)->getBlockID());
+ ++count;
+ workq.push(*I);
+ }
+ }
+ }
+ return count;
+}
+
+static SourceLocation GetUnreachableLoc(CFGBlock &b, SourceRange &R1,
+ SourceRange &R2) {
+ Stmt *S;
+ unsigned sn = 0;
+ R1 = R2 = SourceRange();
+
+ top:
+ if (sn < b.size())
+ S = b[sn].getStmt();
+ else if (b.getTerminator())
+ S = b.getTerminator();
+ else
+ return SourceLocation();
+
+ switch (S->getStmtClass()) {
+ case Expr::BinaryOperatorClass: {
+ BinaryOperator *BO = cast<BinaryOperator>(S);
+ if (BO->getOpcode() == BinaryOperator::Comma) {
+ if (sn+1 < b.size())
+ return b[sn+1].getStmt()->getLocStart();
+ CFGBlock *n = &b;
+ while (1) {
+ if (n->getTerminator())
+ return n->getTerminator()->getLocStart();
+ if (n->succ_size() != 1)
+ return SourceLocation();
+ n = n[0].succ_begin()[0];
+ if (n->pred_size() != 1)
+ return SourceLocation();
+ if (!n->empty())
+ return n[0][0].getStmt()->getLocStart();
+ }
+ }
+ R1 = BO->getLHS()->getSourceRange();
+ R2 = BO->getRHS()->getSourceRange();
+ return BO->getOperatorLoc();
+ }
+ case Expr::UnaryOperatorClass: {
+ const UnaryOperator *UO = cast<UnaryOperator>(S);
+ R1 = UO->getSubExpr()->getSourceRange();
+ return UO->getOperatorLoc();
+ }
+ case Expr::CompoundAssignOperatorClass: {
+ const CompoundAssignOperator *CAO = cast<CompoundAssignOperator>(S);
+ R1 = CAO->getLHS()->getSourceRange();
+ R2 = CAO->getRHS()->getSourceRange();
+ return CAO->getOperatorLoc();
+ }
+ case Expr::ConditionalOperatorClass: {
+ const ConditionalOperator *CO = cast<ConditionalOperator>(S);
+ return CO->getQuestionLoc();
+ }
+ case Expr::MemberExprClass: {
+ const MemberExpr *ME = cast<MemberExpr>(S);
+ R1 = ME->getSourceRange();
+ return ME->getMemberLoc();
+ }
+ case Expr::ArraySubscriptExprClass: {
+ const ArraySubscriptExpr *ASE = cast<ArraySubscriptExpr>(S);
+ R1 = ASE->getLHS()->getSourceRange();
+ R2 = ASE->getRHS()->getSourceRange();
+ return ASE->getRBracketLoc();
+ }
+ case Expr::CStyleCastExprClass: {
+ const CStyleCastExpr *CSC = cast<CStyleCastExpr>(S);
+ R1 = CSC->getSubExpr()->getSourceRange();
+ return CSC->getLParenLoc();
+ }
+ case Expr::CXXFunctionalCastExprClass: {
+ const CXXFunctionalCastExpr *CE = cast <CXXFunctionalCastExpr>(S);
+ R1 = CE->getSubExpr()->getSourceRange();
+ return CE->getTypeBeginLoc();
+ }
+ case Expr::ImplicitCastExprClass:
+ ++sn;
+ goto top;
+ case Stmt::CXXTryStmtClass: {
+ return cast<CXXTryStmt>(S)->getHandler(0)->getCatchLoc();
+ }
+ default: ;
+ }
+ R1 = S->getSourceRange();
+ return S->getLocStart();
+}
+
+static SourceLocation MarkLiveTop(CFGBlock *e, llvm::BitVector &live,
+ SourceManager &SM) {
+ std::queue<CFGBlock*> workq;
+ // Prep work queue
+ workq.push(e);
+ SourceRange R1, R2;
+ SourceLocation top = GetUnreachableLoc(*e, R1, R2);
+ bool FromMainFile = false;
+ bool FromSystemHeader = false;
+ bool TopValid = false;
+ if (top.isValid()) {
+ FromMainFile = SM.isFromMainFile(top);
+ FromSystemHeader = SM.isInSystemHeader(top);
+ TopValid = true;
+ }
+ // Solve
+ while (!workq.empty()) {
+ CFGBlock *item = workq.front();
+ workq.pop();
+ SourceLocation c = GetUnreachableLoc(*item, R1, R2);
+ if (c.isValid()
+ && (!TopValid
+ || (SM.isFromMainFile(c) && !FromMainFile)
+ || (FromSystemHeader && !SM.isInSystemHeader(c))
+ || SM.isBeforeInTranslationUnit(c, top))) {
+ top = c;
+ FromMainFile = SM.isFromMainFile(top);
+ FromSystemHeader = SM.isInSystemHeader(top);
+ }
+ live.set(item->getBlockID());
+ for (CFGBlock::succ_iterator I=item->succ_begin(),
+ E=item->succ_end();
+ I != E;
+ ++I) {
+ if ((*I) && !live[(*I)->getBlockID()]) {
+ live.set((*I)->getBlockID());
+ workq.push(*I);
+ }
+ }
+ }
+ return top;
+}
+
+static int LineCmp(const void *p1, const void *p2) {
+ SourceLocation *Line1 = (SourceLocation *)p1;
+ SourceLocation *Line2 = (SourceLocation *)p2;
+ return !(*Line1 < *Line2);
+}
+
+namespace {
+ struct ErrLoc {
+ SourceLocation Loc;
+ SourceRange R1;
+ SourceRange R2;
+ ErrLoc(SourceLocation l, SourceRange r1, SourceRange r2)
+ : Loc(l), R1(r1), R2(r2) { }
+ };
+}
+
+/// CheckUnreachable - Check for unreachable code.
+void Sema::CheckUnreachable(AnalysisContext &AC) {
+ unsigned count;
+ // We avoid checking when there are errors, as the CFG won't faithfully match
+ // the user's code.
+ if (getDiagnostics().hasErrorOccurred())
+ return;
+ if (Diags.getDiagnosticLevel(diag::warn_unreachable) == Diagnostic::Ignored)
+ return;
+
+ CFG *cfg = AC.getCFG();
+ if (cfg == 0)
+ return;
+
+ llvm::BitVector live(cfg->getNumBlockIDs());
+ // Mark all live things first.
+ count = MarkLive(&cfg->getEntry(), live);
+
+ if (count == cfg->getNumBlockIDs())
+ // If there are no dead blocks, we're done.
+ return;
+
+ SourceRange R1, R2;
+
+ llvm::SmallVector<ErrLoc, 24> lines;
+ bool AddEHEdges = AC.getAddEHEdges();
+ // First, give warnings for blocks with no predecessors, as they
+ // can't be part of a loop.
+ for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) {
+ CFGBlock &b = **I;
+ if (!live[b.getBlockID()]) {
+ if (b.pred_begin() == b.pred_end()) {
+ if (!AddEHEdges && b.getTerminator()
+ && isa<CXXTryStmt>(b.getTerminator())) {
+ // When not adding EH edges from calls, catch clauses
+ // can otherwise seem dead. Avoid noting them as dead.
+ count += MarkLive(&b, live);
+ continue;
+ }
+ SourceLocation c = GetUnreachableLoc(b, R1, R2);
+ if (!c.isValid()) {
+ // Blocks without a location can't produce a warning, so don't mark
+ // reachable blocks from here as live.
+ live.set(b.getBlockID());
+ ++count;
+ continue;
+ }
+ lines.push_back(ErrLoc(c, R1, R2));
+ // Avoid excessive errors by marking everything reachable from here
+ count += MarkLive(&b, live);
+ }
+ }
+ }
+
+ if (count < cfg->getNumBlockIDs()) {
+ // And then give warnings for the tops of loops.
+ for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) {
+ CFGBlock &b = **I;
+ if (!live[b.getBlockID()])
+ // Avoid excessive errors by marking everything reachable from here
+ lines.push_back(ErrLoc(MarkLiveTop(&b, live, Context.getSourceManager()), SourceRange(), SourceRange()));
+ }
+ }
+
+ llvm::array_pod_sort(lines.begin(), lines.end(), LineCmp);
+ for (llvm::SmallVector<ErrLoc, 24>::iterator I = lines.begin(),
+ E = lines.end();
+ I != E;
+ ++I)
+ if (I->Loc.isValid())
+ Diag(I->Loc, diag::warn_unreachable) << I->R1 << I->R2;
+}
+
+/// CheckFallThrough - Check that we don't fall off the end of a
+/// Statement that should return a value.
+///
+/// \returns AlwaysFallThrough iff we always fall off the end of the statement,
+/// MaybeFallThrough iff we might or might not fall off the end,
+/// NeverFallThroughOrReturn iff we never fall off the end of the statement or
+/// return. We assume NeverFallThrough iff we never fall off the end of the
+/// statement but we may return. We assume that functions not marked noreturn
+/// will return.
+Sema::ControlFlowKind Sema::CheckFallThrough(AnalysisContext &AC) {
+ CFG *cfg = AC.getCFG();
+ if (cfg == 0)
+ // FIXME: This should be NeverFallThrough
+ return NeverFallThroughOrReturn;
+
+ // The CFG leaves in dead things, and we don't want the dead code paths to
+ // confuse us, so we mark all live things first.
+ std::queue<CFGBlock*> workq;
+ llvm::BitVector live(cfg->getNumBlockIDs());
+ unsigned count = MarkLive(&cfg->getEntry(), live);
+
+ bool AddEHEdges = AC.getAddEHEdges();
+ if (!AddEHEdges && count != cfg->getNumBlockIDs())
+ // When there are things remaining dead, and we didn't add EH edges
+ // from CallExprs to the catch clauses, we have to go back and
+ // mark them as live.
+ for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) {
+ CFGBlock &b = **I;
+ if (!live[b.getBlockID()]) {
+ if (b.pred_begin() == b.pred_end()) {
+ if (b.getTerminator() && isa<CXXTryStmt>(b.getTerminator()))
+ // When not adding EH edges from calls, catch clauses
+ // can otherwise seem dead. Avoid noting them as dead.
+ count += MarkLive(&b, live);
+ continue;
+ }
+ }
+ }
+
+ // Now we know what is live, we check the live precessors of the exit block
+ // and look for fall through paths, being careful to ignore normal returns,
+ // and exceptional paths.
+ bool HasLiveReturn = false;
+ bool HasFakeEdge = false;
+ bool HasPlainEdge = false;
+ bool HasAbnormalEdge = false;
+ for (CFGBlock::pred_iterator I=cfg->getExit().pred_begin(),
+ E = cfg->getExit().pred_end();
+ I != E;
+ ++I) {
+ CFGBlock& B = **I;
+ if (!live[B.getBlockID()])
+ continue;
+ if (B.size() == 0) {
+ if (B.getTerminator() && isa<CXXTryStmt>(B.getTerminator())) {
+ HasAbnormalEdge = true;
+ continue;
+ }
+
+ // A labeled empty statement, or the entry block...
+ HasPlainEdge = true;
+ continue;
+ }
+ Stmt *S = B[B.size()-1];
+ if (isa<ReturnStmt>(S)) {
+ HasLiveReturn = true;
+ continue;
+ }
+ if (isa<ObjCAtThrowStmt>(S)) {
+ HasFakeEdge = true;
+ continue;
+ }
+ if (isa<CXXThrowExpr>(S)) {
+ HasFakeEdge = true;
+ continue;
+ }
+ if (const AsmStmt *AS = dyn_cast<AsmStmt>(S)) {
+ if (AS->isMSAsm()) {
+ HasFakeEdge = true;
+ HasLiveReturn = true;
+ continue;
+ }
+ }
+ if (isa<CXXTryStmt>(S)) {
+ HasAbnormalEdge = true;
+ continue;
+ }
+
+ bool NoReturnEdge = false;
+ if (CallExpr *C = dyn_cast<CallExpr>(S)) {
+ if (B.succ_begin()[0] != &cfg->getExit()) {
+ HasAbnormalEdge = true;
+ continue;
+ }
+ Expr *CEE = C->getCallee()->IgnoreParenCasts();
+ if (CEE->getType().getNoReturnAttr()) {
+ NoReturnEdge = true;
+ HasFakeEdge = true;
+ } else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) {
+ ValueDecl *VD = DRE->getDecl();
+ if (VD->hasAttr<NoReturnAttr>()) {
+ NoReturnEdge = true;
+ HasFakeEdge = true;
+ }
+ }
+ }
+ // FIXME: Add noreturn message sends.
+ if (NoReturnEdge == false)
+ HasPlainEdge = true;
+ }
+ if (!HasPlainEdge) {
+ if (HasLiveReturn)
+ return NeverFallThrough;
+ return NeverFallThroughOrReturn;
+ }
+ if (HasAbnormalEdge || HasFakeEdge || HasLiveReturn)
+ return MaybeFallThrough;
+ // This says AlwaysFallThrough for calls to functions that are not marked
+ // noreturn, that don't return. If people would like this warning to be more
+ // accurate, such functions should be marked as noreturn.
+ return AlwaysFallThrough;
+}
+
+/// CheckFallThroughForFunctionDef - Check that we don't fall off the end of a
+/// function that should return a value. Check that we don't fall off the end
+/// of a noreturn function. We assume that functions and blocks not marked
+/// noreturn will return.
+void Sema::CheckFallThroughForFunctionDef(Decl *D, Stmt *Body,
+ AnalysisContext &AC) {
+ // FIXME: Would be nice if we had a better way to control cascading errors,
+ // but for now, avoid them. The problem is that when Parse sees:
+ // int foo() { return a; }
+ // The return is eaten and the Sema code sees just:
+ // int foo() { }
+ // which this code would then warn about.
+ if (getDiagnostics().hasErrorOccurred())
+ return;
+
+ bool ReturnsVoid = false;
+ bool HasNoReturn = false;
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+ // If the result type of the function is a dependent type, we don't know
+ // whether it will be void or not, so don't
+ if (FD->getResultType()->isDependentType())
+ return;
+ if (FD->getResultType()->isVoidType())
+ ReturnsVoid = true;
+ if (FD->hasAttr<NoReturnAttr>())
+ HasNoReturn = true;
+ } else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
+ if (MD->getResultType()->isVoidType())
+ ReturnsVoid = true;
+ if (MD->hasAttr<NoReturnAttr>())
+ HasNoReturn = true;
+ }
+
+ // Short circuit for compilation speed.
+ if ((Diags.getDiagnosticLevel(diag::warn_maybe_falloff_nonvoid_function)
+ == Diagnostic::Ignored || ReturnsVoid)
+ && (Diags.getDiagnosticLevel(diag::warn_noreturn_function_has_return_expr)
+ == Diagnostic::Ignored || !HasNoReturn)
+ && (Diags.getDiagnosticLevel(diag::warn_suggest_noreturn_block)
+ == Diagnostic::Ignored || !ReturnsVoid))
+ return;
+ // FIXME: Function try block
+ if (CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) {
+ switch (CheckFallThrough(AC)) {
+ case MaybeFallThrough:
+ if (HasNoReturn)
+ Diag(Compound->getRBracLoc(), diag::warn_falloff_noreturn_function);
+ else if (!ReturnsVoid)
+ Diag(Compound->getRBracLoc(),diag::warn_maybe_falloff_nonvoid_function);
+ break;
+ case AlwaysFallThrough:
+ if (HasNoReturn)
+ Diag(Compound->getRBracLoc(), diag::warn_falloff_noreturn_function);
+ else if (!ReturnsVoid)
+ Diag(Compound->getRBracLoc(), diag::warn_falloff_nonvoid_function);
+ break;
+ case NeverFallThroughOrReturn:
+ if (ReturnsVoid && !HasNoReturn)
+ Diag(Compound->getLBracLoc(), diag::warn_suggest_noreturn_function);
+ break;
+ case NeverFallThrough:
+ break;
+ }
+ }
+}
+
+/// CheckFallThroughForBlock - Check that we don't fall off the end of a block
+/// that should return a value. Check that we don't fall off the end of a
+/// noreturn block. We assume that functions and blocks not marked noreturn
+/// will return.
+void Sema::CheckFallThroughForBlock(QualType BlockTy, Stmt *Body,
+ AnalysisContext &AC) {
+ // FIXME: Would be nice if we had a better way to control cascading errors,
+ // but for now, avoid them. The problem is that when Parse sees:
+ // int foo() { return a; }
+ // The return is eaten and the Sema code sees just:
+ // int foo() { }
+ // which this code would then warn about.
+ if (getDiagnostics().hasErrorOccurred())
+ return;
+ bool ReturnsVoid = false;
+ bool HasNoReturn = false;
+ if (const FunctionType *FT =BlockTy->getPointeeType()->getAs<FunctionType>()){
+ if (FT->getResultType()->isVoidType())
+ ReturnsVoid = true;
+ if (FT->getNoReturnAttr())
+ HasNoReturn = true;
+ }
+
+ // Short circuit for compilation speed.
+ if (ReturnsVoid
+ && !HasNoReturn
+ && (Diags.getDiagnosticLevel(diag::warn_suggest_noreturn_block)
+ == Diagnostic::Ignored || !ReturnsVoid))
+ return;
+ // FIXME: Funtion try block
+ if (CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) {
+ switch (CheckFallThrough(AC)) {
+ case MaybeFallThrough:
+ if (HasNoReturn)
+ Diag(Compound->getRBracLoc(), diag::err_noreturn_block_has_return_expr);
+ else if (!ReturnsVoid)
+ Diag(Compound->getRBracLoc(), diag::err_maybe_falloff_nonvoid_block);
+ break;
+ case AlwaysFallThrough:
+ if (HasNoReturn)
+ Diag(Compound->getRBracLoc(), diag::err_noreturn_block_has_return_expr);
+ else if (!ReturnsVoid)
+ Diag(Compound->getRBracLoc(), diag::err_falloff_nonvoid_block);
+ break;
+ case NeverFallThroughOrReturn:
+ if (ReturnsVoid)
+ Diag(Compound->getLBracLoc(), diag::warn_suggest_noreturn_block);
+ break;
+ case NeverFallThrough:
+ break;
+ }
+ }
+}
+
+/// CheckParmsForFunctionDef - Check that the parameters of the given
+/// function are appropriate for the definition of a function. This
+/// takes care of any checks that cannot be performed on the
+/// declaration itself, e.g., that the types of each of the function
+/// parameters are complete.
+bool Sema::CheckParmsForFunctionDef(FunctionDecl *FD) {
+ bool HasInvalidParm = false;
+ for (unsigned p = 0, NumParams = FD->getNumParams(); p < NumParams; ++p) {
+ ParmVarDecl *Param = FD->getParamDecl(p);
+
+ // C99 6.7.5.3p4: the parameters in a parameter type list in a
+ // function declarator that is part of a function definition of
+ // that function shall not have incomplete type.
+ //
+ // This is also C++ [dcl.fct]p6.
+ if (!Param->isInvalidDecl() &&
+ RequireCompleteType(Param->getLocation(), Param->getType(),
+ diag::err_typecheck_decl_incomplete_type)) {
+ Param->setInvalidDecl();
+ HasInvalidParm = true;
+ }
+
+ // C99 6.9.1p5: If the declarator includes a parameter type list, the
+ // declaration of each parameter shall include an identifier.
+ if (Param->getIdentifier() == 0 &&
+ !Param->isImplicit() &&
+ !getLangOptions().CPlusPlus)
+ Diag(Param->getLocation(), diag::err_parameter_name_omitted);
+ }
+
+ return HasInvalidParm;
+}
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index a4cda01..fcd419b 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -2234,30 +2234,36 @@ void Sema::CodeCompleteCall(Scope *S, ExprTy *FnIn,
// FIXME: What if we're calling a pseudo-destructor?
// FIXME: What if we're calling a member function?
+ typedef CodeCompleteConsumer::OverloadCandidate ResultCandidate;
+ llvm::SmallVector<ResultCandidate, 8> Results;
+
Expr *NakedFn = Fn->IgnoreParenCasts();
if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(NakedFn))
AddOverloadedCallCandidates(ULE, Args, NumArgs, CandidateSet,
/*PartialOverloading=*/ true);
else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(NakedFn)) {
FunctionDecl *FDecl = dyn_cast<FunctionDecl>(DRE->getDecl());
- if (FDecl)
- AddOverloadCandidate(FDecl, Args, NumArgs, CandidateSet,
- false, false, /*PartialOverloading*/ true);
+ if (FDecl) {
+ if (!FDecl->getType()->getAs<FunctionProtoType>())
+ Results.push_back(ResultCandidate(FDecl));
+ else
+ AddOverloadCandidate(FDecl, Args, NumArgs, CandidateSet,
+ false, false, /*PartialOverloading*/ true);
+ }
}
- // Sort the overload candidate set by placing the best overloads first.
- std::stable_sort(CandidateSet.begin(), CandidateSet.end(),
- IsBetterOverloadCandidate(*this));
+ if (!CandidateSet.empty()) {
+ // Sort the overload candidate set by placing the best overloads first.
+ std::stable_sort(CandidateSet.begin(), CandidateSet.end(),
+ IsBetterOverloadCandidate(*this));
- // Add the remaining viable overload candidates as code-completion reslults.
- typedef CodeCompleteConsumer::OverloadCandidate ResultCandidate;
- llvm::SmallVector<ResultCandidate, 8> Results;
-
- for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(),
- CandEnd = CandidateSet.end();
- Cand != CandEnd; ++Cand) {
- if (Cand->Viable)
- Results.push_back(ResultCandidate(Cand->Function));
+ // Add the remaining viable overload candidates as code-completion reslults.
+ for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(),
+ CandEnd = CandidateSet.end();
+ Cand != CandEnd; ++Cand) {
+ if (Cand->Viable)
+ Results.push_back(ResultCandidate(Cand->Function));
+ }
}
if (Results.empty())
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 0ccb8f2..fbe0289 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -18,13 +18,10 @@
#include "clang/AST/APValue.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
-#include "clang/Analysis/CFG.h"
#include "clang/AST/CXXInheritance.h"
-#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/StmtCXX.h"
-#include "clang/AST/StmtObjC.h"
#include "clang/Parse/DeclSpec.h"
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/Template.h"
@@ -34,13 +31,10 @@
// FIXME: layering (ideally, Sema shouldn't be dependent on Lex API's)
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/HeaderSearch.h"
-#include "llvm/ADT/BitVector.h"
-#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Triple.h"
#include <algorithm>
#include <cstring>
#include <functional>
-#include <queue>
using namespace clang;
/// getDeclName - Return a pretty name for the specified decl if possible, or
@@ -1305,382 +1299,9 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
// Keep a chain of previous declarations.
New->setPreviousDeclaration(Old);
-}
-
-static void MarkLive(CFGBlock *e, llvm::BitVector &live) {
- std::queue<CFGBlock*> workq;
- // Prep work queue
- workq.push(e);
- // Solve
- while (!workq.empty()) {
- CFGBlock *item = workq.front();
- workq.pop();
- live.set(item->getBlockID());
- for (CFGBlock::succ_iterator I=item->succ_begin(),
- E=item->succ_end();
- I != E;
- ++I) {
- if ((*I) && !live[(*I)->getBlockID()]) {
- live.set((*I)->getBlockID());
- workq.push(*I);
- }
- }
- }
-}
-
-static SourceLocation MarkLiveTop(CFGBlock *e, llvm::BitVector &live,
- SourceManager &SM) {
- std::queue<CFGBlock*> workq;
- // Prep work queue
- workq.push(e);
- SourceLocation top;
- if (!e->empty())
- top = e[0][0].getStmt()->getLocStart();
- bool FromMainFile = false;
- bool FromSystemHeader = false;
- bool TopValid = false;
- if (top.isValid()) {
- FromMainFile = SM.isFromMainFile(top);
- FromSystemHeader = SM.isInSystemHeader(top);
- TopValid = true;
- }
- // Solve
- while (!workq.empty()) {
- CFGBlock *item = workq.front();
- workq.pop();
- SourceLocation c;
- if (!item->empty())
- c = item[0][0].getStmt()->getLocStart();
- else if (item->getTerminator())
- c = item->getTerminator()->getLocStart();
- if (c.isValid()
- && (!TopValid
- || (SM.isFromMainFile(c) && !FromMainFile)
- || (FromSystemHeader && !SM.isInSystemHeader(c))
- || SM.isBeforeInTranslationUnit(c, top))) {
- top = c;
- FromMainFile = SM.isFromMainFile(top);
- FromSystemHeader = SM.isInSystemHeader(top);
- }
- live.set(item->getBlockID());
- for (CFGBlock::succ_iterator I=item->succ_begin(),
- E=item->succ_end();
- I != E;
- ++I) {
- if ((*I) && !live[(*I)->getBlockID()]) {
- live.set((*I)->getBlockID());
- workq.push(*I);
- }
- }
- }
- return top;
-}
-namespace {
-class LineCmp {
- SourceManager &SM;
-public:
- LineCmp(SourceManager &sm) : SM(sm) {
- }
- bool operator () (SourceLocation l1, SourceLocation l2) {
- return l1 < l2;
- }
-};
-}
-
-/// CheckUnreachable - Check for unreachable code.
-void Sema::CheckUnreachable(AnalysisContext &AC) {
- // We avoid checking when there are errors, as the CFG won't faithfully match
- // the user's code.
- if (getDiagnostics().hasErrorOccurred())
- return;
- if (Diags.getDiagnosticLevel(diag::warn_unreachable) == Diagnostic::Ignored)
- return;
-
- CFG *cfg = AC.getCFG();
- if (cfg == 0)
- return;
-
- llvm::BitVector live(cfg->getNumBlockIDs());
- // Mark all live things first.
- MarkLive(&cfg->getEntry(), live);
-
- llvm::SmallVector<SourceLocation, 24> lines;
- // First, give warnings for blocks with no predecessors, as they
- // can't be part of a loop.
- for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) {
- CFGBlock &b = **I;
- if (!live[b.getBlockID()]) {
- if (b.pred_begin() == b.pred_end()) {
- if (!b.empty())
- lines.push_back(b[0].getStmt()->getLocStart());
- else if (b.getTerminator())
- lines.push_back(b.getTerminator()->getLocStart());
- // Avoid excessive errors by marking everything reachable from here
- MarkLive(&b, live);
- }
- }
- }
-
- // And then give warnings for the tops of loops.
- for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) {
- CFGBlock &b = **I;
- if (!live[b.getBlockID()])
- // Avoid excessive errors by marking everything reachable from here
- lines.push_back(MarkLiveTop(&b, live, Context.getSourceManager()));
- }
-
- std::sort(lines.begin(), lines.end(), LineCmp(Context.getSourceManager()));
- for (llvm::SmallVector<SourceLocation, 24>::iterator I = lines.begin(),
- E = lines.end();
- I != E;
- ++I)
- if (I->isValid())
- Diag(*I, diag::warn_unreachable);
-}
-
-/// CheckFallThrough - Check that we don't fall off the end of a
-/// Statement that should return a value.
-///
-/// \returns AlwaysFallThrough iff we always fall off the end of the statement,
-/// MaybeFallThrough iff we might or might not fall off the end,
-/// NeverFallThroughOrReturn iff we never fall off the end of the statement or
-/// return. We assume NeverFallThrough iff we never fall off the end of the
-/// statement but we may return. We assume that functions not marked noreturn
-/// will return.
-Sema::ControlFlowKind Sema::CheckFallThrough(AnalysisContext &AC) {
- CFG *cfg = AC.getCFG();
- if (cfg == 0)
- // FIXME: This should be NeverFallThrough
- return NeverFallThroughOrReturn;
-
- // The CFG leaves in dead things, and we don't want to dead code paths to
- // confuse us, so we mark all live things first.
- std::queue<CFGBlock*> workq;
- llvm::BitVector live(cfg->getNumBlockIDs());
- MarkLive(&cfg->getEntry(), live);
-
- // Now we know what is live, we check the live precessors of the exit block
- // and look for fall through paths, being careful to ignore normal returns,
- // and exceptional paths.
- bool HasLiveReturn = false;
- bool HasFakeEdge = false;
- bool HasPlainEdge = false;
- for (CFGBlock::pred_iterator I=cfg->getExit().pred_begin(),
- E = cfg->getExit().pred_end();
- I != E;
- ++I) {
- CFGBlock& B = **I;
- if (!live[B.getBlockID()])
- continue;
- if (B.size() == 0) {
- // A labeled empty statement, or the entry block...
- HasPlainEdge = true;
- continue;
- }
- Stmt *S = B[B.size()-1];
- if (isa<ReturnStmt>(S)) {
- HasLiveReturn = true;
- continue;
- }
- if (isa<ObjCAtThrowStmt>(S)) {
- HasFakeEdge = true;
- continue;
- }
- if (isa<CXXThrowExpr>(S)) {
- HasFakeEdge = true;
- continue;
- }
- if (const AsmStmt *AS = dyn_cast<AsmStmt>(S)) {
- if (AS->isMSAsm()) {
- HasFakeEdge = true;
- HasLiveReturn = true;
- continue;
- }
- }
-
- bool NoReturnEdge = false;
- if (CallExpr *C = dyn_cast<CallExpr>(S)) {
- Expr *CEE = C->getCallee()->IgnoreParenCasts();
- if (CEE->getType().getNoReturnAttr()) {
- NoReturnEdge = true;
- HasFakeEdge = true;
- } else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) {
- ValueDecl *VD = DRE->getDecl();
- if (VD->hasAttr<NoReturnAttr>()) {
- NoReturnEdge = true;
- HasFakeEdge = true;
- }
- }
- }
- // FIXME: Add noreturn message sends.
- if (NoReturnEdge == false)
- HasPlainEdge = true;
- }
- if (!HasPlainEdge) {
- if (HasLiveReturn)
- return NeverFallThrough;
- return NeverFallThroughOrReturn;
- }
- if (HasFakeEdge || HasLiveReturn)
- return MaybeFallThrough;
- // This says AlwaysFallThrough for calls to functions that are not marked
- // noreturn, that don't return. If people would like this warning to be more
- // accurate, such functions should be marked as noreturn.
- return AlwaysFallThrough;
-}
-
-/// CheckFallThroughForFunctionDef - Check that we don't fall off the end of a
-/// function that should return a value. Check that we don't fall off the end
-/// of a noreturn function. We assume that functions and blocks not marked
-/// noreturn will return.
-void Sema::CheckFallThroughForFunctionDef(Decl *D, Stmt *Body,
- AnalysisContext &AC) {
- // FIXME: Would be nice if we had a better way to control cascading errors,
- // but for now, avoid them. The problem is that when Parse sees:
- // int foo() { return a; }
- // The return is eaten and the Sema code sees just:
- // int foo() { }
- // which this code would then warn about.
- if (getDiagnostics().hasErrorOccurred())
- return;
-
- bool ReturnsVoid = false;
- bool HasNoReturn = false;
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
- // If the result type of the function is a dependent type, we don't know
- // whether it will be void or not, so don't
- if (FD->getResultType()->isDependentType())
- return;
- if (FD->getResultType()->isVoidType())
- ReturnsVoid = true;
- if (FD->hasAttr<NoReturnAttr>())
- HasNoReturn = true;
- } else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
- if (MD->getResultType()->isVoidType())
- ReturnsVoid = true;
- if (MD->hasAttr<NoReturnAttr>())
- HasNoReturn = true;
- }
-
- // Short circuit for compilation speed.
- if ((Diags.getDiagnosticLevel(diag::warn_maybe_falloff_nonvoid_function)
- == Diagnostic::Ignored || ReturnsVoid)
- && (Diags.getDiagnosticLevel(diag::warn_noreturn_function_has_return_expr)
- == Diagnostic::Ignored || !HasNoReturn)
- && (Diags.getDiagnosticLevel(diag::warn_suggest_noreturn_block)
- == Diagnostic::Ignored || !ReturnsVoid))
- return;
- // FIXME: Function try block
- if (CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) {
- switch (CheckFallThrough(AC)) {
- case MaybeFallThrough:
- if (HasNoReturn)
- Diag(Compound->getRBracLoc(), diag::warn_falloff_noreturn_function);
- else if (!ReturnsVoid)
- Diag(Compound->getRBracLoc(),diag::warn_maybe_falloff_nonvoid_function);
- break;
- case AlwaysFallThrough:
- if (HasNoReturn)
- Diag(Compound->getRBracLoc(), diag::warn_falloff_noreturn_function);
- else if (!ReturnsVoid)
- Diag(Compound->getRBracLoc(), diag::warn_falloff_nonvoid_function);
- break;
- case NeverFallThroughOrReturn:
- if (ReturnsVoid && !HasNoReturn)
- Diag(Compound->getLBracLoc(), diag::warn_suggest_noreturn_function);
- break;
- case NeverFallThrough:
- break;
- }
- }
-}
-
-/// CheckFallThroughForBlock - Check that we don't fall off the end of a block
-/// that should return a value. Check that we don't fall off the end of a
-/// noreturn block. We assume that functions and blocks not marked noreturn
-/// will return.
-void Sema::CheckFallThroughForBlock(QualType BlockTy, Stmt *Body,
- AnalysisContext &AC) {
- // FIXME: Would be nice if we had a better way to control cascading errors,
- // but for now, avoid them. The problem is that when Parse sees:
- // int foo() { return a; }
- // The return is eaten and the Sema code sees just:
- // int foo() { }
- // which this code would then warn about.
- if (getDiagnostics().hasErrorOccurred())
- return;
- bool ReturnsVoid = false;
- bool HasNoReturn = false;
- if (const FunctionType *FT =BlockTy->getPointeeType()->getAs<FunctionType>()){
- if (FT->getResultType()->isVoidType())
- ReturnsVoid = true;
- if (FT->getNoReturnAttr())
- HasNoReturn = true;
- }
-
- // Short circuit for compilation speed.
- if (ReturnsVoid
- && !HasNoReturn
- && (Diags.getDiagnosticLevel(diag::warn_suggest_noreturn_block)
- == Diagnostic::Ignored || !ReturnsVoid))
- return;
- // FIXME: Funtion try block
- if (CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) {
- switch (CheckFallThrough(AC)) {
- case MaybeFallThrough:
- if (HasNoReturn)
- Diag(Compound->getRBracLoc(), diag::err_noreturn_block_has_return_expr);
- else if (!ReturnsVoid)
- Diag(Compound->getRBracLoc(), diag::err_maybe_falloff_nonvoid_block);
- break;
- case AlwaysFallThrough:
- if (HasNoReturn)
- Diag(Compound->getRBracLoc(), diag::err_noreturn_block_has_return_expr);
- else if (!ReturnsVoid)
- Diag(Compound->getRBracLoc(), diag::err_falloff_nonvoid_block);
- break;
- case NeverFallThroughOrReturn:
- if (ReturnsVoid)
- Diag(Compound->getLBracLoc(), diag::warn_suggest_noreturn_block);
- break;
- case NeverFallThrough:
- break;
- }
- }
-}
-
-/// CheckParmsForFunctionDef - Check that the parameters of the given
-/// function are appropriate for the definition of a function. This
-/// takes care of any checks that cannot be performed on the
-/// declaration itself, e.g., that the types of each of the function
-/// parameters are complete.
-bool Sema::CheckParmsForFunctionDef(FunctionDecl *FD) {
- bool HasInvalidParm = false;
- for (unsigned p = 0, NumParams = FD->getNumParams(); p < NumParams; ++p) {
- ParmVarDecl *Param = FD->getParamDecl(p);
-
- // C99 6.7.5.3p4: the parameters in a parameter type list in a
- // function declarator that is part of a function definition of
- // that function shall not have incomplete type.
- //
- // This is also C++ [dcl.fct]p6.
- if (!Param->isInvalidDecl() &&
- RequireCompleteType(Param->getLocation(), Param->getType(),
- diag::err_typecheck_decl_incomplete_type)) {
- Param->setInvalidDecl();
- HasInvalidParm = true;
- }
-
- // C99 6.9.1p5: If the declarator includes a parameter type list, the
- // declaration of each parameter shall include an identifier.
- if (Param->getIdentifier() == 0 &&
- !Param->isImplicit() &&
- !getLangOptions().CPlusPlus)
- Diag(Param->getLocation(), diag::err_parameter_name_omitted);
- }
-
- return HasInvalidParm;
+ // Inherit access appropriately.
+ New->setAccess(Old->getAccess());
}
/// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with
@@ -1773,6 +1394,7 @@ Sema::DeclPtrTy Sema::ParsedFreeStandingDeclSpec(Scope *S, DeclSpec &DS) {
/// \return true if this is a forbidden redeclaration
static bool CheckAnonMemberRedeclaration(Sema &SemaRef,
Scope *S,
+ DeclContext *Owner,
DeclarationName Name,
SourceLocation NameLoc,
unsigned diagnostic) {
@@ -1785,6 +1407,11 @@ static bool CheckAnonMemberRedeclaration(Sema &SemaRef,
// Pick a representative declaration.
NamedDecl *PrevDecl = R.getRepresentativeDecl()->getUnderlyingDecl();
+ if (PrevDecl && Owner->isRecord()) {
+ RecordDecl *Record = cast<RecordDecl>(Owner);
+ if (!SemaRef.isDeclInScope(PrevDecl, Record, S))
+ return false;
+ }
SemaRef.Diag(NameLoc, diagnostic) << Name;
SemaRef.Diag(PrevDecl->getLocation(), diag::note_previous_declaration);
@@ -1819,7 +1446,7 @@ bool Sema::InjectAnonymousStructOrUnionMembers(Scope *S, DeclContext *Owner,
FEnd = AnonRecord->field_end();
F != FEnd; ++F) {
if ((*F)->getDeclName()) {
- if (CheckAnonMemberRedeclaration(*this, S, (*F)->getDeclName(),
+ if (CheckAnonMemberRedeclaration(*this, S, Owner, (*F)->getDeclName(),
(*F)->getLocation(), diagKind)) {
// C++ [class.union]p2:
// The names of the members of an anonymous union shall be
@@ -3243,7 +2870,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// Synthesize a parameter for each argument type.
for (FunctionProtoType::arg_type_iterator AI = FT->arg_type_begin(),
AE = FT->arg_type_end(); AI != AE; ++AI) {
- ParmVarDecl *Param = ParmVarDecl::Create(Context, DC,
+ ParmVarDecl *Param = ParmVarDecl::Create(Context, NewFD,
SourceLocation(), 0,
*AI, /*TInfo=*/0,
VarDecl::None, 0);
@@ -3322,6 +2949,10 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
}
if (D.getCXXScopeSpec().isSet() && !NewFD->isInvalidDecl()) {
+ // Fake up an access specifier if it's supposed to be a class member.
+ if (isa<CXXRecordDecl>(NewFD->getDeclContext()))
+ NewFD->setAccess(AS_public);
+
// An out-of-line member function declaration must also be a
// definition (C++ [dcl.meaning]p1).
// Note that this is not the case for explicit specializations of
@@ -3332,7 +2963,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
Diag(NewFD->getLocation(), diag::err_out_of_line_declaration)
<< D.getCXXScopeSpec().getRange();
NewFD->setInvalidDecl();
- } else if (!Redeclaration) {
+ } else if (!Redeclaration &&
+ !(isFriend && CurContext->isDependentContext())) {
// The user tried to provide an out-of-line definition for a
// function that is a member of a class or namespace, but there
// was no such member function declared (C++ [class.mfct]p2,
@@ -4236,8 +3868,13 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
QualType T = adjustParameterType(parmDeclType);
+ // Temporarily put parameter variables in the translation unit, not
+ // the enclosing context. This prevents them from accidentally
+ // looking like class members in C++.
+ DeclContext *DC = Context.getTranslationUnitDecl();
+
ParmVarDecl *New
- = ParmVarDecl::Create(Context, CurContext, D.getIdentifierLoc(), II,
+ = ParmVarDecl::Create(Context, DC, D.getIdentifierLoc(), II,
T, TInfo, StorageClass, 0);
if (D.isInvalidType())
@@ -4476,7 +4113,9 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg,
Decl *dcl = D.getAs<Decl>();
Stmt *Body = BodyArg.takeAs<Stmt>();
- AnalysisContext AC(dcl);
+ // Don't generate EH edges for CallExprs as we'd like to avoid the n^2
+ // explosion for destrutors that can result and the compile time hit.
+ AnalysisContext AC(dcl, false);
FunctionDecl *FD = 0;
FunctionTemplateDecl *FunTmpl = dyn_cast_or_null<FunctionTemplateDecl>(dcl);
if (FunTmpl)
@@ -6064,7 +5703,8 @@ Sema::DeclPtrTy Sema::ActOnEnumConstant(Scope *S, DeclPtrTy theEnumDecl,
// Verify that there isn't already something declared with this name in this
// scope.
- NamedDecl *PrevDecl = LookupSingleName(S, Id, LookupOrdinaryName);
+ NamedDecl *PrevDecl = LookupSingleName(S, Id, LookupOrdinaryName,
+ ForRedeclaration);
if (PrevDecl && PrevDecl->isTemplateParameter()) {
// Maybe we will complain about the shadowed template parameter.
DiagnoseTemplateParameterShadow(IdLoc, PrevDecl);
@@ -6092,8 +5732,10 @@ Sema::DeclPtrTy Sema::ActOnEnumConstant(Scope *S, DeclPtrTy theEnumDecl,
IdLoc, Id, Owned(Val));
// Register this decl in the current scope stack.
- if (New)
+ if (New) {
+ New->setAccess(TheEnumDecl->getAccess());
PushOnScopeChains(New, S);
+ }
return DeclPtrTy::make(New);
}
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index a81a04e..9ec95f3 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -1062,8 +1062,23 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD,
if (!TyD) {
if (R.isAmbiguous()) return true;
+ if (SS.isSet() && isDependentScopeSpecifier(SS)) {
+ bool NotUnknownSpecialization = false;
+ DeclContext *DC = computeDeclContext(SS, false);
+ if (CXXRecordDecl *Record = dyn_cast_or_null<CXXRecordDecl>(DC))
+ NotUnknownSpecialization = !Record->hasAnyDependentBases();
+
+ if (!NotUnknownSpecialization) {
+ // When the scope specifier can refer to a member of an unknown
+ // specialization, we take it as a type name.
+ BaseType = CheckTypenameType((NestedNameSpecifier *)SS.getScopeRep(),
+ *MemberOrBase, SS.getRange());
+ R.clear();
+ }
+ }
+
// If no results were found, try to correct typos.
- if (R.empty() &&
+ if (R.empty() && BaseType.isNull() &&
CorrectTypo(R, S, &SS, ClassDecl) && R.isSingleResult()) {
if (FieldDecl *Member = R.getAsSingle<FieldDecl>()) {
if (Member->getDeclContext()->getLookupContext()->Equals(ClassDecl)) {
@@ -1106,20 +1121,22 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD,
}
}
- if (!TyD) {
+ if (!TyD && BaseType.isNull()) {
Diag(IdLoc, diag::err_mem_init_not_member_or_class)
<< MemberOrBase << SourceRange(IdLoc, RParenLoc);
return true;
}
}
- BaseType = Context.getTypeDeclType(TyD);
- if (SS.isSet()) {
- NestedNameSpecifier *Qualifier =
- static_cast<NestedNameSpecifier*>(SS.getScopeRep());
+ if (BaseType.isNull()) {
+ BaseType = Context.getTypeDeclType(TyD);
+ if (SS.isSet()) {
+ NestedNameSpecifier *Qualifier =
+ static_cast<NestedNameSpecifier*>(SS.getScopeRep());
- // FIXME: preserve source range information
- BaseType = Context.getQualifiedNameType(Qualifier, BaseType);
+ // FIXME: preserve source range information
+ BaseType = Context.getQualifiedNameType(Qualifier, BaseType);
+ }
}
}
@@ -4470,9 +4487,9 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
= dyn_cast<CXXRecordDecl>(T2->getAs<RecordType>()->getDecl());
OverloadCandidateSet CandidateSet;
- const UnresolvedSet *Conversions
+ const UnresolvedSetImpl *Conversions
= T2RecordDecl->getVisibleConversionFunctions();
- for (UnresolvedSet::iterator I = Conversions->begin(),
+ for (UnresolvedSetImpl::iterator I = Conversions->begin(),
E = Conversions->end(); I != E; ++I) {
NamedDecl *D = *I;
CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(D->getDeclContext());
@@ -5594,26 +5611,24 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
QualType NewTy = New->getType()->getAs<FunctionType>()->getResultType();
QualType OldTy = Old->getType()->getAs<FunctionType>()->getResultType();
- QualType CNewTy = Context.getCanonicalType(NewTy);
- QualType COldTy = Context.getCanonicalType(OldTy);
-
- if (CNewTy == COldTy &&
- CNewTy.getLocalCVRQualifiers() == COldTy.getLocalCVRQualifiers())
+ if (Context.hasSameType(NewTy, OldTy))
return false;
// Check if the return types are covariant
QualType NewClassTy, OldClassTy;
/// Both types must be pointers or references to classes.
- if (PointerType *NewPT = dyn_cast<PointerType>(NewTy)) {
- if (PointerType *OldPT = dyn_cast<PointerType>(OldTy)) {
+ if (const PointerType *NewPT = NewTy->getAs<PointerType>()) {
+ if (const PointerType *OldPT = OldTy->getAs<PointerType>()) {
NewClassTy = NewPT->getPointeeType();
OldClassTy = OldPT->getPointeeType();
}
- } else if (ReferenceType *NewRT = dyn_cast<ReferenceType>(NewTy)) {
- if (ReferenceType *OldRT = dyn_cast<ReferenceType>(OldTy)) {
- NewClassTy = NewRT->getPointeeType();
- OldClassTy = OldRT->getPointeeType();
+ } else if (const ReferenceType *NewRT = NewTy->getAs<ReferenceType>()) {
+ if (const ReferenceType *OldRT = OldTy->getAs<ReferenceType>()) {
+ if (NewRT->getTypeClass() == OldRT->getTypeClass()) {
+ NewClassTy = NewRT->getPointeeType();
+ OldClassTy = OldRT->getPointeeType();
+ }
}
}
@@ -5661,7 +5676,7 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
}
// The qualifiers of the return types must be the same.
- if (CNewTy.getLocalCVRQualifiers() != COldTy.getLocalCVRQualifiers()) {
+ if (NewTy.getLocalCVRQualifiers() != OldTy.getLocalCVRQualifiers()) {
Diag(New->getLocation(),
diag::err_covariant_return_type_different_qualifications)
<< New->getDeclName() << NewTy << OldTy;
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index f2fc1f4..1b07d19 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -81,6 +81,7 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
IdentifierInfo *ClassName, SourceLocation ClassLoc,
IdentifierInfo *SuperName, SourceLocation SuperLoc,
const DeclPtrTy *ProtoRefs, unsigned NumProtoRefs,
+ const SourceLocation *ProtoLocs,
SourceLocation EndProtoLoc, AttributeList *AttrList) {
assert(ClassName && "Missing class identifier");
@@ -201,7 +202,7 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
/// Check then save referenced protocols.
if (NumProtoRefs) {
IDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs,
- Context);
+ ProtoLocs, Context);
IDecl->setLocEnd(EndProtoLoc);
}
@@ -279,6 +280,7 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc,
SourceLocation ProtocolLoc,
const DeclPtrTy *ProtoRefs,
unsigned NumProtoRefs,
+ const SourceLocation *ProtoLocs,
SourceLocation EndProtoLoc,
AttributeList *AttrList) {
// FIXME: Deal with AttrList.
@@ -312,7 +314,8 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc,
ProcessDeclAttributeList(TUScope, PDecl, AttrList);
if (NumProtoRefs) {
/// Check then save referenced protocols.
- PDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs,Context);
+ PDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs,
+ ProtoLocs, Context);
PDecl->setLocEnd(EndProtoLoc);
}
@@ -432,17 +435,17 @@ void Sema::ComparePropertiesInBaseAndSuper(ObjCInterfaceDecl *IDecl) {
}
}
-/// MergeOneProtocolPropertiesIntoClass - This routine goes thru the list
-/// of properties declared in a protocol and adds them to the list
-/// of properties for current class/category if it is not there already.
+/// MatchOneProtocolPropertiesInClass - This routine goes thru the list
+/// of properties declared in a protocol and compares their attribute against
+/// the same property declared in the class or category.
void
-Sema::MergeOneProtocolPropertiesIntoClass(Decl *CDecl,
+Sema::MatchOneProtocolPropertiesInClass(Decl *CDecl,
ObjCProtocolDecl *PDecl) {
ObjCInterfaceDecl *IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(CDecl);
if (!IDecl) {
// Category
ObjCCategoryDecl *CatDecl = static_cast<ObjCCategoryDecl*>(CDecl);
- assert (CatDecl && "MergeOneProtocolPropertiesIntoClass");
+ assert (CatDecl && "MatchOneProtocolPropertiesInClass");
for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
E = PDecl->prop_end(); P != E; ++P) {
ObjCPropertyDecl *Pr = (*P);
@@ -471,35 +474,35 @@ Sema::MergeOneProtocolPropertiesIntoClass(Decl *CDecl,
}
}
-/// MergeProtocolPropertiesIntoClass - This routine merges properties
-/// declared in 'MergeItsProtocols' objects (which can be a class or an
-/// inherited protocol into the list of properties for class/category 'CDecl'
+/// CompareProperties - This routine compares properties
+/// declared in 'ClassOrProtocol' objects (which can be a class or an
+/// inherited protocol with the list of properties for class/category 'CDecl'
///
-void Sema::MergeProtocolPropertiesIntoClass(Decl *CDecl,
- DeclPtrTy MergeItsProtocols) {
- Decl *ClassDecl = MergeItsProtocols.getAs<Decl>();
+void Sema::CompareProperties(Decl *CDecl,
+ DeclPtrTy ClassOrProtocol) {
+ Decl *ClassDecl = ClassOrProtocol.getAs<Decl>();
ObjCInterfaceDecl *IDecl = dyn_cast_or_null<ObjCInterfaceDecl>(CDecl);
if (!IDecl) {
// Category
ObjCCategoryDecl *CatDecl = static_cast<ObjCCategoryDecl*>(CDecl);
- assert (CatDecl && "MergeProtocolPropertiesIntoClass");
+ assert (CatDecl && "CompareProperties");
if (ObjCCategoryDecl *MDecl = dyn_cast<ObjCCategoryDecl>(ClassDecl)) {
for (ObjCCategoryDecl::protocol_iterator P = MDecl->protocol_begin(),
E = MDecl->protocol_end(); P != E; ++P)
- // Merge properties of category (*P) into IDECL's
- MergeOneProtocolPropertiesIntoClass(CatDecl, *P);
+ // Match properties of category with those of protocol (*P)
+ MatchOneProtocolPropertiesInClass(CatDecl, *P);
- // Go thru the list of protocols for this category and recursively merge
- // their properties into this class as well.
+ // Go thru the list of protocols for this category and recursively match
+ // their properties with those in the category.
for (ObjCCategoryDecl::protocol_iterator P = CatDecl->protocol_begin(),
E = CatDecl->protocol_end(); P != E; ++P)
- MergeProtocolPropertiesIntoClass(CatDecl, DeclPtrTy::make(*P));
+ CompareProperties(CatDecl, DeclPtrTy::make(*P));
} else {
ObjCProtocolDecl *MD = cast<ObjCProtocolDecl>(ClassDecl);
for (ObjCProtocolDecl::protocol_iterator P = MD->protocol_begin(),
E = MD->protocol_end(); P != E; ++P)
- MergeOneProtocolPropertiesIntoClass(CatDecl, *P);
+ MatchOneProtocolPropertiesInClass(CatDecl, *P);
}
return;
}
@@ -507,19 +510,19 @@ void Sema::MergeProtocolPropertiesIntoClass(Decl *CDecl,
if (ObjCInterfaceDecl *MDecl = dyn_cast<ObjCInterfaceDecl>(ClassDecl)) {
for (ObjCInterfaceDecl::protocol_iterator P = MDecl->protocol_begin(),
E = MDecl->protocol_end(); P != E; ++P)
- // Merge properties of class (*P) into IDECL's
- MergeOneProtocolPropertiesIntoClass(IDecl, *P);
+ // Match properties of class IDecl with those of protocol (*P).
+ MatchOneProtocolPropertiesInClass(IDecl, *P);
- // Go thru the list of protocols for this class and recursively merge
- // their properties into this class as well.
+ // Go thru the list of protocols for this class and recursively match
+ // their properties with those declared in the class.
for (ObjCInterfaceDecl::protocol_iterator P = IDecl->protocol_begin(),
E = IDecl->protocol_end(); P != E; ++P)
- MergeProtocolPropertiesIntoClass(IDecl, DeclPtrTy::make(*P));
+ CompareProperties(IDecl, DeclPtrTy::make(*P));
} else {
ObjCProtocolDecl *MD = cast<ObjCProtocolDecl>(ClassDecl);
for (ObjCProtocolDecl::protocol_iterator P = MD->protocol_begin(),
E = MD->protocol_end(); P != E; ++P)
- MergeOneProtocolPropertiesIntoClass(IDecl, *P);
+ MatchOneProtocolPropertiesInClass(IDecl, *P);
}
}
@@ -559,6 +562,7 @@ Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc,
unsigned NumElts,
AttributeList *attrList) {
llvm::SmallVector<ObjCProtocolDecl*, 32> Protocols;
+ llvm::SmallVector<SourceLocation, 8> ProtoLocs;
for (unsigned i = 0; i != NumElts; ++i) {
IdentifierInfo *Ident = IdentList[i].first;
@@ -571,11 +575,13 @@ Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc,
if (attrList)
ProcessDeclAttributeList(TUScope, PDecl, attrList);
Protocols.push_back(PDecl);
+ ProtoLocs.push_back(IdentList[i].second);
}
ObjCForwardProtocolDecl *PDecl =
ObjCForwardProtocolDecl::Create(Context, CurContext, AtProtocolLoc,
- &Protocols[0], Protocols.size());
+ Protocols.data(), Protocols.size(),
+ ProtoLocs.data());
CurContext->addDecl(PDecl);
CheckObjCDeclScope(PDecl);
return DeclPtrTy::make(PDecl);
@@ -588,9 +594,11 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
SourceLocation CategoryLoc,
const DeclPtrTy *ProtoRefs,
unsigned NumProtoRefs,
+ const SourceLocation *ProtoLocs,
SourceLocation EndProtoLoc) {
ObjCCategoryDecl *CDecl =
- ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc, CategoryName);
+ ObjCCategoryDecl::Create(Context, CurContext, AtInterfaceLoc, ClassLoc,
+ CategoryLoc, CategoryName);
// FIXME: PushOnScopeChains?
CurContext->addDecl(CDecl);
@@ -623,12 +631,12 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc,
if (NumProtoRefs) {
CDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs,
- Context);
- CDecl->setLocEnd(EndProtoLoc);
+ ProtoLocs, Context);
// Protocols in the class extension belong to the class.
if (!CDecl->getIdentifier())
IDecl->mergeClassExtensionProtocolList((ObjCProtocolDecl**)ProtoRefs,
- NumProtoRefs,Context);
+ NumProtoRefs, ProtoLocs,
+ Context);
}
CheckObjCDeclScope(CDecl);
@@ -650,6 +658,7 @@ Sema::DeclPtrTy Sema::ActOnStartCategoryImplementation(
// Category @implementation with no corresponding @interface.
// Create and install one.
CatIDecl = ObjCCategoryDecl::Create(Context, CurContext, SourceLocation(),
+ SourceLocation(), SourceLocation(),
CatName);
CatIDecl->setClassInterface(IDecl);
CatIDecl->insertNextClassCategory();
@@ -1077,6 +1086,92 @@ void Sema::MatchAllMethodDeclarations(const llvm::DenseSet<Selector> &InsMap,
}
}
+/// CollectImmediateProperties - This routine collects all properties in
+/// the class and its conforming protocols; but not those it its super class.
+void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl,
+ llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& PropMap) {
+ if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl)) {
+ for (ObjCContainerDecl::prop_iterator P = IDecl->prop_begin(),
+ E = IDecl->prop_end(); P != E; ++P) {
+ ObjCPropertyDecl *Prop = (*P);
+ PropMap[Prop->getIdentifier()] = Prop;
+ }
+ // scan through class's protocols.
+ for (ObjCInterfaceDecl::protocol_iterator PI = IDecl->protocol_begin(),
+ E = IDecl->protocol_end(); PI != E; ++PI)
+ CollectImmediateProperties((*PI), PropMap);
+ }
+ if (ObjCCategoryDecl *CATDecl = dyn_cast<ObjCCategoryDecl>(CDecl)) {
+ for (ObjCContainerDecl::prop_iterator P = CATDecl->prop_begin(),
+ E = CATDecl->prop_end(); P != E; ++P) {
+ ObjCPropertyDecl *Prop = (*P);
+ PropMap[Prop->getIdentifier()] = Prop;
+ }
+ // scan through class's protocols.
+ for (ObjCInterfaceDecl::protocol_iterator PI = CATDecl->protocol_begin(),
+ E = CATDecl->protocol_end(); PI != E; ++PI)
+ CollectImmediateProperties((*PI), PropMap);
+ }
+ else if (ObjCProtocolDecl *PDecl = dyn_cast<ObjCProtocolDecl>(CDecl)) {
+ for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(),
+ E = PDecl->prop_end(); P != E; ++P) {
+ ObjCPropertyDecl *Prop = (*P);
+ ObjCPropertyDecl *&PropEntry = PropMap[Prop->getIdentifier()];
+ if (!PropEntry)
+ PropEntry = Prop;
+ }
+ // scan through protocol's protocols.
+ for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(),
+ E = PDecl->protocol_end(); PI != E; ++PI)
+ CollectImmediateProperties((*PI), PropMap);
+ }
+}
+
+void Sema::DiagnoseUnimplementedProperties(ObjCImplDecl* IMPDecl,
+ ObjCContainerDecl *CDecl,
+ const llvm::DenseSet<Selector>& InsMap) {
+ llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*> PropMap;
+ CollectImmediateProperties(CDecl, PropMap);
+ if (PropMap.empty())
+ return;
+
+ llvm::DenseSet<ObjCPropertyDecl *> PropImplMap;
+ for (ObjCImplDecl::propimpl_iterator
+ I = IMPDecl->propimpl_begin(),
+ EI = IMPDecl->propimpl_end(); I != EI; ++I)
+ PropImplMap.insert((*I)->getPropertyDecl());
+
+ for (llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>::iterator
+ P = PropMap.begin(), E = PropMap.end(); P != E; ++P) {
+ ObjCPropertyDecl *Prop = P->second;
+ // Is there a matching propery synthesize/dynamic?
+ if (Prop->isInvalidDecl() ||
+ Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional ||
+ PropImplMap.count(Prop))
+ continue;
+
+ if (!InsMap.count(Prop->getGetterName())) {
+ Diag(Prop->getLocation(),
+ isa<ObjCCategoryDecl>(CDecl) ?
+ diag::warn_setter_getter_impl_required_in_category :
+ diag::warn_setter_getter_impl_required)
+ << Prop->getDeclName() << Prop->getGetterName();
+ Diag(IMPDecl->getLocation(),
+ diag::note_property_impl_required);
+ }
+
+ if (!Prop->isReadOnly() && !InsMap.count(Prop->getSetterName())) {
+ Diag(Prop->getLocation(),
+ isa<ObjCCategoryDecl>(CDecl) ?
+ diag::warn_setter_getter_impl_required_in_category :
+ diag::warn_setter_getter_impl_required)
+ << Prop->getDeclName() << Prop->getSetterName();
+ Diag(IMPDecl->getLocation(),
+ diag::note_property_impl_required);
+ }
+ }
+}
+
void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl,
ObjCContainerDecl* CDecl,
bool IncompleteImpl) {
@@ -1091,39 +1186,8 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl,
// an implementation or 2) there is a @synthesize/@dynamic implementation
// of the property in the @implementation.
if (isa<ObjCInterfaceDecl>(CDecl))
- for (ObjCContainerDecl::prop_iterator P = CDecl->prop_begin(),
- E = CDecl->prop_end(); P != E; ++P) {
- ObjCPropertyDecl *Prop = (*P);
- if (Prop->isInvalidDecl())
- continue;
- ObjCPropertyImplDecl *PI = 0;
- // Is there a matching propery synthesize/dynamic?
- for (ObjCImplDecl::propimpl_iterator
- I = IMPDecl->propimpl_begin(),
- EI = IMPDecl->propimpl_end(); I != EI; ++I)
- if ((*I)->getPropertyDecl() == Prop) {
- PI = (*I);
- break;
- }
- if (PI)
- continue;
- if (!InsMap.count(Prop->getGetterName())) {
- Diag(Prop->getLocation(),
- diag::warn_setter_getter_impl_required)
- << Prop->getDeclName() << Prop->getGetterName();
- Diag(IMPDecl->getLocation(),
- diag::note_property_impl_required);
- }
-
- if (!Prop->isReadOnly() && !InsMap.count(Prop->getSetterName())) {
- Diag(Prop->getLocation(),
- diag::warn_setter_getter_impl_required)
- << Prop->getDeclName() << Prop->getSetterName();
- Diag(IMPDecl->getLocation(),
- diag::note_property_impl_required);
- }
- }
-
+ DiagnoseUnimplementedProperties(IMPDecl, CDecl, InsMap);
+
llvm::DenseSet<Selector> ClsMap;
for (ObjCImplementationDecl::classmeth_iterator
I = IMPDecl->classmeth_begin(),
@@ -1163,7 +1227,18 @@ void Sema::ImplMethodsVsClassMethods(ObjCImplDecl* IMPDecl,
E = C->protocol_end(); PI != E; ++PI)
CheckProtocolMethodDefs(IMPDecl->getLocation(), *PI, IncompleteImpl,
InsMap, ClsMap, C->getClassInterface());
- }
+ // Report unimplemented properties in the category as well.
+ // When reporting on missing setter/getters, do not report when
+ // setter/getter is implemented in category's primary class
+ // implementation.
+ if (ObjCInterfaceDecl *ID = C->getClassInterface())
+ if (ObjCImplDecl *IMP = ID->getImplementation()) {
+ for (ObjCImplementationDecl::instmeth_iterator
+ I = IMP->instmeth_begin(), E = IMP->instmeth_end(); I!=E; ++I)
+ InsMap.insert((*I)->getSelector());
+ }
+ DiagnoseUnimplementedProperties(IMPDecl, CDecl, InsMap);
+ }
} else
assert(false && "invalid ObjCContainerDecl type.");
}
@@ -1694,14 +1769,14 @@ void Sema::ActOnAtEnd(SourceRange AtEnd,
// Compares properties declared in this class to those of its
// super class.
ComparePropertiesInBaseAndSuper(I);
- MergeProtocolPropertiesIntoClass(I, DeclPtrTy::make(I));
+ CompareProperties(I, DeclPtrTy::make(I));
} else if (ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(ClassDecl)) {
// Categories are used to extend the class by declaring new methods.
// By the same token, they are also used to add new properties. No
// need to compare the added property to those in the class.
- // Merge protocol properties into category
- MergeProtocolPropertiesIntoClass(C, DeclPtrTy::make(C));
+ // Compare protocol properties with those in category
+ CompareProperties(C, DeclPtrTy::make(C));
if (C->getIdentifier() == 0)
DiagnoseClassExtensionDupMethods(C, C->getClassInterface());
}
@@ -2111,7 +2186,8 @@ Sema::DeclPtrTy Sema::ActOnProperty(Scope *S, SourceLocation AtLoc,
assert(DC && "ClassDecl is not a DeclContext");
ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, DC,
FD.D.getIdentifierLoc(),
- FD.D.getIdentifier(), T);
+ FD.D.getIdentifier(),
+ AtLoc, T);
DeclContext::lookup_result Found = DC->lookup(PDecl->getDeclName());
if (Found.first != Found.second && isa<ObjCPropertyDecl>(*Found.first)) {
Diag(PDecl->getLocation(), diag::err_duplicate_property);
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 034accd..50976f7 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -3082,15 +3082,9 @@ Sema::LookupMemberExpr(LookupResult &R, Expr *&BaseExpr,
if (Setter && DiagnoseUseOfDecl(Setter, MemberLoc))
return ExprError();
- if (Getter || Setter) {
+ if (Getter) {
QualType PType;
-
- if (Getter)
- PType = Getter->getResultType();
- else
- // Get the expression type from Setter's incoming parameter.
- PType = (*(Setter->param_end() -1))->getType();
- // FIXME: we must check that the setter has property type.
+ PType = Getter->getResultType();
return Owned(new (Context) ObjCImplicitSetterGetterRefExpr(Getter, PType,
Setter, MemberLoc, BaseExpr));
}
@@ -3663,11 +3657,21 @@ Action::OwningExprResult
Sema::ActOnCompoundLiteral(SourceLocation LParenLoc, TypeTy *Ty,
SourceLocation RParenLoc, ExprArg InitExpr) {
assert((Ty != 0) && "ActOnCompoundLiteral(): missing type");
-
- QualType literalType = GetTypeFromParser(Ty);
-
// FIXME: put back this assert when initializers are worked out.
//assert((InitExpr != 0) && "ActOnCompoundLiteral(): missing expression");
+
+ TypeSourceInfo *TInfo;
+ QualType literalType = GetTypeFromParser(Ty, &TInfo);
+ if (!TInfo)
+ TInfo = Context.getTrivialTypeSourceInfo(literalType);
+
+ return BuildCompoundLiteralExpr(LParenLoc, TInfo, RParenLoc, move(InitExpr));
+}
+
+Action::OwningExprResult
+Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo,
+ SourceLocation RParenLoc, ExprArg InitExpr) {
+ QualType literalType = TInfo->getType();
Expr *literalExpr = static_cast<Expr*>(InitExpr.get());
if (literalType->isArrayType()) {
@@ -3703,8 +3707,7 @@ Sema::ActOnCompoundLiteral(SourceLocation LParenLoc, TypeTy *Ty,
Result.release();
- // FIXME: Store the TInfo to preserve type information better.
- return Owned(new (Context) CompoundLiteralExpr(LParenLoc, literalType,
+ return Owned(new (Context) CompoundLiteralExpr(LParenLoc, TInfo, literalType,
literalExpr, isFileScope));
}
@@ -3906,26 +3909,38 @@ bool Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, Expr *&CastExpr,
Action::OwningExprResult
Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc, TypeTy *Ty,
SourceLocation RParenLoc, ExprArg Op) {
- CastExpr::CastKind Kind = CastExpr::CK_Unknown;
-
assert((Ty != 0) && (Op.get() != 0) &&
"ActOnCastExpr(): missing type or expr");
- Expr *castExpr = (Expr *)Op.get();
- //FIXME: Preserve type source info.
- QualType castType = GetTypeFromParser(Ty);
+ TypeSourceInfo *castTInfo;
+ QualType castType = GetTypeFromParser(Ty, &castTInfo);
+ if (!castTInfo)
+ castTInfo = Context.getTrivialTypeSourceInfo(castType);
// If the Expr being casted is a ParenListExpr, handle it specially.
+ Expr *castExpr = (Expr *)Op.get();
if (isa<ParenListExpr>(castExpr))
- return ActOnCastOfParenListExpr(S, LParenLoc, RParenLoc, move(Op),castType);
+ return ActOnCastOfParenListExpr(S, LParenLoc, RParenLoc, move(Op),
+ castTInfo);
+
+ return BuildCStyleCastExpr(LParenLoc, castTInfo, RParenLoc, move(Op));
+}
+
+Action::OwningExprResult
+Sema::BuildCStyleCastExpr(SourceLocation LParenLoc, TypeSourceInfo *Ty,
+ SourceLocation RParenLoc, ExprArg Op) {
+ Expr *castExpr = static_cast<Expr*>(Op.get());
+
CXXMethodDecl *Method = 0;
- if (CheckCastTypes(SourceRange(LParenLoc, RParenLoc), castType, castExpr,
+ CastExpr::CastKind Kind = CastExpr::CK_Unknown;
+ if (CheckCastTypes(SourceRange(LParenLoc, RParenLoc), Ty->getType(), castExpr,
Kind, Method))
return ExprError();
if (Method) {
- OwningExprResult CastArg = BuildCXXCastArgument(LParenLoc, castType, Kind,
- Method, move(Op));
+ // FIXME: preserve type source info here
+ OwningExprResult CastArg = BuildCXXCastArgument(LParenLoc, Ty->getType(),
+ Kind, Method, move(Op));
if (CastArg.isInvalid())
return ExprError();
@@ -3935,8 +3950,8 @@ Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc, TypeTy *Ty,
Op.release();
}
- return Owned(new (Context) CStyleCastExpr(castType.getNonReferenceType(),
- Kind, castExpr, castType,
+ return Owned(new (Context) CStyleCastExpr(Ty->getType().getNonReferenceType(),
+ Kind, castExpr, Ty,
LParenLoc, RParenLoc));
}
@@ -3961,8 +3976,9 @@ Sema::MaybeConvertParenListExprToParenExpr(Scope *S, ExprArg EA) {
Action::OwningExprResult
Sema::ActOnCastOfParenListExpr(Scope *S, SourceLocation LParenLoc,
SourceLocation RParenLoc, ExprArg Op,
- QualType Ty) {
+ TypeSourceInfo *TInfo) {
ParenListExpr *PE = (ParenListExpr *)Op.get();
+ QualType Ty = TInfo->getType();
// If this is an altivec initializer, '(' type ')' '(' init, ..., init ')'
// then handle it as such.
@@ -3982,13 +3998,12 @@ Sema::ActOnCastOfParenListExpr(Scope *S, SourceLocation LParenLoc,
InitListExpr *E = new (Context) InitListExpr(LParenLoc, &initExprs[0],
initExprs.size(), RParenLoc);
E->setType(Ty);
- return ActOnCompoundLiteral(LParenLoc, Ty.getAsOpaquePtr(), RParenLoc,
- Owned(E));
+ return BuildCompoundLiteralExpr(LParenLoc, TInfo, RParenLoc, Owned(E));
} else {
// This is not an AltiVec-style cast, so turn the ParenListExpr into a
// sequence of BinOp comma operators.
Op = MaybeConvertParenListExprToParenExpr(S, move(Op));
- return ActOnCastExpr(S, LParenLoc, Ty.getAsOpaquePtr(), RParenLoc,move(Op));
+ return BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc, move(Op));
}
}
@@ -4702,8 +4717,9 @@ static void ConstructTransparentUnion(ASTContext &C, Expr *&E,
// Build a compound literal constructing a value of the transparent
// union type from this initializer list.
- E = new (C) CompoundLiteralExpr(SourceLocation(), UnionType, Initializer,
- false);
+ TypeSourceInfo *unionTInfo = C.getTrivialTypeSourceInfo(UnionType);
+ E = new (C) CompoundLiteralExpr(SourceLocation(), unionTInfo, UnionType,
+ Initializer, false);
}
Sema::AssignConvertType
@@ -6785,10 +6801,13 @@ void Sema::ActOnBlockArguments(Declarator &ParamInfo, Scope *CurScope) {
CurBlock->TheDecl->setIsVariadic(CurBlock->isVariadic);
ProcessDeclAttributes(CurScope, CurBlock->TheDecl, ParamInfo);
for (BlockDecl::param_iterator AI = CurBlock->TheDecl->param_begin(),
- E = CurBlock->TheDecl->param_end(); AI != E; ++AI)
+ E = CurBlock->TheDecl->param_end(); AI != E; ++AI) {
+ (*AI)->setOwningFunction(CurBlock->TheDecl);
+
// If this has an identifier, add it to the scope stack.
if ((*AI)->getIdentifier())
PushOnScopeChains(*AI, CurBlock->TheScope);
+ }
// Check for a valid sentinel attribute on this block.
if (!CurBlock->isVariadic &&
@@ -6868,6 +6887,26 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
CurFunctionNeedsScopeChecking = BSI->SavedFunctionNeedsScopeChecking;
BSI->TheDecl->setBody(body.takeAs<CompoundStmt>());
+
+ bool Good = true;
+ // Check goto/label use.
+ for (llvm::DenseMap<IdentifierInfo*, LabelStmt*>::iterator
+ I = BSI->LabelMap.begin(), E = BSI->LabelMap.end(); I != E; ++I) {
+ LabelStmt *L = I->second;
+
+ // Verify that we have no forward references left. If so, there was a goto
+ // or address of a label taken, but no definition of it.
+ if (L->getSubStmt() != 0)
+ continue;
+
+ // Emit error.
+ Diag(L->getIdentLoc(), diag::err_undeclared_label_use) << L->getName();
+ Good = false;
+ }
+ BSI->LabelMap.clear();
+ if (!Good)
+ return ExprError();
+
AnalysisContext AC(BSI->TheDecl);
CheckFallThroughForBlock(BlockTy, BSI->TheDecl->getBody(), AC);
CheckUnreachable(AC);
@@ -7203,8 +7242,15 @@ void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
AlreadyInstantiated = true;
}
- if (!AlreadyInstantiated)
- PendingImplicitInstantiations.push_back(std::make_pair(Function, Loc));
+ if (!AlreadyInstantiated) {
+ if (isa<CXXRecordDecl>(Function->getDeclContext()) &&
+ cast<CXXRecordDecl>(Function->getDeclContext())->isLocalClass())
+ PendingLocalImplicitInstantiations.push_back(std::make_pair(Function,
+ Loc));
+ else
+ PendingImplicitInstantiations.push_back(std::make_pair(Function,
+ Loc));
+ }
}
// FIXME: keep track of references to static functions
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index d10e11f..b004fc3 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -196,8 +196,10 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep,
SourceLocation *CommaLocs,
SourceLocation RParenLoc) {
assert(TypeRep && "Missing type!");
- // FIXME: Preserve type source info.
- QualType Ty = GetTypeFromParser(TypeRep);
+ TypeSourceInfo *TInfo;
+ QualType Ty = GetTypeFromParser(TypeRep, &TInfo);
+ if (!TInfo)
+ TInfo = Context.getTrivialTypeSourceInfo(Ty, SourceLocation());
unsigned NumExprs = exprs.size();
Expr **Exprs = (Expr**)exprs.get();
SourceLocation TyBeginLoc = TypeRange.getBegin();
@@ -252,7 +254,7 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep,
}
return Owned(new (Context) CXXFunctionalCastExpr(Ty.getNonReferenceType(),
- Ty, TyBeginLoc, Kind,
+ TInfo, TyBeginLoc, Kind,
Exprs[0], RParenLoc));
}
@@ -891,9 +893,9 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
if (const RecordType *Record = Type->getAs<RecordType>()) {
llvm::SmallVector<CXXConversionDecl *, 4> ObjectPtrConversions;
CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl());
- const UnresolvedSet *Conversions = RD->getVisibleConversionFunctions();
+ const UnresolvedSetImpl *Conversions = RD->getVisibleConversionFunctions();
- for (UnresolvedSet::iterator I = Conversions->begin(),
+ for (UnresolvedSetImpl::iterator I = Conversions->begin(),
E = Conversions->end(); I != E; ++I) {
// Skip over templated conversion functions; they aren't considered.
if (isa<FunctionTemplateDecl>(*I))
@@ -1448,12 +1450,14 @@ QualType Sema::CheckPointerToMemberOperands(
// overkill?
if (!IsDerivedFrom(LType, Class, Paths) ||
Paths.isAmbiguous(Context.getCanonicalType(Class))) {
- const char *ReplaceStr = isIndirect ? ".*" : "->*";
Diag(Loc, diag::err_bad_memptr_lhs) << OpSpelling
- << (int)isIndirect << lex->getType() <<
- CodeModificationHint::CreateReplacement(SourceRange(Loc), ReplaceStr);
+ << (int)isIndirect << lex->getType();
return QualType();
}
+ // Cast LHS to type of use.
+ QualType UseType = isIndirect ? Context.getPointerType(Class) : Class;
+ bool isLValue = !isIndirect && lex->isLvalue(Context) == Expr::LV_Valid;
+ ImpCastExprToType(lex, UseType, CastExpr::CK_DerivedToBase, isLValue);
}
if (isa<CXXZeroInitValueExpr>(rex->IgnoreParens())) {
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index 85889fa..ea8f4e3 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -398,7 +398,17 @@ Sema::ExprResult Sema::ActOnClassMessage(
return ActOnInstanceMessage(ReceiverExpr.get(), Sel, lbrac,
selectorLoc, rbrac, Args, NumArgs);
}
- return Diag(receiverLoc, diag::err_undeclared_var_use) << receiverName;
+ else if (TypedefDecl *OCTD = dyn_cast_or_null<TypedefDecl>(SuperDecl)) {
+ const ObjCInterfaceType *OCIT;
+ OCIT = OCTD->getUnderlyingType()->getAs<ObjCInterfaceType>();
+ if (!OCIT) {
+ Diag(receiverLoc, diag::err_invalid_receiver_to_message);
+ return true;
+ }
+ ClassDecl = OCIT->getDecl();
+ }
+ else
+ return Diag(receiverLoc, diag::err_undeclared_var_use) << receiverName;
}
} else
ClassDecl = getObjCInterfaceDecl(receiverName, receiverLoc);
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 1970f56..fd62e1a 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -382,7 +382,8 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity,
if (hadError)
return;
- if (ElementEntity.getKind() == InitializedEntity::EK_ArrayOrVectorElement)
+ if (ElementEntity.getKind() == InitializedEntity::EK_ArrayElement ||
+ ElementEntity.getKind() == InitializedEntity::EK_VectorElement)
ElementEntity.setElementIndex(Init);
if (Init >= NumInits || !ILE->getInit(Init)) {
@@ -1828,12 +1829,15 @@ bool Sema::CheckInitList(const InitializedEntity &Entity,
InitializedEntity::InitializedEntity(ASTContext &Context, unsigned Index,
const InitializedEntity &Parent)
- : Kind(EK_ArrayOrVectorElement), Parent(&Parent), Index(Index)
+ : Parent(&Parent), Index(Index)
{
- if (const ArrayType *AT = Context.getAsArrayType(Parent.getType()))
+ if (const ArrayType *AT = Context.getAsArrayType(Parent.getType())) {
+ Kind = EK_ArrayElement;
Type = AT->getElementType();
- else
+ } else {
+ Kind = EK_VectorElement;
Type = Parent.getType()->getAs<VectorType>()->getElementType();
+ }
}
InitializedEntity InitializedEntity::InitializeBase(ASTContext &Context,
@@ -1862,7 +1866,8 @@ DeclarationName InitializedEntity::getName() const {
case EK_New:
case EK_Temporary:
case EK_Base:
- case EK_ArrayOrVectorElement:
+ case EK_ArrayElement:
+ case EK_VectorElement:
return DeclarationName();
}
@@ -1882,7 +1887,8 @@ DeclaratorDecl *InitializedEntity::getDecl() const {
case EK_New:
case EK_Temporary:
case EK_Base:
- case EK_ArrayOrVectorElement:
+ case EK_ArrayElement:
+ case EK_VectorElement:
return 0;
}
@@ -2141,11 +2147,10 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
// refers to.
QualType ToType = AllowRValues? cv1T1 : DestType;
- const UnresolvedSet *Conversions
+ const UnresolvedSetImpl *Conversions
= T2RecordDecl->getVisibleConversionFunctions();
- for (UnresolvedSet::iterator I = Conversions->begin(),
- E = Conversions->end();
- I != E; ++I) {
+ for (UnresolvedSetImpl::const_iterator I = Conversions->begin(),
+ E = Conversions->end(); I != E; ++I) {
NamedDecl *D = *I;
CXXRecordDecl *ActingDC = cast<CXXRecordDecl>(D->getDeclContext());
if (isa<UsingShadowDecl>(D))
@@ -2662,9 +2667,9 @@ static void TryUserDefinedConversion(Sema &S,
CXXRecordDecl *SourceRecordDecl
= cast<CXXRecordDecl>(SourceRecordType->getDecl());
- const UnresolvedSet *Conversions
+ const UnresolvedSetImpl *Conversions
= SourceRecordDecl->getVisibleConversionFunctions();
- for (UnresolvedSet::iterator I = Conversions->begin(),
+ for (UnresolvedSetImpl::const_iterator I = Conversions->begin(),
E = Conversions->end();
I != E; ++I) {
NamedDecl *D = *I;
@@ -2917,7 +2922,8 @@ getAssignmentAction(const InitializedEntity &Entity) {
return Sema::AA_Casting;
case InitializedEntity::EK_Member:
- case InitializedEntity::EK_ArrayOrVectorElement:
+ case InitializedEntity::EK_ArrayElement:
+ case InitializedEntity::EK_VectorElement:
return Sema::AA_Initializing;
}
@@ -2935,7 +2941,8 @@ static bool shouldBindAsTemporary(const InitializedEntity &Entity,
case InitializedEntity::EK_Variable:
case InitializedEntity::EK_Base:
case InitializedEntity::EK_Member:
- case InitializedEntity::EK_ArrayOrVectorElement:
+ case InitializedEntity::EK_ArrayElement:
+ case InitializedEntity::EK_VectorElement:
return false;
case InitializedEntity::EK_Parameter:
@@ -2981,7 +2988,8 @@ static Sema::OwningExprResult CopyIfRequiredForEntity(Sema &S,
case InitializedEntity::EK_Temporary:
case InitializedEntity::EK_Base:
case InitializedEntity::EK_Member:
- case InitializedEntity::EK_ArrayOrVectorElement:
+ case InitializedEntity::EK_ArrayElement:
+ case InitializedEntity::EK_VectorElement:
// We don't need to copy for any of these initialized entities.
return move(CurInit);
}
diff --git a/lib/Sema/SemaInit.h b/lib/Sema/SemaInit.h
index 5eb819a..d7d3756 100644
--- a/lib/Sema/SemaInit.h
+++ b/lib/Sema/SemaInit.h
@@ -47,6 +47,11 @@ public:
/// \brief The entity being initialized is an exception object that
/// is being thrown.
EK_Exception,
+ /// \brief The entity being initialized is a non-static data member
+ /// subobject.
+ EK_Member,
+ /// \brief The entity being initialized is an element of an array.
+ EK_ArrayElement,
/// \brief The entity being initialized is an object (or array of
/// objects) allocated via new.
EK_New,
@@ -54,12 +59,10 @@ public:
EK_Temporary,
/// \brief The entity being initialized is a base member subobject.
EK_Base,
- /// \brief The entity being initialized is a non-static data member
- /// subobject.
- EK_Member,
- /// \brief The entity being initialized is an element of an array
+ /// \brief The entity being initialized is an element of a vector.
/// or vector.
- EK_ArrayOrVectorElement
+ EK_VectorElement
+
};
private:
@@ -211,7 +214,7 @@ public:
/// \brief If this is already the initializer for an array or vector
/// element, sets the element index.
void setElementIndex(unsigned Index) {
- assert(getKind() == EK_ArrayOrVectorElement);
+ assert(getKind() == EK_ArrayElement || getKind() == EK_VectorElement);
this->Index = Index;
}
};
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index cda245d..f5d2a7d 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -317,16 +317,16 @@ void LookupResult::resolveKind() {
// Fast case: no possible ambiguity.
if (N == 0) {
- assert(ResultKind == NotFound);
+ assert(ResultKind == NotFound || ResultKind == NotFoundInCurrentInstantiation);
return;
}
// If there's a single decl, we need to examine it to decide what
// kind of lookup this is.
if (N == 1) {
- if (isa<FunctionTemplateDecl>(Decls[0]))
+ if (isa<FunctionTemplateDecl>(*Decls.begin()))
ResultKind = FoundOverloaded;
- else if (isa<UnresolvedUsingValueDecl>(Decls[0]))
+ else if (isa<UnresolvedUsingValueDecl>(*Decls.begin()))
ResultKind = FoundUnresolvedValue;
return;
}
@@ -445,8 +445,9 @@ static bool LookupDirect(LookupResult &R, const DeclContext *DC) {
DeclContext::lookup_const_iterator I, E;
for (llvm::tie(I, E) = DC->lookup(R.getLookupName()); I != E; ++I) {
- if (R.isAcceptableDecl(*I)) {
- R.addDecl(*I);
+ NamedDecl *D = *I;
+ if (R.isAcceptableDecl(D)) {
+ R.addDecl(D);
Found = true;
}
}
@@ -463,10 +464,9 @@ static bool LookupDirect(LookupResult &R, const DeclContext *DC) {
if (!Record->isDefinition())
return Found;
- const UnresolvedSet *Unresolved = Record->getConversionFunctions();
- for (UnresolvedSet::iterator U = Unresolved->begin(),
- UEnd = Unresolved->end();
- U != UEnd; ++U) {
+ const UnresolvedSetImpl *Unresolved = Record->getConversionFunctions();
+ for (UnresolvedSetImpl::iterator U = Unresolved->begin(),
+ UEnd = Unresolved->end(); U != UEnd; ++U) {
FunctionTemplateDecl *ConvTemplate = dyn_cast<FunctionTemplateDecl>(*U);
if (!ConvTemplate)
continue;
@@ -967,6 +967,8 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
// Perform qualified name lookup into the LookupCtx.
if (LookupDirect(R, LookupCtx)) {
R.resolveKind();
+ if (isa<CXXRecordDecl>(LookupCtx))
+ R.setNamingClass(cast<CXXRecordDecl>(LookupCtx));
return true;
}
@@ -1039,6 +1041,8 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
R.getLookupName().getAsOpaquePtr(), Paths))
return false;
+ R.setNamingClass(LookupRec);
+
// C++ [class.member.lookup]p2:
// [...] If the resulting set of declarations are not all from
// sub-objects of the same type, or the set has a nonstatic member
@@ -1048,10 +1052,15 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
// FIXME: support using declarations!
QualType SubobjectType;
int SubobjectNumber = 0;
+ AccessSpecifier SubobjectAccess = AS_private;
for (CXXBasePaths::paths_iterator Path = Paths.begin(), PathEnd = Paths.end();
Path != PathEnd; ++Path) {
const CXXBasePathElement &PathElement = Path->back();
+ // Pick the best (i.e. most permissive i.e. numerically lowest) access
+ // across all paths.
+ SubobjectAccess = std::min(SubobjectAccess, Path->Access);
+
// Determine whether we're looking at a distinct sub-object or not.
if (SubobjectType.isNull()) {
// This is the first subobject we've looked at. Record its type.
@@ -1106,8 +1115,12 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
// Lookup in a base class succeeded; return these results.
DeclContext::lookup_iterator I, E;
- for (llvm::tie(I,E) = Paths.front().Decls; I != E; ++I)
- R.addDecl(*I);
+ for (llvm::tie(I,E) = Paths.front().Decls; I != E; ++I) {
+ NamedDecl *D = *I;
+ AccessSpecifier AS = CXXRecordDecl::MergeAccess(SubobjectAccess,
+ D->getAccess());
+ R.addDecl(D, AS);
+ }
R.resolveKind();
return true;
}
@@ -1243,7 +1256,12 @@ bool Sema::DiagnoseAmbiguousLookup(LookupResult &Result) {
Diag((*DI)->getLocation(), diag::note_hiding_object);
// For recovery purposes, go ahead and implement the hiding.
- Result.hideDecls(TagDecls);
+ LookupResult::Filter F = Result.makeFilter();
+ while (F.hasNext()) {
+ if (TagDecls.count(F.next()))
+ F.erase();
+ }
+ F.done();
return true;
}
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 6ec4d1b..44a8f15 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -25,7 +25,6 @@
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/STLExtras.h"
#include <algorithm>
-#include <cstdio>
namespace clang {
@@ -183,51 +182,53 @@ isPointerConversionToVoidPointer(ASTContext& Context) const {
/// DebugPrint - Print this standard conversion sequence to standard
/// error. Useful for debugging overloading issues.
void StandardConversionSequence::DebugPrint() const {
+ llvm::raw_ostream &OS = llvm::errs();
bool PrintedSomething = false;
if (First != ICK_Identity) {
- fprintf(stderr, "%s", GetImplicitConversionName(First));
+ OS << GetImplicitConversionName(First);
PrintedSomething = true;
}
if (Second != ICK_Identity) {
if (PrintedSomething) {
- fprintf(stderr, " -> ");
+ OS << " -> ";
}
- fprintf(stderr, "%s", GetImplicitConversionName(Second));
+ OS << GetImplicitConversionName(Second);
if (CopyConstructor) {
- fprintf(stderr, " (by copy constructor)");
+ OS << " (by copy constructor)";
} else if (DirectBinding) {
- fprintf(stderr, " (direct reference binding)");
+ OS << " (direct reference binding)";
} else if (ReferenceBinding) {
- fprintf(stderr, " (reference binding)");
+ OS << " (reference binding)";
}
PrintedSomething = true;
}
if (Third != ICK_Identity) {
if (PrintedSomething) {
- fprintf(stderr, " -> ");
+ OS << " -> ";
}
- fprintf(stderr, "%s", GetImplicitConversionName(Third));
+ OS << GetImplicitConversionName(Third);
PrintedSomething = true;
}
if (!PrintedSomething) {
- fprintf(stderr, "No conversions required");
+ OS << "No conversions required";
}
}
/// DebugPrint - Print this user-defined conversion sequence to standard
/// error. Useful for debugging overloading issues.
void UserDefinedConversionSequence::DebugPrint() const {
+ llvm::raw_ostream &OS = llvm::errs();
if (Before.First || Before.Second || Before.Third) {
Before.DebugPrint();
- fprintf(stderr, " -> ");
+ OS << " -> ";
}
- fprintf(stderr, "'%s'", ConversionFunction->getNameAsString().c_str());
+ OS << "'" << ConversionFunction->getNameAsString() << "'";
if (After.First || After.Second || After.Third) {
- fprintf(stderr, " -> ");
+ OS << " -> ";
After.DebugPrint();
}
}
@@ -235,27 +236,28 @@ void UserDefinedConversionSequence::DebugPrint() const {
/// DebugPrint - Print this implicit conversion sequence to standard
/// error. Useful for debugging overloading issues.
void ImplicitConversionSequence::DebugPrint() const {
+ llvm::raw_ostream &OS = llvm::errs();
switch (ConversionKind) {
case StandardConversion:
- fprintf(stderr, "Standard conversion: ");
+ OS << "Standard conversion: ";
Standard.DebugPrint();
break;
case UserDefinedConversion:
- fprintf(stderr, "User-defined conversion: ");
+ OS << "User-defined conversion: ";
UserDefined.DebugPrint();
break;
case EllipsisConversion:
- fprintf(stderr, "Ellipsis conversion");
+ OS << "Ellipsis conversion";
break;
case AmbiguousConversion:
- fprintf(stderr, "Ambiguous conversion");
+ OS << "Ambiguous conversion";
break;
case BadConversion:
- fprintf(stderr, "Bad conversion");
+ OS << "Bad conversion";
break;
}
- fprintf(stderr, "\n");
+ OS << "\n";
}
void AmbiguousConversionSequence::construct() {
@@ -1100,7 +1102,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
bool &IncompatibleObjC) {
if (!getLangOptions().ObjC1)
return false;
-
+
// First, we handle all conversions on ObjC object pointer types.
const ObjCObjectPointerType* ToObjCPtr = ToType->getAs<ObjCObjectPointerType>();
const ObjCObjectPointerType *FromObjCPtr =
@@ -1141,8 +1143,23 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
QualType ToPointeeType;
if (const PointerType *ToCPtr = ToType->getAs<PointerType>())
ToPointeeType = ToCPtr->getPointeeType();
- else if (const BlockPointerType *ToBlockPtr = ToType->getAs<BlockPointerType>())
+ else if (const BlockPointerType *ToBlockPtr =
+ ToType->getAs<BlockPointerType>()) {
+ // Objective C++: We're able to convert from a pointer to any object
+ // to a block pointer type.
+ if (FromObjCPtr && FromObjCPtr->isObjCBuiltinType()) {
+ ConvertedType = ToType;
+ return true;
+ }
ToPointeeType = ToBlockPtr->getPointeeType();
+ }
+ else if (FromType->getAs<BlockPointerType>() &&
+ ToObjCPtr && ToObjCPtr->isObjCBuiltinType()) {
+ // Objective C++: We're able to convert from a block pointer type to a
+ // pointer to any object.
+ ConvertedType = ToType;
+ return true;
+ }
else
return false;
@@ -1164,6 +1181,16 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
ConvertedType = ToType;
return true;
}
+ // Allow conversion of pointee being objective-c pointer to another one;
+ // as in I* to id.
+ if (FromPointeeType->getAs<ObjCObjectPointerType>() &&
+ ToPointeeType->getAs<ObjCObjectPointerType>() &&
+ isObjCPointerConversion(FromPointeeType, ToPointeeType, ConvertedType,
+ IncompatibleObjC)) {
+ ConvertedType = ToType;
+ return true;
+ }
+
// If we have pointers to functions or blocks, check whether the only
// differences in the argument and result types are in Objective-C
// pointer conversions. If so, we permit the conversion (but
@@ -1523,9 +1550,9 @@ OverloadingResult Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
if (CXXRecordDecl *FromRecordDecl
= dyn_cast<CXXRecordDecl>(FromRecordType->getDecl())) {
// Add all of the conversion functions as candidates.
- const UnresolvedSet *Conversions
+ const UnresolvedSetImpl *Conversions
= FromRecordDecl->getVisibleConversionFunctions();
- for (UnresolvedSet::iterator I = Conversions->begin(),
+ for (UnresolvedSetImpl::iterator I = Conversions->begin(),
E = Conversions->end(); I != E; ++I) {
NamedDecl *D = *I;
CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(D->getDeclContext());
@@ -2756,7 +2783,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
QualType ToCanon = Context.getCanonicalType(ToType).getUnqualifiedType();
if (FromCanon == ToCanon || IsDerivedFrom(FromCanon, ToCanon)) {
Candidate.Viable = false;
- Candidate.FailureKind = ovl_fail_bad_conversion;
+ Candidate.FailureKind = ovl_fail_trivial_conversion;
return;
}
@@ -2794,7 +2821,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
case ImplicitConversionSequence::BadConversion:
Candidate.Viable = false;
- Candidate.FailureKind = ovl_fail_bad_conversion;
+ Candidate.FailureKind = ovl_fail_bad_final_conversion;
break;
default:
@@ -2869,6 +2896,7 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
if (ObjectInit.isBad()) {
Candidate.Viable = false;
Candidate.FailureKind = ovl_fail_bad_conversion;
+ Candidate.Conversions[0] = ObjectInit;
return;
}
@@ -3270,9 +3298,9 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty,
}
CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(TyRec->getDecl());
- const UnresolvedSet *Conversions
+ const UnresolvedSetImpl *Conversions
= ClassDecl->getVisibleConversionFunctions();
- for (UnresolvedSet::iterator I = Conversions->begin(),
+ for (UnresolvedSetImpl::iterator I = Conversions->begin(),
E = Conversions->end(); I != E; ++I) {
// Skip conversion function templates; they don't tell us anything
@@ -3334,10 +3362,10 @@ static Qualifiers CollectVRQualifiers(ASTContext &Context, Expr* ArgExpr) {
}
CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(TyRec->getDecl());
- const UnresolvedSet *Conversions =
+ const UnresolvedSetImpl *Conversions =
ClassDecl->getVisibleConversionFunctions();
- for (UnresolvedSet::iterator I = Conversions->begin(),
+ for (UnresolvedSetImpl::iterator I = Conversions->begin(),
E = Conversions->end(); I != E; ++I) {
if (CXXConversionDecl *Conv = dyn_cast<CXXConversionDecl>(*I)) {
QualType CanTy = Context.getCanonicalType(Conv->getConversionType());
@@ -4386,7 +4414,8 @@ void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) {
QualType FromTy = Conv.Bad.getFromType();
QualType ToTy = Conv.Bad.getToType();
- // Do some hand-waving analysis to see if the non-viability is due to a
+ // Do some hand-waving analysis to see if the non-viability is due
+ // to a qualifier mismatch.
CanQualType CFromTy = S.Context.getCanonicalType(FromTy);
CanQualType CToTy = S.Context.getCanonicalType(ToTy);
if (CanQual<ReferenceType> RT = CToTy->getAs<ReferenceType>())
@@ -4436,6 +4465,20 @@ void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, unsigned I) {
return;
}
+ // Diagnose references or pointers to incomplete types differently,
+ // since it's far from impossible that the incompleteness triggered
+ // the failure.
+ QualType TempFromTy = FromTy.getNonReferenceType();
+ if (const PointerType *PTy = TempFromTy->getAs<PointerType>())
+ TempFromTy = PTy->getPointeeType();
+ if (TempFromTy->isIncompleteType()) {
+ S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_conv_incomplete)
+ << (unsigned) FnKind << FnDesc
+ << (FromExpr ? FromExpr->getSourceRange() : SourceRange())
+ << FromTy << ToTy << (unsigned) isObjectArgument << I+1;
+ return;
+ }
+
// TODO: specialize more based on the kind of mismatch
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_conv)
<< (unsigned) FnKind << FnDesc
@@ -4503,6 +4546,8 @@ void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
return DiagnoseArityMismatch(S, Cand, NumArgs);
case ovl_fail_bad_deduction:
+ case ovl_fail_trivial_conversion:
+ case ovl_fail_bad_final_conversion:
return S.NoteOverloadCandidate(Fn);
case ovl_fail_bad_conversion:
@@ -4582,12 +4627,23 @@ void NoteAmbiguousUserConversions(Sema &S, SourceLocation OpLoc,
}
}
+SourceLocation GetLocationForCandidate(const OverloadCandidate *Cand) {
+ if (Cand->Function)
+ return Cand->Function->getLocation();
+ if (Cand->IsSurrogate)
+ return Cand->Surrogate->getLocation();
+ return SourceLocation();
+}
+
struct CompareOverloadCandidatesForDisplay {
Sema &S;
CompareOverloadCandidatesForDisplay(Sema &S) : S(S) {}
bool operator()(const OverloadCandidate *L,
const OverloadCandidate *R) {
+ // Fast-path this check.
+ if (L == R) return false;
+
// Order first by viability.
if (L->Viable) {
if (!R->Viable) return true;
@@ -4600,25 +4656,132 @@ struct CompareOverloadCandidatesForDisplay {
} else if (R->Viable)
return false;
- // Put declared functions first.
- if (L->Function) {
- if (!R->Function) return true;
- return S.SourceMgr.isBeforeInTranslationUnit(L->Function->getLocation(),
- R->Function->getLocation());
- } else if (R->Function) return false;
-
- // Then surrogates.
- if (L->IsSurrogate) {
- if (!R->IsSurrogate) return true;
- return S.SourceMgr.isBeforeInTranslationUnit(L->Surrogate->getLocation(),
- R->Surrogate->getLocation());
- } else if (R->IsSurrogate) return false;
-
- // And builtins just come in a jumble.
- return false;
+ assert(L->Viable == R->Viable);
+
+ // Criteria by which we can sort non-viable candidates:
+ if (!L->Viable) {
+ // 1. Arity mismatches come after other candidates.
+ if (L->FailureKind == ovl_fail_too_many_arguments ||
+ L->FailureKind == ovl_fail_too_few_arguments)
+ return false;
+ if (R->FailureKind == ovl_fail_too_many_arguments ||
+ R->FailureKind == ovl_fail_too_few_arguments)
+ return true;
+
+ // 2. Bad conversions come first and are ordered by the number
+ // of bad conversions and quality of good conversions.
+ if (L->FailureKind == ovl_fail_bad_conversion) {
+ if (R->FailureKind != ovl_fail_bad_conversion)
+ return true;
+
+ // If there's any ordering between the defined conversions...
+ // FIXME: this might not be transitive.
+ assert(L->Conversions.size() == R->Conversions.size());
+
+ int leftBetter = 0;
+ for (unsigned I = 0, E = L->Conversions.size(); I != E; ++I) {
+ switch (S.CompareImplicitConversionSequences(L->Conversions[I],
+ R->Conversions[I])) {
+ case ImplicitConversionSequence::Better:
+ leftBetter++;
+ break;
+
+ case ImplicitConversionSequence::Worse:
+ leftBetter--;
+ break;
+
+ case ImplicitConversionSequence::Indistinguishable:
+ break;
+ }
+ }
+ if (leftBetter > 0) return true;
+ if (leftBetter < 0) return false;
+
+ } else if (R->FailureKind == ovl_fail_bad_conversion)
+ return false;
+
+ // TODO: others?
+ }
+
+ // Sort everything else by location.
+ SourceLocation LLoc = GetLocationForCandidate(L);
+ SourceLocation RLoc = GetLocationForCandidate(R);
+
+ // Put candidates without locations (e.g. builtins) at the end.
+ if (LLoc.isInvalid()) return false;
+ if (RLoc.isInvalid()) return true;
+
+ return S.SourceMgr.isBeforeInTranslationUnit(LLoc, RLoc);
}
};
+/// CompleteNonViableCandidate - Normally, overload resolution only
+/// computes up to the first
+void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand,
+ Expr **Args, unsigned NumArgs) {
+ assert(!Cand->Viable);
+
+ // Don't do anything on failures other than bad conversion.
+ if (Cand->FailureKind != ovl_fail_bad_conversion) return;
+
+ // Skip forward to the first bad conversion.
+ unsigned ConvIdx = 0;
+ unsigned ConvCount = Cand->Conversions.size();
+ while (true) {
+ assert(ConvIdx != ConvCount && "no bad conversion in candidate");
+ ConvIdx++;
+ if (Cand->Conversions[ConvIdx - 1].isBad())
+ break;
+ }
+
+ if (ConvIdx == ConvCount)
+ return;
+
+ // FIXME: these should probably be preserved from the overload
+ // operation somehow.
+ bool SuppressUserConversions = false;
+ bool ForceRValue = false;
+
+ const FunctionProtoType* Proto;
+ unsigned ArgIdx = ConvIdx;
+
+ if (Cand->IsSurrogate) {
+ QualType ConvType
+ = Cand->Surrogate->getConversionType().getNonReferenceType();
+ if (const PointerType *ConvPtrType = ConvType->getAs<PointerType>())
+ ConvType = ConvPtrType->getPointeeType();
+ Proto = ConvType->getAs<FunctionProtoType>();
+ ArgIdx--;
+ } else if (Cand->Function) {
+ Proto = Cand->Function->getType()->getAs<FunctionProtoType>();
+ if (isa<CXXMethodDecl>(Cand->Function) &&
+ !isa<CXXConstructorDecl>(Cand->Function))
+ ArgIdx--;
+ } else {
+ // Builtin binary operator with a bad first conversion.
+ assert(ConvCount <= 3);
+ for (; ConvIdx != ConvCount; ++ConvIdx)
+ Cand->Conversions[ConvIdx]
+ = S.TryCopyInitialization(Args[ConvIdx],
+ Cand->BuiltinTypes.ParamTypes[ConvIdx],
+ SuppressUserConversions, ForceRValue,
+ /*InOverloadResolution*/ true);
+ return;
+ }
+
+ // Fill in the rest of the conversions.
+ unsigned NumArgsInProto = Proto->getNumArgs();
+ for (; ConvIdx != ConvCount; ++ConvIdx, ++ArgIdx) {
+ if (ArgIdx < NumArgsInProto)
+ Cand->Conversions[ConvIdx]
+ = S.TryCopyInitialization(Args[ArgIdx], Proto->getArgType(ArgIdx),
+ SuppressUserConversions, ForceRValue,
+ /*InOverloadResolution=*/true);
+ else
+ Cand->Conversions[ConvIdx].setEllipsis();
+ }
+}
+
} // end anonymous namespace
/// PrintOverloadCandidates - When overload resolution fails, prints
@@ -4636,9 +4799,15 @@ Sema::PrintOverloadCandidates(OverloadCandidateSet& CandidateSet,
if (OCD == OCD_AllCandidates) Cands.reserve(CandidateSet.size());
for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(),
LastCand = CandidateSet.end();
- Cand != LastCand; ++Cand)
- if (Cand->Viable || OCD == OCD_AllCandidates)
+ Cand != LastCand; ++Cand) {
+ if (Cand->Viable)
Cands.push_back(Cand);
+ else if (OCD == OCD_AllCandidates) {
+ CompleteNonViableCandidate(*this, Cand, Args, NumArgs);
+ Cands.push_back(Cand);
+ }
+ }
+
std::sort(Cands.begin(), Cands.end(),
CompareOverloadCandidatesForDisplay(*this));
@@ -5909,9 +6078,9 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
// functions for each conversion function declared in an
// accessible base class provided the function is not hidden
// within T by another intervening declaration.
- const UnresolvedSet *Conversions
+ const UnresolvedSetImpl *Conversions
= cast<CXXRecordDecl>(Record->getDecl())->getVisibleConversionFunctions();
- for (UnresolvedSet::iterator I = Conversions->begin(),
+ for (UnresolvedSetImpl::iterator I = Conversions->begin(),
E = Conversions->end(); I != E; ++I) {
NamedDecl *D = *I;
CXXRecordDecl *ActingContext = cast<CXXRecordDecl>(D->getDeclContext());
diff --git a/lib/Sema/SemaOverload.h b/lib/Sema/SemaOverload.h
index 20add00..f8353e3 100644
--- a/lib/Sema/SemaOverload.h
+++ b/lib/Sema/SemaOverload.h
@@ -390,7 +390,16 @@ namespace clang {
ovl_fail_too_many_arguments,
ovl_fail_too_few_arguments,
ovl_fail_bad_conversion,
- ovl_fail_bad_deduction
+ ovl_fail_bad_deduction,
+
+ /// This conversion candidate was not considered because it
+ /// duplicates the work of a trivial or derived-to-base
+ /// conversion.
+ ovl_fail_trivial_conversion,
+
+ /// This conversion candidate is not viable because its result
+ /// type is not implicitly convertible to the desired type.
+ ovl_fail_bad_final_conversion
};
/// OverloadCandidate - A single candidate in an overload set (C++ 13.3).
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 7855a7f..0c207fa 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -412,10 +412,10 @@ static bool CheckCXXSwitchCondition(Sema &S, SourceLocation SwitchLoc,
llvm::SmallVector<CXXConversionDecl *, 4> ViableConversions;
llvm::SmallVector<CXXConversionDecl *, 4> ExplicitConversions;
if (const RecordType *RecordTy = CondType->getAs<RecordType>()) {
- const UnresolvedSet *Conversions
+ const UnresolvedSetImpl *Conversions
= cast<CXXRecordDecl>(RecordTy->getDecl())
->getVisibleConversionFunctions();
- for (UnresolvedSet::iterator I = Conversions->begin(),
+ for (UnresolvedSetImpl::iterator I = Conversions->begin(),
E = Conversions->end(); I != E; ++I) {
if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(*I))
if (Conversion->getConversionType().getNonReferenceType()
@@ -879,10 +879,6 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc,
Action::OwningStmtResult
Sema::ActOnGotoStmt(SourceLocation GotoLoc, SourceLocation LabelLoc,
IdentifierInfo *LabelII) {
- // If we are in a block, reject all gotos for now.
- if (CurBlock)
- return StmtError(Diag(GotoLoc, diag::err_goto_in_block));
-
// Look up the record for this label identifier.
LabelStmt *&LabelDecl = getLabelMap()[LabelII];
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 2fad832..0040156 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -449,8 +449,8 @@ Sema::DeclPtrTy Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis,
Loc = KeyLoc;
TemplateTypeParmDecl *Param
- = TemplateTypeParmDecl::Create(Context, CurContext, Loc,
- Depth, Position, ParamName, Typename,
+ = TemplateTypeParmDecl::Create(Context, Context.getTranslationUnitDecl(),
+ Loc, Depth, Position, ParamName, Typename,
Ellipsis);
if (Invalid)
Param->setInvalidDecl();
@@ -572,7 +572,8 @@ Sema::DeclPtrTy Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
}
NonTypeTemplateParmDecl *Param
- = NonTypeTemplateParmDecl::Create(Context, CurContext, D.getIdentifierLoc(),
+ = NonTypeTemplateParmDecl::Create(Context, Context.getTranslationUnitDecl(),
+ D.getIdentifierLoc(),
Depth, Position, ParamName, T, TInfo);
if (Invalid)
Param->setInvalidDecl();
@@ -625,8 +626,8 @@ Sema::DeclPtrTy Sema::ActOnTemplateTemplateParameter(Scope* S,
// Construct the parameter object.
TemplateTemplateParmDecl *Param =
- TemplateTemplateParmDecl::Create(Context, CurContext, TmpLoc, Depth,
- Position, Name,
+ TemplateTemplateParmDecl::Create(Context, Context.getTranslationUnitDecl(),
+ TmpLoc, Depth, Position, Name,
(TemplateParameterList*)Params);
// Make sure the parameter is valid.
@@ -1586,9 +1587,12 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
UnqualifiedId &Name,
TypeTy *ObjectType,
bool EnteringContext) {
- if ((ObjectType &&
- computeDeclContext(QualType::getFromOpaquePtr(ObjectType))) ||
- (SS.isSet() && computeDeclContext(SS, EnteringContext))) {
+ DeclContext *LookupCtx = 0;
+ if (SS.isSet())
+ LookupCtx = computeDeclContext(SS, EnteringContext);
+ if (!LookupCtx && ObjectType)
+ LookupCtx = computeDeclContext(QualType::getFromOpaquePtr(ObjectType));
+ if (LookupCtx) {
// C++0x [temp.names]p5:
// If a name prefixed by the keyword template is not the name of
// a template, the program is ill-formed. [Note: the keyword
@@ -1608,8 +1612,9 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
TemplateTy Template;
TemplateNameKind TNK = isTemplateName(0, SS, Name, ObjectType,
EnteringContext, Template);
- if (TNK == TNK_Non_template &&
- isCurrentInstantiationWithDependentBases(SS)) {
+ if (TNK == TNK_Non_template && LookupCtx->isDependentContext() &&
+ isa<CXXRecordDecl>(LookupCtx) &&
+ cast<CXXRecordDecl>(LookupCtx)->hasAnyDependentBases()) {
// This is a dependent template.
} else if (TNK == TNK_Non_template) {
Diag(Name.getSourceRange().getBegin(),
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index e909c4f..23a9430 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -150,6 +150,7 @@ Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) {
Typedef->setPreviousDeclaration(cast<TypedefDecl>(InstPrev));
}
+ Typedef->setAccess(D->getAccess());
Owner->addDecl(Typedef);
return Typedef;
@@ -208,6 +209,8 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
if (D->isOutOfLine())
Var->setLexicalDeclContext(D->getLexicalDeclContext());
+ Var->setAccess(D->getAccess());
+
// FIXME: In theory, we could have a previous declaration for variables that
// are not static data members.
bool Redeclaration = false;
@@ -375,6 +378,7 @@ Decl *TemplateDeclInstantiator::VisitFieldDecl(FieldDecl *D) {
}
Field->setImplicit(D->isImplicit());
+ Field->setAccess(D->getAccess());
Owner->addDecl(Field);
return Field;
@@ -559,6 +563,7 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
return Inst;
}
+ Inst->setAccess(D->getAccess());
Owner->addDecl(Inst);
// First, we sort the partial specializations by location, so
@@ -634,6 +639,8 @@ TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) {
if (!Instantiated)
return 0;
+ Instantiated->setAccess(D->getAccess());
+
// Link the instantiated function template declaration to the function
// template from which it was instantiated.
FunctionTemplateDecl *InstTemplate
@@ -717,7 +724,10 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
return Info->Function;
}
- Sema::LocalInstantiationScope Scope(SemaRef, TemplateParams != 0);
+ bool MergeWithParentScope = (TemplateParams != 0) ||
+ !(isa<Decl>(Owner) &&
+ cast<Decl>(Owner)->isDefinedOutsideFunctionOrMethod());
+ Sema::LocalInstantiationScope Scope(SemaRef, MergeWithParentScope);
llvm::SmallVector<ParmVarDecl *, 4> Params;
QualType T = SubstFunctionType(D, Params);
@@ -844,7 +854,10 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
return Info->Function;
}
- Sema::LocalInstantiationScope Scope(SemaRef, TemplateParams != 0);
+ bool MergeWithParentScope = (TemplateParams != 0) ||
+ !(isa<Decl>(Owner) &&
+ cast<Decl>(Owner)->isDefinedOutsideFunctionOrMethod());
+ Sema::LocalInstantiationScope Scope(SemaRef, MergeWithParentScope);
llvm::SmallVector<ParmVarDecl *, 4> Params;
QualType T = SubstFunctionType(D, Params);
@@ -958,6 +971,8 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
if (D->isPure())
SemaRef.CheckPureMethod(Method, SourceRange());
+ Method->setAccess(D->getAccess());
+
if (!FunctionTemplate && (!Method->isInvalidDecl() || Previous.empty()) &&
!Method->getFriendObjectKind())
Owner->addDecl(Method);
@@ -997,7 +1012,9 @@ ParmVarDecl *TemplateDeclInstantiator::VisitParmVarDecl(ParmVarDecl *D) {
// Allocate the parameter
ParmVarDecl *Param
- = ParmVarDecl::Create(SemaRef.Context, Owner, D->getLocation(),
+ = ParmVarDecl::Create(SemaRef.Context,
+ SemaRef.Context.getTranslationUnitDecl(),
+ D->getLocation(),
D->getIdentifier(), T, DI, D->getStorageClass(), 0);
// Mark the default argument as being uninstantiated.
@@ -1542,7 +1559,8 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
Proto->hasAnyExceptionSpec(),
Exceptions.size(),
Exceptions.data(),
- Proto->getNoReturnAttr()));
+ Proto->getNoReturnAttr(),
+ Proto->getCallConv()));
}
return false;
@@ -1647,8 +1665,14 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
ActOnStartOfFunctionDef(0, DeclPtrTy::make(Function));
// Introduce a new scope where local variable instantiations will be
- // recorded.
- LocalInstantiationScope Scope(*this);
+ // recorded, unless we're actually a member function within a local
+ // class, in which case we need to merge our results with the parent
+ // scope (of the enclosing function).
+ bool MergeWithParentScope = false;
+ if (CXXRecordDecl *Rec = dyn_cast<CXXRecordDecl>(Function->getDeclContext()))
+ MergeWithParentScope = Rec->isLocalClass();
+
+ LocalInstantiationScope Scope(*this, MergeWithParentScope);
// Introduce the instantiated function parameters into the local
// instantiation scope.
@@ -1685,6 +1709,11 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
DeclGroupRef DG(Function);
Consumer.HandleTopLevelDecl(DG);
+ // This class may have local implicit instantiations that need to be
+ // instantiation within this scope.
+ PerformPendingImplicitInstantiations(/*LocalOnly=*/true);
+ Scope.Exit();
+
if (Recursive) {
// Instantiate any pending implicit instantiations found during the
// instantiation of this template.
@@ -2217,10 +2246,18 @@ NamedDecl *Sema::FindInstantiatedDecl(NamedDecl *D,
/// \brief Performs template instantiation for all implicit template
/// instantiations we have seen until this point.
-void Sema::PerformPendingImplicitInstantiations() {
- while (!PendingImplicitInstantiations.empty()) {
- PendingImplicitInstantiation Inst = PendingImplicitInstantiations.front();
- PendingImplicitInstantiations.pop_front();
+void Sema::PerformPendingImplicitInstantiations(bool LocalOnly) {
+ while (!PendingLocalImplicitInstantiations.empty() ||
+ (!LocalOnly && !PendingImplicitInstantiations.empty())) {
+ PendingImplicitInstantiation Inst;
+
+ if (PendingLocalImplicitInstantiations.empty()) {
+ Inst = PendingImplicitInstantiations.front();
+ PendingImplicitInstantiations.pop_front();
+ } else {
+ Inst = PendingLocalImplicitInstantiations.front();
+ PendingLocalImplicitInstantiations.pop_front();
+ }
// Instantiate function definitions
if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Inst.first)) {
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 9515834..9065761 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -1374,6 +1374,21 @@ namespace {
Sema::GetTypeFromParser(DS.getTypeRep(), &TInfo);
TL.setUnderlyingTInfo(TInfo);
}
+ void VisitBuiltinTypeLoc(BuiltinTypeLoc TL) {
+ // By default, use the source location of the type specifier.
+ TL.setBuiltinLoc(DS.getTypeSpecTypeLoc());
+ if (TL.needsExtraLocalData()) {
+ // Set info for the written builtin specifiers.
+ TL.getWrittenBuiltinSpecs() = DS.getWrittenBuiltinSpecs();
+ // Try to have a meaningful source location.
+ if (TL.getWrittenSignSpec() != TSS_unspecified)
+ // Sign spec loc overrides the others (e.g., 'unsigned long').
+ TL.setBuiltinLoc(DS.getTypeSpecSignLoc());
+ else if (TL.getWrittenWidthSpec() != TSW_unspecified)
+ // Width spec loc overrides type spec loc (e.g., 'short int').
+ TL.setBuiltinLoc(DS.getTypeSpecWidthLoc());
+ }
+ }
void VisitTypeLoc(TypeLoc TL) {
// FIXME: add other typespec types and change this to an assert.
TL.initialize(DS.getTypeSpecTypeLoc());
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 445ef0d..b2102af 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -1014,15 +1014,12 @@ public:
///
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
- OwningExprResult RebuildCStyleCaseExpr(SourceLocation LParenLoc,
- QualType ExplicitTy,
+ OwningExprResult RebuildCStyleCastExpr(SourceLocation LParenLoc,
+ TypeSourceInfo *TInfo,
SourceLocation RParenLoc,
ExprArg SubExpr) {
- return getSema().ActOnCastExpr(/*Scope=*/0,
- LParenLoc,
- ExplicitTy.getAsOpaquePtr(),
- RParenLoc,
- move(SubExpr));
+ return getSema().BuildCStyleCastExpr(LParenLoc, TInfo, RParenLoc,
+ move(SubExpr));
}
/// \brief Build a new compound literal expression.
@@ -1030,11 +1027,11 @@ public:
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
OwningExprResult RebuildCompoundLiteralExpr(SourceLocation LParenLoc,
- QualType T,
+ TypeSourceInfo *TInfo,
SourceLocation RParenLoc,
ExprArg Init) {
- return getSema().ActOnCompoundLiteral(LParenLoc, T.getAsOpaquePtr(),
- RParenLoc, move(Init));
+ return getSema().BuildCompoundLiteralExpr(LParenLoc, TInfo, RParenLoc,
+ move(Init));
}
/// \brief Build a new extended vector element access expression.
@@ -1194,30 +1191,30 @@ public:
OwningExprResult RebuildCXXNamedCastExpr(SourceLocation OpLoc,
Stmt::StmtClass Class,
SourceLocation LAngleLoc,
- QualType T,
+ TypeSourceInfo *TInfo,
SourceLocation RAngleLoc,
SourceLocation LParenLoc,
ExprArg SubExpr,
SourceLocation RParenLoc) {
switch (Class) {
case Stmt::CXXStaticCastExprClass:
- return getDerived().RebuildCXXStaticCastExpr(OpLoc, LAngleLoc, T,
+ return getDerived().RebuildCXXStaticCastExpr(OpLoc, LAngleLoc, TInfo,
RAngleLoc, LParenLoc,
move(SubExpr), RParenLoc);
case Stmt::CXXDynamicCastExprClass:
- return getDerived().RebuildCXXDynamicCastExpr(OpLoc, LAngleLoc, T,
+ return getDerived().RebuildCXXDynamicCastExpr(OpLoc, LAngleLoc, TInfo,
RAngleLoc, LParenLoc,
move(SubExpr), RParenLoc);
case Stmt::CXXReinterpretCastExprClass:
- return getDerived().RebuildCXXReinterpretCastExpr(OpLoc, LAngleLoc, T,
+ return getDerived().RebuildCXXReinterpretCastExpr(OpLoc, LAngleLoc, TInfo,
RAngleLoc, LParenLoc,
move(SubExpr),
RParenLoc);
case Stmt::CXXConstCastExprClass:
- return getDerived().RebuildCXXConstCastExpr(OpLoc, LAngleLoc, T,
+ return getDerived().RebuildCXXConstCastExpr(OpLoc, LAngleLoc, TInfo,
RAngleLoc, LParenLoc,
move(SubExpr), RParenLoc);
@@ -1235,14 +1232,15 @@ public:
/// Subclasses may override this routine to provide different behavior.
OwningExprResult RebuildCXXStaticCastExpr(SourceLocation OpLoc,
SourceLocation LAngleLoc,
- QualType T,
+ TypeSourceInfo *TInfo,
SourceLocation RAngleLoc,
SourceLocation LParenLoc,
ExprArg SubExpr,
SourceLocation RParenLoc) {
- return getSema().ActOnCXXNamedCast(OpLoc, tok::kw_static_cast,
- LAngleLoc, T.getAsOpaquePtr(), RAngleLoc,
- LParenLoc, move(SubExpr), RParenLoc);
+ return getSema().BuildCXXNamedCast(OpLoc, tok::kw_static_cast,
+ TInfo, move(SubExpr),
+ SourceRange(LAngleLoc, RAngleLoc),
+ SourceRange(LParenLoc, RParenLoc));
}
/// \brief Build a new C++ dynamic_cast expression.
@@ -1251,14 +1249,15 @@ public:
/// Subclasses may override this routine to provide different behavior.
OwningExprResult RebuildCXXDynamicCastExpr(SourceLocation OpLoc,
SourceLocation LAngleLoc,
- QualType T,
+ TypeSourceInfo *TInfo,
SourceLocation RAngleLoc,
SourceLocation LParenLoc,
ExprArg SubExpr,
SourceLocation RParenLoc) {
- return getSema().ActOnCXXNamedCast(OpLoc, tok::kw_dynamic_cast,
- LAngleLoc, T.getAsOpaquePtr(), RAngleLoc,
- LParenLoc, move(SubExpr), RParenLoc);
+ return getSema().BuildCXXNamedCast(OpLoc, tok::kw_dynamic_cast,
+ TInfo, move(SubExpr),
+ SourceRange(LAngleLoc, RAngleLoc),
+ SourceRange(LParenLoc, RParenLoc));
}
/// \brief Build a new C++ reinterpret_cast expression.
@@ -1267,14 +1266,15 @@ public:
/// Subclasses may override this routine to provide different behavior.
OwningExprResult RebuildCXXReinterpretCastExpr(SourceLocation OpLoc,
SourceLocation LAngleLoc,
- QualType T,
+ TypeSourceInfo *TInfo,
SourceLocation RAngleLoc,
SourceLocation LParenLoc,
ExprArg SubExpr,
SourceLocation RParenLoc) {
- return getSema().ActOnCXXNamedCast(OpLoc, tok::kw_reinterpret_cast,
- LAngleLoc, T.getAsOpaquePtr(), RAngleLoc,
- LParenLoc, move(SubExpr), RParenLoc);
+ return getSema().BuildCXXNamedCast(OpLoc, tok::kw_reinterpret_cast,
+ TInfo, move(SubExpr),
+ SourceRange(LAngleLoc, RAngleLoc),
+ SourceRange(LParenLoc, RParenLoc));
}
/// \brief Build a new C++ const_cast expression.
@@ -1283,14 +1283,15 @@ public:
/// Subclasses may override this routine to provide different behavior.
OwningExprResult RebuildCXXConstCastExpr(SourceLocation OpLoc,
SourceLocation LAngleLoc,
- QualType T,
+ TypeSourceInfo *TInfo,
SourceLocation RAngleLoc,
SourceLocation LParenLoc,
ExprArg SubExpr,
SourceLocation RParenLoc) {
- return getSema().ActOnCXXNamedCast(OpLoc, tok::kw_const_cast,
- LAngleLoc, T.getAsOpaquePtr(), RAngleLoc,
- LParenLoc, move(SubExpr), RParenLoc);
+ return getSema().BuildCXXNamedCast(OpLoc, tok::kw_const_cast,
+ TInfo, move(SubExpr),
+ SourceRange(LAngleLoc, RAngleLoc),
+ SourceRange(LParenLoc, RParenLoc));
}
/// \brief Build a new C++ functional-style cast expression.
@@ -1298,13 +1299,13 @@ public:
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
OwningExprResult RebuildCXXFunctionalCastExpr(SourceRange TypeRange,
- QualType T,
+ TypeSourceInfo *TInfo,
SourceLocation LParenLoc,
ExprArg SubExpr,
SourceLocation RParenLoc) {
void *Sub = SubExpr.takeAs<Expr>();
return getSema().ActOnCXXTypeConstructExpr(TypeRange,
- T.getAsOpaquePtr(),
+ TInfo->getType().getAsOpaquePtr(),
LParenLoc,
Sema::MultiExprArg(getSema(), &Sub, 1),
/*CommaLocs=*/0,
@@ -2137,7 +2138,11 @@ QualType TransformTypeSpecType(TypeLocBuilder &TLB, TyLoc T) {
template<typename Derived>
QualType TreeTransform<Derived>::TransformBuiltinType(TypeLocBuilder &TLB,
BuiltinTypeLoc T) {
- return TransformTypeSpecType(TLB, T);
+ BuiltinTypeLoc NewT = TLB.push<BuiltinTypeLoc>(T.getType());
+ NewT.setBuiltinLoc(T.getBuiltinLoc());
+ if (T.needsExtraLocalData())
+ NewT.getWrittenBuiltinSpecs() = T.getWrittenBuiltinSpecs();
+ return T.getType();
}
template<typename Derived>
@@ -3815,15 +3820,17 @@ TreeTransform<Derived>::TransformExplicitCastExpr(ExplicitCastExpr *E) {
template<typename Derived>
Sema::OwningExprResult
TreeTransform<Derived>::TransformCStyleCastExpr(CStyleCastExpr *E) {
- QualType T;
+ TypeSourceInfo *OldT;
+ TypeSourceInfo *NewT;
{
// FIXME: Source location isn't quite accurate.
SourceLocation TypeStartLoc
= SemaRef.PP.getLocForEndOfToken(E->getLParenLoc());
TemporaryBase Rebase(*this, TypeStartLoc, DeclarationName());
- T = getDerived().TransformType(E->getTypeAsWritten());
- if (T.isNull())
+ OldT = E->getTypeInfoAsWritten();
+ NewT = getDerived().TransformType(OldT);
+ if (!NewT)
return SemaRef.ExprError();
}
@@ -3833,11 +3840,12 @@ TreeTransform<Derived>::TransformCStyleCastExpr(CStyleCastExpr *E) {
return SemaRef.ExprError();
if (!getDerived().AlwaysRebuild() &&
- T == E->getTypeAsWritten() &&
+ OldT == NewT &&
SubExpr.get() == E->getSubExpr())
return SemaRef.Owned(E->Retain());
- return getDerived().RebuildCStyleCaseExpr(E->getLParenLoc(), T,
+ return getDerived().RebuildCStyleCastExpr(E->getLParenLoc(),
+ NewT,
E->getRParenLoc(),
move(SubExpr));
}
@@ -3845,28 +3853,25 @@ TreeTransform<Derived>::TransformCStyleCastExpr(CStyleCastExpr *E) {
template<typename Derived>
Sema::OwningExprResult
TreeTransform<Derived>::TransformCompoundLiteralExpr(CompoundLiteralExpr *E) {
- QualType T;
- {
- // FIXME: Source location isn't quite accurate.
- SourceLocation FakeTypeLoc
- = SemaRef.PP.getLocForEndOfToken(E->getLParenLoc());
- TemporaryBase Rebase(*this, FakeTypeLoc, DeclarationName());
-
- T = getDerived().TransformType(E->getType());
- if (T.isNull())
- return SemaRef.ExprError();
- }
+ TypeSourceInfo *OldT = E->getTypeSourceInfo();
+ TypeSourceInfo *NewT = getDerived().TransformType(OldT);
+ if (!NewT)
+ return SemaRef.ExprError();
OwningExprResult Init = getDerived().TransformExpr(E->getInitializer());
if (Init.isInvalid())
return SemaRef.ExprError();
if (!getDerived().AlwaysRebuild() &&
- T == E->getType() &&
+ OldT == NewT &&
Init.get() == E->getInitializer())
return SemaRef.Owned(E->Retain());
- return getDerived().RebuildCompoundLiteralExpr(E->getLParenLoc(), T,
+ // Note: the expression type doesn't necessarily match the
+ // type-as-written, but that's okay, because it should always be
+ // derivable from the initializer.
+
+ return getDerived().RebuildCompoundLiteralExpr(E->getLParenLoc(), NewT,
/*FIXME:*/E->getInitializer()->getLocEnd(),
move(Init));
}
@@ -4237,15 +4242,17 @@ TreeTransform<Derived>::TransformCXXMemberCallExpr(CXXMemberCallExpr *E) {
template<typename Derived>
Sema::OwningExprResult
TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E) {
- QualType ExplicitTy;
+ TypeSourceInfo *OldT;
+ TypeSourceInfo *NewT;
{
// FIXME: Source location isn't quite accurate.
SourceLocation TypeStartLoc
= SemaRef.PP.getLocForEndOfToken(E->getOperatorLoc());
TemporaryBase Rebase(*this, TypeStartLoc, DeclarationName());
- ExplicitTy = getDerived().TransformType(E->getTypeAsWritten());
- if (ExplicitTy.isNull())
+ OldT = E->getTypeInfoAsWritten();
+ NewT = getDerived().TransformType(OldT);
+ if (!NewT)
return SemaRef.ExprError();
}
@@ -4255,7 +4262,7 @@ TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E) {
return SemaRef.ExprError();
if (!getDerived().AlwaysRebuild() &&
- ExplicitTy == E->getTypeAsWritten() &&
+ OldT == NewT &&
SubExpr.get() == E->getSubExpr())
return SemaRef.Owned(E->Retain());
@@ -4269,7 +4276,7 @@ TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E) {
return getDerived().RebuildCXXNamedCastExpr(E->getOperatorLoc(),
E->getStmtClass(),
FakeLAngleLoc,
- ExplicitTy,
+ NewT,
FakeRAngleLoc,
FakeRAngleLoc,
move(SubExpr),
@@ -4305,12 +4312,14 @@ template<typename Derived>
Sema::OwningExprResult
TreeTransform<Derived>::TransformCXXFunctionalCastExpr(
CXXFunctionalCastExpr *E) {
- QualType ExplicitTy;
+ TypeSourceInfo *OldT;
+ TypeSourceInfo *NewT;
{
TemporaryBase Rebase(*this, E->getTypeBeginLoc(), DeclarationName());
- ExplicitTy = getDerived().TransformType(E->getTypeAsWritten());
- if (ExplicitTy.isNull())
+ OldT = E->getTypeInfoAsWritten();
+ NewT = getDerived().TransformType(OldT);
+ if (!NewT)
return SemaRef.ExprError();
}
@@ -4320,14 +4329,14 @@ TreeTransform<Derived>::TransformCXXFunctionalCastExpr(
return SemaRef.ExprError();
if (!getDerived().AlwaysRebuild() &&
- ExplicitTy == E->getTypeAsWritten() &&
+ OldT == NewT &&
SubExpr.get() == E->getSubExpr())
return SemaRef.Owned(E->Retain());
// FIXME: The end of the type's source range is wrong
return getDerived().RebuildCXXFunctionalCastExpr(
/*FIXME:*/SourceRange(E->getTypeBeginLoc()),
- ExplicitTy,
+ NewT,
/*FIXME:*/E->getSubExpr()->getLocStart(),
move(SubExpr),
E->getRParenLoc());
OpenPOWER on IntegriCloud