aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorRoman Divacky <rdivacky@FreeBSD.org>2009-11-18 14:59:57 +0000
committerRoman Divacky <rdivacky@FreeBSD.org>2009-11-18 14:59:57 +0000
commitb3d5a323a5ca92ea73443499cee2f15db1ff0fb3 (patch)
tree60a1694bec5a44d15456acc880cb2f91619f66aa /lib
parent8f57cb0305232cb53fff00ef151ca716766f3437 (diff)
downloadsrc-b3d5a323a5ca92ea73443499cee2f15db1ff0fb3.tar.gz
src-b3d5a323a5ca92ea73443499cee2f15db1ff0fb3.zip
Update clang to r89205.
Notes
Notes: svn path=/vendor/clang/dist/; revision=199482
Diffstat (limited to 'lib')
-rw-r--r--lib/AST/ASTContext.cpp113
-rw-r--r--lib/AST/CMakeLists.txt1
-rw-r--r--lib/AST/CXXInheritance.cpp29
-rw-r--r--lib/AST/Decl.cpp6
-rw-r--r--lib/AST/DeclBase.cpp32
-rw-r--r--lib/AST/DeclCXX.cpp86
-rw-r--r--lib/AST/DeclObjC.cpp47
-rw-r--r--lib/AST/DeclPrinter.cpp54
-rw-r--r--lib/AST/DeclTemplate.cpp7
-rw-r--r--lib/AST/DeclarationName.cpp5
-rw-r--r--lib/AST/Expr.cpp19
-rw-r--r--lib/AST/ExprCXX.cpp8
-rw-r--r--lib/AST/ExprConstant.cpp29
-rw-r--r--lib/AST/NestedNameSpecifier.cpp2
-rw-r--r--lib/AST/RecordLayoutBuilder.cpp3
-rw-r--r--lib/AST/StmtDumper.cpp7
-rw-r--r--lib/AST/StmtProfile.cpp4
-rw-r--r--lib/AST/TemplateBase.cpp14
-rw-r--r--lib/AST/Type.cpp710
-rw-r--r--lib/AST/TypePrinter.cpp728
-rw-r--r--lib/Analysis/AnalysisManager.cpp35
-rw-r--r--lib/Analysis/ArrayBoundChecker.cpp86
-rw-r--r--lib/Analysis/AttrNonNullChecker.cpp22
-rw-r--r--lib/Analysis/BadCallChecker.cpp25
-rw-r--r--lib/Analysis/BasicObjCFoundationChecks.cpp2
-rw-r--r--lib/Analysis/BasicStore.cpp19
-rw-r--r--lib/Analysis/CFRefCount.cpp585
-rw-r--r--lib/Analysis/CMakeLists.txt17
-rw-r--r--lib/Analysis/CallGraph.cpp2
-rw-r--r--lib/Analysis/CastToStructChecker.cpp77
-rw-r--r--lib/Analysis/CheckSecuritySyntaxOnly.cpp52
-rw-r--r--lib/Analysis/CheckSizeofPointer.cpp72
-rw-r--r--lib/Analysis/DereferenceChecker.cpp161
-rw-r--r--lib/Analysis/DivZeroChecker.cpp21
-rw-r--r--lib/Analysis/ExplodedGraph.cpp2
-rw-r--r--lib/Analysis/FixedAddressChecker.cpp70
-rw-r--r--lib/Analysis/GRCoreEngine.cpp49
-rw-r--r--lib/Analysis/GRExprEngine.cpp448
-rw-r--r--lib/Analysis/GRExprEngineExperimentalChecks.cpp38
-rw-r--r--lib/Analysis/GRExprEngineExperimentalChecks.h26
-rw-r--r--lib/Analysis/GRExprEngineInternalChecks.cpp115
-rw-r--r--lib/Analysis/GRExprEngineInternalChecks.h39
-rw-r--r--lib/Analysis/GRState.cpp6
-rw-r--r--lib/Analysis/LiveVariables.cpp12
-rw-r--r--lib/Analysis/MallocChecker.cpp218
-rw-r--r--lib/Analysis/ManagerRegistry.cpp (renamed from lib/Frontend/ManagerRegistry.cpp)2
-rw-r--r--lib/Analysis/MemRegion.cpp20
-rw-r--r--lib/Analysis/NSErrorChecker.cpp13
-rw-r--r--lib/Analysis/PointerArithChecker.cpp71
-rw-r--r--lib/Analysis/PointerSubChecker.cpp77
-rw-r--r--lib/Analysis/PthreadLockChecker.cpp141
-rw-r--r--lib/Analysis/RangeConstraintManager.cpp2
-rw-r--r--lib/Analysis/RegionStore.cpp25
-rw-r--r--lib/Analysis/ReturnPointerRangeChecker.cpp97
-rw-r--r--lib/Analysis/ReturnStackAddressChecker.cpp97
-rw-r--r--lib/Analysis/ReturnUndefChecker.cpp68
-rw-r--r--lib/Analysis/SVals.cpp10
-rw-r--r--lib/Analysis/SValuator.cpp3
-rw-r--r--lib/Analysis/Store.cpp22
-rw-r--r--lib/Analysis/UndefinedArgChecker.cpp29
-rw-r--r--lib/Analysis/UndefinedArraySubscriptChecker.cpp56
-rw-r--r--lib/Analysis/UndefinedAssignmentChecker.cpp5
-rw-r--r--lib/Analysis/VLASizeChecker.cpp153
-rw-r--r--lib/Basic/SourceManager.cpp4
-rw-r--r--lib/Basic/TargetInfo.cpp39
-rw-r--r--lib/Basic/Targets.cpp352
-rw-r--r--lib/Basic/Version.cpp4
-rw-r--r--lib/CodeGen/CGBlocks.cpp69
-rw-r--r--lib/CodeGen/CGBlocks.h3
-rw-r--r--lib/CodeGen/CGBuiltin.cpp21
-rw-r--r--lib/CodeGen/CGCXX.cpp631
-rw-r--r--lib/CodeGen/CGCXXClass.cpp3
-rw-r--r--lib/CodeGen/CGCXXExpr.cpp264
-rw-r--r--lib/CodeGen/CGCall.cpp13
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp265
-rw-r--r--lib/CodeGen/CGDebugInfo.h6
-rw-r--r--lib/CodeGen/CGDecl.cpp6
-rw-r--r--lib/CodeGen/CGExpr.cpp205
-rw-r--r--lib/CodeGen/CGExprAgg.cpp1
-rw-r--r--lib/CodeGen/CGExprConstant.cpp28
-rw-r--r--lib/CodeGen/CGExprScalar.cpp121
-rw-r--r--lib/CodeGen/CGObjCGNU.cpp6
-rw-r--r--lib/CodeGen/CGObjCMac.cpp83
-rw-r--r--lib/CodeGen/CGRecordLayoutBuilder.cpp6
-rw-r--r--lib/CodeGen/CGRtti.cpp396
-rw-r--r--lib/CodeGen/CGStmt.cpp25
-rw-r--r--lib/CodeGen/CGVtable.cpp579
-rw-r--r--lib/CodeGen/CGVtable.h11
-rw-r--r--lib/CodeGen/CodeGenFunction.cpp127
-rw-r--r--lib/CodeGen/CodeGenFunction.h57
-rw-r--r--lib/CodeGen/CodeGenModule.cpp74
-rw-r--r--lib/CodeGen/CodeGenModule.h75
-rw-r--r--lib/CodeGen/CodeGenTypes.cpp2
-rw-r--r--lib/CodeGen/CodeGenTypes.h4
-rw-r--r--lib/CodeGen/GlobalDecl.h110
-rw-r--r--lib/CodeGen/Mangle.cpp70
-rw-r--r--lib/CodeGen/Mangle.h5
-rw-r--r--lib/CodeGen/ModuleBuilder.cpp14
-rw-r--r--lib/CodeGen/TargetABIInfo.cpp39
-rw-r--r--lib/Driver/ToolChains.h13
-rw-r--r--lib/Driver/Tools.cpp132
-rw-r--r--lib/Driver/Types.cpp13
-rw-r--r--lib/Frontend/ASTUnit.cpp16
-rw-r--r--lib/Frontend/AnalysisConsumer.cpp283
-rw-r--r--lib/Frontend/Backend.cpp91
-rw-r--r--lib/Frontend/CMakeLists.txt7
-rw-r--r--lib/Frontend/CompilerInstance.cpp403
-rw-r--r--lib/Frontend/CompilerInvocation.cpp548
-rw-r--r--lib/Frontend/DependencyFile.cpp44
-rw-r--r--lib/Frontend/DocumentXML.cpp4
-rw-r--r--lib/Frontend/FrontendAction.cpp225
-rw-r--r--lib/Frontend/FrontendActions.cpp281
-rw-r--r--lib/Frontend/FrontendOptions.cpp31
-rw-r--r--lib/Frontend/HTMLDiagnostics.cpp2
-rw-r--r--lib/Frontend/InitHeaderSearch.cpp289
-rw-r--r--lib/Frontend/InitPreprocessor.cpp117
-rw-r--r--lib/Frontend/PCHReader.cpp186
-rw-r--r--lib/Frontend/PCHReaderDecl.cpp9
-rw-r--r--lib/Frontend/PCHWriter.cpp22
-rw-r--r--lib/Frontend/PCHWriterDecl.cpp4
-rw-r--r--lib/Frontend/PlistDiagnostics.cpp10
-rw-r--r--lib/Frontend/PrintParserCallbacks.cpp3
-rw-r--r--lib/Frontend/PrintPreprocessedOutput.cpp26
-rw-r--r--lib/Frontend/RewriteObjC.cpp2
-rw-r--r--lib/Frontend/TextDiagnosticPrinter.cpp11
-rw-r--r--lib/Frontend/VerifyDiagnosticsClient.cpp344
-rw-r--r--lib/Frontend/Warnings.cpp18
-rw-r--r--lib/Headers/stdint.h615
-rw-r--r--lib/Index/ResolveLocation.cpp14
-rw-r--r--lib/Lex/Lexer.cpp8
-rw-r--r--lib/Lex/PPCaching.cpp2
-rw-r--r--lib/Lex/PPExpressions.cpp2
-rw-r--r--lib/Lex/PTHLexer.cpp40
-rw-r--r--lib/Lex/Preprocessor.cpp24
-rw-r--r--lib/Parse/AttributeList.cpp1
-rw-r--r--lib/Parse/DeclSpec.cpp10
-rw-r--r--lib/Parse/MinimalAction.cpp7
-rw-r--r--lib/Parse/ParseDecl.cpp1
-rw-r--r--lib/Parse/ParseDeclCXX.cpp17
-rw-r--r--lib/Parse/ParseExprCXX.cpp67
-rw-r--r--lib/Parse/ParseObjc.cpp51
-rw-r--r--lib/Parse/ParseTemplate.cpp163
-rw-r--r--lib/Parse/Parser.cpp1
-rw-r--r--lib/Rewrite/DeltaTree.cpp28
-rw-r--r--lib/Sema/CodeCompleteConsumer.cpp491
-rw-r--r--lib/Sema/JumpDiagnostics.cpp2
-rw-r--r--lib/Sema/Lookup.h392
-rw-r--r--lib/Sema/ParseAST.cpp17
-rw-r--r--lib/Sema/Sema.cpp338
-rw-r--r--lib/Sema/Sema.h507
-rw-r--r--lib/Sema/SemaAttr.cpp7
-rw-r--r--lib/Sema/SemaCXXCast.cpp150
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp29
-rw-r--r--lib/Sema/SemaChecking.cpp23
-rw-r--r--lib/Sema/SemaCodeComplete.cpp554
-rw-r--r--lib/Sema/SemaDecl.cpp249
-rw-r--r--lib/Sema/SemaDeclAttr.cpp44
-rw-r--r--lib/Sema/SemaDeclCXX.cpp745
-rw-r--r--lib/Sema/SemaDeclObjC.cpp81
-rw-r--r--lib/Sema/SemaExceptionSpec.cpp4
-rw-r--r--lib/Sema/SemaExpr.cpp374
-rw-r--r--lib/Sema/SemaExprCXX.cpp182
-rw-r--r--lib/Sema/SemaInit.cpp3
-rw-r--r--lib/Sema/SemaLookup.cpp433
-rw-r--r--lib/Sema/SemaOverload.cpp199
-rw-r--r--lib/Sema/SemaOverload.h8
-rw-r--r--lib/Sema/SemaStmt.cpp10
-rw-r--r--lib/Sema/SemaTemplate.cpp961
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp198
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp294
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp199
-rw-r--r--lib/Sema/SemaType.cpp5
-rw-r--r--lib/Sema/TreeTransform.h44
173 files changed, 13844 insertions, 5596 deletions
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 8562249479ca..dc13e7f4688c 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -35,7 +35,7 @@ enum FloatingRank {
};
ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM,
- TargetInfo &t,
+ const TargetInfo &t,
IdentifierTable &idents, SelectorTable &sels,
Builtin::Context &builtins,
bool FreeMem, unsigned size_reserve) :
@@ -256,9 +256,9 @@ ASTContext::setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl,
= new (*this) MemberSpecializationInfo(Tmpl, TSK);
}
-UnresolvedUsingDecl *
+NamedDecl *
ASTContext::getInstantiatedFromUnresolvedUsingDecl(UsingDecl *UUD) {
- llvm::DenseMap<UsingDecl *, UnresolvedUsingDecl *>::iterator Pos
+ llvm::DenseMap<UsingDecl *, NamedDecl *>::const_iterator Pos
= InstantiatedFromUnresolvedUsingDecl.find(UUD);
if (Pos == InstantiatedFromUnresolvedUsingDecl.end())
return 0;
@@ -268,7 +268,10 @@ ASTContext::getInstantiatedFromUnresolvedUsingDecl(UsingDecl *UUD) {
void
ASTContext::setInstantiatedFromUnresolvedUsingDecl(UsingDecl *UD,
- UnresolvedUsingDecl *UUD) {
+ NamedDecl *UUD) {
+ assert((isa<UnresolvedUsingValueDecl>(UUD) ||
+ isa<UnresolvedUsingTypenameDecl>(UUD)) &&
+ "original declaration is not an unresolved using decl");
assert(!InstantiatedFromUnresolvedUsingDecl[UD] &&
"Already noted what using decl what instantiated from");
InstantiatedFromUnresolvedUsingDecl[UD] = UUD;
@@ -1186,7 +1189,7 @@ QualType ASTContext::getNoReturnType(QualType T) {
}
}
- return getQualifiedType(ResultType, T.getQualifiers());
+ return getQualifiedType(ResultType, T.getLocalQualifiers());
}
/// getComplexType - Return the uniqued reference to the type for a complex
@@ -2350,6 +2353,12 @@ TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name) {
return DTN->CanonicalTemplateName;
}
+bool ASTContext::hasSameTemplateName(TemplateName X, TemplateName Y) {
+ X = getCanonicalTemplateName(X);
+ Y = getCanonicalTemplateName(Y);
+ return X.getAsVoidPointer() == Y.getAsVoidPointer();
+}
+
TemplateArgument
ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) {
switch (Arg.getKind()) {
@@ -2357,12 +2366,14 @@ ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) {
return Arg;
case TemplateArgument::Expression:
- // FIXME: Build canonical expression?
return Arg;
case TemplateArgument::Declaration:
return TemplateArgument(Arg.getAsDecl()->getCanonicalDecl());
+ case TemplateArgument::Template:
+ return TemplateArgument(getCanonicalTemplateName(Arg.getAsTemplate()));
+
case TemplateArgument::Integral:
return TemplateArgument(*Arg.getAsIntegral(),
getCanonicalType(Arg.getIntegralType()));
@@ -2427,7 +2438,7 @@ ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) {
const ArrayType *ASTContext::getAsArrayType(QualType T) {
// Handle the non-qualified case efficiently.
- if (!T.hasQualifiers()) {
+ if (!T.hasLocalQualifiers()) {
// Handle the common positive case fast.
if (const ArrayType *AT = dyn_cast<ArrayType>(T))
return AT;
@@ -2732,12 +2743,22 @@ int ASTContext::getIntegerTypeOrder(QualType LHS, QualType RHS) {
return 1;
}
+static RecordDecl *
+CreateRecordDecl(ASTContext &Ctx, RecordDecl::TagKind TK, DeclContext *DC,
+ SourceLocation L, IdentifierInfo *Id) {
+ if (Ctx.getLangOptions().CPlusPlus)
+ return CXXRecordDecl::Create(Ctx, TK, DC, L, Id);
+ else
+ return RecordDecl::Create(Ctx, TK, DC, L, Id);
+}
+
// getCFConstantStringType - Return the type used for constant CFStrings.
QualType ASTContext::getCFConstantStringType() {
if (!CFConstantStringTypeDecl) {
CFConstantStringTypeDecl =
- RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
- &Idents.get("NSConstantString"));
+ CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
+ &Idents.get("NSConstantString"));
+
QualType FieldTypes[4];
// const int *isa;
@@ -2774,8 +2795,8 @@ void ASTContext::setCFConstantStringType(QualType T) {
QualType ASTContext::getObjCFastEnumerationStateType() {
if (!ObjCFastEnumerationStateTypeDecl) {
ObjCFastEnumerationStateTypeDecl =
- RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
- &Idents.get("__objcFastEnumerationState"));
+ CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
+ &Idents.get("__objcFastEnumerationState"));
QualType FieldTypes[] = {
UnsignedLongTy,
@@ -2807,8 +2828,8 @@ QualType ASTContext::getBlockDescriptorType() {
RecordDecl *T;
// FIXME: Needs the FlagAppleBlock bit.
- T = RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
- &Idents.get("__block_descriptor"));
+ T = CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
+ &Idents.get("__block_descriptor"));
QualType FieldTypes[] = {
UnsignedLongTy,
@@ -2850,8 +2871,8 @@ QualType ASTContext::getBlockDescriptorExtendedType() {
RecordDecl *T;
// FIXME: Needs the FlagAppleBlock bit.
- T = RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
- &Idents.get("__block_descriptor_withcopydispose"));
+ T = CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
+ &Idents.get("__block_descriptor_withcopydispose"));
QualType FieldTypes[] = {
UnsignedLongTy,
@@ -2920,8 +2941,8 @@ QualType ASTContext::BuildByRefType(const char *DeclName, QualType Ty) {
llvm::raw_svector_ostream(Name) << "__Block_byref_" <<
++UniqueBlockByRefTypeID << '_' << DeclName;
RecordDecl *T;
- T = RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
- &Idents.get(Name.str()));
+ T = CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
+ &Idents.get(Name.str()));
T->startDefinition();
QualType Int32Ty = IntTy;
assert(getIntWidth(IntTy) == 32 && "non-32bit int not supported");
@@ -2970,8 +2991,8 @@ QualType ASTContext::getBlockParmType(
llvm::raw_svector_ostream(Name) << "__block_literal_"
<< ++UniqueBlockParmTypeID;
RecordDecl *T;
- T = RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
- &Idents.get(Name.str()));
+ T = CreateRecordDecl(*this, TagDecl::TK_struct, TUDecl, SourceLocation(),
+ &Idents.get(Name.str()));
QualType FieldTypes[] = {
getPointerType(VoidPtrTy),
IntTy,
@@ -3053,6 +3074,54 @@ int ASTContext::getObjCEncodingTypeSize(QualType type) {
return sz / getTypeSize(CharTy);
}
+/// getObjCEncodingForBlockDecl - Return the encoded type for this method
+/// declaration.
+void ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr,
+ std::string& S) {
+ const BlockDecl *Decl = Expr->getBlockDecl();
+ QualType BlockTy =
+ Expr->getType()->getAs<BlockPointerType>()->getPointeeType();
+ // Encode result type.
+ getObjCEncodingForType(cast<FunctionType>(BlockTy)->getResultType(), S);
+ // Compute size of all parameters.
+ // Start with computing size of a pointer in number of bytes.
+ // FIXME: There might(should) be a better way of doing this computation!
+ SourceLocation Loc;
+ int PtrSize = getTypeSize(VoidPtrTy) / getTypeSize(CharTy);
+ int ParmOffset = PtrSize;
+ for (ObjCMethodDecl::param_iterator PI = Decl->param_begin(),
+ E = Decl->param_end(); PI != E; ++PI) {
+ QualType PType = (*PI)->getType();
+ int sz = getObjCEncodingTypeSize(PType);
+ assert (sz > 0 && "BlockExpr - Incomplete param type");
+ ParmOffset += sz;
+ }
+ // Size of the argument frame
+ S += llvm::utostr(ParmOffset);
+ // Block pointer and offset.
+ S += "@?0";
+ ParmOffset = PtrSize;
+
+ // Argument types.
+ ParmOffset = PtrSize;
+ for (BlockDecl::param_const_iterator PI = Decl->param_begin(), E =
+ Decl->param_end(); PI != E; ++PI) {
+ ParmVarDecl *PVDecl = *PI;
+ QualType PType = PVDecl->getOriginalType();
+ if (const ArrayType *AT =
+ dyn_cast<ArrayType>(PType->getCanonicalTypeInternal())) {
+ // Use array's original type only if it has known number of
+ // elements.
+ if (!isa<ConstantArrayType>(AT))
+ PType = PVDecl->getType();
+ } else if (PType->isFunctionType())
+ PType = PVDecl->getType();
+ getObjCEncodingForType(PType, S);
+ S += llvm::utostr(ParmOffset);
+ ParmOffset += getObjCEncodingTypeSize(PType);
+ }
+}
+
/// getObjCEncodingForMethodDecl - Return the encoded type for this method
/// declaration.
void ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl,
@@ -4186,8 +4255,8 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) {
return LHS;
// If the qualifiers are different, the types aren't compatible... mostly.
- Qualifiers LQuals = LHSCan.getQualifiers();
- Qualifiers RQuals = RHSCan.getQualifiers();
+ Qualifiers LQuals = LHSCan.getLocalQualifiers();
+ Qualifiers RQuals = RHSCan.getLocalQualifiers();
if (LQuals != RQuals) {
// If any of these qualifiers are different, we have a type
// mismatch.
@@ -4394,7 +4463,7 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) {
//===----------------------------------------------------------------------===//
unsigned ASTContext::getIntWidth(QualType T) {
- if (T == BoolTy)
+ if (T->isBooleanType())
return 1;
if (FixedWidthIntType *FWIT = dyn_cast<FixedWidthIntType>(T)) {
return FWIT->getWidth();
diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt
index e541406790a6..0f0b22d65f6f 100644
--- a/lib/AST/CMakeLists.txt
+++ b/lib/AST/CMakeLists.txt
@@ -30,6 +30,7 @@ add_clang_library(clangAST
TemplateName.cpp
Type.cpp
TypeLoc.cpp
+ TypePrinter.cpp
)
add_dependencies(clangAST ClangDiagnosticAST)
diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp
index b59b45f6467e..023bca436339 100644
--- a/lib/AST/CXXInheritance.cpp
+++ b/lib/AST/CXXInheritance.cpp
@@ -76,31 +76,31 @@ void CXXBasePaths::swap(CXXBasePaths &Other) {
std::swap(DetectedVirtual, Other.DetectedVirtual);
}
-bool CXXRecordDecl::isDerivedFrom(CXXRecordDecl *Base) {
+bool CXXRecordDecl::isDerivedFrom(CXXRecordDecl *Base) const {
CXXBasePaths Paths(/*FindAmbiguities=*/false, /*RecordPaths=*/false,
/*DetectVirtual=*/false);
return isDerivedFrom(Base, Paths);
}
-bool CXXRecordDecl::isDerivedFrom(CXXRecordDecl *Base, CXXBasePaths &Paths) {
+bool CXXRecordDecl::isDerivedFrom(CXXRecordDecl *Base, CXXBasePaths &Paths) const {
if (getCanonicalDecl() == Base->getCanonicalDecl())
return false;
- Paths.setOrigin(this);
+ Paths.setOrigin(const_cast<CXXRecordDecl*>(this));
return lookupInBases(&FindBaseClass, Base->getCanonicalDecl(), Paths);
}
bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches,
void *UserData,
- CXXBasePaths &Paths) {
+ CXXBasePaths &Paths) const {
bool FoundPath = false;
ASTContext &Context = getASTContext();
- for (base_class_iterator BaseSpec = bases_begin(), BaseSpecEnd = bases_end();
- BaseSpec != BaseSpecEnd; ++BaseSpec) {
+ for (base_class_const_iterator BaseSpec = bases_begin(),
+ BaseSpecEnd = bases_end(); BaseSpec != BaseSpecEnd; ++BaseSpec) {
// Find the record of the base class subobjects for this type.
- QualType BaseType = Context.getCanonicalType(BaseSpec->getType());
- BaseType = BaseType.getUnqualifiedType();
+ QualType BaseType = Context.getCanonicalType(BaseSpec->getType())
+ .getUnqualifiedType();
// C++ [temp.dep]p3:
// In the definition of a class template or a member of a class template,
@@ -183,7 +183,7 @@ bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches,
return FoundPath;
}
-bool CXXRecordDecl::FindBaseClass(CXXBaseSpecifier *Specifier,
+bool CXXRecordDecl::FindBaseClass(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path,
void *BaseRecord) {
assert(((Decl *)BaseRecord)->getCanonicalDecl() == BaseRecord &&
@@ -192,7 +192,7 @@ bool CXXRecordDecl::FindBaseClass(CXXBaseSpecifier *Specifier,
->getCanonicalDecl() == BaseRecord;
}
-bool CXXRecordDecl::FindTagMember(CXXBaseSpecifier *Specifier,
+bool CXXRecordDecl::FindTagMember(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path,
void *Name) {
RecordDecl *BaseRecord = Specifier->getType()->getAs<RecordType>()->getDecl();
@@ -208,7 +208,7 @@ bool CXXRecordDecl::FindTagMember(CXXBaseSpecifier *Specifier,
return false;
}
-bool CXXRecordDecl::FindOrdinaryMember(CXXBaseSpecifier *Specifier,
+bool CXXRecordDecl::FindOrdinaryMember(const CXXBaseSpecifier *Specifier,
CXXBasePath &Path,
void *Name) {
RecordDecl *BaseRecord = Specifier->getType()->getAs<RecordType>()->getDecl();
@@ -225,9 +225,10 @@ bool CXXRecordDecl::FindOrdinaryMember(CXXBaseSpecifier *Specifier,
return false;
}
-bool CXXRecordDecl::FindNestedNameSpecifierMember(CXXBaseSpecifier *Specifier,
- CXXBasePath &Path,
- void *Name) {
+bool CXXRecordDecl::
+FindNestedNameSpecifierMember(const CXXBaseSpecifier *Specifier,
+ CXXBasePath &Path,
+ void *Name) {
RecordDecl *BaseRecord = Specifier->getType()->getAs<RecordType>()->getDecl();
DeclarationName N = DeclarationName::getFromOpaquePtr(Name);
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index a6996a4bfe5c..bdc804722c41 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -289,6 +289,10 @@ bool NamedDecl::declarationReplaces(NamedDecl *OldD) const {
if (isa<ObjCInterfaceDecl>(this) && isa<ObjCCompatibleAliasDecl>(OldD))
return true;
+ if (isa<UsingShadowDecl>(this) && isa<UsingShadowDecl>(OldD))
+ return cast<UsingShadowDecl>(this)->getTargetDecl() ==
+ cast<UsingShadowDecl>(OldD)->getTargetDecl();
+
// For non-function declarations, if the declarations are of the
// same kind then this must be a redeclaration, or semantic analysis
// would not have given us the new declaration.
@@ -308,7 +312,7 @@ bool NamedDecl::hasLinkage() const {
NamedDecl *NamedDecl::getUnderlyingDecl() {
NamedDecl *ND = this;
while (true) {
- if (UsingDecl *UD = dyn_cast<UsingDecl>(ND))
+ if (UsingShadowDecl *UD = dyn_cast<UsingShadowDecl>(ND))
ND = UD->getTargetDecl();
else if (ObjCCompatibleAliasDecl *AD
= dyn_cast<ObjCCompatibleAliasDecl>(ND))
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 6cfdcdd3e50e..831f552489f9 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -97,7 +97,7 @@ bool Decl::isTemplateParameterPack() const {
}
bool Decl::isFunctionOrFunctionTemplate() const {
- if (const UsingDecl *UD = dyn_cast<UsingDecl>(this))
+ if (const UsingShadowDecl *UD = dyn_cast<UsingShadowDecl>(this))
return UD->getTargetDecl()->isFunctionOrFunctionTemplate();
return isa<FunctionDecl>(this) || isa<FunctionTemplateDecl>(this);
@@ -189,10 +189,11 @@ ASTContext &Decl::getASTContext() const {
unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
switch (DeclKind) {
- default:
- if (DeclKind >= FunctionFirst && DeclKind <= FunctionLast)
- return IDNS_Ordinary;
- assert(0 && "Unknown decl kind!");
+ case Function:
+ case CXXMethod:
+ case CXXConstructor:
+ case CXXDestructor:
+ case CXXConversion:
case OverloadedFunction:
case Typedef:
case EnumConstant:
@@ -200,8 +201,6 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case ImplicitParam:
case ParmVar:
case NonTypeTemplateParm:
- case Using:
- case UnresolvedUsing:
case ObjCMethod:
case ObjCContainer:
case ObjCCategory:
@@ -210,6 +209,16 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case ObjCCompatibleAlias:
return IDNS_Ordinary;
+ case UsingShadow:
+ return 0; // we'll actually overwrite this later
+
+ case UnresolvedUsingValue:
+ case UnresolvedUsingTypename:
+ return IDNS_Ordinary | IDNS_Using;
+
+ case Using:
+ return IDNS_Using;
+
case ObjCProtocol:
return IDNS_ObjCProtocol;
@@ -256,6 +265,8 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case ClassTemplatePartialSpecialization:
return 0;
}
+
+ return 0;
}
void Decl::addAttr(Attr *NewAttr) {
@@ -663,6 +674,13 @@ void DeclContext::buildLookup(DeclContext *DCtx) {
if (D->getDeclContext() == DCtx)
makeDeclVisibleInContextImpl(ND);
+ // Insert any forward-declared Objective-C interfaces into the lookup
+ // data structure.
+ if (ObjCClassDecl *Class = dyn_cast<ObjCClassDecl>(*D))
+ for (ObjCClassDecl::iterator I = Class->begin(), IEnd = Class->end();
+ I != IEnd; ++I)
+ makeDeclVisibleInContextImpl(I->getInterface());
+
// If this declaration is itself a transparent declaration context,
// add its members (recursively).
if (DeclContext *InnerCtx = dyn_cast<DeclContext>(*D))
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index b4c0c59733e5..a21c93ffcdc9 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -211,7 +211,7 @@ bool CXXRecordDecl::hasConstCopyAssignment(ASTContext &Context,
if (!ArgType.isConstQualified())
AcceptsConst = false;
}
- if (Context.getCanonicalType(ArgType).getUnqualifiedType() != ClassType)
+ if (!Context.hasSameUnqualifiedType(ArgType, ClassType))
continue;
MD = Method;
// We have a single argument of type cv X or cv X&, i.e. we've found the
@@ -276,10 +276,13 @@ void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context,
QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType(
const_cast<CXXRecordDecl*>(this)));
- if (ClassType != Context.getCanonicalType(ArgType))
+ if (!Context.hasSameUnqualifiedType(ClassType, ArgType))
return;
// This is a copy assignment operator.
+ // Note on the decl that it is a copy assignment operator.
+ OpDecl->setCopyAssignment(true);
+
// Suppress the implicit declaration of a copy constructor.
UserDeclaredCopyAssignment = true;
@@ -749,6 +752,33 @@ bool CXXConstructorDecl::isConvertingConstructor(bool AllowExplicit) const {
(getNumParams() > 1 && getParamDecl(1)->hasDefaultArg());
}
+bool CXXConstructorDecl::isCopyConstructorLikeSpecialization() const {
+ if ((getNumParams() < 1) ||
+ (getNumParams() > 1 && !getParamDecl(1)->hasDefaultArg()) ||
+ (getPrimaryTemplate() == 0) ||
+ (getDescribedFunctionTemplate() != 0))
+ return false;
+
+ const ParmVarDecl *Param = getParamDecl(0);
+
+ ASTContext &Context = getASTContext();
+ CanQualType ParamType = Context.getCanonicalType(Param->getType());
+
+ // Strip off the lvalue reference, if any.
+ if (CanQual<LValueReferenceType> ParamRefType
+ = ParamType->getAs<LValueReferenceType>())
+ ParamType = ParamRefType->getPointeeType();
+
+
+ // Is it the same as our our class type?
+ CanQualType ClassTy
+ = Context.getCanonicalType(Context.getTagDeclType(getParent()));
+ if (ParamType.getUnqualifiedType() != ClassTy)
+ return false;
+
+ return true;
+}
+
CXXDestructorDecl *
CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
SourceLocation L, DeclarationName N,
@@ -761,12 +791,6 @@ CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
}
void
-CXXDestructorDecl::Destroy(ASTContext& C) {
- C.Deallocate(BaseOrMemberDestructions);
- CXXMethodDecl::Destroy(C);
-}
-
-void
CXXConstructorDecl::Destroy(ASTContext& C) {
C.Deallocate(BaseOrMemberInitializers);
CXXMethodDecl::Destroy(C);
@@ -890,22 +914,36 @@ NamespaceAliasDecl *NamespaceAliasDecl::Create(ASTContext &C, DeclContext *DC,
}
UsingDecl *UsingDecl::Create(ASTContext &C, DeclContext *DC,
- SourceLocation L, SourceRange NNR, SourceLocation TargetNL,
- SourceLocation UL, NamedDecl* Target,
- NestedNameSpecifier* TargetNNS, bool IsTypeNameArg) {
- return new (C) UsingDecl(DC, L, NNR, TargetNL, UL, Target,
- TargetNNS, IsTypeNameArg);
-}
-
-UnresolvedUsingDecl *UnresolvedUsingDecl::Create(ASTContext &C, DeclContext *DC,
- SourceLocation UsingLoc,
- SourceRange TargetNNR,
- NestedNameSpecifier *TargetNNS,
- SourceLocation TargetNameLoc,
- DeclarationName TargetName,
- bool IsTypeNameArg) {
- return new (C) UnresolvedUsingDecl(DC, UsingLoc, TargetNNR, TargetNNS,
- TargetNameLoc, TargetName, IsTypeNameArg);
+ SourceLocation L, SourceRange NNR, SourceLocation UL,
+ NestedNameSpecifier* TargetNNS, DeclarationName Name,
+ bool IsTypeNameArg) {
+ return new (C) UsingDecl(DC, L, NNR, UL, TargetNNS, Name, IsTypeNameArg);
+}
+
+UnresolvedUsingValueDecl *
+UnresolvedUsingValueDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation UsingLoc,
+ SourceRange TargetNNR,
+ NestedNameSpecifier *TargetNNS,
+ SourceLocation TargetNameLoc,
+ DeclarationName TargetName) {
+ return new (C) UnresolvedUsingValueDecl(DC, C.DependentTy, UsingLoc,
+ TargetNNR, TargetNNS,
+ TargetNameLoc, TargetName);
+}
+
+UnresolvedUsingTypenameDecl *
+UnresolvedUsingTypenameDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation UsingLoc,
+ SourceLocation TypenameLoc,
+ SourceRange TargetNNR,
+ NestedNameSpecifier *TargetNNS,
+ SourceLocation TargetNameLoc,
+ DeclarationName TargetName) {
+ return new (C) UnresolvedUsingTypenameDecl(DC, UsingLoc, TypenameLoc,
+ TargetNNR, TargetNNS,
+ TargetNameLoc,
+ TargetName.getAsIdentifierInfo());
}
StaticAssertDecl *StaticAssertDecl::Create(ASTContext &C, DeclContext *DC,
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index 7b48b724c0eb..c33720f5633a 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -571,34 +571,55 @@ ObjCMethodDecl *ObjCProtocolDecl::lookupMethod(Selector Sel,
//===----------------------------------------------------------------------===//
ObjCClassDecl::ObjCClassDecl(DeclContext *DC, SourceLocation L,
- ObjCInterfaceDecl *const *Elts, unsigned nElts,
+ ObjCInterfaceDecl *const *Elts,
+ const SourceLocation *Locs,
+ unsigned nElts,
ASTContext &C)
: Decl(ObjCClass, DC, L) {
- ForwardDecls.set(Elts, nElts, C);
+ setClassList(C, Elts, Locs, nElts);
}
+void ObjCClassDecl::setClassList(ASTContext &C, ObjCInterfaceDecl*const*List,
+ const SourceLocation *Locs, unsigned Num) {
+ ForwardDecls = (ObjCClassRef*) C.Allocate(sizeof(ObjCClassRef)*Num,
+ llvm::alignof<ObjCClassRef>());
+ for (unsigned i = 0; i < Num; ++i)
+ new (&ForwardDecls[i]) ObjCClassRef(List[i], Locs[i]);
+
+ NumDecls = Num;
+}
ObjCClassDecl *ObjCClassDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation L,
ObjCInterfaceDecl *const *Elts,
+ const SourceLocation *Locs,
unsigned nElts) {
- return new (C) ObjCClassDecl(DC, L, Elts, nElts, C);
+ return new (C) ObjCClassDecl(DC, L, Elts, Locs, nElts, C);
}
void ObjCClassDecl::Destroy(ASTContext &C) {
-
- // FIXME: There is no clear ownership policy now for referenced
- // ObjCInterfaceDecls. Some of them can be forward declarations that
- // are never later defined (in which case the ObjCClassDecl owns them)
- // or the ObjCInterfaceDecl later becomes a real definition later. Ideally
- // we should have separate objects for forward declarations and definitions,
- // obviating this problem. Because of this situation, referenced
- // ObjCInterfaceDecls are destroyed in ~TranslationUnit.
-
- ForwardDecls.Destroy(C);
+ // ObjCInterfaceDecls registered with a DeclContext will get destroyed
+ // when the DeclContext is destroyed. For those created only by a forward
+ // declaration, the first @class that created the ObjCInterfaceDecl gets
+ // to destroy it.
+ // FIXME: Note that this ownership role is very brittle; a better
+ // polict is surely need in the future.
+ for (iterator I = begin(), E = end(); I !=E ; ++I) {
+ ObjCInterfaceDecl *ID = I->getInterface();
+ if (ID->isForwardDecl() && ID->getLocStart() == getLocStart())
+ ID->Destroy(C);
+ }
+
+ C.Deallocate(ForwardDecls);
Decl::Destroy(C);
}
+SourceRange ObjCClassDecl::getSourceRange() const {
+ // FIXME: We should include the semicolon
+ assert(NumDecls);
+ return SourceRange(getLocation(), ForwardDecls[NumDecls-1].getLocation());
+}
+
//===----------------------------------------------------------------------===//
// ObjCForwardProtocolDecl
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index d9d195016bf3..131de8b2e11b 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -71,8 +71,10 @@ namespace {
void VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D);
void VisitObjCPropertyDecl(ObjCPropertyDecl *D);
void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D);
- void VisitUnresolvedUsingDecl(UnresolvedUsingDecl *D);
+ void VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D);
+ void VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D);
void VisitUsingDecl(UsingDecl *D);
+ void VisitUsingShadowDecl(UsingShadowDecl *D);
};
}
@@ -401,37 +403,6 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
}
}
}
- else if (CXXDestructorDecl *DDecl = dyn_cast<CXXDestructorDecl>(D)) {
- if (DDecl->getNumBaseOrMemberDestructions() > 0) {
- // List order of base/member destruction for visualization purposes.
- assert (D->isThisDeclarationADefinition() && "Destructor with dtor-list");
- Proto += "/* : ";
- for (CXXDestructorDecl::destr_const_iterator *B = DDecl->destr_begin(),
- *E = DDecl->destr_end();
- B != E; ++B) {
- uintptr_t BaseOrMember = (*B);
- if (B != DDecl->destr_begin())
- Proto += ", ";
-
- if (DDecl->isMemberToDestroy(BaseOrMember)) {
- FieldDecl *FD = DDecl->getMemberToDestroy(BaseOrMember);
- Proto += "~";
- Proto += FD->getNameAsString();
- }
- else // FIXME. skip dependent types for now.
- if (const RecordType *RT =
- DDecl->getAnyBaseClassToDestroy(BaseOrMember)
- ->getAs<RecordType>()) {
- const CXXRecordDecl *BaseDecl =
- cast<CXXRecordDecl>(RT->getDecl());
- Proto += "~";
- Proto += BaseDecl->getNameAsString();
- }
- Proto += "()";
- }
- Proto += " */";
- }
- }
else
AFT->getResultType().getAsStringInternal(Proto, Policy);
} else {
@@ -654,7 +625,7 @@ void DeclPrinter::VisitObjCClassDecl(ObjCClassDecl *D) {
for (ObjCClassDecl::iterator I = D->begin(), E = D->end();
I != E; ++I) {
if (I != D->begin()) Out << ", ";
- Out << (*I)->getNameAsString();
+ Out << I->getInterface()->getNameAsString();
}
}
@@ -856,11 +827,22 @@ void DeclPrinter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PID) {
void DeclPrinter::VisitUsingDecl(UsingDecl *D) {
Out << "using ";
D->getTargetNestedNameDecl()->print(Out, Policy);
- Out << D->getTargetDecl()->getNameAsString();
+ Out << D->getNameAsString();
+}
+
+void
+DeclPrinter::VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) {
+ Out << "using typename ";
+ D->getTargetNestedNameSpecifier()->print(Out, Policy);
+ Out << D->getDeclName().getAsString();
}
-void DeclPrinter::VisitUnresolvedUsingDecl(UnresolvedUsingDecl *D) {
+void DeclPrinter::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) {
Out << "using ";
D->getTargetNestedNameSpecifier()->print(Out, Policy);
- Out << D->getTargetName().getAsString();
+ Out << D->getDeclName().getAsString();
+}
+
+void DeclPrinter::VisitUsingShadowDecl(UsingShadowDecl *D) {
+ // ignore
}
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index 9ebc91afe142..0c14714812f5 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -220,7 +220,7 @@ QualType ClassTemplateDecl::getInjectedClassNameType(ASTContext &Context) {
TemplateArgs.push_back(TemplateArgument(E));
} else {
TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*Param);
- TemplateArgs.push_back(TemplateArgument(TTP));
+ TemplateArgs.push_back(TemplateArgument(TemplateName(TTP)));
}
}
@@ -285,11 +285,6 @@ TemplateTemplateParmDecl::Create(ASTContext &C, DeclContext *DC,
return new (C) TemplateTemplateParmDecl(DC, L, D, P, Id, Params);
}
-SourceLocation TemplateTemplateParmDecl::getDefaultArgumentLoc() const {
- return DefaultArgument? DefaultArgument->getSourceRange().getBegin()
- : SourceLocation();
-}
-
//===----------------------------------------------------------------------===//
// TemplateArgumentListBuilder Implementation
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp
index 8664c508615f..1ff068c9862c 100644
--- a/lib/AST/DeclarationName.cpp
+++ b/lib/AST/DeclarationName.cpp
@@ -18,6 +18,7 @@
#include "clang/Basic/IdentifierTable.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
+#include <cstdio>
using namespace clang;
namespace clang {
@@ -310,6 +311,10 @@ DeclarationName DeclarationName::getUsingDirectiveName() {
return DeclarationName(Ptr);
}
+void DeclarationName::dump() const {
+ fprintf(stderr, "%s\n", getAsString().c_str());
+}
+
DeclarationNameTable::DeclarationNameTable() {
CXXSpecialNamesImpl = new llvm::FoldingSet<CXXSpecialName>;
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index a8ea752a4a7e..90b50c61f989 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -490,6 +490,8 @@ const char *CastExpr::getCastKindName() const {
return "BitCast";
case CastExpr::CK_NoOp:
return "NoOp";
+ case CastExpr::CK_BaseToDerived:
+ return "BaseToDerived";
case CastExpr::CK_DerivedToBase:
return "DerivedToBase";
case CastExpr::CK_Dynamic:
@@ -812,6 +814,11 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
}
return false;
}
+
+ case CXXTemporaryObjectExprClass:
+ case CXXConstructExprClass:
+ return false;
+
case ObjCMessageExprClass:
return false;
@@ -853,15 +860,19 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
Loc = cast<CStyleCastExpr>(this)->getLParenLoc();
R1 = cast<CStyleCastExpr>(this)->getSubExpr()->getSourceRange();
return true;
- case CXXFunctionalCastExprClass:
- // If this is a cast to void, check the operand. Otherwise, the result of
- // the cast is unused.
- if (getType()->isVoidType())
+ case CXXFunctionalCastExprClass: {
+ const CastExpr *CE = cast<CastExpr>(this);
+
+ // If this is a cast to void or a constructor conversion, check the operand.
+ // Otherwise, the result of the cast is unused.
+ if (CE->getCastKind() == CastExpr::CK_ToVoid ||
+ CE->getCastKind() == CastExpr::CK_ConstructorConversion)
return (cast<CastExpr>(this)->getSubExpr()
->isUnusedResultAWarning(Loc, R1, R2, Ctx));
Loc = cast<CXXFunctionalCastExpr>(this)->getTypeBeginLoc();
R1 = cast<CXXFunctionalCastExpr>(this)->getSubExpr()->getSourceRange();
return true;
+ }
case ImplicitCastExprClass:
// Check the operand, since implicit casts are inserted by Sema
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index 7c6fc41ef12b..0ba4608ee198 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -323,6 +323,14 @@ Expr *CXXMemberCallExpr::getImplicitObjectArgument() {
return 0;
}
+SourceRange CXXMemberCallExpr::getSourceRange() const {
+ SourceLocation LocStart = getCallee()->getLocStart();
+ if (LocStart.isInvalid() && getNumArgs() > 0)
+ LocStart = getArg(0)->getLocStart();
+ return SourceRange(LocStart, getRParenLoc());
+}
+
+
//===----------------------------------------------------------------------===//
// Named casts
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 7862c57c2d47..2689859e8e4a 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -204,13 +204,6 @@ public:
bool VisitUnaryOperator(UnaryOperator *E) { return Visit(E->getSubExpr()); }
};
-bool HasSideEffects(const Expr* E, ASTContext &Ctx) {
- Expr::EvalResult Result;
- EvalInfo Info(Ctx, Result);
-
- return HasSideEffect(Info).Visit(const_cast<Expr*>(E));
-}
-
} // end anonymous namespace
//===----------------------------------------------------------------------===//
@@ -964,7 +957,7 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
}
}
- if (HasSideEffects(E->getArg(0), Info.Ctx)) {
+ if (E->getArg(0)->HasSideEffects(Info.Ctx)) {
if (E->getArg(1)->EvaluateAsInt(Info.Ctx).getZExtValue() < 2)
return Success(-1ULL, E);
return Success(0, E);
@@ -1495,7 +1488,7 @@ public:
// FIXME: Missing: __real__/__imag__, array subscript of vector,
// member of vector, ImplicitValueInitExpr,
- // conditional ?:, comma
+ // conditional ?:
};
} // end anonymous namespace
@@ -1584,6 +1577,18 @@ bool FloatExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) {
}
bool FloatExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
+ if (E->getOpcode() == BinaryOperator::Comma) {
+ if (!EvaluateFloat(E->getRHS(), Result, Info))
+ return false;
+
+ // If we can't evaluate the LHS, it might have side effects;
+ // conservatively mark it.
+ if (!E->getLHS()->isEvaluatable(Info.Ctx))
+ Info.EvalResult.HasSideEffects = true;
+
+ return true;
+ }
+
// FIXME: Diagnostics? I really don't understand how the warnings
// and errors are supposed to work.
APFloat RHS(0.0);
@@ -1947,6 +1952,12 @@ bool Expr::isEvaluatable(ASTContext &Ctx) const {
return Evaluate(Result, Ctx) && !Result.HasSideEffects;
}
+bool Expr::HasSideEffects(ASTContext &Ctx) const {
+ Expr::EvalResult Result;
+ EvalInfo Info(Ctx, Result);
+ return HasSideEffect(Info).Visit(const_cast<Expr*>(this));
+}
+
APSInt Expr::EvaluateAsInt(ASTContext &Ctx) const {
EvalResult EvalResult;
bool Result = Evaluate(EvalResult, Ctx);
diff --git a/lib/AST/NestedNameSpecifier.cpp b/lib/AST/NestedNameSpecifier.cpp
index d969776aa0ee..e26c0bba4934 100644
--- a/lib/AST/NestedNameSpecifier.cpp
+++ b/lib/AST/NestedNameSpecifier.cpp
@@ -167,7 +167,7 @@ NestedNameSpecifier::print(llvm::raw_ostream &OS,
InnerPolicy);
} else {
// Print the type normally
- T->getAsStringInternal(TypeStr, InnerPolicy);
+ TypeStr = QualType(T, 0).getAsString(InnerPolicy);
}
OS << TypeStr;
break;
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index 021c53e9514f..b9cfcfec74f0 100644
--- a/lib/AST/RecordLayoutBuilder.cpp
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -226,8 +226,7 @@ void ASTRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *Class,
if (RD == Class)
BaseOffset = getBaseOffset(Base);
else {
- const ASTRecordLayout &Layout
- = Ctx.getASTRecordLayout(RD);
+ const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
BaseOffset = Offset + Layout.getBaseClassOffset(Base);
}
}
diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp
index cf71d6b986a2..93bf8755d580 100644
--- a/lib/AST/StmtDumper.cpp
+++ b/lib/AST/StmtDumper.cpp
@@ -115,6 +115,7 @@ namespace {
// Exprs
void VisitExpr(Expr *Node);
void VisitCastExpr(CastExpr *Node);
+ void VisitImplicitCastExpr(ImplicitCastExpr *Node);
void VisitDeclRefExpr(DeclRefExpr *Node);
void VisitPredefinedExpr(PredefinedExpr *Node);
void VisitCharacterLiteral(CharacterLiteral *Node);
@@ -301,6 +302,12 @@ void StmtDumper::VisitCastExpr(CastExpr *Node) {
fprintf(F, " <%s>", Node->getCastKindName());
}
+void StmtDumper::VisitImplicitCastExpr(ImplicitCastExpr *Node) {
+ VisitCastExpr(Node);
+ if (Node->isLvalueCast())
+ fprintf(F, " lvalue");
+}
+
void StmtDumper::VisitDeclRefExpr(DeclRefExpr *Node) {
DumpExpr(Node);
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index 02e0c74bb63a..4458c2b9cd25 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -695,6 +695,10 @@ void StmtProfiler::VisitTemplateArgument(const TemplateArgument &Arg) {
VisitType(Arg.getAsType());
break;
+ case TemplateArgument::Template:
+ VisitTemplateName(Arg.getAsTemplate());
+ break;
+
case TemplateArgument::Declaration:
VisitDecl(Arg.getAsDecl());
break;
diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp
index 94e1ca1e06e7..ff02f9a31cb2 100644
--- a/lib/AST/TemplateBase.cpp
+++ b/lib/AST/TemplateBase.cpp
@@ -58,6 +58,11 @@ void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID,
ID.AddPointer(getAsDecl()? getAsDecl()->getCanonicalDecl() : 0);
break;
+ case Template:
+ ID.AddPointer(Context.getCanonicalTemplateName(getAsTemplate())
+ .getAsVoidPointer());
+ break;
+
case Integral:
getAsIntegral()->Profile(ID);
getIntegralType().Profile(ID);
@@ -82,10 +87,19 @@ SourceRange TemplateArgumentLoc::getSourceRange() const {
switch (Argument.getKind()) {
case TemplateArgument::Expression:
return getSourceExpression()->getSourceRange();
+
case TemplateArgument::Declaration:
return getSourceDeclExpression()->getSourceRange();
+
case TemplateArgument::Type:
return getSourceDeclaratorInfo()->getTypeLoc().getFullSourceRange();
+
+ case TemplateArgument::Template:
+ if (getTemplateQualifierRange().isValid())
+ return SourceRange(getTemplateQualifierRange().getBegin(),
+ getTemplateNameLoc());
+ return SourceRange(getTemplateNameLoc());
+
case TemplateArgument::Integral:
case TemplateArgument::Pack:
case TemplateArgument::Null:
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 779f6808b6c1..297534eaf1fc 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -98,6 +98,44 @@ const Type *Type::getArrayElementTypeNoTypeQual() const {
->getElementType().getTypePtr();
}
+/// \brief Retrieve the unqualified variant of the given type, removing as
+/// little sugar as possible.
+///
+/// This routine looks through various kinds of sugar to find the
+/// least-desuraged type that is unqualified. For example, given:
+///
+/// \code
+/// typedef int Integer;
+/// typedef const Integer CInteger;
+/// typedef CInteger DifferenceType;
+/// \endcode
+///
+/// Executing \c getUnqualifiedTypeSlow() on the type \c DifferenceType will
+/// desugar until we hit the type \c Integer, which has no qualifiers on it.
+QualType QualType::getUnqualifiedTypeSlow() const {
+ QualType Cur = *this;
+ while (true) {
+ if (!Cur.hasQualifiers())
+ return Cur;
+
+ const Type *CurTy = Cur.getTypePtr();
+ switch (CurTy->getTypeClass()) {
+#define ABSTRACT_TYPE(Class, Parent)
+#define TYPE(Class, Parent) \
+ case Type::Class: { \
+ const Class##Type *Ty = cast<Class##Type>(CurTy); \
+ if (!Ty->isSugared()) \
+ return Cur.getLocalUnqualifiedType(); \
+ Cur = Ty->desugar(); \
+ break; \
+ }
+#include "clang/AST/TypeNodes.def"
+ }
+ }
+
+ return Cur.getUnqualifiedType();
+}
+
/// getDesugaredType - Return the specified type with any "sugar" removed from
/// the type. This takes off typedefs, typeof's etc. If the outer level of
/// the type is already concrete, it returns it unmodified. This is similar
@@ -425,7 +463,7 @@ bool Type::isSignedIntegerType() const {
bool Type::isUnsignedIntegerType() const {
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) {
return BT->getKind() >= BuiltinType::Bool &&
- BT->getKind() <= BuiltinType::ULongLong;
+ BT->getKind() <= BuiltinType::UInt128;
}
if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType))
@@ -453,8 +491,7 @@ bool Type::isFloatingType() const {
bool Type::isRealFloatingType() const {
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
- return BT->getKind() >= BuiltinType::Float &&
- BT->getKind() <= BuiltinType::LongDouble;
+ return BT->isFloatingPoint();
if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType))
return VT->getElementType()->isRealFloatingType();
return false;
@@ -808,6 +845,9 @@ static bool isDependent(const TemplateArgument &Arg) {
case TemplateArgument::Type:
return Arg.getAsType()->isDependentType();
+ case TemplateArgument::Template:
+ return Arg.getAsTemplate().isDependent();
+
case TemplateArgument::Declaration:
case TemplateArgument::Integral:
// Never dependent
@@ -907,539 +947,6 @@ QualType QualifierCollector::apply(const Type *T) const {
return Context->getQualifiedType(T, *this);
}
-
-//===----------------------------------------------------------------------===//
-// Type Printing
-//===----------------------------------------------------------------------===//
-
-void QualType::dump(const char *msg) const {
- std::string R = "identifier";
- LangOptions LO;
- getAsStringInternal(R, PrintingPolicy(LO));
- if (msg)
- fprintf(stderr, "%s: %s\n", msg, R.c_str());
- else
- fprintf(stderr, "%s\n", R.c_str());
-}
-void QualType::dump() const {
- dump("");
-}
-
-void Type::dump() const {
- std::string S = "identifier";
- LangOptions LO;
- getAsStringInternal(S, PrintingPolicy(LO));
- fprintf(stderr, "%s\n", S.c_str());
-}
-
-
-
-static void AppendTypeQualList(std::string &S, unsigned TypeQuals) {
- if (TypeQuals & Qualifiers::Const) {
- if (!S.empty()) S += ' ';
- S += "const";
- }
- if (TypeQuals & Qualifiers::Volatile) {
- if (!S.empty()) S += ' ';
- S += "volatile";
- }
- if (TypeQuals & Qualifiers::Restrict) {
- if (!S.empty()) S += ' ';
- S += "restrict";
- }
-}
-
-std::string Qualifiers::getAsString() const {
- LangOptions LO;
- return getAsString(PrintingPolicy(LO));
-}
-
-// Appends qualifiers to the given string, separated by spaces. Will
-// prefix a space if the string is non-empty. Will not append a final
-// space.
-void Qualifiers::getAsStringInternal(std::string &S,
- const PrintingPolicy&) const {
- AppendTypeQualList(S, getCVRQualifiers());
- if (unsigned AddressSpace = getAddressSpace()) {
- if (!S.empty()) S += ' ';
- S += "__attribute__((address_space(";
- S += llvm::utostr_32(AddressSpace);
- S += ")))";
- }
- if (Qualifiers::GC GCAttrType = getObjCGCAttr()) {
- if (!S.empty()) S += ' ';
- S += "__attribute__((objc_gc(";
- if (GCAttrType == Qualifiers::Weak)
- S += "weak";
- else
- S += "strong";
- S += ")))";
- }
-}
-
-std::string QualType::getAsString() const {
- std::string S;
- LangOptions LO;
- getAsStringInternal(S, PrintingPolicy(LO));
- return S;
-}
-
-void
-QualType::getAsStringInternal(std::string &S,
- const PrintingPolicy &Policy) const {
- if (isNull()) {
- S += "NULL TYPE";
- return;
- }
-
- if (Policy.SuppressSpecifiers && getTypePtr()->isSpecifierType())
- return;
-
- // Print qualifiers as appropriate.
- Qualifiers Quals = getQualifiers();
- if (!Quals.empty()) {
- std::string TQS;
- Quals.getAsStringInternal(TQS, Policy);
-
- if (!S.empty()) {
- TQS += ' ';
- TQS += S;
- }
- std::swap(S, TQS);
- }
-
- getTypePtr()->getAsStringInternal(S, Policy);
-}
-
-void BuiltinType::getAsStringInternal(std::string &S,
- const PrintingPolicy &Policy) const {
- if (S.empty()) {
- S = getName(Policy.LangOpts);
- } else {
- // Prefix the basic type, e.g. 'int X'.
- S = ' ' + S;
- S = getName(Policy.LangOpts) + S;
- }
-}
-
-void FixedWidthIntType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
- // FIXME: Once we get bitwidth attribute, write as
- // "int __attribute__((bitwidth(x)))".
- std::string prefix = "__clang_fixedwidth";
- prefix += llvm::utostr_32(Width);
- prefix += (char)(Signed ? 'S' : 'U');
- if (S.empty()) {
- S = prefix;
- } else {
- // Prefix the basic type, e.g. 'int X'.
- S = prefix + S;
- }
-}
-
-
-void ComplexType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
- ElementType->getAsStringInternal(S, Policy);
- S = "_Complex " + S;
-}
-
-void PointerType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
- S = '*' + S;
-
- // Handle things like 'int (*A)[4];' correctly.
- // FIXME: this should include vectors, but vectors use attributes I guess.
- if (isa<ArrayType>(getPointeeType()))
- S = '(' + S + ')';
-
- getPointeeType().getAsStringInternal(S, Policy);
-}
-
-void BlockPointerType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
- S = '^' + S;
- PointeeType.getAsStringInternal(S, Policy);
-}
-
-void LValueReferenceType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
- S = '&' + S;
-
- // Handle things like 'int (&A)[4];' correctly.
- // FIXME: this should include vectors, but vectors use attributes I guess.
- if (isa<ArrayType>(getPointeeTypeAsWritten()))
- S = '(' + S + ')';
-
- getPointeeTypeAsWritten().getAsStringInternal(S, Policy);
-}
-
-void RValueReferenceType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
- S = "&&" + S;
-
- // Handle things like 'int (&&A)[4];' correctly.
- // FIXME: this should include vectors, but vectors use attributes I guess.
- if (isa<ArrayType>(getPointeeTypeAsWritten()))
- S = '(' + S + ')';
-
- getPointeeTypeAsWritten().getAsStringInternal(S, Policy);
-}
-
-void MemberPointerType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
- std::string C;
- Class->getAsStringInternal(C, Policy);
- C += "::*";
- S = C + S;
-
- // Handle things like 'int (Cls::*A)[4];' correctly.
- // FIXME: this should include vectors, but vectors use attributes I guess.
- if (isa<ArrayType>(getPointeeType()))
- S = '(' + S + ')';
-
- getPointeeType().getAsStringInternal(S, Policy);
-}
-
-void ConstantArrayType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
- S += '[';
- S += llvm::utostr(getSize().getZExtValue());
- S += ']';
-
- getElementType().getAsStringInternal(S, Policy);
-}
-
-void IncompleteArrayType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
- S += "[]";
-
- getElementType().getAsStringInternal(S, Policy);
-}
-
-void VariableArrayType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
- S += '[';
-
- if (getIndexTypeQualifiers().hasQualifiers()) {
- AppendTypeQualList(S, getIndexTypeCVRQualifiers());
- S += ' ';
- }
-
- if (getSizeModifier() == Static)
- S += "static";
- else if (getSizeModifier() == Star)
- S += '*';
-
- if (getSizeExpr()) {
- std::string SStr;
- llvm::raw_string_ostream s(SStr);
- getSizeExpr()->printPretty(s, 0, Policy);
- S += s.str();
- }
- S += ']';
-
- getElementType().getAsStringInternal(S, Policy);
-}
-
-void DependentSizedArrayType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
- S += '[';
-
- if (getIndexTypeQualifiers().hasQualifiers()) {
- AppendTypeQualList(S, getIndexTypeCVRQualifiers());
- S += ' ';
- }
-
- if (getSizeModifier() == Static)
- S += "static";
- else if (getSizeModifier() == Star)
- S += '*';
-
- if (getSizeExpr()) {
- std::string SStr;
- llvm::raw_string_ostream s(SStr);
- getSizeExpr()->printPretty(s, 0, Policy);
- S += s.str();
- }
- S += ']';
-
- getElementType().getAsStringInternal(S, Policy);
-}
-
-void DependentSizedExtVectorType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
- getElementType().getAsStringInternal(S, Policy);
-
- S += " __attribute__((ext_vector_type(";
- if (getSizeExpr()) {
- std::string SStr;
- llvm::raw_string_ostream s(SStr);
- getSizeExpr()->printPretty(s, 0, Policy);
- S += s.str();
- }
- S += ")))";
-}
-
-void VectorType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
- // FIXME: We prefer to print the size directly here, but have no way
- // to get the size of the type.
- S += " __attribute__((__vector_size__(";
- S += llvm::utostr_32(NumElements); // convert back to bytes.
- S += " * sizeof(" + ElementType.getAsString() + "))))";
- ElementType.getAsStringInternal(S, Policy);
-}
-
-void ExtVectorType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
- S += " __attribute__((ext_vector_type(";
- S += llvm::utostr_32(NumElements);
- S += ")))";
- ElementType.getAsStringInternal(S, Policy);
-}
-
-void TypeOfExprType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const {
- if (!InnerString.empty()) // Prefix the basic type, e.g. 'typeof(e) X'.
- InnerString = ' ' + InnerString;
- std::string Str;
- llvm::raw_string_ostream s(Str);
- getUnderlyingExpr()->printPretty(s, 0, Policy);
- InnerString = "typeof " + s.str() + InnerString;
-}
-
-void TypeOfType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const {
- if (!InnerString.empty()) // Prefix the basic type, e.g. 'typeof(t) X'.
- InnerString = ' ' + InnerString;
- std::string Tmp;
- getUnderlyingType().getAsStringInternal(Tmp, Policy);
- InnerString = "typeof(" + Tmp + ")" + InnerString;
-}
-
-void DecltypeType::getAsStringInternal(std::string &InnerString,
- const PrintingPolicy &Policy) const {
- if (!InnerString.empty()) // Prefix the basic type, e.g. 'decltype(t) X'.
- InnerString = ' ' + InnerString;
- std::string Str;
- llvm::raw_string_ostream s(Str);
- getUnderlyingExpr()->printPretty(s, 0, Policy);
- InnerString = "decltype(" + s.str() + ")" + InnerString;
-}
-
-void FunctionNoProtoType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
- // If needed for precedence reasons, wrap the inner part in grouping parens.
- if (!S.empty())
- S = "(" + S + ")";
-
- S += "()";
- if (getNoReturnAttr())
- S += " __attribute__((noreturn))";
- getResultType().getAsStringInternal(S, Policy);
-}
-
-void FunctionProtoType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const {
- // If needed for precedence reasons, wrap the inner part in grouping parens.
- if (!S.empty())
- S = "(" + S + ")";
-
- S += "(";
- std::string Tmp;
- PrintingPolicy ParamPolicy(Policy);
- ParamPolicy.SuppressSpecifiers = false;
- for (unsigned i = 0, e = getNumArgs(); i != e; ++i) {
- if (i) S += ", ";
- getArgType(i).getAsStringInternal(Tmp, ParamPolicy);
- S += Tmp;
- Tmp.clear();
- }
-
- if (isVariadic()) {
- if (getNumArgs())
- S += ", ";
- S += "...";
- } else if (getNumArgs() == 0 && !Policy.LangOpts.CPlusPlus) {
- // Do not emit int() if we have a proto, emit 'int(void)'.
- S += "void";
- }
-
- S += ")";
- if (getNoReturnAttr())
- S += " __attribute__((noreturn))";
- getResultType().getAsStringInternal(S, Policy);
-}
-
-
-void TypedefType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const {
- if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'.
- InnerString = ' ' + InnerString;
- InnerString = getDecl()->getIdentifier()->getName().str() + InnerString;
-}
-
-void TemplateTypeParmType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const {
- if (!InnerString.empty()) // Prefix the basic type, e.g. 'parmname X'.
- InnerString = ' ' + InnerString;
-
- if (!Name)
- InnerString = "type-parameter-" + llvm::utostr_32(Depth) + '-' +
- llvm::utostr_32(Index) + InnerString;
- else
- InnerString = Name->getName().str() + InnerString;
-}
-
-void SubstTemplateTypeParmType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const {
- getReplacementType().getAsStringInternal(InnerString, Policy);
-}
-
-static void PrintTemplateArgument(std::string &Buffer,
- const TemplateArgument &Arg,
- const PrintingPolicy &Policy) {
- switch (Arg.getKind()) {
- case TemplateArgument::Null:
- assert(false && "Null template argument");
- break;
-
- case TemplateArgument::Type:
- Arg.getAsType().getAsStringInternal(Buffer, Policy);
- break;
-
- case TemplateArgument::Declaration:
- Buffer = cast<NamedDecl>(Arg.getAsDecl())->getNameAsString();
- break;
-
- case TemplateArgument::Integral:
- Buffer = Arg.getAsIntegral()->toString(10, true);
- break;
-
- case TemplateArgument::Expression: {
- llvm::raw_string_ostream s(Buffer);
- Arg.getAsExpr()->printPretty(s, 0, Policy);
- break;
- }
-
- case TemplateArgument::Pack:
- assert(0 && "FIXME: Implement!");
- break;
- }
-}
-
-std::string
-TemplateSpecializationType::PrintTemplateArgumentList(
- const TemplateArgument *Args,
- unsigned NumArgs,
- const PrintingPolicy &Policy) {
- std::string SpecString;
- SpecString += '<';
- for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
- if (Arg)
- SpecString += ", ";
-
- // Print the argument into a string.
- std::string ArgString;
- PrintTemplateArgument(ArgString, Args[Arg], Policy);
-
- // If this is the first argument and its string representation
- // begins with the global scope specifier ('::foo'), add a space
- // to avoid printing the diagraph '<:'.
- if (!Arg && !ArgString.empty() && ArgString[0] == ':')
- SpecString += ' ';
-
- SpecString += ArgString;
- }
-
- // If the last character of our string is '>', add another space to
- // keep the two '>''s separate tokens. We don't *have* to do this in
- // C++0x, but it's still good hygiene.
- if (SpecString[SpecString.size() - 1] == '>')
- SpecString += ' ';
-
- SpecString += '>';
-
- return SpecString;
-}
-
-// Sadly, repeat all that with TemplateArgLoc.
-std::string TemplateSpecializationType::
-PrintTemplateArgumentList(const TemplateArgumentLoc *Args, unsigned NumArgs,
- const PrintingPolicy &Policy) {
- std::string SpecString;
- SpecString += '<';
- for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
- if (Arg)
- SpecString += ", ";
-
- // Print the argument into a string.
- std::string ArgString;
- PrintTemplateArgument(ArgString, Args[Arg].getArgument(), Policy);
-
- // If this is the first argument and its string representation
- // begins with the global scope specifier ('::foo'), add a space
- // to avoid printing the diagraph '<:'.
- if (!Arg && !ArgString.empty() && ArgString[0] == ':')
- SpecString += ' ';
-
- SpecString += ArgString;
- }
-
- // If the last character of our string is '>', add another space to
- // keep the two '>''s separate tokens. We don't *have* to do this in
- // C++0x, but it's still good hygiene.
- if (SpecString[SpecString.size() - 1] == '>')
- SpecString += ' ';
-
- SpecString += '>';
-
- return SpecString;
-}
-
-void
-TemplateSpecializationType::
-getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const {
- std::string SpecString;
-
- {
- llvm::raw_string_ostream OS(SpecString);
- Template.print(OS, Policy);
- }
-
- SpecString += PrintTemplateArgumentList(getArgs(), getNumArgs(), Policy);
- if (InnerString.empty())
- InnerString.swap(SpecString);
- else
- InnerString = SpecString + ' ' + InnerString;
-}
-
-void QualifiedNameType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const {
- std::string MyString;
-
- {
- llvm::raw_string_ostream OS(MyString);
- NNS->print(OS, Policy);
- }
-
- std::string TypeStr;
- PrintingPolicy InnerPolicy(Policy);
- InnerPolicy.SuppressTagKind = true;
- InnerPolicy.SuppressScope = true;
- NamedType.getAsStringInternal(TypeStr, InnerPolicy);
-
- MyString += TypeStr;
- if (InnerString.empty())
- InnerString.swap(MyString);
- else
- InnerString = MyString + ' ' + InnerString;
-}
-
-void TypenameType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const {
- std::string MyString;
-
- {
- llvm::raw_string_ostream OS(MyString);
- OS << "typename ";
- NNS->print(OS, Policy);
-
- if (const IdentifierInfo *Ident = getIdentifier())
- OS << Ident->getName();
- else if (const TemplateSpecializationType *Spec = getTemplateId()) {
- Spec->getTemplateName().print(OS, Policy, true);
- OS << TemplateSpecializationType::PrintTemplateArgumentList(
- Spec->getArgs(),
- Spec->getNumArgs(),
- Policy);
- }
- }
-
- if (InnerString.empty())
- InnerString.swap(MyString);
- else
- InnerString = MyString + ' ' + InnerString;
-}
-
void ObjCInterfaceType::Profile(llvm::FoldingSetNodeID &ID,
const ObjCInterfaceDecl *Decl,
ObjCProtocolDecl **protocols,
@@ -1455,134 +962,3 @@ void ObjCInterfaceType::Profile(llvm::FoldingSetNodeID &ID) {
else
Profile(ID, getDecl(), 0, 0);
}
-
-void ObjCInterfaceType::getAsStringInternal(std::string &InnerString,
- const PrintingPolicy &Policy) const {
- if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'.
- InnerString = ' ' + InnerString;
-
- std::string ObjCQIString = getDecl()->getNameAsString();
- if (getNumProtocols()) {
- ObjCQIString += '<';
- bool isFirst = true;
- for (qual_iterator I = qual_begin(), E = qual_end(); I != E; ++I) {
- if (isFirst)
- isFirst = false;
- else
- ObjCQIString += ',';
- ObjCQIString += (*I)->getNameAsString();
- }
- ObjCQIString += '>';
- }
- InnerString = ObjCQIString + InnerString;
-}
-
-void ObjCObjectPointerType::getAsStringInternal(std::string &InnerString,
- const PrintingPolicy &Policy) const {
- std::string ObjCQIString;
-
- if (isObjCIdType() || isObjCQualifiedIdType())
- ObjCQIString = "id";
- else if (isObjCClassType() || isObjCQualifiedClassType())
- ObjCQIString = "Class";
- else
- ObjCQIString = getInterfaceDecl()->getNameAsString();
-
- if (!qual_empty()) {
- ObjCQIString += '<';
- for (qual_iterator I = qual_begin(), E = qual_end(); I != E; ++I) {
- ObjCQIString += (*I)->getNameAsString();
- if (I+1 != E)
- ObjCQIString += ',';
- }
- ObjCQIString += '>';
- }
-
- PointeeType.getQualifiers().getAsStringInternal(ObjCQIString, Policy);
-
- if (!isObjCIdType() && !isObjCQualifiedIdType())
- ObjCQIString += " *"; // Don't forget the implicit pointer.
- else if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'.
- InnerString = ' ' + InnerString;
-
- InnerString = ObjCQIString + InnerString;
-}
-
-void ElaboratedType::getAsStringInternal(std::string &InnerString,
- const PrintingPolicy &Policy) const {
- std::string TypeStr;
- PrintingPolicy InnerPolicy(Policy);
- InnerPolicy.SuppressTagKind = true;
- UnderlyingType.getAsStringInternal(InnerString, InnerPolicy);
-
- InnerString = std::string(getNameForTagKind(getTagKind())) + ' ' + InnerString;
-}
-
-void TagType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const {
- if (Policy.SuppressTag)
- return;
-
- if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'.
- InnerString = ' ' + InnerString;
-
- const char *Kind = Policy.SuppressTagKind? 0 : getDecl()->getKindName();
- const char *ID;
- if (const IdentifierInfo *II = getDecl()->getIdentifier())
- ID = II->getNameStart();
- else if (TypedefDecl *Typedef = getDecl()->getTypedefForAnonDecl()) {
- Kind = 0;
- assert(Typedef->getIdentifier() && "Typedef without identifier?");
- ID = Typedef->getIdentifier()->getNameStart();
- } else
- ID = "<anonymous>";
-
- // If this is a class template specialization, print the template
- // arguments.
- if (ClassTemplateSpecializationDecl *Spec
- = dyn_cast<ClassTemplateSpecializationDecl>(getDecl())) {
- const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
- std::string TemplateArgsStr
- = TemplateSpecializationType::PrintTemplateArgumentList(
- TemplateArgs.getFlatArgumentList(),
- TemplateArgs.flat_size(),
- Policy);
- InnerString = TemplateArgsStr + InnerString;
- }
-
- if (!Policy.SuppressScope) {
- // Compute the full nested-name-specifier for this type. In C,
- // this will always be empty.
- std::string ContextStr;
- for (DeclContext *DC = getDecl()->getDeclContext();
- !DC->isTranslationUnit(); DC = DC->getParent()) {
- std::string MyPart;
- if (NamespaceDecl *NS = dyn_cast<NamespaceDecl>(DC)) {
- if (NS->getIdentifier())
- MyPart = NS->getNameAsString();
- } else if (ClassTemplateSpecializationDecl *Spec
- = dyn_cast<ClassTemplateSpecializationDecl>(DC)) {
- const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
- std::string TemplateArgsStr
- = TemplateSpecializationType::PrintTemplateArgumentList(
- TemplateArgs.getFlatArgumentList(),
- TemplateArgs.flat_size(),
- Policy);
- MyPart = Spec->getIdentifier()->getName().str() + TemplateArgsStr;
- } else if (TagDecl *Tag = dyn_cast<TagDecl>(DC)) {
- if (TypedefDecl *Typedef = Tag->getTypedefForAnonDecl())
- MyPart = Typedef->getIdentifier()->getName();
- else if (Tag->getIdentifier())
- MyPart = Tag->getIdentifier()->getName();
- }
-
- if (!MyPart.empty())
- ContextStr = MyPart + "::" + ContextStr;
- }
-
- if (Kind)
- InnerString = std::string(Kind) + ' ' + ContextStr + ID + InnerString;
- else
- InnerString = ContextStr + ID + InnerString;
- } else
- InnerString = ID + InnerString;
-}
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
new file mode 100644
index 000000000000..a48233378286
--- /dev/null
+++ b/lib/AST/TypePrinter.cpp
@@ -0,0 +1,728 @@
+//===--- TypePrinter.cpp - Pretty-Print Clang Types -----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This contains code to print types from Clang's type system.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/Type.h"
+#include "clang/AST/PrettyPrinter.h"
+#include "clang/Basic/LangOptions.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace clang;
+
+namespace {
+ class TypePrinter {
+ PrintingPolicy Policy;
+
+ public:
+ explicit TypePrinter(const PrintingPolicy &Policy) : Policy(Policy) { }
+
+ void Print(QualType T, std::string &S);
+ void PrintTag(const TagType *T, std::string &S);
+#define ABSTRACT_TYPE(CLASS, PARENT)
+#define TYPE(CLASS, PARENT) \
+ void Print##CLASS(const CLASS##Type *T, std::string &S);
+#include "clang/AST/TypeNodes.def"
+ };
+}
+
+static void AppendTypeQualList(std::string &S, unsigned TypeQuals) {
+ if (TypeQuals & Qualifiers::Const) {
+ if (!S.empty()) S += ' ';
+ S += "const";
+ }
+ if (TypeQuals & Qualifiers::Volatile) {
+ if (!S.empty()) S += ' ';
+ S += "volatile";
+ }
+ if (TypeQuals & Qualifiers::Restrict) {
+ if (!S.empty()) S += ' ';
+ S += "restrict";
+ }
+}
+
+void TypePrinter::Print(QualType T, std::string &S) {
+ if (T.isNull()) {
+ S += "NULL TYPE";
+ return;
+ }
+
+ if (Policy.SuppressSpecifiers && T->isSpecifierType())
+ return;
+
+ // Print qualifiers as appropriate.
+ Qualifiers Quals = T.getLocalQualifiers();
+ if (!Quals.empty()) {
+ std::string TQS;
+ Quals.getAsStringInternal(TQS, Policy);
+
+ if (!S.empty()) {
+ TQS += ' ';
+ TQS += S;
+ }
+ std::swap(S, TQS);
+ }
+
+ switch (T->getTypeClass()) {
+#define ABSTRACT_TYPE(CLASS, PARENT)
+#define TYPE(CLASS, PARENT) case Type::CLASS: \
+ Print##CLASS(cast<CLASS##Type>(T.getTypePtr()), S); \
+ break;
+#include "clang/AST/TypeNodes.def"
+ }
+}
+
+void TypePrinter::PrintBuiltin(const BuiltinType *T, std::string &S) {
+ if (S.empty()) {
+ S = T->getName(Policy.LangOpts);
+ } else {
+ // Prefix the basic type, e.g. 'int X'.
+ S = ' ' + S;
+ S = T->getName(Policy.LangOpts) + S;
+ }
+}
+
+void TypePrinter::PrintFixedWidthInt(const FixedWidthIntType *T,
+ std::string &S) {
+ // FIXME: Once we get bitwidth attribute, write as
+ // "int __attribute__((bitwidth(x)))".
+ std::string prefix = "__clang_fixedwidth";
+ prefix += llvm::utostr_32(T->getWidth());
+ prefix += (char)(T->isSigned() ? 'S' : 'U');
+ if (S.empty()) {
+ S = prefix;
+ } else {
+ // Prefix the basic type, e.g. 'int X'.
+ S = prefix + S;
+ }
+}
+
+void TypePrinter::PrintComplex(const ComplexType *T, std::string &S) {
+ Print(T->getElementType(), S);
+ S = "_Complex " + S;
+}
+
+void TypePrinter::PrintPointer(const PointerType *T, std::string &S) {
+ S = '*' + S;
+
+ // Handle things like 'int (*A)[4];' correctly.
+ // FIXME: this should include vectors, but vectors use attributes I guess.
+ if (isa<ArrayType>(T->getPointeeType()))
+ S = '(' + S + ')';
+
+ Print(T->getPointeeType(), S);
+}
+
+void TypePrinter::PrintBlockPointer(const BlockPointerType *T, std::string &S) {
+ S = '^' + S;
+ Print(T->getPointeeType(), S);
+}
+
+void TypePrinter::PrintLValueReference(const LValueReferenceType *T,
+ std::string &S) {
+ S = '&' + S;
+
+ // Handle things like 'int (&A)[4];' correctly.
+ // FIXME: this should include vectors, but vectors use attributes I guess.
+ if (isa<ArrayType>(T->getPointeeTypeAsWritten()))
+ S = '(' + S + ')';
+
+ Print(T->getPointeeTypeAsWritten(), S);
+}
+
+void TypePrinter::PrintRValueReference(const RValueReferenceType *T,
+ std::string &S) {
+ S = "&&" + S;
+
+ // Handle things like 'int (&&A)[4];' correctly.
+ // FIXME: this should include vectors, but vectors use attributes I guess.
+ if (isa<ArrayType>(T->getPointeeTypeAsWritten()))
+ S = '(' + S + ')';
+
+ Print(T->getPointeeTypeAsWritten(), S);
+}
+
+void TypePrinter::PrintMemberPointer(const MemberPointerType *T,
+ std::string &S) {
+ std::string C;
+ Print(QualType(T->getClass(), 0), C);
+ C += "::*";
+ S = C + S;
+
+ // Handle things like 'int (Cls::*A)[4];' correctly.
+ // FIXME: this should include vectors, but vectors use attributes I guess.
+ if (isa<ArrayType>(T->getPointeeType()))
+ S = '(' + S + ')';
+
+ Print(T->getPointeeType(), S);
+}
+
+void TypePrinter::PrintConstantArray(const ConstantArrayType *T,
+ std::string &S) {
+ S += '[';
+ S += llvm::utostr(T->getSize().getZExtValue());
+ S += ']';
+
+ Print(T->getElementType(), S);
+}
+
+void TypePrinter::PrintIncompleteArray(const IncompleteArrayType *T,
+ std::string &S) {
+ S += "[]";
+ Print(T->getElementType(), S);
+}
+
+void TypePrinter::PrintVariableArray(const VariableArrayType *T,
+ std::string &S) {
+ S += '[';
+
+ if (T->getIndexTypeQualifiers().hasQualifiers()) {
+ AppendTypeQualList(S, T->getIndexTypeCVRQualifiers());
+ S += ' ';
+ }
+
+ if (T->getSizeModifier() == VariableArrayType::Static)
+ S += "static";
+ else if (T->getSizeModifier() == VariableArrayType::Star)
+ S += '*';
+
+ if (T->getSizeExpr()) {
+ std::string SStr;
+ llvm::raw_string_ostream s(SStr);
+ T->getSizeExpr()->printPretty(s, 0, Policy);
+ S += s.str();
+ }
+ S += ']';
+
+ Print(T->getElementType(), S);
+}
+
+void TypePrinter::PrintDependentSizedArray(const DependentSizedArrayType *T,
+ std::string &S) {
+ S += '[';
+
+ if (T->getSizeExpr()) {
+ std::string SStr;
+ llvm::raw_string_ostream s(SStr);
+ T->getSizeExpr()->printPretty(s, 0, Policy);
+ S += s.str();
+ }
+ S += ']';
+
+ Print(T->getElementType(), S);
+}
+
+void TypePrinter::PrintDependentSizedExtVector(
+ const DependentSizedExtVectorType *T,
+ std::string &S) {
+ Print(T->getElementType(), S);
+
+ S += " __attribute__((ext_vector_type(";
+ if (T->getSizeExpr()) {
+ std::string SStr;
+ llvm::raw_string_ostream s(SStr);
+ T->getSizeExpr()->printPretty(s, 0, Policy);
+ S += s.str();
+ }
+ S += ")))";
+}
+
+void TypePrinter::PrintVector(const VectorType *T, std::string &S) {
+ // FIXME: We prefer to print the size directly here, but have no way
+ // to get the size of the type.
+ S += " __attribute__((__vector_size__(";
+ S += llvm::utostr_32(T->getNumElements()); // convert back to bytes.
+ std::string ET;
+ Print(T->getElementType(), ET);
+ S += " * sizeof(" + ET + "))))";
+ Print(T->getElementType(), S);
+}
+
+void TypePrinter::PrintExtVector(const ExtVectorType *T, std::string &S) {
+ S += " __attribute__((ext_vector_type(";
+ S += llvm::utostr_32(T->getNumElements());
+ S += ")))";
+ Print(T->getElementType(), S);
+}
+
+void TypePrinter::PrintFunctionProto(const FunctionProtoType *T,
+ std::string &S) {
+ // If needed for precedence reasons, wrap the inner part in grouping parens.
+ if (!S.empty())
+ S = "(" + S + ")";
+
+ S += "(";
+ std::string Tmp;
+ PrintingPolicy ParamPolicy(Policy);
+ ParamPolicy.SuppressSpecifiers = false;
+ for (unsigned i = 0, e = T->getNumArgs(); i != e; ++i) {
+ if (i) S += ", ";
+ Print(T->getArgType(i), Tmp);
+ S += Tmp;
+ Tmp.clear();
+ }
+
+ if (T->isVariadic()) {
+ if (T->getNumArgs())
+ S += ", ";
+ S += "...";
+ } else if (T->getNumArgs() == 0 && !Policy.LangOpts.CPlusPlus) {
+ // Do not emit int() if we have a proto, emit 'int(void)'.
+ S += "void";
+ }
+
+ S += ")";
+ if (T->getNoReturnAttr())
+ S += " __attribute__((noreturn))";
+ Print(T->getResultType(), S);
+
+}
+
+void TypePrinter::PrintFunctionNoProto(const FunctionNoProtoType *T,
+ std::string &S) {
+ // If needed for precedence reasons, wrap the inner part in grouping parens.
+ if (!S.empty())
+ S = "(" + S + ")";
+
+ S += "()";
+ if (T->getNoReturnAttr())
+ S += " __attribute__((noreturn))";
+ Print(T->getResultType(), S);
+}
+
+void TypePrinter::PrintTypedef(const TypedefType *T, std::string &S) {
+ if (!S.empty()) // Prefix the basic type, e.g. 'typedefname X'.
+ S = ' ' + S;
+ S = T->getDecl()->getIdentifier()->getName().str() + S;
+}
+
+void TypePrinter::PrintTypeOfExpr(const TypeOfExprType *T, std::string &S) {
+ if (!S.empty()) // Prefix the basic type, e.g. 'typeof(e) X'.
+ S = ' ' + S;
+ std::string Str;
+ llvm::raw_string_ostream s(Str);
+ T->getUnderlyingExpr()->printPretty(s, 0, Policy);
+ S = "typeof " + s.str() + S;
+}
+
+void TypePrinter::PrintTypeOf(const TypeOfType *T, std::string &S) {
+ if (!S.empty()) // Prefix the basic type, e.g. 'typeof(t) X'.
+ S = ' ' + S;
+ std::string Tmp;
+ Print(T->getUnderlyingType(), Tmp);
+ S = "typeof(" + Tmp + ")" + S;
+}
+
+void TypePrinter::PrintDecltype(const DecltypeType *T, std::string &S) {
+ if (!S.empty()) // Prefix the basic type, e.g. 'decltype(t) X'.
+ S = ' ' + S;
+ std::string Str;
+ llvm::raw_string_ostream s(Str);
+ T->getUnderlyingExpr()->printPretty(s, 0, Policy);
+ S = "decltype(" + s.str() + ")" + S;
+}
+
+void TypePrinter::PrintTag(const TagType *T, std::string &InnerString) {
+ if (Policy.SuppressTag)
+ return;
+
+ if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'.
+ InnerString = ' ' + InnerString;
+
+ const char *Kind = Policy.SuppressTagKind? 0 : T->getDecl()->getKindName();
+ const char *ID;
+ if (const IdentifierInfo *II = T->getDecl()->getIdentifier())
+ ID = II->getNameStart();
+ else if (TypedefDecl *Typedef = T->getDecl()->getTypedefForAnonDecl()) {
+ Kind = 0;
+ assert(Typedef->getIdentifier() && "Typedef without identifier?");
+ ID = Typedef->getIdentifier()->getNameStart();
+ } else
+ ID = "<anonymous>";
+
+ // If this is a class template specialization, print the template
+ // arguments.
+ if (ClassTemplateSpecializationDecl *Spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(T->getDecl())) {
+ const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
+ std::string TemplateArgsStr
+ = TemplateSpecializationType::PrintTemplateArgumentList(
+ TemplateArgs.getFlatArgumentList(),
+ TemplateArgs.flat_size(),
+ Policy);
+ InnerString = TemplateArgsStr + InnerString;
+ }
+
+ if (!Policy.SuppressScope) {
+ // Compute the full nested-name-specifier for this type. In C,
+ // this will always be empty.
+ std::string ContextStr;
+ for (DeclContext *DC = T->getDecl()->getDeclContext();
+ !DC->isTranslationUnit(); DC = DC->getParent()) {
+ std::string MyPart;
+ if (NamespaceDecl *NS = dyn_cast<NamespaceDecl>(DC)) {
+ if (NS->getIdentifier())
+ MyPart = NS->getNameAsString();
+ } else if (ClassTemplateSpecializationDecl *Spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(DC)) {
+ const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
+ std::string TemplateArgsStr
+ = TemplateSpecializationType::PrintTemplateArgumentList(
+ TemplateArgs.getFlatArgumentList(),
+ TemplateArgs.flat_size(),
+ Policy);
+ MyPart = Spec->getIdentifier()->getName().str() + TemplateArgsStr;
+ } else if (TagDecl *Tag = dyn_cast<TagDecl>(DC)) {
+ if (TypedefDecl *Typedef = Tag->getTypedefForAnonDecl())
+ MyPart = Typedef->getIdentifier()->getName();
+ else if (Tag->getIdentifier())
+ MyPart = Tag->getIdentifier()->getName();
+ }
+
+ if (!MyPart.empty())
+ ContextStr = MyPart + "::" + ContextStr;
+ }
+
+ if (Kind)
+ InnerString = std::string(Kind) + ' ' + ContextStr + ID + InnerString;
+ else
+ InnerString = ContextStr + ID + InnerString;
+ } else
+ InnerString = ID + InnerString;
+}
+
+void TypePrinter::PrintRecord(const RecordType *T, std::string &S) {
+ PrintTag(T, S);
+}
+
+void TypePrinter::PrintEnum(const EnumType *T, std::string &S) {
+ PrintTag(T, S);
+}
+
+void TypePrinter::PrintElaborated(const ElaboratedType *T, std::string &S) {
+ std::string TypeStr;
+ PrintingPolicy InnerPolicy(Policy);
+ InnerPolicy.SuppressTagKind = true;
+ TypePrinter(InnerPolicy).Print(T->getUnderlyingType(), S);
+
+ S = std::string(T->getNameForTagKind(T->getTagKind())) + ' ' + S;
+}
+
+void TypePrinter::PrintTemplateTypeParm(const TemplateTypeParmType *T,
+ std::string &S) {
+ if (!S.empty()) // Prefix the basic type, e.g. 'parmname X'.
+ S = ' ' + S;
+
+ if (!T->getName())
+ S = "type-parameter-" + llvm::utostr_32(T->getDepth()) + '-' +
+ llvm::utostr_32(T->getIndex()) + S;
+ else
+ S = T->getName()->getName().str() + S;
+}
+
+void TypePrinter::PrintSubstTemplateTypeParm(const SubstTemplateTypeParmType *T,
+ std::string &S) {
+ Print(T->getReplacementType(), S);
+}
+
+void TypePrinter::PrintTemplateSpecialization(
+ const TemplateSpecializationType *T,
+ std::string &S) {
+ std::string SpecString;
+
+ {
+ llvm::raw_string_ostream OS(SpecString);
+ T->getTemplateName().print(OS, Policy);
+ }
+
+ SpecString += TemplateSpecializationType::PrintTemplateArgumentList(
+ T->getArgs(),
+ T->getNumArgs(),
+ Policy);
+ if (S.empty())
+ S.swap(SpecString);
+ else
+ S = SpecString + ' ' + S;
+}
+
+void TypePrinter::PrintQualifiedName(const QualifiedNameType *T,
+ std::string &S) {
+ std::string MyString;
+
+ {
+ llvm::raw_string_ostream OS(MyString);
+ T->getQualifier()->print(OS, Policy);
+ }
+
+ std::string TypeStr;
+ PrintingPolicy InnerPolicy(Policy);
+ InnerPolicy.SuppressTagKind = true;
+ InnerPolicy.SuppressScope = true;
+ TypePrinter(InnerPolicy).Print(T->getNamedType(), TypeStr);
+
+ MyString += TypeStr;
+ if (S.empty())
+ S.swap(MyString);
+ else
+ S = MyString + ' ' + S;
+}
+
+void TypePrinter::PrintTypename(const TypenameType *T, std::string &S) {
+ std::string MyString;
+
+ {
+ llvm::raw_string_ostream OS(MyString);
+ OS << "typename ";
+ T->getQualifier()->print(OS, Policy);
+
+ if (const IdentifierInfo *Ident = T->getIdentifier())
+ OS << Ident->getName();
+ else if (const TemplateSpecializationType *Spec = T->getTemplateId()) {
+ Spec->getTemplateName().print(OS, Policy, true);
+ OS << TemplateSpecializationType::PrintTemplateArgumentList(
+ Spec->getArgs(),
+ Spec->getNumArgs(),
+ Policy);
+ }
+ }
+
+ if (S.empty())
+ S.swap(MyString);
+ else
+ S = MyString + ' ' + S;
+}
+
+void TypePrinter::PrintObjCInterface(const ObjCInterfaceType *T,
+ std::string &S) {
+ if (!S.empty()) // Prefix the basic type, e.g. 'typedefname X'.
+ S = ' ' + S;
+
+ std::string ObjCQIString = T->getDecl()->getNameAsString();
+ if (T->getNumProtocols()) {
+ ObjCQIString += '<';
+ bool isFirst = true;
+ for (ObjCInterfaceType::qual_iterator I = T->qual_begin(),
+ E = T->qual_end();
+ I != E; ++I) {
+ if (isFirst)
+ isFirst = false;
+ else
+ ObjCQIString += ',';
+ ObjCQIString += (*I)->getNameAsString();
+ }
+ ObjCQIString += '>';
+ }
+ S = ObjCQIString + S;
+}
+
+void TypePrinter::PrintObjCObjectPointer(const ObjCObjectPointerType *T,
+ std::string &S) {
+ std::string ObjCQIString;
+
+ if (T->isObjCIdType() || T->isObjCQualifiedIdType())
+ ObjCQIString = "id";
+ else if (T->isObjCClassType() || T->isObjCQualifiedClassType())
+ ObjCQIString = "Class";
+ else
+ ObjCQIString = T->getInterfaceDecl()->getNameAsString();
+
+ if (!T->qual_empty()) {
+ ObjCQIString += '<';
+ for (ObjCObjectPointerType::qual_iterator I = T->qual_begin(),
+ E = T->qual_end();
+ I != E; ++I) {
+ ObjCQIString += (*I)->getNameAsString();
+ if (I+1 != E)
+ ObjCQIString += ',';
+ }
+ ObjCQIString += '>';
+ }
+
+ T->getPointeeType().getLocalQualifiers().getAsStringInternal(ObjCQIString,
+ Policy);
+
+ if (!T->isObjCIdType() && !T->isObjCQualifiedIdType())
+ ObjCQIString += " *"; // Don't forget the implicit pointer.
+ else if (!S.empty()) // Prefix the basic type, e.g. 'typedefname X'.
+ S = ' ' + S;
+
+ S = ObjCQIString + S;
+}
+
+static void PrintTemplateArgument(std::string &Buffer,
+ const TemplateArgument &Arg,
+ const PrintingPolicy &Policy) {
+ switch (Arg.getKind()) {
+ case TemplateArgument::Null:
+ assert(false && "Null template argument");
+ break;
+
+ case TemplateArgument::Type:
+ Arg.getAsType().getAsStringInternal(Buffer, Policy);
+ break;
+
+ case TemplateArgument::Declaration:
+ Buffer = cast<NamedDecl>(Arg.getAsDecl())->getNameAsString();
+ break;
+
+ case TemplateArgument::Template: {
+ llvm::raw_string_ostream s(Buffer);
+ Arg.getAsTemplate().print(s, Policy);
+ break;
+ }
+
+ case TemplateArgument::Integral:
+ Buffer = Arg.getAsIntegral()->toString(10, true);
+ break;
+
+ case TemplateArgument::Expression: {
+ llvm::raw_string_ostream s(Buffer);
+ Arg.getAsExpr()->printPretty(s, 0, Policy);
+ break;
+ }
+
+ case TemplateArgument::Pack:
+ assert(0 && "FIXME: Implement!");
+ break;
+ }
+}
+
+std::string
+TemplateSpecializationType::PrintTemplateArgumentList(
+ const TemplateArgument *Args,
+ unsigned NumArgs,
+ const PrintingPolicy &Policy) {
+ std::string SpecString;
+ SpecString += '<';
+ for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
+ if (Arg)
+ SpecString += ", ";
+
+ // Print the argument into a string.
+ std::string ArgString;
+ PrintTemplateArgument(ArgString, Args[Arg], Policy);
+
+ // If this is the first argument and its string representation
+ // begins with the global scope specifier ('::foo'), add a space
+ // to avoid printing the diagraph '<:'.
+ if (!Arg && !ArgString.empty() && ArgString[0] == ':')
+ SpecString += ' ';
+
+ SpecString += ArgString;
+ }
+
+ // If the last character of our string is '>', add another space to
+ // keep the two '>''s separate tokens. We don't *have* to do this in
+ // C++0x, but it's still good hygiene.
+ if (SpecString[SpecString.size() - 1] == '>')
+ SpecString += ' ';
+
+ SpecString += '>';
+
+ return SpecString;
+}
+
+// Sadly, repeat all that with TemplateArgLoc.
+std::string TemplateSpecializationType::
+PrintTemplateArgumentList(const TemplateArgumentLoc *Args, unsigned NumArgs,
+ const PrintingPolicy &Policy) {
+ std::string SpecString;
+ SpecString += '<';
+ for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
+ if (Arg)
+ SpecString += ", ";
+
+ // Print the argument into a string.
+ std::string ArgString;
+ PrintTemplateArgument(ArgString, Args[Arg].getArgument(), Policy);
+
+ // If this is the first argument and its string representation
+ // begins with the global scope specifier ('::foo'), add a space
+ // to avoid printing the diagraph '<:'.
+ if (!Arg && !ArgString.empty() && ArgString[0] == ':')
+ SpecString += ' ';
+
+ SpecString += ArgString;
+ }
+
+ // If the last character of our string is '>', add another space to
+ // keep the two '>''s separate tokens. We don't *have* to do this in
+ // C++0x, but it's still good hygiene.
+ if (SpecString[SpecString.size() - 1] == '>')
+ SpecString += ' ';
+
+ SpecString += '>';
+
+ return SpecString;
+}
+
+void QualType::dump(const char *msg) const {
+ std::string R = "identifier";
+ LangOptions LO;
+ getAsStringInternal(R, PrintingPolicy(LO));
+ if (msg)
+ fprintf(stderr, "%s: %s\n", msg, R.c_str());
+ else
+ fprintf(stderr, "%s\n", R.c_str());
+}
+void QualType::dump() const {
+ dump("");
+}
+
+void Type::dump() const {
+ QualType(this, 0).dump();
+}
+
+std::string Qualifiers::getAsString() const {
+ LangOptions LO;
+ return getAsString(PrintingPolicy(LO));
+}
+
+// Appends qualifiers to the given string, separated by spaces. Will
+// prefix a space if the string is non-empty. Will not append a final
+// space.
+void Qualifiers::getAsStringInternal(std::string &S,
+ const PrintingPolicy&) const {
+ AppendTypeQualList(S, getCVRQualifiers());
+ if (unsigned AddressSpace = getAddressSpace()) {
+ if (!S.empty()) S += ' ';
+ S += "__attribute__((address_space(";
+ S += llvm::utostr_32(AddressSpace);
+ S += ")))";
+ }
+ if (Qualifiers::GC GCAttrType = getObjCGCAttr()) {
+ if (!S.empty()) S += ' ';
+ S += "__attribute__((objc_gc(";
+ if (GCAttrType == Qualifiers::Weak)
+ S += "weak";
+ else
+ S += "strong";
+ S += ")))";
+ }
+}
+
+std::string QualType::getAsString() const {
+ std::string S;
+ LangOptions LO;
+ getAsStringInternal(S, PrintingPolicy(LO));
+ return S;
+}
+
+void QualType::getAsStringInternal(std::string &S,
+ const PrintingPolicy &Policy) const {
+ TypePrinter Printer(Policy);
+ Printer.Print(*this, S);
+}
+
diff --git a/lib/Analysis/AnalysisManager.cpp b/lib/Analysis/AnalysisManager.cpp
deleted file mode 100644
index c2733faa683c..000000000000
--- a/lib/Analysis/AnalysisManager.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-//== AnalysisManager.cpp - Path sensitive analysis data manager ----*- C++ -*-//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements the AnalysisManager class.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/Analysis/PathSensitive/AnalysisManager.h"
-#include "clang/Basic/SourceManager.h"
-
-using namespace clang;
-
-void AnalysisManager::DisplayFunction(Decl *D) {
-
- if (DisplayedFunction)
- return;
-
- DisplayedFunction = true;
-
- // FIXME: Is getCodeDecl() always a named decl?
- if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) {
- const NamedDecl *ND = cast<NamedDecl>(D);
- SourceManager &SM = getASTContext().getSourceManager();
- (llvm::errs() << "ANALYZE: "
- << SM.getPresumedLoc(ND->getLocation()).getFilename()
- << ' ' << ND->getNameAsString() << '\n').flush();
- }
-}
-
diff --git a/lib/Analysis/ArrayBoundChecker.cpp b/lib/Analysis/ArrayBoundChecker.cpp
new file mode 100644
index 000000000000..549a22bec172
--- /dev/null
+++ b/lib/Analysis/ArrayBoundChecker.cpp
@@ -0,0 +1,86 @@
+//== ArrayBoundChecker.cpp ------------------------------*- C++ -*--==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines ArrayBoundChecker, which is a path-sensitive check
+// which looks for an out-of-bound array element access.
+//
+//===----------------------------------------------------------------------===//
+
+#include "GRExprEngineInternalChecks.h"
+#include "clang/Analysis/PathSensitive/GRExprEngine.h"
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+
+using namespace clang;
+
+namespace {
+class VISIBILITY_HIDDEN ArrayBoundChecker :
+ public CheckerVisitor<ArrayBoundChecker> {
+ BuiltinBug *BT;
+public:
+ ArrayBoundChecker() : BT(0) {}
+ static void *getTag();
+ void VisitLocation(CheckerContext &C, const Stmt *S, SVal l);
+};
+}
+
+void clang::RegisterArrayBoundChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new ArrayBoundChecker());
+}
+
+void *ArrayBoundChecker::getTag() {
+ static int x = 0; return &x;
+}
+
+void ArrayBoundChecker::VisitLocation(CheckerContext &C, const Stmt *S, SVal l){
+ // Check for out of bound array element access.
+ const MemRegion *R = l.getAsRegion();
+ if (!R)
+ return;
+
+ R = R->StripCasts();
+
+ const ElementRegion *ER = dyn_cast<ElementRegion>(R);
+ if (!ER)
+ return;
+
+ // Get the index of the accessed element.
+ DefinedOrUnknownSVal &Idx = cast<DefinedOrUnknownSVal>(ER->getIndex());
+
+ const GRState *state = C.getState();
+
+ // Get the size of the array.
+ DefinedOrUnknownSVal NumElements
+ = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion());
+
+ const GRState *StInBound = state->AssumeInBound(Idx, NumElements, true);
+ const GRState *StOutBound = state->AssumeInBound(Idx, NumElements, false);
+ if (StOutBound && !StInBound) {
+ ExplodedNode *N = C.GenerateNode(S, StOutBound, true);
+
+ if (!N)
+ return;
+
+ if (!BT)
+ BT = new BuiltinBug("Out-of-bound array access",
+ "Access out-of-bound array element (buffer overflow)");
+
+ // FIXME: It would be nice to eventually make this diagnostic more clear,
+ // e.g., by referencing the original declaration or by saying *why* this
+ // reference is outside the range.
+
+ // Generate a report for this bug.
+ RangedBugReport *report =
+ new RangedBugReport(*BT, BT->getDescription(), N);
+
+ report->addRange(S->getSourceRange());
+
+ C.EmitReport(report);
+ }
+}
diff --git a/lib/Analysis/AttrNonNullChecker.cpp b/lib/Analysis/AttrNonNullChecker.cpp
index 1cf5d0c4af2d..01e1a1fcf69b 100644
--- a/lib/Analysis/AttrNonNullChecker.cpp
+++ b/lib/Analysis/AttrNonNullChecker.cpp
@@ -12,14 +12,28 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/Checkers/AttrNonNullChecker.h"
+#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "GRExprEngineInternalChecks.h"
using namespace clang;
-void *AttrNonNullChecker::getTag() {
- static int x = 0;
- return &x;
+namespace {
+class VISIBILITY_HIDDEN AttrNonNullChecker
+ : public CheckerVisitor<AttrNonNullChecker> {
+ BugType *BT;
+public:
+ AttrNonNullChecker() : BT(0) {}
+ static void *getTag() {
+ static int x = 0;
+ return &x;
+ }
+ void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
+};
+} // end anonymous namespace
+
+void clang::RegisterAttrNonNullChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new AttrNonNullChecker());
}
void AttrNonNullChecker::PreVisitCallExpr(CheckerContext &C,
diff --git a/lib/Analysis/BadCallChecker.cpp b/lib/Analysis/BadCallChecker.cpp
index 33bb5158d2b9..7a7ea188ba59 100644
--- a/lib/Analysis/BadCallChecker.cpp
+++ b/lib/Analysis/BadCallChecker.cpp
@@ -12,14 +12,27 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/Checkers/BadCallChecker.h"
+#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "GRExprEngineInternalChecks.h"
using namespace clang;
-void *BadCallChecker::getTag() {
- static int x = 0;
- return &x;
+namespace {
+class VISIBILITY_HIDDEN BadCallChecker : public CheckerVisitor<BadCallChecker> {
+ BuiltinBug *BT;
+public:
+ BadCallChecker() : BT(0) {}
+ static void *getTag() {
+ static int x = 0;
+ return &x;
+ }
+ void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
+};
+} // end anonymous namespace
+
+void clang::RegisterBadCallChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new BadCallChecker());
}
void BadCallChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
@@ -29,11 +42,11 @@ void BadCallChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
if (L.isUndef() || isa<loc::ConcreteInt>(L)) {
if (ExplodedNode *N = C.GenerateNode(CE, true)) {
if (!BT)
- BT = new BuiltinBug(0, "Invalid function call",
+ BT = new BuiltinBug("Invalid function call",
"Called function pointer is a null or undefined pointer value");
EnhancedBugReport *R =
- new EnhancedBugReport(*BT, BT->getDescription().c_str(), N);
+ new EnhancedBugReport(*BT, BT->getDescription(), N);
R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
bugreporter::GetCalleeExpr(N));
diff --git a/lib/Analysis/BasicObjCFoundationChecks.cpp b/lib/Analysis/BasicObjCFoundationChecks.cpp
index 4781d5ec243e..c2ecfa1f417f 100644
--- a/lib/Analysis/BasicObjCFoundationChecks.cpp
+++ b/lib/Analysis/BasicObjCFoundationChecks.cpp
@@ -384,7 +384,7 @@ bool AuditCFNumberCreate::Audit(ExplodedNode* N,GRStateManager&){
if (!LV)
return false;
- const TypedRegion* R = dyn_cast<TypedRegion>(LV->getBaseRegion());
+ const TypedRegion* R = dyn_cast<TypedRegion>(LV->StripCasts());
if (!R)
return false;
diff --git a/lib/Analysis/BasicStore.cpp b/lib/Analysis/BasicStore.cpp
index 888af9bd57a4..800a76fb0aee 100644
--- a/lib/Analysis/BasicStore.cpp
+++ b/lib/Analysis/BasicStore.cpp
@@ -268,20 +268,6 @@ SValuator::CastResult BasicStoreManager::Retrieve(const GRState *state,
case loc::MemRegionKind: {
const MemRegion* R = cast<loc::MemRegionVal>(loc).getRegion();
- if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
- // Just support void**, void***, intptr_t*, intptr_t**, etc., for now.
- // This is needed to handle OSCompareAndSwapPtr() and friends.
- ASTContext &Ctx = StateMgr.getContext();
- QualType T = ER->getLocationType(Ctx);
-
- if (!isHigherOrderRawPtr(T, Ctx))
- return SValuator::CastResult(state, UnknownVal());
-
- // FIXME: Should check for element 0.
- // Otherwise, strip the element region.
- R = ER->getSuperRegion();
- }
-
if (!(isa<VarRegion>(R) || isa<ObjCIvarRegion>(R)))
return SValuator::CastResult(state, UnknownVal());
@@ -291,7 +277,8 @@ SValuator::CastResult BasicStoreManager::Retrieve(const GRState *state,
if (!Val)
break;
- return CastRetrievedVal(*Val, state, cast<TypedRegion>(R), T);
+ return SValuator::CastResult(state,
+ CastRetrievedVal(*Val, cast<TypedRegion>(R), T));
}
case loc::ConcreteIntKind:
@@ -624,7 +611,7 @@ const GRState *BasicStoreManager::InvalidateRegion(const GRState *state,
const Expr *E,
unsigned Count,
InvalidatedSymbols *IS) {
- R = R->getBaseRegion();
+ R = R->StripCasts();
if (!(isa<VarRegion>(R) || isa<ObjCIvarRegion>(R)))
return state;
diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp
index 03614e83398f..55e5f174cb9f 100644
--- a/lib/Analysis/CFRefCount.cpp
+++ b/lib/Analysis/CFRefCount.cpp
@@ -308,7 +308,234 @@ public:
}
};
+//===----------------------------------------------------------------------===//
+// Reference-counting logic (typestate + counts).
+//===----------------------------------------------------------------------===//
+class VISIBILITY_HIDDEN RefVal {
+public:
+ enum Kind {
+ Owned = 0, // Owning reference.
+ NotOwned, // Reference is not owned by still valid (not freed).
+ Released, // Object has been released.
+ ReturnedOwned, // Returned object passes ownership to caller.
+ ReturnedNotOwned, // Return object does not pass ownership to caller.
+ ERROR_START,
+ ErrorDeallocNotOwned, // -dealloc called on non-owned object.
+ ErrorDeallocGC, // Calling -dealloc with GC enabled.
+ ErrorUseAfterRelease, // Object used after released.
+ ErrorReleaseNotOwned, // Release of an object that was not owned.
+ ERROR_LEAK_START,
+ ErrorLeak, // A memory leak due to excessive reference counts.
+ ErrorLeakReturned, // A memory leak due to the returning method not having
+ // the correct naming conventions.
+ ErrorGCLeakReturned,
+ ErrorOverAutorelease,
+ ErrorReturnedNotOwned
+ };
+
+private:
+ Kind kind;
+ RetEffect::ObjKind okind;
+ unsigned Cnt;
+ unsigned ACnt;
+ QualType T;
+
+ RefVal(Kind k, RetEffect::ObjKind o, unsigned cnt, unsigned acnt, QualType t)
+ : kind(k), okind(o), Cnt(cnt), ACnt(acnt), T(t) {}
+
+ RefVal(Kind k, unsigned cnt = 0)
+ : kind(k), okind(RetEffect::AnyObj), Cnt(cnt), ACnt(0) {}
+
+public:
+ Kind getKind() const { return kind; }
+
+ RetEffect::ObjKind getObjKind() const { return okind; }
+
+ unsigned getCount() const { return Cnt; }
+ unsigned getAutoreleaseCount() const { return ACnt; }
+ unsigned getCombinedCounts() const { return Cnt + ACnt; }
+ void clearCounts() { Cnt = 0; ACnt = 0; }
+ void setCount(unsigned i) { Cnt = i; }
+ void setAutoreleaseCount(unsigned i) { ACnt = i; }
+
+ QualType getType() const { return T; }
+
+ // Useful predicates.
+
+ static bool isError(Kind k) { return k >= ERROR_START; }
+
+ static bool isLeak(Kind k) { return k >= ERROR_LEAK_START; }
+
+ bool isOwned() const {
+ return getKind() == Owned;
+ }
+
+ bool isNotOwned() const {
+ return getKind() == NotOwned;
+ }
+
+ bool isReturnedOwned() const {
+ return getKind() == ReturnedOwned;
+ }
+
+ bool isReturnedNotOwned() const {
+ return getKind() == ReturnedNotOwned;
+ }
+
+ bool isNonLeakError() const {
+ Kind k = getKind();
+ return isError(k) && !isLeak(k);
+ }
+
+ static RefVal makeOwned(RetEffect::ObjKind o, QualType t,
+ unsigned Count = 1) {
+ return RefVal(Owned, o, Count, 0, t);
+ }
+
+ static RefVal makeNotOwned(RetEffect::ObjKind o, QualType t,
+ unsigned Count = 0) {
+ return RefVal(NotOwned, o, Count, 0, t);
+ }
+
+ // Comparison, profiling, and pretty-printing.
+
+ bool operator==(const RefVal& X) const {
+ return kind == X.kind && Cnt == X.Cnt && T == X.T && ACnt == X.ACnt;
+ }
+
+ RefVal operator-(size_t i) const {
+ return RefVal(getKind(), getObjKind(), getCount() - i,
+ getAutoreleaseCount(), getType());
+ }
+
+ RefVal operator+(size_t i) const {
+ return RefVal(getKind(), getObjKind(), getCount() + i,
+ getAutoreleaseCount(), getType());
+ }
+
+ RefVal operator^(Kind k) const {
+ return RefVal(k, getObjKind(), getCount(), getAutoreleaseCount(),
+ getType());
+ }
+
+ RefVal autorelease() const {
+ return RefVal(getKind(), getObjKind(), getCount(), getAutoreleaseCount()+1,
+ getType());
+ }
+
+ void Profile(llvm::FoldingSetNodeID& ID) const {
+ ID.AddInteger((unsigned) kind);
+ ID.AddInteger(Cnt);
+ ID.AddInteger(ACnt);
+ ID.Add(T);
+ }
+
+ void print(llvm::raw_ostream& Out) const;
+};
+
+void RefVal::print(llvm::raw_ostream& Out) const {
+ if (!T.isNull())
+ Out << "Tracked Type:" << T.getAsString() << '\n';
+
+ switch (getKind()) {
+ default: assert(false);
+ case Owned: {
+ Out << "Owned";
+ unsigned cnt = getCount();
+ if (cnt) Out << " (+ " << cnt << ")";
+ break;
+ }
+
+ case NotOwned: {
+ Out << "NotOwned";
+ unsigned cnt = getCount();
+ if (cnt) Out << " (+ " << cnt << ")";
+ break;
+ }
+
+ case ReturnedOwned: {
+ Out << "ReturnedOwned";
+ unsigned cnt = getCount();
+ if (cnt) Out << " (+ " << cnt << ")";
+ break;
+ }
+
+ case ReturnedNotOwned: {
+ Out << "ReturnedNotOwned";
+ unsigned cnt = getCount();
+ if (cnt) Out << " (+ " << cnt << ")";
+ break;
+ }
+
+ case Released:
+ Out << "Released";
+ break;
+
+ case ErrorDeallocGC:
+ Out << "-dealloc (GC)";
+ break;
+
+ case ErrorDeallocNotOwned:
+ Out << "-dealloc (not-owned)";
+ break;
+
+ case ErrorLeak:
+ Out << "Leaked";
+ break;
+
+ case ErrorLeakReturned:
+ Out << "Leaked (Bad naming)";
+ break;
+
+ case ErrorGCLeakReturned:
+ Out << "Leaked (GC-ed at return)";
+ break;
+
+ case ErrorUseAfterRelease:
+ Out << "Use-After-Release [ERROR]";
+ break;
+
+ case ErrorReleaseNotOwned:
+ Out << "Release of Not-Owned [ERROR]";
+ break;
+
+ case RefVal::ErrorOverAutorelease:
+ Out << "Over autoreleased";
+ break;
+
+ case RefVal::ErrorReturnedNotOwned:
+ Out << "Non-owned object returned instead of owned";
+ break;
+ }
+
+ if (ACnt) {
+ Out << " [ARC +" << ACnt << ']';
+ }
+}
+} //end anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// RefBindings - State used to track object reference counts.
+//===----------------------------------------------------------------------===//
+
+typedef llvm::ImmutableMap<SymbolRef, RefVal> RefBindings;
+
+namespace clang {
+ template<>
+ struct GRStateTrait<RefBindings> : public GRStatePartialTrait<RefBindings> {
+ static void* GDMIndex() {
+ static int RefBIndex = 0;
+ return &RefBIndex;
+ }
+ };
+}
+
+//===----------------------------------------------------------------------===//
+// Summaries
+//===----------------------------------------------------------------------===//
+
+namespace {
class VISIBILITY_HIDDEN RetainSummary {
/// Args - an ordered vector of (index, ArgEffect) pairs, where index
/// specifies the argument (starting from 0). This can be sparsely
@@ -757,7 +984,11 @@ public:
RetainSummary* getSummary(FunctionDecl* FD);
- RetainSummary* getInstanceMethodSummary(ObjCMessageExpr* ME,
+ RetainSummary *getInstanceMethodSummary(const ObjCMessageExpr *ME,
+ const GRState *state,
+ const LocationContext *LC);
+
+ RetainSummary* getInstanceMethodSummary(const ObjCMessageExpr* ME,
const ObjCInterfaceDecl* ID) {
return getInstanceMethodSummary(ME->getSelector(), ME->getClassName(),
ID, ME->getMethodDecl(), ME->getType());
@@ -773,7 +1004,7 @@ public:
const ObjCMethodDecl *MD,
QualType RetTy);
- RetainSummary *getClassMethodSummary(ObjCMessageExpr *ME) {
+ RetainSummary *getClassMethodSummary(const ObjCMessageExpr *ME) {
return getClassMethodSummary(ME->getSelector(), ME->getClassName(),
ME->getClassInfo().first,
ME->getMethodDecl(), ME->getType());
@@ -1306,7 +1537,7 @@ RetainSummaryManager::getCommonMethodSummary(const ObjCMethodDecl* MD,
E = MD->param_end(); I != E; ++I, ++i)
if (ParmVarDecl *PD = *I) {
QualType Ty = Ctx.getCanonicalType(PD->getType());
- if (Ty.getUnqualifiedType() == Ctx.VoidPtrTy)
+ if (Ty.getLocalUnqualifiedType() == Ctx.VoidPtrTy)
ScratchArgs = AF.Add(ScratchArgs, i, StopTracking);
}
}
@@ -1350,6 +1581,61 @@ RetainSummaryManager::getCommonMethodSummary(const ObjCMethodDecl* MD,
}
RetainSummary*
+RetainSummaryManager::getInstanceMethodSummary(const ObjCMessageExpr *ME,
+ const GRState *state,
+ const LocationContext *LC) {
+
+ // We need the type-information of the tracked receiver object
+ // Retrieve it from the state.
+ const Expr *Receiver = ME->getReceiver();
+ const ObjCInterfaceDecl* ID = 0;
+
+ // FIXME: Is this really working as expected? There are cases where
+ // we just use the 'ID' from the message expression.
+ SVal receiverV = state->getSValAsScalarOrLoc(Receiver);
+
+ // FIXME: Eventually replace the use of state->get<RefBindings> with
+ // a generic API for reasoning about the Objective-C types of symbolic
+ // objects.
+ if (SymbolRef Sym = receiverV.getAsLocSymbol())
+ if (const RefVal *T = state->get<RefBindings>(Sym))
+ if (const ObjCObjectPointerType* PT =
+ T->getType()->getAs<ObjCObjectPointerType>())
+ ID = PT->getInterfaceDecl();
+
+ // FIXME: this is a hack. This may or may not be the actual method
+ // that is called.
+ if (!ID) {
+ if (const ObjCObjectPointerType *PT =
+ Receiver->getType()->getAs<ObjCObjectPointerType>())
+ ID = PT->getInterfaceDecl();
+ }
+
+ // FIXME: The receiver could be a reference to a class, meaning that
+ // we should use the class method.
+ RetainSummary *Summ = getInstanceMethodSummary(ME, ID);
+
+ // Special-case: are we sending a mesage to "self"?
+ // This is a hack. When we have full-IP this should be removed.
+ if (isa<ObjCMethodDecl>(LC->getDecl())) {
+ if (const loc::MemRegionVal *L = dyn_cast<loc::MemRegionVal>(&receiverV)) {
+ // Get the region associated with 'self'.
+ if (const ImplicitParamDecl *SelfDecl = LC->getSelfDecl()) {
+ SVal SelfVal = state->getSVal(state->getRegion(SelfDecl, LC));
+ if (L->StripCasts() == SelfVal.getAsRegion()) {
+ // Update the summary to make the default argument effect
+ // 'StopTracking'.
+ Summ = copySummary(Summ);
+ Summ->setDefaultArgEffect(StopTracking);
+ }
+ }
+ }
+ }
+
+ return Summ ? Summ : getDefaultSummary();
+}
+
+RetainSummary*
RetainSummaryManager::getInstanceMethodSummary(Selector S,
IdentifierInfo *ClsName,
const ObjCInterfaceDecl* ID,
@@ -1569,230 +1855,6 @@ void RetainSummaryManager::InitializeMethodSummaries() {
}
//===----------------------------------------------------------------------===//
-// Reference-counting logic (typestate + counts).
-//===----------------------------------------------------------------------===//
-
-namespace {
-
-class VISIBILITY_HIDDEN RefVal {
-public:
- enum Kind {
- Owned = 0, // Owning reference.
- NotOwned, // Reference is not owned by still valid (not freed).
- Released, // Object has been released.
- ReturnedOwned, // Returned object passes ownership to caller.
- ReturnedNotOwned, // Return object does not pass ownership to caller.
- ERROR_START,
- ErrorDeallocNotOwned, // -dealloc called on non-owned object.
- ErrorDeallocGC, // Calling -dealloc with GC enabled.
- ErrorUseAfterRelease, // Object used after released.
- ErrorReleaseNotOwned, // Release of an object that was not owned.
- ERROR_LEAK_START,
- ErrorLeak, // A memory leak due to excessive reference counts.
- ErrorLeakReturned, // A memory leak due to the returning method not having
- // the correct naming conventions.
- ErrorGCLeakReturned,
- ErrorOverAutorelease,
- ErrorReturnedNotOwned
- };
-
-private:
- Kind kind;
- RetEffect::ObjKind okind;
- unsigned Cnt;
- unsigned ACnt;
- QualType T;
-
- RefVal(Kind k, RetEffect::ObjKind o, unsigned cnt, unsigned acnt, QualType t)
- : kind(k), okind(o), Cnt(cnt), ACnt(acnt), T(t) {}
-
- RefVal(Kind k, unsigned cnt = 0)
- : kind(k), okind(RetEffect::AnyObj), Cnt(cnt), ACnt(0) {}
-
-public:
- Kind getKind() const { return kind; }
-
- RetEffect::ObjKind getObjKind() const { return okind; }
-
- unsigned getCount() const { return Cnt; }
- unsigned getAutoreleaseCount() const { return ACnt; }
- unsigned getCombinedCounts() const { return Cnt + ACnt; }
- void clearCounts() { Cnt = 0; ACnt = 0; }
- void setCount(unsigned i) { Cnt = i; }
- void setAutoreleaseCount(unsigned i) { ACnt = i; }
-
- QualType getType() const { return T; }
-
- // Useful predicates.
-
- static bool isError(Kind k) { return k >= ERROR_START; }
-
- static bool isLeak(Kind k) { return k >= ERROR_LEAK_START; }
-
- bool isOwned() const {
- return getKind() == Owned;
- }
-
- bool isNotOwned() const {
- return getKind() == NotOwned;
- }
-
- bool isReturnedOwned() const {
- return getKind() == ReturnedOwned;
- }
-
- bool isReturnedNotOwned() const {
- return getKind() == ReturnedNotOwned;
- }
-
- bool isNonLeakError() const {
- Kind k = getKind();
- return isError(k) && !isLeak(k);
- }
-
- static RefVal makeOwned(RetEffect::ObjKind o, QualType t,
- unsigned Count = 1) {
- return RefVal(Owned, o, Count, 0, t);
- }
-
- static RefVal makeNotOwned(RetEffect::ObjKind o, QualType t,
- unsigned Count = 0) {
- return RefVal(NotOwned, o, Count, 0, t);
- }
-
- // Comparison, profiling, and pretty-printing.
-
- bool operator==(const RefVal& X) const {
- return kind == X.kind && Cnt == X.Cnt && T == X.T && ACnt == X.ACnt;
- }
-
- RefVal operator-(size_t i) const {
- return RefVal(getKind(), getObjKind(), getCount() - i,
- getAutoreleaseCount(), getType());
- }
-
- RefVal operator+(size_t i) const {
- return RefVal(getKind(), getObjKind(), getCount() + i,
- getAutoreleaseCount(), getType());
- }
-
- RefVal operator^(Kind k) const {
- return RefVal(k, getObjKind(), getCount(), getAutoreleaseCount(),
- getType());
- }
-
- RefVal autorelease() const {
- return RefVal(getKind(), getObjKind(), getCount(), getAutoreleaseCount()+1,
- getType());
- }
-
- void Profile(llvm::FoldingSetNodeID& ID) const {
- ID.AddInteger((unsigned) kind);
- ID.AddInteger(Cnt);
- ID.AddInteger(ACnt);
- ID.Add(T);
- }
-
- void print(llvm::raw_ostream& Out) const;
-};
-
-void RefVal::print(llvm::raw_ostream& Out) const {
- if (!T.isNull())
- Out << "Tracked Type:" << T.getAsString() << '\n';
-
- switch (getKind()) {
- default: assert(false);
- case Owned: {
- Out << "Owned";
- unsigned cnt = getCount();
- if (cnt) Out << " (+ " << cnt << ")";
- break;
- }
-
- case NotOwned: {
- Out << "NotOwned";
- unsigned cnt = getCount();
- if (cnt) Out << " (+ " << cnt << ")";
- break;
- }
-
- case ReturnedOwned: {
- Out << "ReturnedOwned";
- unsigned cnt = getCount();
- if (cnt) Out << " (+ " << cnt << ")";
- break;
- }
-
- case ReturnedNotOwned: {
- Out << "ReturnedNotOwned";
- unsigned cnt = getCount();
- if (cnt) Out << " (+ " << cnt << ")";
- break;
- }
-
- case Released:
- Out << "Released";
- break;
-
- case ErrorDeallocGC:
- Out << "-dealloc (GC)";
- break;
-
- case ErrorDeallocNotOwned:
- Out << "-dealloc (not-owned)";
- break;
-
- case ErrorLeak:
- Out << "Leaked";
- break;
-
- case ErrorLeakReturned:
- Out << "Leaked (Bad naming)";
- break;
-
- case ErrorGCLeakReturned:
- Out << "Leaked (GC-ed at return)";
- break;
-
- case ErrorUseAfterRelease:
- Out << "Use-After-Release [ERROR]";
- break;
-
- case ErrorReleaseNotOwned:
- Out << "Release of Not-Owned [ERROR]";
- break;
-
- case RefVal::ErrorOverAutorelease:
- Out << "Over autoreleased";
- break;
-
- case RefVal::ErrorReturnedNotOwned:
- Out << "Non-owned object returned instead of owned";
- break;
- }
-
- if (ACnt) {
- Out << " [ARC +" << ACnt << ']';
- }
-}
-
-} // end anonymous namespace
-
-//===----------------------------------------------------------------------===//
-// RefBindings - State used to track object reference counts.
-//===----------------------------------------------------------------------===//
-
-typedef llvm::ImmutableMap<SymbolRef, RefVal> RefBindings;
-static int RefBIndex = 0;
-
-namespace clang {
- template<>
- struct GRStateTrait<RefBindings> : public GRStatePartialTrait<RefBindings> {
- static inline void* GDMIndex() { return &RefBIndex; }
- };
-}
-
-//===----------------------------------------------------------------------===//
// AutoreleaseBindings - State used to track objects in autorelease pools.
//===----------------------------------------------------------------------===//
@@ -3004,69 +3066,14 @@ void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet& Dst,
GRStmtNodeBuilder& Builder,
ObjCMessageExpr* ME,
ExplodedNode* Pred) {
- RetainSummary* Summ = 0;
-
- if (Expr* Receiver = ME->getReceiver()) {
- // We need the type-information of the tracked receiver object
- // Retrieve it from the state.
- const ObjCInterfaceDecl* ID = 0;
-
- // FIXME: Wouldn't it be great if this code could be reduced? It's just
- // a chain of lookups.
- // FIXME: Is this really working as expected? There are cases where
- // we just use the 'ID' from the message expression.
- const GRState* St = Builder.GetState(Pred);
- SVal V = St->getSValAsScalarOrLoc(Receiver);
-
- SymbolRef Sym = V.getAsLocSymbol();
-
- if (Sym) {
- if (const RefVal* T = St->get<RefBindings>(Sym)) {
- if (const ObjCObjectPointerType* PT =
- T->getType()->getAs<ObjCObjectPointerType>())
- ID = PT->getInterfaceDecl();
- }
- }
-
- // FIXME: this is a hack. This may or may not be the actual method
- // that is called.
- if (!ID) {
- if (const ObjCObjectPointerType *PT =
- Receiver->getType()->getAs<ObjCObjectPointerType>())
- ID = PT->getInterfaceDecl();
- }
-
- // FIXME: The receiver could be a reference to a class, meaning that
- // we should use the class method.
- Summ = Summaries.getInstanceMethodSummary(ME, ID);
-
- // Special-case: are we sending a mesage to "self"?
- // This is a hack. When we have full-IP this should be removed.
- if (isa<ObjCMethodDecl>(Pred->getLocationContext()->getDecl())) {
- if (Expr* Receiver = ME->getReceiver()) {
- SVal X = St->getSValAsScalarOrLoc(Receiver);
- if (loc::MemRegionVal* L = dyn_cast<loc::MemRegionVal>(&X)) {
- // Get the region associated with 'self'.
- const LocationContext *LC = Pred->getLocationContext();
- if (const ImplicitParamDecl *SelfDecl = LC->getSelfDecl()) {
- SVal SelfVal = St->getSVal(St->getRegion(SelfDecl, LC));
- if (L->getBaseRegion() == SelfVal.getAsRegion()) {
- // Update the summary to make the default argument effect
- // 'StopTracking'.
- Summ = Summaries.copySummary(Summ);
- Summ->setDefaultArgEffect(StopTracking);
- }
- }
- }
- }
- }
- }
- else
- Summ = Summaries.getClassMethodSummary(ME);
-
- if (!Summ)
- Summ = Summaries.getDefaultSummary();
+
+ RetainSummary *Summ =
+ ME->getReceiver()
+ ? Summaries.getInstanceMethodSummary(ME, Builder.GetState(Pred),
+ Pred->getLocationContext())
+ : Summaries.getClassMethodSummary(ME);
+ assert(Summ && "RetainSummary is null");
EvalSummary(Dst, Eng, Builder, ME, ME->getReceiver(), *Summ,
ME->arg_begin(), ME->arg_end(), Pred);
}
diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt
index cd4697f2f324..8e8c1e7b25ed 100644
--- a/lib/Analysis/CMakeLists.txt
+++ b/lib/Analysis/CMakeLists.txt
@@ -2,7 +2,7 @@ set(LLVM_NO_RTTI 1)
add_clang_library(clangAnalysis
AnalysisContext.cpp
- AnalysisManager.cpp
+ ArrayBoundChecker.cpp
AttrNonNullChecker.cpp
BadCallChecker.cpp
BasicConstraintManager.cpp
@@ -15,27 +15,39 @@ add_clang_library(clangAnalysis
CFRefCount.cpp
CallGraph.cpp
CallInliner.cpp
+ CastToStructChecker.cpp
CheckDeadStores.cpp
CheckObjCDealloc.cpp
CheckObjCInstMethSignature.cpp
CheckObjCUnusedIVars.cpp
CheckSecuritySyntaxOnly.cpp
+ CheckSizeofPointer.cpp
DereferenceChecker.cpp
DivZeroChecker.cpp
Environment.cpp
ExplodedGraph.cpp
+ FixedAddressChecker.cpp
GRBlockCounter.cpp
GRCoreEngine.cpp
GRExprEngine.cpp
+ GRExprEngineExperimentalChecks.cpp
GRExprEngineInternalChecks.cpp
GRState.cpp
LiveVariables.cpp
+ MallocChecker.cpp
+ ManagerRegistry.cpp
MemRegion.cpp
NSAutoreleasePoolChecker.cpp
NSErrorChecker.cpp
PathDiagnostic.cpp
+ PointerArithChecker.cpp
+ PointerSubChecker.cpp
+ PthreadLockChecker.cpp
RangeConstraintManager.cpp
RegionStore.cpp
+ ReturnPointerRangeChecker.cpp
+ ReturnStackAddressChecker.cpp
+ ReturnUndefChecker.cpp
SVals.cpp
SValuator.cpp
SimpleConstraintManager.cpp
@@ -43,10 +55,11 @@ add_clang_library(clangAnalysis
Store.cpp
SymbolManager.cpp
UndefinedArgChecker.cpp
+ UndefinedArraySubscriptChecker.cpp
UndefinedAssignmentChecker.cpp
UninitializedValues.cpp
- ValueManager.cpp
VLASizeChecker.cpp
+ ValueManager.cpp
)
add_dependencies(clangAnalysis ClangDiagnosticAnalysis)
diff --git a/lib/Analysis/CallGraph.cpp b/lib/Analysis/CallGraph.cpp
index 17dc0685f82f..06e3317691e3 100644
--- a/lib/Analysis/CallGraph.cpp
+++ b/lib/Analysis/CallGraph.cpp
@@ -117,7 +117,7 @@ void CallGraph::print(llvm::raw_ostream &os) {
<< " calls:\n";
for (CallGraphNode::iterator CI = I->second->begin(),
CE = I->second->end(); CI != CE; ++CI) {
- os << " " << CI->second->getName().c_str();
+ os << " " << CI->second->getName();
}
os << '\n';
}
diff --git a/lib/Analysis/CastToStructChecker.cpp b/lib/Analysis/CastToStructChecker.cpp
new file mode 100644
index 000000000000..ccd4a3333e22
--- /dev/null
+++ b/lib/Analysis/CastToStructChecker.cpp
@@ -0,0 +1,77 @@
+//=== CastToStructChecker.cpp - Fixed address usage checker ----*- C++ -*--===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This files defines CastToStructChecker, a builtin checker that checks for
+// assignment of a fixed address to a pointer.
+// This check corresponds to CWE-588.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+#include "GRExprEngineInternalChecks.h"
+
+using namespace clang;
+
+namespace {
+class VISIBILITY_HIDDEN CastToStructChecker
+ : public CheckerVisitor<CastToStructChecker> {
+ BuiltinBug *BT;
+public:
+ CastToStructChecker() : BT(0) {}
+ static void *getTag();
+ void PreVisitCastExpr(CheckerContext &C, const CastExpr *B);
+};
+}
+
+void *CastToStructChecker::getTag() {
+ static int x;
+ return &x;
+}
+
+void CastToStructChecker::PreVisitCastExpr(CheckerContext &C,
+ const CastExpr *CE) {
+ const Expr *E = CE->getSubExpr();
+ ASTContext &Ctx = C.getASTContext();
+ QualType OrigTy = Ctx.getCanonicalType(E->getType());
+ QualType ToTy = Ctx.getCanonicalType(CE->getType());
+
+ PointerType *OrigPTy = dyn_cast<PointerType>(OrigTy.getTypePtr());
+ PointerType *ToPTy = dyn_cast<PointerType>(ToTy.getTypePtr());
+
+ if (!ToPTy || !OrigPTy)
+ return;
+
+ QualType OrigPointeeTy = OrigPTy->getPointeeType();
+ QualType ToPointeeTy = ToPTy->getPointeeType();
+
+ if (!ToPointeeTy->isStructureType())
+ return;
+
+ // We allow cast from void*.
+ if (OrigPointeeTy->isVoidType())
+ return;
+
+ // Now the cast-to-type is struct pointer, the original type is not void*.
+ if (!OrigPointeeTy->isRecordType()) {
+ if (ExplodedNode *N = C.GenerateNode(CE)) {
+ if (!BT)
+ BT = new BuiltinBug("Cast from non-struct type to struct type",
+ "Casting a non-structure type to a structure type "
+ "and accessing a field can lead to memory access "
+ "errors or data corruption.");
+ RangedBugReport *R = new RangedBugReport(*BT,BT->getDescription(), N);
+ R->addRange(CE->getSourceRange());
+ C.EmitReport(R);
+ }
+ }
+}
+
+void clang::RegisterCastToStructChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new CastToStructChecker());
+}
diff --git a/lib/Analysis/CheckSecuritySyntaxOnly.cpp b/lib/Analysis/CheckSecuritySyntaxOnly.cpp
index 9f0d059cb66e..f1b9c2194f8b 100644
--- a/lib/Analysis/CheckSecuritySyntaxOnly.cpp
+++ b/lib/Analysis/CheckSecuritySyntaxOnly.cpp
@@ -23,6 +23,7 @@ namespace {
class VISIBILITY_HIDDEN WalkAST : public StmtVisitor<WalkAST> {
BugReporter &BR;
IdentifierInfo *II_gets;
+ IdentifierInfo *II_getpw;
enum { num_rands = 9 };
IdentifierInfo *II_rand[num_rands];
IdentifierInfo *II_random;
@@ -31,7 +32,7 @@ class VISIBILITY_HIDDEN WalkAST : public StmtVisitor<WalkAST> {
public:
WalkAST(BugReporter &br) : BR(br),
- II_gets(0), II_rand(), II_random(0), II_setid() {}
+ II_gets(0), II_getpw(0), II_rand(), II_random(0), II_setid() {}
// Statement visitor methods.
void VisitCallExpr(CallExpr *CE);
@@ -47,6 +48,7 @@ public:
// Checker-specific methods.
void CheckLoopConditionForFloat(const ForStmt *FS);
void CheckCall_gets(const CallExpr *CE, const FunctionDecl *FD);
+ void CheckCall_getpw(const CallExpr *CE, const FunctionDecl *FD);
void CheckCall_rand(const CallExpr *CE, const FunctionDecl *FD);
void CheckCall_random(const CallExpr *CE, const FunctionDecl *FD);
void CheckUncheckedReturnValue(CallExpr *CE);
@@ -77,6 +79,7 @@ void WalkAST::VisitChildren(Stmt *S) {
void WalkAST::VisitCallExpr(CallExpr *CE) {
if (const FunctionDecl *FD = CE->getDirectCallee()) {
CheckCall_gets(CE, FD);
+ CheckCall_getpw(CE, FD);
CheckCall_rand(CE, FD);
CheckCall_random(CE, FD);
}
@@ -215,22 +218,23 @@ void WalkAST::CheckLoopConditionForFloat(const ForStmt *FS) {
// Check: Any use of 'gets' is insecure.
// Originally: <rdar://problem/6335715>
// Implements (part of): 300-BSI (buildsecurityin.us-cert.gov)
+// CWE-242: Use of Inherently Dangerous Function
//===----------------------------------------------------------------------===//
void WalkAST::CheckCall_gets(const CallExpr *CE, const FunctionDecl *FD) {
if (FD->getIdentifier() != GetIdentifier(II_gets, "gets"))
return;
- const FunctionProtoType *FTP = dyn_cast<FunctionProtoType>(FD->getType());
- if (!FTP)
+ const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FD->getType());
+ if (!FPT)
return;
// Verify that the function takes a single argument.
- if (FTP->getNumArgs() != 1)
+ if (FPT->getNumArgs() != 1)
return;
// Is the argument a 'char*'?
- const PointerType *PT = dyn_cast<PointerType>(FTP->getArgType(0));
+ const PointerType *PT = dyn_cast<PointerType>(FPT->getArgType(0));
if (!PT)
return;
@@ -247,6 +251,44 @@ void WalkAST::CheckCall_gets(const CallExpr *CE, const FunctionDecl *FD) {
}
//===----------------------------------------------------------------------===//
+// Check: Any use of 'getpwd' is insecure.
+// CWE-477: Use of Obsolete Functions
+//===----------------------------------------------------------------------===//
+
+void WalkAST::CheckCall_getpw(const CallExpr *CE, const FunctionDecl *FD) {
+ if (FD->getIdentifier() != GetIdentifier(II_getpw, "getpw"))
+ return;
+
+ const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(FD->getType());
+ if (!FPT)
+ return;
+
+ // Verify that the function takes two arguments.
+ if (FPT->getNumArgs() != 2)
+ return;
+
+ // Verify the first argument type is integer.
+ if (!FPT->getArgType(0)->isIntegerType())
+ return;
+
+ // Verify the second argument type is char*.
+ const PointerType *PT = dyn_cast<PointerType>(FPT->getArgType(1));
+ if (!PT)
+ return;
+
+ if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
+ return;
+
+ // Issue a warning.
+ SourceRange R = CE->getCallee()->getSourceRange();
+ BR.EmitBasicReport("Potential buffer overflow in call to 'getpw'",
+ "Security",
+ "The getpw() function is dangerous as it may overflow the "
+ "provided buffer. It is obsoleted by getpwuid().",
+ CE->getLocStart(), &R, 1);
+}
+
+//===----------------------------------------------------------------------===//
// Check: Linear congruent random number generators should not be used
// Originally: <rdar://problem/63371000>
// CWE-338: Use of cryptographically weak prng
diff --git a/lib/Analysis/CheckSizeofPointer.cpp b/lib/Analysis/CheckSizeofPointer.cpp
new file mode 100644
index 000000000000..174beefbca45
--- /dev/null
+++ b/lib/Analysis/CheckSizeofPointer.cpp
@@ -0,0 +1,72 @@
+//==- CheckSizeofPointer.cpp - Check for sizeof on pointers ------*- C++ -*-==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a check for unintended use of sizeof() on pointer
+// expressions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/Analysis/LocalCheckers.h"
+#include "llvm/Support/Compiler.h"
+
+using namespace clang;
+
+namespace {
+class VISIBILITY_HIDDEN WalkAST : public StmtVisitor<WalkAST> {
+ BugReporter &BR;
+
+public:
+ WalkAST(BugReporter &br) : BR(br) {}
+ void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E);
+ void VisitStmt(Stmt *S) { VisitChildren(S); }
+ void VisitChildren(Stmt *S);
+};
+}
+
+void WalkAST::VisitChildren(Stmt *S) {
+ for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I!=E; ++I)
+ if (Stmt *child = *I)
+ Visit(child);
+}
+
+// CWE-467: Use of sizeof() on a Pointer Type
+void WalkAST::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
+ if (!E->isSizeOf())
+ return;
+
+ // If an explicit type is used in the code, usually the coder knows what he is
+ // doing.
+ if (E->isArgumentType())
+ return;
+
+ QualType T = E->getTypeOfArgument();
+ if (T->isPointerType()) {
+
+ // Many false positives have the form 'sizeof *p'. This is reasonable
+ // because people know what they are doing when they intentionally
+ // dereference the pointer.
+ Expr *ArgEx = E->getArgumentExpr();
+ if (!isa<DeclRefExpr>(ArgEx->IgnoreParens()))
+ return;
+
+ SourceRange R = ArgEx->getSourceRange();
+ BR.EmitBasicReport("Potential unintended use of sizeof() on pointer type",
+ "Logic",
+ "The code calls sizeof() on a pointer type. "
+ "This can produce an unexpected result.",
+ E->getLocStart(), &R, 1);
+ }
+}
+
+void clang::CheckSizeofPointer(const Decl *D, BugReporter &BR) {
+ WalkAST walker(BR);
+ walker.Visit(D->getBody());
+}
diff --git a/lib/Analysis/DereferenceChecker.cpp b/lib/Analysis/DereferenceChecker.cpp
index 33c85d507463..c3aa8f3a2879 100644
--- a/lib/Analysis/DereferenceChecker.cpp
+++ b/lib/Analysis/DereferenceChecker.cpp
@@ -13,100 +13,103 @@
//===----------------------------------------------------------------------===//
#include "clang/Analysis/PathSensitive/Checkers/DereferenceChecker.h"
+#include "clang/Analysis/PathSensitive/Checker.h"
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "GRExprEngineInternalChecks.h"
using namespace clang;
-void *NullDerefChecker::getTag() {
- static int x = 0;
- return &x;
-}
-
-ExplodedNode *NullDerefChecker::CheckLocation(const Stmt *S, ExplodedNode *Pred,
- const GRState *state, SVal V,
- GRExprEngine &Eng) {
- Loc *LV = dyn_cast<Loc>(&V);
-
- // If the value is not a location, don't touch the node.
- if (!LV)
- return Pred;
-
- const GRState *NotNullState = state->Assume(*LV, true);
- const GRState *NullState = state->Assume(*LV, false);
+namespace {
+class VISIBILITY_HIDDEN DereferenceChecker : public Checker {
+ BuiltinBug *BT_null;
+ BuiltinBug *BT_undef;
+ llvm::SmallVector<ExplodedNode*, 2> ImplicitNullDerefNodes;
+public:
+ DereferenceChecker() : BT_null(0), BT_undef(0) {}
+ static void *getTag() { static int tag = 0; return &tag; }
+ void VisitLocation(CheckerContext &C, const Stmt *S, SVal location);
- GRStmtNodeBuilder &Builder = Eng.getBuilder();
- BugReporter &BR = Eng.getBugReporter();
-
- // The explicit NULL case.
- if (NullState) {
- // Use the GDM to mark in the state what lval was null.
- const SVal *PersistentLV = Eng.getBasicVals().getPersistentSVal(*LV);
- NullState = NullState->set<GRState::NullDerefTag>(PersistentLV);
-
- ExplodedNode *N = Builder.generateNode(S, NullState, Pred,
- ProgramPoint::PostNullCheckFailedKind);
- if (N) {
- N->markAsSink();
-
- if (!NotNullState) { // Explicit null case.
- if (!BT)
- BT = new BuiltinBug(NULL, "Null dereference",
- "Dereference of null pointer");
-
- EnhancedBugReport *R =
- new EnhancedBugReport(*BT, BT->getDescription().c_str(), N);
-
- R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
- bugreporter::GetDerefExpr(N));
-
- BR.EmitReport(R);
-
- return 0;
- } else // Implicit null case.
- ImplicitNullDerefNodes.push_back(N);
- }
+ std::pair<ExplodedNode * const*, ExplodedNode * const*>
+ getImplicitNodes() const {
+ return std::make_pair(ImplicitNullDerefNodes.data(),
+ ImplicitNullDerefNodes.data() +
+ ImplicitNullDerefNodes.size());
}
-
- if (!NotNullState)
- return 0;
+};
+} // end anonymous namespace
- return Builder.generateNode(S, NotNullState, Pred,
- ProgramPoint::PostLocationChecksSucceedKind);
+void clang::RegisterDereferenceChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new DereferenceChecker());
}
-
-void *UndefDerefChecker::getTag() {
- static int x = 0;
- return &x;
+std::pair<ExplodedNode * const *, ExplodedNode * const *>
+clang::GetImplicitNullDereferences(GRExprEngine &Eng) {
+ DereferenceChecker *checker = Eng.getChecker<DereferenceChecker>();
+ if (!checker)
+ return std::make_pair((ExplodedNode * const *) 0,
+ (ExplodedNode * const *) 0);
+ return checker->getImplicitNodes();
}
-ExplodedNode *UndefDerefChecker::CheckLocation(const Stmt *S,
- ExplodedNode *Pred,
- const GRState *state, SVal V,
- GRExprEngine &Eng) {
- GRStmtNodeBuilder &Builder = Eng.getBuilder();
- BugReporter &BR = Eng.getBugReporter();
-
- if (V.isUndef()) {
- ExplodedNode *N = Builder.generateNode(S, state, Pred,
- ProgramPoint::PostUndefLocationCheckFailedKind);
+void DereferenceChecker::VisitLocation(CheckerContext &C, const Stmt *S,
+ SVal l) {
+ // Check for dereference of an undefined value.
+ if (l.isUndef()) {
+ ExplodedNode *N = C.GenerateNode(S, true);
if (N) {
- N->markAsSink();
+ if (!BT_undef)
+ BT_undef = new BuiltinBug("Dereference of undefined pointer value");
+
+ EnhancedBugReport *report =
+ new EnhancedBugReport(*BT_undef, BT_undef->getDescription(), N);
+ report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
+ bugreporter::GetDerefExpr(N));
+ C.EmitReport(report);
+ }
+ return;
+ }
+
+ DefinedOrUnknownSVal location = cast<DefinedOrUnknownSVal>(l);
+
+ // Check for null dereferences.
+ if (!isa<Loc>(location))
+ return;
+
+ const GRState *state = C.getState();
+ const GRState *notNullState, *nullState;
+ llvm::tie(notNullState, nullState) = state->Assume(location);
+
+ // The explicit NULL case.
+ if (nullState) {
+ // Generate an error node.
+ ExplodedNode *N = C.GenerateNode(S, nullState, true);
+ if (N) {
+ if (!notNullState) {
+ // We know that 'location' cannot be non-null. This is what
+ // we call an "explicit" null dereference.
+ if (!BT_null)
+ BT_null = new BuiltinBug("Null pointer dereference",
+ "Dereference of null pointer");
- if (!BT)
- BT = new BuiltinBug(0, "Undefined dereference",
- "Dereference of undefined pointer value");
+ EnhancedBugReport *report =
+ new EnhancedBugReport(*BT_null, BT_null->getDescription(), N);
+ report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
+ bugreporter::GetDerefExpr(N));
+
+ C.EmitReport(report);
+ return;
+ }
- EnhancedBugReport *R =
- new EnhancedBugReport(*BT, BT->getDescription().c_str(), N);
- R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
- bugreporter::GetDerefExpr(N));
- BR.EmitReport(R);
+ // Otherwise, we have the case where the location could either be
+ // null or not-null. Record the error node as an "implicit" null
+ // dereference.
+ ImplicitNullDerefNodes.push_back(N);
}
- return 0;
}
-
- return Pred;
+
+ // From this point forward, we know that the location is not null.
+ assert(notNullState);
+ C.addTransition(state != nullState ? C.GenerateNode(S, notNullState) :
+ C.getPredecessor());
}
-
diff --git a/lib/Analysis/DivZeroChecker.cpp b/lib/Analysis/DivZeroChecker.cpp
index 9c2359f3b075..a8630f10088e 100644
--- a/lib/Analysis/DivZeroChecker.cpp
+++ b/lib/Analysis/DivZeroChecker.cpp
@@ -12,10 +12,25 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/Checkers/DivZeroChecker.h"
+#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+#include "GRExprEngineInternalChecks.h"
using namespace clang;
+namespace {
+class VISIBILITY_HIDDEN DivZeroChecker : public CheckerVisitor<DivZeroChecker> {
+ BuiltinBug *BT;
+public:
+ DivZeroChecker() : BT(0) {}
+ static void *getTag();
+ void PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B);
+};
+} // end anonymous namespace
+
+void clang::RegisterDivZeroChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new DivZeroChecker());
+}
+
void *DivZeroChecker::getTag() {
static int x;
return &x;
@@ -50,10 +65,10 @@ void DivZeroChecker::PreVisitBinaryOperator(CheckerContext &C,
if (stateZero && !stateNotZero) {
if (ExplodedNode *N = C.GenerateNode(B, stateZero, true)) {
if (!BT)
- BT = new BuiltinBug(0, "Division by zero");
+ BT = new BuiltinBug("Division by zero");
EnhancedBugReport *R =
- new EnhancedBugReport(*BT, BT->getDescription().c_str(), N);
+ new EnhancedBugReport(*BT, BT->getDescription(), N);
R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
bugreporter::GetDenomExpr(N));
diff --git a/lib/Analysis/ExplodedGraph.cpp b/lib/Analysis/ExplodedGraph.cpp
index 0dc81a4225a8..3b339ffc0dfe 100644
--- a/lib/Analysis/ExplodedGraph.cpp
+++ b/lib/Analysis/ExplodedGraph.cpp
@@ -273,7 +273,7 @@ ExplodedGraph::TrimInternal(const ExplodedNode* const* BeginSources,
ExplodedNode*
InterExplodedGraphMap::getMappedNode(const ExplodedNode* N) const {
- llvm::DenseMap<const ExplodedNode*, ExplodedNode*>::iterator I =
+ llvm::DenseMap<const ExplodedNode*, ExplodedNode*>::const_iterator I =
M.find(N);
return I == M.end() ? 0 : I->second;
diff --git a/lib/Analysis/FixedAddressChecker.cpp b/lib/Analysis/FixedAddressChecker.cpp
new file mode 100644
index 000000000000..80096dcb70d0
--- /dev/null
+++ b/lib/Analysis/FixedAddressChecker.cpp
@@ -0,0 +1,70 @@
+//=== FixedAddressChecker.cpp - Fixed address usage checker ----*- C++ -*--===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This files defines FixedAddressChecker, a builtin checker that checks for
+// assignment of a fixed address to a pointer.
+// This check corresponds to CWE-587.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+#include "GRExprEngineInternalChecks.h"
+
+using namespace clang;
+
+namespace {
+class VISIBILITY_HIDDEN FixedAddressChecker
+ : public CheckerVisitor<FixedAddressChecker> {
+ BuiltinBug *BT;
+public:
+ FixedAddressChecker() : BT(0) {}
+ static void *getTag();
+ void PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B);
+};
+}
+
+void *FixedAddressChecker::getTag() {
+ static int x;
+ return &x;
+}
+
+void FixedAddressChecker::PreVisitBinaryOperator(CheckerContext &C,
+ const BinaryOperator *B) {
+ // Using a fixed address is not portable because that address will probably
+ // not be valid in all environments or platforms.
+
+ if (B->getOpcode() != BinaryOperator::Assign)
+ return;
+
+ QualType T = B->getType();
+ if (!T->isPointerType())
+ return;
+
+ const GRState *state = C.getState();
+
+ SVal RV = state->getSVal(B->getRHS());
+
+ if (!RV.isConstant() || RV.isZeroConstant())
+ return;
+
+ if (ExplodedNode *N = C.GenerateNode(B)) {
+ if (!BT)
+ BT = new BuiltinBug("Use fixed address",
+ "Using a fixed address is not portable because that "
+ "address will probably not be valid in all "
+ "environments or platforms.");
+ RangedBugReport *R = new RangedBugReport(*BT, BT->getDescription(), N);
+ R->addRange(B->getRHS()->getSourceRange());
+ C.EmitReport(R);
+ }
+}
+
+void clang::RegisterFixedAddressChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new FixedAddressChecker());
+}
diff --git a/lib/Analysis/GRCoreEngine.cpp b/lib/Analysis/GRCoreEngine.cpp
index 87472472fdee..b99ba4f257ef 100644
--- a/lib/Analysis/GRCoreEngine.cpp
+++ b/lib/Analysis/GRCoreEngine.cpp
@@ -418,51 +418,38 @@ void GRStmtNodeBuilder::GenerateAutoTransition(ExplodedNode* N) {
Eng.WList->Enqueue(Succ, B, Idx+1);
}
-static inline PostStmt GetPostLoc(const Stmt* S, ProgramPoint::Kind K,
- const LocationContext *L, const void *tag) {
+static ProgramPoint GetProgramPoint(const Stmt *S, ProgramPoint::Kind K,
+ const LocationContext *LC, const void *tag){
switch (K) {
default:
- assert(false && "Invalid PostXXXKind.");
-
+ assert(false && "Unhandled ProgramPoint kind");
+ case ProgramPoint::PreStmtKind:
+ return PreStmt(S, LC, tag);
case ProgramPoint::PostStmtKind:
- return PostStmt(S, L, tag);
-
+ return PostStmt(S, LC, tag);
+ case ProgramPoint::PreLoadKind:
+ return PreLoad(S, LC, tag);
case ProgramPoint::PostLoadKind:
- return PostLoad(S, L, tag);
-
- case ProgramPoint::PostUndefLocationCheckFailedKind:
- return PostUndefLocationCheckFailed(S, L, tag);
-
- case ProgramPoint::PostLocationChecksSucceedKind:
- return PostLocationChecksSucceed(S, L, tag);
-
- case ProgramPoint::PostOutOfBoundsCheckFailedKind:
- return PostOutOfBoundsCheckFailed(S, L, tag);
-
- case ProgramPoint::PostNullCheckFailedKind:
- return PostNullCheckFailed(S, L, tag);
-
+ return PostLoad(S, LC, tag);
+ case ProgramPoint::PreStoreKind:
+ return PreStore(S, LC, tag);
case ProgramPoint::PostStoreKind:
- return PostStore(S, L, tag);
-
+ return PostStore(S, LC, tag);
case ProgramPoint::PostLValueKind:
- return PostLValue(S, L, tag);
-
+ return PostLValue(S, LC, tag);
case ProgramPoint::PostPurgeDeadSymbolsKind:
- return PostPurgeDeadSymbols(S, L, tag);
+ return PostPurgeDeadSymbols(S, LC, tag);
}
}
ExplodedNode*
-GRStmtNodeBuilder::generateNodeInternal(const Stmt* S, const GRState* State,
+GRStmtNodeBuilder::generateNodeInternal(const Stmt* S, const GRState* state,
ExplodedNode* Pred,
ProgramPoint::Kind K,
const void *tag) {
- return K == ProgramPoint::PreStmtKind
- ? generateNodeInternal(PreStmt(S, Pred->getLocationContext(),tag),
- State, Pred)
- : generateNodeInternal(GetPostLoc(S, K, Pred->getLocationContext(), tag),
- State, Pred);
+
+ const ProgramPoint &L = GetProgramPoint(S, K, Pred->getLocationContext(),tag);
+ return generateNodeInternal(L, state, Pred);
}
ExplodedNode*
diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp
index 212fea3a6bcc..26331776141f 100644
--- a/lib/Analysis/GRExprEngine.cpp
+++ b/lib/Analysis/GRExprEngine.cpp
@@ -293,9 +293,7 @@ void GRExprEngine::ProcessStmt(Stmt* S, GRStmtNodeBuilder& builder) {
Builder = &builder;
EntryNode = builder.getLastNode();
- // FIXME: Consolidate.
CurrentStmt = S;
- StateMgr.CurrentStmt = S;
// Set up our simple checks.
if (BatchAuditor)
@@ -320,9 +318,32 @@ void GRExprEngine::ProcessStmt(Stmt* S, GRStmtNodeBuilder& builder) {
SaveAndRestore<bool> OldPurgeDeadSymbols(Builder->PurgingDeadSymbols);
Builder->PurgingDeadSymbols = true;
- getTF().EvalDeadSymbols(Tmp, *this, *Builder, EntryNode, S,
+ // FIXME: This should soon be removed.
+ ExplodedNodeSet Tmp2;
+ getTF().EvalDeadSymbols(Tmp2, *this, *Builder, EntryNode, S,
CleanedState, SymReaper);
+ if (Checkers.empty())
+ Tmp = Tmp2;
+ else {
+ ExplodedNodeSet Tmp3;
+ ExplodedNodeSet *SrcSet = &Tmp2;
+ for (CheckersOrdered::iterator I = Checkers.begin(), E = Checkers.end();
+ I != E; ++I) {
+ ExplodedNodeSet *DstSet = (I+1 == E) ? &Tmp
+ : (SrcSet == &Tmp2) ? &Tmp3
+ : &Tmp2;
+ DstSet->clear();
+ void *tag = I->first;
+ Checker *checker = I->second;
+ for (ExplodedNodeSet::iterator NI = SrcSet->begin(), NE = SrcSet->end();
+ NI != NE; ++NI)
+ checker->GR_EvalDeadSymbols(*DstSet, *Builder, *this, S, *NI,
+ SymReaper, tag);
+ SrcSet = DstSet;
+ }
+ }
+
if (!Builder->BuildSinks && !Builder->HasGeneratedNode)
Tmp.Add(EntryNode);
}
@@ -353,8 +374,6 @@ void GRExprEngine::ProcessStmt(Stmt* S, GRStmtNodeBuilder& builder) {
CleanedState = NULL;
EntryNode = NULL;
- // FIXME: Consolidate.
- StateMgr.CurrentStmt = 0;
CurrentStmt = 0;
Builder = NULL;
@@ -878,6 +897,18 @@ void GRExprEngine::VisitGuardedExpr(Expr* Ex, Expr* L, Expr* R,
MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, X, true));
}
+/// ProcessEndPath - Called by GRCoreEngine. Used to generate end-of-path
+/// nodes when the control reaches the end of a function.
+void GRExprEngine::ProcessEndPath(GREndPathNodeBuilder& builder) {
+ getTF().EvalEndPath(*this, builder);
+ StateMgr.EndPath(builder.getState());
+ for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E;++I){
+ void *tag = I->first;
+ Checker *checker = I->second;
+ checker->EvalEndPath(builder, tag, *this);
+ }
+}
+
/// ProcessSwitch - Called by GRCoreEngine. Used to generate successor
/// nodes by processing the 'effects' of a switch statement.
void GRExprEngine::ProcessSwitch(GRSwitchNodeBuilder& builder) {
@@ -1080,7 +1111,10 @@ void GRExprEngine::VisitArraySubscriptExpr(ArraySubscriptExpr* A,
ExplodedNodeSet Tmp2;
Visit(Idx, *I1, Tmp2); // Evaluate the index.
- for (ExplodedNodeSet::iterator I2=Tmp2.begin(),E2=Tmp2.end();I2!=E2; ++I2) {
+ ExplodedNodeSet Tmp3;
+ CheckerVisit(A, Tmp3, Tmp2, true);
+
+ for (ExplodedNodeSet::iterator I2=Tmp3.begin(),E2=Tmp3.end();I2!=E2; ++I2) {
const GRState* state = GetState(*I2);
SVal V = state->getLValue(A->getType(), state->getSVal(Idx),
state->getSVal(Base));
@@ -1190,112 +1224,87 @@ void GRExprEngine::EvalStore(ExplodedNodeSet& Dst, Expr *AssignE,
assert(Builder && "GRStmtNodeBuilder must be defined.");
// Evaluate the location (checks for bad dereferences).
- Pred = EvalLocation(StoreE, Pred, state, location, tag);
+ ExplodedNodeSet Tmp;
+ EvalLocation(Tmp, StoreE, Pred, state, location, tag, false);
- if (!Pred)
+ if (Tmp.empty())
return;
- assert (!location.isUndef());
- state = GetState(Pred);
+ assert(!location.isUndef());
+ SaveAndRestore<ProgramPoint::Kind> OldSPointKind(Builder->PointKind,
+ ProgramPoint::PostStoreKind);
+ SaveAndRestore<const void*> OldTag(Builder->Tag, tag);
+
// Proceed with the store.
- SaveAndRestore<ProgramPoint::Kind> OldSPointKind(Builder->PointKind);
- SaveAndRestore<const void*> OldTag(Builder->Tag);
- Builder->PointKind = ProgramPoint::PostStoreKind;
- Builder->Tag = tag;
- EvalBind(Dst, AssignE, StoreE, Pred, state, location, Val);
+ for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI)
+ EvalBind(Dst, AssignE, StoreE, *NI, GetState(*NI), location, Val);
}
-void GRExprEngine::EvalLoad(ExplodedNodeSet& Dst, Expr* Ex, ExplodedNode* Pred,
+void GRExprEngine::EvalLoad(ExplodedNodeSet& Dst, Expr *Ex, ExplodedNode* Pred,
const GRState* state, SVal location,
- const void *tag) {
+ const void *tag, QualType LoadTy) {
// Evaluate the location (checks for bad dereferences).
- Pred = EvalLocation(Ex, Pred, state, location, tag);
+ ExplodedNodeSet Tmp;
+ EvalLocation(Tmp, Ex, Pred, state, location, tag, true);
- if (!Pred)
+ if (Tmp.empty())
return;
-
- state = GetState(Pred);
+
+ assert(!location.isUndef());
+
+ SaveAndRestore<ProgramPoint::Kind> OldSPointKind(Builder->PointKind);
+ SaveAndRestore<const void*> OldTag(Builder->Tag);
// Proceed with the load.
- ProgramPoint::Kind K = ProgramPoint::PostLoadKind;
-
- // FIXME: Currently symbolic analysis "generates" new symbols
- // for the contents of values. We need a better approach.
-
- if (location.isUnknown()) {
- // This is important. We must nuke the old binding.
- MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, UnknownVal()),
- K, tag);
- }
- else {
- SVal V = state->getSVal(cast<Loc>(location), Ex->getType());
- MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V), K, tag);
+ for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) {
+ state = GetState(*NI);
+ if (location.isUnknown()) {
+ // This is important. We must nuke the old binding.
+ MakeNode(Dst, Ex, *NI, state->BindExpr(Ex, UnknownVal()),
+ ProgramPoint::PostLoadKind, tag);
+ }
+ else {
+ SVal V = state->getSVal(cast<Loc>(location), LoadTy.isNull() ?
+ Ex->getType() : LoadTy);
+ MakeNode(Dst, Ex, *NI, state->BindExpr(Ex, V), ProgramPoint::PostLoadKind,
+ tag);
+ }
}
}
-ExplodedNode* GRExprEngine::EvalLocation(Stmt* Ex, ExplodedNode* Pred,
- const GRState* state, SVal location,
- const void *tag) {
-
- SaveAndRestore<const void*> OldTag(Builder->Tag);
- Builder->Tag = tag;
+void GRExprEngine::EvalLocation(ExplodedNodeSet &Dst, Stmt *S,
+ ExplodedNode* Pred,
+ const GRState* state, SVal location,
+ const void *tag, bool isLoad) {
- if (location.isUnknown() || Checkers.empty())
- return Pred;
-
-
- for (CheckersOrdered::iterator I=Checkers.begin(), E=Checkers.end(); I!=E;++I)
- {
- Pred = I->second->CheckLocation(Ex, Pred, state, location, *this);
- if (!Pred)
- break;
+ if (location.isUnknown() || Checkers.empty()) {
+ Dst.Add(Pred);
+ return;
}
- return Pred;
-
- // FIXME: Temporarily disable out-of-bounds checking until we make
- // the logic reflect recent changes to CastRegion and friends.
-#if 0
- // Check for out-of-bound array access.
- if (isa<loc::MemRegionVal>(LV)) {
- const MemRegion* R = cast<loc::MemRegionVal>(LV).getRegion();
- if (const ElementRegion* ER = dyn_cast<ElementRegion>(R)) {
- // Get the index of the accessed element.
- SVal Idx = ER->getIndex();
- // Get the extent of the array.
- SVal NumElements = getStoreManager().getSizeInElements(StNotNull,
- ER->getSuperRegion());
-
- const GRState * StInBound = StNotNull->AssumeInBound(Idx, NumElements,
- true);
- const GRState* StOutBound = StNotNull->AssumeInBound(Idx, NumElements,
- false);
-
- if (StOutBound) {
- // Report warning. Make sink node manually.
- ExplodedNode* OOBNode =
- Builder->generateNode(Ex, StOutBound, Pred,
- ProgramPoint::PostOutOfBoundsCheckFailedKind);
-
- if (OOBNode) {
- OOBNode->markAsSink();
-
- if (StInBound)
- ImplicitOOBMemAccesses.insert(OOBNode);
- else
- ExplicitOOBMemAccesses.insert(OOBNode);
- }
- }
-
- if (!StInBound)
- return NULL;
-
- StNotNull = StInBound;
- }
+ ExplodedNodeSet Src, Tmp;
+ Src.Add(Pred);
+ ExplodedNodeSet *PrevSet = &Src;
+
+ for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I)
+ {
+ ExplodedNodeSet *CurrSet = (I+1 == E) ? &Dst
+ : (PrevSet == &Tmp) ? &Src : &Tmp;
+
+ CurrSet->clear();
+ void *tag = I->first;
+ Checker *checker = I->second;
+
+ for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end();
+ NI != NE; ++NI)
+ checker->GR_VisitLocation(*CurrSet, *Builder, *this, S, *NI, state,
+ location, tag, isLoad);
+
+ // Update which NodeSet is the current one.
+ PrevSet = CurrSet;
}
-#endif
}
//===----------------------------------------------------------------------===//
@@ -1311,8 +1320,7 @@ ExplodedNode* GRExprEngine::EvalLocation(Stmt* Ex, ExplodedNode* Pred,
static bool EvalOSAtomicCompareAndSwap(ExplodedNodeSet& Dst,
GRExprEngine& Engine,
GRStmtNodeBuilder& Builder,
- CallExpr* CE, SVal L,
- ExplodedNode* Pred) {
+ CallExpr* CE, ExplodedNode* Pred) {
// Not enough arguments to match OSAtomicCompareAndSwap?
if (CE->getNumArgs() != 3)
@@ -1354,7 +1362,13 @@ static bool EvalOSAtomicCompareAndSwap(ExplodedNodeSet& Dst,
const GRState *state = Pred->getState();
ExplodedNodeSet Tmp;
SVal location = state->getSVal(theValueExpr);
- Engine.EvalLoad(Tmp, theValueExpr, Pred, state, location, OSAtomicLoadTag);
+ // Here we should use the value type of the region as the load type.
+ const MemRegion *R = location.getAsRegion();
+ QualType LoadTy;
+ if (R)
+ LoadTy = cast<TypedRegion>(R)->getValueType(C);
+ Engine.EvalLoad(Tmp, theValueExpr, Pred, state, location, OSAtomicLoadTag,
+ LoadTy);
for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end();
I != E; ++I) {
@@ -1432,7 +1446,7 @@ static bool EvalOSAtomic(ExplodedNodeSet& Dst,
// Check for compare and swap.
if (strncmp(FName, "OSAtomicCompareAndSwap", 22) == 0 ||
strncmp(FName, "objc_atomicCompareAndSwap", 25) == 0)
- return EvalOSAtomicCompareAndSwap(Dst, Engine, Builder, CE, L, Pred);
+ return EvalOSAtomicCompareAndSwap(Dst, Engine, Builder, CE, Pred);
// FIXME: Other atomics.
return false;
@@ -1521,17 +1535,6 @@ bool GRExprEngine::EvalBuiltinFunction(const FunctionDecl *FD, CallExpr *CE,
return false;
}
-void GRExprEngine::EvalCall(ExplodedNodeSet& Dst, CallExpr* CE, SVal L,
- ExplodedNode* Pred) {
- assert (Builder && "GRStmtNodeBuilder must be defined.");
-
- // FIXME: Allow us to chain together transfer functions.
- if (EvalOSAtomic(Dst, *this, *Builder, CE, L, Pred))
- return;
-
- getTF().EvalCall(Dst, *this, *Builder, CE, L, Pred);
-}
-
void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred,
CallExpr::arg_iterator AI,
CallExpr::arg_iterator AE,
@@ -1609,17 +1612,25 @@ void GRExprEngine::VisitCallRec(CallExpr* CE, ExplodedNode* Pred,
continue;
// Dispatch to the plug-in transfer function.
-
- unsigned size = Dst.size();
SaveOr OldHasGen(Builder->HasGeneratedNode);
- EvalCall(Dst, CE, L, *DI);
+ Pred = *DI;
+
+ // Dispatch to transfer function logic to handle the call itself.
+ // FIXME: Allow us to chain together transfer functions.
+ assert(Builder && "GRStmtNodeBuilder must be defined.");
+ ExplodedNodeSet DstTmp;
+
+ if (!EvalOSAtomic(DstTmp, *this, *Builder, CE, L, Pred))
+ getTF().EvalCall(DstTmp, *this, *Builder, CE, L, Pred);
// Handle the case where no nodes where generated. Auto-generate that
// contains the updated state if we aren't generating sinks.
-
- if (!Builder->BuildSinks && Dst.size() == size &&
+ if (!Builder->BuildSinks && DstTmp.empty() &&
!Builder->HasGeneratedNode)
- MakeNode(Dst, CE, *DI, state);
+ MakeNode(DstTmp, CE, Pred, state);
+
+ // Perform the post-condition check of the CallExpr.
+ CheckerVisit(CE, Dst, DstTmp, false);
}
}
@@ -1749,46 +1760,47 @@ void GRExprEngine::VisitObjCForCollectionStmtAux(ObjCForCollectionStmt* S,
ExplodedNode* Pred, ExplodedNodeSet& Dst,
SVal ElementV) {
-
-
- // Get the current state. Use 'EvalLocation' to determine if it is a null
- // pointer, etc.
+ // Check if the location we are writing back to is a null pointer.
Stmt* elem = S->getElement();
-
- Pred = EvalLocation(elem, Pred, GetState(Pred), ElementV);
- if (!Pred)
+ ExplodedNodeSet Tmp;
+ EvalLocation(Tmp, elem, Pred, GetState(Pred), ElementV, NULL, false);
+
+ if (Tmp.empty())
return;
+
+ for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) {
+ Pred = *NI;
+ const GRState *state = GetState(Pred);
+
+ // Handle the case where the container still has elements.
+ SVal TrueV = ValMgr.makeTruthVal(1);
+ const GRState *hasElems = state->BindExpr(S, TrueV);
+
+ // Handle the case where the container has no elements.
+ SVal FalseV = ValMgr.makeTruthVal(0);
+ const GRState *noElems = state->BindExpr(S, FalseV);
+
+ if (loc::MemRegionVal* MV = dyn_cast<loc::MemRegionVal>(&ElementV))
+ if (const TypedRegion* R = dyn_cast<TypedRegion>(MV->getRegion())) {
+ // FIXME: The proper thing to do is to really iterate over the
+ // container. We will do this with dispatch logic to the store.
+ // For now, just 'conjure' up a symbolic value.
+ QualType T = R->getValueType(getContext());
+ assert(Loc::IsLocType(T));
+ unsigned Count = Builder->getCurrentBlockCount();
+ SymbolRef Sym = SymMgr.getConjuredSymbol(elem, T, Count);
+ SVal V = ValMgr.makeLoc(Sym);
+ hasElems = hasElems->bindLoc(ElementV, V);
+
+ // Bind the location to 'nil' on the false branch.
+ SVal nilV = ValMgr.makeIntVal(0, T);
+ noElems = noElems->bindLoc(ElementV, nilV);
+ }
- const GRState *state = GetState(Pred);
-
- // Handle the case where the container still has elements.
- SVal TrueV = ValMgr.makeTruthVal(1);
- const GRState *hasElems = state->BindExpr(S, TrueV);
-
- // Handle the case where the container has no elements.
- SVal FalseV = ValMgr.makeTruthVal(0);
- const GRState *noElems = state->BindExpr(S, FalseV);
-
- if (loc::MemRegionVal* MV = dyn_cast<loc::MemRegionVal>(&ElementV))
- if (const TypedRegion* R = dyn_cast<TypedRegion>(MV->getRegion())) {
- // FIXME: The proper thing to do is to really iterate over the
- // container. We will do this with dispatch logic to the store.
- // For now, just 'conjure' up a symbolic value.
- QualType T = R->getValueType(getContext());
- assert (Loc::IsLocType(T));
- unsigned Count = Builder->getCurrentBlockCount();
- SymbolRef Sym = SymMgr.getConjuredSymbol(elem, T, Count);
- SVal V = ValMgr.makeLoc(Sym);
- hasElems = hasElems->bindLoc(ElementV, V);
-
- // Bind the location to 'nil' on the false branch.
- SVal nilV = ValMgr.makeIntVal(0, T);
- noElems = noElems->bindLoc(ElementV, nilV);
- }
-
- // Create the new nodes.
- MakeNode(Dst, S, Pred, hasElems);
- MakeNode(Dst, S, Pred, noElems);
+ // Create the new nodes.
+ MakeNode(Dst, S, Pred, hasElems);
+ MakeNode(Dst, S, Pred, noElems);
+ }
}
//===----------------------------------------------------------------------===//
@@ -2035,7 +2047,8 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME,
// Transfer functions: Miscellaneous statements.
//===----------------------------------------------------------------------===//
-void GRExprEngine::VisitCast(Expr* CastE, Expr* Ex, ExplodedNode* Pred, ExplodedNodeSet& Dst){
+void GRExprEngine::VisitCast(Expr* CastE, Expr* Ex, ExplodedNode* Pred,
+ ExplodedNodeSet& Dst){
ExplodedNodeSet S1;
QualType T = CastE->getType();
QualType ExTy = Ex->getType();
@@ -2048,16 +2061,18 @@ void GRExprEngine::VisitCast(Expr* CastE, Expr* Ex, ExplodedNode* Pred, Exploded
else
Visit(Ex, Pred, S1);
+ ExplodedNodeSet S2;
+ CheckerVisit(CastE, S2, S1, true);
+
// Check for casting to "void".
if (T->isVoidType()) {
- for (ExplodedNodeSet::iterator I1 = S1.begin(), E1 = S1.end(); I1 != E1; ++I1)
- Dst.Add(*I1);
-
+ for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I)
+ Dst.Add(*I);
return;
}
- for (ExplodedNodeSet::iterator I1 = S1.begin(), E1 = S1.end(); I1 != E1; ++I1) {
- ExplodedNode* N = *I1;
+ 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);
@@ -2107,23 +2122,12 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred,
else
Tmp.Add(Pred);
- for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
+ ExplodedNodeSet Tmp2;
+ CheckerVisit(DS, Tmp2, Tmp, true);
+
+ for (ExplodedNodeSet::iterator I=Tmp2.begin(), E=Tmp2.end(); I!=E; ++I) {
ExplodedNode *N = *I;
- const GRState *state;
-
- for (CheckersOrdered::iterator CI = Checkers.begin(), CE = Checkers.end();
- CI != CE; ++CI) {
- state = GetState(N);
- N = CI->second->CheckType(getContext().getCanonicalType(VD->getType()),
- N, state, DS, *this);
- if (!N)
- break;
- }
-
- if (!N)
- continue;
-
- state = GetState(N);
+ const GRState *state = GetState(N);
// Decls without InitExpr are not initialized explicitly.
const LocationContext *LC = N->getLocationContext();
@@ -2628,63 +2632,37 @@ void GRExprEngine::VisitAsmStmtHelperInputs(AsmStmt* A,
VisitAsmStmtHelperInputs(A, I, E, *NI, Dst);
}
-void GRExprEngine::EvalReturn(ExplodedNodeSet& Dst, ReturnStmt* S,
- ExplodedNode* Pred) {
- assert (Builder && "GRStmtNodeBuilder must be defined.");
-
- unsigned size = Dst.size();
-
- SaveAndRestore<bool> OldSink(Builder->BuildSinks);
- SaveOr OldHasGen(Builder->HasGeneratedNode);
-
- getTF().EvalReturn(Dst, *this, *Builder, S, Pred);
-
- // Handle the case where no nodes where generated.
-
- if (!Builder->BuildSinks && Dst.size() == size && !Builder->HasGeneratedNode)
- MakeNode(Dst, S, Pred, GetState(Pred));
-}
-
-void GRExprEngine::VisitReturnStmt(ReturnStmt* S, ExplodedNode* Pred,
- ExplodedNodeSet& Dst) {
-
- Expr* R = S->getRetValue();
-
- if (!R) {
- EvalReturn(Dst, S, Pred);
- return;
+void GRExprEngine::VisitReturnStmt(ReturnStmt *RS, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+
+ ExplodedNodeSet Src;
+ if (Expr *RetE = RS->getRetValue()) {
+ Visit(RetE, Pred, Src);
}
+ else {
+ Src.Add(Pred);
+ }
+
+ ExplodedNodeSet CheckedSet;
+ CheckerVisit(RS, CheckedSet, Src, true);
+
+ for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end();
+ I != E; ++I) {
- ExplodedNodeSet Tmp;
- Visit(R, Pred, Tmp);
-
- for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) {
- SVal X = (*I)->getState()->getSVal(R);
-
- // Check if we return the address of a stack variable.
- if (isa<loc::MemRegionVal>(X)) {
- // Determine if the value is on the stack.
- const MemRegion* R = cast<loc::MemRegionVal>(&X)->getRegion();
-
- if (R && R->hasStackStorage()) {
- // Create a special node representing the error.
- if (ExplodedNode* N = Builder->generateNode(S, GetState(*I), *I)) {
- N->markAsSink();
- RetsStackAddr.insert(N);
- }
- continue;
- }
- }
- // Check if we return an undefined value.
- else if (X.isUndef()) {
- if (ExplodedNode* N = Builder->generateNode(S, GetState(*I), *I)) {
- N->markAsSink();
- RetsUndef.insert(N);
- }
- continue;
- }
-
- EvalReturn(Dst, S, *I);
+ assert(Builder && "GRStmtNodeBuilder must be defined.");
+
+ Pred = *I;
+ unsigned size = Dst.size();
+
+ SaveAndRestore<bool> OldSink(Builder->BuildSinks);
+ SaveOr OldHasGen(Builder->HasGeneratedNode);
+
+ getTF().EvalReturn(Dst, *this, *Builder, RS, Pred);
+
+ // Handle the case where no nodes where generated.
+ if (!Builder->BuildSinks && Dst.size() == size &&
+ !Builder->HasGeneratedNode)
+ MakeNode(Dst, RS, Pred, GetState(Pred));
}
}
@@ -2878,7 +2856,7 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
//===----------------------------------------------------------------------===//
Checker *GRExprEngine::lookupChecker(void *tag) const {
- CheckerMap::iterator I = CheckerM.find(tag);
+ CheckerMap::const_iterator I = CheckerM.find(tag);
return (I == CheckerM.end()) ? NULL : Checkers[I->second].second;
}
@@ -2898,6 +2876,9 @@ struct VISIBILITY_HIDDEN DOTGraphTraits<ExplodedNode*> :
// work.
static std::string getNodeAttributes(const ExplodedNode* N, void*) {
+#if 0
+ // FIXME: Replace with a general scheme to tell if the node is
+ // an error node.
if (GraphPrintCheckerState->isImplicitNullDeref(N) ||
GraphPrintCheckerState->isExplicitNullDeref(N) ||
GraphPrintCheckerState->isUndefDeref(N) ||
@@ -2907,6 +2888,7 @@ struct VISIBILITY_HIDDEN DOTGraphTraits<ExplodedNode*> :
GraphPrintCheckerState->isBadCall(N) ||
GraphPrintCheckerState->isUndefArg(N))
return "color=\"red\",style=\"filled\"";
+#endif
if (GraphPrintCheckerState->isNoReturnCall(N))
return "color=\"blue\",style=\"filled\"";
@@ -2957,11 +2939,10 @@ struct VISIBILITY_HIDDEN DOTGraphTraits<ExplodedNode*> :
Out << "\\lPostStore\\l";
else if (isa<PostLValue>(Loc))
Out << "\\lPostLValue\\l";
- else if (isa<PostLocationChecksSucceed>(Loc))
- Out << "\\lPostLocationChecksSucceed\\l";
- else if (isa<PostNullCheckFailed>(Loc))
- Out << "\\lPostNullCheckFailed\\l";
+#if 0
+ // FIXME: Replace with a general scheme to determine
+ // the name of the check.
if (GraphPrintCheckerState->isImplicitNullDeref(N))
Out << "\\|Implicit-Null Dereference.\\l";
else if (GraphPrintCheckerState->isExplicitNullDeref(N))
@@ -2978,6 +2959,7 @@ struct VISIBILITY_HIDDEN DOTGraphTraits<ExplodedNode*> :
Out << "\\|Call to NULL/Undefined.";
else if (GraphPrintCheckerState->isUndefArg(N))
Out << "\\|Argument in call is undefined";
+#endif
break;
}
@@ -3039,9 +3021,13 @@ struct VISIBILITY_HIDDEN DOTGraphTraits<ExplodedNode*> :
Out << "\\l";
}
+#if 0
+ // FIXME: Replace with a general scheme to determine
+ // the name of the check.
if (GraphPrintCheckerState->isUndefControlFlow(N)) {
Out << "\\|Control-flow based on\\lUndefined value.\\l";
}
+#endif
}
}
diff --git a/lib/Analysis/GRExprEngineExperimentalChecks.cpp b/lib/Analysis/GRExprEngineExperimentalChecks.cpp
new file mode 100644
index 000000000000..2fb7e9fa482f
--- /dev/null
+++ b/lib/Analysis/GRExprEngineExperimentalChecks.cpp
@@ -0,0 +1,38 @@
+//=-- GRExprEngineExperimentalChecks.h ------------------------------*- C++ -*-=
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines functions to instantiate and register experimental
+// checks in GRExprEngine.
+//
+//===----------------------------------------------------------------------===//
+
+#include "GRExprEngineInternalChecks.h"
+#include "GRExprEngineExperimentalChecks.h"
+#include "clang/Analysis/LocalCheckers.h"
+
+using namespace clang;
+
+void clang::RegisterExperimentalChecks(GRExprEngine &Eng) {
+ // These are checks that never belong as internal checks
+ // within GRExprEngine.
+ RegisterPthreadLockChecker(Eng);
+ RegisterMallocChecker(Eng);
+}
+
+void clang::RegisterExperimentalInternalChecks(GRExprEngine &Eng) {
+ // These are internal checks that should eventually migrate to
+ // RegisterInternalChecks() once they have been further tested.
+
+ // Note that this must be registered after ReturnStackAddresEngsChecker.
+ RegisterReturnPointerRangeChecker(Eng);
+ RegisterPointerSubChecker(Eng);
+ RegisterPointerArithChecker(Eng);
+ RegisterCastToStructChecker(Eng);
+ RegisterArrayBoundChecker(Eng);
+}
diff --git a/lib/Analysis/GRExprEngineExperimentalChecks.h b/lib/Analysis/GRExprEngineExperimentalChecks.h
new file mode 100644
index 000000000000..9a9da32e556e
--- /dev/null
+++ b/lib/Analysis/GRExprEngineExperimentalChecks.h
@@ -0,0 +1,26 @@
+//=-- GRExprEngineExperimentalChecks.h ------------------------------*- C++ -*-=
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines functions to instantiate and register experimental
+// checks in GRExprEngine.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_GREXPRENGINE_EXPERIMENTAL_CHECKS
+#define LLVM_CLANG_GREXPRENGINE_EXPERIMENTAL_CHECKS
+
+namespace clang {
+
+class GRExprEngine;
+
+void RegisterPthreadLockChecker(GRExprEngine &Eng);
+void RegisterMallocChecker(GRExprEngine &Eng);
+
+} // end clang namespace
+#endif
diff --git a/lib/Analysis/GRExprEngineInternalChecks.cpp b/lib/Analysis/GRExprEngineInternalChecks.cpp
index 695f0b02e597..d0f60fde5b1b 100644
--- a/lib/Analysis/GRExprEngineInternalChecks.cpp
+++ b/lib/Analysis/GRExprEngineInternalChecks.cpp
@@ -12,16 +12,11 @@
//
//===----------------------------------------------------------------------===//
+#include "GRExprEngineInternalChecks.h"
#include "clang/Analysis/PathSensitive/BugReporter.h"
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
-#include "clang/Analysis/PathSensitive/Checkers/DereferenceChecker.h"
-#include "clang/Analysis/PathSensitive/Checkers/DivZeroChecker.h"
-#include "clang/Analysis/PathSensitive/Checkers/BadCallChecker.h"
-#include "clang/Analysis/PathSensitive/Checkers/UndefinedArgChecker.h"
#include "clang/Analysis/PathSensitive/Checkers/UndefinedAssignmentChecker.h"
-#include "clang/Analysis/PathSensitive/Checkers/AttrNonNullChecker.h"
-#include "clang/Analysis/PathSensitive/Checkers/VLASizeChecker.h"
#include "clang/Analysis/PathDiagnostic.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/Support/Compiler.h"
@@ -290,79 +285,6 @@ public:
}
};
-class VISIBILITY_HIDDEN RetStack : public BuiltinBug {
-public:
- RetStack(GRExprEngine* eng)
- : BuiltinBug(eng, "Return of address to stack-allocated memory") {}
-
- void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
- for (GRExprEngine::ret_stackaddr_iterator I=Eng.ret_stackaddr_begin(),
- End = Eng.ret_stackaddr_end(); I!=End; ++I) {
-
- ExplodedNode* N = *I;
- const Stmt *S = cast<PostStmt>(N->getLocation()).getStmt();
- const Expr* E = cast<ReturnStmt>(S)->getRetValue();
- assert(E && "Return expression cannot be NULL");
-
- // Get the value associated with E.
- loc::MemRegionVal V = cast<loc::MemRegionVal>(N->getState()->getSVal(E));
-
- // Generate a report for this bug.
- std::string buf;
- llvm::raw_string_ostream os(buf);
- SourceRange R;
-
- // Check if the region is a compound literal.
- if (const CompoundLiteralRegion* CR =
- dyn_cast<CompoundLiteralRegion>(V.getRegion())) {
-
- const CompoundLiteralExpr* CL = CR->getLiteralExpr();
- os << "Address of stack memory associated with a compound literal "
- "declared on line "
- << BR.getSourceManager()
- .getInstantiationLineNumber(CL->getLocStart())
- << " returned.";
-
- R = CL->getSourceRange();
- }
- else if (const AllocaRegion* AR = dyn_cast<AllocaRegion>(V.getRegion())) {
- const Expr* ARE = AR->getExpr();
- SourceLocation L = ARE->getLocStart();
- R = ARE->getSourceRange();
-
- os << "Address of stack memory allocated by call to alloca() on line "
- << BR.getSourceManager().getInstantiationLineNumber(L)
- << " returned.";
- }
- else {
- os << "Address of stack memory associated with local variable '"
- << V.getRegion()->getString() << "' returned.";
- }
-
- RangedBugReport *report = new RangedBugReport(*this, os.str().c_str(), N);
- report->addRange(E->getSourceRange());
- if (R.isValid()) report->addRange(R);
- BR.EmitReport(report);
- }
- }
-};
-
-class VISIBILITY_HIDDEN RetUndef : public BuiltinBug {
-public:
- RetUndef(GRExprEngine* eng) : BuiltinBug(eng, "Garbage return value",
- "Undefined or garbage value returned to caller") {}
-
- void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
- Emit(BR, Eng.ret_undef_begin(), Eng.ret_undef_end());
- }
-
- void registerInitialVisitors(BugReporterContext& BRC,
- const ExplodedNode* N,
- BuiltinBugReport *R) {
- registerTrackNullOrUndefValue(BRC, GetRetValExpr(N), N);
- }
-};
-
class VISIBILITY_HIDDEN UndefBranch : public BuiltinBug {
struct VISIBILITY_HIDDEN FindUndefExpr {
GRStateManager& VM;
@@ -439,17 +361,6 @@ public:
}
};
-class VISIBILITY_HIDDEN OutOfBoundMemoryAccess : public BuiltinBug {
-public:
- OutOfBoundMemoryAccess(GRExprEngine* eng)
- : BuiltinBug(eng,"Out-of-bounds memory access",
- "Load or store into an out-of-bound memory position.") {}
-
- void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
- Emit(BR, Eng.explicit_oob_memacc_begin(), Eng.explicit_oob_memacc_end());
- }
-};
-
} // end clang namespace
//===----------------------------------------------------------------------===//
@@ -464,11 +375,8 @@ void GRExprEngine::RegisterInternalChecks() {
// to 'FlushReports' from BugReporter.
BR.Register(new UndefBranch(this));
BR.Register(new UndefResult(this));
- BR.Register(new RetStack(this));
- BR.Register(new RetUndef(this));
BR.Register(new BadMsgExprArg(this));
BR.Register(new BadReceiver(this));
- BR.Register(new OutOfBoundMemoryAccess(this));
BR.Register(new NilReceiverStructRet(this));
BR.Register(new NilReceiverLargerThanVoidPtrRet(this));
@@ -476,14 +384,17 @@ void GRExprEngine::RegisterInternalChecks() {
// explicitly registered with the BugReporter. If they issue any BugReports,
// their associated BugType will get registered with the BugReporter
// automatically. Note that the check itself is owned by the GRExprEngine
- // object.
- registerCheck(new AttrNonNullChecker());
- registerCheck(new UndefinedArgChecker());
+ // object.
registerCheck(new UndefinedAssignmentChecker());
- registerCheck(new BadCallChecker());
- registerCheck(new DivZeroChecker());
- registerCheck(new UndefDerefChecker());
- registerCheck(new NullDerefChecker());
- registerCheck(new UndefSizedVLAChecker());
- registerCheck(new ZeroSizedVLAChecker());
+
+ RegisterAttrNonNullChecker(*this);
+ RegisterUndefinedArgChecker(*this);
+ RegisterBadCallChecker(*this);
+ RegisterDereferenceChecker(*this);
+ RegisterVLASizeChecker(*this);
+ RegisterDivZeroChecker(*this);
+ RegisterReturnStackAddressChecker(*this);
+ RegisterReturnUndefChecker(*this);
+ RegisterFixedAddressChecker(*this);
+ RegisterUndefinedArraySubscriptChecker(*this);
}
diff --git a/lib/Analysis/GRExprEngineInternalChecks.h b/lib/Analysis/GRExprEngineInternalChecks.h
new file mode 100644
index 000000000000..a9077bf75715
--- /dev/null
+++ b/lib/Analysis/GRExprEngineInternalChecks.h
@@ -0,0 +1,39 @@
+//=-- GRExprEngineInternalChecks.h- Builtin GRExprEngine Checks -----*- C++ -*-=
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines functions to instantiate and register the "built-in"
+// checks in GRExprEngine.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_GREXPRENGINE_INTERNAL_CHECKS
+#define LLVM_CLANG_GREXPRENGINE_INTERNAL_CHECKS
+
+namespace clang {
+
+class GRExprEngine;
+
+void RegisterAttrNonNullChecker(GRExprEngine &Eng);
+void RegisterBadCallChecker(GRExprEngine &Eng);
+void RegisterDereferenceChecker(GRExprEngine &Eng);
+void RegisterDivZeroChecker(GRExprEngine &Eng);
+void RegisterReturnPointerRangeChecker(GRExprEngine &Eng);
+void RegisterReturnStackAddressChecker(GRExprEngine &Eng);
+void RegisterReturnUndefChecker(GRExprEngine &Eng);
+void RegisterVLASizeChecker(GRExprEngine &Eng);
+void RegisterPointerSubChecker(GRExprEngine &Eng);
+void RegisterPointerArithChecker(GRExprEngine &Eng);
+void RegisterFixedAddressChecker(GRExprEngine &Eng);
+void RegisterCastToStructChecker(GRExprEngine &Eng);
+void RegisterUndefinedArgChecker(GRExprEngine &Eng);
+void RegisterArrayBoundChecker(GRExprEngine &Eng);
+void RegisterUndefinedArraySubscriptChecker(GRExprEngine &Eng);
+
+} // end clang namespace
+#endif
diff --git a/lib/Analysis/GRState.cpp b/lib/Analysis/GRState.cpp
index f269824d5477..23ee0b2258bd 100644
--- a/lib/Analysis/GRState.cpp
+++ b/lib/Analysis/GRState.cpp
@@ -332,9 +332,3 @@ bool GRStateManager::isEqual(const GRState* state, const Expr* Ex,
bool GRStateManager::isEqual(const GRState* state, const Expr* Ex, uint64_t x) {
return isEqual(state, Ex, getBasicVals().getValue(x, Ex->getType()));
}
-
-//===----------------------------------------------------------------------===//
-// Persistent values for indexing into the Generic Data Map.
-
-int GRState::NullDerefTag::TagInt = 0;
-
diff --git a/lib/Analysis/LiveVariables.cpp b/lib/Analysis/LiveVariables.cpp
index ae78d1f35ff6..2510445a7f31 100644
--- a/lib/Analysis/LiveVariables.cpp
+++ b/lib/Analysis/LiveVariables.cpp
@@ -18,6 +18,7 @@
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
#include "clang/Analysis/FlowSensitive/DataflowSolver.h"
+#include "clang/Analysis/Support/SaveAndRestore.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Compiler.h"
@@ -301,10 +302,9 @@ void LiveVariables::runOnAllBlocks(const CFG& cfg,
LiveVariables::ObserverTy* Obs,
bool recordStmtValues) {
Solver S(*this);
- ObserverTy* OldObserver = getAnalysisData().Observer;
- getAnalysisData().Observer = Obs;
+ SaveAndRestore<LiveVariables::ObserverTy*> SRObs(getAnalysisData().Observer,
+ Obs);
S.runOnAllBlocks(cfg, recordStmtValues);
- getAnalysisData().Observer = OldObserver;
}
//===----------------------------------------------------------------------===//
@@ -333,7 +333,7 @@ bool LiveVariables::isLive(const Stmt* Loc, const VarDecl* D) const {
// printing liveness state for debugging
//
-void LiveVariables::dumpLiveness(const ValTy& V, SourceManager& SM) const {
+void LiveVariables::dumpLiveness(const ValTy& V, const SourceManager& SM) const {
const AnalysisDataTy& AD = getAnalysisData();
for (AnalysisDataTy::decl_iterator I = AD.begin_decl(),
@@ -345,8 +345,8 @@ void LiveVariables::dumpLiveness(const ValTy& V, SourceManager& SM) const {
}
}
-void LiveVariables::dumpBlockLiveness(SourceManager& M) const {
- for (BlockDataMapTy::iterator I = getBlockDataMap().begin(),
+void LiveVariables::dumpBlockLiveness(const SourceManager& M) const {
+ for (BlockDataMapTy::const_iterator I = getBlockDataMap().begin(),
E = getBlockDataMap().end(); I!=E; ++I) {
llvm::errs() << "\n[ B" << I->first->getBlockID()
<< " (live variables at block exit) ]\n";
diff --git a/lib/Analysis/MallocChecker.cpp b/lib/Analysis/MallocChecker.cpp
new file mode 100644
index 000000000000..93e708332ed7
--- /dev/null
+++ b/lib/Analysis/MallocChecker.cpp
@@ -0,0 +1,218 @@
+//=== MallocChecker.cpp - A malloc/free checker -------------------*- C++ -*--//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines malloc/free checker, which checks for potential memory
+// leaks, double free, and use-after-free problems.
+//
+//===----------------------------------------------------------------------===//
+
+#include "GRExprEngineExperimentalChecks.h"
+#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+#include "clang/Analysis/PathSensitive/GRState.h"
+#include "clang/Analysis/PathSensitive/GRStateTrait.h"
+#include "clang/Analysis/PathSensitive/SymbolManager.h"
+#include "llvm/ADT/ImmutableMap.h"
+using namespace clang;
+
+namespace {
+
+struct RefState {
+ enum Kind { Allocated, Released, Escaped } K;
+ const Stmt *S;
+
+ RefState(Kind k, const Stmt *s) : K(k), S(s) {}
+
+ bool isAllocated() const { return K == Allocated; }
+ bool isReleased() const { return K == Released; }
+ bool isEscaped() const { return K == Escaped; }
+
+ bool operator==(const RefState &X) const {
+ return K == X.K && S == X.S;
+ }
+
+ static RefState getAllocated(const Stmt *s) { return RefState(Allocated, s); }
+ static RefState getReleased(const Stmt *s) { return RefState(Released, s); }
+ static RefState getEscaped(const Stmt *s) { return RefState(Escaped, s); }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.AddInteger(K);
+ ID.AddPointer(S);
+ }
+};
+
+class VISIBILITY_HIDDEN RegionState {};
+
+class VISIBILITY_HIDDEN MallocChecker : public CheckerVisitor<MallocChecker> {
+ BuiltinBug *BT_DoubleFree;
+ BuiltinBug *BT_Leak;
+ IdentifierInfo *II_malloc;
+ IdentifierInfo *II_free;
+
+public:
+ MallocChecker() : BT_DoubleFree(0), BT_Leak(0), II_malloc(0), II_free(0) {}
+ static void *getTag();
+ void PostVisitCallExpr(CheckerContext &C, const CallExpr *CE);
+ void EvalDeadSymbols(CheckerContext &C,const Stmt *S,SymbolReaper &SymReaper);
+ void EvalEndPath(GREndPathNodeBuilder &B, void *tag, GRExprEngine &Eng);
+ void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S);
+private:
+ void MallocMem(CheckerContext &C, const CallExpr *CE);
+ void FreeMem(CheckerContext &C, const CallExpr *CE);
+};
+}
+
+namespace clang {
+ template <>
+ struct GRStateTrait<RegionState>
+ : public GRStatePartialTrait<llvm::ImmutableMap<SymbolRef, RefState> > {
+ static void *GDMIndex() { return MallocChecker::getTag(); }
+ };
+}
+
+void clang::RegisterMallocChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new MallocChecker());
+}
+
+void *MallocChecker::getTag() {
+ static int x;
+ return &x;
+}
+
+void MallocChecker::PostVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
+ const FunctionDecl *FD = CE->getDirectCallee();
+ if (!FD)
+ return;
+
+ ASTContext &Ctx = C.getASTContext();
+ if (!II_malloc)
+ II_malloc = &Ctx.Idents.get("malloc");
+ if (!II_free)
+ II_free = &Ctx.Idents.get("free");
+
+ if (FD->getIdentifier() == II_malloc) {
+ MallocMem(C, CE);
+ return;
+ }
+
+ if (FD->getIdentifier() == II_free) {
+ FreeMem(C, CE);
+ return;
+ }
+}
+
+void MallocChecker::MallocMem(CheckerContext &C, const CallExpr *CE) {
+ const GRState *state = C.getState();
+ SVal CallVal = state->getSVal(CE);
+ SymbolRef Sym = CallVal.getAsLocSymbol();
+ assert(Sym);
+ // Set the symbol's state to Allocated.
+ const GRState *AllocState
+ = state->set<RegionState>(Sym, RefState::getAllocated(CE));
+ C.addTransition(C.GenerateNode(CE, AllocState));
+}
+
+void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) {
+ const GRState *state = C.getState();
+ SVal ArgVal = state->getSVal(CE->getArg(0));
+ SymbolRef Sym = ArgVal.getAsLocSymbol();
+ assert(Sym);
+
+ const RefState *RS = state->get<RegionState>(Sym);
+ assert(RS);
+
+ // Check double free.
+ if (RS->isReleased()) {
+ ExplodedNode *N = C.GenerateNode(CE, true);
+ if (N) {
+ if (!BT_DoubleFree)
+ BT_DoubleFree = new BuiltinBug("Double free",
+ "Try to free a memory block that has been released");
+ // FIXME: should find where it's freed last time.
+ BugReport *R = new BugReport(*BT_DoubleFree,
+ BT_DoubleFree->getDescription(), N);
+ C.EmitReport(R);
+ }
+ return;
+ }
+
+ // Normal free.
+ const GRState *FreedState
+ = state->set<RegionState>(Sym, RefState::getReleased(CE));
+ C.addTransition(C.GenerateNode(CE, FreedState));
+}
+
+void MallocChecker::EvalDeadSymbols(CheckerContext &C, const Stmt *S,
+ SymbolReaper &SymReaper) {
+ for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(),
+ E = SymReaper.dead_end(); I != E; ++I) {
+ SymbolRef Sym = *I;
+ const GRState *state = C.getState();
+ const RefState *RS = state->get<RegionState>(Sym);
+ if (!RS)
+ return;
+
+ if (RS->isAllocated()) {
+ ExplodedNode *N = C.GenerateNode(S, true);
+ if (N) {
+ if (!BT_Leak)
+ BT_Leak = new BuiltinBug("Memory leak",
+ "Allocated memory never released. Potential memory leak.");
+ // FIXME: where it is allocated.
+ BugReport *R = new BugReport(*BT_Leak, BT_Leak->getDescription(), N);
+ C.EmitReport(R);
+ }
+ }
+ }
+}
+
+void MallocChecker::EvalEndPath(GREndPathNodeBuilder &B, void *tag,
+ GRExprEngine &Eng) {
+ const GRState *state = B.getState();
+ typedef llvm::ImmutableMap<SymbolRef, RefState> SymMap;
+ SymMap M = state->get<RegionState>();
+
+ for (SymMap::iterator I = M.begin(), E = M.end(); I != E; ++I) {
+ RefState RS = I->second;
+ if (RS.isAllocated()) {
+ ExplodedNode *N = B.generateNode(state, tag, B.getPredecessor());
+ if (N) {
+ if (!BT_Leak)
+ BT_Leak = new BuiltinBug("Memory leak",
+ "Allocated memory never released. Potential memory leak.");
+ BugReport *R = new BugReport(*BT_Leak, BT_Leak->getDescription(), N);
+ Eng.getBugReporter().EmitReport(R);
+ }
+ }
+ }
+}
+
+void MallocChecker::PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S) {
+ const Expr *RetE = S->getRetValue();
+ if (!RetE)
+ return;
+
+ const GRState *state = C.getState();
+
+ SymbolRef Sym = state->getSVal(RetE).getAsSymbol();
+
+ if (!Sym)
+ return;
+
+ const RefState *RS = state->get<RegionState>(Sym);
+ if (!RS)
+ return;
+
+ // FIXME: check other cases.
+ if (RS->isAllocated())
+ state = state->set<RegionState>(Sym, RefState::getEscaped(S));
+
+ ExplodedNode *N = C.GenerateNode(S, state);
+ if (N)
+ C.addTransition(N);
+}
diff --git a/lib/Frontend/ManagerRegistry.cpp b/lib/Analysis/ManagerRegistry.cpp
index 79f1e8178e10..8943db2a2343 100644
--- a/lib/Frontend/ManagerRegistry.cpp
+++ b/lib/Analysis/ManagerRegistry.cpp
@@ -11,7 +11,7 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Frontend/ManagerRegistry.h"
+#include "clang/Analysis/ManagerRegistry.h"
using namespace clang;
diff --git a/lib/Analysis/MemRegion.cpp b/lib/Analysis/MemRegion.cpp
index 353e63240294..8c0b85c0c729 100644
--- a/lib/Analysis/MemRegion.cpp
+++ b/lib/Analysis/MemRegion.cpp
@@ -378,11 +378,29 @@ bool MemRegion::hasGlobalsOrParametersStorage() const {
return false;
}
+// getBaseRegion strips away all elements and fields, and get the base region
+// of them.
+const MemRegion *MemRegion::getBaseRegion() const {
+ const MemRegion *R = this;
+ while (true) {
+ if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
+ R = ER->getSuperRegion();
+ continue;
+ }
+ if (const FieldRegion *FR = dyn_cast<FieldRegion>(R)) {
+ R = FR->getSuperRegion();
+ continue;
+ }
+ break;
+ }
+ return R;
+}
+
//===----------------------------------------------------------------------===//
// View handling.
//===----------------------------------------------------------------------===//
-const MemRegion *MemRegion::getBaseRegion() const {
+const MemRegion *MemRegion::StripCasts() const {
const MemRegion *R = this;
while (true) {
if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
diff --git a/lib/Analysis/NSErrorChecker.cpp b/lib/Analysis/NSErrorChecker.cpp
index 307686ff57b3..93b617b115d9 100644
--- a/lib/Analysis/NSErrorChecker.cpp
+++ b/lib/Analysis/NSErrorChecker.cpp
@@ -209,15 +209,12 @@ void NSErrorChecker::CheckParamDeref(const VarDecl *Param,
return;
// Iterate over the implicit-null dereferences.
- NullDerefChecker *Checker = Eng.getChecker<NullDerefChecker>();
- assert(Checker && "NullDerefChecker not exist.");
- for (NullDerefChecker::iterator I = Checker->implicit_nodes_begin(),
- E = Checker->implicit_nodes_end(); I != E; ++I) {
-
+ ExplodedNode *const* I, *const* E;
+ llvm::tie(I, E) = GetImplicitNullDereferences(Eng);
+ for ( ; I != E; ++I) {
const GRState *state = (*I)->getState();
- const SVal* X = state->get<GRState::NullDerefTag>();
-
- if (!X || X->getAsSymbol() != ParamSym)
+ SVal location = state->getSVal((*I)->getLocationAs<StmtPoint>()->getStmt());
+ if (location.getAsSymbol() != ParamSym)
continue;
// Emit an error.
diff --git a/lib/Analysis/PointerArithChecker.cpp b/lib/Analysis/PointerArithChecker.cpp
new file mode 100644
index 000000000000..93823484e1d0
--- /dev/null
+++ b/lib/Analysis/PointerArithChecker.cpp
@@ -0,0 +1,71 @@
+//=== PointerArithChecker.cpp - Pointer arithmetic checker -----*- C++ -*--===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This files defines PointerArithChecker, a builtin checker that checks for
+// pointer arithmetic on locations other than array elements.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+#include "GRExprEngineInternalChecks.h"
+
+using namespace clang;
+
+namespace {
+class VISIBILITY_HIDDEN PointerArithChecker
+ : public CheckerVisitor<PointerArithChecker> {
+ BuiltinBug *BT;
+public:
+ PointerArithChecker() : BT(0) {}
+ static void *getTag();
+ void PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B);
+};
+}
+
+void *PointerArithChecker::getTag() {
+ static int x;
+ return &x;
+}
+
+void PointerArithChecker::PreVisitBinaryOperator(CheckerContext &C,
+ const BinaryOperator *B) {
+ if (B->getOpcode() != BinaryOperator::Sub &&
+ B->getOpcode() != BinaryOperator::Add)
+ return;
+
+ const GRState *state = C.getState();
+ SVal LV = state->getSVal(B->getLHS());
+ SVal RV = state->getSVal(B->getRHS());
+
+ const MemRegion *LR = LV.getAsRegion();
+
+ if (!LR || !RV.isConstant())
+ return;
+
+ // If pointer arithmetic is done on variables of non-array type, this often
+ // means behavior rely on memory organization, which is dangerous.
+ if (isa<VarRegion>(LR) || isa<CodeTextRegion>(LR) ||
+ isa<CompoundLiteralRegion>(LR)) {
+
+ if (ExplodedNode *N = C.GenerateNode(B)) {
+ if (!BT)
+ BT = new BuiltinBug("Dangerous pointer arithmetic",
+ "Pointer arithmetic done on non-array variables "
+ "means reliance on memory layout, which is "
+ "dangerous.");
+ RangedBugReport *R = new RangedBugReport(*BT, BT->getDescription(), N);
+ R->addRange(B->getSourceRange());
+ C.EmitReport(R);
+ }
+ }
+}
+
+void clang::RegisterPointerArithChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new PointerArithChecker());
+}
diff --git a/lib/Analysis/PointerSubChecker.cpp b/lib/Analysis/PointerSubChecker.cpp
new file mode 100644
index 000000000000..4c7906f4beba
--- /dev/null
+++ b/lib/Analysis/PointerSubChecker.cpp
@@ -0,0 +1,77 @@
+//=== PointerSubChecker.cpp - Pointer subtraction checker ------*- C++ -*--===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This files defines PointerSubChecker, a builtin checker that checks for
+// pointer subtractions on two pointers pointing to different memory chunks.
+// This check corresponds to CWE-469.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+#include "GRExprEngineInternalChecks.h"
+
+using namespace clang;
+
+namespace {
+class VISIBILITY_HIDDEN PointerSubChecker
+ : public CheckerVisitor<PointerSubChecker> {
+ BuiltinBug *BT;
+public:
+ PointerSubChecker() : BT(0) {}
+ static void *getTag();
+ void PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B);
+};
+}
+
+void *PointerSubChecker::getTag() {
+ static int x;
+ return &x;
+}
+
+void PointerSubChecker::PreVisitBinaryOperator(CheckerContext &C,
+ const BinaryOperator *B) {
+ // When doing pointer subtraction, if the two pointers do not point to the
+ // same memory chunk, emit a warning.
+ if (B->getOpcode() != BinaryOperator::Sub)
+ return;
+
+ const GRState *state = C.getState();
+ SVal LV = state->getSVal(B->getLHS());
+ SVal RV = state->getSVal(B->getRHS());
+
+ const MemRegion *LR = LV.getAsRegion();
+ const MemRegion *RR = RV.getAsRegion();
+
+ if (!(LR && RR))
+ return;
+
+ const MemRegion *BaseLR = LR->getBaseRegion();
+ const MemRegion *BaseRR = RR->getBaseRegion();
+
+ if (BaseLR == BaseRR)
+ return;
+
+ // Allow arithmetic on different symbolic regions.
+ if (isa<SymbolicRegion>(BaseLR) || isa<SymbolicRegion>(BaseRR))
+ return;
+
+ if (ExplodedNode *N = C.GenerateNode(B)) {
+ if (!BT)
+ BT = new BuiltinBug("Pointer subtraction",
+ "Subtraction of two pointers that do not point to "
+ "the same memory chunk may cause incorrect result.");
+ RangedBugReport *R = new RangedBugReport(*BT, BT->getDescription(), N);
+ R->addRange(B->getSourceRange());
+ C.EmitReport(R);
+ }
+}
+
+void clang::RegisterPointerSubChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new PointerSubChecker());
+}
diff --git a/lib/Analysis/PthreadLockChecker.cpp b/lib/Analysis/PthreadLockChecker.cpp
new file mode 100644
index 000000000000..66206616b008
--- /dev/null
+++ b/lib/Analysis/PthreadLockChecker.cpp
@@ -0,0 +1,141 @@
+//===--- PthreadLockChecker.h - Undefined arguments checker ----*- C++ -*--===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines PthreadLockChecker, a simple lock -> unlock checker. Eventually
+// this shouldn't be registered with GRExprEngineInternalChecks.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Analysis/PathSensitive/GRStateTrait.h"
+#include "GRExprEngineExperimentalChecks.h"
+#include "llvm/ADT/ImmutableSet.h"
+
+using namespace clang;
+
+namespace {
+class VISIBILITY_HIDDEN PthreadLockChecker
+ : public CheckerVisitor<PthreadLockChecker> {
+ BugType *BT;
+public:
+ PthreadLockChecker() : BT(0) {}
+ static void *getTag() {
+ static int x = 0;
+ return &x;
+ }
+ void PostVisitCallExpr(CheckerContext &C, const CallExpr *CE);
+
+ void AcquireLock(CheckerContext &C, const CallExpr *CE,
+ SVal lock, bool isTryLock);
+
+ void ReleaseLock(CheckerContext &C, const CallExpr *CE,
+ SVal lock);
+
+};
+} // end anonymous namespace
+
+// GDM Entry for tracking lock state.
+namespace { class VISIBILITY_HIDDEN LockSet {}; }
+namespace clang {
+template <> struct GRStateTrait<LockSet> :
+ public GRStatePartialTrait<llvm::ImmutableSet<const MemRegion*> > {
+ static void* GDMIndex() { return PthreadLockChecker::getTag(); }
+};
+} // end clang namespace
+
+void clang::RegisterPthreadLockChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new PthreadLockChecker());
+}
+
+
+void PthreadLockChecker::PostVisitCallExpr(CheckerContext &C,
+ const CallExpr *CE) {
+ const GRState *state = C.getState();
+ const Expr *Callee = CE->getCallee();
+ const CodeTextRegion *R =
+ dyn_cast_or_null<CodeTextRegion>(state->getSVal(Callee).getAsRegion());
+
+ if (!R)
+ return;
+
+ llvm::StringRef FName = R->getDecl()->getName();
+
+ if (FName == "pthread_mutex_lock") {
+ if (CE->getNumArgs() != 1)
+ return;
+ AcquireLock(C, CE, state->getSVal(CE->getArg(0)), false);
+ }
+ else if (FName == "pthread_mutex_trylock") {
+ if (CE->getNumArgs() != 1)
+ return;
+ AcquireLock(C, CE, state->getSVal(CE->getArg(0)), true);
+ }
+ else if (FName == "pthread_mutex_unlock") {
+ if (CE->getNumArgs() != 1)
+ return;
+ ReleaseLock(C, CE, state->getSVal(CE->getArg(0)));
+ }
+}
+
+void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE,
+ SVal lock, bool isTryLock) {
+
+ const MemRegion *lockR = lock.getAsRegion();
+ if (!lockR)
+ return;
+
+ const GRState *state = C.getState();
+
+ SVal X = state->getSVal(CE);
+ if (X.isUnknownOrUndef())
+ return;
+
+ DefinedSVal retVal = cast<DefinedSVal>(X);
+ const GRState *lockSucc = state;
+
+ if (isTryLock) {
+ // Bifurcate the state, and allow a mode where the lock acquisition fails.
+ const GRState *lockFail;
+ llvm::tie(lockFail, lockSucc) = state->Assume(retVal);
+ assert(lockFail && lockSucc);
+ C.addTransition(C.GenerateNode(CE, lockFail));
+ }
+ else {
+ // Assume that the return value was 0.
+ lockSucc = state->Assume(retVal, false);
+ assert(lockSucc);
+ }
+
+ // Record that the lock was acquired.
+ lockSucc = lockSucc->add<LockSet>(lockR);
+
+ C.addTransition(lockSucc != state ? C.GenerateNode(CE, lockSucc) :
+ C.getPredecessor());
+}
+
+void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE,
+ SVal lock) {
+
+ const MemRegion *lockR = lock.getAsRegion();
+ if (!lockR)
+ return;
+
+ const GRState *state = C.getState();
+
+ // Record that the lock was released.
+ // FIXME: Handle unlocking locks that were never acquired. This may
+ // require IPA for wrappers.
+ const GRState *unlockState = state->remove<LockSet>(lockR);
+
+ if (state == unlockState)
+ return;
+
+ C.addTransition(C.GenerateNode(CE, unlockState));
+}
diff --git a/lib/Analysis/RangeConstraintManager.cpp b/lib/Analysis/RangeConstraintManager.cpp
index 73b445e6ab36..f5cae698f924 100644
--- a/lib/Analysis/RangeConstraintManager.cpp
+++ b/lib/Analysis/RangeConstraintManager.cpp
@@ -16,7 +16,7 @@
#include "clang/Analysis/PathSensitive/GRState.h"
#include "clang/Analysis/PathSensitive/GRStateTrait.h"
#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
-#include "clang/Frontend/ManagerRegistry.h"
+#include "clang/Analysis/ManagerRegistry.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include "llvm/ADT/FoldingSet.h"
diff --git a/lib/Analysis/RegionStore.cpp b/lib/Analysis/RegionStore.cpp
index dbf8c42d273e..ae3fa14c2a26 100644
--- a/lib/Analysis/RegionStore.cpp
+++ b/lib/Analysis/RegionStore.cpp
@@ -164,7 +164,7 @@ public:
~RegionStoreSubRegionMap() {}
bool iterSubRegions(const MemRegion* Parent, Visitor& V) const {
- Map::iterator I = M.find(Parent);
+ Map::const_iterator I = M.find(Parent);
if (I == M.end())
return true;
@@ -360,7 +360,8 @@ public:
//===------------------------------------------------------------------===//
const GRState *setExtent(const GRState *state, const MemRegion* R, SVal Extent);
- SVal getSizeInElements(const GRState *state, const MemRegion* R);
+ DefinedOrUnknownSVal getSizeInElements(const GRState *state,
+ const MemRegion* R);
//===------------------------------------------------------------------===//
// Utility methods.
@@ -461,7 +462,7 @@ const GRState *RegionStoreManager::InvalidateRegion(const GRState *state,
ASTContext& Ctx = StateMgr.getContext();
// Strip away casts.
- R = R->getBaseRegion();
+ R = R->StripCasts();
// Get the mapping of regions -> subregions.
llvm::OwningPtr<RegionStoreSubRegionMap>
@@ -696,8 +697,8 @@ SVal RegionStoreManager::getLValueElement(QualType elementType, SVal Offset,
// Extents for regions.
//===----------------------------------------------------------------------===//
-SVal RegionStoreManager::getSizeInElements(const GRState *state,
- const MemRegion *R) {
+DefinedOrUnknownSVal RegionStoreManager::getSizeInElements(const GRState *state,
+ const MemRegion *R) {
switch (R->getKind()) {
case MemRegion::MemSpaceRegionKind:
@@ -1028,16 +1029,20 @@ RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) {
return SValuator::CastResult(state, UnknownVal());
if (const FieldRegion* FR = dyn_cast<FieldRegion>(R))
- return CastRetrievedVal(RetrieveField(state, FR), state, FR, T);
+ return SValuator::CastResult(state,
+ CastRetrievedVal(RetrieveField(state, FR), FR, T));
if (const ElementRegion* ER = dyn_cast<ElementRegion>(R))
- return CastRetrievedVal(RetrieveElement(state, ER), state, ER, T);
+ return SValuator::CastResult(state,
+ CastRetrievedVal(RetrieveElement(state, ER), ER, T));
if (const ObjCIvarRegion *IVR = dyn_cast<ObjCIvarRegion>(R))
- return CastRetrievedVal(RetrieveObjCIvar(state, IVR), state, IVR, T);
+ return SValuator::CastResult(state,
+ CastRetrievedVal(RetrieveObjCIvar(state, IVR), IVR, T));
if (const VarRegion *VR = dyn_cast<VarRegion>(R))
- return CastRetrievedVal(RetrieveVar(state, VR), state, VR, T);
+ return SValuator::CastResult(state,
+ CastRetrievedVal(RetrieveVar(state, VR), VR, T));
RegionBindings B = GetRegionBindings(state->getStore());
RegionBindings::data_type* V = B.lookup(R);
@@ -1109,7 +1114,7 @@ SVal RegionStoreManager::RetrieveElement(const GRState* state,
// FIXME: Handle loads from strings where the literal is treated as
// an integer, e.g., *((unsigned int*)"hello")
ASTContext &Ctx = getContext();
- QualType T = StrR->getValueType(Ctx)->getAs<ArrayType>()->getElementType();
+ QualType T = Ctx.getAsArrayType(StrR->getValueType(Ctx))->getElementType();
if (T != Ctx.getCanonicalType(R->getElementType()))
return UnknownVal();
diff --git a/lib/Analysis/ReturnPointerRangeChecker.cpp b/lib/Analysis/ReturnPointerRangeChecker.cpp
new file mode 100644
index 000000000000..44887b2625da
--- /dev/null
+++ b/lib/Analysis/ReturnPointerRangeChecker.cpp
@@ -0,0 +1,97 @@
+//== ReturnPointerRangeChecker.cpp ------------------------------*- C++ -*--==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines ReturnPointerRangeChecker, which is a path-sensitive check
+// which looks for an out-of-bound pointer being returned to callers.
+//
+//===----------------------------------------------------------------------===//
+
+#include "GRExprEngineInternalChecks.h"
+#include "clang/Analysis/PathSensitive/GRExprEngine.h"
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+
+using namespace clang;
+
+namespace {
+class VISIBILITY_HIDDEN ReturnPointerRangeChecker :
+ public CheckerVisitor<ReturnPointerRangeChecker> {
+ BuiltinBug *BT;
+public:
+ ReturnPointerRangeChecker() : BT(0) {}
+ static void *getTag();
+ void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *RS);
+};
+}
+
+void clang::RegisterReturnPointerRangeChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new ReturnPointerRangeChecker());
+}
+
+void *ReturnPointerRangeChecker::getTag() {
+ static int x = 0; return &x;
+}
+
+void ReturnPointerRangeChecker::PreVisitReturnStmt(CheckerContext &C,
+ const ReturnStmt *RS) {
+ const GRState *state = C.getState();
+
+ const Expr *RetE = RS->getRetValue();
+ if (!RetE)
+ return;
+
+ SVal V = state->getSVal(RetE);
+ const MemRegion *R = V.getAsRegion();
+ if (!R)
+ return;
+
+ R = R->StripCasts();
+ if (!R)
+ return;
+
+ const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(R);
+ if (!ER)
+ return;
+
+ DefinedOrUnknownSVal &Idx = cast<DefinedOrUnknownSVal>(ER->getIndex());
+
+ // FIXME: All of this out-of-bounds checking should eventually be refactored
+ // into a common place.
+
+ DefinedOrUnknownSVal NumElements
+ = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion());
+
+ const GRState *StInBound = state->AssumeInBound(Idx, NumElements, true);
+ const GRState *StOutBound = state->AssumeInBound(Idx, NumElements, false);
+ if (StOutBound && !StInBound) {
+ ExplodedNode *N = C.GenerateNode(RS, StOutBound, true);
+
+ if (!N)
+ return;
+
+ // FIXME: This bug correspond to CWE-466. Eventually we should have bug
+ // types explicitly reference such exploit categories (when applicable).
+ if (!BT)
+ BT = new BuiltinBug("Return of pointer value outside of expected range",
+ "Returned pointer value points outside the original object "
+ "(potential buffer overflow)");
+
+ // FIXME: It would be nice to eventually make this diagnostic more clear,
+ // e.g., by referencing the original declaration or by saying *why* this
+ // reference is outside the range.
+
+ // Generate a report for this bug.
+ RangedBugReport *report =
+ new RangedBugReport(*BT, BT->getDescription(), N);
+
+ report->addRange(RetE->getSourceRange());
+
+ C.EmitReport(report);
+ }
+}
diff --git a/lib/Analysis/ReturnStackAddressChecker.cpp b/lib/Analysis/ReturnStackAddressChecker.cpp
new file mode 100644
index 000000000000..e4be8712d09b
--- /dev/null
+++ b/lib/Analysis/ReturnStackAddressChecker.cpp
@@ -0,0 +1,97 @@
+//== ReturnStackAddressChecker.cpp ------------------------------*- C++ -*--==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines ReturnStackAddressChecker, which is a path-sensitive
+// check which looks for the addresses of stack variables being returned to
+// callers.
+//
+//===----------------------------------------------------------------------===//
+
+#include "GRExprEngineInternalChecks.h"
+#include "clang/Analysis/PathSensitive/GRExprEngine.h"
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+#include "llvm/ADT/SmallString.h"
+
+using namespace clang;
+
+namespace {
+class VISIBILITY_HIDDEN ReturnStackAddressChecker :
+ public CheckerVisitor<ReturnStackAddressChecker> {
+ BuiltinBug *BT;
+public:
+ ReturnStackAddressChecker() : BT(0) {}
+ static void *getTag();
+ void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *RS);
+};
+}
+
+void clang::RegisterReturnStackAddressChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new ReturnStackAddressChecker());
+}
+
+void *ReturnStackAddressChecker::getTag() {
+ static int x = 0; return &x;
+}
+
+void ReturnStackAddressChecker::PreVisitReturnStmt(CheckerContext &C,
+ const ReturnStmt *RS) {
+
+ const Expr *RetE = RS->getRetValue();
+ if (!RetE)
+ return;
+
+ SVal V = C.getState()->getSVal(RetE);
+ const MemRegion *R = V.getAsRegion();
+
+ if (!R || !R->hasStackStorage())
+ return;
+
+ ExplodedNode *N = C.GenerateNode(RS, C.getState(), true);
+
+ if (!N)
+ return;
+
+ if (!BT)
+ BT = new BuiltinBug("Return of address to stack-allocated memory");
+
+ // Generate a report for this bug.
+ llvm::SmallString<100> buf;
+ llvm::raw_svector_ostream os(buf);
+ SourceRange range;
+
+ // Check if the region is a compound literal.
+ if (const CompoundLiteralRegion* CR = dyn_cast<CompoundLiteralRegion>(R)) {
+ const CompoundLiteralExpr* CL = CR->getLiteralExpr();
+ os << "Address of stack memory associated with a compound literal "
+ "declared on line "
+ << C.getSourceManager().getInstantiationLineNumber(CL->getLocStart())
+ << " returned to caller";
+ range = CL->getSourceRange();
+ }
+ else if (const AllocaRegion* AR = dyn_cast<AllocaRegion>(R)) {
+ const Expr* ARE = AR->getExpr();
+ SourceLocation L = ARE->getLocStart();
+ range = ARE->getSourceRange();
+ os << "Address of stack memory allocated by call to alloca() on line "
+ << C.getSourceManager().getInstantiationLineNumber(L)
+ << " returned to caller";
+ }
+ else {
+ os << "Address of stack memory associated with local variable '"
+ << R->getString() << "' returned.";
+ }
+
+ RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
+ report->addRange(RS->getSourceRange());
+ if (range.isValid())
+ report->addRange(range);
+
+ C.EmitReport(report);
+}
diff --git a/lib/Analysis/ReturnUndefChecker.cpp b/lib/Analysis/ReturnUndefChecker.cpp
new file mode 100644
index 000000000000..796c7608c86d
--- /dev/null
+++ b/lib/Analysis/ReturnUndefChecker.cpp
@@ -0,0 +1,68 @@
+//== ReturnUndefChecker.cpp -------------------------------------*- C++ -*--==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines ReturnUndefChecker, which is a path-sensitive
+// check which looks for undefined or garbage values being returned to the
+// caller.
+//
+//===----------------------------------------------------------------------===//
+
+#include "GRExprEngineInternalChecks.h"
+#include "clang/Analysis/PathSensitive/GRExprEngine.h"
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+#include "llvm/ADT/SmallString.h"
+
+using namespace clang;
+
+namespace {
+class VISIBILITY_HIDDEN ReturnUndefChecker :
+ public CheckerVisitor<ReturnUndefChecker> {
+ BuiltinBug *BT;
+public:
+ ReturnUndefChecker() : BT(0) {}
+ static void *getTag();
+ void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *RS);
+};
+}
+
+void clang::RegisterReturnUndefChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new ReturnUndefChecker());
+}
+
+void *ReturnUndefChecker::getTag() {
+ static int x = 0; return &x;
+}
+
+void ReturnUndefChecker::PreVisitReturnStmt(CheckerContext &C,
+ const ReturnStmt *RS) {
+
+ const Expr *RetE = RS->getRetValue();
+ if (!RetE)
+ return;
+
+ if (!C.getState()->getSVal(RetE).isUndef())
+ return;
+
+ ExplodedNode *N = C.GenerateNode(RS, C.getState(), true);
+
+ if (!N)
+ return;
+
+ if (!BT)
+ BT = new BuiltinBug("Garbage return value",
+ "Undefined or garbage value returned to caller");
+
+ EnhancedBugReport *report =
+ new EnhancedBugReport(*BT, BT->getDescription(), N);
+
+ report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, RetE);
+
+ C.EmitReport(report);
+}
diff --git a/lib/Analysis/SVals.cpp b/lib/Analysis/SVals.cpp
index 688b7ff6e1e3..d5d36e3b9090 100644
--- a/lib/Analysis/SVals.cpp
+++ b/lib/Analysis/SVals.cpp
@@ -63,7 +63,7 @@ const FunctionDecl *SVal::getAsFunctionDecl() const {
// FIXME: should we consider SymbolRef wrapped in CodeTextRegion?
SymbolRef SVal::getAsLocSymbol() const {
if (const loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(this)) {
- const MemRegion *R = X->getBaseRegion();
+ const MemRegion *R = X->StripCasts();
if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(R))
return SymR->getSymbol();
}
@@ -100,9 +100,9 @@ const MemRegion *SVal::getAsRegion() const {
return 0;
}
-const MemRegion *loc::MemRegionVal::getBaseRegion() const {
+const MemRegion *loc::MemRegionVal::StripCasts() const {
const MemRegion *R = getRegion();
- return R ? R->getBaseRegion() : NULL;
+ return R ? R->StripCasts() : NULL;
}
bool SVal::symbol_iterator::operator==(const symbol_iterator &X) const {
@@ -173,6 +173,10 @@ nonloc::CompoundVal::iterator nonloc::CompoundVal::end() const {
// Useful predicates.
//===----------------------------------------------------------------------===//
+bool SVal::isConstant() const {
+ return isa<nonloc::ConcreteInt>(this) || isa<loc::ConcreteInt>(this);
+}
+
bool SVal::isZeroConstant() const {
if (isa<loc::ConcreteInt>(*this))
return cast<loc::ConcreteInt>(*this).getValue() == 0;
diff --git a/lib/Analysis/SValuator.cpp b/lib/Analysis/SValuator.cpp
index 573cac315b3a..ac727b0ac696 100644
--- a/lib/Analysis/SValuator.cpp
+++ b/lib/Analysis/SValuator.cpp
@@ -62,8 +62,7 @@ SValuator::CastResult SValuator::EvalCast(SVal val, const GRState *state,
ASTContext &C = ValMgr.getContext();
// For const casts, just propagate the value.
- if (C.getCanonicalType(castTy).getUnqualifiedType() ==
- C.getCanonicalType(originalTy).getUnqualifiedType())
+ if (C.hasSameUnqualifiedType(castTy, originalTy))
return CastResult(state, val);
// Check for casts from pointers to integers.
diff --git a/lib/Analysis/Store.cpp b/lib/Analysis/Store.cpp
index 4b4ae6580820..2fd72ac0a148 100644
--- a/lib/Analysis/Store.cpp
+++ b/lib/Analysis/Store.cpp
@@ -21,7 +21,7 @@ StoreManager::StoreManager(GRStateManager &stateMgr)
MRMgr(ValMgr.getRegionManager()) {}
const MemRegion *StoreManager::MakeElementRegion(const MemRegion *Base,
- QualType EleTy, uint64_t index) {
+ QualType EleTy, uint64_t index) {
SVal idx = ValMgr.makeArrayIndex(index);
return MRMgr.getElementRegion(EleTy, idx, Base, ValMgr.getContext());
}
@@ -43,7 +43,7 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy)
// Handle casts to Objective-C objects.
if (CastToTy->isObjCObjectPointerType())
- return R->getBaseRegion();
+ return R->StripCasts();
if (CastToTy->isBlockPointerType()) {
// FIXME: We may need different solutions, depending on the symbol
@@ -64,7 +64,7 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy)
QualType CanonPointeeTy = Ctx.getCanonicalType(PointeeTy);
// Handle casts to void*. We just pass the region through.
- if (CanonPointeeTy.getUnqualifiedType() == Ctx.VoidTy)
+ if (CanonPointeeTy.getLocalUnqualifiedType() == Ctx.VoidTy)
return R;
// Handle casts from compatible types.
@@ -192,14 +192,14 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy)
/// CastRetrievedVal - Used by subclasses of StoreManager to implement
/// implicit casts that arise from loads from regions that are reinterpreted
/// as another region.
-SValuator::CastResult StoreManager::CastRetrievedVal(SVal V,
- const GRState *state,
- const TypedRegion *R,
- QualType castTy) {
- if (castTy.isNull())
- return SValuator::CastResult(state, V);
-
+SVal StoreManager::CastRetrievedVal(SVal V, const TypedRegion *R,
+ QualType castTy) {
ASTContext &Ctx = ValMgr.getContext();
- return ValMgr.getSValuator().EvalCast(V, state, castTy, R->getValueType(Ctx));
+
+ if (castTy.isNull())
+ return V;
+
+ assert(Ctx.hasSameUnqualifiedType(castTy, R->getValueType(Ctx)));
+ return V;
}
diff --git a/lib/Analysis/UndefinedArgChecker.cpp b/lib/Analysis/UndefinedArgChecker.cpp
index a229f55ff6d9..923a7e1bed0b 100644
--- a/lib/Analysis/UndefinedArgChecker.cpp
+++ b/lib/Analysis/UndefinedArgChecker.cpp
@@ -12,14 +12,28 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/Checkers/UndefinedArgChecker.h"
+#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "GRExprEngineInternalChecks.h"
using namespace clang;
-void *UndefinedArgChecker::getTag() {
- static int x = 0;
- return &x;
+namespace {
+class VISIBILITY_HIDDEN UndefinedArgChecker
+ : public CheckerVisitor<UndefinedArgChecker> {
+ BugType *BT;
+public:
+ UndefinedArgChecker() : BT(0) {}
+ static void *getTag() {
+ static int x = 0;
+ return &x;
+ }
+ void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
+};
+} // end anonymous namespace
+
+void clang::RegisterUndefinedArgChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new UndefinedArgChecker());
}
void UndefinedArgChecker::PreVisitCallExpr(CheckerContext &C,
@@ -29,11 +43,10 @@ void UndefinedArgChecker::PreVisitCallExpr(CheckerContext &C,
if (C.getState()->getSVal(*I).isUndef()) {
if (ExplodedNode *N = C.GenerateNode(CE, true)) {
if (!BT)
- BT = new BugType("Pass-by-value argument in function call is "
- "undefined", "Logic error");
+ BT = new BuiltinBug("Pass-by-value argument in function call is "
+ "undefined");
// Generate a report for this bug.
- EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName().c_str(),
- N);
+ EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N);
R->addRange((*I)->getSourceRange());
R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, *I);
C.EmitReport(R);
diff --git a/lib/Analysis/UndefinedArraySubscriptChecker.cpp b/lib/Analysis/UndefinedArraySubscriptChecker.cpp
new file mode 100644
index 000000000000..887c7755fe45
--- /dev/null
+++ b/lib/Analysis/UndefinedArraySubscriptChecker.cpp
@@ -0,0 +1,56 @@
+//===--- UndefinedArraySubscriptChecker.h ----------------------*- C++ -*--===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines UndefinedArraySubscriptChecker, a builtin check in GRExprEngine
+// that performs checks for undefined array subscripts.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "GRExprEngineInternalChecks.h"
+
+using namespace clang;
+
+namespace {
+class VISIBILITY_HIDDEN UndefinedArraySubscriptChecker
+ : public CheckerVisitor<UndefinedArraySubscriptChecker> {
+ BugType *BT;
+public:
+ UndefinedArraySubscriptChecker() : BT(0) {}
+ static void *getTag() {
+ static int x = 0;
+ return &x;
+ }
+ void PreVisitArraySubscriptExpr(CheckerContext &C,
+ const ArraySubscriptExpr *A);
+};
+} // end anonymous namespace
+
+void clang::RegisterUndefinedArraySubscriptChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new UndefinedArraySubscriptChecker());
+}
+
+void
+UndefinedArraySubscriptChecker::PreVisitArraySubscriptExpr(CheckerContext &C,
+ const ArraySubscriptExpr *A) {
+ if (C.getState()->getSVal(A->getIdx()).isUndef()) {
+ if (ExplodedNode *N = C.GenerateNode(A, true)) {
+ if (!BT)
+ BT = new BuiltinBug("Array subscript is undefined");
+
+ // Generate a report for this bug.
+ EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N);
+ R->addRange(A->getIdx()->getSourceRange());
+ R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
+ A->getIdx());
+ C.EmitReport(R);
+ }
+ }
+}
diff --git a/lib/Analysis/UndefinedAssignmentChecker.cpp b/lib/Analysis/UndefinedAssignmentChecker.cpp
index 2e3ac34913ab..b8062f359562 100644
--- a/lib/Analysis/UndefinedAssignmentChecker.cpp
+++ b/lib/Analysis/UndefinedAssignmentChecker.cpp
@@ -36,11 +36,10 @@ void UndefinedAssignmentChecker::PreVisitBind(CheckerContext &C,
return;
if (!BT)
- BT = new BugType("Assigned value is garbage or undefined",
- "Logic error");
+ BT = new BuiltinBug("Assigned value is garbage or undefined");
// Generate a report for this bug.
- EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName().c_str(), N);
+ EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N);
if (AssignE) {
const Expr *ex = 0;
diff --git a/lib/Analysis/VLASizeChecker.cpp b/lib/Analysis/VLASizeChecker.cpp
index 0e731902f4bb..799a73e293c8 100644
--- a/lib/Analysis/VLASizeChecker.cpp
+++ b/lib/Analysis/VLASizeChecker.cpp
@@ -7,96 +7,91 @@
//
//===----------------------------------------------------------------------===//
//
-// This defines two VLASizeCheckers, a builtin check in GRExprEngine that
+// This defines VLASizeChecker, a builtin check in GRExprEngine that
// performs checks for declaration of VLA of undefined or zero size.
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/Checkers/VLASizeChecker.h"
+#include "GRExprEngineInternalChecks.h"
+#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
#include "clang/Analysis/PathSensitive/BugReporter.h"
using namespace clang;
-void *UndefSizedVLAChecker::getTag() {
- static int x = 0;
- return &x;
+namespace {
+class VISIBILITY_HIDDEN VLASizeChecker : public CheckerVisitor<VLASizeChecker> {
+ BugType *BT_zero;
+ BugType *BT_undef;
+
+public:
+ VLASizeChecker() : BT_zero(0), BT_undef(0) {}
+ static void *getTag() { static int tag = 0; return &tag; }
+ void PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS);
+};
+} // end anonymous namespace
+
+void clang::RegisterVLASizeChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new VLASizeChecker());
}
-ExplodedNode *UndefSizedVLAChecker::CheckType(QualType T, ExplodedNode *Pred,
- const GRState *state,
- Stmt *S, GRExprEngine &Eng) {
- GRStmtNodeBuilder &Builder = Eng.getBuilder();
- BugReporter &BR = Eng.getBugReporter();
-
- if (VariableArrayType* VLA = dyn_cast<VariableArrayType>(T)) {
- // FIXME: Handle multi-dimensional VLAs.
- Expr* SE = VLA->getSizeExpr();
- SVal Size_untested = state->getSVal(SE);
-
- if (Size_untested.isUndef()) {
- if (ExplodedNode* N = Builder.generateNode(S, state, Pred)) {
- N->markAsSink();
- if (!BT)
- BT = new BugType("Declared variable-length array (VLA) uses a garbage"
- " value as its size", "Logic error");
-
- EnhancedBugReport *R =
- new EnhancedBugReport(*BT, BT->getName().c_str(), N);
- R->addRange(SE->getSourceRange());
- R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, SE);
- BR.EmitReport(R);
- }
- return 0;
- }
+void VLASizeChecker::PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS) {
+ if (!DS->isSingleDecl())
+ return;
+
+ const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl());
+ if (!VD)
+ return;
+
+ const VariableArrayType *VLA
+ = C.getASTContext().getAsVariableArrayType(VD->getType());
+ if (!VLA)
+ return;
+
+ // FIXME: Handle multi-dimensional VLAs.
+ const Expr* SE = VLA->getSizeExpr();
+ const GRState *state = C.getState();
+ SVal sizeV = state->getSVal(SE);
+
+ if (sizeV.isUndef()) {
+ // Generate an error node.
+ ExplodedNode *N = C.GenerateNode(DS, true);
+ if (!N)
+ return;
+
+ if (!BT_undef)
+ BT_undef = new BuiltinBug("Declared variable-length array (VLA) uses a "
+ "garbage value as its size");
+
+ EnhancedBugReport *report =
+ new EnhancedBugReport(*BT_undef, BT_undef->getName(), N);
+ report->addRange(SE->getSourceRange());
+ report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, SE);
+ C.EmitReport(report);
+ return;
}
- return Pred;
-}
-
-void *ZeroSizedVLAChecker::getTag() {
- static int x;
- return &x;
-}
-
-ExplodedNode *ZeroSizedVLAChecker::CheckType(QualType T, ExplodedNode *Pred,
- const GRState *state, Stmt *S,
- GRExprEngine &Eng) {
- GRStmtNodeBuilder &Builder = Eng.getBuilder();
- BugReporter &BR = Eng.getBugReporter();
-
- if (VariableArrayType* VLA = dyn_cast<VariableArrayType>(T)) {
- // FIXME: Handle multi-dimensional VLAs.
- Expr* SE = VLA->getSizeExpr();
- SVal Size_untested = state->getSVal(SE);
-
- DefinedOrUnknownSVal *Size = dyn_cast<DefinedOrUnknownSVal>(&Size_untested);
- // Undefined size is checked in another checker.
- if (!Size)
- return Pred;
-
- const GRState *zeroState = state->Assume(*Size, false);
- state = state->Assume(*Size, true);
-
- if (zeroState && !state) {
- if (ExplodedNode* N = Builder.generateNode(S, zeroState, Pred)) {
- N->markAsSink();
- if (!BT)
- BT = new BugType("Declared variable-length array (VLA) has zero size",
- "Logic error");
-
- EnhancedBugReport *R =
- new EnhancedBugReport(*BT, BT->getName().c_str(), N);
- R->addRange(SE->getSourceRange());
- R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, SE);
- BR.EmitReport(R);
- }
- }
- if (!state)
- return 0;
-
- return Builder.generateNode(S, state, Pred);
+
+ // Check if the size is zero.
+ DefinedOrUnknownSVal sizeD = cast<DefinedOrUnknownSVal>(sizeV);
+
+ const GRState *stateNotZero, *stateZero;
+ llvm::tie(stateNotZero, stateZero) = state->Assume(sizeD);
+
+ if (stateZero && !stateNotZero) {
+ ExplodedNode* N = C.GenerateNode(DS, stateZero, true);
+ if (!BT_zero)
+ BT_zero = new BuiltinBug("Declared variable-length array (VLA) has zero "
+ "size");
+
+ EnhancedBugReport *report =
+ new EnhancedBugReport(*BT_zero, BT_zero->getName(), N);
+ report->addRange(SE->getSourceRange());
+ report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, SE);
+ C.EmitReport(report);
+ return;
}
- else
- return Pred;
+
+ // From this point on, assume that the size is not zero.
+ if (state != stateNotZero)
+ C.addTransition(C.GenerateNode(DS, stateNotZero));
}
-
diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp
index 962cb4c42a8a..a85bef0f29ed 100644
--- a/lib/Basic/SourceManager.cpp
+++ b/lib/Basic/SourceManager.cpp
@@ -715,8 +715,8 @@ unsigned SourceManager::getInstantiationColumnNumber(SourceLocation Loc) const {
-static void ComputeLineNumbers(ContentCache* FI,
- llvm::BumpPtrAllocator &Alloc) DISABLE_INLINE;
+static DISABLE_INLINE void ComputeLineNumbers(ContentCache* FI,
+ llvm::BumpPtrAllocator &Alloc);
static void ComputeLineNumbers(ContentCache* FI, llvm::BumpPtrAllocator &Alloc){
// Note that calling 'getBuffer()' may lazily page in the file.
const MemoryBuffer *Buffer = FI->getBuffer();
diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp
index 12caf0c8e512..b6c4df87f272 100644
--- a/lib/Basic/TargetInfo.cpp
+++ b/lib/Basic/TargetInfo.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/LangOptions.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/STLExtras.h"
#include <cstdlib>
@@ -24,9 +25,6 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) {
// These should be overridden by concrete targets as needed.
TLSSupported = true;
PointerWidth = PointerAlign = 32;
- WCharWidth = WCharAlign = 32;
- Char16Width = Char16Align = 16;
- Char32Width = Char32Align = 32;
IntWidth = IntAlign = 32;
LongWidth = LongAlign = 32;
LongLongWidth = LongLongAlign = 64;
@@ -36,7 +34,6 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) {
DoubleAlign = 64;
LongDoubleWidth = 64;
LongDoubleAlign = 64;
- IntMaxTWidth = 64;
SizeType = UnsignedLong;
PtrDiffType = SignedLong;
IntMaxType = SignedLongLong;
@@ -51,7 +48,7 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) {
DoubleFormat = &llvm::APFloat::IEEEdouble;
LongDoubleFormat = &llvm::APFloat::IEEEdouble;
DescriptionString = "E-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
- "i64:64:64-f32:32:32-f64:64:64";
+ "i64:64:64-f32:32:32-f64:64:64-n32";
UserLabelPrefix = "_";
}
@@ -95,17 +92,33 @@ const char *TargetInfo::getTypeConstantSuffix(IntType T) {
unsigned TargetInfo::getTypeWidth(IntType T) const {
switch (T) {
default: assert(0 && "not an integer!");
- case SignedShort: return getShortWidth();
+ case SignedShort:
case UnsignedShort: return getShortWidth();
- case SignedInt: return getIntWidth();
+ case SignedInt:
case UnsignedInt: return getIntWidth();
- case SignedLong: return getLongWidth();
+ case SignedLong:
case UnsignedLong: return getLongWidth();
- case SignedLongLong: return getLongLongWidth();
+ case SignedLongLong:
case UnsignedLongLong: return getLongLongWidth();
};
}
+/// getTypeAlign - Return the alignment (in bits) of the specified integer type
+/// enum. For example, SignedInt -> getIntAlign().
+unsigned TargetInfo::getTypeAlign(IntType T) const {
+ switch (T) {
+ default: assert(0 && "not an integer!");
+ case SignedShort:
+ case UnsignedShort: return getShortAlign();
+ case SignedInt:
+ case UnsignedInt: return getIntAlign();
+ case SignedLong:
+ case UnsignedLong: return getLongAlign();
+ case SignedLongLong:
+ case UnsignedLongLong: return getLongLongAlign();
+ };
+}
+
/// isTypeSigned - Return whether an integer types is signed. Returns true if
/// the type is signed; false otherwise.
bool TargetInfo::isTypeSigned(IntType T) const {
@@ -124,6 +137,14 @@ bool TargetInfo::isTypeSigned(IntType T) const {
};
}
+/// setForcedLangOptions - Set forced language options.
+/// Apply changes to the target information with respect to certain
+/// language options which change the target configuration.
+void TargetInfo::setForcedLangOptions(LangOptions &Opts) {
+ if (Opts.ShortWChar) {
+ WCharType = UnsignedShort;
+ }
+}
//===----------------------------------------------------------------------===//
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index f418c5a81c12..07c2bb960bcf 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -12,14 +12,18 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Basic/Builtins.h"
-#include "clang/Basic/TargetBuiltins.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/Builtins.h"
+#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/TargetBuiltins.h"
+#include "clang/Basic/TargetOptions.h"
#include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringSwitch.h"
#include "llvm/ADT/Triple.h"
#include "llvm/MC/MCSectionMachO.h"
using namespace clang;
@@ -151,29 +155,6 @@ static void getDarwinIPhoneOSDefines(std::vector<char> &Defs,
iPhoneOSStr);
}
-/// GetDarwinLanguageOptions - Set the default language options for darwin.
-static void GetDarwinLanguageOptions(LangOptions &Opts,
- const llvm::Triple &Triple) {
- Opts.NeXTRuntime = true;
-
- if (Triple.getOS() != llvm::Triple::Darwin)
- return;
-
- unsigned MajorVersion = Triple.getDarwinMajorNumber();
-
- // Blocks and stack protectors default to on for 10.6 (darwin10) and beyond.
- if (MajorVersion > 9) {
- Opts.Blocks = 1;
- Opts.setStackProtectorMode(LangOptions::SSPOn);
- }
-
- // Non-fragile ABI (in 64-bit mode) default to on for 10.5 (darwin9) and
- // beyond.
- if (MajorVersion >= 9 && Opts.ObjC1 &&
- Triple.getArch() == llvm::Triple::x86_64)
- Opts.ObjCNonFragileABI = 1;
-}
-
namespace {
template<typename Target>
class DarwinTargetInfo : public OSTargetInfo<Target> {
@@ -184,13 +165,6 @@ protected:
getDarwinOSXDefines(Defines, Triple);
}
- /// getDefaultLangOptions - Allow the target to specify default settings for
- /// various language options. These may be overridden by command line
- /// options.
- virtual void getDefaultLangOptions(LangOptions &Opts) {
- TargetInfo::getDefaultLangOptions(Opts);
- GetDarwinLanguageOptions(Opts, TargetInfo::getTriple());
- }
public:
DarwinTargetInfo(const std::string& triple) :
OSTargetInfo<Target>(triple) {
@@ -320,6 +294,25 @@ public:
: OSTargetInfo<Target>(triple) {}
};
+// PSP Target
+template<typename Target>
+class PSPTargetInfo : public OSTargetInfo<Target> {
+protected:
+ virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ std::vector<char> &Defs) const {
+ // PSP defines; list based on the output of the pspdev gcc toolchain.
+ Define(Defs, "PSP", "1");
+ Define(Defs, "_PSP", "1");
+ Define(Defs, "__psp__", "1");
+ Define(Defs, "__ELF__", "1");
+ }
+public:
+ PSPTargetInfo(const std::string& triple)
+ : OSTargetInfo<Target>(triple) {
+ this->UserLabelPrefix = "";
+ }
+};
+
// AuroraUX target
template<typename Target>
class AuroraUXTargetInfo : public OSTargetInfo<Target> {
@@ -413,10 +406,6 @@ public:
return true;
}
}
- virtual void getDefaultLangOptions(LangOptions &Opts) {
- TargetInfo::getDefaultLangOptions(Opts);
- Opts.CharIsSigned = false;
- }
virtual const char *getClobbers() const {
return "";
}
@@ -568,7 +557,7 @@ class PPC32TargetInfo : public PPCTargetInfo {
public:
PPC32TargetInfo(const std::string& triple) : PPCTargetInfo(triple) {
DescriptionString = "E-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
- "i64:64:64-f32:32:32-f64:64:64-v128:128:128";
+ "i64:64:64-f32:32:32-f64:64:64-v128:128:128-n32";
}
};
} // end anonymous namespace.
@@ -582,7 +571,7 @@ public:
UIntMaxType = UnsignedLong;
Int64Type = SignedLong;
DescriptionString = "E-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
- "i64:64:64-f32:32:32-f64:64:64-v128:128:128";
+ "i64:64:64-f32:32:32-f64:64:64-v128:128:128-n32:64";
}
};
} // end anonymous namespace.
@@ -655,7 +644,7 @@ public:
bool Enabled) const;
virtual void getDefaultFeatures(const std::string &CPU,
llvm::StringMap<bool> &Features) const;
- virtual void HandleTargetFeatures(const llvm::StringMap<bool> &Features);
+ virtual void HandleTargetFeatures(const std::vector<std::string> &Features);
};
void X86TargetInfo::getDefaultFeatures(const std::string &CPU,
@@ -772,21 +761,25 @@ bool X86TargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features,
/// HandleTargetOptions - Perform initialization based on the user
/// configured set of features.
-void X86TargetInfo::HandleTargetFeatures(const llvm::StringMap<bool>&Features) {
- if (Features.lookup("sse42"))
- SSELevel = SSE42;
- else if (Features.lookup("sse41"))
- SSELevel = SSE41;
- else if (Features.lookup("ssse3"))
- SSELevel = SSSE3;
- else if (Features.lookup("sse3"))
- SSELevel = SSE3;
- else if (Features.lookup("sse2"))
- SSELevel = SSE2;
- else if (Features.lookup("sse"))
- SSELevel = SSE1;
- else if (Features.lookup("mmx"))
- SSELevel = MMX;
+void
+X86TargetInfo::HandleTargetFeatures(const std::vector<std::string> &Features) {
+ // Remember the maximum enabled sselevel.
+ for (unsigned i = 0, e = Features.size(); i !=e; ++i) {
+ // Ignore disabled features.
+ if (Features[i][0] == '-')
+ continue;
+
+ assert(Features[i][0] == '+' && "Invalid target feature!");
+ X86SSEEnum Level = llvm::StringSwitch<X86SSEEnum>(Features[i].substr(1))
+ .Case("sse42", SSE42)
+ .Case("sse41", SSE41)
+ .Case("ssse3", SSSE3)
+ .Case("sse2", SSE2)
+ .Case("sse", SSE1)
+ .Case("mmx", MMX)
+ .Default(NoMMXSSE);
+ SSELevel = std::max(SSELevel, Level);
+ }
}
/// X86TargetInfo::getTargetDefines - Return a set of the X86-specific #defines
@@ -902,7 +895,7 @@ public:
LongDoubleAlign = 32;
DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
"i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-"
- "a0:0:64-f80:32:32";
+ "a0:0:64-f80:32:32-n8:16:32";
SizeType = UnsignedInt;
PtrDiffType = SignedInt;
IntPtrType = SignedInt;
@@ -943,7 +936,7 @@ public:
IntPtrType = SignedLong;
DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
"i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-"
- "a0:0:64-f80:128:128";
+ "a0:0:64-f80:128:128-n8:16:32";
}
};
@@ -957,11 +950,10 @@ public:
: X86_32TargetInfo(triple) {
TLSSupported = false;
WCharType = UnsignedShort;
- WCharWidth = WCharAlign = 16;
DoubleAlign = LongLongAlign = 64;
DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
"i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-"
- "a0:0:64-f80:32:32";
+ "a0:0:64-f80:32:32-n8:16:32";
}
virtual void getTargetDefines(const LangOptions &Opts,
std::vector<char> &Defines) const {
@@ -977,11 +969,6 @@ public:
namespace {
-/// GetWindowsVisualStudioLanguageOptions - Set the default language options for Windows.
-static void GetWindowsVisualStudioLanguageOptions(LangOptions &Opts) {
- Opts.Microsoft = true;
-}
-
// x86-32 Windows Visual Studio target
class VisualStudioWindowsX86_32TargetInfo : public WindowsX86_32TargetInfo {
public:
@@ -996,10 +983,6 @@ public:
// We lost the original triple, so we use the default.
Define(Defines, "_M_IX86", "600");
}
- virtual void getDefaultLangOptions(LangOptions &Opts) {
- WindowsX86_32TargetInfo::getDefaultLangOptions(Opts);
- GetWindowsVisualStudioLanguageOptions(Opts);
- }
};
} // end anonymous namespace
@@ -1028,11 +1011,10 @@ public:
: X86_32TargetInfo(triple) {
TLSSupported = false;
WCharType = UnsignedShort;
- WCharWidth = WCharAlign = 16;
DoubleAlign = LongLongAlign = 64;
DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
"i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-"
- "a0:0:64-f80:32:32";
+ "a0:0:64-f80:32:32-n8:16:32";
}
virtual void getTargetDefines(const LangOptions &Opts,
std::vector<char> &Defines) const {
@@ -1059,7 +1041,7 @@ public:
DescriptionString = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
"i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-"
- "a0:0:64-s0:64:64-f80:128:128";
+ "a0:0:64-s0:64:64-f80:128:128-n8:16:32:64";
}
virtual const char *getVAListDeclaration() const {
return "typedef struct __va_list_tag {"
@@ -1087,7 +1069,6 @@ public:
: X86_64TargetInfo(triple) {
TLSSupported = false;
WCharType = UnsignedShort;
- WCharWidth = WCharAlign = 16;
LongWidth = LongAlign = 32;
DoubleAlign = LongLongAlign = 64;
}
@@ -1208,11 +1189,11 @@ public:
if (IsThumb) {
DescriptionString = ("e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-"
"i64:64:64-f32:32:32-f64:64:64-"
- "v64:64:64-v128:128:128-a0:0:32");
+ "v64:64:64-v128:128:128-a0:0:32-n32");
} else {
DescriptionString = ("e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
"i64:64:64-f32:32:32-f64:64:64-"
- "v64:64:64-v128:128:128-a0:0:64");
+ "v64:64:64-v128:128:128-a0:0:64-n32");
}
}
virtual const char *getABI() const { return ABI.c_str(); }
@@ -1230,11 +1211,11 @@ public:
if (IsThumb) {
DescriptionString = ("e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-"
"i64:32:32-f32:32:32-f64:32:32-"
- "v64:64:64-v128:128:128-a0:0:32");
+ "v64:64:64-v128:128:128-a0:0:32-n32");
} else {
DescriptionString = ("e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
"i64:32:32-f32:32:32-f64:32:32-"
- "v64:64:64-v128:128:128-a0:0:64");
+ "v64:64:64-v128:128:128-a0:0:64-n32");
}
// FIXME: Override "preferred align" for double and long long.
@@ -1391,7 +1372,7 @@ public:
SparcV8TargetInfo(const std::string& triple) : TargetInfo(triple) {
// FIXME: Support Sparc quad-precision long double?
DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
- "i64:64:64-f32:32:32-f64:64:64-v64:64:64";
+ "i64:64:64-f32:32:32-f64:64:64-v64:64:64-n32";
}
virtual void getTargetDefines(const LangOptions &Opts,
std::vector<char> &Defines) const {
@@ -1502,7 +1483,6 @@ namespace {
TLSSupported = false;
IntWidth = 16;
LongWidth = LongLongWidth = 32;
- IntMaxTWidth = 32;
PointerWidth = 16;
IntAlign = 8;
LongAlign = LongLongAlign = 8;
@@ -1521,7 +1501,7 @@ namespace {
FloatFormat = &llvm::APFloat::IEEEsingle;
DoubleFormat = &llvm::APFloat::IEEEsingle;
LongDoubleFormat = &llvm::APFloat::IEEEsingle;
- DescriptionString = "e-p:16:8:8-i8:8:8-i16:8:8-i32:8:8-f32:32:32";
+ DescriptionString = "e-p:16:8:8-i8:8:8-i16:8:8-i32:8:8-f32:32:32-n8";
}
virtual uint64_t getPointerWidthV(unsigned AddrSpace) const { return 16; }
@@ -1570,7 +1550,6 @@ namespace {
TLSSupported = false;
IntWidth = 16;
LongWidth = LongLongWidth = 32;
- IntMaxTWidth = 32;
PointerWidth = 16;
IntAlign = 8;
LongAlign = LongLongAlign = 8;
@@ -1580,7 +1559,7 @@ namespace {
UIntMaxType = UnsignedLong;
IntPtrType = SignedShort;
PtrDiffType = SignedInt;
- DescriptionString = "e-p:16:8:8-i8:8:8-i16:8:8-i32:8:8";
+ DescriptionString = "e-p:16:8:8-i8:8:8-i16:8:8-i32:8:8-n8:16";
}
virtual void getTargetDefines(const LangOptions &Opts,
std::vector<char> &Defines) const {
@@ -1639,7 +1618,8 @@ namespace {
IntWidth = IntAlign = 32;
LongWidth = LongLongWidth = LongAlign = LongLongAlign = 64;
PointerWidth = PointerAlign = 64;
- DescriptionString = "E-p:64:64:64-i8:8:16-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-f128:128:128-a0:16:16";
+ DescriptionString = "E-p:64:64:64-i8:8:16-i16:16:16-i32:32:32-"
+ "i64:64:64-f32:32:32-f64:64:64-f128:128:128-a0:16:16-n32:64";
}
virtual void getTargetDefines(const LangOptions &Opts,
std::vector<char> &Defines) const {
@@ -1653,11 +1633,6 @@ namespace {
NumRecords = 0;
}
- virtual void getDefaultLangOptions(LangOptions &Opts) {
- TargetInfo::getDefaultLangOptions(Opts);
- Opts.CharIsSigned = false;
- }
-
virtual void getGCCRegNames(const char * const *&Names,
unsigned &NumNames) const;
virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
@@ -1702,7 +1677,7 @@ namespace {
DoubleAlign = 32;
LongLongAlign = 32;
LongDoubleAlign = 32;
- DescriptionString = "e-p:32:32-i64:32-f64:32";
+ DescriptionString = "e-p:32:32-i64:32-f64:32-n32";
}
virtual void getTargetDefines(const LangOptions &Opts,
@@ -1783,7 +1758,6 @@ namespace {
TLSSupported = false;
IntWidth = 32;
LongWidth = LongLongWidth = 32;
- IntMaxTWidth = 32;
PointerWidth = 32;
IntAlign = 32;
LongAlign = LongLongAlign = 32;
@@ -1804,7 +1778,7 @@ namespace {
LongDoubleFormat = &llvm::APFloat::IEEEsingle;
DescriptionString = "E-p:32:32:32-a0:32:32"
"-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64"
- "-f32:32:32-f64:32:64";
+ "-f32:32:32-f64:32:64-n32";
}
virtual void getTargetDefines(const LangOptions &Opts,
@@ -1832,13 +1806,141 @@ namespace {
};
}
+namespace {
+class MipsTargetInfo : public TargetInfo {
+ static const TargetInfo::GCCRegAlias GCCRegAliases[];
+ static const char * const GCCRegNames[];
+public:
+ MipsTargetInfo(const std::string& triple) : TargetInfo(triple) {
+ DescriptionString = "E-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-"
+ "i64:32:64-f32:32:32-f64:64:64-v64:64:64-n32";
+ }
+ virtual void getTargetDefines(const LangOptions &Opts,
+ std::vector<char> &Defines) const {
+ DefineStd(Defines, "mips", Opts);
+ Define(Defines, "_mips");
+ DefineStd(Defines, "MIPSEB", Opts);
+ Define(Defines, "_MIPSEB");
+ Define(Defines, "__REGISTER_PREFIX__", "");
+ }
+ virtual void getTargetBuiltins(const Builtin::Info *&Records,
+ unsigned &NumRecords) const {
+ // FIXME: Implement!
+ }
+ virtual const char *getVAListDeclaration() const {
+ return "typedef void* __builtin_va_list;";
+ }
+ virtual void getGCCRegNames(const char * const *&Names,
+ unsigned &NumNames) const;
+ virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
+ unsigned &NumAliases) const;
+ virtual bool validateAsmConstraint(const char *&Name,
+ TargetInfo::ConstraintInfo &Info) const {
+ switch (*Name) {
+ default:
+ case 'r': // CPU registers.
+ case 'd': // Equivalent to "r" unless generating MIPS16 code.
+ case 'y': // Equivalent to "r", backwards compatibility only.
+ case 'f': // floating-point registers.
+ Info.setAllowsRegister();
+ return true;
+ }
+ return false;
+ }
+
+ virtual const char *getClobbers() const {
+ // FIXME: Implement!
+ return "";
+ }
+};
+
+const char * const MipsTargetInfo::GCCRegNames[] = {
+ "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7",
+ "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15",
+ "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23",
+ "$24", "$25", "$26", "$27", "$28", "$sp", "$fp", "$31",
+ "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7",
+ "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15",
+ "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23",
+ "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31",
+ "hi", "lo", "", "$fcc0","$fcc1","$fcc2","$fcc3","$fcc4",
+ "$fcc5","$fcc6","$fcc7"
+};
+
+void MipsTargetInfo::getGCCRegNames(const char * const *&Names,
+ unsigned &NumNames) const {
+ Names = GCCRegNames;
+ NumNames = llvm::array_lengthof(GCCRegNames);
+}
+
+const TargetInfo::GCCRegAlias MipsTargetInfo::GCCRegAliases[] = {
+ { { "at" }, "$1" },
+ { { "v0" }, "$2" },
+ { { "v1" }, "$3" },
+ { { "a0" }, "$4" },
+ { { "a1" }, "$5" },
+ { { "a2" }, "$6" },
+ { { "a3" }, "$7" },
+ { { "t0" }, "$8" },
+ { { "t1" }, "$9" },
+ { { "t2" }, "$10" },
+ { { "t3" }, "$11" },
+ { { "t4" }, "$12" },
+ { { "t5" }, "$13" },
+ { { "t6" }, "$14" },
+ { { "t7" }, "$15" },
+ { { "s0" }, "$16" },
+ { { "s1" }, "$17" },
+ { { "s2" }, "$18" },
+ { { "s3" }, "$19" },
+ { { "s4" }, "$20" },
+ { { "s5" }, "$21" },
+ { { "s6" }, "$22" },
+ { { "s7" }, "$23" },
+ { { "t8" }, "$24" },
+ { { "t9" }, "$25" },
+ { { "k0" }, "$26" },
+ { { "k1" }, "$27" },
+ { { "gp" }, "$28" },
+ { { "sp" }, "$29" },
+ { { "fp" }, "$30" },
+ { { "ra" }, "$31" }
+};
+
+void MipsTargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases,
+ unsigned &NumAliases) const {
+ Aliases = GCCRegAliases;
+ NumAliases = llvm::array_lengthof(GCCRegAliases);
+}
+} // end anonymous namespace.
+
+namespace {
+class MipselTargetInfo : public MipsTargetInfo {
+public:
+ MipselTargetInfo(const std::string& triple) : MipsTargetInfo(triple) {
+ DescriptionString = "e-p:32:32:32-i1:8:8-i8:8:32-i16:16:32-i32:32:32-"
+ "i64:32:64-f32:32:32-f64:64:64-v64:64:64-n32";
+ }
+
+ virtual void getTargetDefines(const LangOptions &Opts,
+ std::vector<char> &Defines) const;
+};
+
+void MipselTargetInfo::getTargetDefines(const LangOptions &Opts,
+ std::vector<char> &Defines) const {
+ DefineStd(Defines, "mips", Opts);
+ Define(Defines, "_mips");
+ DefineStd(Defines, "MIPSEL", Opts);
+ Define(Defines, "_MIPSEL");
+ Define(Defines, "__REGISTER_PREFIX__", "");
+}
+} // end anonymous namespace.
+
//===----------------------------------------------------------------------===//
// Driver code
//===----------------------------------------------------------------------===//
-/// CreateTargetInfo - Return the target info object for the specified target
-/// triple.
-TargetInfo* TargetInfo::CreateTargetInfo(const std::string &T) {
+static TargetInfo *AllocateTarget(const std::string &T) {
llvm::Triple Triple(T);
llvm::Triple::OSType os = Triple.getOS();
@@ -1863,6 +1965,20 @@ TargetInfo* TargetInfo::CreateTargetInfo(const std::string &T) {
case llvm::Triple::msp430:
return new MSP430TargetInfo(T);
+ case llvm::Triple::mips:
+ if (os == llvm::Triple::Psp)
+ return new PSPTargetInfo<MipsTargetInfo>(T);
+ if (os == llvm::Triple::Linux)
+ return new LinuxTargetInfo<MipsTargetInfo>(T);
+ return new MipsTargetInfo(T);
+
+ case llvm::Triple::mipsel:
+ if (os == llvm::Triple::Psp)
+ return new PSPTargetInfo<MipselTargetInfo>(T);
+ if (os == llvm::Triple::Linux)
+ return new LinuxTargetInfo<MipselTargetInfo>(T);
+ return new MipselTargetInfo(T);
+
case llvm::Triple::pic16:
return new PIC16TargetInfo(T);
@@ -1942,3 +2058,53 @@ TargetInfo* TargetInfo::CreateTargetInfo(const std::string &T) {
}
}
}
+
+/// CreateTargetInfo - Return the target info object for the specified target
+/// triple.
+TargetInfo *TargetInfo::CreateTargetInfo(Diagnostic &Diags,
+ const TargetOptions &Opts) {
+ llvm::Triple Triple(Opts.Triple);
+
+ // Construct the target
+ llvm::OwningPtr<TargetInfo> Target(AllocateTarget(Triple.str()));
+ if (!Target) {
+ Diags.Report(diag::err_target_unknown_triple) << Triple.str();
+ return 0;
+ }
+
+ // Set the target ABI if specified.
+ if (!Opts.ABI.empty() && !Target->setABI(Opts.ABI)) {
+ Diags.Report(diag::err_target_unknown_abi) << Opts.ABI;
+ return 0;
+ }
+
+ // Compute the default target features, we need the target to handle this
+ // because features may have dependencies on one another.
+ llvm::StringMap<bool> Features;
+ Target->getDefaultFeatures(Opts.CPU, Features);
+
+ // Apply the user specified deltas.
+ for (std::vector<std::string>::const_iterator it = Opts.Features.begin(),
+ ie = Opts.Features.end(); it != ie; ++it) {
+ const char *Name = it->c_str();
+
+ // Apply the feature via the target.
+ if ((Name[0] != '-' && Name[0] != '+') ||
+ !Target->setFeatureEnabled(Features, Name + 1, (Name[0] == '+'))) {
+ Diags.Report(diag::err_target_invalid_feature) << Name;
+ return 0;
+ }
+ }
+
+ // Add the features to the compile options.
+ //
+ // FIXME: If we are completely confident that we have the right set, we only
+ // need to pass the minuses.
+ std::vector<std::string> StrFeatures;
+ for (llvm::StringMap<bool>::const_iterator it = Features.begin(),
+ ie = Features.end(); it != ie; ++it)
+ StrFeatures.push_back(std::string(it->second ? "+" : "-") + it->first());
+ Target->HandleTargetFeatures(StrFeatures);
+
+ return Target.take();
+}
diff --git a/lib/Basic/Version.cpp b/lib/Basic/Version.cpp
index 30383f6251f6..ba31544384cb 100644
--- a/lib/Basic/Version.cpp
+++ b/lib/Basic/Version.cpp
@@ -26,6 +26,10 @@ const char *getClangSubversionPath() {
if (End)
*End = 0;
+ End = strstr(URL, "/clang/tools/clang");
+ if (End)
+ *End = 0;
+
char *Begin = strstr(URL, "cfe/");
if (Begin) {
Path = Begin + 4;
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index 682cf5da1e72..bc9eb67674ff 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -146,7 +146,23 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
if (0 && CanBlockBeGlobal(Info))
return CGM.GetAddrOfGlobalBlock(BE, Name.c_str());
- std::vector<llvm::Constant*> Elts(5);
+ size_t BlockFields = 5;
+
+ bool hasIntrospection = CGM.getContext().getLangOptions().BlockIntrospection;
+
+ if (hasIntrospection) {
+ BlockFields++;
+ }
+ std::vector<llvm::Constant*> Elts(BlockFields);
+
+ if (hasIntrospection) {
+ std::string BlockTypeEncoding;
+ CGM.getContext().getObjCEncodingForBlock(BE, BlockTypeEncoding);
+
+ Elts[5] = llvm::ConstantExpr::getBitCast(
+ CGM.GetAddrOfConstantCString(BlockTypeEncoding), PtrToInt8Ty);
+ }
+
llvm::Constant *C;
llvm::Value *V;
@@ -154,6 +170,9 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
// C = BuildBlockStructInitlist();
unsigned int flags = BLOCK_HAS_DESCRIPTOR;
+ if (hasIntrospection)
+ flags |= BLOCK_HAS_OBJC_TYPE;
+
// We run this first so that we set BlockHasCopyDispose from the entire
// block literal.
// __invoke
@@ -211,19 +230,21 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
return C;
}
- std::vector<const llvm::Type *> Types(5+subBlockDeclRefDecls.size());
+ std::vector<const llvm::Type *> Types(BlockFields+subBlockDeclRefDecls.size());
for (int i=0; i<4; ++i)
Types[i] = Elts[i]->getType();
Types[4] = PtrToInt8Ty;
+ if (hasIntrospection)
+ Types[5] = PtrToInt8Ty;
for (unsigned i=0; i < subBlockDeclRefDecls.size(); ++i) {
const Expr *E = subBlockDeclRefDecls[i];
const BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(E);
QualType Ty = E->getType();
if (BDRE && BDRE->isByRef()) {
- Types[i+5] = llvm::PointerType::get(BuildByRefType(BDRE->getDecl()), 0);
+ Types[i+BlockFields] = llvm::PointerType::get(BuildByRefType(BDRE->getDecl()), 0);
} else
- Types[i+5] = ConvertType(Ty);
+ Types[i+BlockFields] = ConvertType(Ty);
}
llvm::StructType *Ty = llvm::StructType::get(VMContext, Types, true);
@@ -237,6 +258,8 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
for (unsigned i=0; i<4; ++i)
Builder.CreateStore(Elts[i], Builder.CreateStructGEP(V, i, "block.tmp"));
+ if (hasIntrospection)
+ Builder.CreateStore(Elts[5], Builder.CreateStructGEP(V, 5, "block.tmp"));
for (unsigned i=0; i < subBlockDeclRefDecls.size(); ++i)
{
@@ -252,7 +275,7 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
BlockDeclRefExpr *BDRE = dyn_cast<BlockDeclRefExpr>(E);
VD = BDRE->getDecl();
- llvm::Value* Addr = Builder.CreateStructGEP(V, i+5, "tmp");
+ llvm::Value* Addr = Builder.CreateStructGEP(V, i+BlockFields, "tmp");
NoteForHelper[helpersize].index = i+5;
NoteForHelper[helpersize].RequiresCopying
= BlockRequiresCopying(VD->getType());
@@ -291,7 +314,7 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
RValue r = EmitAnyExpr(E, Addr, false);
if (r.isScalar()) {
llvm::Value *Loc = r.getScalarVal();
- const llvm::Type *Ty = Types[i+5];
+ const llvm::Type *Ty = Types[i+BlockFields];
if (BDRE->isByRef()) {
// E is now the address of the value field, instead, we want the
// address of the actual ByRef struct. We optimize this slightly
@@ -375,8 +398,20 @@ const llvm::Type *BlockModule::getGenericBlockLiteralType() {
// int __reserved;
// void (*__invoke)(void *);
// struct __block_descriptor *__descriptor;
+ // // GNU runtime only:
+ // const char *types;
// };
- GenericBlockLiteralType = llvm::StructType::get(IntTy->getContext(),
+ if (CGM.getContext().getLangOptions().BlockIntrospection)
+ GenericBlockLiteralType = llvm::StructType::get(IntTy->getContext(),
+ PtrToInt8Ty,
+ IntTy,
+ IntTy,
+ PtrToInt8Ty,
+ BlockDescPtrTy,
+ PtrToInt8Ty,
+ NULL);
+ else
+ GenericBlockLiteralType = llvm::StructType::get(IntTy->getContext(),
PtrToInt8Ty,
IntTy,
IntTy,
@@ -571,8 +606,12 @@ BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) {
llvm::GlobalVariable::InternalLinkage,
DescriptorStruct, "__block_descriptor_global");
+ int FieldCount = 5;
// Generate the constants for the block literal.
- llvm::Constant *LiteralFields[5];
+ if (CGM.getContext().getLangOptions().BlockIntrospection)
+ FieldCount = 6;
+
+ std::vector<llvm::Constant*> LiteralFields(FieldCount);
CodeGenFunction::BlockInfo Info(0, n);
uint64_t subBlockSize, subBlockAlign;
@@ -592,7 +631,9 @@ BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) {
LiteralFields[0] = getNSConcreteGlobalBlock();
// Flags
- LiteralFields[1] =
+ LiteralFields[1] = CGM.getContext().getLangOptions().BlockIntrospection ?
+ llvm::ConstantInt::get(IntTy, BLOCK_IS_GLOBAL | BLOCK_HAS_DESCRIPTOR |
+ BLOCK_HAS_OBJC_TYPE) :
llvm::ConstantInt::get(IntTy, BLOCK_IS_GLOBAL | BLOCK_HAS_DESCRIPTOR);
// Reserved
@@ -603,9 +644,17 @@ BlockModule::GetAddrOfGlobalBlock(const BlockExpr *BE, const char * n) {
// Descriptor
LiteralFields[4] = Descriptor;
+
+ // Type encoding
+ if (CGM.getContext().getLangOptions().BlockIntrospection) {
+ std::string BlockTypeEncoding;
+ CGM.getContext().getObjCEncodingForBlock(BE, BlockTypeEncoding);
+
+ LiteralFields[5] = CGM.GetAddrOfConstantCString(BlockTypeEncoding);
+ }
llvm::Constant *BlockLiteralStruct =
- llvm::ConstantStruct::get(VMContext, &LiteralFields[0], 5, false);
+ llvm::ConstantStruct::get(VMContext, LiteralFields, false);
llvm::GlobalVariable *BlockLiteral =
new llvm::GlobalVariable(getModule(), BlockLiteralStruct->getType(), true,
diff --git a/lib/CodeGen/CGBlocks.h b/lib/CodeGen/CGBlocks.h
index 3ab4efb71bee..38e02a70a4e2 100644
--- a/lib/CodeGen/CGBlocks.h
+++ b/lib/CodeGen/CGBlocks.h
@@ -55,7 +55,8 @@ public:
BLOCK_HAS_CXX_OBJ = (1 << 26),
BLOCK_IS_GC = (1 << 27),
BLOCK_IS_GLOBAL = (1 << 28),
- BLOCK_HAS_DESCRIPTOR = (1 << 29)
+ BLOCK_HAS_DESCRIPTOR = (1 << 29),
+ BLOCK_HAS_OBJC_TYPE = (1 << 30)
};
};
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
index c26921969a88..399b8733e720 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -121,7 +121,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
const llvm::Type *ResultType = ConvertType(E->getType());
Value *Result = Builder.CreateCall(F, ArgValue, "tmp");
if (Result->getType() != ResultType)
- Result = Builder.CreateIntCast(Result, ResultType, "cast");
+ Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true,
+ "cast");
return RValue::get(Result);
}
case Builtin::BI__builtin_clz:
@@ -135,7 +136,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
const llvm::Type *ResultType = ConvertType(E->getType());
Value *Result = Builder.CreateCall(F, ArgValue, "tmp");
if (Result->getType() != ResultType)
- Result = Builder.CreateIntCast(Result, ResultType, "cast");
+ Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true,
+ "cast");
return RValue::get(Result);
}
case Builtin::BI__builtin_ffs:
@@ -154,7 +156,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Value *IsZero = Builder.CreateICmpEQ(ArgValue, Zero, "iszero");
Value *Result = Builder.CreateSelect(IsZero, Zero, Tmp, "ffs");
if (Result->getType() != ResultType)
- Result = Builder.CreateIntCast(Result, ResultType, "cast");
+ Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true,
+ "cast");
return RValue::get(Result);
}
case Builtin::BI__builtin_parity:
@@ -171,7 +174,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Value *Result = Builder.CreateAnd(Tmp, llvm::ConstantInt::get(ArgType, 1),
"tmp");
if (Result->getType() != ResultType)
- Result = Builder.CreateIntCast(Result, ResultType, "cast");
+ Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true,
+ "cast");
return RValue::get(Result);
}
case Builtin::BI__builtin_popcount:
@@ -185,7 +189,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
const llvm::Type *ResultType = ConvertType(E->getType());
Value *Result = Builder.CreateCall(F, ArgValue, "tmp");
if (Result->getType() != ResultType)
- Result = Builder.CreateIntCast(Result, ResultType, "cast");
+ Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true,
+ "cast");
return RValue::get(Result);
}
case Builtin::BI__builtin_expect:
@@ -199,8 +204,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
return RValue::get(Builder.CreateCall(F, ArgValue, "tmp"));
}
case Builtin::BI__builtin_object_size: {
- // FIXME: We're awaiting the llvm intrincis.
-#if 0
+#if 1
// We pass this builtin onto the optimizer so that it can
// figure out the object size in more complex cases.
const llvm::Type *ResType[] = {
@@ -211,8 +215,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
EmitScalarExpr(E->getArg(0)),
EmitScalarExpr(E->getArg(1))));
#else
- // FIXME: Implement. For now we just always fail and pretend we
- // don't know the object size.
+ // FIXME: Remove after testing.
llvm::APSInt TypeArg = E->getArg(1)->EvaluateAsInt(CGM.getContext());
const llvm::Type *ResType = ConvertType(E->getType());
// bool UseSubObject = TypeArg.getZExtValue() & 1;
diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp
index cf172b1a1cb6..8f5cff4efafe 100644
--- a/lib/CodeGen/CGCXX.cpp
+++ b/lib/CodeGen/CGCXX.cpp
@@ -27,7 +27,7 @@ using namespace clang;
using namespace CodeGen;
void
-CodeGenFunction::EmitCXXGlobalDtorRegistration(const CXXDestructorDecl *Dtor,
+CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn,
llvm::Constant *DeclPtr) {
const llvm::Type *Int8PtrTy =
llvm::Type::getInt8Ty(VMContext)->getPointerTo();
@@ -55,9 +55,6 @@ CodeGenFunction::EmitCXXGlobalDtorRegistration(const CXXDestructorDecl *Dtor,
llvm::Constant *Handle = CGM.CreateRuntimeVariable(Int8PtrTy,
"__dso_handle");
-
- llvm::Constant *DtorFn = CGM.GetAddrOfCXXDestructor(Dtor, Dtor_Complete);
-
llvm::Value *Args[3] = { llvm::ConstantExpr::getBitCast(DtorFn, DtorFnTy),
llvm::ConstantExpr::getBitCast(DeclPtr, Int8PtrTy),
llvm::ConstantExpr::getBitCast(Handle, Int8PtrTy) };
@@ -82,11 +79,29 @@ void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D,
EmitComplexExprIntoAddr(Init, DeclPtr, isVolatile);
} else {
EmitAggExpr(Init, DeclPtr, isVolatile);
-
+ // Avoid generating destructor(s) for initialized objects.
+ if (!isa<CXXConstructExpr>(Init))
+ return;
+ const ConstantArrayType *Array = getContext().getAsConstantArrayType(T);
+ if (Array)
+ T = getContext().getBaseElementType(Array);
+
if (const RecordType *RT = T->getAs<RecordType>()) {
CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
- if (!RD->hasTrivialDestructor())
- EmitCXXGlobalDtorRegistration(RD->getDestructor(getContext()), DeclPtr);
+ if (!RD->hasTrivialDestructor()) {
+ llvm::Constant *DtorFn;
+ if (Array) {
+ DtorFn = CodeGenFunction(CGM).GenerateCXXAggrDestructorHelper(
+ RD->getDestructor(getContext()),
+ Array, DeclPtr);
+ DeclPtr =
+ llvm::Constant::getNullValue(llvm::Type::getInt8PtrTy(VMContext));
+ }
+ else
+ DtorFn = CGM.GetAddrOfCXXDestructor(RD->getDestructor(getContext()),
+ Dtor_Complete);
+ EmitCXXGlobalDtorRegistration(DtorFn, DeclPtr);
+ }
}
}
}
@@ -267,14 +282,20 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE) {
// We also don't emit a virtual call if the base expression has a record type
// because then we know what the type is.
llvm::Value *Callee;
- if (MD->isVirtual() && !ME->hasQualifier() &&
- !canDevirtualizeMemberFunctionCalls(ME->getBase()))
- Callee = BuildVirtualCall(MD, This, Ty);
- else if (const CXXDestructorDecl *Destructor
- = dyn_cast<CXXDestructorDecl>(MD))
- Callee = CGM.GetAddrOfFunction(GlobalDecl(Destructor, Dtor_Complete), Ty);
- else
+ if (const CXXDestructorDecl *Destructor
+ = dyn_cast<CXXDestructorDecl>(MD)) {
+ if (MD->isVirtual() && !ME->hasQualifier() &&
+ !canDevirtualizeMemberFunctionCalls(ME->getBase())) {
+ Callee = BuildVirtualCall(Destructor, Dtor_Complete, This, Ty);
+ } else {
+ Callee = CGM.GetAddrOfFunction(GlobalDecl(Destructor, Dtor_Complete), Ty);
+ }
+ } else if (MD->isVirtual() && !ME->hasQualifier() &&
+ !canDevirtualizeMemberFunctionCalls(ME->getBase())) {
+ Callee = BuildVirtualCall(MD, This, Ty);
+ } else {
Callee = CGM.GetAddrOfFunction(MD, Ty);
+ }
return EmitCXXMemberCall(MD, Callee, This,
CE->arg_begin(), CE->arg_end());
@@ -410,10 +431,15 @@ CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E,
const llvm::Type *Ty =
CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
FPT->isVariadic());
- llvm::Constant *Callee = CGM.GetAddrOfFunction(MD, Ty);
llvm::Value *This = EmitLValue(E->getArg(0)).getAddress();
+ llvm::Value *Callee;
+ if (MD->isVirtual() && !canDevirtualizeMemberFunctionCalls(E->getArg(0)))
+ Callee = BuildVirtualCall(MD, This, Ty);
+ else
+ Callee = CGM.GetAddrOfFunction(MD, Ty);
+
return EmitCXXMemberCall(MD, Callee, This,
E->arg_begin() + 1, E->arg_end());
}
@@ -506,16 +532,25 @@ CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D,
llvm::Value *This) {
const ConstantArrayType *CA = dyn_cast<ConstantArrayType>(Array);
assert(CA && "Do we support VLA for destruction ?");
+ uint64_t ElementCount = getContext().getConstantArrayElementCount(CA);
+ llvm::Value* ElementCountPtr =
+ llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), ElementCount);
+ EmitCXXAggrDestructorCall(D, ElementCountPtr, This);
+}
+
+/// EmitCXXAggrDestructorCall - calls the default destructor on array
+/// elements in reverse order of construction.
+void
+CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D,
+ llvm::Value *UpperCount,
+ llvm::Value *This) {
llvm::Value *One = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
1);
- uint64_t ElementCount = getContext().getConstantArrayElementCount(CA);
// Create a temporary for the loop index and initialize it with count of
// array elements.
llvm::Value *IndexPtr = CreateTempAlloca(llvm::Type::getInt64Ty(VMContext),
"loop.index");
// Index = ElementCount;
- llvm::Value* UpperCount =
- llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), ElementCount);
Builder.CreateStore(UpperCount, IndexPtr, false);
// Start the loop with a block that tests the condition.
@@ -543,7 +578,16 @@ CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D,
Counter = Builder.CreateLoad(IndexPtr);
Counter = Builder.CreateSub(Counter, One);
llvm::Value *Address = Builder.CreateInBoundsGEP(This, Counter, "arrayidx");
- EmitCXXDestructorCall(D, Dtor_Complete, Address);
+ if (D->isVirtual()) {
+ const llvm::Type *Ty =
+ CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(D),
+ /*isVariadic=*/false);
+
+ llvm::Value *Callee = BuildVirtualCall(D, Dtor_Deleting, Address, Ty);
+ EmitCXXMemberCall(D, Callee, Address, 0, 0);
+ }
+ else
+ EmitCXXDestructorCall(D, Dtor_Complete, Address);
EmitBlock(ContinueBlock);
@@ -559,6 +603,50 @@ CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D,
EmitBlock(AfterFor, true);
}
+/// GenerateCXXAggrDestructorHelper - Generates a helper function which when invoked,
+/// calls the default destructor on array elements in reverse order of
+/// construction.
+llvm::Constant *
+CodeGenFunction::GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D,
+ const ArrayType *Array,
+ llvm::Value *This) {
+ static int UniqueCount;
+ FunctionArgList Args;
+ ImplicitParamDecl *Dst =
+ ImplicitParamDecl::Create(getContext(), 0,
+ SourceLocation(), 0,
+ getContext().getPointerType(getContext().VoidTy));
+ Args.push_back(std::make_pair(Dst, Dst->getType()));
+
+ llvm::SmallString<16> Name;
+ llvm::raw_svector_ostream(Name) << "__tcf_" << (++UniqueCount);
+ QualType R = getContext().VoidTy;
+ const CGFunctionInfo &FI = CGM.getTypes().getFunctionInfo(R, Args);
+ const llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI, false);
+ llvm::Function *Fn =
+ llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage,
+ Name.c_str(),
+ &CGM.getModule());
+ IdentifierInfo *II
+ = &CGM.getContext().Idents.get(Name.c_str());
+ FunctionDecl *FD = FunctionDecl::Create(getContext(),
+ getContext().getTranslationUnitDecl(),
+ SourceLocation(), II, R, 0,
+ FunctionDecl::Static,
+ false, true);
+ StartFunction(FD, R, Fn, Args, SourceLocation());
+ QualType BaseElementTy = getContext().getBaseElementType(Array);
+ const llvm::Type *BasePtr = ConvertType(BaseElementTy);
+ BasePtr = llvm::PointerType::getUnqual(BasePtr);
+ llvm::Value *BaseAddrPtr = Builder.CreateBitCast(This, BasePtr);
+ EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr);
+ FinishFunction();
+ llvm::Type *Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext),
+ 0);
+ llvm::Constant *m = llvm::ConstantExpr::getBitCast(Fn, Ptr8Ty);
+ return m;
+}
+
void
CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
CXXCtorType Type,
@@ -612,8 +700,13 @@ CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest,
// Code gen optimization to eliminate copy constructor and return
// its first argument instead.
if (getContext().getLangOptions().ElideConstructors && E->isElidable()) {
- CXXConstructExpr::const_arg_iterator i = E->arg_begin();
- EmitAggExpr((*i), Dest, false);
+ const Expr *Arg = E->getArg(0);
+
+ if (const CXXBindTemporaryExpr *BindExpr =
+ dyn_cast<CXXBindTemporaryExpr>(Arg))
+ Arg = BindExpr->getSubExpr();
+
+ EmitAggExpr(Arg, Dest, false);
return;
}
if (Array) {
@@ -649,8 +742,10 @@ void CodeGenModule::EmitCXXConstructor(const CXXConstructorDecl *D,
llvm::Function *
CodeGenModule::GetAddrOfCXXConstructor(const CXXConstructorDecl *D,
CXXCtorType Type) {
+ const FunctionProtoType *FPT = D->getType()->getAs<FunctionProtoType>();
const llvm::FunctionType *FTy =
- getTypes().GetFunctionType(getTypes().getFunctionInfo(D), false);
+ getTypes().GetFunctionType(getTypes().getFunctionInfo(D),
+ FPT->isVariadic());
const char *Name = getMangledCXXCtorName(D, Type);
return cast<llvm::Function>(
@@ -668,6 +763,8 @@ const char *CodeGenModule::getMangledCXXCtorName(const CXXConstructorDecl *D,
}
void CodeGenModule::EmitCXXDestructors(const CXXDestructorDecl *D) {
+ if (D->isVirtual())
+ EmitCXXDestructor(D, Dtor_Deleting);
EmitCXXDestructor(D, Dtor_Complete);
EmitCXXDestructor(D, Dtor_Base);
}
@@ -919,20 +1016,35 @@ CodeGenFunction::GetVirtualCXXBaseClassOffset(llvm::Value *This,
return VBaseOffset;
}
+static llvm::Value *BuildVirtualCall(CodeGenFunction &CGF, int64_t VtableIndex,
+ llvm::Value *This, const llvm::Type *Ty) {
+ Ty = Ty->getPointerTo()->getPointerTo()->getPointerTo();
+
+ llvm::Value *Vtable = CGF.Builder.CreateBitCast(This, Ty);
+ Vtable = CGF.Builder.CreateLoad(Vtable);
+
+ llvm::Value *VFuncPtr =
+ CGF.Builder.CreateConstInBoundsGEP1_64(Vtable, VtableIndex, "vfn");
+ return CGF.Builder.CreateLoad(VFuncPtr);
+}
+
llvm::Value *
-CodeGenFunction::BuildVirtualCall(const CXXMethodDecl *MD, llvm::Value *&This,
+CodeGenFunction::BuildVirtualCall(const CXXMethodDecl *MD, llvm::Value *This,
const llvm::Type *Ty) {
- int64_t Index = CGM.getVtableInfo().getMethodVtableIndex(MD);
+ MD = MD->getCanonicalDecl();
+ int64_t VtableIndex = CGM.getVtableInfo().getMethodVtableIndex(MD);
- Ty = llvm::PointerType::get(Ty, 0);
- Ty = llvm::PointerType::get(Ty, 0);
- Ty = llvm::PointerType::get(Ty, 0);
- llvm::Value *vtbl = Builder.CreateBitCast(This, Ty);
- vtbl = Builder.CreateLoad(vtbl);
- llvm::Value *vfn = Builder.CreateConstInBoundsGEP1_64(vtbl,
- Index, "vfn");
- vfn = Builder.CreateLoad(vfn);
- return vfn;
+ return ::BuildVirtualCall(*this, VtableIndex, This, Ty);
+}
+
+llvm::Value *
+CodeGenFunction::BuildVirtualCall(const CXXDestructorDecl *DD, CXXDtorType Type,
+ llvm::Value *&This, const llvm::Type *Ty) {
+ DD = cast<CXXDestructorDecl>(DD->getCanonicalDecl());
+ int64_t VtableIndex =
+ CGM.getVtableInfo().getMethodVtableIndex(GlobalDecl(DD, Type));
+
+ return ::BuildVirtualCall(*this, VtableIndex, This, Ty);
}
/// EmitClassAggrMemberwiseCopy - This routine generates code to copy a class
@@ -1269,8 +1381,16 @@ CodeGenFunction::SynthesizeCXXCopyConstructor(const CXXConstructorDecl *Ctor,
// Do a built-in assignment of scalar data members.
LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0);
LValue RHS = EmitLValueForField(LoadOfSrc, *Field, false, 0);
- RValue RVRHS = EmitLoadOfLValue(RHS, FieldType);
- EmitStoreThroughLValue(RVRHS, LHS, FieldType);
+ if (!hasAggregateLLVMType(Field->getType())) {
+ RValue RVRHS = EmitLoadOfLValue(RHS, Field->getType());
+ EmitStoreThroughLValue(RVRHS, LHS, Field->getType());
+ } else if (Field->getType()->isAnyComplexType()) {
+ ComplexPairTy Pair = LoadComplexFromAddr(RHS.getAddress(),
+ RHS.isVolatileQualified());
+ StoreComplexToAddr(Pair, LHS.getAddress(), LHS.isVolatileQualified());
+ } else {
+ EmitAggregateCopy(LHS.getAddress(), RHS.getAddress(), Field->getType());
+ }
}
FinishFunction();
}
@@ -1366,12 +1486,122 @@ void CodeGenFunction::SynthesizeCXXCopyAssignment(const CXXMethodDecl *CD,
FinishFunction();
}
+static void EmitBaseInitializer(CodeGenFunction &CGF,
+ const CXXRecordDecl *ClassDecl,
+ CXXBaseOrMemberInitializer *BaseInit,
+ CXXCtorType CtorType) {
+ assert(BaseInit->isBaseInitializer() &&
+ "Must have base initializer!");
+
+ llvm::Value *ThisPtr = CGF.LoadCXXThis();
+
+ const Type *BaseType = BaseInit->getBaseClass();
+ CXXRecordDecl *BaseClassDecl =
+ cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl());
+ llvm::Value *V = CGF.GetAddressCXXOfBaseClass(ThisPtr, ClassDecl,
+ BaseClassDecl,
+ /*NullCheckValue=*/false);
+ CGF.EmitCXXConstructorCall(BaseInit->getConstructor(),
+ CtorType, V,
+ BaseInit->const_arg_begin(),
+ BaseInit->const_arg_end());
+}
+
+static void EmitMemberInitializer(CodeGenFunction &CGF,
+ const CXXRecordDecl *ClassDecl,
+ CXXBaseOrMemberInitializer *MemberInit) {
+ assert(MemberInit->isMemberInitializer() &&
+ "Must have member initializer!");
+
+ // non-static data member initializers.
+ FieldDecl *Field = MemberInit->getMember();
+ QualType FieldType = CGF.getContext().getCanonicalType(Field->getType());
+
+ llvm::Value *ThisPtr = CGF.LoadCXXThis();
+ LValue LHS;
+ if (FieldType->isReferenceType()) {
+ // FIXME: This is really ugly; should be refactored somehow
+ unsigned idx = CGF.CGM.getTypes().getLLVMFieldNo(Field);
+ llvm::Value *V = CGF.Builder.CreateStructGEP(ThisPtr, idx, "tmp");
+ assert(!FieldType.getObjCGCAttr() && "fields cannot have GC attrs");
+ LHS = LValue::MakeAddr(V, CGF.MakeQualifiers(FieldType));
+ } else {
+ LHS = CGF.EmitLValueForField(ThisPtr, Field, ClassDecl->isUnion(), 0);
+ }
+
+ // If we are initializing an anonymous union field, drill down to the field.
+ if (MemberInit->getAnonUnionMember()) {
+ Field = MemberInit->getAnonUnionMember();
+ LHS = CGF.EmitLValueForField(LHS.getAddress(), Field,
+ /*IsUnion=*/true, 0);
+ FieldType = Field->getType();
+ }
+
+ // If the field is an array, branch based on the element type.
+ const ConstantArrayType *Array =
+ CGF.getContext().getAsConstantArrayType(FieldType);
+ if (Array)
+ FieldType = CGF.getContext().getBaseElementType(FieldType);
+
+ // We lose the constructor for anonymous union members, so handle them
+ // explicitly.
+ // FIXME: This is somwhat ugly.
+ if (MemberInit->getAnonUnionMember() && FieldType->getAs<RecordType>()) {
+ if (MemberInit->getNumArgs())
+ CGF.EmitAggExpr(*MemberInit->arg_begin(), LHS.getAddress(),
+ LHS.isVolatileQualified());
+ else
+ CGF.EmitAggregateClear(LHS.getAddress(), Field->getType());
+ return;
+ }
+
+ if (FieldType->getAs<RecordType>()) {
+ assert(MemberInit->getConstructor() &&
+ "EmitCtorPrologue - no constructor to initialize member");
+ if (Array) {
+ const llvm::Type *BasePtr = CGF.ConvertType(FieldType);
+ BasePtr = llvm::PointerType::getUnqual(BasePtr);
+ llvm::Value *BaseAddrPtr =
+ CGF.Builder.CreateBitCast(LHS.getAddress(), BasePtr);
+ CGF.EmitCXXAggrConstructorCall(MemberInit->getConstructor(),
+ Array, BaseAddrPtr);
+ }
+ else
+ CGF.EmitCXXConstructorCall(MemberInit->getConstructor(),
+ Ctor_Complete, LHS.getAddress(),
+ MemberInit->const_arg_begin(),
+ MemberInit->const_arg_end());
+ return;
+ }
+
+ assert(MemberInit->getNumArgs() == 1 && "Initializer count must be 1 only");
+ Expr *RhsExpr = *MemberInit->arg_begin();
+ RValue RHS;
+ if (FieldType->isReferenceType()) {
+ RHS = CGF.EmitReferenceBindingToExpr(RhsExpr, FieldType,
+ /*IsInitializer=*/true);
+ CGF.EmitStoreThroughLValue(RHS, LHS, FieldType);
+ } else if (Array) {
+ CGF.EmitMemSetToZero(LHS.getAddress(), Field->getType());
+ } else if (!CGF.hasAggregateLLVMType(RhsExpr->getType())) {
+ RHS = RValue::get(CGF.EmitScalarExpr(RhsExpr, true));
+ CGF.EmitStoreThroughLValue(RHS, LHS, FieldType);
+ } else if (RhsExpr->getType()->isAnyComplexType()) {
+ CGF.EmitComplexExprIntoAddr(RhsExpr, LHS.getAddress(),
+ LHS.isVolatileQualified());
+ } else {
+ // Handle member function pointers; other aggregates shouldn't get this far.
+ CGF.EmitAggExpr(RhsExpr, LHS.getAddress(), LHS.isVolatileQualified());
+ }
+}
+
/// EmitCtorPrologue - This routine generates necessary code to initialize
/// base classes and non-static data members belonging to this constructor.
/// FIXME: This needs to take a CXXCtorType.
void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
CXXCtorType CtorType) {
- const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(CD->getDeclContext());
+ const CXXRecordDecl *ClassDecl = CD->getParent();
+
// FIXME: Add vbase initialization
llvm::Value *LoadOfThis = 0;
@@ -1379,136 +1609,18 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
E = CD->init_end();
B != E; ++B) {
CXXBaseOrMemberInitializer *Member = (*B);
- if (Member->isBaseInitializer()) {
- LoadOfThis = LoadCXXThis();
- Type *BaseType = Member->getBaseClass();
- CXXRecordDecl *BaseClassDecl =
- cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl());
- llvm::Value *V = GetAddressCXXOfBaseClass(LoadOfThis, ClassDecl,
- BaseClassDecl,
- /*NullCheckValue=*/false);
- EmitCXXConstructorCall(Member->getConstructor(),
- CtorType, V,
- Member->const_arg_begin(),
- Member->const_arg_end());
- } else {
- // non-static data member initilaizers.
- FieldDecl *Field = Member->getMember();
- QualType FieldType = getContext().getCanonicalType((Field)->getType());
- const ConstantArrayType *Array =
- getContext().getAsConstantArrayType(FieldType);
- if (Array)
- FieldType = getContext().getBaseElementType(FieldType);
+
+ assert(LiveTemporaries.empty() &&
+ "Should not have any live temporaries at initializer start!");
- LoadOfThis = LoadCXXThis();
- LValue LHS;
- if (FieldType->isReferenceType()) {
- // FIXME: This is really ugly; should be refactored somehow
- unsigned idx = CGM.getTypes().getLLVMFieldNo(Field);
- llvm::Value *V = Builder.CreateStructGEP(LoadOfThis, idx, "tmp");
- assert(!FieldType.getObjCGCAttr() && "fields cannot have GC attrs");
- LHS = LValue::MakeAddr(V, MakeQualifiers(FieldType));
- } else {
- LHS = EmitLValueForField(LoadOfThis, Field, false, 0);
- }
- if (FieldType->getAs<RecordType>()) {
- if (!Field->isAnonymousStructOrUnion()) {
- assert(Member->getConstructor() &&
- "EmitCtorPrologue - no constructor to initialize member");
- if (Array) {
- const llvm::Type *BasePtr = ConvertType(FieldType);
- BasePtr = llvm::PointerType::getUnqual(BasePtr);
- llvm::Value *BaseAddrPtr =
- Builder.CreateBitCast(LHS.getAddress(), BasePtr);
- EmitCXXAggrConstructorCall(Member->getConstructor(),
- Array, BaseAddrPtr);
- }
- else
- EmitCXXConstructorCall(Member->getConstructor(),
- Ctor_Complete, LHS.getAddress(),
- Member->const_arg_begin(),
- Member->const_arg_end());
- continue;
- }
- else {
- // Initializing an anonymous union data member.
- FieldDecl *anonMember = Member->getAnonUnionMember();
- LHS = EmitLValueForField(LHS.getAddress(), anonMember,
- /*IsUnion=*/true, 0);
- FieldType = anonMember->getType();
- }
- }
+ if (Member->isBaseInitializer())
+ EmitBaseInitializer(*this, ClassDecl, Member, CtorType);
+ else
+ EmitMemberInitializer(*this, ClassDecl, Member);
- assert(Member->getNumArgs() == 1 && "Initializer count must be 1 only");
- Expr *RhsExpr = *Member->arg_begin();
- RValue RHS;
- if (FieldType->isReferenceType())
- RHS = EmitReferenceBindingToExpr(RhsExpr, FieldType,
- /*IsInitializer=*/true);
- else if (FieldType->isMemberFunctionPointerType())
- RHS = RValue::get(CGM.EmitConstantExpr(RhsExpr, FieldType, this));
- else
- RHS = RValue::get(EmitScalarExpr(RhsExpr, true));
- EmitStoreThroughLValue(RHS, LHS, FieldType);
- }
- }
-
- if (!CD->getNumBaseOrMemberInitializers() && !CD->isTrivial()) {
- // Nontrivial default constructor with no initializer list. It may still
- // have bases classes and/or contain non-static data members which require
- // construction.
- for (CXXRecordDecl::base_class_const_iterator Base =
- ClassDecl->bases_begin();
- Base != ClassDecl->bases_end(); ++Base) {
- // FIXME. copy assignment of virtual base NYI
- if (Base->isVirtual())
- continue;
-
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
- if (BaseClassDecl->hasTrivialConstructor())
- continue;
- if (CXXConstructorDecl *BaseCX =
- BaseClassDecl->getDefaultConstructor(getContext())) {
- LoadOfThis = LoadCXXThis();
- llvm::Value *V = GetAddressCXXOfBaseClass(LoadOfThis, ClassDecl,
- BaseClassDecl,
- /*NullCheckValue=*/false);
- EmitCXXConstructorCall(BaseCX, Ctor_Complete, V, 0, 0);
- }
- }
-
- for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
- FieldEnd = ClassDecl->field_end();
- Field != FieldEnd; ++Field) {
- QualType FieldType = getContext().getCanonicalType((*Field)->getType());
- const ConstantArrayType *Array =
- getContext().getAsConstantArrayType(FieldType);
- if (Array)
- FieldType = getContext().getBaseElementType(FieldType);
- if (!FieldType->getAs<RecordType>() || Field->isAnonymousStructOrUnion())
- continue;
- const RecordType *ClassRec = FieldType->getAs<RecordType>();
- CXXRecordDecl *MemberClassDecl =
- dyn_cast<CXXRecordDecl>(ClassRec->getDecl());
- if (!MemberClassDecl || MemberClassDecl->hasTrivialConstructor())
- continue;
- if (CXXConstructorDecl *MamberCX =
- MemberClassDecl->getDefaultConstructor(getContext())) {
- LoadOfThis = LoadCXXThis();
- LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0);
- if (Array) {
- const llvm::Type *BasePtr = ConvertType(FieldType);
- BasePtr = llvm::PointerType::getUnqual(BasePtr);
- llvm::Value *BaseAddrPtr =
- Builder.CreateBitCast(LHS.getAddress(), BasePtr);
- EmitCXXAggrConstructorCall(MamberCX, Array, BaseAddrPtr);
- }
- else
- EmitCXXConstructorCall(MamberCX, Ctor_Complete, LHS.getAddress(),
- 0, 0);
- }
- }
+ // Pop any live temporaries that the initializers might have pushed.
+ while (!LiveTemporaries.empty())
+ PopCXXTemporary();
}
// Initialize the vtable pointer
@@ -1520,7 +1632,7 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0);
PtrPtr8Ty = llvm::PointerType::get(Ptr8Ty, 0);
VtableField = Builder.CreateBitCast(LoadOfThis, PtrPtr8Ty);
- llvm::Value *vtable = GenerateVtable(ClassDecl);
+ llvm::Value *vtable = CGM.getVtableInfo().getVtable(ClassDecl);
Builder.CreateStore(vtable, VtableField);
}
}
@@ -1531,138 +1643,117 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
/// FIXME: This needs to take a CXXDtorType.
void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD,
CXXDtorType DtorType) {
- const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(DD->getDeclContext());
- assert(!ClassDecl->getNumVBases() &&
- "FIXME: Destruction of virtual bases not supported");
- (void)ClassDecl; // prevent warning.
-
- for (CXXDestructorDecl::destr_const_iterator *B = DD->destr_begin(),
- *E = DD->destr_end(); B != E; ++B) {
- uintptr_t BaseOrMember = (*B);
- if (DD->isMemberToDestroy(BaseOrMember)) {
- FieldDecl *FD = DD->getMemberToDestroy(BaseOrMember);
- QualType FieldType = getContext().getCanonicalType((FD)->getType());
- const ConstantArrayType *Array =
- getContext().getAsConstantArrayType(FieldType);
- if (Array)
- FieldType = getContext().getBaseElementType(FieldType);
- const RecordType *RT = FieldType->getAs<RecordType>();
- CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl());
- if (FieldClassDecl->hasTrivialDestructor())
- continue;
- llvm::Value *LoadOfThis = LoadCXXThis();
- LValue LHS = EmitLValueForField(LoadOfThis, FD, false, 0);
- if (Array) {
- const llvm::Type *BasePtr = ConvertType(FieldType);
- BasePtr = llvm::PointerType::getUnqual(BasePtr);
- llvm::Value *BaseAddrPtr =
- Builder.CreateBitCast(LHS.getAddress(), BasePtr);
- EmitCXXAggrDestructorCall(FieldClassDecl->getDestructor(getContext()),
- Array, BaseAddrPtr);
- }
- else
- EmitCXXDestructorCall(FieldClassDecl->getDestructor(getContext()),
- Dtor_Complete, LHS.getAddress());
- } else {
- const RecordType *RT =
- DD->getAnyBaseClassToDestroy(BaseOrMember)->getAs<RecordType>();
- CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(RT->getDecl());
- if (BaseClassDecl->hasTrivialDestructor())
- continue;
- llvm::Value *V = GetAddressCXXOfBaseClass(LoadCXXThis(),
- ClassDecl, BaseClassDecl,
- /*NullCheckValue=*/false);
- EmitCXXDestructorCall(BaseClassDecl->getDestructor(getContext()),
- DtorType, V);
- }
- }
- if (DD->getNumBaseOrMemberDestructions() || DD->isTrivial())
- return;
- // Case of destructor synthesis with fields and base classes
- // which have non-trivial destructors. They must be destructed in
- // reverse order of their construction.
- llvm::SmallVector<FieldDecl *, 16> DestructedFields;
+ assert(!DD->isTrivial() &&
+ "Should not emit dtor epilogue for trivial dtor!");
- for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
- FieldEnd = ClassDecl->field_end();
- Field != FieldEnd; ++Field) {
- QualType FieldType = getContext().getCanonicalType((*Field)->getType());
- if (getContext().getAsConstantArrayType(FieldType))
- FieldType = getContext().getBaseElementType(FieldType);
- if (const RecordType *RT = FieldType->getAs<RecordType>()) {
- CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl());
- if (FieldClassDecl->hasTrivialDestructor())
+ const CXXRecordDecl *ClassDecl = DD->getParent();
+
+ // Collect the fields.
+ llvm::SmallVector<const FieldDecl *, 16> FieldDecls;
+ for (CXXRecordDecl::field_iterator I = ClassDecl->field_begin(),
+ E = ClassDecl->field_end(); I != E; ++I) {
+ const FieldDecl *Field = *I;
+
+ QualType FieldType = getContext().getCanonicalType(Field->getType());
+ FieldType = getContext().getBaseElementType(FieldType);
+
+ const RecordType *RT = FieldType->getAs<RecordType>();
+ if (!RT)
+ continue;
+
+ CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl());
+ if (FieldClassDecl->hasTrivialDestructor())
continue;
- DestructedFields.push_back(*Field);
- }
+
+ FieldDecls.push_back(Field);
}
- if (!DestructedFields.empty())
- for (int i = DestructedFields.size() -1; i >= 0; --i) {
- FieldDecl *Field = DestructedFields[i];
- QualType FieldType = Field->getType();
- const ConstantArrayType *Array =
- getContext().getAsConstantArrayType(FieldType);
- if (Array)
- FieldType = getContext().getBaseElementType(FieldType);
- const RecordType *RT = FieldType->getAs<RecordType>();
- CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl());
- llvm::Value *LoadOfThis = LoadCXXThis();
- LValue LHS = EmitLValueForField(LoadOfThis, Field, false, 0);
- if (Array) {
- const llvm::Type *BasePtr = ConvertType(FieldType);
- BasePtr = llvm::PointerType::getUnqual(BasePtr);
- llvm::Value *BaseAddrPtr =
+
+ // Now destroy the fields.
+ for (size_t i = FieldDecls.size(); i > 0; --i) {
+ const FieldDecl *Field = FieldDecls[i - 1];
+
+ QualType FieldType = Field->getType();
+ const ConstantArrayType *Array =
+ getContext().getAsConstantArrayType(FieldType);
+ if (Array)
+ FieldType = getContext().getBaseElementType(FieldType);
+
+ const RecordType *RT = FieldType->getAs<RecordType>();
+ CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl());
+
+ llvm::Value *ThisPtr = LoadCXXThis();
+
+ LValue LHS = EmitLValueForField(ThisPtr, Field,
+ /*isUnion=*/false,
+ // FIXME: Qualifiers?
+ /*CVRQualifiers=*/0);
+ if (Array) {
+ const llvm::Type *BasePtr = ConvertType(FieldType);
+ BasePtr = llvm::PointerType::getUnqual(BasePtr);
+ llvm::Value *BaseAddrPtr =
Builder.CreateBitCast(LHS.getAddress(), BasePtr);
- EmitCXXAggrDestructorCall(FieldClassDecl->getDestructor(getContext()),
- Array, BaseAddrPtr);
- }
- else
- EmitCXXDestructorCall(FieldClassDecl->getDestructor(getContext()),
- Dtor_Complete, LHS.getAddress());
- }
+ EmitCXXAggrDestructorCall(FieldClassDecl->getDestructor(getContext()),
+ Array, BaseAddrPtr);
+ } else
+ EmitCXXDestructorCall(FieldClassDecl->getDestructor(getContext()),
+ Dtor_Complete, LHS.getAddress());
+ }
- llvm::SmallVector<CXXRecordDecl*, 4> DestructedBases;
- for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin();
- Base != ClassDecl->bases_end(); ++Base) {
- // FIXME. copy assignment of virtual base NYI
- if (Base->isVirtual())
+ // Destroy non-virtual bases.
+ for (CXXRecordDecl::reverse_base_class_const_iterator I =
+ ClassDecl->bases_rbegin(), E = ClassDecl->bases_rend(); I != E; ++I) {
+ const CXXBaseSpecifier &Base = *I;
+
+ // Ignore virtual bases.
+ if (Base.isVirtual())
continue;
-
+
CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+ = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
+
+ // Ignore trivial destructors.
if (BaseClassDecl->hasTrivialDestructor())
continue;
- DestructedBases.push_back(BaseClassDecl);
- }
- if (DestructedBases.empty())
- return;
- for (int i = DestructedBases.size() -1; i >= 0; --i) {
- CXXRecordDecl *BaseClassDecl = DestructedBases[i];
+
llvm::Value *V = GetAddressCXXOfBaseClass(LoadCXXThis(),
- ClassDecl,BaseClassDecl,
+ ClassDecl, BaseClassDecl,
/*NullCheckValue=*/false);
EmitCXXDestructorCall(BaseClassDecl->getDestructor(getContext()),
- Dtor_Complete, V);
+ Dtor_Base, V);
}
+
+ // If we're emitting a base destructor, we don't want to emit calls to the
+ // virtual bases.
+ if (DtorType == Dtor_Base)
+ return;
+
+ // FIXME: Handle virtual bases.
+ for (CXXRecordDecl::reverse_base_class_const_iterator I =
+ ClassDecl->vbases_rbegin(), E = ClassDecl->vbases_rend(); I != E; ++I) {
+ assert(false && "FIXME: Handle virtual bases.");
+ }
+
+ // If we have a deleting destructor, emit a call to the delete operator.
+ if (DtorType == Dtor_Deleting)
+ EmitDeleteCall(DD->getOperatorDelete(), LoadCXXThis(),
+ getContext().getTagDeclType(ClassDecl));
}
void CodeGenFunction::SynthesizeDefaultDestructor(const CXXDestructorDecl *Dtor,
CXXDtorType DtorType,
llvm::Function *Fn,
const FunctionArgList &Args) {
-
- const CXXRecordDecl *ClassDecl = Dtor->getParent();
- assert(!ClassDecl->hasUserDeclaredDestructor() &&
+ assert(!Dtor->getParent()->hasUserDeclaredDestructor() &&
"SynthesizeDefaultDestructor - destructor has user declaration");
- (void) ClassDecl;
StartFunction(GlobalDecl(Dtor, DtorType), Dtor->getResultType(), Fn, Args,
SourceLocation());
+
EmitDtorEpilogue(Dtor, DtorType);
FinishFunction();
}
-// FIXME: Move this to CGCXXStmt.cpp
+// FIXME: Move this to CGStmtCXX.cpp
void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) {
// FIXME: We need to do more here.
EmitStmt(S.getTryBlock());
diff --git a/lib/CodeGen/CGCXXClass.cpp b/lib/CodeGen/CGCXXClass.cpp
index 56a28fc9a007..533aabc8616e 100644
--- a/lib/CodeGen/CGCXXClass.cpp
+++ b/lib/CodeGen/CGCXXClass.cpp
@@ -31,6 +31,9 @@ ComputeNonVirtualBaseClassOffset(ASTContext &Context, CXXBasePaths &Paths,
const ASTRecordLayout &Layout = Context.getASTRecordLayout(Element.Class);
const CXXBaseSpecifier *BS = Element.Base;
+ // FIXME: enable test3 from virt.cc to not abort.
+ if (BS->isVirtual())
+ return 0;
assert(!BS->isVirtual() && "Should not see virtual bases here!");
const CXXRecordDecl *Base =
diff --git a/lib/CodeGen/CGCXXExpr.cpp b/lib/CodeGen/CGCXXExpr.cpp
index 2d62df6c58a4..cd7d21b3b951 100644
--- a/lib/CodeGen/CGCXXExpr.cpp
+++ b/lib/CodeGen/CGCXXExpr.cpp
@@ -218,6 +218,7 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
if (NullCheckResult) {
Builder.CreateBr(NewEnd);
+ NewNotNull = Builder.GetInsertBlock();
EmitBlock(NewNull);
Builder.CreateBr(NewEnd);
EmitBlock(NewEnd);
@@ -233,12 +234,35 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
return NewPtr;
}
-void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) {
- if (E->isArrayForm()) {
- ErrorUnsupported(E, "delete[] expression");
- return;
- };
+void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD,
+ llvm::Value *Ptr,
+ QualType DeleteTy) {
+ const FunctionProtoType *DeleteFTy =
+ DeleteFD->getType()->getAs<FunctionProtoType>();
+
+ CallArgList DeleteArgs;
+
+ QualType ArgTy = DeleteFTy->getArgType(0);
+ llvm::Value *DeletePtr = Builder.CreateBitCast(Ptr, ConvertType(ArgTy));
+ DeleteArgs.push_back(std::make_pair(RValue::get(DeletePtr), ArgTy));
+
+ if (DeleteFTy->getNumArgs() == 2) {
+ QualType SizeTy = DeleteFTy->getArgType(1);
+ uint64_t SizeVal = getContext().getTypeSize(DeleteTy) / 8;
+ llvm::Constant *Size = llvm::ConstantInt::get(ConvertType(SizeTy),
+ SizeVal);
+ DeleteArgs.push_back(std::make_pair(RValue::get(Size), SizeTy));
+ }
+
+ // Emit the call to delete.
+ EmitCall(CGM.getTypes().getFunctionInfo(DeleteFTy->getResultType(),
+ DeleteArgs),
+ CGM.GetAddrOfFunction(DeleteFD),
+ DeleteArgs, DeleteFD);
+}
+void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) {
+
// Get at the argument before we performed the implicit conversion
// to void*.
const Expr *Arg = E->getArgument();
@@ -264,41 +288,237 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) {
Builder.CreateCondBr(IsNull, DeleteEnd, DeleteNotNull);
EmitBlock(DeleteNotNull);
-
+
+ bool ShouldCallDelete = true;
+
// Call the destructor if necessary.
if (const RecordType *RT = DeleteTy->getAs<RecordType>()) {
if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
if (!RD->hasTrivialDestructor()) {
const CXXDestructorDecl *Dtor = RD->getDestructor(getContext());
- if (Dtor->isVirtual()) {
+ if (E->isArrayForm()) {
+ QualType SizeTy = getContext().getSizeType();
+ uint64_t CookiePadding = std::max(getContext().getTypeSize(SizeTy),
+ static_cast<uint64_t>(getContext().getTypeAlign(DeleteTy))) / 8;
+ if (CookiePadding) {
+ llvm::Type *Ptr8Ty =
+ llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0);
+ uint64_t CookieOffset =
+ CookiePadding - getContext().getTypeSize(SizeTy) / 8;
+ llvm::Value *AllocatedObjectPtr =
+ Builder.CreateConstInBoundsGEP1_64(
+ Builder.CreateBitCast(Ptr, Ptr8Ty), -CookiePadding);
+ llvm::Value *NumElementsPtr =
+ Builder.CreateConstInBoundsGEP1_64(AllocatedObjectPtr,
+ CookieOffset);
+ NumElementsPtr = Builder.CreateBitCast(NumElementsPtr,
+ ConvertType(SizeTy)->getPointerTo());
+
+ llvm::Value *NumElements =
+ Builder.CreateLoad(NumElementsPtr);
+ NumElements =
+ Builder.CreateIntCast(NumElements,
+ llvm::Type::getInt64Ty(VMContext), false,
+ "count.tmp");
+ EmitCXXAggrDestructorCall(Dtor, NumElements, Ptr);
+ Ptr = AllocatedObjectPtr;
+ }
+ }
+ else if (Dtor->isVirtual()) {
const llvm::Type *Ty =
CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(Dtor),
/*isVariadic=*/false);
- llvm::Value *Callee = BuildVirtualCall(Dtor, Ptr, Ty);
+ llvm::Value *Callee = BuildVirtualCall(Dtor, Dtor_Deleting, Ptr, Ty);
EmitCXXMemberCall(Dtor, Callee, Ptr, 0, 0);
+
+ // The dtor took care of deleting the object.
+ ShouldCallDelete = false;
} else
EmitCXXDestructorCall(Dtor, Dtor_Complete, Ptr);
}
}
}
- // Call delete.
- FunctionDecl *DeleteFD = E->getOperatorDelete();
- const FunctionProtoType *DeleteFTy =
- DeleteFD->getType()->getAs<FunctionProtoType>();
+ if (ShouldCallDelete)
+ EmitDeleteCall(E->getOperatorDelete(), Ptr, DeleteTy);
- CallArgList DeleteArgs;
+ EmitBlock(DeleteEnd);
+}
- QualType ArgTy = DeleteFTy->getArgType(0);
- llvm::Value *DeletePtr = Builder.CreateBitCast(Ptr, ConvertType(ArgTy));
- DeleteArgs.push_back(std::make_pair(RValue::get(DeletePtr), ArgTy));
+llvm::Value * CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) {
+ QualType Ty = E->getType();
+ const llvm::Type *LTy = ConvertType(Ty)->getPointerTo();
+ if (E->isTypeOperand()) {
+ Ty = E->getTypeOperand();
+ CanQualType CanTy = CGM.getContext().getCanonicalType(Ty);
+ Ty = CanTy.getUnqualifiedType().getNonReferenceType();
+ if (const RecordType *RT = Ty->getAs<RecordType>()) {
+ const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+ if (RD->isPolymorphic())
+ return Builder.CreateBitCast(CGM.GenerateRttiRef(RD), LTy);
+ return Builder.CreateBitCast(CGM.GenerateRtti(RD), LTy);
+ }
+ return Builder.CreateBitCast(CGM.GenerateRttiNonClass(Ty), LTy);
+ }
+ Expr *subE = E->getExprOperand();
+ Ty = subE->getType();
+ CanQualType CanTy = CGM.getContext().getCanonicalType(Ty);
+ Ty = CanTy.getUnqualifiedType().getNonReferenceType();
+ if (const RecordType *RT = Ty->getAs<RecordType>()) {
+ const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
+ if (RD->isPolymorphic()) {
+ // FIXME: if subE is an lvalue do
+ LValue Obj = EmitLValue(subE);
+ llvm::Value *This = Obj.getAddress();
+ LTy = LTy->getPointerTo()->getPointerTo();
+ llvm::Value *V = Builder.CreateBitCast(This, LTy);
+ // We need to do a zero check for *p, unless it has NonNullAttr.
+ // FIXME: PointerType->hasAttr<NonNullAttr>()
+ bool CanBeZero = false;
+ if (UnaryOperator *UO = dyn_cast<UnaryOperator>(subE->IgnoreParens()))
+ if (UO->getOpcode() == UnaryOperator::Deref)
+ CanBeZero = true;
+ if (CanBeZero) {
+ llvm::BasicBlock *NonZeroBlock = createBasicBlock();
+ llvm::BasicBlock *ZeroBlock = createBasicBlock();
+
+ llvm::Value *Zero = llvm::Constant::getNullValue(LTy);
+ Builder.CreateCondBr(Builder.CreateICmpNE(V, Zero),
+ NonZeroBlock, ZeroBlock);
+ EmitBlock(ZeroBlock);
+ /// Call __cxa_bad_typeid
+ const llvm::Type *ResultType = llvm::Type::getVoidTy(VMContext);
+ const llvm::FunctionType *FTy;
+ FTy = llvm::FunctionType::get(ResultType, false);
+ llvm::Value *F = CGM.CreateRuntimeFunction(FTy, "__cxa_bad_typeid");
+ Builder.CreateCall(F)->setDoesNotReturn();
+ Builder.CreateUnreachable();
+ EmitBlock(NonZeroBlock);
+ }
+ V = Builder.CreateLoad(V, "vtable");
+ V = Builder.CreateConstInBoundsGEP1_64(V, -1ULL);
+ V = Builder.CreateLoad(V);
+ return V;
+ }
+ return Builder.CreateBitCast(CGM.GenerateRtti(RD), LTy);
+ }
+ return Builder.CreateBitCast(CGM.GenerateRttiNonClass(Ty), LTy);
+}
- // Emit the call to delete.
- EmitCall(CGM.getTypes().getFunctionInfo(DeleteFTy->getResultType(),
- DeleteArgs),
- CGM.GetAddrOfFunction(DeleteFD),
- DeleteArgs, DeleteFD);
+llvm::Value *CodeGenFunction::EmitDynamicCast(llvm::Value *V,
+ const CXXDynamicCastExpr *DCE) {
+ QualType CastTy = DCE->getTypeAsWritten();
+ QualType InnerType = CastTy->getPointeeType();
+ QualType ArgTy = DCE->getSubExpr()->getType();
+ const llvm::Type *LArgTy = ConvertType(ArgTy);
+ const llvm::Type *LTy = ConvertType(DCE->getType());
+
+ bool CanBeZero = false;
+ bool ToVoid = false;
+ bool ThrowOnBad = false;
+ if (CastTy->isPointerType()) {
+ // FIXME: if PointerType->hasAttr<NonNullAttr>(), we don't set this
+ CanBeZero = true;
+ if (InnerType->isVoidType())
+ ToVoid = true;
+ } else {
+ LTy = LTy->getPointerTo();
+ ThrowOnBad = true;
+ }
- EmitBlock(DeleteEnd);
+ CXXRecordDecl *SrcTy;
+ QualType Ty = ArgTy;
+ if (ArgTy.getTypePtr()->isPointerType()
+ || ArgTy.getTypePtr()->isReferenceType())
+ Ty = Ty.getTypePtr()->getPointeeType();
+ CanQualType CanTy = CGM.getContext().getCanonicalType(Ty);
+ Ty = CanTy.getUnqualifiedType();
+ SrcTy = cast<CXXRecordDecl>(Ty->getAs<RecordType>()->getDecl());
+
+ llvm::BasicBlock *ContBlock = createBasicBlock();
+ llvm::BasicBlock *NullBlock = 0;
+ llvm::BasicBlock *NonZeroBlock = 0;
+ if (CanBeZero) {
+ NonZeroBlock = createBasicBlock();
+ NullBlock = createBasicBlock();
+ llvm::Value *Zero = llvm::Constant::getNullValue(LArgTy);
+ Builder.CreateCondBr(Builder.CreateICmpNE(V, Zero),
+ NonZeroBlock, NullBlock);
+ EmitBlock(NonZeroBlock);
+ }
+
+ llvm::BasicBlock *BadCastBlock = 0;
+
+ const llvm::Type *PtrDiffTy = ConvertType(getContext().getSizeType());
+
+ // See if this is a dynamic_cast(void*)
+ if (ToVoid) {
+ llvm::Value *This = V;
+ V = Builder.CreateBitCast(This, PtrDiffTy->getPointerTo()->getPointerTo());
+ V = Builder.CreateLoad(V, "vtable");
+ V = Builder.CreateConstInBoundsGEP1_64(V, -2ULL);
+ V = Builder.CreateLoad(V, "offset to top");
+ This = Builder.CreateBitCast(This, llvm::Type::getInt8PtrTy(VMContext));
+ V = Builder.CreateInBoundsGEP(This, V);
+ V = Builder.CreateBitCast(V, LTy);
+ } else {
+ /// Call __dynamic_cast
+ const llvm::Type *ResultType = llvm::Type::getInt8PtrTy(VMContext);
+ const llvm::FunctionType *FTy;
+ std::vector<const llvm::Type*> ArgTys;
+ const llvm::Type *PtrToInt8Ty
+ = llvm::Type::getInt8Ty(VMContext)->getPointerTo();
+ ArgTys.push_back(PtrToInt8Ty);
+ ArgTys.push_back(PtrToInt8Ty);
+ ArgTys.push_back(PtrToInt8Ty);
+ ArgTys.push_back(PtrDiffTy);
+ FTy = llvm::FunctionType::get(ResultType, ArgTys, false);
+ CXXRecordDecl *DstTy;
+ Ty = CastTy.getTypePtr()->getPointeeType();
+ CanTy = CGM.getContext().getCanonicalType(Ty);
+ Ty = CanTy.getUnqualifiedType();
+ DstTy = cast<CXXRecordDecl>(Ty->getAs<RecordType>()->getDecl());
+
+ // FIXME: Calculate better hint.
+ llvm::Value *hint = llvm::ConstantInt::get(PtrDiffTy, -1ULL);
+ llvm::Value *SrcArg = CGM.GenerateRttiRef(SrcTy);
+ llvm::Value *DstArg = CGM.GenerateRttiRef(DstTy);
+ V = Builder.CreateBitCast(V, PtrToInt8Ty);
+ V = Builder.CreateCall4(CGM.CreateRuntimeFunction(FTy, "__dynamic_cast"),
+ V, SrcArg, DstArg, hint);
+ V = Builder.CreateBitCast(V, LTy);
+
+ if (ThrowOnBad) {
+ BadCastBlock = createBasicBlock();
+
+ llvm::Value *Zero = llvm::Constant::getNullValue(LTy);
+ Builder.CreateCondBr(Builder.CreateICmpNE(V, Zero),
+ ContBlock, BadCastBlock);
+ EmitBlock(BadCastBlock);
+ /// Call __cxa_bad_cast
+ ResultType = llvm::Type::getVoidTy(VMContext);
+ const llvm::FunctionType *FBadTy;
+ FBadTy = llvm::FunctionType::get(ResultType, false);
+ llvm::Value *F = CGM.CreateRuntimeFunction(FBadTy, "__cxa_bad_cast");
+ Builder.CreateCall(F)->setDoesNotReturn();
+ Builder.CreateUnreachable();
+ }
+ }
+
+ if (CanBeZero) {
+ Builder.CreateBr(ContBlock);
+ EmitBlock(NullBlock);
+ Builder.CreateBr(ContBlock);
+ }
+ EmitBlock(ContBlock);
+ if (CanBeZero) {
+ llvm::PHINode *PHI = Builder.CreatePHI(LTy);
+ PHI->reserveOperandSpace(2);
+ PHI->addIncoming(V, NonZeroBlock);
+ PHI->addIncoming(llvm::Constant::getNullValue(LTy), NullBlock);
+ V = PHI;
+ }
+
+ return V;
}
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index 06cd05cc75a8..d0c7d03f20ef 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -19,7 +19,7 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
-#include "clang/Frontend/CompileOptions.h"
+#include "clang/CodeGen/CodeGenOptions.h"
#include "llvm/Attributes.h"
#include "llvm/Support/CallSite.h"
#include "llvm/Target/TargetData.h"
@@ -441,18 +441,13 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
RetAttrs |= llvm::Attribute::NoAlias;
}
- if (CompileOpts.OptimizeSize)
+ if (CodeGenOpts.OptimizeSize)
FuncAttrs |= llvm::Attribute::OptimizeForSize;
- if (CompileOpts.DisableRedZone)
+ if (CodeGenOpts.DisableRedZone)
FuncAttrs |= llvm::Attribute::NoRedZone;
- if (CompileOpts.NoImplicitFloat)
+ if (CodeGenOpts.NoImplicitFloat)
FuncAttrs |= llvm::Attribute::NoImplicitFloat;
- if (Features.getStackProtectorMode() == LangOptions::SSPOn)
- FuncAttrs |= llvm::Attribute::StackProtect;
- else if (Features.getStackProtectorMode() == LangOptions::SSPReq)
- FuncAttrs |= llvm::Attribute::StackProtectReq;
-
QualType RetTy = FI.getReturnType();
unsigned Index = 1;
const ABIArgInfo &RetAI = FI.getReturnInfo();
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index 1b01e1537b42..055166721085 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -21,7 +21,7 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/Version.h"
-#include "clang/Frontend/CompileOptions.h"
+#include "clang/CodeGen/CodeGenOptions.h"
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Instructions.h"
@@ -57,7 +57,7 @@ llvm::DIDescriptor CGDebugInfo::getContext(const VarDecl *Decl,
if (Decl->getDeclContext()->isFunctionOrMethod()) {
// Find the last subprogram in region stack.
for (unsigned RI = RegionStack.size(), RE = 0; RI != RE; --RI) {
- llvm::DIDescriptor R = RegionStack[RI - 1];
+ llvm::DIDescriptor R(RegionStack[RI - 1]);
if (R.isSubprogram())
return R;
}
@@ -136,10 +136,11 @@ llvm::DICompileUnit CGDebugInfo::getOrCreateCompileUnit(SourceLocation Loc) {
RuntimeVers = LO.ObjCNonFragileABI ? 2 : 1;
// Create new compile unit.
- return Unit = DebugFactory.CreateCompileUnit(LangTag, AbsFileName.getLast(),
- AbsFileName.getDirname(),
- Producer, isMain, isOptimized,
- Flags, RuntimeVers);
+ return Unit = DebugFactory.CreateCompileUnit(LangTag,
+ AbsFileName.getLast().c_str(),
+ AbsFileName.getDirname().c_str(),
+ Producer.c_str(), isMain,
+ isOptimized, Flags, RuntimeVers);
}
/// CreateType - Get the Basic type from the cache or create a new
@@ -178,8 +179,6 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT,
BT->getName(M->getContext().getLangOptions()),
Unit, 0, Size, Align,
Offset, /*flags*/ 0, Encoding);
-
- TypeCache[QualType(BT, 0).getAsOpaquePtr()] = DbgTy.getNode();
return DbgTy;
}
@@ -198,7 +197,6 @@ llvm::DIType CGDebugInfo::CreateType(const ComplexType *Ty,
DebugFactory.CreateBasicType(Unit, "complex",
Unit, 0, Size, Align,
Offset, /*flags*/ 0, Encoding);
- TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = DbgTy.getNode();
return DbgTy;
}
@@ -236,38 +234,41 @@ llvm::DIType CGDebugInfo::CreateQualifiedType(QualType Ty, llvm::DICompileUnit U
llvm::DIType DbgTy =
DebugFactory.CreateDerivedType(Tag, Unit, "", llvm::DICompileUnit(),
0, 0, 0, 0, 0, FromTy);
- TypeCache[Ty.getAsOpaquePtr()] = DbgTy.getNode();
return DbgTy;
}
llvm::DIType CGDebugInfo::CreateType(const ObjCObjectPointerType *Ty,
llvm::DICompileUnit Unit) {
- llvm::DIType EltTy = getOrCreateType(Ty->getPointeeType(), Unit);
-
- // Bit size, align and offset of the type.
- uint64_t Size = M->getContext().getTypeSize(Ty);
- uint64_t Align = M->getContext().getTypeAlign(Ty);
-
llvm::DIType DbgTy =
- DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_pointer_type, Unit,
- "", llvm::DICompileUnit(),
- 0, Size, Align, 0, 0, EltTy);
- TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = DbgTy.getNode();
+ CreatePointerLikeType(llvm::dwarf::DW_TAG_pointer_type, Ty,
+ Ty->getPointeeType(), Unit);
return DbgTy;
}
llvm::DIType CGDebugInfo::CreateType(const PointerType *Ty,
llvm::DICompileUnit Unit) {
- llvm::DIType EltTy = getOrCreateType(Ty->getPointeeType(), Unit);
+ return CreatePointerLikeType(llvm::dwarf::DW_TAG_pointer_type, Ty,
+ Ty->getPointeeType(), Unit);
+}
+
+llvm::DIType CGDebugInfo::CreatePointerLikeType(unsigned Tag,
+ const Type *Ty,
+ QualType PointeeTy,
+ llvm::DICompileUnit Unit) {
+ llvm::DIType EltTy = getOrCreateType(PointeeTy, Unit);
// Bit size, align and offset of the type.
- uint64_t Size = M->getContext().getTypeSize(Ty);
+
+ // Size is always the size of a pointer. We can't use getTypeSize here
+ // because that does not return the correct value for references.
+ uint64_t Size =
+ M->getContext().Target.getPointerWidth(PointeeTy.getAddressSpace());
uint64_t Align = M->getContext().getTypeAlign(Ty);
return
- DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_pointer_type, Unit,
- "", llvm::DICompileUnit(),
+ DebugFactory.CreateDerivedType(Tag, Unit, "", llvm::DICompileUnit(),
0, Size, Align, 0, 0, EltTy);
+
}
llvm::DIType CGDebugInfo::CreateType(const BlockPointerType *Ty,
@@ -407,7 +408,6 @@ llvm::DIType CGDebugInfo::CreateType(const TypedefType *Ty,
// We don't set size information, but do specify where the typedef was
// declared.
- std::string TyName = Ty->getDecl()->getNameAsString();
SourceLocation DefLoc = Ty->getDecl()->getLocation();
llvm::DICompileUnit DefUnit = getOrCreateCompileUnit(DefLoc);
@@ -417,8 +417,8 @@ llvm::DIType CGDebugInfo::CreateType(const TypedefType *Ty,
llvm::DIType DbgTy =
DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_typedef, Unit,
- TyName, DefUnit, Line, 0, 0, 0, 0, Src);
- TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = DbgTy.getNode();
+ Ty->getDecl()->getNameAsCString(),
+ DefUnit, Line, 0, 0, 0, 0, Src);
return DbgTy;
}
@@ -446,7 +446,6 @@ llvm::DIType CGDebugInfo::CreateType(const FunctionType *Ty,
Unit, "", llvm::DICompileUnit(),
0, 0, 0, 0, 0,
llvm::DIType(), EltTypeArray);
- TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = DbgTy.getNode();
return DbgTy;
}
@@ -468,8 +467,6 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty,
SourceManager &SM = M->getContext().getSourceManager();
// Get overall information about the record type for the debug info.
- std::string Name = Decl->getNameAsString();
-
PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation());
llvm::DICompileUnit DefUnit;
unsigned Line = 0;
@@ -485,13 +482,15 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty,
// 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, Name, DefUnit, Line, 0, 0, 0, 0,
+ DebugFactory.CreateCompositeType(Tag, Unit, Decl->getNameAsString().data(),
+ DefUnit, Line, 0, 0, 0, 0,
llvm::DIType(), llvm::DIArray());
// If this is just a forward declaration, return it.
if (!Decl->getDefinition(M->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();
@@ -508,10 +507,10 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty,
FieldDecl *Field = *I;
llvm::DIType FieldTy = getOrCreateType(Field->getType(), Unit);
- std::string FieldName = Field->getNameAsString();
+ const char *FieldName = Field->getNameAsCString();
// Ignore unnamed fields.
- if (FieldName.empty())
+ if (!FieldName)
continue;
// Get the location for the field.
@@ -559,15 +558,13 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty,
uint64_t Align = M->getContext().getTypeAlign(Ty);
llvm::DICompositeType RealDecl =
- DebugFactory.CreateCompositeType(Tag, Unit, Name, DefUnit, Line, Size,
- Align, 0, 0, llvm::DIType(), Elements);
-
- // Update TypeCache.
- TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = RealDecl.getNode();
+ DebugFactory.CreateCompositeType(Tag, Unit, Decl->getNameAsString().data(),
+ DefUnit, Line, Size, Align, 0, 0,
+ llvm::DIType(), Elements);
// Now that we have a real decl for the struct, replace anything using the
// old decl with the new one. This will recursively update the debug info.
- FwdDecl.replaceAllUsesWith(RealDecl);
+ llvm::DIDerivedType(FwdDeclNode).replaceAllUsesWith(RealDecl);
return RealDecl;
}
@@ -581,8 +578,6 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
SourceManager &SM = M->getContext().getSourceManager();
// Get overall information about the record type for the debug info.
- std::string Name = Decl->getNameAsString();
-
llvm::DICompileUnit DefUnit = getOrCreateCompileUnit(Decl->getLocation());
PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation());
unsigned Line = PLoc.isInvalid() ? 0 : PLoc.getLine();
@@ -597,7 +592,8 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
// 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, Name, DefUnit, Line, 0, 0, 0, 0,
+ DebugFactory.CreateCompositeType(Tag, Unit, Decl->getNameAsCString(),
+ DefUnit, Line, 0, 0, 0, 0,
llvm::DIType(), llvm::DIArray(),
RuntimeLang);
@@ -605,6 +601,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
if (Decl->isForwardDecl())
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();
@@ -631,10 +628,10 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
ObjCIvarDecl *Field = *I;
llvm::DIType FieldTy = getOrCreateType(Field->getType(), Unit);
- std::string FieldName = Field->getNameAsString();
+ const char *FieldName = Field->getNameAsCString();
// Ignore unnamed fields.
- if (FieldName.empty())
+ if (!FieldName)
continue;
// Get the location for the field.
@@ -685,16 +682,13 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
uint64_t Align = M->getContext().getTypeAlign(Ty);
llvm::DICompositeType RealDecl =
- DebugFactory.CreateCompositeType(Tag, Unit, Name, DefUnit, Line, Size,
- Align, 0, 0, llvm::DIType(), Elements,
- RuntimeLang);
-
- // Update TypeCache.
- TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = RealDecl.getNode();
+ DebugFactory.CreateCompositeType(Tag, Unit, Decl->getNameAsCString(), DefUnit,
+ Line, Size, Align, 0, 0, llvm::DIType(),
+ Elements, RuntimeLang);
// Now that we have a real decl for the struct, replace anything using the
// old decl with the new one. This will recursively update the debug info.
- FwdDecl.replaceAllUsesWith(RealDecl);
+ llvm::DIDerivedType(FwdDeclNode).replaceAllUsesWith(RealDecl);
return RealDecl;
}
@@ -709,7 +703,7 @@ llvm::DIType CGDebugInfo::CreateType(const EnumType *Ty,
for (EnumDecl::enumerator_iterator
Enum = Decl->enumerator_begin(), EnumEnd = Decl->enumerator_end();
Enum != EnumEnd; ++Enum) {
- Enumerators.push_back(DebugFactory.CreateEnumerator(Enum->getNameAsString(),
+ Enumerators.push_back(DebugFactory.CreateEnumerator(Enum->getNameAsCString(),
Enum->getInitVal().getZExtValue()));
}
@@ -717,7 +711,6 @@ llvm::DIType CGDebugInfo::CreateType(const EnumType *Ty,
llvm::DIArray EltArray =
DebugFactory.GetOrCreateArray(Enumerators.data(), Enumerators.size());
- std::string EnumName = Decl->getNameAsString();
SourceLocation DefLoc = Decl->getLocation();
llvm::DICompileUnit DefUnit = getOrCreateCompileUnit(DefLoc);
SourceManager &SM = M->getContext().getSourceManager();
@@ -735,11 +728,9 @@ llvm::DIType CGDebugInfo::CreateType(const EnumType *Ty,
llvm::DIType DbgTy =
DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_enumeration_type,
- Unit, EnumName, DefUnit, Line,
+ Unit, Decl->getNameAsCString(), DefUnit, Line,
Size, Align, 0, 0,
llvm::DIType(), EltArray);
-
- TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = DbgTy.getNode();
return DbgTy;
}
@@ -797,11 +788,37 @@ llvm::DIType CGDebugInfo::CreateType(const ArrayType *Ty,
0, Size, Align, 0, 0,
getOrCreateType(EltTy, Unit),
SubscriptArray);
-
- TypeCache[QualType(Ty, 0).getAsOpaquePtr()] = DbgTy.getNode();
return DbgTy;
}
+llvm::DIType CGDebugInfo::CreateType(const LValueReferenceType *Ty,
+ llvm::DICompileUnit Unit) {
+ return CreatePointerLikeType(llvm::dwarf::DW_TAG_reference_type,
+ Ty, Ty->getPointeeType(), Unit);
+}
+
+static QualType CanonicalizeTypeForDebugInfo(QualType T) {
+ switch (T->getTypeClass()) {
+ default:
+ return T;
+ case Type::TemplateSpecialization:
+ return cast<TemplateSpecializationType>(T)->desugar();
+ case Type::TypeOfExpr: {
+ TypeOfExprType *Ty = cast<TypeOfExprType>(T);
+ return CanonicalizeTypeForDebugInfo(Ty->getUnderlyingExpr()->getType());
+ }
+ case Type::TypeOf:
+ return cast<TypeOfType>(T)->getUnderlyingType();
+ case Type::Decltype:
+ return cast<DecltypeType>(T)->getUnderlyingType();
+ case Type::QualifiedName:
+ return cast<QualifiedNameType>(T)->getNamedType();
+ case Type::SubstTemplateTypeParm:
+ return cast<SubstTemplateTypeParmType>(T)->getReplacementType();
+ case Type::Elaborated:
+ return cast<ElaboratedType>(T)->getUnderlyingType();
+ }
+}
/// getOrCreateType - Get the type from the cache or create a new
/// one if necessary.
@@ -810,6 +827,9 @@ llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty,
if (Ty.isNull())
return llvm::DIType();
+ // Canonicalize the type.
+ Ty = CanonicalizeTypeForDebugInfo(Ty);
+
// Check for existing entry.
std::map<void *, llvm::WeakVH>::iterator it =
TypeCache.find(Ty.getAsOpaquePtr());
@@ -821,15 +841,17 @@ llvm::DIType CGDebugInfo::getOrCreateType(QualType Ty,
// Otherwise create the type.
llvm::DIType Res = CreateTypeNode(Ty, Unit);
+
+ // And update the type cache.
+ TypeCache[Ty.getAsOpaquePtr()] = Res.getNode();
return Res;
}
-/// getOrCreateTypeNode - Get the type metadata node from the cache or create a
-/// new one if necessary.
+/// CreateTypeNode - Create a new debug type node.
llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty,
llvm::DICompileUnit Unit) {
// Handle qualifiers, which recursively handles what they refer to.
- if (Ty.hasQualifiers())
+ if (Ty.hasLocalQualifiers())
return CreateQualifiedType(Ty, Unit);
// Work out details of type.
@@ -841,16 +863,13 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty,
#include "clang/AST/TypeNodes.def"
assert(false && "Dependent types cannot show up in debug information");
- default:
- case Type::LValueReference:
- case Type::RValueReference:
- case Type::Vector:
+ // FIXME: Handle these.
case Type::ExtVector:
+ case Type::Vector:
case Type::FixedWidthInt:
- case Type::MemberPointer:
- case Type::TemplateSpecialization:
- case Type::QualifiedName:
- // Unsupported types
+ return llvm::DIType();
+ default:
+ assert(false && "Unhandled type class!");
return llvm::DIType();
case Type::ObjCObjectPointer:
return CreateType(cast<ObjCObjectPointerType>(Ty), Unit);
@@ -868,21 +887,14 @@ llvm::DIType CGDebugInfo::CreateTypeNode(QualType Ty,
case Type::FunctionProto:
case Type::FunctionNoProto:
return CreateType(cast<FunctionType>(Ty), Unit);
- case Type::Elaborated:
- return getOrCreateType(cast<ElaboratedType>(Ty)->getUnderlyingType(),
- Unit);
-
case Type::ConstantArray:
case Type::VariableArray:
case Type::IncompleteArray:
return CreateType(cast<ArrayType>(Ty), Unit);
- case Type::TypeOfExpr:
- return getOrCreateType(cast<TypeOfExprType>(Ty)->getUnderlyingExpr()
- ->getType(), Unit);
- case Type::TypeOf:
- return getOrCreateType(cast<TypeOfType>(Ty)->getUnderlyingType(), Unit);
- case Type::Decltype:
- return getOrCreateType(cast<DecltypeType>(Ty)->getUnderlyingType(), Unit);
+
+ case Type::LValueReference:
+ return CreateType(cast<LValueReferenceType>(Ty), Unit);
+
}
}
@@ -909,12 +921,8 @@ void CGDebugInfo::EmitFunctionStart(const char *Name, QualType FnType,
getOrCreateType(FnType, Unit),
Fn->hasInternalLinkage(), true/*definition*/);
-#ifndef ATTACH_DEBUG_INFO_TO_AN_INSN
- DebugFactory.InsertSubprogramStart(SP, Builder.GetInsertBlock());
-#endif
-
// Push function on region stack.
- RegionStack.push_back(SP);
+ RegionStack.push_back(SP.getNode());
}
@@ -936,31 +944,23 @@ void CGDebugInfo::EmitStopPoint(llvm::Function *Fn, CGBuilderTy &Builder) {
llvm::DICompileUnit Unit = getOrCreateCompileUnit(CurLoc);
PresumedLoc PLoc = SM.getPresumedLoc(CurLoc);
-#ifdef ATTACH_DEBUG_INFO_TO_AN_INSN
- llvm::DIDescriptor DR = RegionStack.back();
+ llvm::DIDescriptor DR(RegionStack.back());
llvm::DIScope DS = llvm::DIScope(DR.getNode());
llvm::DILocation DO(NULL);
llvm::DILocation DL =
DebugFactory.CreateLocation(PLoc.getLine(), PLoc.getColumn(),
DS, DO);
Builder.SetCurrentDebugLocation(DL.getNode());
-#else
- DebugFactory.InsertStopPoint(Unit, PLoc.getLine(), PLoc.getColumn(),
- Builder.GetInsertBlock());
-#endif
}
/// EmitRegionStart- Constructs the debug code for entering a declarative
/// region - "llvm.dbg.region.start.".
void CGDebugInfo::EmitRegionStart(llvm::Function *Fn, CGBuilderTy &Builder) {
- llvm::DIDescriptor D;
- if (!RegionStack.empty())
- D = RegionStack.back();
- D = DebugFactory.CreateLexicalBlock(D);
- RegionStack.push_back(D);
-#ifndef ATTACH_DEBUG_INFO_TO_AN_INSN
- DebugFactory.InsertRegionStart(D, Builder.GetInsertBlock());
-#endif
+ llvm::DIDescriptor D =
+ DebugFactory.CreateLexicalBlock(RegionStack.empty() ?
+ llvm::DIDescriptor() :
+ llvm::DIDescriptor(RegionStack.back()));
+ RegionStack.push_back(D.getNode());
}
/// EmitRegionEnd - Constructs the debug code for exiting a declarative
@@ -971,9 +971,6 @@ void CGDebugInfo::EmitRegionEnd(llvm::Function *Fn, CGBuilderTy &Builder) {
// Provide an region stop point.
EmitStopPoint(Fn, Builder);
-#ifndef ATTACH_DEBUG_INFO_TO_AN_INSN
- DebugFactory.InsertRegionEnd(RegionStack.back(), Builder.GetInsertBlock());
-#endif
RegionStack.pop_back();
}
@@ -985,8 +982,8 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag,
// Do not emit variable debug information while generating optimized code.
// The llvm optimizer and code generator are not yet ready to support
// optimized code debugging.
- const CompileOptions &CO = M->getCompileOpts();
- if (CO.OptimizationLevel)
+ const CodeGenOptions &CGO = M->getCodeGenOpts();
+ if (CGO.OptimizationLevel)
return;
llvm::DICompileUnit Unit = getOrCreateCompileUnit(Decl->getLocation());
@@ -1105,10 +1102,9 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag,
FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
FieldSize = M->getContext().getTypeSize(FType);
FieldAlign = Align*8;
- std::string Name = Decl->getNameAsString();
FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
- Name, DefUnit,
+ Decl->getNameAsCString(), DefUnit,
0, FieldSize, FieldAlign,
FieldOffset, 0, FieldTy);
EltTys.push_back(FieldTy);
@@ -1128,18 +1124,28 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag,
SourceManager &SM = M->getContext().getSourceManager();
PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation());
unsigned Line = 0;
- if (!PLoc.isInvalid())
+ unsigned Column = 0;
+ if (!PLoc.isInvalid()) {
Line = PLoc.getLine();
- else
+ Column = PLoc.getColumn();
+ } else {
Unit = llvm::DICompileUnit();
-
+ }
// Create the descriptor for the variable.
llvm::DIVariable D =
- DebugFactory.CreateVariable(Tag, RegionStack.back(),Decl->getNameAsString(),
+ DebugFactory.CreateVariable(Tag, llvm::DIDescriptor(RegionStack.back()),
+ Decl->getNameAsCString(),
Unit, Line, Ty);
// Insert an llvm.dbg.declare into the current block.
- DebugFactory.InsertDeclare(Storage, D, Builder.GetInsertBlock());
+ llvm::Instruction *Call =
+ DebugFactory.InsertDeclare(Storage, D, Builder.GetInsertBlock());
+
+ llvm::DIScope DS(RegionStack.back());
+ llvm::DILocation DO(NULL);
+ llvm::DILocation DL =
+ DebugFactory.CreateLocation(Line, Column, DS, DO);
+ Builder.SetDebugLocation(Call, DL.getNode());
}
/// EmitDeclare - Emit local variable declaration debug info.
@@ -1152,8 +1158,8 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag,
// Do not emit variable debug information while generating optimized code.
// The llvm optimizer and code generator are not yet ready to support
// optimized code debugging.
- const CompileOptions &CO = M->getCompileOpts();
- if (CO.OptimizationLevel || Builder.GetInsertBlock() == 0)
+ const CodeGenOptions &CGO = M->getCodeGenOpts();
+ if (CGO.OptimizationLevel || Builder.GetInsertBlock() == 0)
return;
uint64_t XOffset = 0;
@@ -1273,11 +1279,10 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag,
FieldTy = CGDebugInfo::getOrCreateType(FType, Unit);
FieldSize = M->getContext().getTypeSize(FType);
FieldAlign = Align*8;
- std::string Name = Decl->getNameAsString();
XOffset = FieldOffset;
FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
- Name, DefUnit,
+ Decl->getNameAsCString(), DefUnit,
0, FieldSize, FieldAlign,
FieldOffset, 0, FieldTy);
EltTys.push_back(FieldTy);
@@ -1330,11 +1335,18 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag,
// Create the descriptor for the variable.
llvm::DIVariable D =
- DebugFactory.CreateComplexVariable(Tag, RegionStack.back(),
- Decl->getNameAsString(), Unit, Line, Ty,
+ DebugFactory.CreateComplexVariable(Tag, llvm::DIDescriptor(RegionStack.back()),
+ Decl->getNameAsCString(), Unit, Line, Ty,
addr);
// Insert an llvm.dbg.declare into the current block.
- DebugFactory.InsertDeclare(Storage, D, Builder.GetInsertPoint());
+ llvm::Instruction *Call =
+ DebugFactory.InsertDeclare(Storage, D, Builder.GetInsertPoint());
+
+ llvm::DIScope DS(RegionStack.back());
+ llvm::DILocation DO(NULL);
+ llvm::DILocation DL =
+ DebugFactory.CreateLocation(Line, PLoc.getColumn(), DS, DO);
+ Builder.SetDebugLocation(Call, DL.getNode());
}
void CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *Decl,
@@ -1362,21 +1374,12 @@ void CGDebugInfo::EmitDeclareOfArgVariable(const VarDecl *Decl, llvm::Value *AI,
void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
const VarDecl *Decl) {
- // Do not emit variable debug information while generating optimized code.
- // The llvm optimizer and code generator are not yet ready to support
- // optimized code debugging.
- const CompileOptions &CO = M->getCompileOpts();
- if (CO.OptimizationLevel)
- return;
-
// Create global variable debug descriptor.
llvm::DICompileUnit Unit = getOrCreateCompileUnit(Decl->getLocation());
SourceManager &SM = M->getContext().getSourceManager();
PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation());
unsigned LineNo = PLoc.isInvalid() ? 0 : PLoc.getLine();
- std::string Name = Var->getName();
-
QualType T = Decl->getType();
if (T->isIncompleteArrayType()) {
@@ -1389,9 +1392,9 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
T = M->getContext().getConstantArrayType(ET, ConstVal,
ArrayType::Normal, 0);
}
-
- DebugFactory.CreateGlobalVariable(getContext(Decl, Unit),
- Name, Name, Name, Unit, LineNo,
+ const char *DeclName = Decl->getNameAsCString();
+ DebugFactory.CreateGlobalVariable(getContext(Decl, Unit), DeclName, DeclName,
+ NULL, Unit, LineNo,
getOrCreateType(T, Unit),
Var->hasInternalLinkage(),
true/*definition*/, Var);
@@ -1406,7 +1409,7 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation());
unsigned LineNo = PLoc.isInvalid() ? 0 : PLoc.getLine();
- std::string Name = Decl->getNameAsString();
+ const char *Name = Decl->getNameAsCString();
QualType T = M->getContext().getObjCInterfaceType(Decl);
if (T->isIncompleteArrayType()) {
diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h
index 2e44e09d2590..af86e2b263fd 100644
--- a/lib/CodeGen/CGDebugInfo.h
+++ b/lib/CodeGen/CGDebugInfo.h
@@ -56,7 +56,7 @@ class CGDebugInfo {
bool BlockLiteralGenericSet;
llvm::DIType BlockLiteralGeneric;
- std::vector<llvm::DIDescriptor> RegionStack;
+ std::vector<llvm::TrackingVH<llvm::MDNode> > RegionStack;
/// Helper functions for getOrCreateType.
llvm::DIType CreateType(const BuiltinType *Ty, llvm::DICompileUnit U);
@@ -73,7 +73,11 @@ class CGDebugInfo {
llvm::DIType CreateType(const ObjCInterfaceType *Ty, llvm::DICompileUnit U);
llvm::DIType CreateType(const EnumType *Ty, llvm::DICompileUnit U);
llvm::DIType CreateType(const ArrayType *Ty, llvm::DICompileUnit U);
+ llvm::DIType CreateType(const LValueReferenceType *Ty, llvm::DICompileUnit U);
+ llvm::DIType CreatePointerLikeType(unsigned Tag,
+ const Type *Ty, QualType PointeeTy,
+ llvm::DICompileUnit U);
public:
CGDebugInfo(CodeGenModule *m);
~CGDebugInfo();
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index 2021ced31683..1d2040bae203 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -19,7 +19,7 @@
#include "clang/AST/DeclObjC.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
-#include "clang/Frontend/CompileOptions.h"
+#include "clang/CodeGen/CodeGenOptions.h"
#include "llvm/GlobalVariable.h"
#include "llvm/Intrinsics.h"
#include "llvm/Target/TargetData.h"
@@ -320,7 +320,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
// All constant structs and arrays should be global if
// their initializer is constant and if the element type is POD.
- if (CGM.getCompileOpts().MergeAllConstants) {
+ if (CGM.getCodeGenOpts().MergeAllConstants) {
if (Ty.isConstant(getContext())
&& (Ty->isArrayType() || Ty->isRecordType())
&& (D.getInit()
@@ -507,7 +507,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
// Handle CXX destruction of variables.
QualType DtorTy(Ty);
- if (const ArrayType *Array = DtorTy->getAs<ArrayType>())
+ while (const ArrayType *Array = getContext().getAsArrayType(DtorTy))
DtorTy = getContext().getBaseElementType(Array);
if (const RecordType *RT = DtorTy->getAs<RecordType>())
if (CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) {
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index d9dd70ac9e49..2a544c560931 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -267,6 +267,12 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
return EmitCXXBindTemporaryLValue(cast<CXXBindTemporaryExpr>(E));
case Expr::CXXExprWithTemporariesClass:
return EmitCXXExprWithTemporariesLValue(cast<CXXExprWithTemporaries>(E));
+ case Expr::CXXZeroInitValueExprClass:
+ return EmitNullInitializationLValue(cast<CXXZeroInitValueExpr>(E));
+ case Expr::CXXDefaultArgExprClass:
+ return EmitLValue(cast<CXXDefaultArgExpr>(E)->getExpr());
+ case Expr::CXXTypeidExprClass:
+ return EmitCXXTypeidLValue(cast<CXXTypeidExpr>(E));
case Expr::ObjCMessageExprClass:
return EmitObjCMessageExprLValue(cast<ObjCMessageExpr>(E));
@@ -303,8 +309,6 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
case Expr::CXXReinterpretCastExprClass:
case Expr::CXXConstCastExprClass:
return EmitCastLValue(cast<CastExpr>(E));
- case Expr::CXXZeroInitValueExprClass:
- return EmitNullInitializationLValue(cast<CXXZeroInitValueExpr>(E));
}
}
@@ -813,53 +817,53 @@ static void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E,
}
}
+static LValue EmitGlobalVarDeclLValue(CodeGenFunction &CGF,
+ const Expr *E, const VarDecl *VD) {
+ assert((VD->hasExternalStorage() || VD->isFileVarDecl()) &&
+ "Var decl must have external storage or be a file var decl!");
+
+ llvm::Value *V = CGF.CGM.GetAddrOfGlobalVar(VD);
+ if (VD->getType()->isReferenceType())
+ V = CGF.Builder.CreateLoad(V, "tmp");
+ LValue LV = LValue::MakeAddr(V, CGF.MakeQualifiers(E->getType()));
+ setObjCGCLValueClass(CGF.getContext(), E, LV);
+ return LV;
+}
+
LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
- const VarDecl *VD = dyn_cast<VarDecl>(E->getDecl());
-
- if (VD && (VD->isBlockVarDecl() || isa<ParmVarDecl>(VD) ||
- isa<ImplicitParamDecl>(VD))) {
- LValue LV;
- bool NonGCable = VD->hasLocalStorage() &&
- !VD->hasAttr<BlocksAttr>();
- if (VD->hasExternalStorage()) {
- llvm::Value *V = CGM.GetAddrOfGlobalVar(VD);
- if (VD->getType()->isReferenceType())
- V = Builder.CreateLoad(V, "tmp");
- LV = LValue::MakeAddr(V, MakeQualifiers(E->getType()));
- } else {
- llvm::Value *V = LocalDeclMap[VD];
- assert(V && "DeclRefExpr not entered in LocalDeclMap?");
-
- Qualifiers Quals = MakeQualifiers(E->getType());
- // local variables do not get their gc attribute set.
- // local static?
- if (NonGCable) Quals.removeObjCGCAttr();
-
- if (VD->hasAttr<BlocksAttr>()) {
- V = Builder.CreateStructGEP(V, 1, "forwarding");
- V = Builder.CreateLoad(V, false);
- V = Builder.CreateStructGEP(V, getByRefValueLLVMField(VD),
- VD->getNameAsString());
- }
- if (VD->getType()->isReferenceType())
- V = Builder.CreateLoad(V, "tmp");
- LV = LValue::MakeAddr(V, Quals);
+ const NamedDecl *ND = E->getDecl();
+
+ if (const VarDecl *VD = dyn_cast<VarDecl>(ND)) {
+
+ // Check if this is a global variable.
+ if (VD->hasExternalStorage() || VD->isFileVarDecl())
+ return EmitGlobalVarDeclLValue(*this, E, VD);
+
+ bool NonGCable = VD->hasLocalStorage() && !VD->hasAttr<BlocksAttr>();
+
+ llvm::Value *V = LocalDeclMap[VD];
+ assert(V && "DeclRefExpr not entered in LocalDeclMap?");
+
+ Qualifiers Quals = MakeQualifiers(E->getType());
+ // local variables do not get their gc attribute set.
+ // local static?
+ if (NonGCable) Quals.removeObjCGCAttr();
+
+ if (VD->hasAttr<BlocksAttr>()) {
+ V = Builder.CreateStructGEP(V, 1, "forwarding");
+ V = Builder.CreateLoad(V, false);
+ V = Builder.CreateStructGEP(V, getByRefValueLLVMField(VD),
+ VD->getNameAsString());
}
- LValue::SetObjCNonGC(LV, NonGCable);
- setObjCGCLValueClass(getContext(), E, LV);
- return LV;
- }
-
- if (VD && VD->isFileVarDecl()) {
- llvm::Value *V = CGM.GetAddrOfGlobalVar(VD);
if (VD->getType()->isReferenceType())
V = Builder.CreateLoad(V, "tmp");
- LValue LV = LValue::MakeAddr(V, MakeQualifiers(E->getType()));
+ LValue LV = LValue::MakeAddr(V, Quals);
+ LValue::SetObjCNonGC(LV, NonGCable);
setObjCGCLValueClass(getContext(), E, LV);
return LV;
}
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(E->getDecl())) {
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
llvm::Value* V = CGM.GetAddrOfFunction(FD);
if (!FD->hasPrototype()) {
if (const FunctionProtoType *Proto =
@@ -876,20 +880,15 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
return LValue::MakeAddr(V, MakeQualifiers(E->getType()));
}
- if (const ImplicitParamDecl *IPD = dyn_cast<ImplicitParamDecl>(E->getDecl())){
- llvm::Value *V = LocalDeclMap[IPD];
- assert(V && "BlockVarDecl not entered in LocalDeclMap?");
- return LValue::MakeAddr(V, MakeQualifiers(E->getType()));
- }
-
if (E->getQualifier()) {
// FIXME: the qualifier check does not seem sufficient here
- return EmitPointerToDataMemberLValue(E);
+ return EmitPointerToDataMemberLValue(cast<FieldDecl>(ND));
}
- assert(0 && "Unimp declref");
- //an invalid LValue, but the assert will
- //ensure that this point is never reached.
+ assert(false && "Unhandled DeclRefExpr");
+
+ // an invalid LValue, but the assert will
+ // ensure that this point is never reached.
return LValue();
}
@@ -924,13 +923,17 @@ LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) {
return LV;
}
case UnaryOperator::Real:
- case UnaryOperator::Imag:
+ case UnaryOperator::Imag: {
LValue LV = EmitLValue(E->getSubExpr());
unsigned Idx = E->getOpcode() == UnaryOperator::Imag;
return LValue::MakeAddr(Builder.CreateStructGEP(LV.getAddress(),
Idx, "idx"),
MakeQualifiers(ExprTy));
}
+ case UnaryOperator::PreInc:
+ case UnaryOperator::PreDec:
+ return EmitUnsupportedLValue(E, "pre-inc/dec expression");
+ }
}
LValue CodeGenFunction::EmitStringLiteralLValue(const StringLiteral *E) {
@@ -1151,18 +1154,24 @@ LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) {
BaseQuals = BaseTy.getQualifiers();
}
- FieldDecl *Field = dyn_cast<FieldDecl>(E->getMemberDecl());
- // FIXME: Handle non-field member expressions
- assert(Field && "No code generation for non-field member references");
- LValue MemExpLV = EmitLValueForField(BaseValue, Field, isUnion,
- BaseQuals.getCVRQualifiers());
- LValue::SetObjCNonGC(MemExpLV, isNonGC);
- setObjCGCLValueClass(getContext(), E, MemExpLV);
- return MemExpLV;
+ NamedDecl *ND = E->getMemberDecl();
+ if (FieldDecl *Field = dyn_cast<FieldDecl>(ND)) {
+ LValue LV = EmitLValueForField(BaseValue, Field, isUnion,
+ BaseQuals.getCVRQualifiers());
+ LValue::SetObjCNonGC(LV, isNonGC);
+ setObjCGCLValueClass(getContext(), E, LV);
+ return LV;
+ }
+
+ if (VarDecl *VD = dyn_cast<VarDecl>(ND))
+ return EmitGlobalVarDeclLValue(*this, E, VD);
+
+ assert(false && "Unhandled member declaration!");
+ return LValue();
}
LValue CodeGenFunction::EmitLValueForBitfield(llvm::Value* BaseValue,
- FieldDecl* Field,
+ const FieldDecl* Field,
unsigned CVRQualifiers) {
CodeGenTypes::BitFieldInfo Info = CGM.getTypes().getBitFieldInfo(Field);
@@ -1187,7 +1196,7 @@ LValue CodeGenFunction::EmitLValueForBitfield(llvm::Value* BaseValue,
}
LValue CodeGenFunction::EmitLValueForField(llvm::Value* BaseValue,
- FieldDecl* Field,
+ const FieldDecl* Field,
bool isUnion,
unsigned CVRQualifiers) {
if (Field->isBitField())
@@ -1281,22 +1290,26 @@ CodeGenFunction::EmitConditionalOperatorLValue(const ConditionalOperator* E) {
return LValue::MakeAddr(Temp, MakeQualifiers(E->getType()));
}
-/// EmitCastLValue - Casts are never lvalues. If a cast is needed by the code
-/// generator in an lvalue context, then it must mean that we need the address
-/// of an aggregate in order to access one of its fields. This can happen for
-/// all the reasons that casts are permitted with aggregate result, including
-/// noop aggregate casts, and cast from scalar to union.
+/// EmitCastLValue - Casts are never lvalues unless that cast is a dynamic_cast.
+/// If the cast is a dynamic_cast, we can have the usual lvalue result,
+/// otherwise if a cast is needed by the code generator in an lvalue context,
+/// then it must mean that we need the address of an aggregate in order to
+/// access one of its fields. This can happen for all the reasons that casts
+/// are permitted with aggregate result, including noop aggregate casts, and
+/// cast from scalar to union.
LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
switch (E->getCastKind()) {
default:
- // If this is an lvalue cast, treat it as a no-op.
- // FIXME: We shouldn't need to check for this explicitly!
- if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E))
- if (ICE->isLvalueCast())
- return EmitLValue(E->getSubExpr());
-
- assert(0 && "Unhandled cast!");
-
+ return EmitUnsupportedLValue(E, "unexpected cast lvalue");
+
+ case CastExpr::CK_Dynamic: {
+ LValue LV = EmitLValue(E->getSubExpr());
+ llvm::Value *V = LV.getAddress();
+ const CXXDynamicCastExpr *DCE = cast<CXXDynamicCastExpr>(E);
+ return LValue::MakeAddr(EmitDynamicCast(V, DCE),
+ MakeQualifiers(E->getType()));
+ }
+
case CastExpr::CK_NoOp:
case CastExpr::CK_ConstructorConversion:
case CastExpr::CK_UserDefinedConversion:
@@ -1320,13 +1333,24 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
return LValue::MakeAddr(Base, MakeQualifiers(E->getType()));
}
-
case CastExpr::CK_ToUnion: {
llvm::Value *Temp = CreateTempAlloca(ConvertType(E->getType()));
EmitAnyExpr(E->getSubExpr(), Temp, false);
return LValue::MakeAddr(Temp, MakeQualifiers(E->getType()));
- }
+ }
+ case CastExpr::CK_BaseToDerived: {
+ return EmitUnsupportedLValue(E, "base-to-derived cast lvalue");
+ }
+ case CastExpr::CK_BitCast: {
+ // This must be a reinterpret_cast (or c-style equivalent).
+ const ExplicitCastExpr *CE = cast<ExplicitCastExpr>(E);
+
+ LValue LV = EmitLValue(E->getSubExpr());
+ llvm::Value *V = Builder.CreateBitCast(LV.getAddress(),
+ ConvertType(CE->getTypeAsWritten()));
+ return LValue::MakeAddr(V, MakeQualifiers(E->getType()));
+ }
}
}
@@ -1449,6 +1473,12 @@ LValue CodeGenFunction::EmitCXXConstructLValue(const CXXConstructExpr *E) {
}
LValue
+CodeGenFunction::EmitCXXTypeidLValue(const CXXTypeidExpr *E) {
+ llvm::Value *Temp = EmitCXXTypeidExpr(E);
+ return LValue::MakeAddr(Temp, MakeQualifiers(E->getType()));
+}
+
+LValue
CodeGenFunction::EmitCXXBindTemporaryLValue(const CXXBindTemporaryExpr *E) {
LValue LV = EmitLValue(E->getSubExpr());
PushCXXTemporary(E->getTemporary(), LV.getAddress());
@@ -1526,19 +1556,18 @@ LValue CodeGenFunction::EmitStmtExprLValue(const StmtExpr *E) {
}
-LValue CodeGenFunction::EmitPointerToDataMemberLValue(const DeclRefExpr *E) {
- const FieldDecl *Field = cast<FieldDecl>(E->getDecl());
+LValue CodeGenFunction::EmitPointerToDataMemberLValue(const FieldDecl *Field) {
const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Field->getDeclContext());
QualType NNSpecTy =
getContext().getCanonicalType(
getContext().getTypeDeclType(const_cast<CXXRecordDecl*>(ClassDecl)));
NNSpecTy = getContext().getPointerType(NNSpecTy);
llvm::Value *V = llvm::Constant::getNullValue(ConvertType(NNSpecTy));
- LValue MemExpLV = EmitLValueForField(V, const_cast<FieldDecl*>(Field),
- /*isUnion*/false, /*Qualifiers*/0);
+ LValue MemExpLV = EmitLValueForField(V, Field, /*isUnion=*/false,
+ /*Qualifiers=*/0);
const llvm::Type *ResultType = ConvertType(getContext().getPointerDiffType());
V = Builder.CreatePtrToInt(MemExpLV.getAddress(), ResultType, "datamember");
- return LValue::MakeAddr(V, MakeQualifiers(E->getType()));
+ return LValue::MakeAddr(V, MakeQualifiers(Field->getType()));
}
RValue CodeGenFunction::EmitCall(llvm::Value *Callee, QualType CalleeType,
@@ -1571,16 +1600,14 @@ RValue CodeGenFunction::EmitCall(llvm::Value *Callee, QualType CalleeType,
LValue CodeGenFunction::
EmitPointerToDataMemberBinaryExpr(const BinaryOperator *E) {
- llvm::Value *BaseV = EmitLValue(E->getLHS()).getAddress();
+ llvm::Value *BaseV;
if (E->getOpcode() == BinaryOperator::PtrMemI)
- BaseV = Builder.CreateLoad(BaseV, "indir.ptr");
+ BaseV = EmitScalarExpr(E->getLHS());
+ else
+ BaseV = EmitLValue(E->getLHS()).getAddress();
const llvm::Type *i8Ty = llvm::Type::getInt8PtrTy(getLLVMContext());
BaseV = Builder.CreateBitCast(BaseV, i8Ty);
- LValue RHSLV = EmitLValue(E->getRHS());
- llvm::Value *OffsetV =
- EmitLoadOfLValue(RHSLV, E->getRHS()->getType()).getScalarVal();
- const llvm::Type* ResultType = ConvertType(getContext().getPointerDiffType());
- OffsetV = Builder.CreateBitCast(OffsetV, ResultType);
+ llvm::Value *OffsetV = EmitScalarExpr(E->getRHS());
llvm::Value *AddV = Builder.CreateInBoundsGEP(BaseV, OffsetV, "add.ptr");
QualType Ty = E->getRHS()->getType();
diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp
index 901f867a5913..0e10368ab04e 100644
--- a/lib/CodeGen/CGExprAgg.cpp
+++ b/lib/CodeGen/CGExprAgg.cpp
@@ -114,6 +114,7 @@ public:
void VisitCXXConstructExpr(const CXXConstructExpr *E);
void VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E);
void VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *E);
+ void VisitCXXTypeidExpr(CXXTypeidExpr *E) { EmitAggLoadOfLValue(E); }
void VisitVAArgExpr(VAArgExpr *E);
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp
index 9145d92128a1..40b845dba050 100644
--- a/lib/CodeGen/CGExprConstant.cpp
+++ b/lib/CodeGen/CGExprConstant.cpp
@@ -262,7 +262,7 @@ class VISIBILITY_HIDDEN ConstStructBuilder {
uint64_t NumBytes =
AlignedElementOffsetInBytes - ElementOffsetInBytes;
- const llvm::Type *Ty = llvm::Type::getInt8Ty(CGF->getLLVMContext());
+ const llvm::Type *Ty = llvm::Type::getInt8Ty(CGM.getLLVMContext());
if (NumBytes > 1)
Ty = llvm::ArrayType::get(Ty, NumBytes);
@@ -766,27 +766,21 @@ public:
return llvm::ConstantExpr::getBitCast(C, ConvertType(E->getType()));
}
case Expr::PredefinedExprClass: {
- // __func__/__FUNCTION__ -> "". __PRETTY_FUNCTION__ -> "top level".
- std::string Str;
- if (cast<PredefinedExpr>(E)->getIdentType() ==
- PredefinedExpr::PrettyFunction)
- Str = "top level";
+ unsigned Type = cast<PredefinedExpr>(E)->getIdentType();
+ if (CGF) {
+ LValue Res = CGF->EmitPredefinedFunctionName(Type);
+ return cast<llvm::Constant>(Res.getAddress());
+ } else if (Type == PredefinedExpr::PrettyFunction) {
+ return CGM.GetAddrOfConstantCString("top level", ".tmp");
+ }
- return CGM.GetAddrOfConstantCString(Str, ".tmp");
+ return CGM.GetAddrOfConstantCString("", ".tmp");
}
case Expr::AddrLabelExprClass: {
assert(CGF && "Invalid address of label expression outside function.");
-#ifndef USEINDIRECTBRANCH
- unsigned id =
- CGF->GetIDForAddrOfLabel(cast<AddrLabelExpr>(E)->getLabel());
- llvm::Constant *C =
- llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), id);
- return llvm::ConstantExpr::getIntToPtr(C, ConvertType(E->getType()));
-#else
llvm::Constant *Ptr =
CGF->GetAddrOfLabel(cast<AddrLabelExpr>(E)->getLabel());
return llvm::ConstantExpr::getBitCast(Ptr, ConvertType(E->getType()));
-#endif
}
case Expr::CallExprClass: {
CallExpr* CE = cast<CallExpr>(E);
@@ -827,9 +821,7 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E,
else
Success = E->Evaluate(Result, Context);
- if (Success) {
- assert(!Result.HasSideEffects &&
- "Constant expr should not have any side effects!");
+ if (Success && !Result.HasSideEffects) {
switch (Result.Val.getKind()) {
case APValue::Uninitialized:
assert(0 && "Constant expressions should be initialized.");
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index 96b58d8995ae..e9bbf35fcd8d 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -135,16 +135,8 @@ public:
}
Value *VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E);
Value *VisitAddrLabelExpr(const AddrLabelExpr *E) {
-#ifndef USEINDIRECTBRANCH
- llvm::Value *V =
- llvm::ConstantInt::get(llvm::Type::getInt32Ty(CGF.getLLVMContext()),
- CGF.GetIDForAddrOfLabel(E->getLabel()));
-
- return Builder.CreateIntToPtr(V, ConvertType(E->getType()));
-#else
llvm::Value *V = CGF.GetAddrOfLabel(E->getLabel());
return Builder.CreateBitCast(V, ConvertType(E->getType()));
-#endif
}
// l-values.
@@ -356,6 +348,9 @@ public:
Value *VisitBinLOr (const BinaryOperator *E);
Value *VisitBinComma (const BinaryOperator *E);
+ Value *VisitBinPtrMemD(const Expr *E) { return EmitLoadOfLValue(E); }
+ Value *VisitBinPtrMemI(const Expr *E) { return EmitLoadOfLValue(E); }
+
// Other Operators.
Value *VisitBlockExpr(const BlockExpr *BE);
Value *VisitConditionalOperator(const ConditionalOperator *CO);
@@ -547,13 +542,6 @@ EmitComplexToScalarConversion(CodeGenFunction::ComplexPairTy Src,
//===----------------------------------------------------------------------===//
Value *ScalarExprEmitter::VisitExpr(Expr *E) {
- if (const BinaryOperator *BExpr = dyn_cast<BinaryOperator>(E))
- if (BExpr->getOpcode() == BinaryOperator::PtrMemD) {
- LValue LV = CGF.EmitPointerToDataMemberBinaryExpr(BExpr);
- Value *InVal = CGF.EmitLoadOfLValue(LV, E->getType()).getScalarVal();
- return InVal;
- }
-
CGF.ErrorUnsupported(E, "scalar expression");
if (E->getType()->isVoidType())
return 0;
@@ -773,49 +761,20 @@ Value *ScalarExprEmitter::EmitCastExpr(const CastExpr *CE) {
switch (Kind) {
default:
- // FIXME: Assert here.
- // assert(0 && "Unhandled cast kind!");
+ //return CGF.ErrorUnsupported(E, "type of cast");
break;
+
case CastExpr::CK_Unknown:
- // FIXME: We should really assert here - Unknown casts should never get
- // as far as to codegen.
+ //assert(0 && "Unknown cast kind!");
break;
+
case CastExpr::CK_BitCast: {
Value *Src = Visit(const_cast<Expr*>(E));
return Builder.CreateBitCast(Src, ConvertType(DestTy));
}
- case CastExpr::CK_ArrayToPointerDecay: {
- assert(E->getType()->isArrayType() &&
- "Array to pointer decay must have array source type!");
-
- Value *V = EmitLValue(E).getAddress(); // Bitfields can't be arrays.
+ case CastExpr::CK_NoOp:
+ return Visit(const_cast<Expr*>(E));
- // Note that VLA pointers are always decayed, so we don't need to do
- // anything here.
- if (!E->getType()->isVariableArrayType()) {
- assert(isa<llvm::PointerType>(V->getType()) && "Expected pointer");
- assert(isa<llvm::ArrayType>(cast<llvm::PointerType>(V->getType())
- ->getElementType()) &&
- "Expected pointer to array");
- V = Builder.CreateStructGEP(V, 0, "arraydecay");
- }
-
- // The resultant pointer type can be implicitly casted to other pointer
- // types as well (e.g. void*) and can be implicitly converted to integer.
- const llvm::Type *DestLTy = ConvertType(DestTy);
- if (V->getType() != DestLTy) {
- if (isa<llvm::PointerType>(DestLTy))
- V = Builder.CreateBitCast(V, DestLTy, "ptrconv");
- else {
- assert(isa<llvm::IntegerType>(DestLTy) && "Unknown array decay");
- V = Builder.CreatePtrToInt(V, DestLTy, "ptrconv");
- }
- }
- return V;
- }
- case CastExpr::CK_NullToMemberPointer:
- return CGF.CGM.EmitNullConstant(DestTy);
-
case CastExpr::CK_DerivedToBase: {
const RecordType *DerivedClassTy =
E->getType()->getAs<PointerType>()->getPointeeType()->getAs<RecordType>();
@@ -841,6 +800,33 @@ Value *ScalarExprEmitter::EmitCastExpr(const CastExpr *CE) {
return CGF.GetAddressCXXOfBaseClass(Src, DerivedClassDecl, BaseClassDecl,
NullCheckValue);
}
+ case CastExpr::CK_ToUnion: {
+ assert(0 && "Should be unreachable!");
+ break;
+ }
+ case CastExpr::CK_ArrayToPointerDecay: {
+ assert(E->getType()->isArrayType() &&
+ "Array to pointer decay must have array source type!");
+
+ Value *V = EmitLValue(E).getAddress(); // Bitfields can't be arrays.
+
+ // Note that VLA pointers are always decayed, so we don't need to do
+ // anything here.
+ if (!E->getType()->isVariableArrayType()) {
+ assert(isa<llvm::PointerType>(V->getType()) && "Expected pointer");
+ assert(isa<llvm::ArrayType>(cast<llvm::PointerType>(V->getType())
+ ->getElementType()) &&
+ "Expected pointer to array");
+ V = Builder.CreateStructGEP(V, 0, "arraydecay");
+ }
+
+ return V;
+ }
+ case CastExpr::CK_FunctionToPointerDecay:
+ return EmitLValue(E).getAddress();
+
+ case CastExpr::CK_NullToMemberPointer:
+ return CGF.CGM.EmitNullConstant(DestTy);
case CastExpr::CK_IntegralToPointer: {
Value *Src = Visit(const_cast<Expr*>(E));
@@ -860,7 +846,40 @@ Value *ScalarExprEmitter::EmitCastExpr(const CastExpr *CE) {
Value *Src = Visit(const_cast<Expr*>(E));
return Builder.CreatePtrToInt(Src, ConvertType(DestTy));
}
-
+
+ case CastExpr::CK_ToVoid: {
+ CGF.EmitAnyExpr(E, 0, false, true);
+ return 0;
+ }
+
+ case CastExpr::CK_Dynamic: {
+ Value *V = Visit(const_cast<Expr*>(E));
+ const CXXDynamicCastExpr *DCE = cast<CXXDynamicCastExpr>(CE);
+ return CGF.EmitDynamicCast(V, DCE);
+ }
+
+ case CastExpr::CK_VectorSplat: {
+ const llvm::Type *DstTy = ConvertType(DestTy);
+ Value *Elt = Visit(const_cast<Expr*>(E));
+
+ // Insert the element in element zero of an undef vector
+ llvm::Value *UnV = llvm::UndefValue::get(DstTy);
+ llvm::Value *Idx =
+ llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), 0);
+ UnV = Builder.CreateInsertElement(UnV, Elt, Idx, "tmp");
+
+ // Splat the element across to all elements
+ llvm::SmallVector<llvm::Constant*, 16> Args;
+ unsigned NumElements = cast<llvm::VectorType>(DstTy)->getNumElements();
+ for (unsigned i = 0; i < NumElements; i++)
+ Args.push_back(llvm::ConstantInt::get(
+ llvm::Type::getInt32Ty(VMContext), 0));
+
+ llvm::Constant *Mask = llvm::ConstantVector::get(&Args[0], NumElements);
+ llvm::Value *Yay = Builder.CreateShuffleVector(UnV, UnV, Mask, "splat");
+ return Yay;
+ }
+
}
// Handle cases where the source is an non-complex type.
diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp
index f348bfffcb86..b431daa958f0 100644
--- a/lib/CodeGen/CGObjCGNU.cpp
+++ b/lib/CodeGen/CGObjCGNU.cpp
@@ -608,6 +608,8 @@ llvm::Constant *CGObjCGNU::GenerateIvarList(
const llvm::SmallVectorImpl<llvm::Constant *> &IvarNames,
const llvm::SmallVectorImpl<llvm::Constant *> &IvarTypes,
const llvm::SmallVectorImpl<llvm::Constant *> &IvarOffsets) {
+ if (IvarNames.size() == 0)
+ return NULLPtr;
// Get the method structure type.
llvm::StructType *ObjCIvarTy = llvm::StructType::get(VMContext,
PtrToInt8Ty,
@@ -1189,8 +1191,8 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
Context.getObjCEncodingForType((*iter)->getType(), TypeStr);
IvarTypes.push_back(MakeConstantString(TypeStr));
// Get the offset
- uint64_t Offset = 0;
uint64_t BaseOffset = ComputeIvarBaseOffset(CGM, ClassDecl, *iter);
+ uint64_t Offset = BaseOffset;
if (CGM.getContext().getLangOptions().ObjCNonFragileABI) {
Offset = BaseOffset - superInstanceSize;
}
@@ -1301,7 +1303,7 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
}
//Generate metaclass for class methods
llvm::Constant *MetaClassStruct = GenerateClassStructure(NULLPtr,
- NULLPtr, 0x12L, /*name*/"", 0, Zeros[0], GenerateIvarList(
+ NULLPtr, 0x12L, ClassName.c_str(), 0, Zeros[0], GenerateIvarList(
empty, empty, empty), ClassMethodList, NULLPtr, NULLPtr, NULLPtr);
// Generate the class structure
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index 9b2f4a1faee7..4355e66feecd 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -991,6 +991,9 @@ private:
/// for the given class.
llvm::Value *EmitClassRef(CGBuilderTy &Builder,
const ObjCInterfaceDecl *ID);
+
+ /// EmitSuperClassRef - Emits reference to class's main metadata class.
+ llvm::Value *EmitSuperClassRef(const ObjCInterfaceDecl *ID);
CodeGen::RValue EmitMessageSend(CodeGen::CodeGenFunction &CGF,
QualType ResultType,
@@ -1167,6 +1170,9 @@ private:
/// legacy messaging dispatch.
llvm::DenseSet<Selector> NonLegacyDispatchMethods;
+ /// DefinedMetaClasses - List of defined meta-classes.
+ std::vector<llvm::GlobalValue*> DefinedMetaClasses;
+
/// LegacyDispatchedSelector - Returns true if SEL is not in the list of
/// NonLegacyDispatchMethods; false otherwise.
bool LegacyDispatchedSelector(Selector Sel);
@@ -1485,8 +1491,13 @@ CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
llvm::Value *Super = CGF.Builder.CreateLoad(SuperPtr);
Target = Super;
}
- } else {
+ }
+ else if (isCategoryImpl)
Target = EmitClassRef(CGF.Builder, Class->getSuperClass());
+ else {
+ llvm::Value *ClassPtr = EmitSuperClassRef(Class);
+ ClassPtr = CGF.Builder.CreateStructGEP(ClassPtr, 1);
+ Target = CGF.Builder.CreateLoad(ClassPtr);
}
// FIXME: We shouldn't need to do this cast, rectify the ASTContext and
// ObjCTypes types.
@@ -2051,11 +2062,22 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) {
Values[11] = EmitClassExtension(ID);
llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ClassTy,
Values);
-
- llvm::GlobalVariable *GV =
- CreateMetadataVar("\01L_OBJC_CLASS_" + ClassName, Init,
- "__OBJC,__class,regular,no_dead_strip",
- 4, true);
+ std::string Name("\01L_OBJC_CLASS_");
+ Name += ClassName;
+ const char *Section = "__OBJC,__class,regular,no_dead_strip";
+ // Check for a forward reference.
+ llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name);
+ if (GV) {
+ assert(GV->getType()->getElementType() == ObjCTypes.ClassTy &&
+ "Forward metaclass reference has incorrect type.");
+ GV->setLinkage(llvm::GlobalValue::InternalLinkage);
+ GV->setInitializer(Init);
+ GV->setSection(Section);
+ GV->setAlignment(4);
+ CGM.AddUsedGlobal(GV);
+ }
+ else
+ GV = CreateMetadataVar(Name, Init, Section, 4, true);
DefinedClasses.push_back(GV);
}
@@ -2154,6 +2176,22 @@ llvm::Constant *CGObjCMac::EmitMetaClassRef(const ObjCInterfaceDecl *ID) {
}
}
+llvm::Value *CGObjCMac::EmitSuperClassRef(const ObjCInterfaceDecl *ID) {
+ std::string Name = "\01L_OBJC_CLASS_" + ID->getNameAsString();
+
+ if (llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name,
+ true)) {
+ assert(GV->getType()->getElementType() == ObjCTypes.ClassTy &&
+ "Forward class metadata reference has incorrect type.");
+ return GV;
+ } else {
+ return new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassTy, false,
+ llvm::GlobalValue::ExternalLinkage,
+ 0,
+ Name);
+ }
+}
+
/*
struct objc_class_ext {
uint32_t size;
@@ -4095,6 +4133,25 @@ void CGObjCNonFragileABIMac::FinishNonFragileABIModule() {
AddModuleClassList(DefinedClasses,
"\01L_OBJC_LABEL_CLASS_$",
"__DATA, __objc_classlist, regular, no_dead_strip");
+
+ bool hasWeakImport = false;
+ for (unsigned i = 0; i < DefinedClasses.size(); i++) {
+ llvm::GlobalValue *IMPLGV = DefinedClasses[i];
+ if (IMPLGV->getLinkage() != llvm::GlobalValue::ExternalWeakLinkage)
+ continue;
+ IMPLGV->setLinkage(llvm::GlobalValue::ExternalLinkage);
+ hasWeakImport = true;
+ }
+
+ if (hasWeakImport) {
+ for (unsigned i = 0; i < DefinedMetaClasses.size(); i++) {
+ llvm::GlobalValue *IMPLGV = DefinedMetaClasses[i];
+ if (IMPLGV->getLinkage() != llvm::GlobalValue::ExternalWeakLinkage)
+ continue;
+ IMPLGV->setLinkage(llvm::GlobalValue::ExternalLinkage);
+ }
+ }
+
AddModuleClassList(DefinedNonLazyClasses,
"\01L_OBJC_LABEL_NONLAZY_CLASS_$",
"__DATA, __objc_nlclslist, regular, no_dead_strip");
@@ -4384,6 +4441,8 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
std::string SuperClassName =
ObjCMetaClassName + ID->getClassInterface()->getSuperClass()->getNameAsString();
SuperClassGV = GetClassGlobal(SuperClassName);
+ if (ID->getClassInterface()->getSuperClass()->hasAttr<WeakImportAttr>())
+ SuperClassGV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
}
llvm::GlobalVariable *CLASS_RO_GV = BuildClassRoTInitializer(flags,
InstanceStart,
@@ -4392,6 +4451,7 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
llvm::GlobalVariable *MetaTClass =
BuildClassMetaData(TClassName, IsAGV, SuperClassGV, CLASS_RO_GV,
classIsHidden);
+ DefinedMetaClasses.push_back(MetaTClass);
// Metadata for the class
flags = CLS;
@@ -4409,6 +4469,8 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) {
std::string RootClassName =
ID->getClassInterface()->getSuperClass()->getNameAsString();
SuperClassGV = GetClassGlobal(ObjCClassName + RootClassName);
+ if (ID->getClassInterface()->getSuperClass()->hasAttr<WeakImportAttr>())
+ SuperClassGV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
}
GetClassSizeInfo(ID, InstanceStart, InstanceSize);
CLASS_RO_GV = BuildClassRoTInitializer(flags,
@@ -4489,6 +4551,9 @@ void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) {
Values[0] = GetClassName(OCD->getIdentifier());
// meta-class entry symbol
llvm::GlobalVariable *ClassGV = GetClassGlobal(ExtClassName);
+ if (Interface->hasAttr<WeakImportAttr>())
+ ClassGV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
+
Values[1] = ClassGV;
std::vector<llvm::Constant*> Methods;
std::string MethodListName(Prefix);
@@ -5178,6 +5243,12 @@ llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CGBuilderTy &Builder,
/// decl.
llvm::Value *CGObjCNonFragileABIMac::GetClass(CGBuilderTy &Builder,
const ObjCInterfaceDecl *ID) {
+ if (ID->hasAttr<WeakImportAttr>()) {
+ std::string ClassName(getClassSymbolPrefix() + ID->getNameAsString());
+ llvm::GlobalVariable *ClassGV = GetClassGlobal(ClassName);
+ ClassGV->setLinkage(llvm::GlobalValue::ExternalWeakLinkage);
+ }
+
return EmitClassRef(Builder, ID);
}
diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp
index 7baf69d87689..8e0864b8dd83 100644
--- a/lib/CodeGen/CGRecordLayoutBuilder.cpp
+++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp
@@ -208,7 +208,11 @@ void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) {
Align = 1;
}
}
-
+ if (!Align) {
+ assert((D->field_begin() == D->field_end()) && "LayoutUnion - Align 0");
+ Align = 1;
+ }
+
// Append tail padding.
if (Layout.getSize() / 8 > Size)
AppendPadding(Layout.getSize() / 8, Align);
diff --git a/lib/CodeGen/CGRtti.cpp b/lib/CodeGen/CGRtti.cpp
index 7af15f0a8ca4..e18843d5cf3f 100644
--- a/lib/CodeGen/CGRtti.cpp
+++ b/lib/CodeGen/CGRtti.cpp
@@ -11,36 +11,378 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/AST/Type.h"
+#include "clang/AST/RecordLayout.h"
#include "CodeGenModule.h"
using namespace clang;
using namespace CodeGen;
+class RttiBuilder {
+ CodeGenModule &CGM; // Per-module state.
+ llvm::LLVMContext &VMContext;
+ const llvm::Type *Int8PtrTy;
+ llvm::SmallSet<const CXXRecordDecl *, 16> SeenVBase;
+ llvm::SmallSet<const CXXRecordDecl *, 32> SeenBase;
+public:
+ RttiBuilder(CodeGenModule &cgm)
+ : CGM(cgm), VMContext(cgm.getModule().getContext()),
+ Int8PtrTy(llvm::Type::getInt8PtrTy(VMContext)) { }
+
+ /// BuildVtableRef - Build a reference to a vtable.
+ llvm::Constant *BuildVtableRef(const char *Name) {
+ // Build a descriptor for Name
+ llvm::Constant *GV = CGM.getModule().getGlobalVariable(Name);
+ if (GV)
+ GV = llvm::ConstantExpr::getBitCast(GV,
+ llvm::PointerType::get(Int8PtrTy, 0));
+ else {
+ llvm::GlobalVariable::LinkageTypes linktype;
+ linktype = llvm::GlobalValue::ExternalLinkage;
+ GV = new llvm::GlobalVariable(CGM.getModule(), Int8PtrTy,
+ true, linktype, 0, Name);
+ }
+ llvm::Constant *C;
+ C = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), 2);
+ C = llvm::ConstantExpr::getInBoundsGetElementPtr(GV, &C, 1);
+ return llvm::ConstantExpr::getBitCast(C, Int8PtrTy);
+ }
+
+ llvm::Constant *BuildName(QualType Ty, bool Hidden) {
+ llvm::SmallString<256> OutName;
+ llvm::raw_svector_ostream Out(OutName);
+ mangleCXXRttiName(CGM.getMangleContext(), Ty, Out);
+
+ llvm::GlobalVariable::LinkageTypes linktype;
+ linktype = llvm::GlobalValue::LinkOnceODRLinkage;
+
+ llvm::Constant *C;
+ C = llvm::ConstantArray::get(VMContext, Out.str().substr(4));
+
+ llvm::GlobalVariable * GV = new llvm::GlobalVariable(CGM.getModule(),
+ C->getType(),
+ true, linktype, C,
+ Out.str());
+ if (Hidden)
+ GV->setVisibility(llvm::GlobalVariable::HiddenVisibility);
+ return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy);
+ };
+
+ /// - BuildFlags - Build a psABI __flags value for __vmi_class_type_info.
+ llvm::Constant *BuildFlags(int f) {
+ return llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), f);
+ }
+
+ /// BuildBaseCount - Build a psABI __base_count value for
+ /// __vmi_class_type_info.
+ llvm::Constant *BuildBaseCount(unsigned c) {
+ return llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), c);
+ }
+
+ llvm::Constant *BuildTypeRef(QualType Ty) {
+ llvm::Constant *C;
+
+ if (!CGM.getContext().getLangOptions().Rtti)
+ return llvm::Constant::getNullValue(Int8PtrTy);
+
+ llvm::SmallString<256> OutName;
+ llvm::raw_svector_ostream Out(OutName);
+ mangleCXXRtti(CGM.getMangleContext(), Ty, Out);
+
+ C = CGM.getModule().getGlobalVariable(Out.str());
+ if (C)
+ return llvm::ConstantExpr::getBitCast(C, Int8PtrTy);
+
+ llvm::GlobalVariable::LinkageTypes linktype;
+ linktype = llvm::GlobalValue::ExternalLinkage;;
+
+ C = new llvm::GlobalVariable(CGM.getModule(), Int8PtrTy, true, linktype,
+ 0, Out.str());
+ return llvm::ConstantExpr::getBitCast(C, Int8PtrTy);
+ }
+
+ llvm::Constant *Buildclass_type_infoRef(const CXXRecordDecl *RD) {
+ return BuildTypeRef(CGM.getContext().getTagDeclType(RD));
+ }
+
+ /// CalculateFlags - Calculate the flags for the __vmi_class_type_info
+ /// datastructure. 1 for non-diamond repeated inheritance, 2 for a dimond
+ /// shaped class.
+ int CalculateFlags(const CXXRecordDecl*RD) {
+ int flags = 0;
+ if (SeenBase.count(RD))
+ flags |= 1;
+ else
+ SeenBase.insert(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()) {
+ if (SeenVBase.count(Base))
+ flags |= 2;
+ else
+ SeenVBase.insert(Base);
+ }
+ flags |= CalculateFlags(Base);
+ }
+ return flags;
+ }
+
+ bool SimpleInheritance(const CXXRecordDecl *RD) {
+ if (RD->getNumBases() != 1)
+ return false;
+ CXXRecordDecl::base_class_const_iterator i = RD->bases_begin();
+ if (i->isVirtual())
+ return false;
+ if (i->getAccessSpecifier() != AS_public)
+ return false;
+
+ const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
+ const CXXRecordDecl *Base =
+ cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
+ if (Layout.getBaseClassOffset(Base) != 0)
+ return false;
+ return true;
+ }
+
+ llvm::Constant *finish(std::vector<llvm::Constant *> &info,
+ llvm::GlobalVariable *GV,
+ llvm::StringRef Name, bool Hidden) {
+ llvm::GlobalVariable::LinkageTypes linktype;
+ linktype = llvm::GlobalValue::LinkOnceODRLinkage;
+
+ llvm::Constant *C;
+ C = llvm::ConstantStruct::get(VMContext, &info[0], info.size(), false);
+
+ if (GV == 0)
+ GV = new llvm::GlobalVariable(CGM.getModule(), C->getType(), true,
+ linktype, C, Name);
+ else {
+ llvm::GlobalVariable *OGV = GV;
+ GV = new llvm::GlobalVariable(CGM.getModule(), C->getType(), true,
+ linktype, C, Name);
+ GV->takeName(OGV);
+ llvm::Constant *NewPtr = llvm::ConstantExpr::getBitCast(GV,
+ OGV->getType());
+ OGV->replaceAllUsesWith(NewPtr);
+ OGV->eraseFromParent();
+ }
+ if (Hidden)
+ GV->setVisibility(llvm::GlobalVariable::HiddenVisibility);
+ return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy);
+ }
+
+
+ llvm::Constant *Buildclass_type_info(const CXXRecordDecl *RD) {
+ if (!CGM.getContext().getLangOptions().Rtti)
+ return llvm::Constant::getNullValue(Int8PtrTy);
+
+ llvm::Constant *C;
+
+ llvm::SmallString<256> OutName;
+ llvm::raw_svector_ostream Out(OutName);
+ mangleCXXRtti(CGM.getMangleContext(), CGM.getContext().getTagDeclType(RD),
+ Out);
+
+ llvm::GlobalVariable *GV;
+ GV = CGM.getModule().getGlobalVariable(Out.str());
+ if (GV && !GV->isDeclaration())
+ return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy);
+
+ std::vector<llvm::Constant *> info;
+
+ bool Hidden = CGM.getDeclVisibilityMode(RD) == LangOptions::Hidden;
+
+ bool simple = false;
+ if (RD->getNumBases() == 0)
+ C = BuildVtableRef("_ZTVN10__cxxabiv117__class_type_infoE");
+ else if (SimpleInheritance(RD)) {
+ simple = true;
+ C = BuildVtableRef("_ZTVN10__cxxabiv120__si_class_type_infoE");
+ } else
+ C = BuildVtableRef("_ZTVN10__cxxabiv121__vmi_class_type_infoE");
+ info.push_back(C);
+ info.push_back(BuildName(CGM.getContext().getTagDeclType(RD), Hidden));
+
+ // If we have no bases, there are no more fields.
+ if (RD->getNumBases()) {
+ if (!simple) {
+ info.push_back(BuildFlags(CalculateFlags(RD)));
+ info.push_back(BuildBaseCount(RD->getNumBases()));
+ }
+
+ const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(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());
+ info.push_back(CGM.GenerateRttiRef(Base));
+ if (simple)
+ break;
+ int64_t offset;
+ if (!i->isVirtual())
+ offset = Layout.getBaseClassOffset(Base)/8;
+ else
+ offset = CGM.getVtableInfo().getVirtualBaseOffsetIndex(RD, Base);
+ offset <<= 8;
+ // Now set the flags.
+ offset += i->isVirtual() ? 1 : 0;;
+ offset += i->getAccessSpecifier() == AS_public ? 2 : 0;
+ const llvm::Type *LongTy =
+ CGM.getTypes().ConvertType(CGM.getContext().LongTy);
+ C = llvm::ConstantInt::get(LongTy, offset);
+ info.push_back(C);
+ }
+ }
+
+ return finish(info, GV, Out.str(), Hidden);
+ }
+
+ /// - BuildFlags - Build a __flags value for __pbase_type_info.
+ llvm::Constant *BuildInt(int f) {
+ return llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), f);
+ }
+
+ llvm::Constant *BuildType2(QualType Ty) {
+ if (const RecordType *RT = Ty.getTypePtr()->getAs<RecordType>())
+ if (const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()))
+ return Buildclass_type_info(RD);
+ return BuildType(Ty);
+ }
+
+ llvm::Constant *BuildPointerType(QualType Ty) {
+ llvm::Constant *C;
+
+ llvm::SmallString<256> OutName;
+ llvm::raw_svector_ostream Out(OutName);
+ mangleCXXRtti(CGM.getMangleContext(), Ty, Out);
+
+ llvm::GlobalVariable *GV;
+ GV = CGM.getModule().getGlobalVariable(Out.str());
+ if (GV && !GV->isDeclaration())
+ return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy);
+
+ std::vector<llvm::Constant *> info;
+
+ // FIXME: pointer to hidden should be hidden, we should be able to
+ // grab a bit off the type for this.
+ bool Hidden = false;
+
+ QualType PTy = Ty->getPointeeType();
+ QualType BTy;
+ bool PtrMem = false;
+ if (const MemberPointerType *MPT = dyn_cast<MemberPointerType>(Ty)) {
+ PtrMem = true;
+ BTy = QualType(MPT->getClass(), 0);
+ PTy = MPT->getPointeeType();
+ }
+
+ if (PtrMem)
+ C = BuildVtableRef("_ZTVN10__cxxabiv129__pointer_to_member_type_infoE");
+ else
+ C = BuildVtableRef("_ZTVN10__cxxabiv119__pointer_type_infoE");
+ info.push_back(C);
+ info.push_back(BuildName(Ty, Hidden));
+ Qualifiers Q = PTy.getQualifiers();
+ PTy = CGM.getContext().getCanonicalType(PTy).getUnqualifiedType();
+ int flags = 0;
+ flags += Q.hasConst() ? 0x1 : 0;
+ flags += Q.hasVolatile() ? 0x2 : 0;
+ flags += Q.hasRestrict() ? 0x4 : 0;
+ flags += Ty.getTypePtr()->isIncompleteType() ? 0x8 : 0;
+ if (PtrMem && BTy.getTypePtr()->isIncompleteType())
+ flags += 0x10;
+
+ info.push_back(BuildInt(flags));
+ info.push_back(BuildInt(0));
+ info.push_back(BuildType2(PTy));
+
+ if (PtrMem)
+ info.push_back(BuildType2(BTy));
+
+ return finish(info, GV, Out.str(), true);
+ }
+
+ llvm::Constant *BuildSimpleType(QualType Ty, const char *vtbl) {
+ llvm::Constant *C;
+
+ llvm::SmallString<256> OutName;
+ llvm::raw_svector_ostream Out(OutName);
+ mangleCXXRtti(CGM.getMangleContext(), Ty, Out);
+
+ llvm::GlobalVariable *GV;
+ GV = CGM.getModule().getGlobalVariable(Out.str());
+ if (GV && !GV->isDeclaration())
+ return llvm::ConstantExpr::getBitCast(GV, Int8PtrTy);
+
+ std::vector<llvm::Constant *> info;
+
+ // FIXME: pointer to hidden should be hidden, we should be able to
+ // grab a bit off the type for this.
+ bool Hidden = false;
+
+ C = BuildVtableRef(vtbl);
+ info.push_back(C);
+ info.push_back(BuildName(Ty, Hidden));
+
+ return finish(info, GV, Out.str(), true);
+ }
+
+ llvm::Constant *BuildType(QualType Ty) {
+ const clang::Type &Type
+ = *CGM.getContext().getCanonicalType(Ty).getTypePtr();
+ switch (Type.getTypeClass()) {
+ default: {
+ assert(0 && "typeid expression");
+ return llvm::Constant::getNullValue(Int8PtrTy);
+ }
+
+ case Type::Builtin: {
+ // We expect all type_info objects for builtin types to be in the library.
+ return BuildTypeRef(Ty);
+ }
+
+ case Type::Pointer: {
+ QualType PTy = Ty->getPointeeType();
+ Qualifiers Q = PTy.getQualifiers();
+ Q.removeConst();
+ // T* and const T* for all builtin types T are expected in the library.
+ if (isa<BuiltinType>(PTy) && Q.empty())
+ return BuildTypeRef(Ty);
+
+ return BuildPointerType(Ty);
+ }
+ case Type::MemberPointer:
+ return BuildPointerType(Ty);
+ case Type::FunctionProto:
+ case Type::FunctionNoProto:
+ return BuildSimpleType(Ty, "_ZTVN10__cxxabiv120__function_type_infoE");
+ case Type::ConstantArray:
+ case Type::IncompleteArray:
+ case Type::VariableArray:
+ case Type::Vector:
+ case Type::ExtVector:
+ return BuildSimpleType(Ty, "_ZTVN10__cxxabiv117__array_type_infoE");
+ case Type::Enum:
+ return BuildSimpleType(Ty, "_ZTVN10__cxxabiv116__enum_type_infoE");
+ }
+ }
+};
+
+llvm::Constant *CodeGenModule::GenerateRttiRef(const CXXRecordDecl *RD) {
+ RttiBuilder b(*this);
+
+ return b.Buildclass_type_infoRef(RD);
+}
+
llvm::Constant *CodeGenModule::GenerateRtti(const CXXRecordDecl *RD) {
- const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext);
-
- if (!getContext().getLangOptions().Rtti)
- return llvm::Constant::getNullValue(Int8PtrTy);
-
- llvm::SmallString<256> OutName;
- llvm::raw_svector_ostream Out(OutName);
- mangleCXXRtti(getMangleContext(), Context.getTagDeclType(RD), Out);
-
- llvm::GlobalVariable::LinkageTypes linktype;
- linktype = llvm::GlobalValue::WeakAnyLinkage;
- std::vector<llvm::Constant *> info;
- // assert(0 && "FIXME: implement rtti descriptor");
- // FIXME: descriptor
- info.push_back(llvm::Constant::getNullValue(Int8PtrTy));
- // assert(0 && "FIXME: implement rtti ts");
- // FIXME: TS
- info.push_back(llvm::Constant::getNullValue(Int8PtrTy));
-
- llvm::Constant *C;
- llvm::ArrayType *type = llvm::ArrayType::get(Int8PtrTy, info.size());
- C = llvm::ConstantArray::get(type, info);
- llvm::Constant *Rtti =
- new llvm::GlobalVariable(getModule(), type, true, linktype, C,
- Out.str());
- Rtti = llvm::ConstantExpr::getBitCast(Rtti, Int8PtrTy);
- return Rtti;
+ RttiBuilder b(*this);
+
+ return b.Buildclass_type_info(RD);
+}
+
+llvm::Constant *CodeGenModule::GenerateRttiNonClass(QualType Ty) {
+ RttiBuilder b(*this);
+
+ return b.BuildType(Ty);
}
diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp
index 9126c2c99cdf..b6d7b3990452 100644
--- a/lib/CodeGen/CGStmt.cpp
+++ b/lib/CodeGen/CGStmt.cpp
@@ -148,13 +148,8 @@ RValue CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast,
CGDebugInfo *DI = getDebugInfo();
if (DI) {
-#ifdef ATTACH_DEBUG_INFO_TO_AN_INSN
DI->setLocation(S.getLBracLoc());
DI->EmitRegionStart(CurFn, Builder);
-#else
- EnsureInsertPoint();
- DI->setLocation(S.getLBracLoc());
-#endif
}
// Keep track of the current cleanup stack depth.
@@ -167,13 +162,8 @@ RValue CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast,
EmitStmt(*I);
if (DI) {
-#ifdef ATTACH_DEBUG_INFO_TO_AN_INSN
DI->setLocation(S.getLBracLoc());
DI->EmitRegionEnd(CurFn, Builder);
-#else
- EnsureInsertPoint();
- DI->setLocation(S.getLBracLoc());
-#endif
}
RValue RV;
@@ -284,16 +274,9 @@ void CodeGenFunction::EmitGotoStmt(const GotoStmt &S) {
void CodeGenFunction::EmitIndirectGotoStmt(const IndirectGotoStmt &S) {
- // Emit initial switch which will be patched up later by
- // EmitIndirectSwitches(). We need a default dest, so we use the
- // current BB, but this is overwritten.
-#ifndef USEINDIRECTBRANCH
- llvm::Value *V = Builder.CreatePtrToInt(EmitScalarExpr(S.getTarget()),
- llvm::Type::getInt32Ty(VMContext),
-#else
+ // Ensure that we have an i8* for our PHI node.
llvm::Value *V = Builder.CreateBitCast(EmitScalarExpr(S.getTarget()),
llvm::Type::getInt8PtrTy(VMContext),
-#endif
"addr");
llvm::BasicBlock *CurBB = Builder.GetInsertBlock();
@@ -491,13 +474,11 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S) {
BreakContinueStack.push_back(BreakContinue(AfterFor, ContinueBlock));
// If the condition is true, execute the body of the for stmt.
-#ifdef ATTACH_DEBUG_INFO_TO_AN_INSN
CGDebugInfo *DI = getDebugInfo();
if (DI) {
DI->setLocation(S.getSourceRange().getBegin());
DI->EmitRegionStart(CurFn, Builder);
}
-#endif
EmitStmt(S.getBody());
BreakContinueStack.pop_back();
@@ -510,12 +491,10 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S) {
// Finally, branch back up to the condition for the next iteration.
EmitBranch(CondBlock);
-#ifdef ATTACH_DEBUG_INFO_TO_AN_INSN
if (DI) {
DI->setLocation(S.getSourceRange().getEnd());
DI->EmitRegionEnd(CurFn, Builder);
}
-#endif
// Emit the fall-through block.
EmitBlock(AfterFor, true);
@@ -758,7 +737,7 @@ void CodeGenFunction::EmitSwitchStmt(const SwitchStmt &S) {
}
static std::string
-SimplifyConstraint(const char *Constraint, TargetInfo &Target,
+SimplifyConstraint(const char *Constraint, const TargetInfo &Target,
llvm::SmallVectorImpl<TargetInfo::ConstraintInfo> *OutCons=0) {
std::string Result;
diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp
index e2e11478de26..4c97a9bdeebf 100644
--- a/lib/CodeGen/CGVtable.cpp
+++ b/lib/CodeGen/CGVtable.cpp
@@ -15,6 +15,7 @@
#include "CodeGenFunction.h"
#include "clang/AST/RecordLayout.h"
+#include <cstdio>
using namespace clang;
using namespace CodeGen;
@@ -29,6 +30,11 @@ private:
llvm::Type *Ptr8Ty;
/// Class - The most derived class that this vtable is being built for.
const CXXRecordDecl *Class;
+ /// LayoutClass - The most derived class used for virtual base layout
+ /// information.
+ const CXXRecordDecl *LayoutClass;
+ /// LayoutOffset - The offset for Class in LayoutClass.
+ uint64_t LayoutOffset;
/// BLayout - Layout for the most derived class that this vtable is being
/// built for.
const ASTRecordLayout &BLayout;
@@ -39,38 +45,45 @@ private:
CodeGenModule &CGM; // Per-module state.
/// Index - Maps a method decl into a vtable index. Useful for virtual
/// dispatch codegen.
- llvm::DenseMap<const CXXMethodDecl *, Index_t> Index;
- llvm::DenseMap<const CXXMethodDecl *, Index_t> VCall;
- llvm::DenseMap<const CXXMethodDecl *, Index_t> VCallOffset;
+ llvm::DenseMap<GlobalDecl, Index_t> Index;
+ llvm::DenseMap<GlobalDecl, Index_t> VCall;
+ llvm::DenseMap<GlobalDecl, Index_t> VCallOffset;
+ // This is the offset to the nearest virtual base
+ llvm::DenseMap<GlobalDecl, Index_t> NonVirtualOffset;
llvm::DenseMap<const CXXRecordDecl *, Index_t> VBIndex;
- typedef llvm::DenseMap<const CXXMethodDecl *, int> Pures_t;
+ typedef llvm::DenseMap<GlobalDecl, int> Pures_t;
Pures_t Pures;
typedef std::pair<Index_t, Index_t> CallOffset;
- typedef llvm::DenseMap<const CXXMethodDecl *, CallOffset> Thunks_t;
+ typedef llvm::DenseMap<GlobalDecl, CallOffset> Thunks_t;
Thunks_t Thunks;
- typedef llvm::DenseMap<const CXXMethodDecl *,
+ typedef llvm::DenseMap<GlobalDecl,
std::pair<std::pair<CallOffset, CallOffset>,
CanQualType> > CovariantThunks_t;
CovariantThunks_t CovariantThunks;
std::vector<Index_t> VCalls;
+
+ typedef std::pair<const CXXRecordDecl *, uint64_t> CtorVtable_t;
+ // CtorVtable - Used to hold the AddressPoints (offsets) into the built vtable
+ // for use in computing the initializers for the VTT.
+ llvm::DenseMap<CtorVtable_t, int64_t> &AddressPoints;
+
typedef CXXRecordDecl::method_iterator method_iter;
// FIXME: Linkage should follow vtable
const bool Extern;
const uint32_t LLVMPointerWidth;
Index_t extra;
- int CurrentVBaseOffset;
typedef std::vector<std::pair<const CXXRecordDecl *, int64_t> > Path_t;
llvm::Constant *cxa_pure;
public:
- VtableBuilder(std::vector<llvm::Constant *> &meth,
- const CXXRecordDecl *c,
- CodeGenModule &cgm)
- : methods(meth), Class(c), BLayout(cgm.getContext().getASTRecordLayout(c)),
- rtti(cgm.GenerateRtti(c)), VMContext(cgm.getModule().getContext()),
- CGM(cgm), Extern(true),
- LLVMPointerWidth(cgm.getContext().Target.getPointerWidth(0)),
- CurrentVBaseOffset(0) {
+ VtableBuilder(std::vector<llvm::Constant *> &meth, const CXXRecordDecl *c,
+ const CXXRecordDecl *l, uint64_t lo, CodeGenModule &cgm)
+ : methods(meth), Class(c), LayoutClass(l), LayoutOffset(lo),
+ BLayout(cgm.getContext().getASTRecordLayout(l)),
+ rtti(cgm.GenerateRttiRef(c)), VMContext(cgm.getModule().getContext()),
+ CGM(cgm), AddressPoints(*new llvm::DenseMap<CtorVtable_t, int64_t>),
+ Extern(true),
+ LLVMPointerWidth(cgm.getContext().Target.getPointerWidth(0)) {
Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0);
// Calculate pointer for ___cxa_pure_virtual.
@@ -81,10 +94,13 @@ public:
cxa_pure = wrap(CGM.CreateRuntimeFunction(FTy, "__cxa_pure_virtual"));
}
- llvm::DenseMap<const CXXMethodDecl *, Index_t> &getIndex() { return Index; }
+ llvm::DenseMap<GlobalDecl, Index_t> &getIndex() { return Index; }
llvm::DenseMap<const CXXRecordDecl *, Index_t> &getVBIndex()
{ return VBIndex; }
+ llvm::DenseMap<CtorVtable_t, int64_t> *getAddressPoints()
+ { return &AddressPoints; }
+
llvm::Constant *wrap(Index_t i) {
llvm::Constant *m;
m = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), i);
@@ -95,8 +111,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) {
@@ -189,9 +205,11 @@ public:
return 0;
}
- bool OverrideMethod(const CXXMethodDecl *MD, llvm::Constant *m,
+ bool OverrideMethod(GlobalDecl GD, llvm::Constant *m,
bool MorallyVirtual, Index_t OverrideOffset,
- Index_t Offset) {
+ Index_t Offset, int64_t CurrentVBaseOffset) {
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
+
const bool isPure = MD->isPure();
typedef CXXMethodDecl::method_iterator meth_iter;
// FIXME: Should OverrideOffset's be Offset?
@@ -204,9 +222,16 @@ public:
for (meth_iter mi = MD->begin_overridden_methods(),
e = MD->end_overridden_methods();
mi != e; ++mi) {
+ GlobalDecl OGD;
+
const CXXMethodDecl *OMD = *mi;
+ if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(OMD))
+ OGD = GlobalDecl(DD, GD.getDtorType());
+ else
+ OGD = OMD;
+
llvm::Constant *om;
- om = CGM.GetAddrOfFunction(OMD, Ptr8Ty);
+ om = WrapAddrOf(OGD);
om = llvm::ConstantExpr::getBitCast(om, Ptr8Ty);
for (Index_t i = 0, e = submethods.size();
@@ -229,57 +254,60 @@ public:
Index_t nv = getNVOffset(oret, ret)/8;
ReturnOffset = std::make_pair(nv, getVbaseOffset(oret, ret));
}
- Index[MD] = i;
+ Index[GD] = i;
submethods[i] = m;
if (isPure)
- Pures[MD] = 1;
- Pures.erase(OMD);
- Thunks.erase(OMD);
- if (MorallyVirtual) {
- Index_t &idx = VCall[OMD];
+ Pures[GD] = 1;
+ Pures.erase(OGD);
+ Thunks.erase(OGD);
+ if (MorallyVirtual || VCall.count(OGD)) {
+ Index_t &idx = VCall[OGD];
if (idx == 0) {
- VCallOffset[MD] = OverrideOffset/8;
+ NonVirtualOffset[GD] = -OverrideOffset/8 + CurrentVBaseOffset/8;
+ VCallOffset[GD] = OverrideOffset/8;
idx = VCalls.size()+1;
VCalls.push_back(0);
D1(printf(" vcall for %s at %d with delta %d most derived %s\n",
- MD->getNameAsCString(),
- (int)-VCalls.size()-3, (int)VCallOffset[MD],
- Class->getNameAsCString()));
+ MD->getNameAsString().c_str(), (int)-idx-3,
+ (int)VCalls[idx-1], Class->getNameAsCString()));
} else {
- VCallOffset[MD] = VCallOffset[OMD];
- VCalls[idx-1] = -VCallOffset[OMD] + OverrideOffset/8;
+ 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->getNameAsCString(),
- (int)-VCalls.size()-3, (int)VCallOffset[MD],
- Class->getNameAsCString()));
+ MD->getNameAsString().c_str(), (int)-idx-3,
+ (int)VCalls[idx-1], Class->getNameAsCString()));
}
- VCall[MD] = idx;
- CallOffset ThisOffset;
- ThisOffset = std::make_pair(CurrentVBaseOffset/8 - Offset/8,
- -((idx+extra+2)*LLVMPointerWidth/8));
+ VCall[GD] = idx;
+ int64_t O = NonVirtualOffset[GD];
+ int v = -((idx+extra+2)*LLVMPointerWidth/8);
+ // Optimize out virtual adjustments of 0.
+ if (VCalls[idx-1] == 0)
+ v = 0;
+ CallOffset ThisOffset = std::make_pair(O, v);
// FIXME: Do we always have to build a covariant thunk to save oret,
// which is the containing virtual base class?
if (ReturnOffset.first || ReturnOffset.second)
- CovariantThunks[MD] = std::make_pair(std::make_pair(ThisOffset,
+ CovariantThunks[GD] = std::make_pair(std::make_pair(ThisOffset,
ReturnOffset),
oret);
- else if (!isPure)
- Thunks[MD] = ThisOffset;
+ else if (!isPure && (ThisOffset.first || ThisOffset.second))
+ Thunks[GD] = ThisOffset;
return true;
}
// FIXME: finish off
- int64_t O = VCallOffset[OMD] - OverrideOffset/8;
- // int64_t O = CurrentVBaseOffset/8 - OverrideOffset/8;
+ int64_t O = VCallOffset[OGD] - OverrideOffset/8;
+
if (O || ReturnOffset.first || ReturnOffset.second) {
CallOffset ThisOffset = std::make_pair(O, 0);
if (ReturnOffset.first || ReturnOffset.second)
- CovariantThunks[MD] = std::make_pair(std::make_pair(ThisOffset,
+ CovariantThunks[GD] = std::make_pair(std::make_pair(ThisOffset,
ReturnOffset),
oret);
else if (!isPure)
- Thunks[MD] = ThisOffset;
+ Thunks[GD] = ThisOffset;
}
return true;
}
@@ -291,9 +319,10 @@ public:
void InstallThunks() {
for (Thunks_t::iterator i = Thunks.begin(), e = Thunks.end();
i != e; ++i) {
- const CXXMethodDecl *MD = i->first;
+ GlobalDecl GD = i->first;
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
assert(!MD->isPure() && "Trying to thunk a pure");
- Index_t idx = Index[MD];
+ Index_t idx = Index[GD];
Index_t nv_O = i->second.first;
Index_t v_O = i->second.second;
submethods[idx] = CGM.BuildThunk(MD, Extern, nv_O, v_O);
@@ -302,10 +331,11 @@ public:
for (CovariantThunks_t::iterator i = CovariantThunks.begin(),
e = CovariantThunks.end();
i != e; ++i) {
- const CXXMethodDecl *MD = i->first;
+ GlobalDecl GD = i->first;
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
if (MD->isPure())
continue;
- Index_t idx = Index[MD];
+ Index_t idx = Index[GD];
Index_t nv_t = i->second.first.first.first;
Index_t v_t = i->second.first.first.second;
Index_t nv_r = i->second.first.second.first;
@@ -316,16 +346,18 @@ public:
CovariantThunks.clear();
for (Pures_t::iterator i = Pures.begin(), e = Pures.end();
i != e; ++i) {
- const CXXMethodDecl *MD = i->first;
- Index_t idx = Index[MD];
+ GlobalDecl GD = i->first;
+ Index_t idx = Index[GD];
submethods[idx] = cxa_pure;
}
Pures.clear();
}
- llvm::Constant *WrapAddrOf(const CXXMethodDecl *MD) {
+ llvm::Constant *WrapAddrOf(GlobalDecl GD) {
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
+
if (const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(MD))
- return wrap(CGM.GetAddrOfCXXDestructor(Dtor, Dtor_Complete));
+ return wrap(CGM.GetAddrOfCXXDestructor(Dtor, GD.getDtorType()));
const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
const llvm::Type *Ty =
@@ -335,63 +367,95 @@ public:
return wrap(CGM.GetAddrOfFunction(MD, Ty));
}
- void OverrideMethods(Path_t *Path, bool MorallyVirtual, int64_t Offset) {
+ void OverrideMethods(Path_t *Path, bool MorallyVirtual, int64_t Offset,
+ int64_t CurrentVBaseOffset) {
for (Path_t::reverse_iterator i = Path->rbegin(),
e = Path->rend(); i != e; ++i) {
const CXXRecordDecl *RD = i->first;
int64_t OverrideOffset = i->second;
for (method_iter mi = RD->method_begin(), me = RD->method_end(); mi != me;
++mi) {
- if (!mi->isVirtual())
+ const CXXMethodDecl *MD = *mi;
+
+ if (!MD->isVirtual())
continue;
- const CXXMethodDecl *MD = *mi;
- llvm::Constant *m = WrapAddrOf(MD);
- OverrideMethod(MD, m, MorallyVirtual, OverrideOffset, Offset);
+ if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
+ // Override both the complete and the deleting destructor.
+ GlobalDecl CompDtor(DD, Dtor_Complete);
+ OverrideMethod(CompDtor, WrapAddrOf(CompDtor), MorallyVirtual,
+ OverrideOffset, Offset, CurrentVBaseOffset);
+
+ GlobalDecl DeletingDtor(DD, Dtor_Deleting);
+ OverrideMethod(DeletingDtor, WrapAddrOf(DeletingDtor), MorallyVirtual,
+ OverrideOffset, Offset, CurrentVBaseOffset);
+ } else {
+ OverrideMethod(MD, WrapAddrOf(MD), MorallyVirtual, OverrideOffset,
+ Offset, CurrentVBaseOffset);
+ }
}
}
}
- void AddMethod(const CXXMethodDecl *MD, bool MorallyVirtual, Index_t Offset,
- bool ForVirtualBase) {
- llvm::Constant *m = WrapAddrOf(MD);
+ void AddMethod(const GlobalDecl GD, bool MorallyVirtual, Index_t Offset,
+ bool ForVirtualBase, int64_t CurrentVBaseOffset) {
+ llvm::Constant *m = WrapAddrOf(GD);
// If we can find a previously allocated slot for this, reuse it.
- if (OverrideMethod(MD, m, MorallyVirtual, Offset, Offset))
+ if (OverrideMethod(GD, m, MorallyVirtual, Offset, Offset,
+ CurrentVBaseOffset))
return;
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
+
// else allocate a new slot.
- Index[MD] = submethods.size();
+ Index[GD] = submethods.size();
submethods.push_back(m);
- D1(printf(" vfn for %s at %d\n", MD->getNameAsCString(), (int)Index[MD]));
+ D1(printf(" vfn for %s at %d\n", MD->getNameAsString().c_str(),
+ (int)Index[GD]));
if (MD->isPure())
- Pures[MD] = 1;
+ Pures[GD] = 1;
if (MorallyVirtual) {
- VCallOffset[MD] = Offset/8;
- Index_t &idx = VCall[MD];
+ VCallOffset[GD] = Offset/8;
+ Index_t &idx = VCall[GD];
// Allocate the first one, after that, we reuse the previous one.
if (idx == 0) {
+ NonVirtualOffset[GD] = CurrentVBaseOffset/8 - Offset/8;
idx = VCalls.size()+1;
VCalls.push_back(0);
D1(printf(" vcall for %s at %d with delta %d\n",
- MD->getNameAsCString(), (int)-VCalls.size()-3,
- (int)VCallOffset[MD]));
+ MD->getNameAsString().c_str(), (int)-VCalls.size()-3, 0));
}
}
}
void AddMethods(const CXXRecordDecl *RD, bool MorallyVirtual,
- Index_t Offset, bool RDisVirtualBase) {
+ Index_t Offset, bool RDisVirtualBase,
+ int64_t CurrentVBaseOffset) {
for (method_iter mi = RD->method_begin(), me = RD->method_end(); mi != me;
- ++mi)
- if (mi->isVirtual())
- AddMethod(*mi, MorallyVirtual, Offset, RDisVirtualBase);
+ ++mi) {
+ const CXXMethodDecl *MD = *mi;
+ if (!MD->isVirtual())
+ continue;
+
+ if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
+ // For destructors, add both the complete and the deleting destructor
+ // to the vtable.
+ AddMethod(GlobalDecl(DD, Dtor_Complete), MorallyVirtual, Offset,
+ RDisVirtualBase, CurrentVBaseOffset);
+ AddMethod(GlobalDecl(DD, Dtor_Deleting), MorallyVirtual, Offset,
+ RDisVirtualBase, CurrentVBaseOffset);
+ } else
+ AddMethod(MD, MorallyVirtual, Offset, RDisVirtualBase,
+ CurrentVBaseOffset);
+ }
}
void NonVirtualBases(const CXXRecordDecl *RD, const ASTRecordLayout &Layout,
const CXXRecordDecl *PrimaryBase,
bool PrimaryBaseWasVirtual, bool MorallyVirtual,
- int64_t Offset, Path_t *Path) {
+ int64_t Offset, int64_t CurrentVBaseOffset,
+ Path_t *Path) {
Path->push_back(std::make_pair(RD, Offset));
for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
e = RD->bases_end(); i != e; ++i) {
@@ -402,8 +466,8 @@ public:
if (Base != PrimaryBase || PrimaryBaseWasVirtual) {
uint64_t o = Offset + Layout.getBaseClassOffset(Base);
StartNewTable();
- CurrentVBaseOffset = Offset;
- GenerateVtableForBase(Base, MorallyVirtual, o, false, Path);
+ GenerateVtableForBase(Base, o, MorallyVirtual, false,
+ CurrentVBaseOffset, Path);
}
}
Path->pop_back();
@@ -424,11 +488,39 @@ public:
i != e; ++i)
methods[InsertionPoint++] = wrap((0?600:0) + *i);
VCalls.clear();
+ VCall.clear();
}
+ 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(),
+ LayoutClass->getNameAsCString(), (int)Offset, (int)AddressPoint));
+ AddressPoints[std::make_pair(RD, Offset)] = AddressPoint;
+
+ // Now also add the address point for all our primary bases.
+ while (1) {
+ const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
+ RD = Layout.getPrimaryBase();
+ const bool PrimaryBaseWasVirtual = Layout.getPrimaryBaseWasVirtual();
+ // FIXME: Double check this.
+ if (RD == 0)
+ break;
+ if (PrimaryBaseWasVirtual &&
+ 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(),
+ LayoutClass->getNameAsCString(), (int)Offset, (int)AddressPoint));
+ AddressPoints[std::make_pair(RD, Offset)] = AddressPoint;
+ }
+ }
+
+
Index_t end(const CXXRecordDecl *RD, const ASTRecordLayout &Layout,
const CXXRecordDecl *PrimaryBase, bool PrimaryBaseWasVirtual,
bool MorallyVirtual, int64_t Offset, bool ForVirtualBase,
+ int64_t CurrentVBaseOffset,
Path_t *Path) {
bool alloc = false;
if (Path == 0) {
@@ -446,7 +538,7 @@ public:
// FIXME: just for extra, or for all uses of VCalls.size post this?
extra = -VCalls.size();
- methods.push_back(wrap(-(Offset/8)));
+ methods.push_back(wrap(-((Offset-LayoutOffset)/8)));
methods.push_back(rtti);
Index_t AddressPoint = methods.size();
@@ -457,13 +549,22 @@ public:
// and then the non-virtual bases.
NonVirtualBases(RD, Layout, PrimaryBase, PrimaryBaseWasVirtual,
- MorallyVirtual, Offset, Path);
+ MorallyVirtual, Offset, CurrentVBaseOffset, Path);
if (ForVirtualBase) {
- insertVCalls(VCallInsertionPoint);
+ // FIXME: We're adding to VCalls in callers, we need to do the overrides
+ // in the inner part, so that we know the complete set of vcalls during
+ // the build and don't have to insert into methods. Saving out the
+ // AddressPoint here, would need to be fixed, if we didn't do that. Also
+ // retroactively adding vcalls for overrides later wind up in the wrong
+ // place, the vcall slot has to be alloted during the walk of the base
+ // when the function is first introduces.
AddressPoint += VCalls.size();
+ insertVCalls(VCallInsertionPoint);
}
+ AddAddressPoints(RD, Offset, AddressPoint);
+
if (alloc) {
delete Path;
}
@@ -472,7 +573,7 @@ public:
void Primaries(const CXXRecordDecl *RD, bool MorallyVirtual, int64_t Offset,
bool updateVBIndex, Index_t current_vbindex,
- bool RDisVirtualBase) {
+ bool RDisVirtualBase, int64_t CurrentVBaseOffset) {
if (!RD->isDynamicClass())
return;
@@ -485,21 +586,27 @@ public:
D1(printf(" doing primaries for %s most derived %s\n",
RD->getNameAsCString(), Class->getNameAsCString()));
+ int BaseCurrentVBaseOffset = CurrentVBaseOffset;
+ if (PrimaryBaseWasVirtual)
+ BaseCurrentVBaseOffset = BLayout.getVBaseClassOffset(PrimaryBase);
+
if (!PrimaryBaseWasVirtual)
Primaries(PrimaryBase, PrimaryBaseWasVirtual|MorallyVirtual, Offset,
- updateVBIndex, current_vbindex, PrimaryBaseWasVirtual);
+ updateVBIndex, current_vbindex, PrimaryBaseWasVirtual,
+ BaseCurrentVBaseOffset);
}
D1(printf(" doing vcall entries for %s most derived %s\n",
RD->getNameAsCString(), Class->getNameAsCString()));
// And add the virtuals for the class to the primary vtable.
- AddMethods(RD, MorallyVirtual, Offset, RDisVirtualBase);
+ AddMethods(RD, MorallyVirtual, Offset, RDisVirtualBase, CurrentVBaseOffset);
}
void VBPrimaries(const CXXRecordDecl *RD, bool MorallyVirtual, int64_t Offset,
bool updateVBIndex, Index_t current_vbindex,
- bool RDisVirtualBase, bool bottom=false) {
+ bool RDisVirtualBase, int64_t CurrentVBaseOffset,
+ bool bottom=false) {
if (!RD->isDynamicClass())
return;
@@ -509,14 +616,18 @@ public:
// vtables are composed from the chain of primaries.
if (PrimaryBase) {
- if (PrimaryBaseWasVirtual)
+ int BaseCurrentVBaseOffset = CurrentVBaseOffset;
+ if (PrimaryBaseWasVirtual) {
IndirectPrimary.insert(PrimaryBase);
+ BaseCurrentVBaseOffset = BLayout.getVBaseClassOffset(PrimaryBase);
+ }
D1(printf(" doing primaries for %s most derived %s\n",
RD->getNameAsCString(), Class->getNameAsCString()));
VBPrimaries(PrimaryBase, PrimaryBaseWasVirtual|MorallyVirtual, Offset,
- updateVBIndex, current_vbindex, PrimaryBaseWasVirtual);
+ updateVBIndex, current_vbindex, PrimaryBaseWasVirtual,
+ BaseCurrentVBaseOffset);
}
D1(printf(" doing vbase entries for %s most derived %s\n",
@@ -525,17 +636,23 @@ public:
if (RDisVirtualBase || bottom) {
Primaries(RD, MorallyVirtual, Offset, updateVBIndex, current_vbindex,
- RDisVirtualBase);
+ RDisVirtualBase, CurrentVBaseOffset);
}
}
- int64_t GenerateVtableForBase(const CXXRecordDecl *RD,
- bool MorallyVirtual = false, int64_t Offset = 0,
+ int64_t GenerateVtableForBase(const CXXRecordDecl *RD, int64_t Offset = 0,
+ bool MorallyVirtual = false,
bool ForVirtualBase = false,
+ int CurrentVBaseOffset = 0,
Path_t *Path = 0) {
if (!RD->isDynamicClass())
return 0;
+ // Construction vtable don't need parts that have no virtual bases and
+ // aren't morally virtual.
+ if ((LayoutClass != Class) && RD->getNumVBases() == 0 && !MorallyVirtual)
+ return 0;
+
const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
const bool PrimaryBaseWasVirtual = Layout.getPrimaryBaseWasVirtual();
@@ -548,13 +665,13 @@ public:
extra = VCalls.size();
VBPrimaries(RD, MorallyVirtual, Offset, !ForVirtualBase, 0, ForVirtualBase,
- true);
+ CurrentVBaseOffset, true);
if (Path)
- OverrideMethods(Path, MorallyVirtual, Offset);
+ OverrideMethods(Path, MorallyVirtual, Offset, CurrentVBaseOffset);
return end(RD, Layout, PrimaryBase, PrimaryBaseWasVirtual, MorallyVirtual,
- Offset, ForVirtualBase, Path);
+ Offset, ForVirtualBase, CurrentVBaseOffset, Path);
}
void GenerateVtableForVBases(const CXXRecordDecl *RD,
@@ -578,16 +695,21 @@ public:
StartNewTable();
VCall.clear();
int64_t BaseOffset = BLayout.getVBaseClassOffset(Base);
- CurrentVBaseOffset = BaseOffset;
+ int64_t CurrentVBaseOffset = BaseOffset;
D1(printf("vtable %s virtual base %s\n",
Class->getNameAsCString(), Base->getNameAsCString()));
- GenerateVtableForBase(Base, true, BaseOffset, true, Path);
+ GenerateVtableForBase(Base, BaseOffset, true, true, CurrentVBaseOffset,
+ Path);
}
- int64_t BaseOffset = Offset;
+ int64_t BaseOffset;
if (i->isVirtual())
BaseOffset = BLayout.getVBaseClassOffset(Base);
+ else {
+ const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
+ BaseOffset = Offset + Layout.getBaseClassOffset(Base);
+ }
+
if (Base->getNumVBases()) {
- CurrentVBaseOffset = BaseOffset;
GenerateVtableForVBases(Base, BaseOffset, Path);
}
}
@@ -603,19 +725,17 @@ VtableBuilder::Index_t VtableBuilder::VBlookup(CXXRecordDecl *D,
return CGM.getVtableInfo().getVirtualBaseOffsetIndex(D, B);
}
-int64_t CGVtableInfo::getMethodVtableIndex(const CXXMethodDecl *MD) {
- MD = MD->getCanonicalDecl();
-
- MethodVtableIndicesTy::iterator I = MethodVtableIndices.find(MD);
+int64_t CGVtableInfo::getMethodVtableIndex(GlobalDecl GD) {
+ MethodVtableIndicesTy::iterator I = MethodVtableIndices.find(GD);
if (I != MethodVtableIndices.end())
return I->second;
- const CXXRecordDecl *RD = MD->getParent();
+ const CXXRecordDecl *RD = cast<CXXMethodDecl>(GD.getDecl())->getParent();
std::vector<llvm::Constant *> methods;
// FIXME: This seems expensive. Can we do a partial job to get
// just this data.
- VtableBuilder b(methods, RD, CGM);
+ VtableBuilder b(methods, RD, RD, 0, CGM);
D1(printf("vtable %s\n", RD->getNameAsCString()));
b.GenerateVtableForBase(RD);
b.GenerateVtableForVBases(RD);
@@ -623,7 +743,7 @@ int64_t CGVtableInfo::getMethodVtableIndex(const CXXMethodDecl *MD) {
MethodVtableIndices.insert(b.getIndex().begin(),
b.getIndex().end());
- I = MethodVtableIndices.find(MD);
+ I = MethodVtableIndices.find(GD);
assert(I != MethodVtableIndices.end() && "Did not find index!");
return I->second;
}
@@ -640,7 +760,7 @@ int64_t CGVtableInfo::getVirtualBaseOffsetIndex(const CXXRecordDecl *RD,
std::vector<llvm::Constant *> methods;
// FIXME: This seems expensive. Can we do a partial job to get
// just this data.
- VtableBuilder b(methods, RD, CGM);
+ VtableBuilder b(methods, RD, RD, 0, CGM);
D1(printf("vtable %s\n", RD->getNameAsCString()));
b.GenerateVtableForBase(RD);
b.GenerateVtableForVBases(RD);
@@ -659,10 +779,15 @@ int64_t CGVtableInfo::getVirtualBaseOffsetIndex(const CXXRecordDecl *RD,
return I->second;
}
-llvm::Value *CodeGenFunction::GenerateVtable(const CXXRecordDecl *RD) {
+llvm::Constant *CodeGenModule::GenerateVtable(const CXXRecordDecl *LayoutClass,
+ const CXXRecordDecl *RD,
+ uint64_t Offset) {
llvm::SmallString<256> OutName;
llvm::raw_svector_ostream Out(OutName);
- mangleCXXVtable(CGM.getMangleContext(), RD, Out);
+ if (LayoutClass != RD)
+ mangleCXXCtorVtable(getMangleContext(), LayoutClass, Offset/8, RD, Out);
+ else
+ mangleCXXVtable(getMangleContext(), RD, Out);
llvm::GlobalVariable::LinkageTypes linktype;
linktype = llvm::GlobalValue::LinkOnceODRLinkage;
@@ -670,23 +795,245 @@ llvm::Value *CodeGenFunction::GenerateVtable(const CXXRecordDecl *RD) {
llvm::Type *Ptr8Ty=llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext),0);
int64_t AddressPoint;
- VtableBuilder b(methods, RD, CGM);
+ VtableBuilder b(methods, RD, LayoutClass, Offset, *this);
D1(printf("vtable %s\n", RD->getNameAsCString()));
// First comes the vtables for all the non-virtual bases...
- AddressPoint = b.GenerateVtableForBase(RD);
+ AddressPoint = b.GenerateVtableForBase(RD, Offset);
// then the vtables for all the virtual bases.
- b.GenerateVtableForVBases(RD);
+ b.GenerateVtableForVBases(RD, Offset);
+
+ CodeGenModule::AddrMap_t *&ref = AddressPoints[LayoutClass];
+ if (ref == 0)
+ ref = new CodeGenModule::AddrMap_t;
+
+ (*ref)[RD] = b.getAddressPoints();
llvm::Constant *C;
llvm::ArrayType *type = llvm::ArrayType::get(Ptr8Ty, methods.size());
C = llvm::ConstantArray::get(type, methods);
- llvm::Value *vtable = new llvm::GlobalVariable(CGM.getModule(), type, true,
- linktype, C, Out.str());
- vtable = Builder.CreateBitCast(vtable, Ptr8Ty);
- vtable = Builder.CreateGEP(vtable,
- llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
- AddressPoint*LLVMPointerWidth/8));
+ llvm::GlobalVariable *GV = new llvm::GlobalVariable(getModule(), type,
+ true, linktype, C,
+ Out.str());
+ bool Hidden = getDeclVisibilityMode(RD) == LangOptions::Hidden;
+ if (Hidden)
+ GV->setVisibility(llvm::GlobalVariable::HiddenVisibility);
+ llvm::Constant *vtable = llvm::ConstantExpr::getBitCast(GV, Ptr8Ty);
+ llvm::Constant *AddressPointC;
+ uint32_t LLVMPointerWidth = getContext().Target.getPointerWidth(0);
+ AddressPointC = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
+ AddressPoint*LLVMPointerWidth/8);
+ vtable = llvm::ConstantExpr::getInBoundsGetElementPtr(vtable, &AddressPointC,
+ 1);
+
return vtable;
}
+
+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;
+ CodeGenModule::AddrMap_t &AddressPoints;
+ // vtbl - A pointer to the vtable for Class.
+ llvm::Constant *ClassVtbl;
+ llvm::LLVMContext &VMContext;
+
+ /// BuildVtablePtr - Build up a referene to the given secondary vtable
+ llvm::Constant *BuildVtablePtr(llvm::Constant *vtbl,
+ const CXXRecordDecl *VtblClass,
+ const CXXRecordDecl *RD,
+ uint64_t Offset) {
+ int64_t AddressPoint;
+ AddressPoint = (*AddressPoints[VtblClass])[std::make_pair(RD, Offset)];
+ // FIXME: We can never have 0 address point. Do this for now so gepping
+ // retains the same structure.
+ 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));
+ uint32_t LLVMPointerWidth = CGM.getContext().Target.getPointerWidth(0);
+ llvm::Constant *init;
+ init = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
+ AddressPoint*LLVMPointerWidth/8);
+ init = llvm::ConstantExpr::getInBoundsGetElementPtr(vtbl, &init, 1);
+ return init;
+ }
+
+ /// 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 = BuildVtablePtr(vtbl, VtblClass, RD, Offset);
+ else {
+ init = CGM.getVtableInfo().getCtorVtable(Class, Base, BaseOffset);
+ subvtbl = dyn_cast<llvm::Constant>(init->getOperand(0));
+ subVtblClass = Base;
+ }
+ 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 *init;
+ const CXXRecordDecl *VtblClass;
+
+ // First comes the primary virtual table pointer...
+ if (MorallyVirtual) {
+ init = BuildVtablePtr(ClassVtbl, Class, RD, Offset);
+ VtblClass = Class;
+ } else {
+ init = CGM.getVtableInfo().getCtorVtable(Class, RD, Offset);
+ VtblClass = RD;
+ }
+ llvm::Constant *vtbl = dyn_cast<llvm::Constant>(init->getOperand(0));
+ Inits.push_back(init);
+
+ // then the secondary VTTs....
+ SecondaryVTTs(RD, Offset, MorallyVirtual);
+
+ // and last the secondary vtable pointers.
+ Secondary(RD, vtbl, VtblClass, 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, true);
+ }
+ VirtualVTTs(Base);
+ }
+ }
+public:
+ VTTBuilder(std::vector<llvm::Constant *> &inits, const CXXRecordDecl *c,
+ CodeGenModule &cgm)
+ : Inits(inits), Class(c), CGM(cgm),
+ BLayout(cgm.getContext().getASTRecordLayout(c)),
+ AddressPoints(*cgm.AddressPoints[c]),
+ VMContext(cgm.getModule().getContext()) {
+
+ // First comes the primary virtual table pointer for the complete class...
+ ClassVtbl = CGM.getVtableInfo().getVtable(Class);
+ Inits.push_back(ClassVtbl);
+ ClassVtbl = dyn_cast<llvm::Constant>(ClassVtbl->getOperand(0));
+
+ // then the secondary VTTs...
+ SecondaryVTTs(Class);
+
+ // then the secondary vtable pointers...
+ Secondary(Class, ClassVtbl, Class);
+
+ // and last, the virtual VTTs.
+ VirtualVTTs(Class);
+ }
+};
+
+llvm::Constant *CodeGenModule::GenerateVTT(const CXXRecordDecl *RD) {
+ // Only classes that have virtual bases need a VTT.
+ if (RD->getNumVBases() == 0)
+ return 0;
+
+ llvm::SmallString<256> OutName;
+ llvm::raw_svector_ostream Out(OutName);
+ mangleCXXVTT(getMangleContext(), RD, Out);
+
+ llvm::GlobalVariable::LinkageTypes linktype;
+ linktype = llvm::GlobalValue::LinkOnceODRLinkage;
+ std::vector<llvm::Constant *> inits;
+ llvm::Type *Ptr8Ty=llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext),0);
+
+ D1(printf("vtt %s\n", RD->getNameAsCString()));
+
+ VTTBuilder b(inits, RD, *this);
+
+ llvm::Constant *C;
+ llvm::ArrayType *type = llvm::ArrayType::get(Ptr8Ty, inits.size());
+ C = llvm::ConstantArray::get(type, inits);
+ llvm::GlobalVariable *vtt = new llvm::GlobalVariable(getModule(), type, true,
+ linktype, C, Out.str());
+ bool Hidden = getDeclVisibilityMode(RD) == LangOptions::Hidden;
+ if (Hidden)
+ vtt->setVisibility(llvm::GlobalVariable::HiddenVisibility);
+ return llvm::ConstantExpr::getBitCast(vtt, Ptr8Ty);
+}
+
+llvm::Constant *CGVtableInfo::getVtable(const CXXRecordDecl *RD) {
+ llvm::Constant *&vtbl = Vtables[RD];
+ if (vtbl)
+ return vtbl;
+ vtbl = CGM.GenerateVtable(RD, RD);
+ CGM.GenerateRtti(RD);
+ CGM.GenerateVTT(RD);
+ return vtbl;
+}
+
+llvm::Constant *CGVtableInfo::getCtorVtable(const CXXRecordDecl *LayoutClass,
+ const CXXRecordDecl *RD,
+ uint64_t Offset) {
+ return CGM.GenerateVtable(LayoutClass, RD, Offset);
+}
diff --git a/lib/CodeGen/CGVtable.h b/lib/CodeGen/CGVtable.h
index 69fb1f100599..f9ddf44284b1 100644
--- a/lib/CodeGen/CGVtable.h
+++ b/lib/CodeGen/CGVtable.h
@@ -15,6 +15,7 @@
#define CLANG_CODEGEN_CGVTABLE_H
#include "llvm/ADT/DenseMap.h"
+#include "GlobalDecl.h"
namespace clang {
class CXXMethodDecl;
@@ -28,7 +29,7 @@ class CGVtableInfo {
/// MethodVtableIndices - Contains the index (relative to the vtable address
/// point) where the function pointer for a virtual function is stored.
- typedef llvm::DenseMap<const CXXMethodDecl *, int64_t> MethodVtableIndicesTy;
+ typedef llvm::DenseMap<GlobalDecl, int64_t> MethodVtableIndicesTy;
MethodVtableIndicesTy MethodVtableIndices;
typedef std::pair<const CXXRecordDecl *,
@@ -38,6 +39,8 @@ class CGVtableInfo {
/// offsets for virtual bases of a class are stored.
typedef llvm::DenseMap<ClassPairTy, int64_t> VirtualBaseClassIndiciesTy;
VirtualBaseClassIndiciesTy VirtualBaseClassIndicies;
+
+ llvm::DenseMap<const CXXRecordDecl *, llvm::Constant *> Vtables;
public:
CGVtableInfo(CodeGenModule &CGM)
: CGM(CGM) { }
@@ -45,7 +48,7 @@ public:
/// getMethodVtableIndex - Return the index (relative to the vtable address
/// point) where the function pointer for the given virtual function is
/// stored.
- int64_t getMethodVtableIndex(const CXXMethodDecl *MD);
+ int64_t getMethodVtableIndex(GlobalDecl GD);
/// getVirtualBaseOffsetIndex - Return the index (relative to the vtable
/// address point) where the offset of the virtual base that contains the
@@ -54,6 +57,10 @@ public:
/// base.
int64_t getVirtualBaseOffsetIndex(const CXXRecordDecl *RD,
const CXXRecordDecl *VBase);
+
+ llvm::Constant *getVtable(const CXXRecordDecl *RD);
+ llvm::Constant *getCtorVtable(const CXXRecordDecl *RD,
+ const CXXRecordDecl *Class, uint64_t Offset);
};
}
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index 4be341311ce4..475c7bfefd1d 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -27,11 +27,7 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm)
: BlockFunction(cgm, *this, Builder), CGM(cgm),
Target(CGM.getContext().Target),
Builder(cgm.getModule().getContext()),
-#ifndef USEINDIRECTBRANCH
- DebugInfo(0), IndirectGotoSwitch(0),
-#else
DebugInfo(0), IndirectBranch(0),
-#endif
SwitchInsn(0), CaseRangeBlock(0), InvokeDest(0),
CXXThisDecl(0) {
LLVMIntTy = ConvertType(getContext().IntTy);
@@ -134,7 +130,6 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
EmitFunctionEpilog(*CurFnInfo, ReturnValue);
-#ifdef USEINDIRECTBRANCH
// If someone did an indirect goto, emit the indirect goto block at the end of
// the function.
if (IndirectBranch) {
@@ -142,13 +137,10 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
Builder.ClearInsertionPoint();
}
-
-#endif
// Remove the AllocaInsertPt instruction, which is just a convenience for us.
llvm::Instruction *Ptr = AllocaInsertPt;
AllocaInsertPt = 0;
Ptr->eraseFromParent();
-#ifdef USEINDIRECTBRANCH
// If someone took the address of a label but never did an indirect goto, we
// made a zero entry PHI node, which is illegal, zap it now.
@@ -159,8 +151,6 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
PN->eraseFromParent();
}
}
-
-#endif
}
void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
@@ -260,19 +250,21 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD,
// FIXME: Support CXXTryStmt here, too.
if (const CompoundStmt *S = FD->getCompoundBody()) {
StartFunction(GD, FD->getResultType(), Fn, Args, S->getLBracLoc());
- const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(FD);
- llvm::BasicBlock *DtorEpilogue = 0;
- if (DD) {
- DtorEpilogue = createBasicBlock("dtor.epilogue");
-
- PushCleanupBlock(DtorEpilogue);
- }
-
- if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD))
+
+ if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD)) {
EmitCtorPrologue(CD, GD.getCtorType());
- EmitStmt(S);
+ EmitStmt(S);
+
+ // If any of the member initializers are temporaries bound to references
+ // make sure to emit their destructors.
+ EmitCleanupBlocks(0);
+
+ } else if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(FD)) {
+ llvm::BasicBlock *DtorEpilogue = createBasicBlock("dtor.epilogue");
+ PushCleanupBlock(DtorEpilogue);
+
+ EmitStmt(S);
- if (DD) {
CleanupBlockInfo Info = PopCleanupBlock();
assert(Info.CleanupBlock == DtorEpilogue && "Block mismatch!");
@@ -283,7 +275,11 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD,
EmitBlock(Info.SwitchBlock);
if (Info.EndBlock)
EmitBlock(Info.EndBlock);
+ } else {
+ // Just a regular function, emit its body.
+ EmitStmt(S);
}
+
FinishFunction(S->getRBracLoc());
} else if (FD->isImplicit()) {
const CXXRecordDecl *ClassDecl =
@@ -493,121 +489,32 @@ void CodeGenFunction::EmitMemSetToZero(llvm::Value *DestPtr, QualType Ty) {
TypeInfo.second/8));
}
-#ifndef USEINDIRECTBRANCH
-unsigned CodeGenFunction::GetIDForAddrOfLabel(const LabelStmt *L) {
- // Use LabelIDs.size()+1 as the new ID if one hasn't been assigned.
- unsigned &Entry = LabelIDs[L];
- if (Entry) return Entry;
-#else
-
llvm::BlockAddress *CodeGenFunction::GetAddrOfLabel(const LabelStmt *L) {
// Make sure that there is a block for the indirect goto.
if (IndirectBranch == 0)
GetIndirectGotoBlock();
-#endif
-#ifndef USEINDIRECTBRANCH
- Entry = LabelIDs.size();
-#else
llvm::BasicBlock *BB = getBasicBlockForLabel(L);
-#endif
-
-#ifndef USEINDIRECTBRANCH
- // If this is the first "address taken" of a label and the indirect goto has
- // already been seen, add this to it.
- if (IndirectGotoSwitch) {
- // If this is the first address-taken label, set it as the default dest.
- if (Entry == 1)
- IndirectGotoSwitch->setSuccessor(0, getBasicBlockForLabel(L));
- else {
- // Otherwise add it to the switch as a new dest.
- const llvm::IntegerType *Int32Ty = llvm::Type::getInt32Ty(VMContext);
- IndirectGotoSwitch->addCase(llvm::ConstantInt::get(Int32Ty, Entry),
- getBasicBlockForLabel(L));
- }
- }
- return Entry;
-#else
// Make sure the indirect branch includes all of the address-taken blocks.
IndirectBranch->addDestination(BB);
return llvm::BlockAddress::get(CurFn, BB);
-#endif
}
llvm::BasicBlock *CodeGenFunction::GetIndirectGotoBlock() {
-#ifndef USEINDIRECTBRANCH
- // If we already made the switch stmt for indirect goto, return its block.
- if (IndirectGotoSwitch) return IndirectGotoSwitch->getParent();
-#else
// If we already made the indirect branch for indirect goto, return its block.
if (IndirectBranch) return IndirectBranch->getParent();
-#endif
-#ifndef USEINDIRECTBRANCH
- EmitBlock(createBasicBlock("indirectgoto"));
-#else
CGBuilderTy TmpBuilder(createBasicBlock("indirectgoto"));
-#endif
-#ifndef USEINDIRECTBRANCH
- const llvm::IntegerType *Int32Ty = llvm::Type::getInt32Ty(VMContext);
-#else
const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext);
-#endif
// Create the PHI node that indirect gotos will add entries to.
-#ifndef USEINDIRECTBRANCH
- llvm::Value *DestVal = Builder.CreatePHI(Int32Ty, "indirect.goto.dest");
-#else
llvm::Value *DestVal = TmpBuilder.CreatePHI(Int8PtrTy, "indirect.goto.dest");
-#endif
-
-#ifndef USEINDIRECTBRANCH
- // Create the switch instruction. For now, set the insert block to this block
- // which will be fixed as labels are added.
- IndirectGotoSwitch = Builder.CreateSwitch(DestVal, Builder.GetInsertBlock());
-
- // Clear the insertion point to indicate we are in unreachable code.
- Builder.ClearInsertionPoint();
- // If we already have labels created, add them.
- if (!LabelIDs.empty()) {
- // Invert LabelID's so that the order is determinstic.
- std::vector<const LabelStmt*> AddrTakenLabelsByID;
- AddrTakenLabelsByID.resize(LabelIDs.size());
-
- for (std::map<const LabelStmt*,unsigned>::iterator
- LI = LabelIDs.begin(), LE = LabelIDs.end(); LI != LE; ++LI) {
- assert(LI->second-1 < AddrTakenLabelsByID.size() &&
- "Numbering inconsistent");
- AddrTakenLabelsByID[LI->second-1] = LI->first;
- }
-
- // Set the default entry as the first block.
- IndirectGotoSwitch->setSuccessor(0,
- getBasicBlockForLabel(AddrTakenLabelsByID[0]));
-
- // FIXME: The iteration order of this is nondeterminstic!
- for (unsigned i = 1, e = AddrTakenLabelsByID.size(); i != e; ++i)
- IndirectGotoSwitch->addCase(llvm::ConstantInt::get(Int32Ty, i+1),
- getBasicBlockForLabel(AddrTakenLabelsByID[i]));
- } else {
- // Otherwise, create a dead block and set it as the default dest. This will
- // be removed by the optimizers after the indirect goto is set up.
- llvm::BasicBlock *Dummy = createBasicBlock("indgoto.dummy");
- EmitBlock(Dummy);
- IndirectGotoSwitch->setSuccessor(0, Dummy);
- Builder.CreateUnreachable();
- Builder.ClearInsertionPoint();
- }
-
- return IndirectGotoSwitch->getParent();
-#else
// Create the indirect branch instruction.
IndirectBranch = TmpBuilder.CreateIndirectBr(DestVal);
return IndirectBranch->getParent();
-#endif
}
llvm::Value *CodeGenFunction::GetVLASize(const VariableArrayType *VAT) {
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index fe8113e95332..d96c3551010e 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -74,7 +74,7 @@ class CodeGenFunction : public BlockFunction {
void operator=(const CodeGenFunction&); // DO NOT IMPLEMENT
public:
CodeGenModule &CGM; // Per-module state.
- TargetInfo &Target;
+ const TargetInfo &Target;
typedef std::pair<llvm::Value *, llvm::Value *> ComplexPairTy;
CGBuilderTy Builder;
@@ -193,28 +193,12 @@ public:
private:
CGDebugInfo *DebugInfo;
-#ifndef USEINDIRECTBRANCH
- /// LabelIDs - Track arbitrary ids assigned to labels for use in implementing
- /// the GCC address-of-label extension and indirect goto. IDs are assigned to
- /// labels inside getIDForAddrOfLabel().
- std::map<const LabelStmt*, unsigned> LabelIDs;
-#else
/// IndirectBranch - The first time an indirect goto is seen we create a
/// block with an indirect branch. Every time we see the address of a label
/// taken, we add the label to the indirect goto. Every subsequent indirect
/// goto is codegen'd as a jump to the IndirectBranch's basic block.
llvm::IndirectBrInst *IndirectBranch;
-#endif
-
-#ifndef USEINDIRECTBRANCH
- /// IndirectGotoSwitch - The first time an indirect goto is seen we create a
- /// block with the switch for the indirect gotos. Every time we see the
- /// address of a label taken, we add the label to the indirect goto. Every
- /// subsequent indirect goto is codegen'd as a jump to the
- /// IndirectGotoSwitch's basic block.
- llvm::SwitchInst *IndirectGotoSwitch;
-#endif
/// LocalDeclMap - This keeps track of the LLVM allocas or globals for local C
/// decls.
llvm::DenseMap<const Decl*, llvm::Value*> LocalDeclMap;
@@ -397,9 +381,6 @@ public:
/// legal to call this function even if there is no current insertion point.
void FinishFunction(SourceLocation EndLoc=SourceLocation());
- /// GenerateVtable - Generate the vtable for the given type.
- llvm::Value *GenerateVtable(const CXXRecordDecl *RD);
-
/// DynamicTypeAdjust - Do the non-virtual and virtual adjustments on an
/// object pointer to alter the dynamic type of the pointer. Used by
/// GenerateCovariantThunk for building thunks.
@@ -586,11 +567,7 @@ public:
/// the input field number being accessed.
static unsigned getAccessedFieldNo(unsigned Idx, const llvm::Constant *Elts);
-#ifndef USEINDIRECTBRANCH
- unsigned GetIDForAddrOfLabel(const LabelStmt *L);
-#else
llvm::BlockAddress *GetAddrOfLabel(const LabelStmt *L);
-#endif
llvm::BasicBlock *GetIndirectGotoBlock();
/// EmitMemSetToZero - Generate code to memset a value of the given type to 0.
@@ -669,6 +646,14 @@ public:
const ArrayType *Array,
llvm::Value *This);
+ void EmitCXXAggrDestructorCall(const CXXDestructorDecl *D,
+ llvm::Value *NumElements,
+ llvm::Value *This);
+
+ llvm::Constant * GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D,
+ const ArrayType *Array,
+ llvm::Value *This);
+
void EmitCXXDestructorCall(const CXXDestructorDecl *D, CXXDtorType Type,
llvm::Value *This);
@@ -678,6 +663,12 @@ public:
llvm::Value *EmitCXXNewExpr(const CXXNewExpr *E);
void EmitCXXDeleteExpr(const CXXDeleteExpr *E);
+ void EmitDeleteCall(const FunctionDecl *DeleteFD, llvm::Value *Ptr,
+ QualType DeleteTy);
+
+ llvm::Value* EmitCXXTypeidExpr(const CXXTypeidExpr *E);
+ llvm::Value *EmitDynamicCast(llvm::Value *V, const CXXDynamicCastExpr *DCE);
+
//===--------------------------------------------------------------------===//
// Declaration Emission
//===--------------------------------------------------------------------===//
@@ -851,17 +842,18 @@ public:
LValue EmitConditionalOperatorLValue(const ConditionalOperator *E);
LValue EmitCastLValue(const CastExpr *E);
LValue EmitNullInitializationLValue(const CXXZeroInitValueExpr *E);
- LValue EmitPointerToDataMemberLValue(const DeclRefExpr *E);
+
+ LValue EmitPointerToDataMemberLValue(const FieldDecl *Field);
llvm::Value *EmitIvarOffset(const ObjCInterfaceDecl *Interface,
const ObjCIvarDecl *Ivar);
- LValue EmitLValueForField(llvm::Value* Base, FieldDecl* Field,
+ LValue EmitLValueForField(llvm::Value* Base, const FieldDecl* Field,
bool isUnion, unsigned CVRQualifiers);
LValue EmitLValueForIvar(QualType ObjectTy,
llvm::Value* Base, const ObjCIvarDecl *Ivar,
unsigned CVRQualifiers);
- LValue EmitLValueForBitfield(llvm::Value* Base, FieldDecl* Field,
+ LValue EmitLValueForBitfield(llvm::Value* Base, const FieldDecl* Field,
unsigned CVRQualifiers);
LValue EmitBlockDeclRefLValue(const BlockDeclRefExpr *E);
@@ -870,6 +862,7 @@ public:
LValue EmitCXXConstructLValue(const CXXConstructExpr *E);
LValue EmitCXXBindTemporaryLValue(const CXXBindTemporaryExpr *E);
LValue EmitCXXExprWithTemporariesLValue(const CXXExprWithTemporaries *E);
+ LValue EmitCXXTypeidLValue(const CXXTypeidExpr *E);
LValue EmitObjCMessageExprLValue(const ObjCMessageExpr *E);
LValue EmitObjCIvarRefLValue(const ObjCIvarRefExpr *E);
@@ -901,8 +894,11 @@ public:
const Decl *TargetDecl = 0);
RValue EmitCallExpr(const CallExpr *E);
- llvm::Value *BuildVirtualCall(const CXXMethodDecl *MD, llvm::Value *&This,
+ llvm::Value *BuildVirtualCall(const CXXMethodDecl *MD, llvm::Value *This,
const llvm::Type *Ty);
+ llvm::Value *BuildVirtualCall(const CXXDestructorDecl *DD, CXXDtorType Type,
+ llvm::Value *&This, const llvm::Type *Ty);
+
RValue EmitCXXMemberCall(const CXXMethodDecl *MD,
llvm::Value *Callee,
llvm::Value *This,
@@ -1016,7 +1012,7 @@ public:
/// EmitCXXGlobalDtorRegistration - Emits a call to register the global ptr
/// with the C++ runtime so that its destructor will be called at exit.
- void EmitCXXGlobalDtorRegistration(const CXXDestructorDecl *Dtor,
+ void EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn,
llvm::Constant *DeclPtr);
/// GenerateCXXGlobalInitFunc - Generates code for initializing global
@@ -1033,7 +1029,7 @@ public:
bool IsInitializer = false);
void EmitCXXThrowExpr(const CXXThrowExpr *E);
-
+
//===--------------------------------------------------------------------===//
// Internal Helpers
//===--------------------------------------------------------------------===//
@@ -1101,6 +1097,7 @@ private:
if (CallArgTypeInfo) {
for (typename T::arg_type_iterator I = CallArgTypeInfo->arg_type_begin(),
E = CallArgTypeInfo->arg_type_end(); I != E; ++I, ++Arg) {
+ assert(Arg != ArgEnd && "Running over edge of argument list!");
QualType ArgType = *I;
assert(getContext().getCanonicalType(ArgType.getNonReferenceType()).
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index db609f62453c..0e6f4a63a42c 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -17,7 +17,7 @@
#include "CGCall.h"
#include "CGObjCRuntime.h"
#include "Mangle.h"
-#include "clang/Frontend/CompileOptions.h"
+#include "clang/CodeGen/CodeGenOptions.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclCXX.h"
@@ -30,15 +30,16 @@
#include "llvm/Module.h"
#include "llvm/Intrinsics.h"
#include "llvm/Target/TargetData.h"
+#include "llvm/Support/ErrorHandling.h"
using namespace clang;
using namespace CodeGen;
-CodeGenModule::CodeGenModule(ASTContext &C, const CompileOptions &compileOpts,
+CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
llvm::Module &M, const llvm::TargetData &TD,
Diagnostic &diags)
: BlockModule(C, M, TD, Types, *this), Context(C),
- Features(C.getLangOptions()), CompileOpts(compileOpts), TheModule(M),
+ Features(C.getLangOptions()), CodeGenOpts(CGO), TheModule(M),
TheTargetData(TD), Diags(diags), Types(C, M, TD), MangleCtx(C),
VtableInfo(*this), Runtime(0),
MemCpyFn(0), MemMoveFn(0), MemSetFn(0), CFConstantStringClassRef(0),
@@ -54,7 +55,7 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CompileOptions &compileOpts,
Runtime = CreateMacObjCRuntime(*this);
// If debug info generation is enabled, create the CGDebugInfo object.
- DebugInfo = CompileOpts.DebugInfo ? new CGDebugInfo(this) : 0;
+ DebugInfo = CodeGenOpts.DebugInfo ? new CGDebugInfo(this) : 0;
}
CodeGenModule::~CodeGenModule() {
@@ -347,6 +348,11 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
if (D->hasAttr<NoInlineAttr>())
F->addFnAttr(llvm::Attribute::NoInline);
+ if (Features.getStackProtectorMode() == LangOptions::SSPOn)
+ F->addFnAttr(llvm::Attribute::StackProtect);
+ else if (Features.getStackProtectorMode() == LangOptions::SSPReq)
+ F->addFnAttr(llvm::Attribute::StackProtectReq);
+
if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
F->setAlignment(AA->getAlignment()/8);
// C++ ABI requires 2-byte alignment for member functions.
@@ -543,10 +549,15 @@ bool CodeGenModule::MayDeferGeneration(const ValueDecl *Global) {
// Static data may be deferred, but out-of-line static data members
// cannot be.
- // FIXME: What if the initializer has side effects?
- return VD->isInAnonymousNamespace() ||
- (VD->getStorageClass() == VarDecl::Static &&
- !(VD->isStaticDataMember() && VD->isOutOfLine()));
+ if (VD->isInAnonymousNamespace())
+ return true;
+ if (VD->getStorageClass() == VarDecl::Static) {
+ // Initializer has side effects?
+ if (VD->getInit() && VD->getInit()->HasSideEffects(Context))
+ return false;
+ return !(VD->isStaticDataMember() && VD->isOutOfLine());
+ }
+ return false;
}
void CodeGenModule::EmitGlobal(GlobalDecl GD) {
@@ -639,6 +650,24 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(const char *MangledName,
return llvm::ConstantExpr::getBitCast(Entry, PTy);
}
+ // This function doesn't have a complete type (for example, the return
+ // type is an incomplete struct). Use a fake type instead, and make
+ // sure not to try to set attributes.
+ bool IsIncompleteFunction = false;
+ if (!isa<llvm::FunctionType>(Ty)) {
+ Ty = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
+ std::vector<const llvm::Type*>(), false);
+ IsIncompleteFunction = true;
+ }
+ llvm::Function *F = llvm::Function::Create(cast<llvm::FunctionType>(Ty),
+ llvm::Function::ExternalLinkage,
+ "", &getModule());
+ F->setName(MangledName);
+ if (D.getDecl())
+ SetFunctionAttributes(cast<FunctionDecl>(D.getDecl()), F,
+ IsIncompleteFunction);
+ Entry = F;
+
// This is the first use or definition of a mangled name. If there is a
// deferred decl with this name, remember that we need to emit it at the end
// of the file.
@@ -672,23 +701,6 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(const char *MangledName,
DeferredCopyAssignmentToEmit(D);
}
- // This function doesn't have a complete type (for example, the return
- // type is an incomplete struct). Use a fake type instead, and make
- // sure not to try to set attributes.
- bool IsIncompleteFunction = false;
- if (!isa<llvm::FunctionType>(Ty)) {
- Ty = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
- std::vector<const llvm::Type*>(), false);
- IsIncompleteFunction = true;
- }
- llvm::Function *F = llvm::Function::Create(cast<llvm::FunctionType>(Ty),
- llvm::Function::ExternalLinkage,
- "", &getModule());
- F->setName(MangledName);
- if (D.getDecl())
- SetFunctionAttributes(cast<FunctionDecl>(D.getDecl()), F,
- IsIncompleteFunction);
- Entry = F;
return F;
}
@@ -1075,7 +1087,7 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
GV->setLinkage(llvm::GlobalVariable::WeakAnyLinkage);
} else if (Linkage == GVA_TemplateInstantiation)
GV->setLinkage(llvm::GlobalVariable::WeakAnyLinkage);
- else if (!CompileOpts.NoCommon &&
+ else if (!CodeGenOpts.NoCommon &&
!D->hasExternalStorage() && !D->getInit() &&
!D->getAttr<SectionAttr>()) {
GV->setLinkage(llvm::GlobalVariable::CommonLinkage);
@@ -1548,7 +1560,14 @@ std::string CodeGenModule::GetStringForStringLiteral(const StringLiteral *E) {
llvm::Constant *
CodeGenModule::GetAddrOfConstantStringFromLiteral(const StringLiteral *S) {
// FIXME: This can be more efficient.
- return GetAddrOfConstantString(GetStringForStringLiteral(S));
+ // FIXME: We shouldn't need to bitcast the constant in the wide string case.
+ llvm::Constant *C = GetAddrOfConstantString(GetStringForStringLiteral(S));
+ if (S->isWide()) {
+ llvm::Type *DestTy =
+ llvm::PointerType::getUnqual(getTypes().ConvertType(S->getType()));
+ C = llvm::ConstantExpr::getBitCast(C, DestTy);
+ }
+ return C;
}
/// GetAddrOfConstantStringFromObjCEncode - Return a pointer to a constant
@@ -1697,6 +1716,7 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
EmitNamespace(cast<NamespaceDecl>(D));
break;
// No code generation needed.
+ case Decl::UsingShadow:
case Decl::Using:
case Decl::UsingDirective:
case Decl::ClassTemplate:
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index 2e58337ee52d..c8562d6745eb 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -23,6 +23,7 @@
#include "CGCXX.h"
#include "CGVtable.h"
#include "CodeGenTypes.h"
+#include "GlobalDecl.h"
#include "Mangle.h"
#include "llvm/Module.h"
#include "llvm/ADT/DenseMap.h"
@@ -31,8 +32,6 @@
#include "llvm/Support/ValueHandle.h"
#include <list>
-#define ATTACH_DEBUG_INFO_TO_AN_INSN 1
-
namespace llvm {
class Module;
class Constant;
@@ -61,7 +60,7 @@ namespace clang {
class ValueDecl;
class VarDecl;
class LangOptions;
- class CompileOptions;
+ class CodeGenOptions;
class Diagnostic;
class AnnotateAttr;
class CXXDestructorDecl;
@@ -72,46 +71,7 @@ namespace CodeGen {
class CGDebugInfo;
class CGObjCRuntime;
-/// GlobalDecl - represents a global declaration. This can either be a
-/// CXXConstructorDecl and the constructor type (Base, Complete).
-/// a CXXDestructorDecl and the destructor type (Base, Complete) or
-/// a VarDecl, a FunctionDecl or a BlockDecl.
-class GlobalDecl {
- llvm::PointerIntPair<const Decl*, 2> Value;
-
- void Init(const Decl *D) {
- assert(!isa<CXXConstructorDecl>(D) && "Use other ctor with ctor decls!");
- assert(!isa<CXXDestructorDecl>(D) && "Use other ctor with dtor decls!");
-
- Value.setPointer(D);
- }
-public:
- GlobalDecl() {}
-
- GlobalDecl(const VarDecl *D) { Init(D);}
- GlobalDecl(const FunctionDecl *D) { Init(D); }
- GlobalDecl(const BlockDecl *D) { Init(D); }
- GlobalDecl(const ObjCMethodDecl *D) { Init(D); }
-
- GlobalDecl(const CXXConstructorDecl *D, CXXCtorType Type)
- : Value(D, Type) {}
- GlobalDecl(const CXXDestructorDecl *D, CXXDtorType Type)
- : Value(D, Type) {}
-
- const Decl *getDecl() const { return Value.getPointer(); }
-
- CXXCtorType getCtorType() const {
- assert(isa<CXXConstructorDecl>(getDecl()) && "Decl is not a ctor!");
- return static_cast<CXXCtorType>(Value.getInt());
- }
-
- CXXDtorType getDtorType() const {
- assert(isa<CXXDestructorDecl>(getDecl()) && "Decl is not a dtor!");
- return static_cast<CXXDtorType>(Value.getInt());
- }
-};
-
/// CodeGenModule - This class organizes the cross-function state that is used
/// while generating LLVM code.
class CodeGenModule : public BlockModule {
@@ -122,7 +82,7 @@ class CodeGenModule : public BlockModule {
ASTContext &Context;
const LangOptions &Features;
- const CompileOptions &CompileOpts;
+ const CodeGenOptions &CodeGenOpts;
llvm::Module &TheModule;
const llvm::TargetData &TheTargetData;
Diagnostic &Diags;
@@ -201,7 +161,7 @@ class CodeGenModule : public BlockModule {
llvm::LLVMContext &VMContext;
public:
- CodeGenModule(ASTContext &C, const CompileOptions &CompileOpts,
+ CodeGenModule(ASTContext &C, const CodeGenOptions &CodeGenOpts,
llvm::Module &M, const llvm::TargetData &TD, Diagnostic &Diags);
~CodeGenModule();
@@ -222,7 +182,7 @@ public:
CGDebugInfo *getDebugInfo() { return DebugInfo; }
ASTContext &getContext() const { return Context; }
- const CompileOptions &getCompileOpts() const { return CompileOpts; }
+ const CodeGenOptions &getCodeGenOpts() const { return CodeGenOpts; }
const LangOptions &getLangOptions() const { return Features; }
llvm::Module &getModule() const { return TheModule; }
CodeGenTypes &getTypes() { return Types; }
@@ -252,8 +212,26 @@ public:
llvm::Constant *GetAddrOfFunction(GlobalDecl GD,
const llvm::Type *Ty = 0);
+ /// GenerateVtable - Generate the vtable for the given type. LayoutClass is
+ /// the class to use for the virtual base layout information. For
+ /// non-construction vtables, this is always the same as RD. Offset is the
+ /// offset in bits for the RD object in the LayoutClass, if we're generating a
+ /// construction vtable, otherwise 0.
+ llvm::Constant *GenerateVtable(const CXXRecordDecl *LayoutClass,
+ const CXXRecordDecl *RD,
+ uint64_t Offset=0);
+
+ /// GenerateVTT - Generate the VTT for the given type.
+ llvm::Constant *GenerateVTT(const CXXRecordDecl *RD);
+
/// GenerateRtti - Generate the rtti information for the given type.
llvm::Constant *GenerateRtti(const CXXRecordDecl *RD);
+ /// GenerateRttiRef - Generate a reference to the rtti information for the
+ /// given type.
+ llvm::Constant *GenerateRttiRef(const CXXRecordDecl *RD);
+ /// GenerateRttiNonClass - Generate the rtti information for the given
+ /// non-class type.
+ llvm::Constant *GenerateRttiNonClass(QualType Ty);
/// BuildThunk - Build a thunk for the given method
llvm::Constant *BuildThunk(const CXXMethodDecl *MD, bool Extern, int64_t nv,
@@ -263,6 +241,11 @@ public:
int64_t nv_t, int64_t v_t,
int64_t nv_r, int64_t v_r);
+ typedef std::pair<const CXXRecordDecl *, uint64_t> CtorVtable_t;
+ typedef llvm::DenseMap<const CXXRecordDecl *,
+ llvm::DenseMap<CtorVtable_t, int64_t>*> AddrMap_t;
+ llvm::DenseMap<const CXXRecordDecl *, AddrMap_t*> AddressPoints;
+
/// GetCXXBaseClassOffset - Returns the offset from a derived class to its
/// base class. Returns null if the offset is 0.
llvm::Constant *GetCXXBaseClassOffset(const CXXRecordDecl *ClassDecl,
@@ -499,7 +482,7 @@ private:
/// EmitCXXGlobalInitFunc - Emit a function that initializes C++ globals.
void EmitCXXGlobalInitFunc();
-
+
// FIXME: Hardcoding priority here is gross.
void AddGlobalCtor(llvm::Function *Ctor, int Priority=65535);
void AddGlobalDtor(llvm::Function *Dtor, int Priority=65535);
diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp
index d43d13e26bbb..1f83f37e0479 100644
--- a/lib/CodeGen/CodeGenTypes.cpp
+++ b/lib/CodeGen/CodeGenTypes.cpp
@@ -492,7 +492,7 @@ const CGRecordLayout &
CodeGenTypes::getCGRecordLayout(const TagDecl *TD) const {
const Type *Key =
Context.getTagDeclType(TD).getTypePtr();
- llvm::DenseMap<const Type*, CGRecordLayout *>::iterator I
+ llvm::DenseMap<const Type*, CGRecordLayout *>::const_iterator I
= CGRecordLayouts.find(Key);
assert (I != CGRecordLayouts.end()
&& "Unable to find record layout information for type");
diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h
index a92a019b988e..f447549f669c 100644
--- a/lib/CodeGen/CodeGenTypes.h
+++ b/lib/CodeGen/CodeGenTypes.h
@@ -91,7 +91,7 @@ namespace CodeGen {
/// while lowering AST types to LLVM types.
class CodeGenTypes {
ASTContext &Context;
- TargetInfo &Target;
+ const TargetInfo &Target;
llvm::Module& TheModule;
const llvm::TargetData& TheTargetData;
mutable const ABIInfo* TheABIInfo;
@@ -153,7 +153,7 @@ public:
~CodeGenTypes();
const llvm::TargetData &getTargetData() const { return TheTargetData; }
- TargetInfo &getTarget() const { return Target; }
+ const TargetInfo &getTarget() const { return Target; }
ASTContext &getContext() const { return Context; }
const ABIInfo &getABIInfo() const;
llvm::LLVMContext &getLLVMContext() { return TheModule.getContext(); }
diff --git a/lib/CodeGen/GlobalDecl.h b/lib/CodeGen/GlobalDecl.h
new file mode 100644
index 000000000000..b812020f2aa4
--- /dev/null
+++ b/lib/CodeGen/GlobalDecl.h
@@ -0,0 +1,110 @@
+//===--- GlobalDecl.h - Global declaration holder ---------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// A GlobalDecl can hold either a regular variable/function or a C++ ctor/dtor
+// together with its type.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_CODEGEN_GLOBALDECL_H
+#define CLANG_CODEGEN_GLOBALDECL_H
+
+namespace clang {
+
+namespace CodeGen {
+
+/// GlobalDecl - represents a global declaration. This can either be a
+/// CXXConstructorDecl and the constructor type (Base, Complete).
+/// a CXXDestructorDecl and the destructor type (Base, Complete) or
+/// a VarDecl, a FunctionDecl or a BlockDecl.
+class GlobalDecl {
+ llvm::PointerIntPair<const Decl*, 2> Value;
+
+ void Init(const Decl *D) {
+ assert(!isa<CXXConstructorDecl>(D) && "Use other ctor with ctor decls!");
+ assert(!isa<CXXDestructorDecl>(D) && "Use other ctor with dtor decls!");
+
+ Value.setPointer(D);
+ }
+
+public:
+ GlobalDecl() {}
+
+ GlobalDecl(const VarDecl *D) { Init(D);}
+ GlobalDecl(const FunctionDecl *D) { Init(D); }
+ GlobalDecl(const BlockDecl *D) { Init(D); }
+ GlobalDecl(const ObjCMethodDecl *D) { Init(D); }
+
+ GlobalDecl(const CXXConstructorDecl *D, CXXCtorType Type)
+ : Value(D, Type) {}
+ GlobalDecl(const CXXDestructorDecl *D, CXXDtorType Type)
+ : Value(D, Type) {}
+
+ const Decl *getDecl() const { return Value.getPointer(); }
+
+ CXXCtorType getCtorType() const {
+ assert(isa<CXXConstructorDecl>(getDecl()) && "Decl is not a ctor!");
+ return static_cast<CXXCtorType>(Value.getInt());
+ }
+
+ CXXDtorType getDtorType() const {
+ assert(isa<CXXDestructorDecl>(getDecl()) && "Decl is not a dtor!");
+ return static_cast<CXXDtorType>(Value.getInt());
+ }
+
+ friend bool operator==(const GlobalDecl &LHS, const GlobalDecl &RHS) {
+ return LHS.Value == RHS.Value;
+ }
+
+ void *getAsOpaquePtr() const { return Value.getOpaqueValue(); }
+
+ static GlobalDecl getFromOpaquePtr(void *P) {
+ GlobalDecl GD;
+ GD.Value.setFromOpaqueValue(P);
+ return GD;
+ }
+};
+
+} // end namespace CodeGen
+} // end namespace clang
+
+namespace llvm {
+ template<class> struct DenseMapInfo;
+
+ template<> struct DenseMapInfo<clang::CodeGen::GlobalDecl> {
+ static inline clang::CodeGen::GlobalDecl getEmptyKey() {
+ return clang::CodeGen::GlobalDecl();
+ }
+
+ static inline clang::CodeGen::GlobalDecl getTombstoneKey() {
+ return clang::CodeGen::GlobalDecl::
+ getFromOpaquePtr(reinterpret_cast<void*>(-1));
+ }
+
+ static unsigned getHashValue(clang::CodeGen::GlobalDecl GD) {
+ return DenseMapInfo<void*>::getHashValue(GD.getAsOpaquePtr());
+ }
+
+ static bool isEqual(clang::CodeGen::GlobalDecl LHS,
+ clang::CodeGen::GlobalDecl RHS) {
+ return LHS == RHS;
+ }
+
+ static bool isPod() {
+ // GlobalDecl isn't *technically* a POD type. However, we can get
+ // away with calling it a POD type since its copy constructor,
+ // copy assignment operator, and destructor are all trivial.
+ return true;
+ }
+
+ };
+
+}
+
+#endif
diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp
index a5b34527969b..0a7124de3621 100644
--- a/lib/CodeGen/Mangle.cpp
+++ b/lib/CodeGen/Mangle.cpp
@@ -53,7 +53,10 @@ namespace {
void mangleCXXVtable(const CXXRecordDecl *RD);
void mangleCXXVTT(const CXXRecordDecl *RD);
+ void mangleCXXCtorVtable(const CXXRecordDecl *RD, int64_t Offset,
+ const CXXRecordDecl *Type);
void mangleCXXRtti(QualType Ty);
+ void mangleCXXRttiName(QualType Ty);
void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type);
void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type);
@@ -65,6 +68,8 @@ namespace {
bool mangleStandardSubstitution(const NamedDecl *ND);
void addSubstitution(const NamedDecl *ND) {
+ ND = cast<NamedDecl>(ND->getCanonicalDecl());
+
addSubstitution(reinterpret_cast<uintptr_t>(ND));
}
void addSubstitution(QualType T);
@@ -127,8 +132,10 @@ static bool isInCLinkageSpecification(const Decl *D) {
bool CXXNameMangler::mangleFunctionDecl(const FunctionDecl *FD) {
// Clang's "overloadable" attribute extension to C/C++ implies name mangling
- // (always).
- if (!FD->hasAttr<OverloadableAttr>()) {
+ // (always) as does passing a C++ member function and a function
+ // whose name is not a simple identifier.
+ if (!FD->hasAttr<OverloadableAttr>() && !isa<CXXMethodDecl>(FD) &&
+ FD->getDeclName().isIdentifier()) {
// C functions are not mangled, and "main" is never mangled.
if (!Context.getASTContext().getLangOptions().CPlusPlus || FD->isMain())
return false;
@@ -140,7 +147,7 @@ bool CXXNameMangler::mangleFunctionDecl(const FunctionDecl *FD) {
return false;
// No name mangling in a C linkage specification.
- if (!isa<CXXMethodDecl>(FD) && isInCLinkageSpecification(FD))
+ if (isInCLinkageSpecification(FD))
return false;
}
@@ -212,6 +219,17 @@ void CXXNameMangler::mangleCXXVTT(const CXXRecordDecl *RD) {
mangleName(RD);
}
+void CXXNameMangler::mangleCXXCtorVtable(const CXXRecordDecl *RD,
+ int64_t Offset,
+ const CXXRecordDecl *Type) {
+ // <special-name> ::= TC <type> <offset number> _ <base type>
+ Out << "_ZTC";
+ mangleName(RD);
+ Out << Offset;
+ Out << "_";
+ mangleName(Type);
+}
+
void CXXNameMangler::mangleCXXRtti(QualType Ty) {
// <special-name> ::= TI <type> # typeinfo structure
Out << "_ZTI";
@@ -219,6 +237,13 @@ void CXXNameMangler::mangleCXXRtti(QualType Ty) {
mangleType(Ty);
}
+void CXXNameMangler::mangleCXXRttiName(QualType Ty) {
+ // <special-name> ::= TS <type> # typeinfo name (null terminated byte string)
+ Out << "_ZTS";
+
+ mangleType(Ty);
+}
+
void CXXNameMangler::mangleGuardVariable(const VarDecl *D) {
// <special-name> ::= GV <object name> # Guard variable for one-time
// # initialization
@@ -719,15 +744,15 @@ void CXXNameMangler::mangleType(QualType T) {
// Only operate on the canonical type!
T = Context.getASTContext().getCanonicalType(T);
- bool IsSubstitutable = T.hasQualifiers() || !isa<BuiltinType>(T);
+ bool IsSubstitutable = T.hasLocalQualifiers() || !isa<BuiltinType>(T);
if (IsSubstitutable && mangleSubstitution(T))
return;
- if (Qualifiers Quals = T.getQualifiers()) {
+ if (Qualifiers Quals = T.getLocalQualifiers()) {
mangleQualifiers(Quals);
// Recurse: even if the qualified type isn't yet substitutable,
// the unqualified type might be.
- mangleType(T.getUnqualifiedType());
+ mangleType(T.getLocalUnqualifiedType());
} else {
switch (T->getTypeClass()) {
#define ABSTRACT_TYPE(CLASS, PARENT)
@@ -1015,6 +1040,11 @@ void CXXNameMangler::mangleExpression(const Expr *E) {
// ::= <expr-primary>
switch (E->getStmtClass()) {
default: assert(false && "Unhandled expression kind!");
+
+ case Expr::ParenExprClass:
+ mangleExpression(cast<ParenExpr>(E)->getSubExpr());
+ break;
+
case Expr::DeclRefExprClass: {
const Decl *D = cast<DeclRefExpr>(E)->getDecl();
@@ -1169,6 +1199,7 @@ bool CXXNameMangler::mangleSubstitution(const NamedDecl *ND) {
if (mangleStandardSubstitution(ND))
return true;
+ ND = cast<NamedDecl>(ND->getCanonicalDecl());
return mangleSubstitution(reinterpret_cast<uintptr_t>(ND));
}
@@ -1255,6 +1286,8 @@ static bool isCharSpecialization(QualType T, const char *Name) {
bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) {
// <substitution> ::= St # ::std::
+ // FIXME: type_info == comes out as __ZNK3std9type_infoeqERKS0_ instead of
+ // __ZNKSt9type_infoeqERKS_
if (const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(ND)) {
if (isStdNamespace(NS)) {
Out << "St";
@@ -1433,6 +1466,23 @@ namespace clang {
os.flush();
}
+ void mangleCXXVTT(MangleContext &Context, const CXXRecordDecl *RD,
+ llvm::raw_ostream &os) {
+ CXXNameMangler Mangler(Context, os);
+ Mangler.mangleCXXVTT(RD);
+
+ os.flush();
+ }
+
+ void mangleCXXCtorVtable(MangleContext &Context, const CXXRecordDecl *RD,
+ int64_t Offset, const CXXRecordDecl *Type,
+ llvm::raw_ostream &os) {
+ CXXNameMangler Mangler(Context, os);
+ Mangler.mangleCXXCtorVtable(RD, Offset, Type);
+
+ os.flush();
+ }
+
void mangleCXXRtti(MangleContext &Context, QualType Ty,
llvm::raw_ostream &os) {
CXXNameMangler Mangler(Context, os);
@@ -1440,4 +1490,12 @@ namespace clang {
os.flush();
}
+
+ void mangleCXXRttiName(MangleContext &Context, QualType Ty,
+ llvm::raw_ostream &os) {
+ CXXNameMangler Mangler(Context, os);
+ Mangler.mangleCXXRttiName(Ty);
+
+ os.flush();
+ }
}
diff --git a/lib/CodeGen/Mangle.h b/lib/CodeGen/Mangle.h
index 7f46a106f32a..458708fca6ad 100644
--- a/lib/CodeGen/Mangle.h
+++ b/lib/CodeGen/Mangle.h
@@ -67,8 +67,13 @@ namespace clang {
llvm::raw_ostream &os);
void mangleCXXVTT(MangleContext &Context, const CXXRecordDecl *RD,
llvm::raw_ostream &os);
+ void mangleCXXCtorVtable(MangleContext &Context, const CXXRecordDecl *RD,
+ int64_t Offset, const CXXRecordDecl *Type,
+ llvm::raw_ostream &os);
void mangleCXXRtti(MangleContext &Context, QualType T,
llvm::raw_ostream &os);
+ void mangleCXXRttiName(MangleContext &Context, QualType T,
+ llvm::raw_ostream &os);
void mangleCXXCtor(MangleContext &Context, const CXXConstructorDecl *D,
CXXCtorType Type, llvm::raw_ostream &os);
void mangleCXXDtor(MangleContext &Context, const CXXDestructorDecl *D,
diff --git a/lib/CodeGen/ModuleBuilder.cpp b/lib/CodeGen/ModuleBuilder.cpp
index c8f686a06f50..1d8f31dd9b24 100644
--- a/lib/CodeGen/ModuleBuilder.cpp
+++ b/lib/CodeGen/ModuleBuilder.cpp
@@ -13,7 +13,7 @@
#include "clang/CodeGen/ModuleBuilder.h"
#include "CodeGenModule.h"
-#include "clang/Frontend/CompileOptions.h"
+#include "clang/CodeGen/CodeGenOptions.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
@@ -32,14 +32,14 @@ namespace {
Diagnostic &Diags;
llvm::OwningPtr<const llvm::TargetData> TD;
ASTContext *Ctx;
- const CompileOptions CompileOpts; // Intentionally copied in.
+ const CodeGenOptions CodeGenOpts; // Intentionally copied in.
protected:
llvm::OwningPtr<llvm::Module> M;
llvm::OwningPtr<CodeGen::CodeGenModule> Builder;
public:
CodeGeneratorImpl(Diagnostic &diags, const std::string& ModuleName,
- const CompileOptions &CO, llvm::LLVMContext& C)
- : Diags(diags), CompileOpts(CO), M(new llvm::Module(ModuleName, C)) {}
+ const CodeGenOptions &CGO, llvm::LLVMContext& C)
+ : Diags(diags), CodeGenOpts(CGO), M(new llvm::Module(ModuleName, C)) {}
virtual ~CodeGeneratorImpl() {}
@@ -57,7 +57,7 @@ namespace {
M->setTargetTriple(Ctx->Target.getTriple().getTriple());
M->setDataLayout(Ctx->Target.getTargetDescription());
TD.reset(new llvm::TargetData(Ctx->Target.getTargetDescription()));
- Builder.reset(new CodeGen::CodeGenModule(Context, CompileOpts,
+ Builder.reset(new CodeGen::CodeGenModule(Context, CodeGenOpts,
*M, *TD, Diags));
}
@@ -96,7 +96,7 @@ namespace {
CodeGenerator *clang::CreateLLVMCodeGen(Diagnostic &Diags,
const std::string& ModuleName,
- const CompileOptions &CO,
+ const CodeGenOptions &CGO,
llvm::LLVMContext& C) {
- return new CodeGeneratorImpl(Diags, ModuleName, CO, C);
+ return new CodeGeneratorImpl(Diags, ModuleName, CGO, C);
}
diff --git a/lib/CodeGen/TargetABIInfo.cpp b/lib/CodeGen/TargetABIInfo.cpp
index 852bba4ef033..ba0bc6668e27 100644
--- a/lib/CodeGen/TargetABIInfo.cpp
+++ b/lib/CodeGen/TargetABIInfo.cpp
@@ -168,8 +168,28 @@ static bool is32Or64BitBasicType(QualType Ty, ASTContext &Context) {
return Size == 32 || Size == 64;
}
-static bool areAllFields32Or64BitBasicType(const RecordDecl *RD,
- ASTContext &Context) {
+/// 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;
@@ -442,14 +462,13 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty,
if (Ty->isStructureType() && Context.getTypeSize(Ty) == 0)
return ABIArgInfo::getIgnore();
- // Expand structs with size <= 128-bits which consist only of
- // basic types (int, long long, float, double, xxx*). This is
- // non-recursive and does not ignore empty fields.
- if (const RecordType *RT = Ty->getAsStructureType()) {
- if (Context.getTypeSize(Ty) <= 4*32 &&
- areAllFields32Or64BitBasicType(RT->getDecl(), Context))
- return ABIArgInfo::getExpand();
- }
+ // 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 {
diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h
index 6088d9617cf0..fcd96f1e5c8c 100644
--- a/lib/Driver/ToolChains.h
+++ b/lib/Driver/ToolChains.h
@@ -137,7 +137,20 @@ public:
virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const;
virtual bool IsMathErrnoDefault() const;
+ virtual bool IsBlocksDefault() const {
+ // Blocks default to on for 10.6 (darwin10) and beyond.
+ return (DarwinVersion[0] > 9);
+ }
+ virtual bool IsObjCNonFragileABIDefault() const {
+ // Non-fragile ABI default to on for 10.5 (darwin9) and beyond on x86-64.
+ return (DarwinVersion[0] >= 9 &&
+ getTriple().getArch() == llvm::Triple::x86_64);
+ }
virtual bool IsUnwindTablesDefault() const;
+ virtual unsigned GetDefaultStackProtectorLevel() const {
+ // Stack protectors default to on for 10.6 (darwin10) and beyond.
+ return (DarwinVersion[0] > 9) ? 1 : 0;
+ }
virtual const char *GetDefaultRelocationModel() const;
virtual const char *GetForcedPicModel() const;
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 808c31c64828..34154f3a3dce 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -26,6 +26,7 @@
#include "llvm/ADT/Twine.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/System/Host.h"
#include "llvm/System/Process.h"
#include "InputInfo.h"
@@ -320,6 +321,23 @@ static std::string getLLVMTriple(const ToolChain &TC, const ArgList &Args) {
}
}
+// FIXME: Move to target hook.
+static bool isSignedCharDefault(const llvm::Triple &Triple) {
+ switch (Triple.getArch()) {
+ default:
+ return true;
+
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ if (Triple.getOS() == llvm::Triple::Darwin)
+ return true;
+ return false;
+
+ case llvm::Triple::systemz:
+ return false;
+ }
+}
+
void Clang::AddARMTargetArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
const Driver &D = getToolChain().getHost().getDriver();
@@ -428,28 +446,42 @@ void Clang::AddX86TargetArgs(const ArgList &Args,
false))
CmdArgs.push_back("--no-implicit-float");
+ const char *CPUName = 0;
if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
- // FIXME: We may need some translation here from the options gcc takes to
- // names the LLVM backend understand?
- CmdArgs.push_back("-mcpu");
- CmdArgs.push_back(A->getValue(Args));
- } else {
- // Select default CPU.
+ if (llvm::StringRef(A->getValue(Args)) == "native") {
+ // FIXME: Reject attempts to use -march=native unless the target matches
+ // the host.
+ //
+ // FIXME: We should also incorporate the detected target features for use
+ // with -native.
+ std::string CPU = llvm::sys::getHostCPUName();
+ if (!CPU.empty())
+ CPUName = Args.MakeArgString(CPU);
+ } else
+ CPUName = A->getValue(Args);
+ }
+ // Select the default CPU if none was given (or detection failed).
+ if (!CPUName) {
// FIXME: Need target hooks.
if (memcmp(getToolChain().getOS().c_str(), "darwin", 6) == 0) {
if (getToolChain().getArchName() == "x86_64")
- CmdArgs.push_back("--mcpu=core2");
+ CPUName = "core2";
else if (getToolChain().getArchName() == "i386")
- CmdArgs.push_back("--mcpu=yonah");
+ CPUName = "yonah";
} else {
if (getToolChain().getArchName() == "x86_64")
- CmdArgs.push_back("--mcpu=x86-64");
+ CPUName = "x86-64";
else if (getToolChain().getArchName() == "i386")
- CmdArgs.push_back("--mcpu=pentium4");
+ CPUName = "pentium4";
}
}
+ if (CPUName) {
+ CmdArgs.push_back("--mcpu");
+ CmdArgs.push_back(CPUName);
+ }
+
// FIXME: Use iterator.
for (ArgList::const_iterator
it = Args.begin(), ie = Args.end(); it != ie; ++it) {
@@ -855,18 +887,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_femit_all_decls);
Args.AddLastArg(CmdArgs, options::OPT_ffreestanding);
Args.AddLastArg(CmdArgs, options::OPT_fheinous_gnu_extensions);
- Args.AddLastArg(CmdArgs, options::OPT_fgnu_runtime);
Args.AddLastArg(CmdArgs, options::OPT_flax_vector_conversions);
- Args.AddLastArg(CmdArgs, options::OPT_fms_extensions);
- Args.AddLastArg(CmdArgs, options::OPT_fnext_runtime);
Args.AddLastArg(CmdArgs, options::OPT_fno_caret_diagnostics);
Args.AddLastArg(CmdArgs, options::OPT_fno_show_column);
Args.AddLastArg(CmdArgs, options::OPT_fobjc_gc_only);
Args.AddLastArg(CmdArgs, options::OPT_fobjc_gc);
Args.AddLastArg(CmdArgs, options::OPT_fobjc_sender_dependent_dispatch);
- // FIXME: Should we remove this?
- Args.AddLastArg(CmdArgs, options::OPT_fobjc_nonfragile_abi);
- Args.AddLastArg(CmdArgs, options::OPT_fobjc_tight_layout);
Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_print_source_range_info);
Args.AddLastArg(CmdArgs, options::OPT_ftime_report);
Args.AddLastArg(CmdArgs, options::OPT_ftrapv);
@@ -875,32 +901,34 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_pthread);
- // Forward stack protector flags.
+ // -stack-protector=0 is default.
+ unsigned StackProtectorLevel = 0;
if (Arg *A = Args.getLastArg(options::OPT_fno_stack_protector,
options::OPT_fstack_protector_all,
options::OPT_fstack_protector)) {
- if (A->getOption().matches(options::OPT_fno_stack_protector))
- CmdArgs.push_back("--stack-protector=0");
- else if (A->getOption().matches(options::OPT_fstack_protector))
- CmdArgs.push_back("--stack-protector=1");
- else
- CmdArgs.push_back("--stack-protector=2");
+ if (A->getOption().matches(options::OPT_fstack_protector))
+ StackProtectorLevel = 1;
+ else if (A->getOption().matches(options::OPT_fstack_protector_all))
+ StackProtectorLevel = 2;
+ } else
+ StackProtectorLevel = getToolChain().GetDefaultStackProtectorLevel();
+ if (StackProtectorLevel) {
+ CmdArgs.push_back("-stack-protector");
+ CmdArgs.push_back(Args.MakeArgString(llvm::Twine(StackProtectorLevel)));
}
// Forward -f options with positive and negative forms; we translate
// these by hand.
- // -fbuiltin is default, only pass non-default.
+ // -fbuiltin is default.
if (!Args.hasFlag(options::OPT_fbuiltin, options::OPT_fno_builtin))
CmdArgs.push_back("-fbuiltin=0");
- // -fblocks default varies depending on platform and language; only
- // pass if specified.
- if (Arg *A = Args.getLastArg(options::OPT_fblocks, options::OPT_fno_blocks)) {
- if (A->getOption().matches(options::OPT_fblocks))
- CmdArgs.push_back("-fblocks");
- else
- CmdArgs.push_back("-fblocks=0");
+ // -fblocks=0 is default.
+ if (Args.hasFlag(options::OPT_fblocks, options::OPT_fno_blocks,
+ getToolChain().IsBlocksDefault())) {
+ Args.AddLastArg(CmdArgs, options::OPT_fblock_introspection);
+ CmdArgs.push_back("-fblocks");
}
if (needsExceptions(Args, InputType, getToolChain().getTriple()))
@@ -908,18 +936,40 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
else
CmdArgs.push_back("-fexceptions=0");
- // -frtti is default, only pass non-default.
+ // -frtti is default.
if (!Args.hasFlag(options::OPT_frtti, options::OPT_fno_rtti))
CmdArgs.push_back("-frtti=0");
- // -fsigned-char/-funsigned-char default varies depending on platform; only
+ // -fsigned-char is default.
+ if (!Args.hasFlag(options::OPT_fsigned_char,
+ options::OPT_funsigned_char,
+ isSignedCharDefault(getToolChain().getTriple())))
+ CmdArgs.push_back("-fsigned-char=0");
+
+ // -fms-extensions=0 is default.
+ if (Args.hasFlag(options::OPT_fms_extensions,
+ options::OPT_fno_ms_extensions,
+ getToolChain().getTriple().getOS() == llvm::Triple::Win32))
+ CmdArgs.push_back("-fms-extensions");
+
+ // -fnext-runtime is default.
+ if (!Args.hasFlag(options::OPT_fnext_runtime,
+ options::OPT_fgnu_runtime,
+ getToolChain().getTriple().getOS() == llvm::Triple::Darwin))
+ CmdArgs.push_back("-fgnu-runtime");
+
+ // -fobjc-nonfragile-abi=0 is default.
+ if (types::isObjC(InputType)) {
+ if (Args.hasArg(options::OPT_fobjc_nonfragile_abi) ||
+ getToolChain().IsObjCNonFragileABIDefault())
+ CmdArgs.push_back("-fobjc-nonfragile-abi");
+ }
+
+ // -fshort-wchar default varies depending on platform; only
// pass if specified.
- if (Arg *A = Args.getLastArg(options::OPT_fsigned_char,
- options::OPT_funsigned_char)) {
- if (A->getOption().matches(options::OPT_fsigned_char))
- CmdArgs.push_back("-fsigned-char");
- else
- CmdArgs.push_back("-fsigned-char=0");
+ if (Arg *A = Args.getLastArg(options::OPT_fshort_wchar)) {
+ if (A->getOption().matches(options::OPT_fshort_wchar))
+ CmdArgs.push_back("-fshort-wchar");
}
// -fno-pascal-strings is default, only pass non-default. If the tool chain
@@ -2588,6 +2638,10 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA,
else
CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtendS.o")));
CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtn.o")));
+ // FIXME: g++ is more complicated here, it tries to put -lstdc++
+ // before -lm, for example.
+ if (D.CCCIsCXX)
+ CmdArgs.push_back("-lstdc++");
}
const char *Exec =
diff --git a/lib/Driver/Types.cpp b/lib/Driver/Types.cpp
index c616c6a5bf4b..30893e7cc0cc 100644
--- a/lib/Driver/Types.cpp
+++ b/lib/Driver/Types.cpp
@@ -89,6 +89,19 @@ bool types::isAcceptedByClang(ID Id) {
}
}
+bool types::isObjC(ID Id) {
+ switch (Id) {
+ default:
+ return false;
+
+ case TY_ObjC: case TY_PP_ObjC:
+ case TY_ObjCXX: case TY_PP_ObjCXX:
+ case TY_ObjCHeader: case TY_PP_ObjCHeader:
+ case TY_ObjCXXHeader: case TY_PP_ObjCXXHeader:
+ return true;
+ }
+}
+
bool types::isCXX(ID Id) {
switch (Id) {
default:
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index c0415bf550f8..e3cd6ddd08d6 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -18,6 +18,7 @@
#include "clang/AST/StmtVisitor.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Basic/TargetOptions.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/Diagnostic.h"
#include "llvm/Support/Compiler.h"
@@ -61,14 +62,14 @@ public:
return false;
}
- virtual bool ReadTargetTriple(const std::string &Triple) {
+ virtual bool ReadTargetTriple(llvm::StringRef Triple) {
TargetTriple = Triple;
return false;
}
- virtual bool ReadPredefinesBuffer(const char *PCHPredef,
- unsigned PCHPredefLen,
+ virtual bool ReadPredefinesBuffer(llvm::StringRef PCHPredef,
FileID PCHBufferID,
+ llvm::StringRef OriginalFileName,
std::string &SuggestedPredefines) {
Predefines = PCHPredef;
return false;
@@ -132,7 +133,14 @@ ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename,
// PCH loaded successfully. Now create the preprocessor.
// Get information about the target being compiled for.
- AST->Target.reset(TargetInfo::CreateTargetInfo(TargetTriple));
+ //
+ // FIXME: This is broken, we should store the TargetOptions in the PCH.
+ TargetOptions TargetOpts;
+ TargetOpts.ABI = "";
+ TargetOpts.CPU = "";
+ TargetOpts.Features.clear();
+ TargetOpts.Triple = TargetTriple;
+ AST->Target.reset(TargetInfo::CreateTargetInfo(AST->Diags, TargetOpts));
AST->PP.reset(new Preprocessor(AST->Diags, LangInfo, *AST->Target.get(),
AST->getSourceManager(), HeaderInfo));
Preprocessor &PP = *AST->PP.get();
diff --git a/lib/Frontend/AnalysisConsumer.cpp b/lib/Frontend/AnalysisConsumer.cpp
index d2831fae566a..ede3d474c848 100644
--- a/lib/Frontend/AnalysisConsumer.cpp
+++ b/lib/Frontend/AnalysisConsumer.cpp
@@ -20,6 +20,7 @@
#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/LocalCheckers.h"
+#include "clang/Analysis/ManagerRegistry.h"
#include "clang/Analysis/PathDiagnostic.h"
#include "clang/Analysis/PathSensitive/AnalysisManager.h"
#include "clang/Analysis/PathSensitive/BugReporter.h"
@@ -27,7 +28,6 @@
#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
-#include "clang/Frontend/ManagerRegistry.h"
#include "clang/Frontend/PathDiagnosticClients.h"
#include "clang/Lex/Preprocessor.h"
#include "llvm/Support/Compiler.h"
@@ -44,10 +44,6 @@ static ExplodedNode::Auditor* CreateUbiViz();
// Basic type definitions.
//===----------------------------------------------------------------------===//
-namespace {
- typedef void (*CodeAction)(AnalysisManager& Mgr, Decl *D);
-} // end anonymous namespace
-
//===----------------------------------------------------------------------===//
// Special PathDiagnosticClients.
//===----------------------------------------------------------------------===//
@@ -66,116 +62,135 @@ CreatePlistHTMLDiagnosticClient(const std::string& prefix,
namespace {
- class VISIBILITY_HIDDEN AnalysisConsumer : public ASTConsumer {
- typedef std::vector<CodeAction> Actions;
- Actions FunctionActions;
- Actions ObjCMethodActions;
- Actions ObjCImplementationActions;
- Actions TranslationUnitActions;
+ class VISIBILITY_HIDDEN AnalysisConsumer : public ASTConsumer {
+ public:
+ typedef void (*CodeAction)(AnalysisConsumer &C, AnalysisManager &M, Decl *D);
+
+ private:
+ typedef std::vector<CodeAction> Actions;
+ Actions FunctionActions;
+ Actions ObjCMethodActions;
+ Actions ObjCImplementationActions;
+ Actions TranslationUnitActions;
- public:
- ASTContext* Ctx;
- const Preprocessor &PP;
- const std::string OutDir;
- AnalyzerOptions Opts;
+public:
+ ASTContext* Ctx;
+ const Preprocessor &PP;
+ const std::string OutDir;
+ AnalyzerOptions Opts;
+ bool declDisplayed;
- // PD is owned by AnalysisManager.
- PathDiagnosticClient *PD;
+ // PD is owned by AnalysisManager.
+ PathDiagnosticClient *PD;
- StoreManagerCreator CreateStoreMgr;
- ConstraintManagerCreator CreateConstraintMgr;
+ StoreManagerCreator CreateStoreMgr;
+ ConstraintManagerCreator CreateConstraintMgr;
- llvm::OwningPtr<AnalysisManager> Mgr;
+ llvm::OwningPtr<AnalysisManager> Mgr;
- AnalysisConsumer(const Preprocessor& pp,
- const std::string& outdir,
- const AnalyzerOptions& opts)
- : Ctx(0), PP(pp), OutDir(outdir),
- Opts(opts), PD(0) {
- DigestAnalyzerOptions();
- }
+ AnalysisConsumer(const Preprocessor& pp,
+ const std::string& outdir,
+ const AnalyzerOptions& opts)
+ : Ctx(0), PP(pp), OutDir(outdir),
+ Opts(opts), declDisplayed(false), PD(0) {
+ DigestAnalyzerOptions();
+ }
- void DigestAnalyzerOptions() {
- // Create the PathDiagnosticClient.
- if (!OutDir.empty()) {
- switch (Opts.AnalysisDiagOpt) {
- default:
+ void DigestAnalyzerOptions() {
+ // Create the PathDiagnosticClient.
+ if (!OutDir.empty()) {
+ switch (Opts.AnalysisDiagOpt) {
+ default:
#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN, AUTOCREATE) \
- case PD_##NAME: PD = CREATEFN(OutDir, PP); break;
+ case PD_##NAME: PD = CREATEFN(OutDir, PP); break;
#include "clang/Frontend/Analyses.def"
- }
}
+ }
- // Create the analyzer component creators.
- if (ManagerRegistry::StoreMgrCreator != 0) {
- CreateStoreMgr = ManagerRegistry::StoreMgrCreator;
- }
- else {
- switch (Opts.AnalysisStoreOpt) {
- default:
- assert(0 && "Unknown store manager.");
+ // Create the analyzer component creators.
+ if (ManagerRegistry::StoreMgrCreator != 0) {
+ CreateStoreMgr = ManagerRegistry::StoreMgrCreator;
+ }
+ else {
+ switch (Opts.AnalysisStoreOpt) {
+ default:
+ assert(0 && "Unknown store manager.");
#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATEFN) \
- case NAME##Model: CreateStoreMgr = CREATEFN; break;
+ case NAME##Model: CreateStoreMgr = CREATEFN; break;
#include "clang/Frontend/Analyses.def"
- }
}
+ }
- if (ManagerRegistry::ConstraintMgrCreator != 0)
- CreateConstraintMgr = ManagerRegistry::ConstraintMgrCreator;
- else {
- switch (Opts.AnalysisConstraintsOpt) {
- default:
- assert(0 && "Unknown store manager.");
+ if (ManagerRegistry::ConstraintMgrCreator != 0)
+ CreateConstraintMgr = ManagerRegistry::ConstraintMgrCreator;
+ else {
+ switch (Opts.AnalysisConstraintsOpt) {
+ default:
+ assert(0 && "Unknown store manager.");
#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATEFN) \
- case NAME##Model: CreateConstraintMgr = CREATEFN; break;
+ case NAME##Model: CreateConstraintMgr = CREATEFN; break;
#include "clang/Frontend/Analyses.def"
- }
}
}
-
- void addCodeAction(CodeAction action) {
- FunctionActions.push_back(action);
- ObjCMethodActions.push_back(action);
- }
-
- void addObjCImplementationAction(CodeAction action) {
- ObjCImplementationActions.push_back(action);
- }
-
- void addTranslationUnitAction(CodeAction action) {
- TranslationUnitActions.push_back(action);
+ }
+
+ void DisplayFunction(const Decl *D) {
+ if (!Opts.AnalyzerDisplayProgress || declDisplayed)
+ return;
+
+ declDisplayed = true;
+ // FIXME: Is getCodeDecl() always a named decl?
+ if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) {
+ const NamedDecl *ND = cast<NamedDecl>(D);
+ SourceManager &SM = Mgr->getASTContext().getSourceManager();
+ llvm::errs() << "ANALYZE: "
+ << SM.getPresumedLoc(ND->getLocation()).getFilename()
+ << ' ' << ND->getNameAsString() << '\n';
}
+ }
- virtual void Initialize(ASTContext &Context) {
- Ctx = &Context;
- Mgr.reset(new AnalysisManager(*Ctx, PP.getDiagnostics(),
- PP.getLangOptions(), PD,
- CreateStoreMgr, CreateConstraintMgr,
- Opts.AnalyzerDisplayProgress,
- Opts.VisualizeEGDot, Opts.VisualizeEGUbi,
- Opts.PurgeDead, Opts.EagerlyAssume,
- Opts.TrimGraph));
- }
+ void addCodeAction(CodeAction action) {
+ FunctionActions.push_back(action);
+ ObjCMethodActions.push_back(action);
+ }
- virtual void HandleTopLevelDecl(DeclGroupRef D) {
- for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I)
- HandleTopLevelSingleDecl(*I);
- }
+ void addObjCImplementationAction(CodeAction action) {
+ ObjCImplementationActions.push_back(action);
+ }
- void HandleTopLevelSingleDecl(Decl *D);
- virtual void HandleTranslationUnit(ASTContext &C);
+ void addTranslationUnitAction(CodeAction action) {
+ TranslationUnitActions.push_back(action);
+ }
- void HandleCode(Decl* D, Stmt* Body, Actions& actions);
- };
+ virtual void Initialize(ASTContext &Context) {
+ Ctx = &Context;
+ Mgr.reset(new AnalysisManager(*Ctx, PP.getDiagnostics(),
+ PP.getLangOptions(), PD,
+ CreateStoreMgr, CreateConstraintMgr,
+ Opts.AnalyzerDisplayProgress,
+ Opts.VisualizeEGDot, Opts.VisualizeEGUbi,
+ Opts.PurgeDead, Opts.EagerlyAssume,
+ Opts.TrimGraph));
+ }
+ virtual void HandleTopLevelDecl(DeclGroupRef D) {
+ declDisplayed = false;
+ for (DeclGroupRef::iterator I = D.begin(), E = D.end(); I != E; ++I)
+ HandleTopLevelSingleDecl(*I);
+ }
+ void HandleTopLevelSingleDecl(Decl *D);
+ virtual void HandleTranslationUnit(ASTContext &C);
+ void HandleCode(Decl* D, Stmt* Body, Actions& actions);
+};
} // end anonymous namespace
namespace llvm {
- template <> struct FoldingSetTrait<CodeAction> {
- static inline void Profile(CodeAction X, FoldingSetNodeID& ID) {
+ template <> struct FoldingSetTrait<AnalysisConsumer::CodeAction> {
+ static inline void Profile(AnalysisConsumer::CodeAction X,
+ FoldingSetNodeID& ID) {
ID.AddPointer(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(X)));
}
};
@@ -238,7 +253,7 @@ void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
for (Actions::iterator I = TranslationUnitActions.begin(),
E = TranslationUnitActions.end(); I != E; ++I)
- (*I)(*Mgr, FD);
+ (*I)(*this, *Mgr, FD);
}
if (!ObjCImplementationActions.empty()) {
@@ -272,34 +287,38 @@ void AnalysisConsumer::HandleCode(Decl *D, Stmt* Body, Actions& actions) {
// Dispatch on the actions.
for (Actions::iterator I = actions.begin(), E = actions.end(); I != E; ++I)
- (*I)(*Mgr, D);
+ (*I)(*this, *Mgr, D);
}
//===----------------------------------------------------------------------===//
// Analyses
//===----------------------------------------------------------------------===//
-static void ActionWarnDeadStores(AnalysisManager& mgr, Decl *D) {
+static void ActionWarnDeadStores(AnalysisConsumer &C, AnalysisManager& mgr,
+ Decl *D) {
if (LiveVariables *L = mgr.getLiveVariables(D)) {
+ C.DisplayFunction(D);
BugReporter BR(mgr);
CheckDeadStores(*mgr.getCFG(D), *L, mgr.getParentMap(D), BR);
}
}
-static void ActionWarnUninitVals(AnalysisManager& mgr, Decl *D) {
- if (CFG* c = mgr.getCFG(D))
+static void ActionWarnUninitVals(AnalysisConsumer &C, AnalysisManager& mgr,
+ Decl *D) {
+ if (CFG* c = mgr.getCFG(D)) {
+ C.DisplayFunction(D);
CheckUninitializedValues(*c, mgr.getASTContext(), mgr.getDiagnostic());
+ }
}
-static void ActionGRExprEngine(AnalysisManager& mgr, Decl *D,
+static void ActionGRExprEngine(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D,
GRTransferFuncs* tf) {
-
llvm::OwningPtr<GRTransferFuncs> TF(tf);
// Display progress.
- mgr.DisplayFunction(D);
+ C.DisplayFunction(D);
// Construct the analysis engine. We first query for the LiveVariables
// information to see if the CFG is valid.
@@ -312,8 +331,14 @@ static void ActionGRExprEngine(AnalysisManager& mgr, Decl *D,
Eng.setTransferFunctions(tf);
Eng.RegisterInternalChecks(); // FIXME: Internal checks should just
// automatically register.
+
+ if (C.Opts.EnableExperimentalInternalChecks)
+ RegisterExperimentalInternalChecks(Eng);
+
RegisterAppleChecks(Eng, *D);
-
+
+ if (C.Opts.EnableExperimentalChecks)
+ RegisterExperimentalChecks(Eng);
// Set the graph auditor.
llvm::OwningPtr<ExplodedNode::Auditor> Auditor;
@@ -337,85 +362,103 @@ static void ActionGRExprEngine(AnalysisManager& mgr, Decl *D,
Eng.getBugReporter().FlushReports();
}
-static void ActionCheckerCFRefAux(AnalysisManager& mgr, Decl *D,
- bool GCEnabled) {
+static void ActionCheckerCFRefAux(AnalysisConsumer &C, AnalysisManager& mgr,
+ Decl *D, bool GCEnabled) {
GRTransferFuncs* TF = MakeCFRefCountTF(mgr.getASTContext(),
GCEnabled,
mgr.getLangOptions());
- ActionGRExprEngine(mgr, D, TF);
+ ActionGRExprEngine(C, mgr, D, TF);
}
-static void ActionCheckerCFRef(AnalysisManager& mgr, Decl *D) {
+static void ActionCheckerCFRef(AnalysisConsumer &C, AnalysisManager& mgr,
+ Decl *D) {
switch (mgr.getLangOptions().getGCMode()) {
default:
assert (false && "Invalid GC mode.");
case LangOptions::NonGC:
- ActionCheckerCFRefAux(mgr, D, false);
+ ActionCheckerCFRefAux(C, mgr, D, false);
break;
case LangOptions::GCOnly:
- ActionCheckerCFRefAux(mgr, D, true);
+ ActionCheckerCFRefAux(C, mgr, D, true);
break;
case LangOptions::HybridGC:
- ActionCheckerCFRefAux(mgr, D, false);
- ActionCheckerCFRefAux(mgr, D, true);
+ ActionCheckerCFRefAux(C, mgr, D, false);
+ ActionCheckerCFRefAux(C, mgr, D, true);
break;
}
}
-static void ActionDisplayLiveVariables(AnalysisManager& mgr, Decl *D) {
+static void ActionDisplayLiveVariables(AnalysisConsumer &C,
+ AnalysisManager& mgr, Decl *D) {
if (LiveVariables* L = mgr.getLiveVariables(D)) {
- mgr.DisplayFunction(D);
+ C.DisplayFunction(D);
L->dumpBlockLiveness(mgr.getSourceManager());
}
}
-static void ActionCFGDump(AnalysisManager& mgr, Decl *D) {
- if (CFG* c = mgr.getCFG(D)) {
- mgr.DisplayFunction(D);
- c->dump(mgr.getLangOptions());
+static void ActionCFGDump(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D) {
+ if (CFG *cfg = mgr.getCFG(D)) {
+ C.DisplayFunction(D);
+ cfg->dump(mgr.getLangOptions());
}
}
-static void ActionCFGView(AnalysisManager& mgr, Decl *D) {
- if (CFG* c = mgr.getCFG(D)) {
- mgr.DisplayFunction(D);
- c->viewCFG(mgr.getLangOptions());
+static void ActionCFGView(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D) {
+ if (CFG *cfg = mgr.getCFG(D)) {
+ C.DisplayFunction(D);
+ cfg->viewCFG(mgr.getLangOptions());
}
}
-static void ActionSecuritySyntacticChecks(AnalysisManager &mgr, Decl *D) {
+static void ActionSecuritySyntacticChecks(AnalysisConsumer &C,
+ AnalysisManager &mgr, Decl *D) {
+ C.DisplayFunction(D);
BugReporter BR(mgr);
CheckSecuritySyntaxOnly(D, BR);
}
-static void ActionWarnObjCDealloc(AnalysisManager& mgr, Decl *D) {
+static void ActionWarnObjCDealloc(AnalysisConsumer &C, AnalysisManager& mgr,
+ Decl *D) {
if (mgr.getLangOptions().getGCMode() == LangOptions::GCOnly)
return;
+ C.DisplayFunction(D);
BugReporter BR(mgr);
- CheckObjCDealloc(cast<ObjCImplementationDecl>(D), mgr.getLangOptions(), BR);
+ CheckObjCDealloc(cast<ObjCImplementationDecl>(D), mgr.getLangOptions(), BR);
}
-static void ActionWarnObjCUnusedIvars(AnalysisManager& mgr, Decl *D) {
+static void ActionWarnObjCUnusedIvars(AnalysisConsumer &C, AnalysisManager& mgr,
+ Decl *D) {
+ C.DisplayFunction(D);
BugReporter BR(mgr);
- CheckObjCUnusedIvar(cast<ObjCImplementationDecl>(D), BR);
+ CheckObjCUnusedIvar(cast<ObjCImplementationDecl>(D), BR);
}
-static void ActionWarnObjCMethSigs(AnalysisManager& mgr, Decl *D) {
+static void ActionWarnObjCMethSigs(AnalysisConsumer &C, AnalysisManager& mgr,
+ Decl *D) {
+ C.DisplayFunction(D);
BugReporter BR(mgr);
-
CheckObjCInstMethSignature(cast<ObjCImplementationDecl>(D), BR);
}
-static void ActionInlineCall(AnalysisManager &mgr, Decl *D) {
+static void ActionWarnSizeofPointer(AnalysisConsumer &C, AnalysisManager &mgr,
+ Decl *D) {
+ C.DisplayFunction(D);
+ BugReporter BR(mgr);
+ CheckSizeofPointer(D, BR);
+}
+
+static void ActionInlineCall(AnalysisConsumer &C, AnalysisManager &mgr,
+ Decl *D) {
if (!D)
return;
+ C.DisplayFunction(D);
llvm::OwningPtr<GRTransferFuncs> TF(CreateCallInliner(mgr.getASTContext()));
// Construct the analysis engine.
diff --git a/lib/Frontend/Backend.cpp b/lib/Frontend/Backend.cpp
index 13aecf171718..bc56029e73d2 100644
--- a/lib/Frontend/Backend.cpp
+++ b/lib/Frontend/Backend.cpp
@@ -8,12 +8,13 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/ASTConsumers.h"
-#include "clang/CodeGen/ModuleBuilder.h"
-#include "clang/Frontend/CompileOptions.h"
-#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclGroup.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TargetOptions.h"
+#include "clang/CodeGen/CodeGenOptions.h"
+#include "clang/CodeGen/ModuleBuilder.h"
#include "llvm/Module.h"
#include "llvm/ModuleProvider.h"
#include "llvm/PassManager.h"
@@ -40,7 +41,8 @@ using namespace llvm;
namespace {
class VISIBILITY_HIDDEN BackendConsumer : public ASTConsumer {
BackendAction Action;
- CompileOptions CompileOpts;
+ CodeGenOptions CodeGenOpts;
+ TargetOptions TargetOpts;
llvm::raw_ostream *AsmOutStream;
llvm::formatted_raw_ostream FormattedOutStream;
ASTContext *Context;
@@ -75,11 +77,12 @@ namespace {
public:
BackendConsumer(BackendAction action, Diagnostic &Diags,
- const LangOptions &langopts, const CompileOptions &compopts,
- const std::string &infile, llvm::raw_ostream* OS,
- LLVMContext& C) :
+ const LangOptions &langopts, const CodeGenOptions &compopts,
+ const TargetOptions &targetopts, const std::string &infile,
+ llvm::raw_ostream* OS, LLVMContext& C) :
Action(action),
- CompileOpts(compopts),
+ CodeGenOpts(compopts),
+ TargetOpts(targetopts),
AsmOutStream(OS),
LLVMIRGeneration("LLVM IR Generation Time"),
CodeGenerationTime("Code Generation Time"),
@@ -92,7 +95,7 @@ namespace {
formatted_raw_ostream::PRESERVE_STREAM);
// Enable -time-passes if -ftime-report is enabled.
- llvm::TimePassesIsEnabled = CompileOpts.TimePasses;
+ llvm::TimePassesIsEnabled = CodeGenOpts.TimePasses;
}
~BackendConsumer() {
@@ -106,7 +109,7 @@ namespace {
virtual void Initialize(ASTContext &Ctx) {
Context = &Ctx;
- if (CompileOpts.TimePasses)
+ if (CodeGenOpts.TimePasses)
LLVMIRGeneration.startTimer();
Gen->Initialize(Ctx);
@@ -115,7 +118,7 @@ namespace {
ModuleProvider = new ExistingModuleProvider(TheModule);
TheTargetData = new llvm::TargetData(Ctx.Target.getTargetDescription());
- if (CompileOpts.TimePasses)
+ if (CodeGenOpts.TimePasses)
LLVMIRGeneration.stopTimer();
}
@@ -124,24 +127,24 @@ namespace {
Context->getSourceManager(),
"LLVM IR generation of declaration");
- if (CompileOpts.TimePasses)
+ if (CodeGenOpts.TimePasses)
LLVMIRGeneration.startTimer();
Gen->HandleTopLevelDecl(D);
- if (CompileOpts.TimePasses)
+ if (CodeGenOpts.TimePasses)
LLVMIRGeneration.stopTimer();
}
virtual void HandleTranslationUnit(ASTContext &C) {
{
PrettyStackTraceString CrashInfo("Per-file LLVM IR generation");
- if (CompileOpts.TimePasses)
+ if (CodeGenOpts.TimePasses)
LLVMIRGeneration.startTimer();
Gen->HandleTranslationUnit(C);
- if (CompileOpts.TimePasses)
+ if (CodeGenOpts.TimePasses)
LLVMIRGeneration.stopTimer();
}
@@ -202,7 +205,7 @@ bool BackendConsumer::AddEmitPasses(std::string &Error) {
} else if (Action == Backend_EmitLL) {
getPerModulePasses()->add(createPrintModulePass(&FormattedOutStream));
} else {
- bool Fast = CompileOpts.OptimizationLevel == 0;
+ bool Fast = CodeGenOpts.OptimizationLevel == 0;
// Create the TargetMachine for generating code.
std::string Triple = TheModule->getTargetTriple();
@@ -213,12 +216,12 @@ bool BackendConsumer::AddEmitPasses(std::string &Error) {
}
std::string FeaturesStr;
- if (CompileOpts.CPU.size() || CompileOpts.Features.size()) {
+ if (TargetOpts.CPU.size() || TargetOpts.Features.size()) {
SubtargetFeatures Features;
- Features.setCPU(CompileOpts.CPU);
+ Features.setCPU(TargetOpts.CPU);
for (std::vector<std::string>::iterator
- it = CompileOpts.Features.begin(),
- ie = CompileOpts.Features.end(); it != ie; ++it)
+ it = TargetOpts.Features.begin(),
+ ie = TargetOpts.Features.end(); it != ie; ++it)
Features.AddFeature(*it);
FeaturesStr = Features.getString();
}
@@ -237,7 +240,7 @@ bool BackendConsumer::AddEmitPasses(std::string &Error) {
FunctionPassManager *PM = getCodeGenPasses();
CodeGenOpt::Level OptLevel = CodeGenOpt::Default;
- switch (CompileOpts.OptimizationLevel) {
+ switch (CodeGenOpts.OptimizationLevel) {
default: break;
case 0: OptLevel = CodeGenOpt::None; break;
case 3: OptLevel = CodeGenOpt::Aggressive; break;
@@ -266,37 +269,44 @@ bool BackendConsumer::AddEmitPasses(std::string &Error) {
}
void BackendConsumer::CreatePasses() {
+ unsigned OptLevel = CodeGenOpts.OptimizationLevel;
+ CodeGenOptions::InliningMethod Inlining = CodeGenOpts.Inlining;
+
+ // Handle disabling of LLVM optimization, where we want to preserve the
+ // internal module before any optimization.
+ if (CodeGenOpts.DisableLLVMOpts) {
+ OptLevel = 0;
+ Inlining = CodeGenOpts.NoInlining;
+ }
+
// In -O0 if checking is disabled, we don't even have per-function passes.
- if (CompileOpts.VerifyModule)
+ if (CodeGenOpts.VerifyModule)
getPerFunctionPasses()->add(createVerifierPass());
// Assume that standard function passes aren't run for -O0.
- if (CompileOpts.OptimizationLevel > 0)
- llvm::createStandardFunctionPasses(getPerFunctionPasses(),
- CompileOpts.OptimizationLevel);
+ if (OptLevel > 0)
+ llvm::createStandardFunctionPasses(getPerFunctionPasses(), OptLevel);
llvm::Pass *InliningPass = 0;
- switch (CompileOpts.Inlining) {
- case CompileOptions::NoInlining: break;
- case CompileOptions::NormalInlining: {
+ switch (Inlining) {
+ case CodeGenOptions::NoInlining: break;
+ case CodeGenOptions::NormalInlining: {
// Inline small functions
- unsigned Threshold = (CompileOpts.OptimizeSize ||
- CompileOpts.OptimizationLevel < 3) ? 50 : 200;
+ unsigned Threshold = (CodeGenOpts.OptimizeSize || OptLevel < 3) ? 50 : 200;
InliningPass = createFunctionInliningPass(Threshold);
break;
}
- case CompileOptions::OnlyAlwaysInlining:
+ case CodeGenOptions::OnlyAlwaysInlining:
InliningPass = createAlwaysInlinerPass(); // Respect always_inline
break;
}
// For now we always create per module passes.
PassManager *PM = getPerModulePasses();
- llvm::createStandardModulePasses(PM, CompileOpts.OptimizationLevel,
- CompileOpts.OptimizeSize,
- CompileOpts.UnitAtATime,
- CompileOpts.UnrollLoops,
- CompileOpts.SimplifyLibCalls,
+ llvm::createStandardModulePasses(PM, OptLevel, CodeGenOpts.OptimizeSize,
+ CodeGenOpts.UnitAtATime,
+ CodeGenOpts.UnrollLoops,
+ CodeGenOpts.SimplifyLibCalls,
/*HaveExceptions=*/true,
InliningPass);
}
@@ -308,7 +318,7 @@ void BackendConsumer::EmitAssembly() {
if (!TheModule || !TheTargetData)
return;
- TimeRegion Region(CompileOpts.TimePasses ? &CodeGenerationTime : 0);
+ TimeRegion Region(CodeGenOpts.TimePasses ? &CodeGenerationTime : 0);
// Make sure IR generation is happy with the module. This is
// released by the module provider.
@@ -363,10 +373,11 @@ void BackendConsumer::EmitAssembly() {
ASTConsumer *clang::CreateBackendConsumer(BackendAction Action,
Diagnostic &Diags,
const LangOptions &LangOpts,
- const CompileOptions &CompileOpts,
+ const CodeGenOptions &CodeGenOpts,
+ const TargetOptions &TargetOpts,
const std::string& InFile,
llvm::raw_ostream* OS,
LLVMContext& C) {
- return new BackendConsumer(Action, Diags, LangOpts, CompileOpts,
- InFile, OS, C);
+ return new BackendConsumer(Action, Diags, LangOpts, CodeGenOpts,
+ TargetOpts, InFile, OS, C);
}
diff --git a/lib/Frontend/CMakeLists.txt b/lib/Frontend/CMakeLists.txt
index e3ec78627da0..3f0f43099c69 100644
--- a/lib/Frontend/CMakeLists.txt
+++ b/lib/Frontend/CMakeLists.txt
@@ -6,17 +6,21 @@ add_clang_library(clangFrontend
AnalysisConsumer.cpp
Backend.cpp
CacheTokens.cpp
+ CompilerInstance.cpp
+ CompilerInvocation.cpp
DeclXML.cpp
DependencyFile.cpp
DiagChecker.cpp
DocumentXML.cpp
FixItRewriter.cpp
+ FrontendAction.cpp
+ FrontendActions.cpp
+ FrontendOptions.cpp
GeneratePCH.cpp
HTMLDiagnostics.cpp
HTMLPrint.cpp
InitHeaderSearch.cpp
InitPreprocessor.cpp
- ManagerRegistry.cpp
PCHReader.cpp
PCHReaderDecl.cpp
PCHReaderStmt.cpp
@@ -34,6 +38,7 @@ add_clang_library(clangFrontend
TextDiagnosticBuffer.cpp
TextDiagnosticPrinter.cpp
TypeXML.cpp
+ VerifyDiagnosticsClient.cpp
Warnings.cpp
)
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
new file mode 100644
index 000000000000..0365761c840e
--- /dev/null
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -0,0 +1,403 @@
+//===--- CompilerInstance.cpp ---------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/PTHManager.h"
+#include "clang/Frontend/ChainedDiagnosticClient.h"
+#include "clang/Frontend/PCHReader.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Frontend/VerifyDiagnosticsClient.h"
+#include "clang/Frontend/Utils.h"
+#include "clang/Sema/CodeCompleteConsumer.h"
+#include "llvm/LLVMContext.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/System/Path.h"
+using namespace clang;
+
+CompilerInstance::CompilerInstance(llvm::LLVMContext *_LLVMContext,
+ bool _OwnsLLVMContext)
+ : LLVMContext(_LLVMContext),
+ OwnsLLVMContext(_OwnsLLVMContext) {
+ }
+
+CompilerInstance::~CompilerInstance() {
+ if (OwnsLLVMContext)
+ delete LLVMContext;
+}
+
+void CompilerInstance::setDiagnostics(Diagnostic *Value) {
+ Diagnostics.reset(Value);
+}
+
+void CompilerInstance::setDiagnosticClient(DiagnosticClient *Value) {
+ DiagClient.reset(Value);
+}
+
+void CompilerInstance::setTarget(TargetInfo *Value) {
+ Target.reset(Value);
+}
+
+void CompilerInstance::setFileManager(FileManager *Value) {
+ FileMgr.reset(Value);
+}
+
+void CompilerInstance::setSourceManager(SourceManager *Value) {
+ SourceMgr.reset(Value);
+}
+
+void CompilerInstance::setPreprocessor(Preprocessor *Value) {
+ PP.reset(Value);
+}
+
+void CompilerInstance::setASTContext(ASTContext *Value) {
+ Context.reset(Value);
+}
+
+void CompilerInstance::setASTConsumer(ASTConsumer *Value) {
+ Consumer.reset(Value);
+}
+
+void CompilerInstance::setCodeCompletionConsumer(CodeCompleteConsumer *Value) {
+ CompletionConsumer.reset(Value);
+}
+
+// Diagnostics
+
+static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts,
+ unsigned argc, char **argv,
+ llvm::OwningPtr<DiagnosticClient> &DiagClient) {
+ std::string ErrorInfo;
+ llvm::raw_ostream *OS =
+ new llvm::raw_fd_ostream(DiagOpts.DumpBuildInformation.c_str(), ErrorInfo);
+ if (!ErrorInfo.empty()) {
+ // FIXME: Do not fail like this.
+ llvm::errs() << "error opening -dump-build-information file '"
+ << DiagOpts.DumpBuildInformation << "', option ignored!\n";
+ delete OS;
+ return;
+ }
+
+ (*OS) << "clang-cc command line arguments: ";
+ for (unsigned i = 0; i != argc; ++i)
+ (*OS) << argv[i] << ' ';
+ (*OS) << '\n';
+
+ // Chain in a diagnostic client which will log the diagnostics.
+ DiagnosticClient *Logger =
+ new TextDiagnosticPrinter(*OS, DiagOpts, /*OwnsOutputStream=*/true);
+ DiagClient.reset(new ChainedDiagnosticClient(DiagClient.take(), Logger));
+}
+
+void CompilerInstance::createDiagnostics(int Argc, char **Argv) {
+ Diagnostics.reset(createDiagnostics(getDiagnosticOpts(), Argc, Argv));
+
+ if (Diagnostics)
+ DiagClient.reset(Diagnostics->getClient());
+}
+
+Diagnostic *CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts,
+ int Argc, char **Argv) {
+ llvm::OwningPtr<Diagnostic> Diags(new Diagnostic());
+
+ // Create the diagnostic client for reporting errors or for
+ // implementing -verify.
+ llvm::OwningPtr<DiagnosticClient> DiagClient(
+ new TextDiagnosticPrinter(llvm::errs(), Opts));
+
+ // Chain in -verify checker, if requested.
+ if (Opts.VerifyDiagnostics)
+ DiagClient.reset(new VerifyDiagnosticsClient(*Diags, DiagClient.take()));
+
+ if (!Opts.DumpBuildInformation.empty())
+ SetUpBuildDumpLog(Opts, Argc, Argv, DiagClient);
+
+ // Configure our handling of diagnostics.
+ Diags->setClient(DiagClient.take());
+ if (ProcessWarningOptions(*Diags, Opts))
+ return 0;
+
+ return Diags.take();
+}
+
+// File Manager
+
+void CompilerInstance::createFileManager() {
+ FileMgr.reset(new FileManager());
+}
+
+// Source Manager
+
+void CompilerInstance::createSourceManager() {
+ SourceMgr.reset(new SourceManager());
+}
+
+// Preprocessor
+
+void CompilerInstance::createPreprocessor() {
+ PP.reset(createPreprocessor(getDiagnostics(), getLangOpts(),
+ getPreprocessorOpts(), getHeaderSearchOpts(),
+ getDependencyOutputOpts(), getTarget(),
+ getSourceManager(), getFileManager()));
+}
+
+Preprocessor *
+CompilerInstance::createPreprocessor(Diagnostic &Diags,
+ const LangOptions &LangInfo,
+ const PreprocessorOptions &PPOpts,
+ const HeaderSearchOptions &HSOpts,
+ const DependencyOutputOptions &DepOpts,
+ const TargetInfo &Target,
+ SourceManager &SourceMgr,
+ FileManager &FileMgr) {
+ // Create a PTH manager if we are using some form of a token cache.
+ PTHManager *PTHMgr = 0;
+ if (!PPOpts.TokenCache.empty())
+ PTHMgr = PTHManager::Create(PPOpts.TokenCache, Diags);
+
+ // FIXME: Don't fail like this.
+ if (Diags.hasErrorOccurred())
+ exit(1);
+
+ // Create the Preprocessor.
+ HeaderSearch *HeaderInfo = new HeaderSearch(FileMgr);
+ Preprocessor *PP = new Preprocessor(Diags, LangInfo, Target,
+ SourceMgr, *HeaderInfo, PTHMgr,
+ /*OwnsHeaderSearch=*/true);
+
+ // Note that this is different then passing PTHMgr to Preprocessor's ctor.
+ // That argument is used as the IdentifierInfoLookup argument to
+ // IdentifierTable's ctor.
+ if (PTHMgr) {
+ PTHMgr->setPreprocessor(PP);
+ PP->setPTHManager(PTHMgr);
+ }
+
+ InitializePreprocessor(*PP, PPOpts, HSOpts);
+
+ // Handle generating dependencies, if requested.
+ if (!DepOpts.OutputFile.empty())
+ AttachDependencyFileGen(*PP, DepOpts);
+
+ return PP;
+}
+
+// ASTContext
+
+void CompilerInstance::createASTContext() {
+ Preprocessor &PP = getPreprocessor();
+ Context.reset(new ASTContext(getLangOpts(), PP.getSourceManager(),
+ getTarget(), PP.getIdentifierTable(),
+ PP.getSelectorTable(), PP.getBuiltinInfo(),
+ /*FreeMemory=*/ !getFrontendOpts().DisableFree,
+ /*size_reserve=*/ 0));
+}
+
+// ExternalASTSource
+
+void CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path) {
+ llvm::OwningPtr<ExternalASTSource> Source;
+ Source.reset(createPCHExternalASTSource(Path, getHeaderSearchOpts().Sysroot,
+ getPreprocessor(), getASTContext()));
+ getASTContext().setExternalSource(Source);
+}
+
+ExternalASTSource *
+CompilerInstance::createPCHExternalASTSource(llvm::StringRef Path,
+ const std::string &Sysroot,
+ Preprocessor &PP,
+ ASTContext &Context) {
+ llvm::OwningPtr<PCHReader> Reader;
+ Reader.reset(new PCHReader(PP, &Context,
+ Sysroot.empty() ? 0 : Sysroot.c_str()));
+
+ switch (Reader->ReadPCH(Path)) {
+ case PCHReader::Success:
+ // Set the predefines buffer as suggested by the PCH reader. Typically, the
+ // predefines buffer will be empty.
+ PP.setPredefines(Reader->getSuggestedPredefines());
+ return Reader.take();
+
+ case PCHReader::Failure:
+ // Unrecoverable failure: don't even try to process the input file.
+ break;
+
+ case PCHReader::IgnorePCH:
+ // No suitable PCH file could be found. Return an error.
+ break;
+ }
+
+ return 0;
+}
+
+// Code Completion
+
+void CompilerInstance::createCodeCompletionConsumer() {
+ const ParsedSourceLocation &Loc = getFrontendOpts().CodeCompletionAt;
+ CompletionConsumer.reset(
+ createCodeCompletionConsumer(getPreprocessor(),
+ Loc.FileName, Loc.Line, Loc.Column,
+ getFrontendOpts().DebugCodeCompletionPrinter,
+ getFrontendOpts().ShowMacrosInCodeCompletion,
+ llvm::outs()));
+}
+
+CodeCompleteConsumer *
+CompilerInstance::createCodeCompletionConsumer(Preprocessor &PP,
+ const std::string &Filename,
+ unsigned Line,
+ unsigned Column,
+ bool UseDebugPrinter,
+ bool ShowMacros,
+ llvm::raw_ostream &OS) {
+ // Tell the source manager to chop off the given file at a specific
+ // line and column.
+ const FileEntry *Entry = PP.getFileManager().getFile(Filename);
+ if (!Entry) {
+ PP.getDiagnostics().Report(diag::err_fe_invalid_code_complete_file)
+ << Filename;
+ return 0;
+ }
+
+ // Truncate the named file at the given line/column.
+ PP.getSourceManager().truncateFileAt(Entry, Line, Column);
+
+ // Set up the creation routine for code-completion.
+ if (UseDebugPrinter)
+ return new PrintingCodeCompleteConsumer(ShowMacros, OS);
+ else
+ return new CIndexCodeCompleteConsumer(ShowMacros, OS);
+}
+
+// Output Files
+
+void CompilerInstance::addOutputFile(llvm::StringRef Path,
+ llvm::raw_ostream *OS) {
+ assert(OS && "Attempt to add empty stream to output list!");
+ OutputFiles.push_back(std::make_pair(Path, OS));
+}
+
+void CompilerInstance::ClearOutputFiles(bool EraseFiles) {
+ for (std::list< std::pair<std::string, llvm::raw_ostream*> >::iterator
+ it = OutputFiles.begin(), ie = OutputFiles.end(); it != ie; ++it) {
+ delete it->second;
+ if (EraseFiles && !it->first.empty())
+ llvm::sys::Path(it->first).eraseFromDisk();
+ }
+ OutputFiles.clear();
+}
+
+llvm::raw_fd_ostream *
+CompilerInstance::createDefaultOutputFile(bool Binary,
+ llvm::StringRef InFile,
+ llvm::StringRef Extension) {
+ return createOutputFile(getFrontendOpts().OutputFile, Binary,
+ InFile, Extension);
+}
+
+llvm::raw_fd_ostream *
+CompilerInstance::createOutputFile(llvm::StringRef OutputPath,
+ bool Binary,
+ llvm::StringRef InFile,
+ llvm::StringRef Extension) {
+ std::string Error, OutputPathName;
+ llvm::raw_fd_ostream *OS = createOutputFile(OutputPath, Error, Binary,
+ InFile, Extension,
+ &OutputPathName);
+ if (!OS) {
+ // FIXME: Don't fail this way.
+ llvm::errs() << "ERROR: " << Error << "\n";
+ ::exit(1);
+ }
+
+ // Add the output file -- but don't try to remove "-", since this means we are
+ // using stdin.
+ addOutputFile((OutputPathName != "-") ? OutputPathName : "", OS);
+
+ return OS;
+}
+
+llvm::raw_fd_ostream *
+CompilerInstance::createOutputFile(llvm::StringRef OutputPath,
+ std::string &Error,
+ bool Binary,
+ llvm::StringRef InFile,
+ llvm::StringRef Extension,
+ std::string *ResultPathName) {
+ std::string OutFile;
+ if (!OutputPath.empty()) {
+ OutFile = OutputPath;
+ } else if (InFile == "-") {
+ OutFile = "-";
+ } else if (!Extension.empty()) {
+ llvm::sys::Path Path(InFile);
+ Path.eraseSuffix();
+ Path.appendSuffix(Extension);
+ OutFile = Path.str();
+ } else {
+ OutFile = "-";
+ }
+
+ llvm::raw_fd_ostream *OS =
+ new llvm::raw_fd_ostream(OutFile.c_str(), Error,
+ (Binary ? llvm::raw_fd_ostream::F_Binary : 0));
+ if (!OS)
+ return 0;
+
+ if (ResultPathName)
+ *ResultPathName = OutFile;
+
+ return OS;
+}
+
+// Initialization Utilities
+
+bool CompilerInstance::InitializeSourceManager(llvm::StringRef InputFile) {
+ return InitializeSourceManager(InputFile, getDiagnostics(), getFileManager(),
+ getSourceManager(), getFrontendOpts());
+}
+
+bool CompilerInstance::InitializeSourceManager(llvm::StringRef InputFile,
+ Diagnostic &Diags,
+ FileManager &FileMgr,
+ SourceManager &SourceMgr,
+ const FrontendOptions &Opts) {
+ // Figure out where to get and map in the main file.
+ if (Opts.EmptyInputOnly) {
+ const char *EmptyStr = "";
+ llvm::MemoryBuffer *SB =
+ llvm::MemoryBuffer::getMemBuffer(EmptyStr, EmptyStr, "<empty input>");
+ SourceMgr.createMainFileIDForMemBuffer(SB);
+ } else if (InputFile != "-") {
+ const FileEntry *File = FileMgr.getFile(InputFile);
+ if (File) SourceMgr.createMainFileID(File, SourceLocation());
+ if (SourceMgr.getMainFileID().isInvalid()) {
+ Diags.Report(diag::err_fe_error_reading) << InputFile;
+ return false;
+ }
+ } else {
+ llvm::MemoryBuffer *SB = llvm::MemoryBuffer::getSTDIN();
+ SourceMgr.createMainFileIDForMemBuffer(SB);
+ if (SourceMgr.getMainFileID().isInvalid()) {
+ Diags.Report(diag::err_fe_error_reading_stdin);
+ return false;
+ }
+ }
+
+ return true;
+}
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
new file mode 100644
index 000000000000..ed6d0b71a51b
--- /dev/null
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -0,0 +1,548 @@
+//===--- CompilerInvocation.cpp -------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/CompilerInvocation.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/ErrorHandling.h"
+using namespace clang;
+
+void CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
+ const llvm::SmallVectorImpl<llvm::StringRef> &Args) {
+ llvm::llvm_report_error("FIXME: Not yet implemented!");
+}
+
+static const char *getAnalysisName(Analyses Kind) {
+ switch (Kind) {
+ default:
+ llvm::llvm_unreachable("Unknown analysis store!");
+#define ANALYSIS(NAME, CMDFLAG, DESC, SCOPE)\
+ case NAME: return CMDFLAG;
+#include "clang/Frontend/Analyses.def"
+ }
+}
+
+static const char *getAnalysisStoreName(AnalysisStores Kind) {
+ switch (Kind) {
+ default:
+ llvm::llvm_unreachable("Unknown analysis store!");
+#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN) \
+ case NAME##Model: return CMDFLAG;
+#include "clang/Frontend/Analyses.def"
+ }
+}
+
+static const char *getAnalysisConstraintName(AnalysisConstraints Kind) {
+ switch (Kind) {
+ default:
+ llvm::llvm_unreachable("Unknown analysis constraints!");
+#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN) \
+ case NAME##Model: return CMDFLAG;
+#include "clang/Frontend/Analyses.def"
+ }
+}
+
+static const char *getAnalysisDiagClientName(AnalysisDiagClients Kind) {
+ switch (Kind) {
+ default:
+ llvm::llvm_unreachable("Unknown analysis client!");
+#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN, AUTOCREATE) \
+ case PD_##NAME: return CMDFLAG;
+#include "clang/Frontend/Analyses.def"
+ }
+}
+
+static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts,
+ std::vector<std::string> &Res) {
+ for (unsigned i = 0, e = Opts.AnalysisList.size(); i != e; ++i)
+ Res.push_back(getAnalysisName(Opts.AnalysisList[i]));
+ if (Opts.AnalysisStoreOpt != BasicStoreModel) {
+ Res.push_back("-analyzer-store");
+ Res.push_back(getAnalysisStoreName(Opts.AnalysisStoreOpt));
+ }
+ if (Opts.AnalysisConstraintsOpt != RangeConstraintsModel) {
+ Res.push_back("-analyzer-constraints");
+ Res.push_back(getAnalysisConstraintName(Opts.AnalysisConstraintsOpt));
+ }
+ if (Opts.AnalysisDiagOpt != PD_HTML) {
+ Res.push_back("-analyzer-output");
+ Res.push_back(getAnalysisDiagClientName(Opts.AnalysisDiagOpt));
+ }
+ if (!Opts.AnalyzeSpecificFunction.empty()) {
+ Res.push_back("-analyze-function");
+ Res.push_back(Opts.AnalyzeSpecificFunction);
+ }
+ if (Opts.AnalyzeAll)
+ Res.push_back("-analyzer-opt-analyze-headers");
+ if (Opts.AnalyzerDisplayProgress)
+ Res.push_back("-analyzer-display-progress");
+ if (Opts.EagerlyAssume)
+ Res.push_back("-analyzer-eagerly-assume");
+ if (Opts.PurgeDead)
+ Res.push_back("-analyzer-purge-dead");
+ if (Opts.TrimGraph)
+ Res.push_back("-trim-egraph");
+ if (Opts.VisualizeEGDot)
+ Res.push_back("-analyzer-viz-egraph-graphviz");
+ if (Opts.VisualizeEGDot)
+ Res.push_back("-analyzer-viz-egraph-ubigraph");
+ if (Opts.EnableExperimentalChecks)
+ Res.push_back("-analyzer-experimental-checks");
+ if (Opts.EnableExperimentalInternalChecks)
+ Res.push_back("-analyzer-experimental-internal-checls");
+}
+
+static void CodeGenOptsToArgs(const CodeGenOptions &Opts,
+ std::vector<std::string> &Res) {
+ if (Opts.DebugInfo)
+ Res.push_back("-g");
+ if (Opts.DisableLLVMOpts)
+ Res.push_back("-disable-llvm-optzns");
+ if (Opts.DisableRedZone)
+ Res.push_back("-disable-red-zone");
+ if (!Opts.MergeAllConstants)
+ Res.push_back("-fno-merge-all-constants");
+ // NoCommon is only derived.
+ if (Opts.NoImplicitFloat)
+ Res.push_back("-no-implicit-float");
+ if (Opts.OptimizeSize) {
+ assert(Opts.OptimizationLevel == 2 && "Invalid options!");
+ Res.push_back("-Os");
+ } else if (Opts.OptimizationLevel == 0)
+ Res.push_back("-O" + Opts.OptimizationLevel);
+ // SimplifyLibCalls is only derived.
+ // TimePasses is only derived.
+ // UnitAtATime is unused.
+ // UnrollLoops is only derived.
+ // VerifyModule is only derived.
+ // Inlining is only derived.
+}
+
+static void DependencyOutputOptsToArgs(const DependencyOutputOptions &Opts,
+ std::vector<std::string> &Res) {
+ if (Opts.IncludeSystemHeaders)
+ Res.push_back("-sys-header-deps");
+ if (Opts.UsePhonyTargets)
+ Res.push_back("-MP");
+ if (!Opts.OutputFile.empty()) {
+ Res.push_back("-dependency-file");
+ Res.push_back(Opts.OutputFile);
+ }
+ for (unsigned i = 0, e = Opts.Targets.size(); i != e; ++i) {
+ Res.push_back("-MT");
+ Res.push_back(Opts.Targets[i]);
+ }
+}
+
+static void DiagnosticOptsToArgs(const DiagnosticOptions &Opts,
+ std::vector<std::string> &Res) {
+ if (Opts.IgnoreWarnings)
+ Res.push_back("-w");
+ if (Opts.NoRewriteMacros)
+ Res.push_back("-Wno-rewrite-macros");
+ if (Opts.Pedantic)
+ Res.push_back("-pedantic");
+ if (Opts.PedanticErrors)
+ Res.push_back("-pedantic-errors");
+ if (!Opts.ShowColumn)
+ Res.push_back("-fno-show-column");
+ if (!Opts.ShowLocation)
+ Res.push_back("-fno-show-source-location");
+ if (!Opts.ShowCarets)
+ Res.push_back("-fno-caret-diagnostics");
+ if (!Opts.ShowFixits)
+ Res.push_back("-fno-diagnostics-fixit-info");
+ if (Opts.ShowSourceRanges)
+ Res.push_back("-fdiagnostics-print-source-range-info");
+ if (Opts.ShowColors)
+ Res.push_back("-fcolor-diagnostics");
+ if (Opts.VerifyDiagnostics)
+ Res.push_back("-verify");
+ if (Opts.ShowOptionNames)
+ Res.push_back("-fdiagnostics-show-option");
+ if (Opts.MessageLength) {
+ Res.push_back("-fmessage-length");
+ Res.push_back(llvm::utostr(Opts.MessageLength));
+ }
+ if (!Opts.DumpBuildInformation.empty()) {
+ Res.push_back("-dump-build-information");
+ Res.push_back(Opts.DumpBuildInformation);
+ }
+ for (unsigned i = 0, e = Opts.Warnings.size(); i != e; ++i)
+ Res.push_back("-W" + Opts.Warnings[i]);
+}
+
+static const char *getInputKindName(FrontendOptions::InputKind Kind) {
+ switch (Kind) {
+ case FrontendOptions::IK_None: break;
+ case FrontendOptions::IK_AST: return "ast";
+ case FrontendOptions::IK_Asm: return "assembler-with-cpp";
+ case FrontendOptions::IK_C: return "c";
+ case FrontendOptions::IK_CXX: return "c++";
+ case FrontendOptions::IK_ObjC: return "objective-c";
+ case FrontendOptions::IK_ObjCXX: return "objective-c++";
+ case FrontendOptions::IK_OpenCL: return "cl";
+ case FrontendOptions::IK_PreprocessedC: return "cpp-output";
+ case FrontendOptions::IK_PreprocessedCXX: return "c++-cpp-output";
+ case FrontendOptions::IK_PreprocessedObjC: return "objective-c-cpp-output";
+ case FrontendOptions::IK_PreprocessedObjCXX: return "objective-c++-cpp-output";
+ }
+
+ llvm::llvm_unreachable("Unexpected language kind!");
+ return 0;
+}
+
+static const char *getActionName(frontend::ActionKind Kind) {
+ switch (Kind) {
+ case frontend::PluginAction:
+ case frontend::InheritanceView:
+ llvm::llvm_unreachable("Invalid kind!");
+
+ case frontend::ASTDump: return "-ast-dump";
+ case frontend::ASTPrint: return "-ast-print";
+ case frontend::ASTPrintXML: return "-ast-print-xml";
+ case frontend::ASTView: return "-ast-view";
+ case frontend::DumpRawTokens: return "-dump-raw-tokens";
+ case frontend::DumpRecordLayouts: return "-dump-record-layouts";
+ case frontend::DumpTokens: return "-dump-tokens";
+ case frontend::EmitAssembly: return "-S";
+ case frontend::EmitBC: return "-emit-llvm-bc";
+ case frontend::EmitHTML: return "-emit-html";
+ case frontend::EmitLLVM: return "-emit-llvm";
+ case frontend::EmitLLVMOnly: return "-emit-llvm-only";
+ case frontend::FixIt: return "-fixit";
+ case frontend::GeneratePCH: return "-emit-pch";
+ case frontend::GeneratePTH: return "-emit-pth";
+ case frontend::ParseNoop: return "-parse-noop";
+ case frontend::ParsePrintCallbacks: return "-parse-print-callbacks";
+ case frontend::ParseSyntaxOnly: return "-fsyntax-only";
+ case frontend::PrintDeclContext: return "-print-decl-contexts";
+ case frontend::PrintPreprocessedInput: return "-E";
+ case frontend::RewriteBlocks: return "-rewrite-blocks";
+ case frontend::RewriteMacros: return "-rewrite-macros";
+ case frontend::RewriteObjC: return "-rewrite-objc";
+ case frontend::RewriteTest: return "-rewrite-test";
+ case frontend::RunAnalysis: return "-analyze";
+ case frontend::RunPreprocessorOnly: return "-Eonly";
+ }
+
+ llvm::llvm_unreachable("Unexpected language kind!");
+ return 0;
+}
+
+static void FrontendOptsToArgs(const FrontendOptions &Opts,
+ std::vector<std::string> &Res) {
+ if (!Opts.DebugCodeCompletionPrinter)
+ Res.push_back("-code-completion-debug-printer=0");
+ if (Opts.DisableFree)
+ Res.push_back("-disable-free");
+ if (Opts.EmptyInputOnly)
+ Res.push_back("-empty-input-only");
+ if (Opts.RelocatablePCH)
+ Res.push_back("-relocatable-pch");
+ if (Opts.ShowMacrosInCodeCompletion)
+ Res.push_back("-code-completion-macros");
+ if (Opts.ShowStats)
+ Res.push_back("-stats");
+ if (Opts.ShowTimers)
+ Res.push_back("-ftime-report");
+
+ bool NeedLang = false;
+ for (unsigned i = 0, e = Opts.Inputs.size(); i != e; ++i)
+ if (FrontendOptions::getInputKindForExtension(Opts.Inputs[i].second) !=
+ Opts.Inputs[i].first)
+ NeedLang = true;
+ if (NeedLang) {
+ Res.push_back("-x");
+ Res.push_back(getInputKindName(Opts.Inputs[0].first));
+ }
+ for (unsigned i = 0, e = Opts.Inputs.size(); i != e; ++i) {
+ assert((!NeedLang || Opts.Inputs[i].first == Opts.Inputs[0].first) &&
+ "Unable to represent this input vector!");
+ Res.push_back(Opts.Inputs[i].second);
+ }
+
+ if (!Opts.OutputFile.empty()) {
+ Res.push_back("-o");
+ Res.push_back(Opts.OutputFile);
+ }
+ if (!Opts.ViewClassInheritance.empty()) {
+ Res.push_back("-cxx-inheritance-view");
+ Res.push_back(Opts.ViewClassInheritance);
+ }
+ for (unsigned i = 0, e = Opts.FixItLocations.size(); i != e; ++i) {
+ Res.push_back("-fixit-at");
+ Res.push_back(Opts.FixItLocations[i].FileName + ":" +
+ llvm::utostr(Opts.FixItLocations[i].Line) + ":" +
+ llvm::utostr(Opts.FixItLocations[i].Column));
+ }
+ if (!Opts.CodeCompletionAt.FileName.empty()) {
+ Res.push_back("-code-completion-at");
+ Res.push_back(Opts.CodeCompletionAt.FileName + ":" +
+ llvm::utostr(Opts.CodeCompletionAt.Line) + ":" +
+ llvm::utostr(Opts.CodeCompletionAt.Column));
+ }
+ if (Opts.ProgramAction != frontend::InheritanceView &&
+ Opts.ProgramAction != frontend::PluginAction)
+ Res.push_back(getActionName(Opts.ProgramAction));
+ if (!Opts.ActionName.empty()) {
+ Res.push_back("-plugin");
+ Res.push_back(Opts.ActionName);
+ }
+}
+
+static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts,
+ std::vector<std::string> &Res) {
+ if (Opts.Sysroot.empty()) {
+ Res.push_back("-isysroot");
+ Res.push_back(Opts.Sysroot);
+ }
+
+ /// User specified include entries.
+ for (unsigned i = 0, e = Opts.UserEntries.size(); i != e; ++i) {
+ const HeaderSearchOptions::Entry &E = Opts.UserEntries[i];
+ if (E.IsFramework && (E.Group != frontend::Angled || E.IsUserSupplied))
+ llvm::llvm_report_error("Invalid option set!");
+ if (E.IsUserSupplied) {
+ if (E.Group == frontend::After) {
+ Res.push_back("-idirafter");
+ } else if (E.Group == frontend::Quoted) {
+ Res.push_back("-iquoted");
+ } else if (E.Group == frontend::System) {
+ Res.push_back("-isystem");
+ } else {
+ assert(E.Group == frontend::Angled && "Invalid group!");
+ Res.push_back(E.IsFramework ? "-F" : "-I");
+ }
+ } else {
+ if (E.Group != frontend::Angled && E.Group != frontend::System)
+ llvm::llvm_report_error("Invalid option set!");
+ Res.push_back(E.Group == frontend::Angled ? "-iwithprefixbefore" :
+ "-iwithprefix");
+ }
+ Res.push_back(E.Path);
+ }
+
+ if (!Opts.EnvIncPath.empty()) {
+ // FIXME: Provide an option for this, and move env detection to driver.
+ llvm::llvm_report_error("Not yet implemented!");
+ }
+ if (!Opts.CEnvIncPath.empty()) {
+ // FIXME: Provide an option for this, and move env detection to driver.
+ llvm::llvm_report_error("Not yet implemented!");
+ }
+ if (!Opts.ObjCEnvIncPath.empty()) {
+ // FIXME: Provide an option for this, and move env detection to driver.
+ llvm::llvm_report_error("Not yet implemented!");
+ }
+ if (!Opts.CXXEnvIncPath.empty()) {
+ // FIXME: Provide an option for this, and move env detection to driver.
+ llvm::llvm_report_error("Not yet implemented!");
+ }
+ if (!Opts.ObjCXXEnvIncPath.empty()) {
+ // FIXME: Provide an option for this, and move env detection to driver.
+ llvm::llvm_report_error("Not yet implemented!");
+ }
+ if (!Opts.BuiltinIncludePath.empty()) {
+ // FIXME: Provide an option for this, and move to driver.
+ }
+ if (!Opts.UseStandardIncludes)
+ Res.push_back("-nostdinc");
+ if (Opts.Verbose)
+ Res.push_back("-v");
+}
+
+static void LangOptsToArgs(const LangOptions &Opts,
+ std::vector<std::string> &Res) {
+ LangOptions DefaultLangOpts;
+
+ // FIXME: Need to set -std to get all the implicit options.
+
+ // FIXME: We want to only pass options relative to the defaults, which
+ // requires constructing a target. :(
+ //
+ // It would be better to push the all target specific choices into the driver,
+ // so that everything below that was more uniform.
+
+ if (Opts.Trigraphs)
+ Res.push_back("-trigraphs");
+ // Implicit based on the input kind:
+ // AsmPreprocessor, CPlusPlus, ObjC1, ObjC2, OpenCL
+ // Implicit based on the input language standard:
+ // BCPLComment, C99, CPlusPlus0x, Digraphs, GNUInline, ImplicitInt, GNUMode
+ if (Opts.DollarIdents)
+ Res.push_back("-fdollars-in-identifiers");
+ if (Opts.Microsoft)
+ Res.push_back("-fms-extensions=1");
+ if (Opts.ObjCNonFragileABI)
+ Res.push_back("-fobjc-nonfragile-abi");
+ // NoInline is implicit.
+ if (!Opts.CXXOperatorNames)
+ Res.push_back("-fno-operator-names");
+ if (Opts.PascalStrings)
+ Res.push_back("-fpascal-strings");
+ if (Opts.WritableStrings)
+ Res.push_back("-fwritable-strings");
+ if (!Opts.LaxVectorConversions)
+ Res.push_back("-fno-lax-vector-conversions");
+ if (Opts.AltiVec)
+ Res.push_back("-faltivec");
+ Res.push_back("-fexceptions");
+ Res.push_back(Opts.Exceptions ? "1" : "0");
+ Res.push_back("-frtti");
+ Res.push_back(Opts.Rtti ? "1" : "0");
+ if (!Opts.NeXTRuntime)
+ Res.push_back("-fgnu-runtime");
+ if (Opts.Freestanding)
+ Res.push_back("-ffreestanding");
+ if (Opts.NoBuiltin)
+ Res.push_back("-fno-builtin");
+ if (Opts.ThreadsafeStatics)
+ llvm::llvm_report_error("FIXME: Not yet implemented!");
+ if (Opts.POSIXThreads)
+ Res.push_back("-pthread");
+ if (Opts.Blocks)
+ Res.push_back("-fblocks=1");
+ if (Opts.EmitAllDecls)
+ Res.push_back("-femit-all-decls");
+ if (!Opts.MathErrno)
+ Res.push_back("-fmath-errno=0");
+ if (Opts.OverflowChecking)
+ Res.push_back("-ftrapv");
+ if (Opts.HeinousExtensions)
+ Res.push_back("-fheinous-gnu-extensions");
+ // Optimize is implicit.
+ // OptimizeSize is implicit.
+ if (Opts.Static)
+ Res.push_back("-static-define");
+ if (Opts.PICLevel) {
+ Res.push_back("-pic-level");
+ Res.push_back(llvm::utostr(Opts.PICLevel));
+ }
+ if (Opts.ObjCGCBitmapPrint)
+ Res.push_back("-print-ivar-layout");
+ Res.push_back("-faccess-control");
+ Res.push_back(Opts.AccessControl ? "1" : "0");
+ Res.push_back("-fsigned-char");
+ Res.push_back(Opts.CharIsSigned ? "1" : "0");
+ Res.push_back("-fshort-wchar");
+ Res.push_back(Opts.ShortWChar ? "1" : "0");
+ if (!Opts.ElideConstructors)
+ Res.push_back("-fno-elide-constructors");
+ if (Opts.getGCMode() != LangOptions::NonGC) {
+ if (Opts.getGCMode() == LangOptions::HybridGC) {
+ Res.push_back("-fobjc-gc");
+ } else {
+ assert(Opts.getGCMode() == LangOptions::GCOnly && "Invalid GC mode!");
+ Res.push_back("-fobjc-gc-only");
+ }
+ }
+ if (Opts.getVisibilityMode() != LangOptions::Default) {
+ Res.push_back("-fvisibility");
+ if (Opts.getVisibilityMode() == LangOptions::Hidden) {
+ Res.push_back("default");
+ } else {
+ assert(Opts.getVisibilityMode() == LangOptions::Protected &&
+ "Invalid visibility!");
+ Res.push_back("protected");
+ }
+ }
+ if (Opts.getStackProtectorMode() != 0) {
+ Res.push_back("-stack-protector");
+ Res.push_back(llvm::utostr(Opts.getStackProtectorMode()));
+ }
+ if (Opts.getMainFileName()) {
+ Res.push_back("-main-file-name");
+ Res.push_back(Opts.getMainFileName());
+ }
+ if (Opts.InstantiationDepth != DefaultLangOpts.InstantiationDepth) {
+ Res.push_back("-ftemplate-depth");
+ Res.push_back(llvm::utostr(Opts.InstantiationDepth));
+ }
+ if (Opts.ObjCConstantStringClass) {
+ Res.push_back("-fconstant-string-class");
+ Res.push_back(Opts.ObjCConstantStringClass);
+ }
+}
+
+static void PreprocessorOptsToArgs(const PreprocessorOptions &Opts,
+ std::vector<std::string> &Res) {
+ for (unsigned i = 0, e = Opts.Macros.size(); i != e; ++i)
+ Res.push_back((Opts.Macros[i].second ? "-U" : "-D") + Opts.Macros[i].first);
+ for (unsigned i = 0, e = Opts.Includes.size(); i != e; ++i) {
+ Res.push_back("-include");
+ Res.push_back(Opts.Includes[i]);
+ }
+ for (unsigned i = 0, e = Opts.MacroIncludes.size(); i != e; ++i) {
+ Res.push_back("-imacros");
+ Res.push_back(Opts.Includes[i]);
+ }
+ if (!Opts.UsePredefines)
+ Res.push_back("-undef");
+ if (!Opts.ImplicitPCHInclude.empty()) {
+ Res.push_back("-implicit-pch-include");
+ Res.push_back(Opts.ImplicitPCHInclude);
+ }
+ if (!Opts.ImplicitPTHInclude.empty()) {
+ Res.push_back("-implicit-pth-include");
+ Res.push_back(Opts.ImplicitPTHInclude);
+ }
+ if (!Opts.TokenCache.empty()) {
+ Res.push_back("-token-cache");
+ Res.push_back(Opts.TokenCache);
+ }
+}
+
+static void PreprocessorOutputOptsToArgs(const PreprocessorOutputOptions &Opts,
+ std::vector<std::string> &Res) {
+ if (!Opts.ShowCPP && !Opts.ShowMacros)
+ llvm::llvm_report_error("Invalid option combination!");
+
+ if (Opts.ShowCPP && Opts.ShowMacros)
+ Res.push_back("-dD");
+ else if (!Opts.ShowCPP && Opts.ShowMacros)
+ Res.push_back("-dM");
+
+ if (!Opts.ShowLineMarkers)
+ Res.push_back("-P");
+ if (Opts.ShowComments)
+ Res.push_back("-C");
+ if (Opts.ShowMacroComments)
+ Res.push_back("-CC");
+}
+
+static void TargetOptsToArgs(const TargetOptions &Opts,
+ std::vector<std::string> &Res) {
+ Res.push_back("-triple");
+ Res.push_back(Opts.Triple);
+ if (!Opts.CPU.empty()) {
+ Res.push_back("-target-cpu");
+ Res.push_back(Opts.CPU);
+ }
+ if (!Opts.ABI.empty()) {
+ Res.push_back("-target-abi");
+ Res.push_back(Opts.ABI);
+ }
+ for (unsigned i = 0, e = Opts.Features.size(); i != e; ++i) {
+ Res.push_back("-target-feature");
+ Res.push_back(Opts.Features[i]);
+ }
+}
+
+void CompilerInvocation::toArgs(std::vector<std::string> &Res) {
+ AnalyzerOptsToArgs(getAnalyzerOpts(), Res);
+ CodeGenOptsToArgs(getCodeGenOpts(), Res);
+ DependencyOutputOptsToArgs(getDependencyOutputOpts(), Res);
+ DiagnosticOptsToArgs(getDiagnosticOpts(), Res);
+ FrontendOptsToArgs(getFrontendOpts(), Res);
+ HeaderSearchOptsToArgs(getHeaderSearchOpts(), Res);
+ LangOptsToArgs(getLangOpts(), Res);
+ PreprocessorOptsToArgs(getPreprocessorOpts(), Res);
+ PreprocessorOutputOptsToArgs(getPreprocessorOutputOpts(), Res);
+ TargetOptsToArgs(getTargetOpts(), Res);
+}
diff --git a/lib/Frontend/DependencyFile.cpp b/lib/Frontend/DependencyFile.cpp
index 81d1179f28e3..c7f93595e1ea 100644
--- a/lib/Frontend/DependencyFile.cpp
+++ b/lib/Frontend/DependencyFile.cpp
@@ -12,12 +12,14 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/Utils.h"
-#include "clang/Basic/SourceManager.h"
#include "clang/Basic/FileManager.h"
-#include "clang/Lex/Preprocessor.h"
-#include "clang/Lex/PPCallbacks.h"
-#include "clang/Lex/DirectoryLookup.h"
#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Frontend/DependencyOutputOptions.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Lex/DirectoryLookup.h"
+#include "clang/Lex/PPCallbacks.h"
+#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/raw_ostream.h"
@@ -42,11 +44,10 @@ private:
public:
DependencyFileCallback(const Preprocessor *_PP,
llvm::raw_ostream *_OS,
- const std::vector<std::string> &_Targets,
- bool _IncludeSystemHeaders,
- bool _PhonyTarget)
- : PP(_PP), Targets(_Targets), OS(_OS),
- IncludeSystemHeaders(_IncludeSystemHeaders), PhonyTarget(_PhonyTarget) {}
+ const DependencyOutputOptions &Opts)
+ : PP(_PP), Targets(Opts.Targets), OS(_OS),
+ IncludeSystemHeaders(Opts.IncludeSystemHeaders),
+ PhonyTarget(Opts.UsePhonyTargets) {}
~DependencyFileCallback() {
OutputDependencyFile();
@@ -59,18 +60,23 @@ public:
};
}
+void clang::AttachDependencyFileGen(Preprocessor &PP,
+ const DependencyOutputOptions &Opts) {
+ if (Opts.Targets.empty()) {
+ PP.getDiagnostics().Report(diag::err_fe_dependency_file_requires_MT);
+ return;
+ }
+ std::string Err;
+ llvm::raw_ostream *OS(new llvm::raw_fd_ostream(Opts.OutputFile.c_str(), Err));
+ if (!Err.empty()) {
+ PP.getDiagnostics().Report(diag::err_fe_error_opening)
+ << Opts.OutputFile << Err;
+ return;
+ }
-void clang::AttachDependencyFileGen(Preprocessor *PP, llvm::raw_ostream *OS,
- std::vector<std::string> &Targets,
- bool IncludeSystemHeaders,
- bool PhonyTarget) {
- assert(!Targets.empty() && "Target required for dependency generation");
-
- DependencyFileCallback *PPDep =
- new DependencyFileCallback(PP, OS, Targets, IncludeSystemHeaders,
- PhonyTarget);
- PP->setPPCallbacks(PPDep);
+ assert(!PP.getPPCallbacks() && "Preprocessor callbacks already registered!");
+ PP.setPPCallbacks(new DependencyFileCallback(&PP, OS, Opts));
}
/// FileMatchesDepCriteria - Determine whether the given Filename should be
diff --git a/lib/Frontend/DocumentXML.cpp b/lib/Frontend/DocumentXML.cpp
index d92d4cb7b8de..0263c30bfd57 100644
--- a/lib/Frontend/DocumentXML.cpp
+++ b/lib/Frontend/DocumentXML.cpp
@@ -135,7 +135,7 @@ void DocumentXML::finalize() {
for (XML::IdMap<QualType>::iterator i = Types.begin(), e = Types.end();
i != e; ++i) {
- if (i->first.hasQualifiers()) {
+ if (i->first.hasLocalQualifiers()) {
writeTypeToXML(i->first);
addAttribute("id", getPrefixedId(i->second, ID_NORMAL));
toParent();
@@ -205,7 +205,7 @@ void DocumentXML::addTypeRecursively(const QualType& pType)
{
addTypeRecursively(pType.getTypePtr());
// beautifier: a non-qualified type shall be transparent
- if (!pType.hasQualifiers())
+ if (!pType.hasLocalQualifiers())
{
Types[pType] = BasicTypes[pType.getTypePtr()];
}
diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp
new file mode 100644
index 000000000000..ff63a0dab5f9
--- /dev/null
+++ b/lib/Frontend/FrontendAction.cpp
@@ -0,0 +1,225 @@
+//===--- FrontendAction.cpp -----------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/FrontendAction.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Sema/ParseAST.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Timer.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace clang;
+
+FrontendAction::FrontendAction() : Instance(0), CurrentTimer(0) {}
+
+FrontendAction::~FrontendAction() {}
+
+void FrontendAction::setCurrentFile(llvm::StringRef Value, ASTUnit *AST) {
+ CurrentFile = Value;
+ CurrentASTUnit.reset(AST);
+}
+
+bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
+ llvm::StringRef Filename,
+ bool IsAST) {
+ assert(!Instance && "Already processing a source file!");
+ assert(!Filename.empty() && "Unexpected empty filename!");
+ setCurrentFile(Filename);
+ setCompilerInstance(&CI);
+
+ // AST files follow a very different path, since they share objects via the
+ // AST unit.
+ if (IsAST) {
+ assert(!usesPreprocessorOnly() &&
+ "Attempt to pass AST file to preprocessor only action!");
+ assert(hasASTSupport() && "This action does not have AST support!");
+
+ std::string Error;
+ ASTUnit *AST = ASTUnit::LoadFromPCHFile(Filename, &Error);
+ if (!AST) {
+ CI.getDiagnostics().Report(diag::err_fe_invalid_ast_file) << Error;
+ goto failure;
+ }
+
+ setCurrentFile(Filename, AST);
+
+ // Set the shared objects, these are reset when we finish processing the
+ // file, otherwise the CompilerInstance will happily destroy them.
+ CI.setFileManager(&AST->getFileManager());
+ CI.setSourceManager(&AST->getSourceManager());
+ CI.setPreprocessor(&AST->getPreprocessor());
+ CI.setASTContext(&AST->getASTContext());
+
+ // Initialize the action.
+ if (!BeginSourceFileAction(CI, Filename))
+ goto failure;
+
+ /// Create the AST consumer.
+ CI.setASTConsumer(CreateASTConsumer(CI, Filename));
+ if (!CI.hasASTConsumer())
+ goto failure;
+
+ return true;
+ }
+
+ // Inform the diagnostic client we are processing a source file.
+ CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(),
+ &CI.getPreprocessor());
+
+ // Initialize the action.
+ if (!BeginSourceFileAction(CI, Filename))
+ goto failure;
+
+ /// Create the AST context and consumer unless this is a preprocessor only
+ /// action.
+ if (!usesPreprocessorOnly()) {
+ CI.createASTContext();
+ CI.setASTConsumer(CreateASTConsumer(CI, Filename));
+ if (!CI.hasASTConsumer())
+ goto failure;
+
+ /// Use PCH?
+ if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) {
+ assert(hasPCHSupport() && "This action does not have PCH support!");
+ CI.createPCHExternalASTSource(
+ CI.getPreprocessorOpts().ImplicitPCHInclude);
+ if (!CI.getASTContext().getExternalSource())
+ goto failure;
+ }
+ }
+
+ // Initialize builtin info as long as we aren't using an external AST
+ // source.
+ if (!CI.hasASTContext() || !CI.getASTContext().getExternalSource()) {
+ Preprocessor &PP = CI.getPreprocessor();
+ PP.getBuiltinInfo().InitializeBuiltins(PP.getIdentifierTable(),
+ PP.getLangOptions().NoBuiltin);
+ }
+
+ return true;
+
+ // If we failed, reset state since the client will not end up calling the
+ // matching EndSourceFile().
+ failure:
+ if (isCurrentFileAST()) {
+ CI.takeASTContext();
+ CI.takePreprocessor();
+ CI.takeSourceManager();
+ CI.takeFileManager();
+ }
+
+ CI.getDiagnosticClient().EndSourceFile();
+ setCurrentFile("");
+ setCompilerInstance(0);
+ return false;
+}
+
+void FrontendAction::Execute() {
+ CompilerInstance &CI = getCompilerInstance();
+
+ // Initialize the main file entry. This needs to be delayed until after PCH
+ // has loaded.
+ if (isCurrentFileAST()) {
+ // Set the main file ID to an empty file.
+ //
+ // FIXME: We probably shouldn't need this, but for now this is the
+ // simplest way to reuse the logic in ParseAST.
+ const char *EmptyStr = "";
+ llvm::MemoryBuffer *SB =
+ llvm::MemoryBuffer::getMemBuffer(EmptyStr, EmptyStr, "<dummy input>");
+ CI.getSourceManager().createMainFileIDForMemBuffer(SB);
+ } else {
+ if (!CI.InitializeSourceManager(getCurrentFile()))
+ return;
+ }
+
+ llvm::TimeRegion Timer(CurrentTimer);
+ ExecuteAction();
+}
+
+void FrontendAction::EndSourceFile() {
+ CompilerInstance &CI = getCompilerInstance();
+
+ // Finalize the action.
+ EndSourceFileAction();
+
+ // Release the consumer and the AST, in that order since the consumer may
+ // perform actions in its destructor which require the context.
+ //
+ // FIXME: There is more per-file stuff we could just drop here?
+ if (CI.getFrontendOpts().DisableFree) {
+ CI.takeASTConsumer();
+ if (!isCurrentFileAST())
+ CI.takeASTContext();
+ } else {
+ CI.setASTConsumer(0);
+ if (!isCurrentFileAST())
+ CI.setASTContext(0);
+ }
+
+ if (CI.getFrontendOpts().ShowStats) {
+ llvm::errs() << "\nSTATISTICS FOR '" << getCurrentFile() << "':\n";
+ CI.getPreprocessor().PrintStats();
+ CI.getPreprocessor().getIdentifierTable().PrintStats();
+ CI.getPreprocessor().getHeaderSearchInfo().PrintStats();
+ CI.getSourceManager().PrintStats();
+ llvm::errs() << "\n";
+ }
+
+ // Cleanup the output streams, and erase the output files if we encountered
+ // an error.
+ CI.ClearOutputFiles(/*EraseFiles=*/CI.getDiagnostics().getNumErrors());
+
+ // Inform the diagnostic client we are done with this source file.
+ CI.getDiagnosticClient().EndSourceFile();
+
+ if (isCurrentFileAST()) {
+ CI.takeASTContext();
+ CI.takePreprocessor();
+ CI.takeSourceManager();
+ CI.takeFileManager();
+ }
+
+ setCompilerInstance(0);
+ setCurrentFile("");
+}
+
+//===----------------------------------------------------------------------===//
+// Utility Actions
+//===----------------------------------------------------------------------===//
+
+void ASTFrontendAction::ExecuteAction() {
+ CompilerInstance &CI = getCompilerInstance();
+
+ // FIXME: Move the truncation aspect of this into Sema, we delayed this till
+ // here so the source manager would be initialized.
+ if (hasCodeCompletionSupport() &&
+ !CI.getFrontendOpts().CodeCompletionAt.FileName.empty())
+ CI.createCodeCompletionConsumer();
+
+ // Use a code completion consumer?
+ CodeCompleteConsumer *CompletionConsumer = 0;
+ if (CI.hasCodeCompletionConsumer())
+ CompletionConsumer = &CI.getCodeCompletionConsumer();
+
+ ParseAST(CI.getPreprocessor(), &CI.getASTConsumer(), CI.getASTContext(),
+ CI.getFrontendOpts().ShowStats,
+ usesCompleteTranslationUnit(), CompletionConsumer);
+}
+
+ASTConsumer *
+PreprocessorFrontendAction::CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ llvm::llvm_unreachable("Invalid CreateASTConsumer on preprocessor action!");
+}
diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp
new file mode 100644
index 000000000000..7a7537bce40f
--- /dev/null
+++ b/lib/Frontend/FrontendActions.cpp
@@ -0,0 +1,281 @@
+//===--- FrontendActions.cpp ----------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Parse/Parser.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Frontend/AnalysisConsumer.h"
+#include "clang/Frontend/ASTConsumers.h"
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FixItRewriter.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Frontend/Utils.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace clang;
+
+//===----------------------------------------------------------------------===//
+// AST Consumer Actions
+//===----------------------------------------------------------------------===//
+
+ASTConsumer *AnalysisAction::CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ return CreateAnalysisConsumer(CI.getPreprocessor(),
+ CI.getFrontendOpts().OutputFile,
+ CI.getAnalyzerOpts());
+}
+
+ASTConsumer *ASTPrintAction::CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ return CreateASTPrinter(CI.createDefaultOutputFile(false, InFile));
+}
+
+ASTConsumer *ASTPrintXMLAction::CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ return CreateASTPrinterXML(CI.createDefaultOutputFile(false, InFile,
+ "xml"));
+}
+
+ASTConsumer *ASTDumpAction::CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ return CreateASTDumper();
+}
+
+ASTConsumer *ASTViewAction::CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ return CreateASTViewer();
+}
+
+ASTConsumer *DeclContextPrintAction::CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ return CreateDeclContextPrinter();
+}
+
+ASTConsumer *DumpRecordAction::CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ return CreateRecordLayoutDumper();
+}
+
+ASTConsumer *GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ const std::string &Sysroot = CI.getHeaderSearchOpts().Sysroot;
+ if (CI.getFrontendOpts().RelocatablePCH &&
+ Sysroot.empty()) {
+ CI.getDiagnostics().Report(diag::err_relocatable_without_without_isysroot);
+ return 0;
+ }
+
+ llvm::raw_ostream *OS = CI.createDefaultOutputFile(true, InFile);
+ if (CI.getFrontendOpts().RelocatablePCH)
+ return CreatePCHGenerator(CI.getPreprocessor(), OS, Sysroot.c_str());
+
+ return CreatePCHGenerator(CI.getPreprocessor(), OS);
+}
+
+ASTConsumer *HTMLPrintAction::CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ return CreateHTMLPrinter(CI.createDefaultOutputFile(false, InFile),
+ CI.getPreprocessor());
+}
+
+ASTConsumer *InheritanceViewAction::CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ return CreateInheritanceViewer(CI.getFrontendOpts().ViewClassInheritance);
+}
+
+FixItAction::FixItAction() {}
+FixItAction::~FixItAction() {}
+
+ASTConsumer *FixItAction::CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ return new ASTConsumer();
+}
+
+/// AddFixItLocations - Add any individual user specified "fix-it" locations,
+/// and return true on success.
+static bool AddFixItLocations(CompilerInstance &CI,
+ FixItRewriter &FixItRewrite) {
+ const std::vector<ParsedSourceLocation> &Locs =
+ CI.getFrontendOpts().FixItLocations;
+ for (unsigned i = 0, e = Locs.size(); i != e; ++i) {
+ const FileEntry *File = CI.getFileManager().getFile(Locs[i].FileName);
+ if (!File) {
+ CI.getDiagnostics().Report(diag::err_fe_unable_to_find_fixit_file)
+ << Locs[i].FileName;
+ return false;
+ }
+
+ RequestedSourceLocation Requested;
+ Requested.File = File;
+ Requested.Line = Locs[i].Line;
+ Requested.Column = Locs[i].Column;
+ FixItRewrite.addFixItLocation(Requested);
+ }
+
+ return true;
+}
+
+bool FixItAction::BeginSourceFileAction(CompilerInstance &CI,
+ llvm::StringRef Filename) {
+ Rewriter.reset(new FixItRewriter(CI.getDiagnostics(), CI.getSourceManager(),
+ CI.getLangOpts()));
+ if (!AddFixItLocations(CI, *Rewriter))
+ return false;
+
+ return true;
+}
+
+void FixItAction::EndSourceFileAction() {
+ const FrontendOptions &FEOpts = getCompilerInstance().getFrontendOpts();
+ Rewriter->WriteFixedFile(getCurrentFile(), FEOpts.OutputFile);
+}
+
+ASTConsumer *RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ return CreateObjCRewriter(InFile,
+ CI.createDefaultOutputFile(true, InFile, "cpp"),
+ CI.getDiagnostics(), CI.getLangOpts(),
+ CI.getDiagnosticOpts().NoRewriteMacros);
+}
+
+ASTConsumer *RewriteBlocksAction::CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ return CreateBlockRewriter(InFile, CI.getDiagnostics(), CI.getLangOpts());
+}
+
+ASTConsumer *SyntaxOnlyAction::CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ return new ASTConsumer();
+}
+
+CodeGenAction::CodeGenAction(unsigned _Act) : Act(_Act) {}
+
+ASTConsumer *CodeGenAction::CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ BackendAction BA = static_cast<BackendAction>(Act);
+ llvm::OwningPtr<llvm::raw_ostream> OS;
+ if (BA == Backend_EmitAssembly)
+ OS.reset(CI.createDefaultOutputFile(false, InFile, "s"));
+ else if (BA == Backend_EmitLL)
+ OS.reset(CI.createDefaultOutputFile(false, InFile, "ll"));
+ else if (BA == Backend_EmitBC)
+ OS.reset(CI.createDefaultOutputFile(true, InFile, "bc"));
+
+ return CreateBackendConsumer(BA, CI.getDiagnostics(), CI.getLangOpts(),
+ CI.getCodeGenOpts(), CI.getTargetOpts(), InFile,
+ OS.take(), CI.getLLVMContext());
+}
+
+EmitAssemblyAction::EmitAssemblyAction()
+ : CodeGenAction(Backend_EmitAssembly) {}
+
+EmitBCAction::EmitBCAction() : CodeGenAction(Backend_EmitBC) {}
+
+EmitLLVMAction::EmitLLVMAction() : CodeGenAction(Backend_EmitLL) {}
+
+EmitLLVMOnlyAction::EmitLLVMOnlyAction() : CodeGenAction(Backend_EmitNothing) {}
+
+//===----------------------------------------------------------------------===//
+// Preprocessor Actions
+//===----------------------------------------------------------------------===//
+
+void DumpRawTokensAction::ExecuteAction() {
+ Preprocessor &PP = getCompilerInstance().getPreprocessor();
+ SourceManager &SM = PP.getSourceManager();
+
+ // Start lexing the specified input file.
+ Lexer RawLex(SM.getMainFileID(), SM, PP.getLangOptions());
+ RawLex.SetKeepWhitespaceMode(true);
+
+ Token RawTok;
+ RawLex.LexFromRawLexer(RawTok);
+ while (RawTok.isNot(tok::eof)) {
+ PP.DumpToken(RawTok, true);
+ fprintf(stderr, "\n");
+ RawLex.LexFromRawLexer(RawTok);
+ }
+}
+
+void DumpTokensAction::ExecuteAction() {
+ Preprocessor &PP = getCompilerInstance().getPreprocessor();
+ // Start preprocessing the specified input file.
+ Token Tok;
+ PP.EnterMainSourceFile();
+ do {
+ PP.Lex(Tok);
+ PP.DumpToken(Tok, true);
+ fprintf(stderr, "\n");
+ } while (Tok.isNot(tok::eof));
+}
+
+void GeneratePTHAction::ExecuteAction() {
+ CompilerInstance &CI = getCompilerInstance();
+ if (CI.getFrontendOpts().OutputFile.empty() ||
+ CI.getFrontendOpts().OutputFile == "-") {
+ // FIXME: Don't fail this way.
+ // FIXME: Verify that we can actually seek in the given file.
+ llvm::errs() << "ERROR: PTH requires an seekable file for output!\n";
+ ::exit(1);
+ }
+ llvm::raw_fd_ostream *OS =
+ CI.createDefaultOutputFile(true, getCurrentFile());
+ CacheTokens(CI.getPreprocessor(), OS);
+}
+
+void ParseOnlyAction::ExecuteAction() {
+ Preprocessor &PP = getCompilerInstance().getPreprocessor();
+ llvm::OwningPtr<Action> PA(new MinimalAction(PP));
+
+ Parser P(PP, *PA);
+ PP.EnterMainSourceFile();
+ P.ParseTranslationUnit();
+}
+
+void PreprocessOnlyAction::ExecuteAction() {
+ Preprocessor &PP = getCompilerInstance().getPreprocessor();
+
+ Token Tok;
+ // Start parsing the specified input file.
+ PP.EnterMainSourceFile();
+ do {
+ PP.Lex(Tok);
+ } while (Tok.isNot(tok::eof));
+}
+
+void PrintParseAction::ExecuteAction() {
+ CompilerInstance &CI = getCompilerInstance();
+ Preprocessor &PP = getCompilerInstance().getPreprocessor();
+ llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, getCurrentFile());
+ llvm::OwningPtr<Action> PA(CreatePrintParserActionsAction(PP, OS));
+
+ Parser P(PP, *PA);
+ PP.EnterMainSourceFile();
+ P.ParseTranslationUnit();
+}
+
+void PrintPreprocessedAction::ExecuteAction() {
+ CompilerInstance &CI = getCompilerInstance();
+ llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, getCurrentFile());
+ DoPrintPreprocessedInput(CI.getPreprocessor(), OS,
+ CI.getPreprocessorOutputOpts());
+}
+
+void RewriteMacrosAction::ExecuteAction() {
+ CompilerInstance &CI = getCompilerInstance();
+ llvm::raw_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile());
+ RewriteMacrosInInput(CI.getPreprocessor(), OS);
+}
+
+void RewriteTestAction::ExecuteAction() {
+ CompilerInstance &CI = getCompilerInstance();
+ llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, getCurrentFile());
+ DoRewriteTest(CI.getPreprocessor(), OS);
+}
diff --git a/lib/Frontend/FrontendOptions.cpp b/lib/Frontend/FrontendOptions.cpp
new file mode 100644
index 000000000000..bd916386056b
--- /dev/null
+++ b/lib/Frontend/FrontendOptions.cpp
@@ -0,0 +1,31 @@
+//===--- FrontendOptions.cpp ----------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open