aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorRoman Divacky <rdivacky@FreeBSD.org>2009-12-01 11:08:04 +0000
committerRoman Divacky <rdivacky@FreeBSD.org>2009-12-01 11:08:04 +0000
commit1569ce68681d909594d64f9b056d71f5dd7563bf (patch)
tree867cbbe32a66fd7d62dd9ce9df23a23fefdb8290 /lib
parentf5bd02d290ff15268853e0456c130a1afa15e907 (diff)
downloadsrc-1569ce68681d909594d64f9b056d71f5dd7563bf.tar.gz
src-1569ce68681d909594d64f9b056d71f5dd7563bf.zip
Update clang to r90226.
Notes
Notes: svn path=/vendor/clang/dist/; revision=199990
Diffstat (limited to 'lib')
-rw-r--r--lib/AST/ASTContext.cpp113
-rw-r--r--lib/AST/Decl.cpp205
-rw-r--r--lib/AST/DeclBase.cpp15
-rw-r--r--lib/AST/DeclCXX.cpp46
-rw-r--r--lib/AST/DeclPrinter.cpp15
-rw-r--r--lib/AST/DeclTemplate.cpp7
-rw-r--r--lib/AST/DeclarationName.cpp44
-rw-r--r--lib/AST/Expr.cpp212
-rw-r--r--lib/AST/ExprCXX.cpp244
-rw-r--r--lib/AST/ExprConstant.cpp62
-rw-r--r--lib/AST/RecordLayoutBuilder.cpp259
-rw-r--r--lib/AST/RecordLayoutBuilder.h20
-rw-r--r--lib/AST/Stmt.cpp6
-rw-r--r--lib/AST/StmtDumper.cpp3
-rw-r--r--lib/AST/StmtPrinter.cpp52
-rw-r--r--lib/AST/StmtProfile.cpp46
-rw-r--r--lib/AST/StmtViz.cpp5
-rw-r--r--lib/AST/TemplateBase.cpp14
-rw-r--r--lib/AST/Type.cpp6
-rw-r--r--lib/AST/TypePrinter.cpp10
-rw-r--r--lib/Analysis/AnalysisContext.cpp87
-rw-r--r--lib/Analysis/ArrayBoundChecker.cpp12
-rw-r--r--lib/Analysis/AttrNonNullChecker.cpp8
-rw-r--r--lib/Analysis/BadCallChecker.cpp57
-rw-r--r--lib/Analysis/BasicConstraintManager.cpp7
-rw-r--r--lib/Analysis/BasicObjCFoundationChecks.cpp73
-rw-r--r--lib/Analysis/BasicObjCFoundationChecks.h12
-rw-r--r--lib/Analysis/BasicStore.cpp5
-rw-r--r--lib/Analysis/BugReporter.cpp23
-rw-r--r--lib/Analysis/BugReporterVisitors.cpp4
-rw-r--r--lib/Analysis/CFG.cpp22
-rw-r--r--lib/Analysis/CFRefCount.cpp252
-rw-r--r--lib/Analysis/CMakeLists.txt7
-rw-r--r--lib/Analysis/CallAndMessageChecker.cpp267
-rw-r--r--lib/Analysis/CallGraph.cpp4
-rw-r--r--lib/Analysis/CallInliner.cpp2
-rw-r--r--lib/Analysis/CastToStructChecker.cpp4
-rw-r--r--lib/Analysis/CheckDeadStores.cpp18
-rw-r--r--lib/Analysis/CheckObjCDealloc.cpp7
-rw-r--r--lib/Analysis/CheckObjCInstMethSignature.cpp2
-rw-r--r--lib/Analysis/CheckObjCUnusedIVars.cpp36
-rw-r--r--lib/Analysis/CheckSecuritySyntaxOnly.cpp9
-rw-r--r--lib/Analysis/CheckSizeofPointer.cpp3
-rw-r--r--lib/Analysis/Checker.cpp35
-rw-r--r--lib/Analysis/DereferenceChecker.cpp68
-rw-r--r--lib/Analysis/DivZeroChecker.cpp7
-rw-r--r--lib/Analysis/Environment.cpp3
-rw-r--r--lib/Analysis/FixedAddressChecker.cpp4
-rw-r--r--lib/Analysis/GRCoreEngine.cpp7
-rw-r--r--lib/Analysis/GRExprEngine.cpp462
-rw-r--r--lib/Analysis/GRExprEngineExperimentalChecks.cpp2
-rw-r--r--lib/Analysis/GRExprEngineInternalChecks.cpp400
-rw-r--r--lib/Analysis/GRExprEngineInternalChecks.h6
-rw-r--r--lib/Analysis/GRState.cpp23
-rw-r--r--lib/Analysis/LiveVariables.cpp25
-rw-r--r--lib/Analysis/MallocChecker.cpp21
-rw-r--r--lib/Analysis/MemRegion.cpp132
-rw-r--r--lib/Analysis/NSAutoreleasePoolChecker.cpp6
-rw-r--r--lib/Analysis/NSErrorChecker.cpp7
-rw-r--r--lib/Analysis/PointerArithChecker.cpp4
-rw-r--r--lib/Analysis/PointerSubChecker.cpp4
-rw-r--r--lib/Analysis/PthreadLockChecker.cpp8
-rw-r--r--lib/Analysis/RangeConstraintManager.cpp11
-rw-r--r--lib/Analysis/RegionStore.cpp92
-rw-r--r--lib/Analysis/ReturnPointerRangeChecker.cpp5
-rw-r--r--lib/Analysis/ReturnStackAddressChecker.cpp13
-rw-r--r--lib/Analysis/ReturnUndefChecker.cpp4
-rw-r--r--lib/Analysis/SVals.cpp2
-rw-r--r--lib/Analysis/SimpleSValuator.cpp3
-rw-r--r--lib/Analysis/Store.cpp10
-rw-r--r--lib/Analysis/UndefBranchChecker.cpp117
-rw-r--r--lib/Analysis/UndefResultChecker.cpp86
-rw-r--r--lib/Analysis/UndefinedArgChecker.cpp56
-rw-r--r--lib/Analysis/UndefinedArraySubscriptChecker.cpp4
-rw-r--r--lib/Analysis/UndefinedAssignmentChecker.cpp22
-rw-r--r--lib/Analysis/UninitializedValues.cpp7
-rw-r--r--lib/Analysis/VLASizeChecker.cpp9
-rw-r--r--lib/Analysis/ValueManager.cpp11
-rw-r--r--lib/Basic/TargetInfo.cpp1
-rw-r--r--lib/Basic/Targets.cpp49
-rw-r--r--lib/Basic/TokenKinds.cpp55
-rw-r--r--lib/CodeGen/CGBlocks.cpp16
-rw-r--r--lib/CodeGen/CGBuiltin.cpp11
-rw-r--r--lib/CodeGen/CGCXX.cpp346
-rw-r--r--lib/CodeGen/CGCall.cpp62
-rw-r--r--lib/CodeGen/CGClass.cpp (renamed from lib/CodeGen/CGCXXClass.cpp)124
-rw-r--r--lib/CodeGen/CGDebugInfo.cpp42
-rw-r--r--lib/CodeGen/CGDecl.cpp20
-rw-r--r--lib/CodeGen/CGException.cpp390
-rw-r--r--lib/CodeGen/CGExpr.cpp84
-rw-r--r--lib/CodeGen/CGExprAgg.cpp30
-rw-r--r--lib/CodeGen/CGExprCXX.cpp (renamed from lib/CodeGen/CGCXXExpr.cpp)59
-rw-r--r--lib/CodeGen/CGExprComplex.cpp31
-rw-r--r--lib/CodeGen/CGExprConstant.cpp13
-rw-r--r--lib/CodeGen/CGExprScalar.cpp181
-rw-r--r--lib/CodeGen/CGObjCGNU.cpp13
-rw-r--r--lib/CodeGen/CGObjCMac.cpp21
-rw-r--r--lib/CodeGen/CGRecordLayoutBuilder.cpp34
-rw-r--r--lib/CodeGen/CGRtti.cpp45
-rw-r--r--lib/CodeGen/CGStmt.cpp136
-rw-r--r--lib/CodeGen/CGTemporaries.cpp (renamed from lib/CodeGen/CGCXXTemp.cpp)24
-rw-r--r--lib/CodeGen/CGVtable.cpp546
-rw-r--r--lib/CodeGen/CGVtable.h86
-rw-r--r--lib/CodeGen/CMakeLists.txt8
-rw-r--r--lib/CodeGen/CodeGenFunction.cpp35
-rw-r--r--lib/CodeGen/CodeGenFunction.h178
-rw-r--r--lib/CodeGen/CodeGenModule.cpp182
-rw-r--r--lib/CodeGen/CodeGenModule.h18
-rw-r--r--lib/CodeGen/CodeGenTypes.cpp9
-rw-r--r--lib/CodeGen/CodeGenTypes.h31
-rw-r--r--lib/CodeGen/Mangle.cpp816
-rw-r--r--lib/CodeGen/Mangle.h91
-rw-r--r--lib/CodeGen/ModuleBuilder.cpp4
-rw-r--r--lib/CodeGen/TargetABIInfo.cpp28
-rw-r--r--lib/Driver/ArgList.cpp112
-rw-r--r--lib/Driver/CC1Options.cpp9
-rw-r--r--lib/Driver/Compilation.cpp7
-rw-r--r--lib/Driver/Driver.cpp7
-rw-r--r--lib/Driver/DriverOptions.cpp5
-rw-r--r--lib/Driver/Tools.cpp179
-rw-r--r--lib/Driver/Types.cpp1
-rw-r--r--lib/Frontend/ASTUnit.cpp102
-rw-r--r--lib/Frontend/AnalysisConsumer.cpp32
-rw-r--r--lib/Frontend/Backend.cpp79
-rw-r--r--lib/Frontend/CMakeLists.txt1
-rw-r--r--lib/Frontend/CacheTokens.cpp14
-rw-r--r--lib/Frontend/CompilerInstance.cpp22
-rw-r--r--lib/Frontend/CompilerInvocation.cpp807
-rw-r--r--lib/Frontend/DependencyFile.cpp3
-rw-r--r--lib/Frontend/DiagChecker.cpp3
-rw-r--r--lib/Frontend/FrontendAction.cpp9
-rw-r--r--lib/Frontend/FrontendActions.cpp13
-rw-r--r--lib/Frontend/GeneratePCH.cpp7
-rw-r--r--lib/Frontend/HTMLDiagnostics.cpp3
-rw-r--r--lib/Frontend/InitHeaderSearch.cpp157
-rw-r--r--lib/Frontend/InitPreprocessor.cpp7
-rw-r--r--lib/Frontend/LangStandards.cpp44
-rw-r--r--lib/Frontend/PCHReader.cpp22
-rw-r--r--lib/Frontend/PCHReaderDecl.cpp4
-rw-r--r--lib/Frontend/PCHReaderStmt.cpp4
-rw-r--r--lib/Frontend/PCHWriter.cpp24
-rw-r--r--lib/Frontend/PCHWriterStmt.cpp4
-rw-r--r--lib/Frontend/PlistDiagnostics.cpp4
-rw-r--r--lib/Frontend/PrintParserCallbacks.cpp15
-rw-r--r--lib/Frontend/RewriteMacros.cpp3
-rw-r--r--lib/Frontend/RewriteObjC.cpp2
-rw-r--r--lib/Frontend/StmtXML.cpp5
-rw-r--r--lib/Frontend/TextDiagnosticBuffer.cpp21
-rw-r--r--lib/Frontend/VerifyDiagnosticsClient.cpp8
-rw-r--r--lib/Headers/stdint.h71
-rw-r--r--lib/Index/Analyzer.cpp9
-rw-r--r--lib/Index/DeclReferenceMap.cpp3
-rw-r--r--lib/Index/ResolveLocation.cpp7
-rw-r--r--lib/Index/SelectorMap.cpp3
-rw-r--r--lib/Lex/Lexer.cpp11
-rw-r--r--lib/Lex/LiteralSupport.cpp42
-rw-r--r--lib/Lex/PPDirectives.cpp5
-rw-r--r--lib/Lex/PPLexerChange.cpp20
-rw-r--r--lib/Lex/PTHLexer.cpp14
-rw-r--r--lib/Parse/AttributeList.cpp24
-rw-r--r--lib/Parse/MinimalAction.cpp2
-rw-r--r--lib/Parse/ParseCXXInlineMethods.cpp3
-rw-r--r--lib/Parse/ParseDecl.cpp126
-rw-r--r--lib/Parse/ParseDeclCXX.cpp270
-rw-r--r--lib/Parse/ParseExpr.cpp29
-rw-r--r--lib/Parse/ParseExprCXX.cpp113
-rw-r--r--lib/Parse/ParseObjc.cpp8
-rw-r--r--lib/Parse/ParseStmt.cpp187
-rw-r--r--lib/Parse/ParseTemplate.cpp50
-rw-r--r--lib/Parse/ParseTentative.cpp88
-rw-r--r--lib/Parse/Parser.cpp27
-rw-r--r--lib/Rewrite/HTMLRewrite.cpp6
-rw-r--r--lib/Rewrite/TokenRewriter.cpp3
-rw-r--r--lib/Sema/CodeCompleteConsumer.cpp492
-rw-r--r--lib/Sema/Lookup.h46
-rw-r--r--lib/Sema/ParseAST.cpp3
-rw-r--r--lib/Sema/Sema.cpp15
-rw-r--r--lib/Sema/Sema.h354
-rw-r--r--lib/Sema/SemaCodeComplete.cpp103
-rw-r--r--lib/Sema/SemaDecl.cpp183
-rw-r--r--lib/Sema/SemaDeclAttr.cpp223
-rw-r--r--lib/Sema/SemaDeclCXX.cpp230
-rw-r--r--lib/Sema/SemaExpr.cpp1957
-rw-r--r--lib/Sema/SemaExprCXX.cpp210
-rw-r--r--lib/Sema/SemaInit.cpp45
-rw-r--r--lib/Sema/SemaLookup.cpp52
-rw-r--r--lib/Sema/SemaOverload.cpp556
-rw-r--r--lib/Sema/SemaStmt.cpp246
-rw-r--r--lib/Sema/SemaTemplate.cpp723
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp108
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp54
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp38
-rw-r--r--lib/Sema/SemaType.cpp1
-rw-r--r--lib/Sema/TreeTransform.h673
194 files changed, 10578 insertions, 6394 deletions
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index dc13e7f4688c..6c9ecf089b98 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -48,6 +48,7 @@ ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM,
BuiltinInfo(builtins), ExternalSource(0), PrintingPolicy(LOpts) {
ObjCIdRedefinitionType = QualType();
ObjCClassRedefinitionType = QualType();
+ ObjCSelRedefinitionType = QualType();
if (size_reserve > 0) Types.reserve(size_reserve);
TUDecl = TranslationUnitDecl::Create(*this);
InitBuiltinTypes();
@@ -220,10 +221,12 @@ void ASTContext::InitBuiltinTypes() {
// "Builtin" typedefs set by Sema::ActOnTranslationUnitScope().
ObjCIdTypedefType = QualType();
ObjCClassTypedefType = QualType();
+ ObjCSelTypedefType = QualType();
- // Builtin types for 'id' and 'Class'.
+ // Builtin types for 'id', 'Class', and 'SEL'.
InitBuiltinType(ObjCBuiltinIdTy, BuiltinType::ObjCId);
InitBuiltinType(ObjCBuiltinClassTy, BuiltinType::ObjCClass);
+ InitBuiltinType(ObjCBuiltinSelTy, BuiltinType::ObjCSel);
ObjCConstantStringType = QualType();
@@ -517,18 +520,23 @@ const llvm::fltSemantics &ASTContext::getFloatTypeSemantics(QualType T) const {
/// getDeclAlignInBytes - Return a conservative estimate of the alignment of the
/// specified decl. Note that bitfields do not have a valid alignment, so
/// this method will assert on them.
-unsigned ASTContext::getDeclAlignInBytes(const Decl *D) {
+/// If @p RefAsPointee, references are treated like their underlying type
+/// (for alignof), else they're treated like pointers (for CodeGen).
+unsigned ASTContext::getDeclAlignInBytes(const Decl *D, bool RefAsPointee) {
unsigned Align = Target.getCharWidth();
if (const AlignedAttr* AA = D->getAttr<AlignedAttr>())
- Align = std::max(Align, AA->getAlignment());
+ Align = std::max(Align, AA->getMaxAlignment());
if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
QualType T = VD->getType();
if (const ReferenceType* RT = T->getAs<ReferenceType>()) {
- unsigned AS = RT->getPointeeType().getAddressSpace();
- Align = Target.getPointerAlign(AS);
- } else if (!T->isIncompleteType() && !T->isFunctionType()) {
+ if (RefAsPointee)
+ T = RT->getPointeeType();
+ else
+ T = getPointerType(RT->getPointeeType());
+ }
+ if (!T->isIncompleteType() && !T->isFunctionType()) {
// Incomplete or function types default to 1.
while (isa<VariableArrayType>(T) || isa<IncompleteArrayType>(T))
T = cast<ArrayType>(T)->getElementType();
@@ -687,19 +695,21 @@ ASTContext::getTypeInfo(const Type *T) {
Align = Target.getPointerAlign(AS);
break;
}
+ case Type::LValueReference:
+ case Type::RValueReference: {
+ // alignof and sizeof should never enter this code path here, so we go
+ // the pointer route.
+ unsigned AS = cast<ReferenceType>(T)->getPointeeType().getAddressSpace();
+ Width = Target.getPointerWidth(AS);
+ Align = Target.getPointerAlign(AS);
+ break;
+ }
case Type::Pointer: {
unsigned AS = cast<PointerType>(T)->getPointeeType().getAddressSpace();
Width = Target.getPointerWidth(AS);
Align = Target.getPointerAlign(AS);
break;
}
- case Type::LValueReference:
- case Type::RValueReference:
- // "When applied to a reference or a reference type, the result is the size
- // of the referenced type." C++98 5.3.3p2: expr.sizeof.
- // FIXME: This is wrong for struct layout: a reference in a struct has
- // pointer size.
- return getTypeInfo(cast<ReferenceType>(T)->getPointeeType());
case Type::MemberPointer: {
// FIXME: This is ABI dependent. We use the Itanium C++ ABI.
// http://www.codesourcery.com/public/cxx-abi/abi.html#member-pointers
@@ -761,7 +771,8 @@ ASTContext::getTypeInfo(const Type *T) {
case Type::Typedef: {
const TypedefDecl *Typedef = cast<TypedefType>(T)->getDecl();
if (const AlignedAttr *Aligned = Typedef->getAttr<AlignedAttr>()) {
- Align = Aligned->getAlignment();
+ Align = std::max(Aligned->getMaxAlignment(),
+ getTypeAlign(Typedef->getUnderlyingType().getTypePtr()));
Width = getTypeSize(Typedef->getUnderlyingType().getTypePtr());
} else
return getTypeInfo(Typedef->getUnderlyingType().getTypePtr());
@@ -1460,16 +1471,24 @@ QualType ASTContext::getDependentSizedArrayType(QualType EltTy,
ArrayType::ArraySizeModifier ASM,
unsigned EltTypeQuals,
SourceRange Brackets) {
- assert((NumElts->isTypeDependent() || NumElts->isValueDependent()) &&
+ assert((!NumElts || NumElts->isTypeDependent() ||
+ NumElts->isValueDependent()) &&
"Size must be type- or value-dependent!");
- llvm::FoldingSetNodeID ID;
- DependentSizedArrayType::Profile(ID, *this, getCanonicalType(EltTy), ASM,
- EltTypeQuals, NumElts);
-
void *InsertPos = 0;
- DependentSizedArrayType *Canon
- = DependentSizedArrayTypes.FindNodeOrInsertPos(ID, InsertPos);
+ DependentSizedArrayType *Canon = 0;
+
+ if (NumElts) {
+ // Dependently-sized array types that do not have a specified
+ // number of elements will have their sizes deduced from an
+ // initializer.
+ llvm::FoldingSetNodeID ID;
+ DependentSizedArrayType::Profile(ID, *this, getCanonicalType(EltTy), ASM,
+ EltTypeQuals, NumElts);
+
+ Canon = DependentSizedArrayTypes.FindNodeOrInsertPos(ID, InsertPos);
+ }
+
DependentSizedArrayType *New;
if (Canon) {
// We already have a canonical version of this array type; use it as
@@ -1483,7 +1502,9 @@ QualType ASTContext::getDependentSizedArrayType(QualType EltTy,
New = new (*this, TypeAlignment)
DependentSizedArrayType(*this, EltTy, QualType(),
NumElts, ASM, EltTypeQuals, Brackets);
- DependentSizedArrayTypes.InsertNode(New, InsertPos);
+
+ if (NumElts)
+ DependentSizedArrayTypes.InsertNode(New, InsertPos);
} else {
QualType Canon = getDependentSizedArrayType(CanonEltTy, NumElts,
ASM, EltTypeQuals,
@@ -1818,9 +1839,10 @@ QualType ASTContext::getTemplateTypeParmType(unsigned Depth, unsigned Index,
QualType
ASTContext::getTemplateSpecializationType(TemplateName Template,
- const TemplateArgumentLoc *Args,
- unsigned NumArgs,
+ const TemplateArgumentListInfo &Args,
QualType Canon) {
+ unsigned NumArgs = Args.size();
+
llvm::SmallVector<TemplateArgument, 4> ArgVec;
ArgVec.reserve(NumArgs);
for (unsigned i = 0; i != NumArgs; ++i)
@@ -2320,6 +2342,22 @@ CanQualType ASTContext::getCanonicalType(QualType T) {
VAT->getBracketsRange()));
}
+DeclarationName ASTContext::getNameForTemplate(TemplateName Name) {
+ if (TemplateDecl *TD = Name.getAsTemplateDecl())
+ return TD->getDeclName();
+
+ if (DependentTemplateName *DTN = Name.getAsDependentTemplateName()) {
+ if (DTN->isIdentifier()) {
+ return DeclarationNames.getIdentifier(DTN->getIdentifier());
+ } else {
+ return DeclarationNames.getCXXOperatorName(DTN->getOperator());
+ }
+ }
+
+ assert(Name.getAsOverloadedFunctionDecl());
+ return Name.getAsOverloadedFunctionDecl()->getDeclName();
+}
+
TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name) {
// If this template name refers to a template, the canonical
// template name merely stores the template itself.
@@ -3374,9 +3412,14 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
false);
return;
}
-
+
if (const PointerType *PT = T->getAs<PointerType>()) {
+ if (PT->isObjCSelType()) {
+ S += ':';
+ return;
+ }
QualType PointeeTy = PT->getPointeeType();
+
bool isReadOnly = false;
// For historical/compatibility reasons, the read-only qualifier of the
// pointee gets emitted _before_ the '^'. The read-only qualifier of
@@ -3407,10 +3450,6 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S,
S.replace(S.end()-2, S.end(), replace);
}
}
- if (isObjCSelType(PointeeTy)) {
- S += ':';
- return;
- }
if (PointeeTy->isCharType()) {
// char pointer types should be encoded as '*' unless it is a
@@ -3633,21 +3672,7 @@ void ASTContext::setObjCIdType(QualType T) {
}
void ASTContext::setObjCSelType(QualType T) {
- ObjCSelType = T;
-
- const TypedefType *TT = T->getAs<TypedefType>();
- if (!TT)
- return;
- TypedefDecl *TD = TT->getDecl();
-
- // typedef struct objc_selector *SEL;
- const PointerType *ptr = TD->getUnderlyingType()->getAs<PointerType>();
- if (!ptr)
- return;
- const RecordType *rec = ptr->getPointeeType()->getAsStructureType();
- if (!rec)
- return;
- SelStructType = rec;
+ ObjCSelTypedefType = T;
}
void ASTContext::setObjCProtoType(QualType QT) {
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index bdc804722c41..572d76ff72d2 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -211,6 +211,203 @@ FileScopeAsmDecl *FileScopeAsmDecl::Create(ASTContext &C, DeclContext *DC,
// NamedDecl Implementation
//===----------------------------------------------------------------------===//
+static NamedDecl::Linkage getLinkageForNamespaceScopeDecl(const NamedDecl *D) {
+ assert(D->getDeclContext()->getLookupContext()->isFileContext() &&
+ "Not a name having namespace scope");
+ ASTContext &Context = D->getASTContext();
+
+ // C++ [basic.link]p3:
+ // A name having namespace scope (3.3.6) has internal linkage if it
+ // is the name of
+ // - an object, reference, function or function template that is
+ // explicitly declared static; or,
+ // (This bullet corresponds to C99 6.2.2p3.)
+ if (const VarDecl *Var = dyn_cast<VarDecl>(D)) {
+ // Explicitly declared static.
+ if (Var->getStorageClass() == VarDecl::Static)
+ return NamedDecl::InternalLinkage;
+
+ // - an object or reference that is explicitly declared const
+ // and neither explicitly declared extern nor previously
+ // declared to have external linkage; or
+ // (there is no equivalent in C99)
+ if (Context.getLangOptions().CPlusPlus &&
+ Var->getType().isConstant(Context) &&
+ Var->getStorageClass() != VarDecl::Extern &&
+ Var->getStorageClass() != VarDecl::PrivateExtern) {
+ bool FoundExtern = false;
+ for (const VarDecl *PrevVar = Var->getPreviousDeclaration();
+ PrevVar && !FoundExtern;
+ PrevVar = PrevVar->getPreviousDeclaration())
+ if (PrevVar->getLinkage() == NamedDecl::ExternalLinkage)
+ FoundExtern = true;
+
+ if (!FoundExtern)
+ return NamedDecl::InternalLinkage;
+ }
+ } else if (isa<FunctionDecl>(D) || isa<FunctionTemplateDecl>(D)) {
+ const FunctionDecl *Function = 0;
+ if (const FunctionTemplateDecl *FunTmpl
+ = dyn_cast<FunctionTemplateDecl>(D))
+ Function = FunTmpl->getTemplatedDecl();
+ else
+ Function = cast<FunctionDecl>(D);
+
+ // Explicitly declared static.
+ if (Function->getStorageClass() == FunctionDecl::Static)
+ return NamedDecl::InternalLinkage;
+ } else if (const FieldDecl *Field = dyn_cast<FieldDecl>(D)) {
+ // - a data member of an anonymous union.
+ if (cast<RecordDecl>(Field->getDeclContext())->isAnonymousStructOrUnion())
+ return NamedDecl::InternalLinkage;
+ }
+
+ // C++ [basic.link]p4:
+
+ // A name having namespace scope has external linkage if it is the
+ // name of
+ //
+ // - an object or reference, unless it has internal linkage; or
+ if (const VarDecl *Var = dyn_cast<VarDecl>(D)) {
+ if (!Context.getLangOptions().CPlusPlus &&
+ (Var->getStorageClass() == VarDecl::Extern ||
+ Var->getStorageClass() == VarDecl::PrivateExtern)) {
+ // C99 6.2.2p4:
+ // For an identifier declared with the storage-class specifier
+ // extern in a scope in which a prior declaration of that
+ // identifier is visible, if the prior declaration specifies
+ // internal or external linkage, the linkage of the identifier
+ // at the later declaration is the same as the linkage
+ // specified at the prior declaration. If no prior declaration
+ // is visible, or if the prior declaration specifies no
+ // linkage, then the identifier has external linkage.
+ if (const VarDecl *PrevVar = Var->getPreviousDeclaration()) {
+ if (NamedDecl::Linkage L = PrevVar->getLinkage())
+ return L;
+ }
+ }
+
+ // C99 6.2.2p5:
+ // If the declaration of an identifier for an object has file
+ // scope and no storage-class specifier, its linkage is
+ // external.
+ return NamedDecl::ExternalLinkage;
+ }
+
+ // - a function, unless it has internal linkage; or
+ if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
+ // C99 6.2.2p5:
+ // If the declaration of an identifier for a function has no
+ // storage-class specifier, its linkage is determined exactly
+ // as if it were declared with the storage-class specifier
+ // extern.
+ if (!Context.getLangOptions().CPlusPlus &&
+ (Function->getStorageClass() == FunctionDecl::Extern ||
+ Function->getStorageClass() == FunctionDecl::PrivateExtern ||
+ Function->getStorageClass() == FunctionDecl::None)) {
+ // C99 6.2.2p4:
+ // For an identifier declared with the storage-class specifier
+ // extern in a scope in which a prior declaration of that
+ // identifier is visible, if the prior declaration specifies
+ // internal or external linkage, the linkage of the identifier
+ // at the later declaration is the same as the linkage
+ // specified at the prior declaration. If no prior declaration
+ // is visible, or if the prior declaration specifies no
+ // linkage, then the identifier has external linkage.
+ if (const FunctionDecl *PrevFunc = Function->getPreviousDeclaration()) {
+ if (NamedDecl::Linkage L = PrevFunc->getLinkage())
+ return L;
+ }
+ }
+
+ return NamedDecl::ExternalLinkage;
+ }
+
+ // - a named class (Clause 9), or an unnamed class defined in a
+ // typedef declaration in which the class has the typedef name
+ // for linkage purposes (7.1.3); or
+ // - a named enumeration (7.2), or an unnamed enumeration
+ // defined in a typedef declaration in which the enumeration
+ // has the typedef name for linkage purposes (7.1.3); or
+ if (const TagDecl *Tag = dyn_cast<TagDecl>(D))
+ if (Tag->getDeclName() || Tag->getTypedefForAnonDecl())
+ return NamedDecl::ExternalLinkage;
+
+ // - an enumerator belonging to an enumeration with external linkage;
+ if (isa<EnumConstantDecl>(D))
+ if (cast<NamedDecl>(D->getDeclContext())->getLinkage()
+ == NamedDecl::ExternalLinkage)
+ return NamedDecl::ExternalLinkage;
+
+ // - a template, unless it is a function template that has
+ // internal linkage (Clause 14);
+ if (isa<TemplateDecl>(D))
+ return NamedDecl::ExternalLinkage;
+
+ // - a namespace (7.3), unless it is declared within an unnamed
+ // namespace.
+ if (isa<NamespaceDecl>(D) && !D->isInAnonymousNamespace())
+ return NamedDecl::ExternalLinkage;
+
+ return NamedDecl::NoLinkage;
+}
+
+NamedDecl::Linkage NamedDecl::getLinkage() const {
+ // Handle linkage for namespace-scope names.
+ if (getDeclContext()->getLookupContext()->isFileContext())
+ if (Linkage L = getLinkageForNamespaceScopeDecl(this))
+ return L;
+
+ // C++ [basic.link]p5:
+ // In addition, a member function, static data member, a named
+ // class or enumeration of class scope, or an unnamed class or
+ // enumeration defined in a class-scope typedef declaration such
+ // that the class or enumeration has the typedef name for linkage
+ // purposes (7.1.3), has external linkage if the name of the class
+ // has external linkage.
+ if (getDeclContext()->isRecord() &&
+ (isa<CXXMethodDecl>(this) || isa<VarDecl>(this) ||
+ (isa<TagDecl>(this) &&
+ (getDeclName() || cast<TagDecl>(this)->getTypedefForAnonDecl()))) &&
+ cast<RecordDecl>(getDeclContext())->getLinkage() == ExternalLinkage)
+ return ExternalLinkage;
+
+ // C++ [basic.link]p6:
+ // The name of a function declared in block scope and the name of
+ // an object declared by a block scope extern declaration have
+ // linkage. If there is a visible declaration of an entity with
+ // linkage having the same name and type, ignoring entities
+ // declared outside the innermost enclosing namespace scope, the
+ // block scope declaration declares that same entity and receives
+ // the linkage of the previous declaration. If there is more than
+ // one such matching entity, the program is ill-formed. Otherwise,
+ // if no matching entity is found, the block scope entity receives
+ // external linkage.
+ if (getLexicalDeclContext()->isFunctionOrMethod()) {
+ if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(this)) {
+ if (Function->getPreviousDeclaration())
+ if (Linkage L = Function->getPreviousDeclaration()->getLinkage())
+ return L;
+
+ return ExternalLinkage;
+ }
+
+ if (const VarDecl *Var = dyn_cast<VarDecl>(this))
+ if (Var->getStorageClass() == VarDecl::Extern ||
+ Var->getStorageClass() == VarDecl::PrivateExtern) {
+ if (Var->getPreviousDeclaration())
+ if (Linkage L = Var->getPreviousDeclaration()->getLinkage())
+ return L;
+
+ return ExternalLinkage;
+ }
+ }
+
+ // C++ [basic.link]p6:
+ // Names not covered by these rules have no linkage.
+ return NoLinkage;
+}
+
std::string NamedDecl::getQualifiedNameAsString() const {
return getQualifiedNameAsString(getASTContext().getLangOptions());
}
@@ -300,13 +497,7 @@ bool NamedDecl::declarationReplaces(NamedDecl *OldD) const {
}
bool NamedDecl::hasLinkage() const {
- if (const VarDecl *VD = dyn_cast<VarDecl>(this))
- return VD->hasExternalStorage() || VD->isFileVarDecl();
-
- if (isa<FunctionDecl>(this) && !isa<CXXMethodDecl>(this))
- return true;
-
- return false;
+ return getLinkage() != NoLinkage;
}
NamedDecl *NamedDecl::getUnderlyingDecl() {
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 831f552489f9..2dcd80b01fcc 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -55,8 +55,7 @@ const char *DeclContext::getDeclKindName() const {
}
bool Decl::CollectingStats(bool Enable) {
- if (Enable)
- StatSwitch = true;
+ if (Enable) StatSwitch = true;
return StatSwitch;
}
@@ -119,7 +118,7 @@ void PrettyStackTraceDecl::print(llvm::raw_ostream &OS) const {
OS << Message;
- if (NamedDecl *DN = dyn_cast_or_null<NamedDecl>(TheDecl))
+ if (const NamedDecl *DN = dyn_cast_or_null<NamedDecl>(TheDecl))
OS << " '" << DN->getQualifiedNameAsString() << '\'';
OS << '\n';
}
@@ -130,9 +129,6 @@ void PrettyStackTraceDecl::print(llvm::raw_ostream &OS) const {
// Out-of-line virtual method providing a home for Decl.
Decl::~Decl() {
- if (isOutOfSemaDC())
- delete getMultipleDC();
-
assert(!HasAttrs && "attributes should have been freed by Destroy");
}
@@ -148,7 +144,7 @@ void Decl::setLexicalDeclContext(DeclContext *DC) {
return;
if (isInSemaDC()) {
- MultipleDC *MDC = new MultipleDC();
+ MultipleDC *MDC = new (getASTContext()) MultipleDC();
MDC->SemanticDC = getDeclContext();
MDC->LexicalDC = DC;
DeclCtx = MDC;
@@ -343,9 +339,12 @@ void Decl::Destroy(ASTContext &C) {
N = Tmp;
}
+ if (isOutOfSemaDC())
+ delete (C) getMultipleDC();
+
this->~Decl();
C.Deallocate((void *)this);
-#endif
+#endif
}
Decl *Decl::castFromDeclContext (const DeclContext *D) {
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index a21c93ffcdc9..40019880074a 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -36,8 +36,6 @@ CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC,
HasTrivialCopyConstructor(true), HasTrivialCopyAssignment(true),
HasTrivialDestructor(true), ComputedVisibleConversions(false),
Bases(0), NumBases(0), VBases(0), NumVBases(0),
- Conversions(DC, DeclarationName()),
- VisibleConversions(DC, DeclarationName()),
TemplateOrInstantiation() { }
CXXRecordDecl *CXXRecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC,
@@ -299,14 +297,11 @@ void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context,
void
CXXRecordDecl::collectConversionFunctions(
- llvm::SmallPtrSet<CanQualType, 8>& ConversionsTypeSet)
+ llvm::SmallPtrSet<CanQualType, 8>& ConversionsTypeSet) const
{
- OverloadedFunctionDecl *TopConversions = getConversionFunctions();
- for (OverloadedFunctionDecl::function_iterator
- TFunc = TopConversions->function_begin(),
- TFuncEnd = TopConversions->function_end();
- TFunc != TFuncEnd; ++TFunc) {
- NamedDecl *TopConv = TFunc->get();
+ const UnresolvedSet *Cs = getConversionFunctions();
+ for (UnresolvedSet::iterator I = Cs->begin(), E = Cs->end(); I != E; ++I) {
+ NamedDecl *TopConv = *I;
CanQualType TConvType;
if (FunctionTemplateDecl *TConversionTemplate =
dyn_cast<FunctionTemplateDecl>(TopConv))
@@ -336,14 +331,11 @@ CXXRecordDecl::getNestedVisibleConversionFunctions(CXXRecordDecl *RD,
bool inTopClass = (RD == this);
QualType ClassType = getASTContext().getTypeDeclType(this);
if (const RecordType *Record = ClassType->getAs<RecordType>()) {
- OverloadedFunctionDecl *Conversions
+ const UnresolvedSet *Cs
= cast<CXXRecordDecl>(Record->getDecl())->getConversionFunctions();
- for (OverloadedFunctionDecl::function_iterator
- Func = Conversions->function_begin(),
- FuncEnd = Conversions->function_end();
- Func != FuncEnd; ++Func) {
- NamedDecl *Conv = Func->get();
+ for (UnresolvedSet::iterator I = Cs->begin(), E = Cs->end(); I != E; ++I) {
+ NamedDecl *Conv = *I;
// Only those conversions not exact match of conversions in current
// class are candidateconversion routines.
CanQualType ConvType;
@@ -405,8 +397,7 @@ CXXRecordDecl::getNestedVisibleConversionFunctions(CXXRecordDecl *RD,
/// getVisibleConversionFunctions - get all conversion functions visible
/// in current class; including conversion function templates.
-OverloadedFunctionDecl *
-CXXRecordDecl::getVisibleConversionFunctions() {
+const UnresolvedSet *CXXRecordDecl::getVisibleConversionFunctions() {
// If root class, all conversions are visible.
if (bases_begin() == bases_end())
return &Conversions;
@@ -425,26 +416,26 @@ void CXXRecordDecl::addVisibleConversionFunction(
CXXConversionDecl *ConvDecl) {
assert(!ConvDecl->getDescribedFunctionTemplate() &&
"Conversion function templates should cast to FunctionTemplateDecl.");
- VisibleConversions.addOverload(ConvDecl);
+ VisibleConversions.addDecl(ConvDecl);
}
void CXXRecordDecl::addVisibleConversionFunction(
FunctionTemplateDecl *ConvDecl) {
assert(isa<CXXConversionDecl>(ConvDecl->getTemplatedDecl()) &&
"Function template is not a conversion function template");
- VisibleConversions.addOverload(ConvDecl);
+ VisibleConversions.addDecl(ConvDecl);
}
void CXXRecordDecl::addConversionFunction(CXXConversionDecl *ConvDecl) {
assert(!ConvDecl->getDescribedFunctionTemplate() &&
"Conversion function templates should cast to FunctionTemplateDecl.");
- Conversions.addOverload(ConvDecl);
+ Conversions.addDecl(ConvDecl);
}
void CXXRecordDecl::addConversionFunction(FunctionTemplateDecl *ConvDecl) {
assert(isa<CXXConversionDecl>(ConvDecl->getTemplatedDecl()) &&
"Function template is not a conversion function template");
- Conversions.addOverload(ConvDecl);
+ Conversions.addDecl(ConvDecl);
}
CXXRecordDecl *CXXRecordDecl::getInstantiatedFromMemberClass() const {
@@ -895,12 +886,21 @@ UsingDirectiveDecl *UsingDirectiveDecl::Create(ASTContext &C, DeclContext *DC,
SourceRange QualifierRange,
NestedNameSpecifier *Qualifier,
SourceLocation IdentLoc,
- NamespaceDecl *Used,
+ NamedDecl *Used,
DeclContext *CommonAncestor) {
+ if (NamespaceDecl *NS = dyn_cast_or_null<NamespaceDecl>(Used))
+ Used = NS->getOriginalNamespace();
return new (C) UsingDirectiveDecl(DC, L, NamespaceLoc, QualifierRange,
Qualifier, IdentLoc, Used, CommonAncestor);
}
+NamespaceDecl *UsingDirectiveDecl::getNominatedNamespace() {
+ if (NamespaceAliasDecl *NA =
+ dyn_cast_or_null<NamespaceAliasDecl>(NominatedNamespace))
+ return NA->getNamespace();
+ return cast_or_null<NamespaceDecl>(NominatedNamespace);
+}
+
NamespaceAliasDecl *NamespaceAliasDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation L,
SourceLocation AliasLoc,
@@ -909,6 +909,8 @@ NamespaceAliasDecl *NamespaceAliasDecl::Create(ASTContext &C, DeclContext *DC,
NestedNameSpecifier *Qualifier,
SourceLocation IdentLoc,
NamedDecl *Namespace) {
+ if (NamespaceDecl *NS = dyn_cast_or_null<NamespaceDecl>(Namespace))
+ Namespace = NS->getOriginalNamespace();
return new (C) NamespaceAliasDecl(DC, L, AliasLoc, Alias, QualifierRange,
Qualifier, IdentLoc, Namespace);
}
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index 131de8b2e11b..a5982cfd97f1 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -18,19 +18,18 @@
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
#include "clang/AST/PrettyPrinter.h"
-#include "llvm/Support/Compiler.h"
-#include "llvm/Support/Format.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
namespace {
- class VISIBILITY_HIDDEN DeclPrinter : public DeclVisitor<DeclPrinter> {
+ class DeclPrinter : public DeclVisitor<DeclPrinter> {
llvm::raw_ostream &Out;
ASTContext &Context;
PrintingPolicy Policy;
unsigned Indentation;
- llvm::raw_ostream& Indent();
+ llvm::raw_ostream& Indent() { return Indent(Indentation); }
+ llvm::raw_ostream& Indent(unsigned Indentation);
void ProcessDeclGroup(llvm::SmallVectorImpl<Decl*>& Decls);
void Print(AccessSpecifier AS);
@@ -154,8 +153,8 @@ void Decl::dump() const {
print(llvm::errs());
}
-llvm::raw_ostream& DeclPrinter::Indent() {
- for (unsigned i = 0; i < Indentation; ++i)
+llvm::raw_ostream& DeclPrinter::Indent(unsigned Indentation) {
+ for (unsigned i = 0; i != Indentation; ++i)
Out << " ";
return Out;
}
@@ -205,6 +204,8 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) {
AccessSpecifier AS = D->getAccess();
if (AS != CurAS) {
+ if (Indent)
+ this->Indent(Indentation - Policy.Indentation);
Print(AS);
Out << ":\n";
CurAS = AS;
@@ -502,7 +503,7 @@ void DeclPrinter::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) {
Out << "using namespace ";
if (D->getQualifier())
D->getQualifier()->print(Out, Policy);
- Out << D->getNominatedNamespace()->getNameAsString();
+ Out << D->getNominatedNamespaceAsWritten()->getNameAsString();
}
void DeclPrinter::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) {
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index 0c14714812f5..902339e1efcf 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -214,9 +214,7 @@ QualType ClassTemplateDecl::getInjectedClassNameType(ASTContext &Context) {
} else if (NonTypeTemplateParmDecl *NTTP =
dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
Expr *E = new (Context) DeclRefExpr(NTTP, NTTP->getType(),
- NTTP->getLocation(),
- NTTP->getType()->isDependentType(),
- /*Value-dependent=*/true);
+ NTTP->getLocation());
TemplateArgs.push_back(TemplateArgument(E));
} else {
TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*Param);
@@ -453,8 +451,9 @@ Create(ASTContext &Context, DeclContext *DC, SourceLocation L,
TemplateParameterList *Params,
ClassTemplateDecl *SpecializedTemplate,
TemplateArgumentListBuilder &Builder,
- TemplateArgumentLoc *ArgInfos, unsigned N,
+ const TemplateArgumentListInfo &ArgInfos,
ClassTemplatePartialSpecializationDecl *PrevDecl) {
+ unsigned N = ArgInfos.size();
TemplateArgumentLoc *ClonedArgs = new (Context) TemplateArgumentLoc[N];
for (unsigned I = 0; I != N; ++I)
ClonedArgs[I] = ArgInfos[I];
diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp
index 1ff068c9862c..3471657b6523 100644
--- a/lib/AST/DeclarationName.cpp
+++ b/lib/AST/DeclarationName.cpp
@@ -50,6 +50,17 @@ public:
void *FETokenInfo;
};
+/// CXXLiberalOperatorName - Contains the actual identifier that makes up the
+/// name.
+///
+/// This identifier is stored here rather than directly in DeclarationName so as
+/// to allow Objective-C selectors, which are about a million times more common,
+/// to consume minimal memory.
+class CXXLiteralOperatorIdName : public DeclarationNameExtra {
+public:
+ IdentifierInfo *ID;
+};
+
bool operator<(DeclarationName LHS, DeclarationName RHS) {
if (LHS.getNameKind() != RHS.getNameKind())
return LHS.getNameKind() < RHS.getNameKind();
@@ -89,6 +100,10 @@ bool operator<(DeclarationName LHS, DeclarationName RHS) {
case DeclarationName::CXXOperatorName:
return LHS.getCXXOverloadedOperator() < RHS.getCXXOverloadedOperator();
+
+ case DeclarationName::CXXLiteralOperatorName:
+ return LHS.getCXXLiteralIdentifier()->getName() <
+ RHS.getCXXLiteralIdentifier()->getName();
case DeclarationName::CXXUsingDirective:
return false;
@@ -143,6 +158,9 @@ DeclarationName::NameKind DeclarationName::getNameKind() const {
case DeclarationNameExtra::CXXConversionFunction:
return CXXConversionFunctionName;
+ case DeclarationNameExtra::CXXLiteralOperator:
+ return CXXLiteralOperatorName;
+
case DeclarationNameExtra::CXXUsingDirective:
return CXXUsingDirective;
@@ -208,6 +226,10 @@ std::string DeclarationName::getAsString() const {
return Result;
}
+ case CXXLiteralOperatorName: {
+ return "operator \"\" " + std::string(getCXXLiteralIdentifier()->getName());
+ }
+
case CXXConversionFunctionName: {
std::string Result = "operator ";
QualType Type = getCXXNameType();
@@ -242,6 +264,13 @@ OverloadedOperatorKind DeclarationName::getCXXOverloadedOperator() const {
}
}
+IdentifierInfo *DeclarationName::getCXXLiteralIdentifier() const {
+ if (CXXLiteralOperatorIdName *CXXLit = getAsCXXLiteralOperatorIdName())
+ return CXXLit->ID;
+ else
+ return 0;
+}
+
Selector DeclarationName::getObjCSelector() const {
switch (getNameKind()) {
case ObjCZeroArgSelector:
@@ -273,6 +302,9 @@ void *DeclarationName::getFETokenInfoAsVoid() const {
case CXXOperatorName:
return getAsCXXOperatorIdName()->FETokenInfo;
+ case CXXLiteralOperatorName:
+ return getCXXLiteralIdentifier()->getFETokenInfo<void>();
+
default:
assert(false && "Declaration name has no FETokenInfo");
}
@@ -295,6 +327,10 @@ void DeclarationName::setFETokenInfo(void *T) {
getAsCXXOperatorIdName()->FETokenInfo = T;
break;
+ case CXXLiteralOperatorName:
+ getCXXLiteralIdentifier()->setFETokenInfo(T);
+ break;
+
default:
assert(false && "Declaration name has no FETokenInfo");
}
@@ -390,6 +426,14 @@ DeclarationNameTable::getCXXOperatorName(OverloadedOperatorKind Op) {
return DeclarationName(&CXXOperatorNames[(unsigned)Op]);
}
+DeclarationName
+DeclarationNameTable::getCXXLiteralOperatorName(IdentifierInfo *II) {
+ CXXLiteralOperatorIdName *LiteralName = new CXXLiteralOperatorIdName;
+ LiteralName->ExtraKindOrNumArgs = DeclarationNameExtra::CXXLiteralOperator;
+ LiteralName->ID = II;
+ return DeclarationName(LiteralName);
+}
+
unsigned
llvm::DenseMapInfo<clang::DeclarationName>::
getHashValue(clang::DeclarationName N) {
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 90b50c61f989..624a620b9fbb 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -31,49 +31,104 @@ using namespace clang;
// Primary Expressions.
//===----------------------------------------------------------------------===//
+void ExplicitTemplateArgumentList::initializeFrom(
+ const TemplateArgumentListInfo &Info) {
+ LAngleLoc = Info.getLAngleLoc();
+ RAngleLoc = Info.getRAngleLoc();
+ NumTemplateArgs = Info.size();
+
+ TemplateArgumentLoc *ArgBuffer = getTemplateArgs();
+ for (unsigned i = 0; i != NumTemplateArgs; ++i)
+ new (&ArgBuffer[i]) TemplateArgumentLoc(Info[i]);
+}
+
+void ExplicitTemplateArgumentList::copyInto(
+ TemplateArgumentListInfo &Info) const {
+ Info.setLAngleLoc(LAngleLoc);
+ Info.setRAngleLoc(RAngleLoc);
+ for (unsigned I = 0; I != NumTemplateArgs; ++I)
+ Info.addArgument(getTemplateArgs()[I]);
+}
+
+std::size_t ExplicitTemplateArgumentList::sizeFor(
+ const TemplateArgumentListInfo &Info) {
+ return sizeof(ExplicitTemplateArgumentList) +
+ sizeof(TemplateArgumentLoc) * Info.size();
+}
+
+void DeclRefExpr::computeDependence() {
+ TypeDependent = false;
+ ValueDependent = false;
+
+ NamedDecl *D = getDecl();
+
+ // (TD) C++ [temp.dep.expr]p3:
+ // An id-expression is type-dependent if it contains:
+ //
+ // and
+ //
+ // (VD) C++ [temp.dep.constexpr]p2:
+ // An identifier is value-dependent if it is:
+
+ // (TD) - an identifier that was declared with dependent type
+ // (VD) - a name declared with a dependent type,
+ if (getType()->isDependentType()) {
+ TypeDependent = true;
+ ValueDependent = true;
+ }
+ // (TD) - a conversion-function-id that specifies a dependent type
+ else if (D->getDeclName().getNameKind()
+ == DeclarationName::CXXConversionFunctionName &&
+ D->getDeclName().getCXXNameType()->isDependentType()) {
+ TypeDependent = true;
+ ValueDependent = true;
+ }
+ // (TD) - a template-id that is dependent,
+ else if (hasExplicitTemplateArgumentList() &&
+ TemplateSpecializationType::anyDependentTemplateArguments(
+ getTemplateArgs(),
+ getNumTemplateArgs())) {
+ TypeDependent = true;
+ ValueDependent = true;
+ }
+ // (VD) - the name of a non-type template parameter,
+ else if (isa<NonTypeTemplateParmDecl>(D))
+ ValueDependent = true;
+ // (VD) - a constant with integral or enumeration type and is
+ // initialized with an expression that is value-dependent.
+ else if (VarDecl *Var = dyn_cast<VarDecl>(D)) {
+ if (Var->getType()->isIntegralType() &&
+ Var->getType().getCVRQualifiers() == Qualifiers::Const &&
+ Var->getInit() &&
+ Var->getInit()->isValueDependent())
+ ValueDependent = true;
+ }
+ // (TD) - a nested-name-specifier or a qualified-id that names a
+ // member of an unknown specialization.
+ // (handled by DependentScopeDeclRefExpr)
+}
+
DeclRefExpr::DeclRefExpr(NestedNameSpecifier *Qualifier,
SourceRange QualifierRange,
NamedDecl *D, SourceLocation NameLoc,
- bool HasExplicitTemplateArgumentList,
- SourceLocation LAngleLoc,
- const TemplateArgumentLoc *ExplicitTemplateArgs,
- unsigned NumExplicitTemplateArgs,
- SourceLocation RAngleLoc,
- QualType T, bool TD, bool VD)
- : Expr(DeclRefExprClass, T, TD, VD),
+ const TemplateArgumentListInfo *TemplateArgs,
+ QualType T)
+ : Expr(DeclRefExprClass, T, false, false),
DecoratedD(D,
(Qualifier? HasQualifierFlag : 0) |
- (HasExplicitTemplateArgumentList?
- HasExplicitTemplateArgumentListFlag : 0)),
+ (TemplateArgs ? HasExplicitTemplateArgumentListFlag : 0)),
Loc(NameLoc) {
+ assert(!isa<OverloadedFunctionDecl>(D));
if (Qualifier) {
NameQualifier *NQ = getNameQualifier();
NQ->NNS = Qualifier;
NQ->Range = QualifierRange;
}
- if (HasExplicitTemplateArgumentList) {
- ExplicitTemplateArgumentList *ETemplateArgs
- = getExplicitTemplateArgumentList();
- ETemplateArgs->LAngleLoc = LAngleLoc;
- ETemplateArgs->RAngleLoc = RAngleLoc;
- ETemplateArgs->NumTemplateArgs = NumExplicitTemplateArgs;
-
- TemplateArgumentLoc *TemplateArgs = ETemplateArgs->getTemplateArgs();
- for (unsigned I = 0; I < NumExplicitTemplateArgs; ++I)
- new (TemplateArgs + I) TemplateArgumentLoc(ExplicitTemplateArgs[I]);
- }
-}
+ if (TemplateArgs)
+ getExplicitTemplateArgumentList()->initializeFrom(*TemplateArgs);
-DeclRefExpr *DeclRefExpr::Create(ASTContext &Context,
- NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
- NamedDecl *D,
- SourceLocation NameLoc,
- QualType T, bool TD, bool VD) {
- return Create(Context, Qualifier, QualifierRange, D, NameLoc,
- false, SourceLocation(), 0, 0, SourceLocation(),
- T, TD, VD);
+ computeDependence();
}
DeclRefExpr *DeclRefExpr::Create(ASTContext &Context,
@@ -81,28 +136,18 @@ DeclRefExpr *DeclRefExpr::Create(ASTContext &Context,
SourceRange QualifierRange,
NamedDecl *D,
SourceLocation NameLoc,
- bool HasExplicitTemplateArgumentList,
- SourceLocation LAngleLoc,
- const TemplateArgumentLoc *ExplicitTemplateArgs,
- unsigned NumExplicitTemplateArgs,
- SourceLocation RAngleLoc,
- QualType T, bool TD, bool VD) {
+ QualType T,
+ const TemplateArgumentListInfo *TemplateArgs) {
std::size_t Size = sizeof(DeclRefExpr);
if (Qualifier != 0)
Size += sizeof(NameQualifier);
- if (HasExplicitTemplateArgumentList)
- Size += sizeof(ExplicitTemplateArgumentList) +
- sizeof(TemplateArgumentLoc) * NumExplicitTemplateArgs;
+ if (TemplateArgs)
+ Size += ExplicitTemplateArgumentList::sizeFor(*TemplateArgs);
void *Mem = Context.Allocate(Size, llvm::alignof<DeclRefExpr>());
return new (Mem) DeclRefExpr(Qualifier, QualifierRange, D, NameLoc,
- HasExplicitTemplateArgumentList,
- LAngleLoc,
- ExplicitTemplateArgs,
- NumExplicitTemplateArgs,
- RAngleLoc,
- T, TD, VD);
+ TemplateArgs, T);
}
SourceRange DeclRefExpr::getSourceRange() const {
@@ -427,15 +472,13 @@ QualType CallExpr::getCallReturnType() const {
MemberExpr::MemberExpr(Expr *base, bool isarrow, NestedNameSpecifier *qual,
SourceRange qualrange, NamedDecl *memberdecl,
- SourceLocation l, bool has_explicit,
- SourceLocation langle,
- const TemplateArgumentLoc *targs, unsigned numtargs,
- SourceLocation rangle, QualType ty)
+ SourceLocation l, const TemplateArgumentListInfo *targs,
+ QualType ty)
: Expr(MemberExprClass, ty,
base->isTypeDependent() || (qual && qual->isDependent()),
base->isValueDependent() || (qual && qual->isDependent())),
Base(base), MemberDecl(memberdecl), MemberLoc(l), IsArrow(isarrow),
- HasQualifier(qual != 0), HasExplicitTemplateArgumentList(has_explicit) {
+ HasQualifier(qual != 0), HasExplicitTemplateArgumentList(targs) {
// Initialize the qualifier, if any.
if (HasQualifier) {
NameQualifier *NQ = getMemberQualifier();
@@ -444,17 +487,8 @@ MemberExpr::MemberExpr(Expr *base, bool isarrow, NestedNameSpecifier *qual,
}
// Initialize the explicit template argument list, if any.
- if (HasExplicitTemplateArgumentList) {
- ExplicitTemplateArgumentList *ETemplateArgs
- = getExplicitTemplateArgumentList();
- ETemplateArgs->LAngleLoc = langle;
- ETemplateArgs->RAngleLoc = rangle;
- ETemplateArgs->NumTemplateArgs = numtargs;
-
- TemplateArgumentLoc *TemplateArgs = ETemplateArgs->getTemplateArgs();
- for (unsigned I = 0; I < numtargs; ++I)
- new (TemplateArgs + I) TemplateArgumentLoc(targs[I]);
- }
+ if (targs)
+ getExplicitTemplateArgumentList()->initializeFrom(*targs);
}
MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow,
@@ -462,24 +496,18 @@ MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow,
SourceRange qualrange,
NamedDecl *memberdecl,
SourceLocation l,
- bool has_explicit,
- SourceLocation langle,
- const TemplateArgumentLoc *targs,
- unsigned numtargs,
- SourceLocation rangle,
+ const TemplateArgumentListInfo *targs,
QualType ty) {
std::size_t Size = sizeof(MemberExpr);
if (qual != 0)
Size += sizeof(NameQualifier);
- if (has_explicit)
- Size += sizeof(ExplicitTemplateArgumentList) +
- sizeof(TemplateArgumentLoc) * numtargs;
+ if (targs)
+ Size += ExplicitTemplateArgumentList::sizeFor(*targs);
void *Mem = C.Allocate(Size, llvm::alignof<MemberExpr>());
return new (Mem) MemberExpr(base, isarrow, qual, qualrange, memberdecl, l,
- has_explicit, langle, targs, numtargs, rangle,
- ty);
+ targs, ty);
}
const char *CastExpr::getCastKindName() const {
@@ -528,6 +556,8 @@ const char *CastExpr::getCastKindName() const {
return "FloatingToIntegral";
case CastExpr::CK_FloatingCast:
return "FloatingCast";
+ case CastExpr::CK_MemberPointerToBoolean:
+ return "MemberPointerToBoolean";
}
assert(0 && "Unhandled cast kind!");
@@ -640,12 +670,17 @@ OverloadedOperatorKind BinaryOperator::getOverloadedOperator(Opcode Opc) {
InitListExpr::InitListExpr(SourceLocation lbraceloc,
Expr **initExprs, unsigned numInits,
SourceLocation rbraceloc)
- : Expr(InitListExprClass, QualType(),
- hasAnyTypeDependentArguments(initExprs, numInits),
- hasAnyValueDependentArguments(initExprs, numInits)),
+ : Expr(InitListExprClass, QualType(), false, false),
LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), SyntacticForm(0),
- UnionFieldInit(0), HadArrayRangeDesignator(false) {
-
+ UnionFieldInit(0), HadArrayRangeDesignator(false)
+{
+ for (unsigned I = 0; I != numInits; ++I) {
+ if (initExprs[I]->isTypeDependent())
+ TypeDependent = true;
+ if (initExprs[I]->isValueDependent())
+ ValueDependent = true;
+ }
+
InitExprs.insert(InitExprs.end(), initExprs, initExprs+numInits);
}
@@ -1091,10 +1126,10 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const {
return LV_Valid;
case PredefinedExprClass:
return LV_Valid;
+ case UnresolvedLookupExprClass:
+ return LV_Valid;
case CXXDefaultArgExprClass:
return cast<CXXDefaultArgExpr>(this)->getExpr()->isLvalue(Ctx);
- case CXXConditionDeclExprClass:
- return LV_Valid;
case CStyleCastExprClass:
case CXXFunctionalCastExprClass:
case CXXStaticCastExprClass:
@@ -1141,18 +1176,6 @@ Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const {
return LV_Valid;
}
- case TemplateIdRefExprClass: {
- const TemplateIdRefExpr *TID = cast<TemplateIdRefExpr>(this);
- TemplateName Template = TID->getTemplateName();
- NamedDecl *ND = Template.getAsTemplateDecl();
- if (!ND)
- ND = Template.getAsOverloadedFunctionDecl();
- if (ND && DeclCanBeLvalue(ND, Ctx))
- return LV_Valid;
-
- break;
- }
-
default:
break;
}
@@ -1491,19 +1514,18 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case Expr::CXXNullPtrLiteralExprClass:
case Expr::CXXThisExprClass:
case Expr::CXXThrowExprClass:
- case Expr::CXXConditionDeclExprClass: // FIXME: is this correct?
case Expr::CXXNewExprClass:
case Expr::CXXDeleteExprClass:
case Expr::CXXPseudoDestructorExprClass:
- case Expr::UnresolvedFunctionNameExprClass:
- case Expr::UnresolvedDeclRefExprClass:
- case Expr::TemplateIdRefExprClass:
+ case Expr::UnresolvedLookupExprClass:
+ case Expr::DependentScopeDeclRefExprClass:
case Expr::CXXConstructExprClass:
case Expr::CXXBindTemporaryExprClass:
case Expr::CXXExprWithTemporariesClass:
case Expr::CXXTemporaryObjectExprClass:
case Expr::CXXUnresolvedConstructExprClass:
- case Expr::CXXUnresolvedMemberExprClass:
+ case Expr::CXXDependentScopeMemberExprClass:
+ case Expr::UnresolvedMemberExprClass:
case Expr::ObjCStringLiteralClass:
case Expr::ObjCEncodeExprClass:
case Expr::ObjCMessageExprClass:
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index 0ba4608ee198..d1a0390a0a68 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -72,14 +72,6 @@ Stmt::child_iterator CXXZeroInitValueExpr::child_end() {
return child_iterator();
}
-// CXXConditionDeclExpr
-Stmt::child_iterator CXXConditionDeclExpr::child_begin() {
- return getVarDecl();
-}
-Stmt::child_iterator CXXConditionDeclExpr::child_end() {
- return child_iterator();
-}
-
// CXXNewExpr
CXXNewExpr::CXXNewExpr(bool globalNew, FunctionDecl *operatorNew,
Expr **placementArgs, unsigned numPlaceArgs,
@@ -121,11 +113,45 @@ Stmt::child_iterator CXXPseudoDestructorExpr::child_end() {
return &Base + 1;
}
-// UnresolvedFunctionNameExpr
-Stmt::child_iterator UnresolvedFunctionNameExpr::child_begin() {
+// UnresolvedLookupExpr
+UnresolvedLookupExpr *
+UnresolvedLookupExpr::Create(ASTContext &C, bool Dependent,
+ NestedNameSpecifier *Qualifier,
+ SourceRange QualifierRange, DeclarationName Name,
+ SourceLocation NameLoc, bool ADL,
+ const TemplateArgumentListInfo &Args)
+{
+ void *Mem = C.Allocate(sizeof(UnresolvedLookupExpr) +
+ ExplicitTemplateArgumentList::sizeFor(Args));
+ UnresolvedLookupExpr *ULE
+ = new (Mem) UnresolvedLookupExpr(Dependent ? C.DependentTy : C.OverloadTy,
+ Dependent, Qualifier, QualifierRange,
+ Name, NameLoc, ADL,
+ /*Overload*/ true,
+ /*ExplicitTemplateArgs*/ true);
+
+ reinterpret_cast<ExplicitTemplateArgumentList*>(ULE+1)->initializeFrom(Args);
+
+ return ULE;
+}
+
+bool UnresolvedLookupExpr::ComputeDependence(NamedDecl * const *Begin,
+ NamedDecl * const *End,
+ const TemplateArgumentListInfo *Args) {
+ for (NamedDecl * const *I = Begin; I != End; ++I)
+ if ((*I)->getDeclContext()->isDependentContext())
+ return true;
+
+ if (Args && TemplateSpecializationType::anyDependentTemplateArguments(*Args))
+ return true;
+
+ return false;
+}
+
+Stmt::child_iterator UnresolvedLookupExpr::child_begin() {
return child_iterator();
}
-Stmt::child_iterator UnresolvedFunctionNameExpr::child_end() {
+Stmt::child_iterator UnresolvedLookupExpr::child_end() {
return child_iterator();
}
// UnaryTypeTraitExpr
@@ -136,72 +162,37 @@ Stmt::child_iterator UnaryTypeTraitExpr::child_end() {
return child_iterator();
}
-// UnresolvedDeclRefExpr
-StmtIterator UnresolvedDeclRefExpr::child_begin() {
- return child_iterator();
+// DependentScopeDeclRefExpr
+DependentScopeDeclRefExpr *
+DependentScopeDeclRefExpr::Create(ASTContext &C,
+ NestedNameSpecifier *Qualifier,
+ SourceRange QualifierRange,
+ DeclarationName Name,
+ SourceLocation NameLoc,
+ const TemplateArgumentListInfo *Args) {
+ std::size_t size = sizeof(DependentScopeDeclRefExpr);
+ if (Args) size += ExplicitTemplateArgumentList::sizeFor(*Args);
+ void *Mem = C.Allocate(size);
+
+ DependentScopeDeclRefExpr *DRE
+ = new (Mem) DependentScopeDeclRefExpr(C.DependentTy,
+ Qualifier, QualifierRange,
+ Name, NameLoc,
+ Args != 0);
+
+ if (Args)
+ reinterpret_cast<ExplicitTemplateArgumentList*>(DRE+1)
+ ->initializeFrom(*Args);
+
+ return DRE;
}
-StmtIterator UnresolvedDeclRefExpr::child_end() {
+StmtIterator DependentScopeDeclRefExpr::child_begin() {
return child_iterator();
}
-TemplateIdRefExpr::TemplateIdRefExpr(QualType T,
- NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
- TemplateName Template,
- SourceLocation TemplateNameLoc,
- SourceLocation LAngleLoc,
- const TemplateArgumentLoc *TemplateArgs,
- unsigned NumTemplateArgs,
- SourceLocation RAngleLoc)
- : Expr(TemplateIdRefExprClass, T,
- (Template.isDependent() ||
- TemplateSpecializationType::anyDependentTemplateArguments(
- TemplateArgs, NumTemplateArgs)),
- (Template.isDependent() ||
- TemplateSpecializationType::anyDependentTemplateArguments(
- TemplateArgs, NumTemplateArgs))),
- Qualifier(Qualifier), QualifierRange(QualifierRange), Template(Template),
- TemplateNameLoc(TemplateNameLoc), LAngleLoc(LAngleLoc),
- RAngleLoc(RAngleLoc), NumTemplateArgs(NumTemplateArgs) {
- TemplateArgumentLoc *StoredTemplateArgs
- = reinterpret_cast<TemplateArgumentLoc *> (this+1);
- for (unsigned I = 0; I != NumTemplateArgs; ++I)
- new (StoredTemplateArgs + I) TemplateArgumentLoc(TemplateArgs[I]);
-}
-
-TemplateIdRefExpr *
-TemplateIdRefExpr::Create(ASTContext &Context, QualType T,
- NestedNameSpecifier *Qualifier,
- SourceRange QualifierRange,
- TemplateName Template, SourceLocation TemplateNameLoc,
- SourceLocation LAngleLoc,
- const TemplateArgumentLoc *TemplateArgs,
- unsigned NumTemplateArgs, SourceLocation RAngleLoc) {
- void *Mem = Context.Allocate(sizeof(TemplateIdRefExpr) +
- sizeof(TemplateArgumentLoc) * NumTemplateArgs);
- return new (Mem) TemplateIdRefExpr(T, Qualifier, QualifierRange, Template,
- TemplateNameLoc, LAngleLoc, TemplateArgs,
- NumTemplateArgs, RAngleLoc);
-}
-
-void TemplateIdRefExpr::DoDestroy(ASTContext &Context) {
- const TemplateArgumentLoc *TemplateArgs = getTemplateArgs();
- for (unsigned I = 0; I != NumTemplateArgs; ++I)
- if (Expr *E = TemplateArgs[I].getArgument().getAsExpr())
- E->Destroy(Context);
- this->~TemplateIdRefExpr();
- Context.Deallocate(this);
-}
-
-Stmt::child_iterator TemplateIdRefExpr::child_begin() {
- // FIXME: Walk the expressions in the template arguments (?)
- return Stmt::child_iterator();
-}
-
-Stmt::child_iterator TemplateIdRefExpr::child_end() {
- // FIXME: Walk the expressions in the template arguments (?)
- return Stmt::child_iterator();
+StmtIterator DependentScopeDeclRefExpr::child_end() {
+ return child_iterator();
}
bool UnaryTypeTraitExpr::EvaluateTrait(ASTContext& C) const {
@@ -526,7 +517,7 @@ Stmt::child_iterator CXXUnresolvedConstructExpr::child_end() {
return child_iterator(reinterpret_cast<Stmt **>(this + 1) + NumArgs);
}
-CXXUnresolvedMemberExpr::CXXUnresolvedMemberExpr(ASTContext &C,
+CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C,
Expr *Base, bool IsArrow,
SourceLocation OperatorLoc,
NestedNameSpecifier *Qualifier,
@@ -534,33 +525,20 @@ CXXUnresolvedMemberExpr::CXXUnresolvedMemberExpr(ASTContext &C,
NamedDecl *FirstQualifierFoundInScope,
DeclarationName Member,
SourceLocation MemberLoc,
- bool HasExplicitTemplateArgs,
- SourceLocation LAngleLoc,
- const TemplateArgumentLoc *TemplateArgs,
- unsigned NumTemplateArgs,
- SourceLocation RAngleLoc)
- : Expr(CXXUnresolvedMemberExprClass, C.DependentTy, true, true),
+ const TemplateArgumentListInfo *TemplateArgs)
+ : Expr(CXXDependentScopeMemberExprClass, C.DependentTy, true, true),
Base(Base), IsArrow(IsArrow),
- HasExplicitTemplateArgumentList(HasExplicitTemplateArgs),
+ HasExplicitTemplateArgumentList(TemplateArgs),
OperatorLoc(OperatorLoc),
Qualifier(Qualifier), QualifierRange(QualifierRange),
FirstQualifierFoundInScope(FirstQualifierFoundInScope),
Member(Member), MemberLoc(MemberLoc) {
- if (HasExplicitTemplateArgumentList) {
- ExplicitTemplateArgumentList *ETemplateArgs
- = getExplicitTemplateArgumentList();
- ETemplateArgs->LAngleLoc = LAngleLoc;
- ETemplateArgs->RAngleLoc = RAngleLoc;
- ETemplateArgs->NumTemplateArgs = NumTemplateArgs;
-
- TemplateArgumentLoc *SavedTemplateArgs = ETemplateArgs->getTemplateArgs();
- for (unsigned I = 0; I < NumTemplateArgs; ++I)
- new (SavedTemplateArgs + I) TemplateArgumentLoc(TemplateArgs[I]);
- }
+ if (TemplateArgs)
+ getExplicitTemplateArgumentList()->initializeFrom(*TemplateArgs);
}
-CXXUnresolvedMemberExpr *
-CXXUnresolvedMemberExpr::Create(ASTContext &C,
+CXXDependentScopeMemberExpr *
+CXXDependentScopeMemberExpr::Create(ASTContext &C,
Expr *Base, bool IsArrow,
SourceLocation OperatorLoc,
NestedNameSpecifier *Qualifier,
@@ -568,37 +546,79 @@ CXXUnresolvedMemberExpr::Create(ASTContext &C,
NamedDecl *FirstQualifierFoundInScope,
DeclarationName Member,
SourceLocation MemberLoc,
- bool HasExplicitTemplateArgs,
- SourceLocation LAngleLoc,
- const TemplateArgumentLoc *TemplateArgs,
- unsigned NumTemplateArgs,
- SourceLocation RAngleLoc) {
- if (!HasExplicitTemplateArgs)
- return new (C) CXXUnresolvedMemberExpr(C, Base, IsArrow, OperatorLoc,
+ const TemplateArgumentListInfo *TemplateArgs) {
+ if (!TemplateArgs)
+ return new (C) CXXDependentScopeMemberExpr(C, Base, IsArrow, OperatorLoc,
Qualifier, QualifierRange,
FirstQualifierFoundInScope,
Member, MemberLoc);
- void *Mem = C.Allocate(sizeof(CXXUnresolvedMemberExpr) +
- sizeof(ExplicitTemplateArgumentList) +
- sizeof(TemplateArgumentLoc) * NumTemplateArgs,
- llvm::alignof<CXXUnresolvedMemberExpr>());
- return new (Mem) CXXUnresolvedMemberExpr(C, Base, IsArrow, OperatorLoc,
+ std::size_t size = sizeof(CXXDependentScopeMemberExpr);
+ if (TemplateArgs)
+ size += ExplicitTemplateArgumentList::sizeFor(*TemplateArgs);
+
+ void *Mem = C.Allocate(size, llvm::alignof<CXXDependentScopeMemberExpr>());
+ return new (Mem) CXXDependentScopeMemberExpr(C, Base, IsArrow, OperatorLoc,
Qualifier, QualifierRange,
FirstQualifierFoundInScope,
Member,
MemberLoc,
- HasExplicitTemplateArgs,
- LAngleLoc,
- TemplateArgs,
- NumTemplateArgs,
- RAngleLoc);
+ TemplateArgs);
+}
+
+Stmt::child_iterator CXXDependentScopeMemberExpr::child_begin() {
+ return child_iterator(&Base);
}
-Stmt::child_iterator CXXUnresolvedMemberExpr::child_begin() {
+Stmt::child_iterator CXXDependentScopeMemberExpr::child_end() {
+ return child_iterator(&Base + 1);
+}
+
+UnresolvedMemberExpr::UnresolvedMemberExpr(QualType T, bool Dependent,
+ bool HasUnresolvedUsing,
+ Expr *Base, bool IsArrow,
+ SourceLocation OperatorLoc,
+ NestedNameSpecifier *Qualifier,
+ SourceRange QualifierRange,
+ DeclarationName MemberName,
+ SourceLocation MemberLoc,
+ const TemplateArgumentListInfo *TemplateArgs)
+ : Expr(UnresolvedMemberExprClass, T, Dependent, Dependent),
+ Base(Base), IsArrow(IsArrow), HasUnresolvedUsing(HasUnresolvedUsing),
+ HasExplicitTemplateArgs(TemplateArgs != 0),
+ OperatorLoc(OperatorLoc),
+ Qualifier(Qualifier), QualifierRange(QualifierRange),
+ MemberName(MemberName), MemberLoc(MemberLoc) {
+ if (TemplateArgs)
+ getExplicitTemplateArgs()->initializeFrom(*TemplateArgs);
+}
+
+UnresolvedMemberExpr *
+UnresolvedMemberExpr::Create(ASTContext &C, bool Dependent,
+ bool HasUnresolvedUsing,
+ Expr *Base, bool IsArrow,
+ SourceLocation OperatorLoc,
+ NestedNameSpecifier *Qualifier,
+ SourceRange QualifierRange,
+ DeclarationName Member,
+ SourceLocation MemberLoc,
+ const TemplateArgumentListInfo *TemplateArgs) {
+ std::size_t size = sizeof(UnresolvedMemberExpr);
+ if (TemplateArgs)
+ size += ExplicitTemplateArgumentList::sizeFor(*TemplateArgs);
+
+ void *Mem = C.Allocate(size, llvm::alignof<UnresolvedMemberExpr>());
+ return new (Mem) UnresolvedMemberExpr(
+ Dependent ? C.DependentTy : C.OverloadTy,
+ Dependent, HasUnresolvedUsing, Base, IsArrow,
+ OperatorLoc, Qualifier, QualifierRange,
+ Member, MemberLoc, TemplateArgs);
+}
+
+Stmt::child_iterator UnresolvedMemberExpr::child_begin() {
return child_iterator(&Base);
}
-Stmt::child_iterator CXXUnresolvedMemberExpr::child_end() {
+Stmt::child_iterator UnresolvedMemberExpr::child_end() {
return child_iterator(&Base + 1);
}
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 2689859e8e4a..a20e1cc6f56b 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -19,7 +19,6 @@
#include "clang/Basic/Builtins.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/SmallString.h"
-#include "llvm/Support/Compiler.h"
#include <cstring>
using namespace clang;
@@ -153,7 +152,7 @@ static APFloat HandleIntToFloatCast(QualType DestType, QualType SrcType,
}
namespace {
-class VISIBILITY_HIDDEN HasSideEffect
+class HasSideEffect
: public StmtVisitor<HasSideEffect, bool> {
EvalInfo &Info;
public:
@@ -210,7 +209,7 @@ public:
// LValue Evaluation
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN LValueExprEvaluator
+class LValueExprEvaluator
: public StmtVisitor<LValueExprEvaluator, APValue> {
EvalInfo &Info;
public:
@@ -353,7 +352,7 @@ APValue LValueExprEvaluator::VisitUnaryDeref(UnaryOperator *E) {
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN PointerExprEvaluator
+class PointerExprEvaluator
: public StmtVisitor<PointerExprEvaluator, APValue> {
EvalInfo &Info;
public:
@@ -508,7 +507,7 @@ APValue PointerExprEvaluator::VisitConditionalOperator(ConditionalOperator *E) {
//===----------------------------------------------------------------------===//
namespace {
- class VISIBILITY_HIDDEN VectorExprEvaluator
+ class VectorExprEvaluator
: public StmtVisitor<VectorExprEvaluator, APValue> {
EvalInfo &Info;
APValue GetZeroVector(QualType VecType);
@@ -702,7 +701,7 @@ APValue VectorExprEvaluator::VisitUnaryImag(const UnaryOperator *E) {
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN IntExprEvaluator
+class IntExprEvaluator
: public StmtVisitor<IntExprEvaluator, bool> {
EvalInfo &Info;
APValue &Result;
@@ -776,7 +775,20 @@ public:
T1.getUnqualifiedType()),
E);
}
- bool VisitDeclRefExpr(const DeclRefExpr *E);
+
+ bool CheckReferencedDecl(const Expr *E, const Decl *D);
+ bool VisitDeclRefExpr(const DeclRefExpr *E) {
+ return CheckReferencedDecl(E, E->getDecl());
+ }
+ bool VisitMemberExpr(const MemberExpr *E) {
+ if (CheckReferencedDecl(E, E->getMemberDecl())) {
+ // Conservatively assume a MemberExpr will have side-effects
+ Info.EvalResult.HasSideEffects = true;
+ return true;
+ }
+ return false;
+ }
+
bool VisitCallExpr(const CallExpr *E);
bool VisitBinaryOperator(const BinaryOperator *E);
bool VisitUnaryOperator(const UnaryOperator *E);
@@ -834,12 +846,12 @@ static bool EvaluateInteger(const Expr* E, APSInt &Result, EvalInfo &Info) {
return true;
}
-bool IntExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) {
+bool IntExprEvaluator::CheckReferencedDecl(const Expr* E, const Decl* D) {
// Enums are integer constant exprs.
- if (const EnumConstantDecl *D = dyn_cast<EnumConstantDecl>(E->getDecl())) {
+ if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(D)) {
// FIXME: This is an ugly hack around the fact that enums don't set their
// signedness consistently; see PR3173.
- APSInt SI = D->getInitVal();
+ APSInt SI = ECD->getInitVal();
SI.setIsUnsigned(!E->getType()->isSignedIntegerType());
// FIXME: This is an ugly hack around the fact that enums don't
// set their width (!?!) consistently; see PR3173.
@@ -851,15 +863,15 @@ bool IntExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) {
// In C, they can also be folded, although they are not ICEs.
if (Info.Ctx.getCanonicalType(E->getType()).getCVRQualifiers()
== Qualifiers::Const) {
- if (const VarDecl *D = dyn_cast<VarDecl>(E->getDecl())) {
+ if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
const VarDecl *Def = 0;
- if (const Expr *Init = D->getDefinition(Def)) {
- if (APValue *V = D->getEvaluatedValue())
+ if (const Expr *Init = VD->getDefinition(Def)) {
+ if (APValue *V = VD->getEvaluatedValue())
return Success(V->getInt(), E);
if (Visit(const_cast<Expr*>(Init))) {
// Cache the evaluated value in the variable declaration.
- D->setEvaluatedValue(Info.Ctx, Result);
+ VD->setEvaluatedValue(Info.Ctx, Result);
return true;
}
@@ -1244,6 +1256,13 @@ bool IntExprEvaluator::VisitConditionalOperator(const ConditionalOperator *E) {
}
unsigned IntExprEvaluator::GetAlignOfType(QualType T) {
+ // C++ [expr.sizeof]p2: "When applied to a reference or a reference type,
+ // the result is the size of the referenced type."
+ // C++ [expr.alignof]p3: "When alignof is applied to a reference type, the
+ // result shall be the alignment of the referenced type."
+ if (const ReferenceType *Ref = T->getAs<ReferenceType>())
+ T = Ref->getPointeeType();
+
// Get information about the alignment.
unsigned CharSize = Info.Ctx.Target.getCharWidth();
@@ -1257,10 +1276,11 @@ unsigned IntExprEvaluator::GetAlignOfExpr(const Expr *E) {
// alignof decl is always accepted, even if it doesn't make sense: we default
// to 1 in those cases.
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
- return Info.Ctx.getDeclAlignInBytes(DRE->getDecl());
+ return Info.Ctx.getDeclAlignInBytes(DRE->getDecl(), /*RefAsPointee*/true);
if (const MemberExpr *ME = dyn_cast<MemberExpr>(E))
- return Info.Ctx.getDeclAlignInBytes(ME->getMemberDecl());
+ return Info.Ctx.getDeclAlignInBytes(ME->getMemberDecl(),
+ /*RefAsPointee*/true);
return GetAlignOfType(E->getType());
}
@@ -1280,6 +1300,12 @@ bool IntExprEvaluator::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E) {
}
QualType SrcTy = E->getTypeOfArgument();
+ // C++ [expr.sizeof]p2: "When applied to a reference or a reference type,
+ // the result is the size of the referenced type."
+ // C++ [expr.alignof]p3: "When alignof is applied to a reference type, the
+ // result shall be the alignment of the referenced type."
+ if (const ReferenceType *Ref = SrcTy->getAs<ReferenceType>())
+ SrcTy = Ref->getPointeeType();
// sizeof(void), __alignof__(void), sizeof(function) = 1 as a gcc
// extension.
@@ -1460,7 +1486,7 @@ bool IntExprEvaluator::VisitUnaryImag(const UnaryOperator *E) {
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN FloatExprEvaluator
+class FloatExprEvaluator
: public StmtVisitor<FloatExprEvaluator, bool> {
EvalInfo &Info;
APFloat &Result;
@@ -1652,7 +1678,7 @@ bool FloatExprEvaluator::VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *E) {
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN ComplexExprEvaluator
+class ComplexExprEvaluator
: public StmtVisitor<ComplexExprEvaluator, APValue> {
EvalInfo &Info;
diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp
index b9cfcfec74f0..326a1dcd270a 100644
--- a/lib/AST/RecordLayoutBuilder.cpp
+++ b/lib/AST/RecordLayoutBuilder.cpp
@@ -14,7 +14,6 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
-#include "clang/AST/RecordLayout.h"
#include "clang/Basic/TargetInfo.h"
#include <llvm/ADT/SmallSet.h>
#include <llvm/Support/MathExtras.h>
@@ -22,9 +21,9 @@
using namespace clang;
ASTRecordLayoutBuilder::ASTRecordLayoutBuilder(ASTContext &Ctx)
- : Ctx(Ctx), Size(0), Alignment(8), Packed(false), MaxFieldAlignment(0),
- DataSize(0), IsUnion(false), NonVirtualSize(0), NonVirtualAlignment(8),
- PrimaryBase(0), PrimaryBaseWasVirtual(false) {}
+ : Ctx(Ctx), Size(0), Alignment(8), Packed(false), UnfilledBitsInLastByte(0),
+ MaxFieldAlignment(0), DataSize(0), IsUnion(false), NonVirtualSize(0),
+ NonVirtualAlignment(8) { }
/// LayoutVtable - Lay out the vtable and set PrimaryBase.
void ASTRecordLayoutBuilder::LayoutVtable(const CXXRecordDecl *RD) {
@@ -34,7 +33,7 @@ void ASTRecordLayoutBuilder::LayoutVtable(const CXXRecordDecl *RD) {
}
SelectPrimaryBase(RD);
- if (PrimaryBase == 0) {
+ if (!PrimaryBase.getBase()) {
int AS = 0;
UpdateAlignment(Ctx.Target.getPointerAlign(AS));
Size += Ctx.Target.getPointerWidth(AS);
@@ -52,7 +51,7 @@ ASTRecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) {
const CXXRecordDecl *Base =
cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
// Skip the PrimaryBase here, as it is laid down first.
- if (Base != PrimaryBase || PrimaryBaseWasVirtual)
+ if (Base != PrimaryBase.getBase() || PrimaryBase.isVirtual())
LayoutBaseNonVirtually(Base, false);
}
}
@@ -74,12 +73,13 @@ bool ASTRecordLayoutBuilder::IsNearlyEmpty(const CXXRecordDecl *RD) const {
}
void ASTRecordLayoutBuilder::IdentifyPrimaryBases(const CXXRecordDecl *RD) {
- const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(RD);
+ const ASTRecordLayout::PrimaryBaseInfo &BaseInfo =
+ Ctx.getASTRecordLayout(RD).getPrimaryBaseInfo();
// If the record has a primary base class that is virtual, add it to the set
// of primary bases.
- if (Layout.getPrimaryBaseWasVirtual())
- IndirectPrimaryBases.insert(Layout.getPrimaryBase());
+ if (BaseInfo.isVirtual())
+ IndirectPrimaryBases.insert(BaseInfo.getBase());
// Now traverse all bases and find primary bases for them.
for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
@@ -107,7 +107,7 @@ ASTRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD,
cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
if (!i->isVirtual()) {
SelectPrimaryVBase(Base, FirstPrimary);
- if (PrimaryBase)
+ if (PrimaryBase.getBase())
return;
continue;
}
@@ -115,7 +115,7 @@ ASTRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD,
if (FirstPrimary==0)
FirstPrimary = Base;
if (!IndirectPrimaryBases.count(Base)) {
- setPrimaryBase(Base, true);
+ setPrimaryBase(Base, /*IsVirtual=*/true);
return;
}
}
@@ -141,14 +141,17 @@ void ASTRecordLayoutBuilder::SelectPrimaryBase(const CXXRecordDecl *RD) {
// base class, if one exists.
for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
e = RD->bases_end(); i != e; ++i) {
- if (!i->isVirtual()) {
- const CXXRecordDecl *Base =
- cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
- if (Base->isDynamicClass()) {
- // We found it.
- setPrimaryBase(Base, false);
- return;
- }
+ // Ignore virtual bases.
+ if (i->isVirtual())
+ continue;
+
+ const CXXRecordDecl *Base =
+ cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
+
+ if (Base->isDynamicClass()) {
+ // We found it.
+ PrimaryBase = ASTRecordLayout::PrimaryBaseInfo(Base, /*IsVirtual=*/false);
+ return;
}
}
@@ -166,8 +169,8 @@ void ASTRecordLayoutBuilder::SelectPrimaryBase(const CXXRecordDecl *RD) {
// Otherwise if is the first nearly empty virtual base, if one exists,
// otherwise there is no primary base class.
- if (!PrimaryBase)
- setPrimaryBase(FirstPrimary, true);
+ if (!PrimaryBase.getBase())
+ setPrimaryBase(FirstPrimary, /*IsVirtual=*/true);
}
void ASTRecordLayoutBuilder::LayoutVirtualBase(const CXXRecordDecl *RD) {
@@ -232,9 +235,10 @@ void ASTRecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *Class,
}
if (Base->getNumVBases()) {
- const ASTRecordLayout &L = Ctx.getASTRecordLayout(Base);
- const CXXRecordDecl *PB = L.getPrimaryBase();
- LayoutVirtualBases(Class, Base, PB, BaseOffset, mark, IndirectPrimary);
+ const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(Base);
+ const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBaseInfo().getBase();
+ LayoutVirtualBases(Class, Base, PrimaryBase, BaseOffset, mark,
+ IndirectPrimary);
}
}
}
@@ -448,17 +452,17 @@ void ASTRecordLayoutBuilder::Layout(const RecordDecl *D) {
MaxFieldAlignment = PPA->getAlignment();
if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
- UpdateAlignment(AA->getAlignment());
+ UpdateAlignment(AA->getMaxAlignment());
// If this is a C++ class, lay out the vtable and the non-virtual bases.
const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D);
if (RD) {
LayoutVtable(RD);
// PrimaryBase goes first.
- if (PrimaryBase) {
- if (PrimaryBaseWasVirtual)
- IndirectPrimaryBases.insert(PrimaryBase);
- LayoutBaseNonVirtually(PrimaryBase, PrimaryBaseWasVirtual);
+ if (PrimaryBase.getBase()) {
+ if (PrimaryBase.isVirtual())
+ IndirectPrimaryBases.insert(PrimaryBase.getBase());
+ LayoutBaseNonVirtually(PrimaryBase.getBase(), PrimaryBase.isVirtual());
}
LayoutNonVirtualBases(RD);
}
@@ -470,7 +474,8 @@ void ASTRecordLayoutBuilder::Layout(const RecordDecl *D) {
if (RD) {
llvm::SmallSet<const CXXRecordDecl*, 32> mark;
- LayoutVirtualBases(RD, RD, PrimaryBase, 0, mark, IndirectPrimaryBases);
+ LayoutVirtualBases(RD, RD, PrimaryBase.getBase(),
+ 0, mark, IndirectPrimaryBases);
}
// Finally, round the size of the total struct up to the alignment of the
@@ -498,7 +503,7 @@ void ASTRecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D,
MaxFieldAlignment = PPA->getAlignment();
if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
- UpdateAlignment(AA->getAlignment());
+ UpdateAlignment(AA->getMaxAlignment());
// Layout each ivar sequentially.
llvm::SmallVector<ObjCIvarDecl*, 16> Ivars;
@@ -519,84 +524,111 @@ void ASTRecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
LayoutField(*Field);
}
+void ASTRecordLayoutBuilder::LayoutBitField(const FieldDecl *D) {
+ bool FieldPacked = Packed || D->hasAttr<PackedAttr>();
+ uint64_t FieldOffset = IsUnion ? 0 : (DataSize - UnfilledBitsInLastByte);
+ uint64_t FieldSize = D->getBitWidth()->EvaluateAsInt(Ctx).getZExtValue();
+
+ std::pair<uint64_t, unsigned> FieldInfo = Ctx.getTypeInfo(D->getType());
+ uint64_t TypeSize = FieldInfo.first;
+ unsigned FieldAlign = FieldInfo.second;
+
+ if (FieldPacked)
+ FieldAlign = 1;
+ if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
+ FieldAlign = std::max(FieldAlign, AA->getMaxAlignment());
+
+ // The maximum field alignment overrides the aligned attribute.
+ if (MaxFieldAlignment)
+ FieldAlign = std::min(FieldAlign, MaxFieldAlignment);
+
+ // Check if we need to add padding to give the field the correct
+ // alignment.
+ if (FieldSize == 0 || (FieldOffset & (FieldAlign-1)) + FieldSize > TypeSize)
+ FieldOffset = (FieldOffset + (FieldAlign-1)) & ~(FieldAlign-1);
+
+ // Padding members don't affect overall alignment
+ if (!D->getIdentifier())
+ FieldAlign = 1;
+
+ // Place this field at the current location.
+ FieldOffsets.push_back(FieldOffset);
+
+ // Update DataSize to include the last byte containing (part of) the bitfield.
+ if (IsUnion) {
+ // FIXME: I think FieldSize should be TypeSize here.
+ DataSize = std::max(DataSize, FieldSize);
+ } else {
+ uint64_t NewSizeInBits = FieldOffset + FieldSize;
+
+ DataSize = llvm::RoundUpToAlignment(NewSizeInBits, 8);
+ UnfilledBitsInLastByte = DataSize - NewSizeInBits;
+ }
+
+ // Update the size.
+ Size = std::max(Size, DataSize);
+
+ // Remember max struct/class alignment.
+ UpdateAlignment(FieldAlign);
+}
+
void ASTRecordLayoutBuilder::LayoutField(const FieldDecl *D) {
- bool FieldPacked = Packed;
+ if (D->isBitField()) {
+ LayoutBitField(D);
+ return;
+ }
+
+ // Reset the unfilled bits.
+ UnfilledBitsInLastByte = 0;
+
+ bool FieldPacked = Packed || D->hasAttr<PackedAttr>();
uint64_t FieldOffset = IsUnion ? 0 : DataSize;
uint64_t FieldSize;
unsigned FieldAlign;
-
- FieldPacked |= D->hasAttr<PackedAttr>();
-
- if (const Expr *BitWidthExpr = D->getBitWidth()) {
- // TODO: Need to check this algorithm on other targets!
- // (tested on Linux-X86)
- FieldSize = BitWidthExpr->EvaluateAsInt(Ctx).getZExtValue();
-
+
+ if (D->getType()->isIncompleteArrayType()) {
+ // This is a flexible array member; we can't directly
+ // query getTypeInfo about these, so we figure it out here.
+ // Flexible array members don't have any size, but they
+ // have to be aligned appropriately for their element type.
+ FieldSize = 0;
+ const ArrayType* ATy = Ctx.getAsArrayType(D->getType());
+ FieldAlign = Ctx.getTypeAlign(ATy->getElementType());
+ } else if (const ReferenceType *RT = D->getType()->getAs<ReferenceType>()) {
+ unsigned AS = RT->getPointeeType().getAddressSpace();
+ FieldSize = Ctx.Target.getPointerWidth(AS);
+ FieldAlign = Ctx.Target.getPointerAlign(AS);
+ } else {
std::pair<uint64_t, unsigned> FieldInfo = Ctx.getTypeInfo(D->getType());
- uint64_t TypeSize = FieldInfo.first;
-
+ FieldSize = FieldInfo.first;
FieldAlign = FieldInfo.second;
+ }
- if (FieldPacked)
- FieldAlign = 1;
- if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
- FieldAlign = std::max(FieldAlign, AA->getAlignment());
- // The maximum field alignment overrides the aligned attribute.
- if (MaxFieldAlignment)
- FieldAlign = std::min(FieldAlign, MaxFieldAlignment);
-
- // Check if we need to add padding to give the field the correct
- // alignment.
- if (FieldSize == 0 || (FieldOffset & (FieldAlign-1)) + FieldSize > TypeSize)
- FieldOffset = (FieldOffset + (FieldAlign-1)) & ~(FieldAlign-1);
-
- // Padding members don't affect overall alignment
- if (!D->getIdentifier())
- FieldAlign = 1;
- } else {
- if (D->getType()->isIncompleteArrayType()) {
- // This is a flexible array member; we can't directly
- // query getTypeInfo about these, so we figure it out here.
- // Flexible array members don't have any size, but they
- // have to be aligned appropriately for their element type.
- FieldSize = 0;
- const ArrayType* ATy = Ctx.getAsArrayType(D->getType());
- FieldAlign = Ctx.getTypeAlign(ATy->getElementType());
- } else if (const ReferenceType *RT = D->getType()->getAs<ReferenceType>()) {
- unsigned AS = RT->getPointeeType().getAddressSpace();
- FieldSize = Ctx.Target.getPointerWidth(AS);
- FieldAlign = Ctx.Target.getPointerAlign(AS);
- } else {
- std::pair<uint64_t, unsigned> FieldInfo = Ctx.getTypeInfo(D->getType());
- FieldSize = FieldInfo.first;
- FieldAlign = FieldInfo.second;
- }
+ if (FieldPacked)
+ FieldAlign = 8;
+ if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
+ FieldAlign = std::max(FieldAlign, AA->getMaxAlignment());
- if (FieldPacked)
- FieldAlign = 8;
- if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
- FieldAlign = std::max(FieldAlign, AA->getAlignment());
- // The maximum field alignment overrides the aligned attribute.
- if (MaxFieldAlignment)
- FieldAlign = std::min(FieldAlign, MaxFieldAlignment);
+ // The maximum field alignment overrides the aligned attribute.
+ if (MaxFieldAlignment)
+ FieldAlign = std::min(FieldAlign, MaxFieldAlignment);
- // Round up the current record size to the field's alignment boundary.
- FieldOffset = llvm::RoundUpToAlignment(FieldOffset, FieldAlign);
-
- if (!IsUnion) {
- while (true) {
- // Check if we can place the field at this offset.
- if (canPlaceFieldAtOffset(D, FieldOffset))
- break;
-
- // We couldn't place the field at the offset. Try again at a new offset.
- FieldOffset += FieldAlign;
- }
+ // Round up the current record size to the field's alignment boundary.
+ FieldOffset = llvm::RoundUpToAlignment(FieldOffset, FieldAlign);
+
+ if (!IsUnion) {
+ while (true) {
+ // Check if we can place the field at this offset.
+ if (canPlaceFieldAtOffset(D, FieldOffset))
+ break;
- UpdateEmptyClassOffsets(D, FieldOffset);
+ // We couldn't place the field at the offset. Try again at a new offset.
+ FieldOffset += FieldAlign;
}
+
+ UpdateEmptyClassOffsets(D, FieldOffset);
}
-
+
// Place this field at the current location.
FieldOffsets.push_back(FieldOffset);
@@ -619,7 +651,7 @@ void ASTRecordLayoutBuilder::FinishLayout() {
Size = 8;
// Finally, round the size of the record up to the alignment of the
// record itself.
- Size = (Size + (Alignment-1)) & ~(Alignment-1);
+ Size = llvm::RoundUpToAlignment(Size, Alignment);
}
void ASTRecordLayoutBuilder::UpdateAlignment(unsigned NewAlignment) {
@@ -631,6 +663,31 @@ void ASTRecordLayoutBuilder::UpdateAlignment(unsigned NewAlignment) {
Alignment = NewAlignment;
}
+static const CXXMethodDecl *GetKeyFunction(const CXXRecordDecl *RD) {
+ if (!RD->isDynamicClass())
+ return 0;
+
+ for (CXXRecordDecl::method_iterator I = RD->method_begin(),
+ E = RD->method_end(); I != E; ++I) {
+ const CXXMethodDecl *MD = *I;
+
+ if (!MD->isVirtual())
+ continue;
+
+ if (MD->isPure())
+ continue;
+
+ const FunctionDecl *fn;
+ if (MD->getBody(fn) && !fn->isOutOfLine())
+ continue;
+
+ // We found it.
+ return MD;
+ }
+
+ return 0;
+}
+
const ASTRecordLayout *
ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx,
const RecordDecl *D) {
@@ -654,17 +711,19 @@ ASTRecordLayoutBuilder::ComputeLayout(ASTContext &Ctx,
uint64_t NonVirtualSize =
IsPODForThePurposeOfLayout ? DataSize : Builder.NonVirtualSize;
+ const CXXMethodDecl *KeyFunction = GetKeyFunction(cast<CXXRecordDecl>(D));
+
return new ASTRecordLayout(Builder.Size, Builder.Alignment, DataSize,
Builder.FieldOffsets.data(),
Builder.FieldOffsets.size(),
NonVirtualSize,
Builder.NonVirtualAlignment,
Builder.PrimaryBase,
- Builder.PrimaryBaseWasVirtual,
Builder.Bases.data(),
Builder.Bases.size(),
Builder.VBases.data(),
- Builder.VBases.size());
+ Builder.VBases.size(),
+ KeyFunction);
}
const ASTRecordLayout *
diff --git a/lib/AST/RecordLayoutBuilder.h b/lib/AST/RecordLayoutBuilder.h
index 077072343b1b..69e0498917c7 100644
--- a/lib/AST/RecordLayoutBuilder.h
+++ b/lib/AST/RecordLayoutBuilder.h
@@ -10,6 +10,7 @@
#ifndef LLVM_CLANG_AST_RECORDLAYOUTBUILDER_H
#define LLVM_CLANG_AST_RECORDLAYOUTBUILDER_H
+#include "clang/AST/RecordLayout.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/System/DataTypes.h"
@@ -27,12 +28,21 @@ namespace clang {
class ASTRecordLayoutBuilder {
ASTContext &Ctx;
+ /// Size - The current size of the record layout.
uint64_t Size;
+
+ /// Alignment - The current alignment of the record layout.
unsigned Alignment;
+
llvm::SmallVector<uint64_t, 16> FieldOffsets;
/// Packed - Whether the record is packed or not.
bool Packed;
+
+ /// UnfilledBitsInLastByte - If the last field laid out was a bitfield,
+ /// this contains the number of bits in the last byte that can be used for
+ /// an adjacent bitfield if necessary.
+ unsigned char UnfilledBitsInLastByte;
/// MaxFieldAlignment - The maximum allowed field alignment. This is set by
/// #pragma pack.
@@ -45,8 +55,8 @@ class ASTRecordLayoutBuilder {
uint64_t NonVirtualSize;
unsigned NonVirtualAlignment;
- const CXXRecordDecl *PrimaryBase;
- bool PrimaryBaseWasVirtual;
+
+ ASTRecordLayout::PrimaryBaseInfo PrimaryBase;
typedef llvm::SmallVector<std::pair<const CXXRecordDecl *,
uint64_t>, 4> BaseOffsetsTy;
@@ -74,6 +84,7 @@ class ASTRecordLayoutBuilder {
void LayoutFields(const RecordDecl *D);
void LayoutField(const FieldDecl *D);
+ void LayoutBitField(const FieldDecl *D);
void SelectPrimaryBase(const CXXRecordDecl *RD);
void SelectPrimaryVBase(const CXXRecordDecl *RD,
@@ -84,9 +95,8 @@ class ASTRecordLayoutBuilder {
/// base class.
void IdentifyPrimaryBases(const CXXRecordDecl *RD);
- void setPrimaryBase(const CXXRecordDecl *PB, bool Virtual) {
- PrimaryBase = PB;
- PrimaryBaseWasVirtual = Virtual;
+ void setPrimaryBase(const CXXRecordDecl *Base, bool IsVirtual) {
+ PrimaryBase = ASTRecordLayout::PrimaryBaseInfo(Base, IsVirtual);
}
bool IsNearlyEmpty(const CXXRecordDecl *RD) const;
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index 6e0da4714912..fad80ec0cf23 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -88,8 +88,8 @@ void Stmt::addStmtClass(StmtClass s) {
static bool StatSwitch = false;
-bool Stmt::CollectingStats(bool enable) {
- if (enable) StatSwitch = true;
+bool Stmt::CollectingStats(bool Enable) {
+ if (Enable) StatSwitch = true;
return StatSwitch;
}
@@ -559,7 +559,7 @@ Stmt::child_iterator CXXCatchStmt::child_end() {
return &HandlerBlock + 1;
}
-QualType CXXCatchStmt::getCaughtType() {
+QualType CXXCatchStmt::getCaughtType() const {
if (ExceptionDecl)
return ExceptionDecl->getType();
return QualType();
diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp
index 93bf8755d580..bbe6a7120141 100644
--- a/lib/AST/StmtDumper.cpp
+++ b/lib/AST/StmtDumper.cpp
@@ -17,7 +17,6 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/PrettyPrinter.h"
#include "clang/Basic/SourceManager.h"
-#include "llvm/Support/Compiler.h"
#include <cstdio>
using namespace clang;
@@ -26,7 +25,7 @@ using namespace clang;
//===----------------------------------------------------------------------===//
namespace {
- class VISIBILITY_HIDDEN StmtDumper : public StmtVisitor<StmtDumper> {
+ class StmtDumper : public StmtVisitor<StmtDumper> {
SourceManager *SM;
FILE *F;
unsigned IndentLevel;
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 4bd7f964be6c..205ea0d182d4 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -16,7 +16,6 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/PrettyPrinter.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/Support/Format.h"
using namespace clang;
@@ -25,7 +24,7 @@ using namespace clang;
//===----------------------------------------------------------------------===//
namespace {
- class VISIBILITY_HIDDEN StmtPrinter : public StmtVisitor<StmtPrinter> {
+ class StmtPrinter : public StmtVisitor<StmtPrinter> {
llvm::raw_ostream &OS;
ASTContext &Context;
unsigned IndentLevel;
@@ -483,19 +482,26 @@ void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) {
Policy);
}
-void StmtPrinter::VisitUnresolvedDeclRefExpr(UnresolvedDeclRefExpr *Node) {
+void StmtPrinter::VisitDependentScopeDeclRefExpr(
+ DependentScopeDeclRefExpr *Node) {
Node->getQualifier()->print(OS, Policy);
OS << Node->getDeclName().getAsString();
+ if (Node->hasExplicitTemplateArgs())
+ OS << TemplateSpecializationType::PrintTemplateArgumentList(
+ Node->getTemplateArgs(),
+ Node->getNumTemplateArgs(),
+ Policy);
}
-void StmtPrinter::VisitTemplateIdRefExpr(TemplateIdRefExpr *Node) {
+void StmtPrinter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node) {
if (Node->getQualifier())
Node->getQualifier()->print(OS, Policy);
- Node->getTemplateName().print(OS, Policy, true);
- OS << TemplateSpecializationType::PrintTemplateArgumentList(
- Node->getTemplateArgs(),
+ OS << Node->getName().getAsString();
+ if (Node->hasExplicitTemplateArgs())
+ OS << TemplateSpecializationType::PrintTemplateArgumentList(
+ Node->getTemplateArgs(),
Node->getNumTemplateArgs(),
- Policy);
+ Policy);
}
void StmtPrinter::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) {
@@ -1048,11 +1054,6 @@ void StmtPrinter::VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *Node) {
OS << Node->getType().getAsString() << "()";
}
-void
-StmtPrinter::VisitCXXConditionDeclExpr(CXXConditionDeclExpr *E) {
- PrintRawDecl(E->getVarDecl());
-}
-
void StmtPrinter::VisitCXXNewExpr(CXXNewExpr *E) {
if (E->isGlobalNew())
OS << "::";
@@ -1118,10 +1119,6 @@ void StmtPrinter::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) {
OS << TypeS;
}
-void StmtPrinter::VisitUnresolvedFunctionNameExpr(UnresolvedFunctionNameExpr *E) {
- OS << E->getName().getAsString();
-}
-
void StmtPrinter::VisitCXXConstructExpr(CXXConstructExpr *E) {
// Nothing to print.
}
@@ -1146,7 +1143,8 @@ StmtPrinter::VisitCXXUnresolvedConstructExpr(
OS << ")";
}
-void StmtPrinter::VisitCXXUnresolvedMemberExpr(CXXUnresolvedMemberExpr *Node) {
+void StmtPrinter::VisitCXXDependentScopeMemberExpr(
+ CXXDependentScopeMemberExpr *Node) {
PrintExpr(Node->getBase());
OS << (Node->isArrow() ? "->" : ".");
if (NestedNameSpecifier *Qualifier = Node->getQualifier())
@@ -1165,6 +1163,24 @@ void StmtPrinter::VisitCXXUnresolvedMemberExpr(CXXUnresolvedMemberExpr *Node) {
}
}
+void StmtPrinter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *Node) {
+ PrintExpr(Node->getBase());
+ OS << (Node->isArrow() ? "->" : ".");
+ if (NestedNameSpecifier *Qualifier = Node->getQualifier())
+ Qualifier->print(OS, Policy);
+
+ // FIXME: this might originally have been written with 'template'
+
+ OS << Node->getMemberName().getAsString();
+
+ if (Node->hasExplicitTemplateArgs()) {
+ OS << TemplateSpecializationType::PrintTemplateArgumentList(
+ Node->getTemplateArgs(),
+ Node->getNumTemplateArgs(),
+ Policy);
+ }
+}
+
static const char *getTypeTraitName(UnaryTypeTrait UTT) {
switch (UTT) {
default: assert(false && "Unknown type trait");
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index 4458c2b9cd25..d832a4649e75 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -20,11 +20,10 @@
#include "clang/AST/ExprObjC.h"
#include "clang/AST/StmtVisitor.h"
#include "llvm/ADT/FoldingSet.h"
-#include "llvm/Support/Compiler.h"
using namespace clang;
namespace {
- class VISIBILITY_HIDDEN StmtProfiler : public StmtVisitor<StmtProfiler> {
+ class StmtProfiler : public StmtVisitor<StmtProfiler> {
llvm::FoldingSetNodeID &ID;
ASTContext &Context;
bool Canonical;
@@ -108,14 +107,17 @@ void StmtProfiler::VisitLabelStmt(LabelStmt *S) {
void StmtProfiler::VisitIfStmt(IfStmt *S) {
VisitStmt(S);
+ VisitDecl(S->getConditionVariable());
}
void StmtProfiler::VisitSwitchStmt(SwitchStmt *S) {
VisitStmt(S);
+ VisitDecl(S->getConditionVariable());
}
void StmtProfiler::VisitWhileStmt(WhileStmt *S) {
VisitStmt(S);
+ VisitDecl(S->getConditionVariable());
}
void StmtProfiler::VisitDoStmt(DoStmt *S) {
@@ -481,10 +483,6 @@ void StmtProfiler::VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *S) {
VisitExpr(S);
}
-void StmtProfiler::VisitCXXConditionDeclExpr(CXXConditionDeclExpr *S) {
- VisitDeclRefExpr(S);
-}
-
void StmtProfiler::VisitCXXDeleteExpr(CXXDeleteExpr *S) {
VisitExpr(S);
ID.AddBoolean(S->isGlobalDelete());
@@ -515,9 +513,13 @@ void StmtProfiler::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *S) {
}
void
-StmtProfiler::VisitUnresolvedFunctionNameExpr(UnresolvedFunctionNameExpr *S) {
+StmtProfiler::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *S) {
VisitExpr(S);
+ VisitNestedNameSpecifier(S->getQualifier());
VisitName(S->getName());
+ ID.AddBoolean(S->hasExplicitTemplateArgs());
+ if (S->hasExplicitTemplateArgs())
+ VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs());
}
void StmtProfiler::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *S) {
@@ -526,18 +528,14 @@ void StmtProfiler::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *S) {
VisitType(S->getQueriedType());
}
-void StmtProfiler::VisitUnresolvedDeclRefExpr(UnresolvedDeclRefExpr *S) {
+void
+StmtProfiler::VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *S) {
VisitExpr(S);
VisitName(S->getDeclName());
VisitNestedNameSpecifier(S->getQualifier());
- ID.AddBoolean(S->isAddressOfOperand());
-}
-
-void StmtProfiler::VisitTemplateIdRefExpr(TemplateIdRefExpr *S) {
- VisitExpr(S);
- VisitNestedNameSpecifier(S->getQualifier());
- VisitTemplateName(S->getTemplateName());
- VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs());
+ ID.AddBoolean(S->hasExplicitTemplateArgs());
+ if (S->hasExplicitTemplateArgs())
+ VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs());
}
void StmtProfiler::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *S) {
@@ -554,11 +552,25 @@ StmtProfiler::VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *S) {
VisitType(S->getTypeAsWritten());
}
-void StmtProfiler::VisitCXXUnresolvedMemberExpr(CXXUnresolvedMemberExpr *S) {
+void
+StmtProfiler::VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *S) {
VisitExpr(S);
ID.AddBoolean(S->isArrow());
VisitNestedNameSpecifier(S->getQualifier());
VisitName(S->getMember());
+ ID.AddBoolean(S->hasExplicitTemplateArgumentList());
+ if (S->hasExplicitTemplateArgumentList())
+ VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs());
+}
+
+void StmtProfiler::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *S) {
+ VisitExpr(S);
+ ID.AddBoolean(S->isArrow());
+ VisitNestedNameSpecifier(S->getQualifier());
+ VisitName(S->getMemberName());
+ ID.AddBoolean(S->hasExplicitTemplateArgs());
+ if (S->hasExplicitTemplateArgs())
+ VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs());
}
void StmtProfiler::VisitObjCStringLiteral(ObjCStringLiteral *S) {
diff --git a/lib/AST/StmtViz.cpp b/lib/AST/StmtViz.cpp
index 61fd750ccc83..8be287e7cb21 100644
--- a/lib/AST/StmtViz.cpp
+++ b/lib/AST/StmtViz.cpp
@@ -30,8 +30,9 @@ void Stmt::viewAST() const {
namespace llvm {
template<>
struct DOTGraphTraits<const Stmt*> : public DefaultDOTGraphTraits {
- static std::string getNodeLabel(const Stmt* Node, const Stmt* Graph,
- bool ShortNames) {
+ DOTGraphTraits (bool isSimple=false) : DefaultDOTGraphTraits(isSimple) {}
+
+ static std::string getNodeLabel(const Stmt* Node, const Stmt* Graph) {
#ifndef NDEBUG
std::string OutSStr;
diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp
index ff02f9a31cb2..f341b45fb971 100644
--- a/lib/AST/TemplateBase.cpp
+++ b/lib/AST/TemplateBase.cpp
@@ -15,6 +15,7 @@
#include "llvm/ADT/FoldingSet.h"
#include "clang/AST/TemplateBase.h"
#include "clang/AST/DeclBase.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/TypeLoc.h"
@@ -59,8 +60,17 @@ void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID,
break;
case Template:
- ID.AddPointer(Context.getCanonicalTemplateName(getAsTemplate())
- .getAsVoidPointer());
+ if (TemplateTemplateParmDecl *TTP
+ = dyn_cast_or_null<TemplateTemplateParmDecl>(
+ getAsTemplate().getAsTemplateDecl())) {
+ ID.AddBoolean(true);
+ ID.AddInteger(TTP->getDepth());
+ ID.AddInteger(TTP->getPosition());
+ } else {
+ ID.AddBoolean(false);
+ ID.AddPointer(Context.getCanonicalTemplateName(getAsTemplate())
+ .getAsVoidPointer());
+ }
break;
case Integral:
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 297534eaf1fc..5a2434da3c37 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -725,6 +725,7 @@ const char *BuiltinType::getName(const LangOptions &LO) const {
case UndeducedAuto: return "auto";
case ObjCId: return "id";
case ObjCClass: return "Class";
+ case ObjCSel: return "SEL";
}
}
@@ -866,6 +867,11 @@ static bool isDependent(const TemplateArgument &Arg) {
}
bool TemplateSpecializationType::
+anyDependentTemplateArguments(const TemplateArgumentListInfo &Args) {
+ return anyDependentTemplateArguments(Args.getArgumentArray(), Args.size());
+}
+
+bool TemplateSpecializationType::
anyDependentTemplateArguments(const TemplateArgumentLoc *Args, unsigned N) {
for (unsigned i = 0; i != N; ++i)
if (isDependent(Args[i].getArgument()))
diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp
index a48233378286..562e830b367e 100644
--- a/lib/AST/TypePrinter.cpp
+++ b/lib/AST/TypePrinter.cpp
@@ -535,6 +535,8 @@ void TypePrinter::PrintObjCObjectPointer(const ObjCObjectPointerType *T,
ObjCQIString = "id";
else if (T->isObjCClassType() || T->isObjCQualifiedClassType())
ObjCQIString = "Class";
+ else if (T->isObjCSelType())
+ ObjCQIString = "SEL";
else
ObjCQIString = T->getInterfaceDecl()->getNameAsString();
@@ -599,6 +601,14 @@ static void PrintTemplateArgument(std::string &Buffer,
}
}
+std::string TemplateSpecializationType::
+ PrintTemplateArgumentList(const TemplateArgumentListInfo &Args,
+ const PrintingPolicy &Policy) {
+ return PrintTemplateArgumentList(Args.getArgumentArray(),
+ Args.size(),
+ Policy);
+}
+
std::string
TemplateSpecializationType::PrintTemplateArgumentList(
const TemplateArgument *Args,
diff --git a/lib/Analysis/AnalysisContext.cpp b/lib/Analysis/AnalysisContext.cpp
index 640912ad6b39..339e2c93cea9 100644
--- a/lib/Analysis/AnalysisContext.cpp
+++ b/lib/Analysis/AnalysisContext.cpp
@@ -18,21 +18,12 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/ParentMap.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/Analysis/Support/BumpVector.h"
#include "llvm/Support/ErrorHandling.h"
using namespace clang;
-AnalysisContext::~AnalysisContext() {
- delete cfg;
- delete liveness;
- delete PM;
-}
-
-AnalysisContextManager::~AnalysisContextManager() {
- for (ContextMap::iterator I = Contexts.begin(), E = Contexts.end(); I!=E; ++I)
- delete I->second;
-}
-
void AnalysisContextManager::clear() {
for (ContextMap::iterator I = Contexts.begin(), E = Contexts.end(); I!=E; ++I)
delete I->second;
@@ -73,7 +64,7 @@ LiveVariables *AnalysisContext::getLiveVariables() {
if (!c)
return 0;
- liveness = new LiveVariables(D->getASTContext(), *c);
+ liveness = new LiveVariables(*this);
liveness->runOnCFG(*c);
liveness->runOnAllBlocks(*c, 0, true);
}
@@ -157,3 +148,75 @@ ScopeContext *LocationContextManager::getScope(AnalysisContext *ctx,
}
return scope;
}
+
+//===----------------------------------------------------------------------===//
+// Lazily generated map to query the external variables referenced by a Block.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class FindBlockDeclRefExprsVals : public StmtVisitor<FindBlockDeclRefExprsVals>{
+ BumpVector<const VarDecl*> &BEVals;
+ BumpVectorContext &BC;
+public:
+ FindBlockDeclRefExprsVals(BumpVector<const VarDecl*> &bevals,
+ BumpVectorContext &bc)
+ : BEVals(bevals), BC(bc) {}
+
+ void VisitStmt(Stmt *S) {
+ for (Stmt::child_iterator I = S->child_begin(), E = S->child_end();I!=E;++I)
+ if (Stmt *child = *I)
+ Visit(child);
+ }
+
+ void VisitBlockDeclRefExpr(BlockDeclRefExpr *DR) {
+ if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()))
+ BEVals.push_back(VD, BC);
+ }
+};
+} // end anonymous namespace
+
+typedef BumpVector<const VarDecl*> DeclVec;
+
+static DeclVec* LazyInitializeReferencedDecls(const BlockDecl *BD,
+ void *&Vec,
+ llvm::BumpPtrAllocator &A) {
+ if (Vec)
+ return (DeclVec*) Vec;
+
+ BumpVectorContext BC(A);
+ DeclVec *BV = (DeclVec*) A.Allocate<DeclVec>();
+ new (BV) DeclVec(BC, 10);
+
+ // Find the referenced variables.
+ FindBlockDeclRefExprsVals F(*BV, BC);
+ F.Visit(BD->getBody());
+
+ Vec = BV;
+ return BV;
+}
+
+std::pair<AnalysisContext::referenced_decls_iterator,
+ AnalysisContext::referenced_decls_iterator>
+AnalysisContext::getReferencedBlockVars(const BlockDecl *BD) {
+ if (!ReferencedBlockVars)
+ ReferencedBlockVars = new llvm::DenseMap<const BlockDecl*,void*>();
+
+ DeclVec *V = LazyInitializeReferencedDecls(BD, (*ReferencedBlockVars)[BD], A);
+ return std::make_pair(V->begin(), V->end());
+}
+
+//===----------------------------------------------------------------------===//
+// Cleanup.
+//===----------------------------------------------------------------------===//
+
+AnalysisContext::~AnalysisContext() {
+ delete cfg;
+ delete liveness;
+ delete PM;
+ delete ReferencedBlockVars;
+}
+
+AnalysisContextManager::~AnalysisContextManager() {
+ for (ContextMap::iterator I = Contexts.begin(), E = Contexts.end(); I!=E; ++I)
+ delete I->second;
+}
diff --git a/lib/Analysis/ArrayBoundChecker.cpp b/lib/Analysis/ArrayBoundChecker.cpp
index 549a22bec172..3d95ab183471 100644
--- a/lib/Analysis/ArrayBoundChecker.cpp
+++ b/lib/Analysis/ArrayBoundChecker.cpp
@@ -20,7 +20,7 @@
using namespace clang;
namespace {
-class VISIBILITY_HIDDEN ArrayBoundChecker :
+class ArrayBoundChecker :
public CheckerVisitor<ArrayBoundChecker> {
BuiltinBug *BT;
public:
@@ -62,8 +62,7 @@ void ArrayBoundChecker::VisitLocation(CheckerContext &C, const Stmt *S, SVal l){
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);
-
+ ExplodedNode *N = C.GenerateSink(StOutBound);
if (!N)
return;
@@ -80,7 +79,12 @@ void ArrayBoundChecker::VisitLocation(CheckerContext &C, const Stmt *S, SVal l){
new RangedBugReport(*BT, BT->getDescription(), N);
report->addRange(S->getSourceRange());
-
C.EmitReport(report);
+ return;
}
+
+ // Array bound check succeeded. From this point forward the array bound
+ // should always succeed.
+ assert(StInBound);
+ C.addTransition(StInBound);
}
diff --git a/lib/Analysis/AttrNonNullChecker.cpp b/lib/Analysis/AttrNonNullChecker.cpp
index 01e1a1fcf69b..aa21700c2483 100644
--- a/lib/Analysis/AttrNonNullChecker.cpp
+++ b/lib/Analysis/AttrNonNullChecker.cpp
@@ -19,7 +19,7 @@
using namespace clang;
namespace {
-class VISIBILITY_HIDDEN AttrNonNullChecker
+class AttrNonNullChecker
: public CheckerVisitor<AttrNonNullChecker> {
BugType *BT;
public:
@@ -39,7 +39,6 @@ void clang::RegisterAttrNonNullChecker(GRExprEngine &Eng) {
void AttrNonNullChecker::PreVisitCallExpr(CheckerContext &C,
const CallExpr *CE) {
const GRState *state = C.getState();
- const GRState *originalState = state;
// Check if the callee has a 'nonnull' attribute.
SVal X = state->getSVal(CE->getCallee());
@@ -74,7 +73,7 @@ void AttrNonNullChecker::PreVisitCallExpr(CheckerContext &C,
if (stateNull && !stateNotNull) {
// Generate an error node. Check for a null node in case
// we cache out.
- if (ExplodedNode *errorNode = C.GenerateNode(CE, stateNull, true)) {
+ if (ExplodedNode *errorNode = C.GenerateSink(stateNull)) {
// Lazily allocate the BugType object if it hasn't already been
// created. Ownership is transferred to the BugReporter object once
@@ -109,6 +108,5 @@ void AttrNonNullChecker::PreVisitCallExpr(CheckerContext &C,
// If we reach here all of the arguments passed the nonnull check.
// If 'state' has been updated generated a new node.
- if (state != originalState)
- C.addTransition(C.GenerateNode(CE, state));
+ C.addTransition(state);
}
diff --git a/lib/Analysis/BadCallChecker.cpp b/lib/Analysis/BadCallChecker.cpp
deleted file mode 100644
index 7a7ea188ba59..000000000000
--- a/lib/Analysis/BadCallChecker.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-//===--- BadCallChecker.h - Bad call 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 BadCallChecker, a builtin check in GRExprEngine that performs
-// checks for bad callee at call sites.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
-#include "GRExprEngineInternalChecks.h"
-
-using namespace clang;
-
-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) {
- const Expr *Callee = CE->getCallee()->IgnoreParens();
- SVal L = C.getState()->getSVal(Callee);
-
- if (L.isUndef() || isa<loc::ConcreteInt>(L)) {
- if (ExplodedNode *N = C.GenerateNode(CE, true)) {
- if (!BT)
- BT = new BuiltinBug("Invalid function call",
- "Called function pointer is a null or undefined pointer value");
-
- EnhancedBugReport *R =
- new EnhancedBugReport(*BT, BT->getDescription(), N);
-
- R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
- bugreporter::GetCalleeExpr(N));
-
- C.EmitReport(R);
- }
- }
-}
diff --git a/lib/Analysis/BasicConstraintManager.cpp b/lib/Analysis/BasicConstraintManager.cpp
index d0b828952854..6c3f7b2245df 100644
--- a/lib/Analysis/BasicConstraintManager.cpp
+++ b/lib/Analysis/BasicConstraintManager.cpp
@@ -16,14 +16,13 @@
#include "clang/Analysis/PathSensitive/GRState.h"
#include "clang/Analysis/PathSensitive/GRStateTrait.h"
#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
-namespace { class VISIBILITY_HIDDEN ConstNotEq {}; }
-namespace { class VISIBILITY_HIDDEN ConstEq {}; }
+namespace { class ConstNotEq {}; }
+namespace { class ConstEq {}; }
typedef llvm::ImmutableMap<SymbolRef,GRState::IntSetTy> ConstNotEqTy;
typedef llvm::ImmutableMap<SymbolRef,const llvm::APSInt*> ConstEqTy;
@@ -46,7 +45,7 @@ struct GRStateTrait<ConstEq> : public GRStatePartialTrait<ConstEqTy> {
namespace {
// BasicConstraintManager only tracks equality and inequality constraints of
// constants and integer variables.
-class VISIBILITY_HIDDEN BasicConstraintManager
+class BasicConstraintManager
: public SimpleConstraintManager {
GRState::IntSetTy::Factory ISetFactory;
public:
diff --git a/lib/Analysis/BasicObjCFoundationChecks.cpp b/lib/Analysis/BasicObjCFoundationChecks.cpp
index c2ecfa1f417f..c91377986496 100644
--- a/lib/Analysis/BasicObjCFoundationChecks.cpp
+++ b/lib/Analysis/BasicObjCFoundationChecks.cpp
@@ -22,12 +22,12 @@
#include "clang/Analysis/PathSensitive/BugReporter.h"
#include "clang/Analysis/PathSensitive/MemRegion.h"
#include "clang/Analysis/PathDiagnostic.h"
+#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
#include "clang/Analysis/LocalCheckers.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/ASTContext.h"
-#include "llvm/Support/Compiler.h"
using namespace clang;
@@ -52,12 +52,12 @@ static const char* GetReceiverNameType(const ObjCMessageExpr* ME) {
namespace {
-class VISIBILITY_HIDDEN APIMisuse : public BugType {
+class APIMisuse : public BugType {
public:
APIMisuse(const char* name) : BugType(name, "API Misuse (Apple)") {}
};
-class VISIBILITY_HIDDEN BasicObjCFoundationChecks : public GRSimpleAPICheck {
+class BasicObjCFoundationChecks : public GRSimpleAPICheck {
APIMisuse *BT;
BugReporter& BR;
ASTContext &Ctx;
@@ -87,7 +87,7 @@ private:
// by the BugReporter object 'BR' once we call BR.EmitWarning.
if (!BT) BT = new APIMisuse("nil argument");
- RangedBugReport *R = new RangedBugReport(*BT, os.str().c_str(), N);
+ RangedBugReport *R = new RangedBugReport(*BT, os.str(), N);
R->addRange(ME->getArg(Arg)->getSourceRange());
BR.EmitReport(R);
}
@@ -228,7 +228,7 @@ bool BasicObjCFoundationChecks::AuditNSString(ExplodedNode* N,
namespace {
-class VISIBILITY_HIDDEN AuditCFNumberCreate : public GRSimpleAPICheck {
+class AuditCFNumberCreate : public GRSimpleAPICheck {
APIMisuse* BT;
// FIXME: Either this should be refactored into GRSimpleAPICheck, or
@@ -435,7 +435,7 @@ void AuditCFNumberCreate::AddError(const TypedRegion* R, const Expr* Ex,
// Lazily create the BugType object. This will be owned
// by the BugReporter object 'BR' once we call BR.EmitWarning.
if (!BT) BT = new APIMisuse("Bad use of CFNumberCreate");
- RangedBugReport *report = new RangedBugReport(*BT, os.str().c_str(), N);
+ RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
report->addRange(Ex->getSourceRange());
BR.EmitReport(report);
}
@@ -450,7 +450,7 @@ clang::CreateAuditCFNumberCreate(ASTContext& Ctx, BugReporter& BR) {
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN AuditCFRetainRelease : public GRSimpleAPICheck {
+class AuditCFRetainRelease : public GRSimpleAPICheck {
APIMisuse *BT;
// FIXME: Either this should be refactored into GRSimpleAPICheck, or
@@ -522,6 +522,64 @@ clang::CreateAuditCFRetainRelease(ASTContext& Ctx, BugReporter& BR) {
}
//===----------------------------------------------------------------------===//
+// Check for sending 'retain', 'release', or 'autorelease' directly to a Class.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class ClassReleaseChecker :
+ public CheckerVisitor<ClassReleaseChecker> {
+ Selector releaseS;
+ Selector retainS;
+ Selector autoreleaseS;
+ Selector drainS;
+ BugType *BT;
+public:
+ ClassReleaseChecker(ASTContext &Ctx)
+ : releaseS(GetNullarySelector("release", Ctx)),
+ retainS(GetNullarySelector("retain", Ctx)),
+ autoreleaseS(GetNullarySelector("autorelease", Ctx)),
+ drainS(GetNullarySelector("drain", Ctx)),
+ BT(0) {}
+
+ static void *getTag() { static int x = 0; return &x; }
+
+ void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME);
+};
+}
+
+void ClassReleaseChecker::PreVisitObjCMessageExpr(CheckerContext &C,
+ const ObjCMessageExpr *ME) {
+
+ const IdentifierInfo *ClsName = ME->getClassName();
+ if (!ClsName)
+ return;
+
+ Selector S = ME->getSelector();
+ if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
+ return;
+
+ if (!BT)
+ BT = new APIMisuse("message incorrectly sent to class instead of class "
+ "instance");
+
+ ExplodedNode *N = C.GenerateNode();
+
+ if (!N)
+ return;
+
+ llvm::SmallString<200> buf;
+ llvm::raw_svector_ostream os(buf);
+
+ os << "The '" << S.getAsString() << "' message should be sent to instances "
+ "of class '" << ClsName->getName()
+ << "' and not the class directly";
+
+ RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
+ report->addRange(ME->getSourceRange());
+ C.EmitReport(report);
+}
+
+//===----------------------------------------------------------------------===//
// Check registration.
//===----------------------------------------------------------------------===//
@@ -536,4 +594,5 @@ void clang::RegisterAppleChecks(GRExprEngine& Eng, const Decl &D) {
RegisterNSErrorChecks(BR, Eng, D);
RegisterNSAutoreleasePoolChecks(Eng);
+ Eng.registerCheck(new ClassReleaseChecker(Ctx));
}
diff --git a/lib/Analysis/BasicObjCFoundationChecks.h b/lib/Analysis/BasicObjCFoundationChecks.h
index ea4d3ecfcaee..679c6dc1df2d 100644
--- a/lib/Analysis/BasicObjCFoundationChecks.h
+++ b/lib/Analysis/BasicObjCFoundationChecks.h
@@ -13,24 +13,16 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
-#include "clang/Analysis/PathSensitive/GRSimpleAPICheck.h"
-#include "clang/Analysis/PathSensitive/GRState.h"
-#include "clang/Analysis/PathDiagnostic.h"
-#include "clang/AST/Expr.h"
-#include "clang/AST/ASTContext.h"
-#include "llvm/Support/Compiler.h"
-
#ifndef LLVM_CLANG_ANALYSIS_BASICOBJCFOUNDATIONCHECKS
#define LLVM_CLANG_ANALYSIS_BASICOBJCFOUNDATIONCHECKS
namespace clang {
-class GRSimpleAPICheck;
class ASTContext;
-class GRStateManager;
class BugReporter;
+class Decl;
class GRExprEngine;
+class GRSimpleAPICheck;
GRSimpleAPICheck *CreateBasicObjCFoundationChecks(ASTContext& Ctx,
BugReporter& BR);
diff --git a/lib/Analysis/BasicStore.cpp b/lib/Analysis/BasicStore.cpp
index 800a76fb0aee..45fc11a534a5 100644
--- a/lib/Analysis/BasicStore.cpp
+++ b/lib/Analysis/BasicStore.cpp
@@ -15,7 +15,6 @@
#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Analysis/PathSensitive/AnalysisContext.h"
#include "clang/Analysis/PathSensitive/GRState.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/ADT/ImmutableMap.h"
using namespace clang;
@@ -24,7 +23,7 @@ typedef llvm::ImmutableMap<const MemRegion*,SVal> BindingsTy;
namespace {
-class VISIBILITY_HIDDEN BasicStoreSubRegionMap : public SubRegionMap {
+class BasicStoreSubRegionMap : public SubRegionMap {
public:
BasicStoreSubRegionMap() {}
@@ -33,7 +32,7 @@ public:
}
};
-class VISIBILITY_HIDDEN BasicStoreManager : public StoreManager {
+class BasicStoreManager : public StoreManager {
BindingsTy::Factory VBFactory;
public:
BasicStoreManager(GRStateManager& mgr)
diff --git a/lib/Analysis/BugReporter.cpp b/lib/Analysis/BugReporter.cpp
index 8235f4acb179..c26a60af9c85 100644
--- a/lib/Analysis/BugReporter.cpp
+++ b/lib/Analysis/BugReporter.cpp
@@ -119,7 +119,7 @@ typedef llvm::DenseMap<const ExplodedNode*,
const ExplodedNode*> NodeBackMap;
namespace {
-class VISIBILITY_HIDDEN NodeMapClosure : public BugReport::NodeResolver {
+class NodeMapClosure : public BugReport::NodeResolver {
NodeBackMap& M;
public:
NodeMapClosure(NodeBackMap *m) : M(*m) {}
@@ -131,7 +131,7 @@ public:
}
};
-class VISIBILITY_HIDDEN PathDiagnosticBuilder : public BugReporterContext {
+class PathDiagnosticBuilder : public BugReporterContext {
BugReport *R;
PathDiagnosticClient *PDC;
llvm::OwningPtr<ParentMap> PM;
@@ -358,7 +358,7 @@ GetMostRecentVarDeclBinding(const ExplodedNode* N,
}
namespace {
-class VISIBILITY_HIDDEN NotableSymbolHandler
+class NotableSymbolHandler
: public StoreManager::BindingsHandler {
SymbolRef Sym;
@@ -458,7 +458,7 @@ static void HandleNotableSymbol(const ExplodedNode* N,
}
namespace {
-class VISIBILITY_HIDDEN ScanNotableSymbols
+class ScanNotableSymbols
: public StoreManager::BindingsHandler {
llvm::SmallSet<SymbolRef, 10> AlreadyProcessed;
@@ -802,7 +802,7 @@ static bool IsControlFlowExpr(const Stmt *S) {
}
namespace {
-class VISIBILITY_HIDDEN ContextLocation : public PathDiagnosticLocation {
+class ContextLocation : public PathDiagnosticLocation {
bool IsDead;
public:
ContextLocation(const PathDiagnosticLocation &L, bool isdead = false)
@@ -812,7 +812,7 @@ public:
bool isDead() const { return IsDead; }
};
-class VISIBILITY_HIDDEN EdgeBuilder {
+class EdgeBuilder {
std::vector<ContextLocation> CLocs;
typedef std::vector<ContextLocation>::iterator iterator;
PathDiagnostic &PD;
@@ -1645,7 +1645,7 @@ void BugReporter::EmitReport(BugReport* R) {
//===----------------------------------------------------------------------===//
namespace {
-struct VISIBILITY_HIDDEN FRIEC_WLItem {
+struct FRIEC_WLItem {
const ExplodedNode *N;
ExplodedNode::const_succ_iterator I, E;
@@ -1738,7 +1738,7 @@ static BugReport *FindReportInEquivalenceClass(BugReportEquivClass& EQ) {
// uses global state, which eventually should go elsewhere.
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN DiagCacheItem : public llvm::FoldingSetNode {
+class DiagCacheItem : public llvm::FoldingSetNode {
llvm::FoldingSetNodeID ID;
public:
DiagCacheItem(BugReport *R, PathDiagnostic *PD) {
@@ -1835,14 +1835,15 @@ void BugReporter::FlushReport(BugReportEquivClass& EQ) {
PD->HandlePathDiagnostic(D.take());
}
-void BugReporter::EmitBasicReport(const char* name, const char* str,
+void BugReporter::EmitBasicReport(llvm::StringRef name, llvm::StringRef str,
SourceLocation Loc,
SourceRange* RBeg, unsigned NumRanges) {
EmitBasicReport(name, "", str, Loc, RBeg, NumRanges);
}
-void BugReporter::EmitBasicReport(const char* name, const char* category,
- const char* str, SourceLocation Loc,
+void BugReporter::EmitBasicReport(llvm::StringRef name,
+ llvm::StringRef category,
+ llvm::StringRef str, SourceLocation Loc,
SourceRange* RBeg, unsigned NumRanges) {
// 'BT' will be owned by BugReporter as soon as we call 'EmitReport'.
diff --git a/lib/Analysis/BugReporterVisitors.cpp b/lib/Analysis/BugReporterVisitors.cpp
index 89c9ca10ec57..87de30ae7aec 100644
--- a/lib/Analysis/BugReporterVisitors.cpp
+++ b/lib/Analysis/BugReporterVisitors.cpp
@@ -83,7 +83,7 @@ clang::bugreporter::GetRetValExpr(const ExplodedNode *N) {
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN FindLastStoreBRVisitor : public BugReporterVisitor {
+class FindLastStoreBRVisitor : public BugReporterVisitor {
const MemRegion *R;
SVal V;
bool satisfied;
@@ -231,7 +231,7 @@ static void registerFindLastStore(BugReporterContext& BRC, const MemRegion *R,
BRC.addVisitor(new FindLastStoreBRVisitor(V, R));
}
-class VISIBILITY_HIDDEN TrackConstraintBRVisitor : public BugReporterVisitor {
+class TrackConstraintBRVisitor : public BugReporterVisitor {
DefinedSVal Constraint;
const bool Assumption;
bool isSatisfied;
diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp
index 31417597f798..c97692f57082 100644
--- a/lib/Analysis/CFG.cpp
+++ b/lib/Analysis/CFG.cpp
@@ -17,7 +17,6 @@
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/PrettyPrinter.h"
#include "llvm/Support/GraphWriter.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Format.h"
#include "llvm/ADT/DenseMap.h"
@@ -50,7 +49,7 @@ static SourceLocation GetEndLoc(Decl* D) {
/// constructed prior to its predecessor. This allows us to nicely capture
/// implicit fall-throughs without extra basic blocks.
///
-class VISIBILITY_HIDDEN CFGBuilder {
+class CFGBuilder {
ASTContext *Context;
llvm::OwningPtr<CFG> cfg;
@@ -461,9 +460,12 @@ CFGBlock *CFGBuilder::VisitBinaryOperator(BinaryOperator *B, bool alwaysAdd) {
return VisitStmt(B, alwaysAdd);
}
-CFGBlock *CFGBuilder::VisitBlockExpr(BlockExpr* E, bool alwaysAdd) {
- // FIXME
- return NYS();
+CFGBlock *CFGBuilder::VisitBlockExpr(BlockExpr *E, bool alwaysAdd) {
+ if (alwaysAdd) {
+ autoCreateBlock();
+ AppendStmt(Block, E);
+ }
+ return Block;
}
CFGBlock *CFGBuilder::VisitBlockDeclRefExpr(BlockDeclRefExpr* E,
@@ -1624,7 +1626,7 @@ CFG::~CFG() {
namespace {
-class VISIBILITY_HIDDEN StmtPrinterHelper : public PrinterHelper {
+class StmtPrinterHelper : public PrinterHelper {
typedef llvm::DenseMap<Stmt*,std::pair<unsigned,unsigned> > StmtMapTy;
StmtMapTy StmtMap;
@@ -1668,7 +1670,7 @@ public:
namespace {
-class VISIBILITY_HIDDEN CFGBlockTerminatorPrint
+class CFGBlockTerminatorPrint
: public StmtVisitor<CFGBlockTerminatorPrint,void> {
llvm::raw_ostream& OS;
@@ -2047,8 +2049,10 @@ void CFG::viewCFG(const LangOptions &LO) const {
namespace llvm {
template<>
struct DOTGraphTraits<const CFG*> : public DefaultDOTGraphTraits {
- static std::string getNodeLabel(const CFGBlock* Node, const CFG* Graph,
- bool ShortNames) {
+
+ DOTGraphTraits (bool isSimple=false) : DefaultDOTGraphTraits(isSimple) {}
+
+ static std::string getNodeLabel(const CFGBlock* Node, const CFG* Graph) {
#ifndef NDEBUG
std::string OutSStr;
diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp
index 55e5f174cb9f..b95f981275e6 100644
--- a/lib/Analysis/CFRefCount.cpp
+++ b/lib/Analysis/CFRefCount.cpp
@@ -22,13 +22,14 @@
#include "clang/Analysis/PathSensitive/BugReporter.h"
#include "clang/Analysis/PathSensitive/SymbolManager.h"
#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
+#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
#include "clang/AST/DeclObjC.h"
+#include "clang/AST/StmtVisitor.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableMap.h"
#include "llvm/ADT/ImmutableList.h"
#include "llvm/ADT/StringExtras.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/ADT/STLExtras.h"
#include <stdarg.h>
@@ -168,7 +169,7 @@ ResolveToInterfaceMethodDecl(const ObjCMethodDecl *MD) {
}
namespace {
-class VISIBILITY_HIDDEN GenericNodeBuilder {
+class GenericNodeBuilder {
GRStmtNodeBuilder *SNB;
Stmt *S;
const void *tag;
@@ -246,7 +247,7 @@ namespace {
/// RetEffect is used to summarize a function/method call's behavior with
/// respect to its return value.
-class VISIBILITY_HIDDEN RetEffect {
+class RetEffect {
public:
enum Kind { NoRet, Alias, OwnedSymbol, OwnedAllocatedSymbol,
NotOwnedSymbol, GCNotOwnedSymbol, ReceiverAlias,
@@ -312,7 +313,7 @@ public:
// Reference-counting logic (typestate + counts).
//===----------------------------------------------------------------------===//
-class VISIBILITY_HIDDEN RefVal {
+class RefVal {
public:
enum Kind {
Owned = 0, // Owning reference.
@@ -536,7 +537,7 @@ namespace clang {
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN RetainSummary {
+class RetainSummary {
/// Args - an ordered vector of (index, ArgEffect) pairs, where index
/// specifies the argument (starting from 0). This can be sparsely
/// populated; arguments with no entry in Args use 'DefaultArgEffect'.
@@ -627,7 +628,7 @@ public:
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN ObjCSummaryKey {
+class ObjCSummaryKey {
IdentifierInfo* II;
Selector S;
public:
@@ -682,7 +683,7 @@ template <> struct DenseMapInfo<ObjCSummaryKey> {
} // end llvm namespace
namespace {
-class VISIBILITY_HIDDEN ObjCSummaryCache {
+class ObjCSummaryCache {
typedef llvm::DenseMap<ObjCSummaryKey, RetainSummary*> MapTy;
MapTy M;
public:
@@ -776,7 +777,7 @@ public:
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN RetainSummaryManager {
+class RetainSummaryManager {
//==-----------------------------------------------------------------==//
// Typedefs.
@@ -1865,8 +1866,8 @@ typedef llvm::ImmutableList<SymbolRef> ARStack;
static int AutoRCIndex = 0;
static int AutoRBIndex = 0;
-namespace { class VISIBILITY_HIDDEN AutoreleasePoolContents {}; }
-namespace { class VISIBILITY_HIDDEN AutoreleaseStack {}; }
+namespace { class AutoreleasePoolContents {}; }
+namespace { class AutoreleaseStack {}; }
namespace clang {
template<> struct GRStateTrait<AutoreleaseStack>
@@ -1908,7 +1909,7 @@ static const GRState * SendAutorelease(const GRState *state,
namespace {
-class VISIBILITY_HIDDEN CFRefCount : public GRTransferFuncs {
+class CFRefCount : public GRTransferFuncs {
public:
class BindingsPrinter : public GRState::Printer {
public:
@@ -2093,11 +2094,11 @@ namespace {
// Bug Descriptions. //
//===-------------===//
- class VISIBILITY_HIDDEN CFRefBug : public BugType {
+ class CFRefBug : public BugType {
protected:
CFRefCount& TF;
- CFRefBug(CFRefCount* tf, const char* name)
+ CFRefBug(CFRefCount* tf, llvm::StringRef name)
: BugType(name, "Memory (Core Foundation/Objective-C)"), TF(*tf) {}
public:
@@ -2110,7 +2111,7 @@ namespace {
virtual bool isLeak() const { return false; }
};
- class VISIBILITY_HIDDEN UseAfterRelease : public CFRefBug {
+ class UseAfterRelease : public CFRefBug {
public:
UseAfterRelease(CFRefCount* tf)
: CFRefBug(tf, "Use-after-release") {}
@@ -2120,7 +2121,7 @@ namespace {
}
};
- class VISIBILITY_HIDDEN BadRelease : public CFRefBug {
+ class BadRelease : public CFRefBug {
public:
BadRelease(CFRefCount* tf) : CFRefBug(tf, "Bad release") {}
@@ -2130,7 +2131,7 @@ namespace {
}
};
- class VISIBILITY_HIDDEN DeallocGC : public CFRefBug {
+ class DeallocGC : public CFRefBug {
public:
DeallocGC(CFRefCount *tf)
: CFRefBug(tf, "-dealloc called while using garbage collection") {}
@@ -2140,7 +2141,7 @@ namespace {
}
};
- class VISIBILITY_HIDDEN DeallocNotOwned : public CFRefBug {
+ class DeallocNotOwned : public CFRefBug {
public:
DeallocNotOwned(CFRefCount *tf)
: CFRefBug(tf, "-dealloc sent to non-exclusively owned object") {}
@@ -2150,7 +2151,7 @@ namespace {
}
};
- class VISIBILITY_HIDDEN OverAutorelease : public CFRefBug {
+ class OverAutorelease : public CFRefBug {
public:
OverAutorelease(CFRefCount *tf) :
CFRefBug(tf, "Object sent -autorelease too many times") {}
@@ -2160,7 +2161,7 @@ namespace {
}
};
- class VISIBILITY_HIDDEN ReturnedNotOwnedForOwned : public CFRefBug {
+ class ReturnedNotOwnedForOwned : public CFRefBug {
public:
ReturnedNotOwnedForOwned(CFRefCount *tf) :
CFRefBug(tf, "Method should return an owned object") {}
@@ -2171,10 +2172,10 @@ namespace {
}
};
- class VISIBILITY_HIDDEN Leak : public CFRefBug {
+ class Leak : public CFRefBug {
const bool isReturn;
protected:
- Leak(CFRefCount* tf, const char* name, bool isRet)
+ Leak(CFRefCount* tf, llvm::StringRef name, bool isRet)
: CFRefBug(tf, name), isReturn(isRet) {}
public:
@@ -2183,15 +2184,15 @@ namespace {
bool isLeak() const { return true; }
};
- class VISIBILITY_HIDDEN LeakAtReturn : public Leak {
+ class LeakAtReturn : public Leak {
public:
- LeakAtReturn(CFRefCount* tf, const char* name)
+ LeakAtReturn(CFRefCount* tf, llvm::StringRef name)
: Leak(tf, name, true) {}
};
- class VISIBILITY_HIDDEN LeakWithinFunction : public Leak {
+ class LeakWithinFunction : public Leak {
public:
- LeakWithinFunction(CFRefCount* tf, const char* name)
+ LeakWithinFunction(CFRefCount* tf, llvm::StringRef name)
: Leak(tf, name, false) {}
};
@@ -2199,7 +2200,7 @@ namespace {
// Bug Reports. //
//===---------===//
- class VISIBILITY_HIDDEN CFRefReport : public RangedBugReport {
+ class CFRefReport : public RangedBugReport {
protected:
SymbolRef Sym;
const CFRefCount &TF;
@@ -2209,7 +2210,7 @@ namespace {
: RangedBugReport(D, D.getDescription(), n), Sym(sym), TF(tf) {}
CFRefReport(CFRefBug& D, const CFRefCount &tf,
- ExplodedNode *n, SymbolRef sym, const char* endText)
+ ExplodedNode *n, SymbolRef sym, llvm::StringRef endText)
: RangedBugReport(D, D.getDescription(), endText, n), Sym(sym), TF(tf) {}
virtual ~CFRefReport() {}
@@ -2240,7 +2241,7 @@ namespace {
BugReporterContext& BRC);
};
- class VISIBILITY_HIDDEN CFRefLeakReport : public CFRefReport {
+ class CFRefLeakReport : public CFRefReport {
SourceLocation AllocSite;
const MemRegion* AllocBinding;
public:
@@ -2255,64 +2256,7 @@ namespace {
};
} // end anonymous namespace
-void CFRefCount::RegisterChecks(GRExprEngine& Eng) {
- BugReporter &BR = Eng.getBugReporter();
-
- useAfterRelease = new UseAfterRelease(this);
- BR.Register(useAfterRelease);
-
- releaseNotOwned = new BadRelease(this);
- BR.Register(releaseNotOwned);
-
- deallocGC = new DeallocGC(this);
- BR.Register(deallocGC);
-
- deallocNotOwned = new DeallocNotOwned(this);
- BR.Register(deallocNotOwned);
-
- overAutorelease = new OverAutorelease(this);
- BR.Register(overAutorelease);
-
- returnNotOwnedForOwned = new ReturnedNotOwnedForOwned(this);
- BR.Register(returnNotOwnedForOwned);
-
- // First register "return" leaks.
- const char* name = 0;
-
- if (isGCEnabled())
- name = "Leak of returned object when using garbage collection";
- else if (getLangOptions().getGCMode() == LangOptions::HybridGC)
- name = "Leak of returned object when not using garbage collection (GC) in "
- "dual GC/non-GC code";
- else {
- assert(getLangOptions().getGCMode() == LangOptions::NonGC);
- name = "Leak of returned object";
- }
-
- // Leaks should not be reported if they are post-dominated by a sink.
- leakAtReturn = new LeakAtReturn(this, name);
- leakAtReturn->setSuppressOnSink(true);
- BR.Register(leakAtReturn);
-
- // Second, register leaks within a function/method.
- if (isGCEnabled())
- name = "Leak of object when using garbage collection";
- else if (getLangOptions().getGCMode() == LangOptions::HybridGC)
- name = "Leak of object when not using garbage collection (GC) in "
- "dual GC/non-GC code";
- else {
- assert(getLangOptions().getGCMode() == LangOptions::NonGC);
- name = "Leak";
- }
-
- // Leaks should not be reported if they are post-dominated by sinks.
- leakWithinFunction = new LeakWithinFunction(this, name);
- leakWithinFunction->setSuppressOnSink(true);
- BR.Register(leakWithinFunction);
- // Save the reference to the BugReporter.
- this->BR = &BR;
-}
static const char* Msgs[] = {
// GC only
@@ -2603,7 +2547,7 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N,
}
namespace {
- class VISIBILITY_HIDDEN FindUniqueBinding :
+ class FindUniqueBinding :
public StoreManager::BindingsHandler {
SymbolRef Sym;
const MemRegion* Binding;
@@ -3052,9 +2996,20 @@ void CFRefCount::EvalCall(ExplodedNodeSet& Dst,
GRStmtNodeBuilder& Builder,
CallExpr* CE, SVal L,
ExplodedNode* Pred) {
- const FunctionDecl* FD = L.getAsFunctionDecl();
- RetainSummary* Summ = !FD ? Summaries.getDefaultSummary()
- : Summaries.getSummary(const_cast<FunctionDecl*>(FD));
+
+ RetainSummary *Summ = 0;
+
+ // FIXME: Better support for blocks. For now we stop tracking anything
+ // that is passed to blocks.
+ // FIXME: Need to handle variables that are "captured" by the block.
+ if (dyn_cast_or_null<BlockDataRegion>(L.getAsRegion())) {
+ Summ = Summaries.getPersistentStopSummary();
+ }
+ else {
+ const FunctionDecl* FD = L.getAsFunctionDecl();
+ Summ = !FD ? Summaries.getDefaultSummary() :
+ Summaries.getSummary(const_cast<FunctionDecl*>(FD));
+ }
assert(Summ);
EvalSummary(Dst, Eng, Builder, CE, 0, *Summ,
@@ -3066,6 +3021,16 @@ void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet& Dst,
GRStmtNodeBuilder& Builder,
ObjCMessageExpr* ME,
ExplodedNode* Pred) {
+ // FIXME: Since we moved the nil check into a checker, we could get nil
+ // receiver here. Need a better way to check such case.
+ if (Expr* Receiver = ME->getReceiver()) {
+ const GRState *state = Pred->getState();
+ DefinedOrUnknownSVal L=cast<DefinedOrUnknownSVal>(state->getSVal(Receiver));
+ if (!state->Assume(L, true)) {
+ Dst.Add(Pred);
+ return;
+ }
+ }
RetainSummary *Summ =
ME->getReceiver()
@@ -3079,7 +3044,7 @@ void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet& Dst,
}
namespace {
-class VISIBILITY_HIDDEN StopTrackingCallback : public SymbolVisitor {
+class StopTrackingCallback : public SymbolVisitor {
const GRState *state;
public:
StopTrackingCallback(const GRState *st) : state(st) {}
@@ -3501,7 +3466,7 @@ CFRefCount::HandleAutoreleaseCounts(const GRState * state, GenericNodeBuilder Bd
CFRefReport *report =
new CFRefReport(*static_cast<CFRefBug*>(overAutorelease),
- *this, N, Sym, os.str().c_str());
+ *this, N, Sym, os.str());
BR->EmitReport(report);
}
@@ -3670,9 +3635,114 @@ void CFRefCount::ProcessNonLeakError(ExplodedNodeSet& Dst,
}
//===----------------------------------------------------------------------===//
+// Pieces of the retain/release checker implemented using a CheckerVisitor.
+// More pieces of the retain/release checker will be migrated to this interface
+// (ideally, all of it some day).
+//===----------------------------------------------------------------------===//
+
+namespace {
+class RetainReleaseChecker
+ : public CheckerVisitor<RetainReleaseChecker> {
+ CFRefCount *TF;
+public:
+ RetainReleaseChecker(CFRefCount *tf) : TF(tf) {}
+ static void* getTag() { static int x = 0; return &x; }
+
+ void PostVisitBlockExpr(CheckerContext &C, const BlockExpr *BE);
+};
+} // end anonymous namespace
+
+
+void RetainReleaseChecker::PostVisitBlockExpr(CheckerContext &C,
+ const BlockExpr *BE) {
+
+ // Scan the BlockDecRefExprs for any object the retain/release checker
+ // may be tracking.
+ if (!BE->hasBlockDeclRefExprs())
+ return;
+
+ const GRState *state = C.getState();
+ const BlockDataRegion *R =
+ cast<BlockDataRegion>(state->getSVal(BE).getAsRegion());
+
+ BlockDataRegion::referenced_vars_iterator I = R->referenced_vars_begin(),
+ E = R->referenced_vars_end();
+
+ if (I == E)
+ return;
+
+ state = state->scanReachableSymbols<StopTrackingCallback>(I, E).getState();
+ C.addTransition(state);
+}
+
+//===----------------------------------------------------------------------===//
// Transfer function creation for external clients.
//===----------------------------------------------------------------------===//
+void CFRefCount::RegisterChecks(GRExprEngine& Eng) {
+ BugReporter &BR = Eng.getBugReporter();
+
+ useAfterRelease = new UseAfterRelease(this);
+ BR.Register(useAfterRelease);
+
+ releaseNotOwned = new BadRelease(this);
+ BR.Register(releaseNotOwned);
+
+ deallocGC = new DeallocGC(this);
+ BR.Register(deallocGC);
+
+ deallocNotOwned = new DeallocNotOwned(this);
+ BR.Register(deallocNotOwned);
+
+ overAutorelease = new OverAutorelease(this);
+ BR.Register(overAutorelease);
+
+ returnNotOwnedForOwned = new ReturnedNotOwnedForOwned(this);
+ BR.Register(returnNotOwnedForOwned);
+
+ // First register "return" leaks.
+ const char* name = 0;
+
+ if (isGCEnabled())
+ name = "Leak of returned object when using garbage collection";
+ else if (getLangOptions().getGCMode() == LangOptions::HybridGC)
+ name = "Leak of returned object when not using garbage collection (GC) in "
+ "dual GC/non-GC code";
+ else {
+ assert(getLangOptions().getGCMode() == LangOptions::NonGC);
+ name = "Leak of returned object";
+ }
+
+ // Leaks should not be reported if they are post-dominated by a sink.
+ leakAtReturn = new LeakAtReturn(this, name);
+ leakAtReturn->setSuppressOnSink(true);
+ BR.Register(leakAtReturn);
+
+ // Second, register leaks within a function/method.
+ if (isGCEnabled())
+ name = "Leak of object when using garbage collection";
+ else if (getLangOptions().getGCMode() == LangOptions::HybridGC)
+ name = "Leak of object when not using garbage collection (GC) in "
+ "dual GC/non-GC code";
+ else {
+ assert(getLangOptions().getGCMode() == LangOptions::NonGC);
+ name = "Leak";
+ }
+
+ // Leaks should not be reported if they are post-dominated by sinks.
+ leakWithinFunction = new LeakWithinFunction(this, name);
+ leakWithinFunction->setSuppressOnSink(true);
+ BR.Register(leakWithinFunction);
+
+ // Save the reference to the BugReporter.
+ this->BR = &BR;
+
+ // Register the RetainReleaseChecker with the GRExprEngine object.
+ // Functionality in CFRefCount will be migrated to RetainReleaseChecker
+ // over time.
+ Eng.registerCheck(new RetainReleaseChecker(this));
+}
+
GRTransferFuncs* clang::MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled,
const LangOptions& lopts) {
return new CFRefCount(Ctx, GCEnabled, lopts);
diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt
index 8e8c1e7b25ed..409292d451d8 100644
--- a/lib/Analysis/CMakeLists.txt
+++ b/lib/Analysis/CMakeLists.txt
@@ -4,7 +4,6 @@ add_clang_library(clangAnalysis
AnalysisContext.cpp
ArrayBoundChecker.cpp
AttrNonNullChecker.cpp
- BadCallChecker.cpp
BasicConstraintManager.cpp
BasicObjCFoundationChecks.cpp
BasicStore.cpp
@@ -13,6 +12,7 @@ add_clang_library(clangAnalysis
BugReporterVisitors.cpp
CFG.cpp
CFRefCount.cpp
+ CallAndMessageChecker.cpp
CallGraph.cpp
CallInliner.cpp
CastToStructChecker.cpp
@@ -22,6 +22,7 @@ add_clang_library(clangAnalysis
CheckObjCUnusedIVars.cpp
CheckSecuritySyntaxOnly.cpp
CheckSizeofPointer.cpp
+ Checker.cpp
DereferenceChecker.cpp
DivZeroChecker.cpp
Environment.cpp
@@ -31,7 +32,6 @@ add_clang_library(clangAnalysis
GRCoreEngine.cpp
GRExprEngine.cpp
GRExprEngineExperimentalChecks.cpp
- GRExprEngineInternalChecks.cpp
GRState.cpp
LiveVariables.cpp
MallocChecker.cpp
@@ -54,7 +54,8 @@ add_clang_library(clangAnalysis
SimpleSValuator.cpp
Store.cpp
SymbolManager.cpp
- UndefinedArgChecker.cpp
+ UndefBranchChecker.cpp
+ UndefResultChecker.cpp
UndefinedArraySubscriptChecker.cpp
UndefinedAssignmentChecker.cpp
UninitializedValues.cpp
diff --git a/lib/Analysis/CallAndMessageChecker.cpp b/lib/Analysis/CallAndMessageChecker.cpp
new file mode 100644
index 000000000000..d8dd16c57b81
--- /dev/null
+++ b/lib/Analysis/CallAndMessageChecker.cpp
@@ -0,0 +1,267 @@
+//===--- CallAndMessageChecker.cpp ------------------------------*- C++ -*--==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines CallAndMessageChecker, a builtin checker that checks for various
+// errors of call and objc message expressions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/AST/ParentMap.h"
+#include "GRExprEngineInternalChecks.h"
+
+using namespace clang;
+
+namespace {
+class CallAndMessageChecker
+ : public CheckerVisitor<CallAndMessageChecker> {
+ BugType *BT_call_null;
+ BugType *BT_call_undef;
+ BugType *BT_call_arg;
+ BugType *BT_msg_undef;
+ BugType *BT_msg_arg;
+ BugType *BT_msg_ret;
+public:
+ CallAndMessageChecker() :
+ BT_call_null(0), BT_call_undef(0), BT_call_arg(0),
+ BT_msg_undef(0), BT_msg_arg(0), BT_msg_ret(0) {}
+
+ static void *getTag() {
+ static int x = 0;
+ return &x;
+ }
+
+ void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
+ void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME);
+
+private:
+ void EmitBadCall(BugType *BT, CheckerContext &C, const CallExpr *CE);
+ void EmitNilReceiverBug(CheckerContext &C, const ObjCMessageExpr *ME,
+ ExplodedNode *N);
+
+ void HandleNilReceiver(CheckerContext &C, const GRState *state,
+ const ObjCMessageExpr *ME);
+};
+} // end anonymous namespace
+
+void clang::RegisterCallAndMessageChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new CallAndMessageChecker());
+}
+
+void CallAndMessageChecker::EmitBadCall(BugType *BT, CheckerContext &C,
+ const CallExpr *CE) {
+ ExplodedNode *N = C.GenerateSink();
+ if (!N)
+ return;
+
+ EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N);
+ R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
+ bugreporter::GetCalleeExpr(N));
+ C.EmitReport(R);
+}
+
+void CallAndMessageChecker::PreVisitCallExpr(CheckerContext &C,
+ const CallExpr *CE){
+
+ const Expr *Callee = CE->getCallee()->IgnoreParens();
+ SVal L = C.getState()->getSVal(Callee);
+
+ if (L.isUndef()) {
+ if (!BT_call_undef)
+ BT_call_undef =
+ new BuiltinBug("Called function pointer is an undefined pointer value");
+ EmitBadCall(BT_call_undef, C, CE);
+ return;
+ }
+
+ if (isa<loc::ConcreteInt>(L)) {
+ if (!BT_call_null)
+ BT_call_null =
+ new BuiltinBug("Called function pointer is null (null dereference)");
+ EmitBadCall(BT_call_null, C, CE);
+ }
+
+ for (CallExpr::const_arg_iterator I = CE->arg_begin(), E = CE->arg_end();
+ I != E; ++I) {
+ if (C.getState()->getSVal(*I).isUndef()) {
+ if (ExplodedNode *N = C.GenerateSink()) {
+ if (!BT_call_arg)
+ BT_call_arg = new BuiltinBug("Pass-by-value argument in function call"
+ " is undefined");
+ // Generate a report for this bug.
+ EnhancedBugReport *R = new EnhancedBugReport(*BT_call_arg,
+ BT_call_arg->getName(), N);
+ R->addRange((*I)->getSourceRange());
+ R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, *I);
+ C.EmitReport(R);
+ return;
+ }
+ }
+ }
+}
+
+void CallAndMessageChecker::PreVisitObjCMessageExpr(CheckerContext &C,
+ const ObjCMessageExpr *ME) {
+
+ const GRState *state = C.getState();
+
+ if (const Expr *receiver = ME->getReceiver())
+ if (state->getSVal(receiver).isUndef()) {
+ if (ExplodedNode *N = C.GenerateSink()) {
+ if (!BT_msg_undef)
+ BT_msg_undef =
+ new BuiltinBug("Receiver in message expression is a garbage value");
+ EnhancedBugReport *R =
+ new EnhancedBugReport(*BT_msg_undef, BT_msg_undef->getName(), N);
+ R->addRange(receiver->getSourceRange());
+ R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
+ receiver);
+ C.EmitReport(R);
+ }
+ return;
+ }
+
+ // Check for any arguments that are uninitialized/undefined.
+ for (ObjCMessageExpr::const_arg_iterator I = ME->arg_begin(),
+ E = ME->arg_end(); I != E; ++I) {
+ if (state->getSVal(*I).isUndef()) {
+ if (ExplodedNode *N = C.GenerateSink()) {
+ if (!BT_msg_arg)
+ BT_msg_arg =
+ new BuiltinBug("Pass-by-value argument in message expression"
+ " is undefined");
+ // Generate a report for this bug.
+ EnhancedBugReport *R = new EnhancedBugReport(*BT_msg_arg,
+ BT_msg_arg->getName(), N);
+ R->addRange((*I)->getSourceRange());
+ R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, *I);
+ C.EmitReport(R);
+ return;
+ }
+ }
+ }
+
+ // Check if the receiver was nil and then returns a value that may
+ // be garbage.
+ if (const Expr *Receiver = ME->getReceiver()) {
+ DefinedOrUnknownSVal receiverVal =
+ cast<DefinedOrUnknownSVal>(state->getSVal(Receiver));
+
+ const GRState *notNullState, *nullState;
+ llvm::tie(notNullState, nullState) = state->Assume(receiverVal);
+
+ if (nullState && !notNullState) {
+ HandleNilReceiver(C, nullState, ME);
+ C.setDoneEvaluating(); // FIXME: eventually remove.
+ return;
+ }
+
+ assert(notNullState);
+ state = notNullState;
+ }
+
+ // Add a state transition if the state has changed.
+ C.addTransition(state);
+}
+
+void CallAndMessageChecker::EmitNilReceiverBug(CheckerContext &C,
+ const ObjCMessageExpr *ME,
+ ExplodedNode *N) {
+
+ if (!BT_msg_ret)
+ BT_msg_ret =
+ new BuiltinBug("Receiver in message expression is "
+ "'nil' and returns a garbage value");
+
+ llvm::SmallString<200> buf;
+ llvm::raw_svector_ostream os(buf);
+ os << "The receiver of message '" << ME->getSelector().getAsString()
+ << "' is nil and returns a value of type '"
+ << ME->getType().getAsString() << "' that will be garbage";
+
+ EnhancedBugReport *report = new EnhancedBugReport(*BT_msg_ret, os.str(), N);
+ const Expr *receiver = ME->getReceiver();
+ report->addRange(receiver->getSourceRange());
+ report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
+ receiver);
+ C.EmitReport(report);
+}
+
+static bool SupportsNilWithFloatRet(const llvm::Triple &triple) {
+ return triple.getVendor() == llvm::Triple::Apple &&
+ triple.getDarwinMajorNumber() >= 9;
+}
+
+void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
+ const GRState *state,
+ const ObjCMessageExpr *ME) {
+
+ // Check the return type of the message expression. A message to nil will
+ // return different values depending on the return type and the architecture.
+ QualType RetTy = ME->getType();
+
+ ASTContext &Ctx = C.getASTContext();
+ CanQualType CanRetTy = Ctx.getCanonicalType(RetTy);
+
+ if (CanRetTy->isStructureType()) {
+ // FIXME: At some point we shouldn't rely on isConsumedExpr(), but instead
+ // have the "use of undefined value" be smarter about where the
+ // undefined value came from.
+ if (C.getPredecessor()->getParentMap().isConsumedExpr(ME)) {
+ if (ExplodedNode* N = C.GenerateSink(state))
+ EmitNilReceiverBug(C, ME, N);
+ return;
+ }
+
+ // The result is not consumed by a surrounding expression. Just propagate
+ // the current state.
+ C.addTransition(state);
+ return;
+ }
+
+ // Other cases: check if the return type is smaller than void*.
+ if (CanRetTy != Ctx.VoidTy &&
+ C.getPredecessor()->getParentMap().isConsumedExpr(ME)) {
+ // Compute: sizeof(void *) and sizeof(return type)
+ const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);
+ const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy);
+
+ if (voidPtrSize < returnTypeSize &&
+ !(SupportsNilWithFloatRet(Ctx.Target.getTriple()) &&
+ (Ctx.FloatTy == CanRetTy ||
+ Ctx.DoubleTy == CanRetTy ||
+ Ctx.LongDoubleTy == CanRetTy ||
+ Ctx.LongLongTy == CanRetTy))) {
+ if (ExplodedNode* N = C.GenerateSink(state))
+ EmitNilReceiverBug(C, ME, N);
+ return;
+ }
+
+ // Handle the safe cases where the return value is 0 if the
+ // receiver is nil.
+ //
+ // FIXME: For now take the conservative approach that we only
+ // return null values if we *know* that the receiver is nil.
+ // This is because we can have surprises like:
+ //
+ // ... = [[NSScreens screens] objectAtIndex:0];
+ //
+ // What can happen is that [... screens] could return nil, but
+ // it most likely isn't nil. We should assume the semantics
+ // of this case unless we have *a lot* more knowledge.
+ //
+ SVal V = C.getValueManager().makeZeroVal(ME->getType());
+ C.GenerateNode(state->BindExpr(ME, V));
+ return;
+ }
+
+ C.addTransition(state);
+}
diff --git a/lib/Analysis/CallGraph.cpp b/lib/Analysis/CallGraph.cpp
index 06e3317691e3..c1040f0c9949 100644
--- a/lib/Analysis/CallGraph.cpp
+++ b/lib/Analysis/CallGraph.cpp
@@ -137,8 +137,10 @@ namespace llvm {
template <>
struct DOTGraphTraits<CallGraph> : public DefaultDOTGraphTraits {
+ DOTGraphTraits (bool isSimple=false) : DefaultDOTGraphTraits(isSimple) {}
+
static std::string getNodeLabel(const CallGraphNode *Node,
- const CallGraph &CG, bool ShortNames) {
+ const CallGraph &CG) {
return Node->getName();
}
diff --git a/lib/Analysis/CallInliner.cpp b/lib/Analysis/CallInliner.cpp
index cca8584a61fa..43523c293d58 100644
--- a/lib/Analysis/CallInliner.cpp
+++ b/lib/Analysis/CallInliner.cpp
@@ -18,7 +18,7 @@ using namespace clang;
namespace {
-class VISIBILITY_HIDDEN CallInliner : public GRTransferFuncs {
+class CallInliner : public GRTransferFuncs {
ASTContext &Ctx;
public:
CallInliner(ASTContext &ctx) : Ctx(ctx) {}
diff --git a/lib/Analysis/CastToStructChecker.cpp b/lib/Analysis/CastToStructChecker.cpp
index ccd4a3333e22..a3663421a082 100644
--- a/lib/Analysis/CastToStructChecker.cpp
+++ b/lib/Analysis/CastToStructChecker.cpp
@@ -19,7 +19,7 @@
using namespace clang;
namespace {
-class VISIBILITY_HIDDEN CastToStructChecker
+class CastToStructChecker
: public CheckerVisitor<CastToStructChecker> {
BuiltinBug *BT;
public:
@@ -59,7 +59,7 @@ void CastToStructChecker::PreVisitCastExpr(CheckerContext &C,
// Now the cast-to-type is struct pointer, the original type is not void*.
if (!OrigPointeeTy->isRecordType()) {
- if (ExplodedNode *N = C.GenerateNode(CE)) {
+ if (ExplodedNode *N = C.GenerateNode()) {
if (!BT)
BT = new BuiltinBug("Cast from non-struct type to struct type",
"Casting a non-structure type to a structure type "
diff --git a/lib/Analysis/CheckDeadStores.cpp b/lib/Analysis/CheckDeadStores.cpp
index d5cb7ca7fdd3..ad63eb4122b0 100644
--- a/lib/Analysis/CheckDeadStores.cpp
+++ b/lib/Analysis/CheckDeadStores.cpp
@@ -22,13 +22,12 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/ParentMap.h"
#include "llvm/ADT/SmallPtrSet.h"
-#include "llvm/Support/Compiler.h"
using namespace clang;
namespace {
-class VISIBILITY_HIDDEN DeadStoreObs : public LiveVariables::ObserverTy {
+class DeadStoreObs : public LiveVariables::ObserverTy {
ASTContext &Ctx;
BugReporter& BR;
ParentMap& Parents;
@@ -77,7 +76,7 @@ public:
break;
}
- BR.EmitBasicReport(BugType, "Dead store", msg.c_str(), L, R);
+ BR.EmitBasicReport(BugType, "Dead store", msg, L, R);
}
void CheckVarDecl(VarDecl* VD, Expr* Ex, Expr* Val,
@@ -134,16 +133,15 @@ public:
if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(B->getLHS()))
if (VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
- Expr* RHS = B->getRHS()->IgnoreParenCasts();
-
// Special case: check for assigning null to a pointer.
// This is a common form of defensive programming.
if (VD->getType()->isPointerType()) {
- if (IntegerLiteral* L = dyn_cast<IntegerLiteral>(RHS))
- // FIXME: Probably should have an Expr::isNullPointerConstant.
- if (L->getValue() == 0)
- return;
+ if (B->getRHS()->isNullPointerConstant(Ctx,
+ Expr::NPC_ValueDependentIsNull))
+ return;
}
+
+ Expr* RHS = B->getRHS()->IgnoreParenCasts();
// Special case: self-assignments. These are often used to shut up
// "unused variable" compiler warnings.
if (DeclRefExpr* RhsDR = dyn_cast<DeclRefExpr>(RHS))
@@ -226,7 +224,7 @@ public:
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN FindEscaped : public CFGRecStmtDeclVisitor<FindEscaped>{
+class FindEscaped : public CFGRecStmtDeclVisitor<FindEscaped>{
CFG *cfg;
public:
FindEscaped(CFG *c) : cfg(c) {}
diff --git a/lib/Analysis/CheckObjCDealloc.cpp b/lib/Analysis/CheckObjCDealloc.cpp
index 92e3e112d9f1..87c1f270a65c 100644
--- a/lib/Analysis/CheckObjCDealloc.cpp
+++ b/lib/Analysis/CheckObjCDealloc.cpp
@@ -169,7 +169,7 @@ void clang::CheckObjCDealloc(const ObjCImplementationDecl* D,
os << "Objective-C class '" << D->getNameAsString()
<< "' lacks a 'dealloc' instance method";
- BR.EmitBasicReport(name, os.str().c_str(), D->getLocStart());
+ BR.EmitBasicReport(name, os.str(), D->getLocStart());
return;
}
@@ -187,7 +187,7 @@ void clang::CheckObjCDealloc(const ObjCImplementationDecl* D,
<< "' does not send a 'dealloc' message to its super class"
" (missing [super dealloc])";
- BR.EmitBasicReport(name, os.str().c_str(), D->getLocStart());
+ BR.EmitBasicReport(name, os.str(), D->getLocStart());
return;
}
@@ -251,8 +251,7 @@ void clang::CheckObjCDealloc(const ObjCImplementationDecl* D,
"but was released in 'dealloc'";
}
- BR.EmitBasicReport(name, category,
- os.str().c_str(), (*I)->getLocation());
+ BR.EmitBasicReport(name, category, os.str(), (*I)->getLocation());
}
}
}
diff --git a/lib/Analysis/CheckObjCInstMethSignature.cpp b/lib/Analysis/CheckObjCInstMethSignature.cpp
index 8c0d39629d50..10ba896557df 100644
--- a/lib/Analysis/CheckObjCInstMethSignature.cpp
+++ b/lib/Analysis/CheckObjCInstMethSignature.cpp
@@ -65,7 +65,7 @@ static void CompareReturnTypes(const ObjCMethodDecl *MethDerived,
"behavior for clients of these classes.";
BR.EmitBasicReport("Incompatible instance method return type",
- os.str().c_str(), MethDerived->getLocStart());
+ os.str(), MethDerived->getLocStart());
}
}
diff --git a/lib/Analysis/CheckObjCUnusedIVars.cpp b/lib/Analysis/CheckObjCUnusedIVars.cpp
index 2d9b53163f6a..d4067c900f3f 100644
--- a/lib/Analysis/CheckObjCUnusedIVars.cpp
+++ b/lib/Analysis/CheckObjCUnusedIVars.cpp
@@ -20,6 +20,7 @@
#include "clang/AST/Expr.h"
#include "clang/AST/DeclObjC.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/SourceManager.h"
using namespace clang;
@@ -85,6 +86,17 @@ static void Scan(IvarUsageMap& M, const ObjCContainerDecl* D) {
}
}
+static void Scan(IvarUsageMap &M, const DeclContext *C, const FileID FID,
+ SourceManager &SM) {
+ for (DeclContext::decl_iterator I=C->decls_begin(), E=C->decls_end();
+ I!=E; ++I)
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) {
+ SourceLocation L = FD->getLocStart();
+ if (SM.getFileID(L) == FID)
+ Scan(M, FD->getBody());
+ }
+}
+
void clang::CheckObjCUnusedIvar(const ObjCImplementationDecl *D,
BugReporter &BR) {
@@ -110,10 +122,30 @@ void clang::CheckObjCUnusedIvar(const ObjCImplementationDecl *D,
if (M.empty())
return;
-
+
// Now scan the implementation declaration.
Scan(M, D);
+
+ // Any potentially unused ivars?
+ bool hasUnused = false;
+ for (IvarUsageMap::iterator I = M.begin(), E = M.end(); I!=E; ++I)
+ if (I->second == Unused) {
+ hasUnused = true;
+ break;
+ }
+
+ if (!hasUnused)
+ return;
+
+ // We found some potentially unused ivars. Scan the entire translation unit
+ // for functions inside the @implementation that reference these ivars.
+ // FIXME: In the future hopefully we can just use the lexical DeclContext
+ // to go from the ObjCImplementationDecl to the lexically "nested"
+ // C functions.
+ SourceManager &SM = BR.getSourceManager();
+ Scan(M, D->getDeclContext(), SM.getFileID(D->getLocation()), SM);
+
// Find ivars that are unused.
for (IvarUsageMap::iterator I = M.begin(), E = M.end(); I!=E; ++I)
if (I->second == Unused) {
@@ -125,6 +157,6 @@ void clang::CheckObjCUnusedIvar(const ObjCImplementationDecl *D,
"(although it may be used by category methods).";
BR.EmitBasicReport("Unused instance variable", "Optimization",
- os.str().c_str(), I->first->getLocation());
+ os.str(), I->first->getLocation());
}
}
diff --git a/lib/Analysis/CheckSecuritySyntaxOnly.cpp b/lib/Analysis/CheckSecuritySyntaxOnly.cpp
index f1b9c2194f8b..e6ab17a75905 100644
--- a/lib/Analysis/CheckSecuritySyntaxOnly.cpp
+++ b/lib/Analysis/CheckSecuritySyntaxOnly.cpp
@@ -14,13 +14,12 @@
#include "clang/Analysis/PathSensitive/BugReporter.h"
#include "clang/Analysis/LocalCheckers.h"
#include "clang/AST/StmtVisitor.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
namespace {
-class VISIBILITY_HIDDEN WalkAST : public StmtVisitor<WalkAST> {
+class WalkAST : public StmtVisitor<WalkAST> {
BugReporter &BR;
IdentifierInfo *II_gets;
IdentifierInfo *II_getpw;
@@ -210,7 +209,7 @@ void WalkAST::CheckLoopConditionForFloat(const ForStmt *FS) {
ranges.push_back(drInc->getSourceRange());
const char *bugType = "Floating point variable used as loop counter";
- BR.EmitBasicReport(bugType, "Security", os.str().c_str(),
+ BR.EmitBasicReport(bugType, "Security", os.str(),
FS->getLocStart(), ranges.data(), ranges.size());
}
@@ -347,7 +346,7 @@ void WalkAST::CheckCall_rand(const CallExpr *CE, const FunctionDecl *FD) {
SourceRange R = CE->getCallee()->getSourceRange();
- BR.EmitBasicReport(os1.str().c_str(), "Security", os2.str().c_str(),
+ BR.EmitBasicReport(os1.str(), "Security", os2.str(),
CE->getLocStart(), &R, 1);
}
@@ -437,7 +436,7 @@ void WalkAST::CheckUncheckedReturnValue(CallExpr *CE) {
SourceRange R = CE->getCallee()->getSourceRange();
- BR.EmitBasicReport(os1.str().c_str(), "Security", os2.str().c_str(),
+ BR.EmitBasicReport(os1.str(), "Security", os2.str(),
CE->getLocStart(), &R, 1);
}
diff --git a/lib/Analysis/CheckSizeofPointer.cpp b/lib/Analysis/CheckSizeofPointer.cpp
index 174beefbca45..4f5da9f5a716 100644
--- a/lib/Analysis/CheckSizeofPointer.cpp
+++ b/lib/Analysis/CheckSizeofPointer.cpp
@@ -15,12 +15,11 @@
#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> {
+class WalkAST : public StmtVisitor<WalkAST> {
BugReporter &BR;
public:
diff --git a/lib/Analysis/Checker.cpp b/lib/Analysis/Checker.cpp
new file mode 100644
index 000000000000..0d907e501686
--- /dev/null
+++ b/lib/Analysis/Checker.cpp
@@ -0,0 +1,35 @@
+//== Checker.h - Abstract interface for checkers -----------------*- 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 Checker and CheckerVisitor, classes used for creating
+// domain-specific checks.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/Checker.h"
+using namespace clang;
+
+Checker::~Checker() {}
+
+CheckerContext::~CheckerContext() {
+ // Do we need to autotransition? 'Dst' can get populated in a variety of
+ // ways, including 'addTransition()' adding the predecessor node to Dst
+ // without actually generated a new node. We also shouldn't autotransition
+ // if we are building sinks or we generated a node and decided to not
+ // add it as a transition.
+ if (Dst.size() == size && !B.BuildSinks && !B.HasGeneratedNode) {
+ if (state && state != B.GetState(Pred)) {
+ static int autoTransitionTag = 0;
+ B.Tag = &autoTransitionTag;
+ addTransition(state);
+ }
+ else
+ Dst.Add(Pred);
+ }
+}
diff --git a/lib/Analysis/DereferenceChecker.cpp b/lib/Analysis/DereferenceChecker.cpp
index c3aa8f3a2879..98243874d7d9 100644
--- a/lib/Analysis/DereferenceChecker.cpp
+++ b/lib/Analysis/DereferenceChecker.cpp
@@ -21,7 +21,7 @@
using namespace clang;
namespace {
-class VISIBILITY_HIDDEN DereferenceChecker : public Checker {
+class DereferenceChecker : public Checker {
BuiltinBug *BT_null;
BuiltinBug *BT_undef;
llvm::SmallVector<ExplodedNode*, 2> ImplicitNullDerefNodes;
@@ -56,8 +56,7 @@ 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) {
+ if (ExplodedNode *N = C.GenerateSink()) {
if (!BT_undef)
BT_undef = new BuiltinBug("Dereference of undefined pointer value");
@@ -82,34 +81,55 @@ void DereferenceChecker::VisitLocation(CheckerContext &C, const Stmt *S,
// 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");
-
- EnhancedBugReport *report =
- new EnhancedBugReport(*BT_null, BT_null->getDescription(), N);
- report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
- bugreporter::GetDerefExpr(N));
-
- C.EmitReport(report);
+ if (!notNullState) {
+ // Generate an error node.
+ ExplodedNode *N = C.GenerateSink(nullState);
+ if (!N)
return;
+
+ // We know that 'location' cannot be non-null. This is what
+ // we call an "explicit" null dereference.
+ if (!BT_null)
+ BT_null = new BuiltinBug("Dereference of null pointer");
+
+ llvm::SmallString<100> buf;
+
+ switch (S->getStmtClass()) {
+ case Stmt::UnaryOperatorClass: {
+ const UnaryOperator *U = cast<UnaryOperator>(S);
+ const Expr *SU = U->getSubExpr()->IgnoreParens();
+ if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(SU)) {
+ if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
+ llvm::raw_svector_ostream os(buf);
+ os << "Dereference of null pointer loaded from variable '"
+ << VD->getName() << '\'';
+ }
+ }
+ }
+ default:
+ break;
}
+ EnhancedBugReport *report =
+ new EnhancedBugReport(*BT_null,
+ buf.empty() ? BT_null->getDescription():buf.str(),
+ N);
+
+ report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
+ bugreporter::GetDerefExpr(N));
+
+ C.EmitReport(report);
+ return;
+ }
+ else {
// 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);
+ // dereference.
+ if (ExplodedNode *N = C.GenerateSink(nullState))
+ ImplicitNullDerefNodes.push_back(N);
}
}
// From this point forward, we know that the location is not null.
- assert(notNullState);
- C.addTransition(state != nullState ? C.GenerateNode(S, notNullState) :
- C.getPredecessor());
+ C.addTransition(notNullState);
}
diff --git a/lib/Analysis/DivZeroChecker.cpp b/lib/Analysis/DivZeroChecker.cpp
index a8630f10088e..266c23609422 100644
--- a/lib/Analysis/DivZeroChecker.cpp
+++ b/lib/Analysis/DivZeroChecker.cpp
@@ -18,7 +18,7 @@
using namespace clang;
namespace {
-class VISIBILITY_HIDDEN DivZeroChecker : public CheckerVisitor<DivZeroChecker> {
+class DivZeroChecker : public CheckerVisitor<DivZeroChecker> {
BuiltinBug *BT;
public:
DivZeroChecker() : BT(0) {}
@@ -63,7 +63,7 @@ void DivZeroChecker::PreVisitBinaryOperator(CheckerContext &C,
llvm::tie(stateNotZero, stateZero) = CM.AssumeDual(C.getState(), *DV);
if (stateZero && !stateNotZero) {
- if (ExplodedNode *N = C.GenerateNode(B, stateZero, true)) {
+ if (ExplodedNode *N = C.GenerateSink(stateZero)) {
if (!BT)
BT = new BuiltinBug("Division by zero");
@@ -80,6 +80,5 @@ void DivZeroChecker::PreVisitBinaryOperator(CheckerContext &C,
// If we get here, then the denom should not be zero. We abandon the implicit
// zero denom case for now.
- if (stateNotZero != C.getState())
- C.addTransition(C.GenerateNode(B, stateNotZero));
+ C.addTransition(stateNotZero);
}
diff --git a/lib/Analysis/Environment.cpp b/lib/Analysis/Environment.cpp
index 1610ad4d271d..dd2f08b48f76 100644
--- a/lib/Analysis/Environment.cpp
+++ b/lib/Analysis/Environment.cpp
@@ -12,7 +12,6 @@
//===----------------------------------------------------------------------===//
#include "clang/Analysis/PathSensitive/GRState.h"
#include "clang/Analysis/Analyses/LiveVariables.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/ADT/ImmutableMap.h"
using namespace clang;
@@ -83,7 +82,7 @@ Environment EnvironmentManager::BindExpr(Environment Env, const Stmt *S,
}
namespace {
-class VISIBILITY_HIDDEN MarkLiveCallback : public SymbolVisitor {
+class MarkLiveCallback : public SymbolVisitor {
SymbolReaper &SymReaper;
public:
MarkLiveCallback(SymbolReaper &symreaper) : SymReaper(symreaper) {}
diff --git a/lib/Analysis/FixedAddressChecker.cpp b/lib/Analysis/FixedAddressChecker.cpp
index 80096dcb70d0..031ca44b602e 100644
--- a/lib/Analysis/FixedAddressChecker.cpp
+++ b/lib/Analysis/FixedAddressChecker.cpp
@@ -19,7 +19,7 @@
using namespace clang;
namespace {
-class VISIBILITY_HIDDEN FixedAddressChecker
+class FixedAddressChecker
: public CheckerVisitor<FixedAddressChecker> {
BuiltinBug *BT;
public:
@@ -53,7 +53,7 @@ void FixedAddressChecker::PreVisitBinaryOperator(CheckerContext &C,
if (!RV.isConstant() || RV.isZeroConstant())
return;
- if (ExplodedNode *N = C.GenerateNode(B)) {
+ if (ExplodedNode *N = C.GenerateNode()) {
if (!BT)
BT = new BuiltinBug("Use fixed address",
"Using a fixed address is not portable because that "
diff --git a/lib/Analysis/GRCoreEngine.cpp b/lib/Analysis/GRCoreEngine.cpp
index b99ba4f257ef..644dd199bead 100644
--- a/lib/Analysis/GRCoreEngine.cpp
+++ b/lib/Analysis/GRCoreEngine.cpp
@@ -15,7 +15,6 @@
#include "clang/Analysis/PathSensitive/GRCoreEngine.h"
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
#include "clang/AST/Expr.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/Support/Casting.h"
#include "llvm/ADT/DenseMap.h"
#include <vector>
@@ -30,7 +29,7 @@ using namespace clang;
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN DFS : public GRWorkList {
+class DFS : public GRWorkList {
llvm::SmallVector<GRWorkListUnit,20> Stack;
public:
virtual bool hasWork() const {
@@ -49,7 +48,7 @@ public:
}
};
-class VISIBILITY_HIDDEN BFS : public GRWorkList {
+class BFS : public GRWorkList {
std::queue<GRWorkListUnit> Queue;
public:
virtual bool hasWork() const {
@@ -79,7 +78,7 @@ GRWorkList *GRWorkList::MakeDFS() { return new DFS(); }
GRWorkList *GRWorkList::MakeBFS() { return new BFS(); }
namespace {
- class VISIBILITY_HIDDEN BFSBlockDFSContents : public GRWorkList {
+ class BFSBlockDFSContents : public GRWorkList {
std::queue<GRWorkListUnit> Queue;
llvm::SmallVector<GRWorkListUnit,20> Stack;
public:
diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp
index 26331776141f..20820d4f3833 100644
--- a/lib/Analysis/GRExprEngine.cpp
+++ b/lib/Analysis/GRExprEngine.cpp
@@ -13,6 +13,7 @@
//
//===----------------------------------------------------------------------===//
+#include "GRExprEngineInternalChecks.h"
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
#include "clang/Analysis/PathSensitive/GRExprEngineBuilders.h"
#include "clang/Analysis/PathSensitive/Checker.h"
@@ -22,7 +23,6 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/PrettyStackTrace.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/ImmutableList.h"
#include "llvm/ADT/StringSwitch.h"
@@ -37,12 +37,21 @@ using llvm::cast;
using llvm::APSInt;
//===----------------------------------------------------------------------===//
+// Utility functions.
+//===----------------------------------------------------------------------===//
+
+static inline Selector GetNullarySelector(const char* name, ASTContext& Ctx) {
+ IdentifierInfo* II = &Ctx.Idents.get(name);
+ return Ctx.Selectors.getSelector(0, &II);
+}
+
+//===----------------------------------------------------------------------===//
// Batch auditor. DEPRECATED.
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN MappedBatchAuditor : public GRSimpleAPICheck {
+class MappedBatchAuditor : public GRSimpleAPICheck {
typedef llvm::ImmutableList<GRSimpleAPICheck*> Checks;
typedef llvm::DenseMap<void*,Checks> MapTy;
@@ -107,16 +116,17 @@ public:
// Checker worklist routines.
//===----------------------------------------------------------------------===//
-void GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &Dst,
+bool GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &Dst,
ExplodedNodeSet &Src, bool isPrevisit) {
if (Checkers.empty()) {
- Dst = Src;
- return;
+ Dst.insert(Src);
+ return false;
}
ExplodedNodeSet Tmp;
ExplodedNodeSet *PrevSet = &Src;
+ bool stopProcessingAfterCurrentChecker = false;
for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I)
{
@@ -126,17 +136,33 @@ void GRExprEngine::CheckerVisit(Stmt *S, ExplodedNodeSet &Dst,
CurrSet->clear();
void *tag = I->first;
Checker *checker = I->second;
-
+
for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end();
- NI != NE; ++NI)
- checker->GR_Visit(*CurrSet, *Builder, *this, S, *NI, tag, isPrevisit);
+ NI != NE; ++NI) {
+ // FIXME: Halting evaluation of the checkers is something we may
+ // not support later. The design is still evolving.
+ if (checker->GR_Visit(*CurrSet, *Builder, *this, S, *NI,
+ tag, isPrevisit)) {
+ if (CurrSet != &Dst)
+ Dst.insert(*CurrSet);
+
+ stopProcessingAfterCurrentChecker = true;
+ continue;
+ }
+ assert(stopProcessingAfterCurrentChecker == false &&
+ "Inconsistent setting of 'stopProcessingAfterCurrentChecker'");
+ }
+
+ if (stopProcessingAfterCurrentChecker)
+ return true;
- // Update which NodeSet is the current one.
+ // Continue on to the next checker. Update the current NodeSet.
PrevSet = CurrSet;
}
// Don't autotransition. The CheckerContext objects should do this
// automatically.
+ return false;
}
// FIXME: This is largely copy-paste from CheckerVisit(). Need to
@@ -179,12 +205,30 @@ void GRExprEngine::CheckerVisitBind(const Stmt *AssignE, const Stmt *StoreE,
// Engine construction and deletion.
//===----------------------------------------------------------------------===//
-static inline Selector GetNullarySelector(const char* name, ASTContext& Ctx) {
- IdentifierInfo* II = &Ctx.Idents.get(name);
- return Ctx.Selectors.getSelector(0, &II);
+static void RegisterInternalChecks(GRExprEngine &Eng) {
+ // Register internal "built-in" BugTypes with the BugReporter. These BugTypes
+ // are different than what probably many checks will do since they don't
+ // create BugReports on-the-fly but instead wait until GRExprEngine finishes
+ // analyzing a function. Generation of BugReport objects is done via a call
+ // to 'FlushReports' from BugReporter.
+ // The following checks do not need to have their associated BugTypes
+ // 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.
+ RegisterAttrNonNullChecker(Eng);
+ RegisterCallAndMessageChecker(Eng);
+ RegisterDereferenceChecker(Eng);
+ RegisterVLASizeChecker(Eng);
+ RegisterDivZeroChecker(Eng);
+ RegisterReturnStackAddressChecker(Eng);
+ RegisterReturnUndefChecker(Eng);
+ RegisterUndefinedArraySubscriptChecker(Eng);
+ RegisterUndefinedAssignmentChecker(Eng);
+ RegisterUndefBranchChecker(Eng);
+ RegisterUndefResultChecker(Eng);
}
-
GRExprEngine::GRExprEngine(AnalysisManager &mgr)
: AMgr(mgr),
CoreEngine(mgr.getASTContext(), *this),
@@ -198,7 +242,11 @@ GRExprEngine::GRExprEngine(AnalysisManager &mgr)
CurrentStmt(NULL),
NSExceptionII(NULL), NSExceptionInstanceRaiseSelectors(NULL),
RaiseSel(GetNullarySelector("raise", G.getContext())),
- BR(mgr, *this) {}
+ BR(mgr, *this)
+{
+ // Register internal checks.
+ RegisterInternalChecks(*this);
+}
GRExprEngine::~GRExprEngine() {
BR.FlushReports();
@@ -211,7 +259,6 @@ GRExprEngine::~GRExprEngine() {
// Utility methods.
//===----------------------------------------------------------------------===//
-
void GRExprEngine::setTransferFunctions(GRTransferFuncs* tf) {
StateMgr.TF = tf;
tf->RegisterChecks(*this);
@@ -410,6 +457,10 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) {
VisitAsmStmt(cast<AsmStmt>(S), Pred, Dst);
break;
+ case Stmt::BlockExprClass:
+ VisitBlockExpr(cast<BlockExpr>(S), Pred, Dst);
+ break;
+
case Stmt::BinaryOperatorClass: {
BinaryOperator* B = cast<BinaryOperator>(S);
@@ -771,55 +822,49 @@ void GRExprEngine::ProcessBranch(Stmt* Condition, Stmt* Term,
Condition->getLocStart(),
"Error evaluating branch");
- const GRState* PrevState = builder.getState();
- SVal X = PrevState->getSVal(Condition);
- DefinedSVal *V = NULL;
-
- while (true) {
- V = dyn_cast<DefinedSVal>(&X);
-
- if (!V) {
- if (X.isUnknown()) {
- if (const Expr *Ex = dyn_cast<Expr>(Condition)) {
- if (Ex->getType()->isIntegerType()) {
- // Try to recover some path-sensitivity. Right now casts of symbolic
- // integers that promote their values are currently not tracked well.
- // If 'Condition' is such an expression, try and recover the
- // underlying value and use that instead.
- SVal recovered = RecoverCastedSymbol(getStateManager(),
- builder.getState(), Condition,
- getContext());
-
- if (!recovered.isUnknown()) {
- X = recovered;
- continue;
- }
- }
- }
+ for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end();I!=E;++I) {
+ void *tag = I->first;
+ Checker *checker = I->second;
+ checker->VisitBranchCondition(builder, *this, Condition, tag);
+ }
- builder.generateNode(MarkBranch(PrevState, Term, true), true);
- builder.generateNode(MarkBranch(PrevState, Term, false), false);
- return;
- }
+ // If the branch condition is undefined, return;
+ if (!builder.isFeasible(true) && !builder.isFeasible(false))
+ return;
- assert(X.isUndef());
- ExplodedNode *N = builder.generateNode(PrevState, true);
+ const GRState* PrevState = builder.getState();
+ SVal X = PrevState->getSVal(Condition);
- if (N) {
- N->markAsSink();
- UndefBranches.insert(N);
+ if (X.isUnknown()) {
+ // Give it a chance to recover from unknown.
+ if (const Expr *Ex = dyn_cast<Expr>(Condition)) {
+ if (Ex->getType()->isIntegerType()) {
+ // Try to recover some path-sensitivity. Right now casts of symbolic
+ // integers that promote their values are currently not tracked well.
+ // If 'Condition' is such an expression, try and recover the
+ // underlying value and use that instead.
+ SVal recovered = RecoverCastedSymbol(getStateManager(),
+ builder.getState(), Condition,
+ getContext());
+
+ if (!recovered.isUnknown()) {
+ X = recovered;
+ }
}
-
- builder.markInfeasible(false);
+ }
+ // If the condition is still unknown, give up.
+ if (X.isUnknown()) {
+ builder.generateNode(MarkBranch(PrevState, Term, true), true);
+ builder.generateNode(MarkBranch(PrevState, Term, false), false);
return;
}
-
- break;
}
+ DefinedSVal V = cast<DefinedSVal>(X);
+
// Process the true branch.
if (builder.isFeasible(true)) {
- if (const GRState *state = PrevState->Assume(*V, true))
+ if (const GRState *state = PrevState->Assume(V, true))
builder.generateNode(MarkBranch(state, Term, true), true);
else
builder.markInfeasible(true);
@@ -827,7 +872,7 @@ void GRExprEngine::ProcessBranch(Stmt* Condition, Stmt* Term,
// Process the false branch.
if (builder.isFeasible(false)) {
- if (const GRState *state = PrevState->Assume(*V, false))
+ if (const GRState *state = PrevState->Assume(V, false))
builder.generateNode(MarkBranch(state, Term, false), false);
else
builder.markInfeasible(false);
@@ -866,8 +911,9 @@ void GRExprEngine::ProcessIndirectGoto(GRIndirectGotoNodeBuilder& builder) {
if (isa<loc::ConcreteInt>(V) || isa<UndefinedVal>(V)) {
// Dispatch to the first target and mark it as a sink.
- ExplodedNode* N = builder.generateNode(builder.begin(), state, true);
- UndefBranches.insert(N);
+ //ExplodedNode* N = builder.generateNode(builder.begin(), state, true);
+ // FIXME: add checker visit.
+ // UndefBranches.insert(N);
return;
}
@@ -918,8 +964,10 @@ void GRExprEngine::ProcessSwitch(GRSwitchNodeBuilder& builder) {
SVal CondV_untested = state->getSVal(CondE);
if (CondV_untested.isUndef()) {
- ExplodedNode* N = builder.generateDefaultCaseNode(state, true);
- UndefBranches.insert(N);
+ //ExplodedNode* N = builder.generateDefaultCaseNode(state, true);
+ // FIXME: add checker
+ //UndefBranches.insert(N);
+
return;
}
DefinedOrUnknownSVal CondV = cast<DefinedOrUnknownSVal>(CondV_untested);
@@ -1052,6 +1100,22 @@ void GRExprEngine::VisitLogicalExpr(BinaryOperator* B, ExplodedNode* Pred,
// Transfer functions: Loads and stores.
//===----------------------------------------------------------------------===//
+void GRExprEngine::VisitBlockExpr(BlockExpr *BE, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+
+ ExplodedNodeSet Tmp;
+
+ CanQualType T = getContext().getCanonicalType(BE->getType());
+ SVal V = ValMgr.getBlockPointer(BE->getBlockDecl(), T,
+ Pred->getLocationContext());
+
+ MakeNode(Tmp, BE, Pred, GetState(Pred)->BindExpr(BE, V),
+ ProgramPoint::PostLValueKind);
+
+ // Post-visit the BlockExpr.
+ CheckerVisit(BE, Dst, Tmp, false);
+}
+
void GRExprEngine::VisitDeclRefExpr(DeclRefExpr *Ex, ExplodedNode *Pred,
ExplodedNodeSet &Dst, bool asLValue) {
@@ -1278,7 +1342,7 @@ void GRExprEngine::EvalLocation(ExplodedNodeSet &Dst, Stmt *S,
ExplodedNode* Pred,
const GRState* state, SVal location,
const void *tag, bool isLoad) {
-
+ // Early checks for performance reason.
if (location.isUnknown() || Checkers.empty()) {
Dst.Add(Pred);
return;
@@ -1298,9 +1362,13 @@ void GRExprEngine::EvalLocation(ExplodedNodeSet &Dst, Stmt *S,
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,
+ NI != NE; ++NI) {
+ // Use the 'state' argument only when the predecessor node is the
+ // same as Pred. This allows us to catch updates to the state.
+ checker->GR_VisitLocation(*CurrSet, *Builder, *this, S, *NI,
+ *NI == Pred ? state : GetState(*NI),
location, tag, isLoad);
+ }
// Update which NodeSet is the current one.
PrevSet = CurrSet;
@@ -1850,197 +1918,89 @@ void GRExprEngine::VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME,
ExplodedNode* Pred,
ExplodedNodeSet& Dst) {
- // FIXME: More logic for the processing the method call.
-
- const GRState* state = GetState(Pred);
- bool RaisesException = false;
-
-
- if (Expr* Receiver = ME->getReceiver()) {
-
- SVal L_untested = state->getSVal(Receiver);
-
- // Check for undefined control-flow.
- if (L_untested.isUndef()) {
- ExplodedNode* N = Builder->generateNode(ME, state, Pred);
-
- if (N) {
- N->markAsSink();
- UndefReceivers.insert(N);
- }
-
- return;
- }
-
- // "Assume" that the receiver is not NULL.
- DefinedOrUnknownSVal L = cast<DefinedOrUnknownSVal>(L_untested);
- const GRState *StNotNull = state->Assume(L, true);
-
- // "Assume" that the receiver is NULL.
- const GRState *StNull = state->Assume(L, false);
-
- if (StNull) {
- QualType RetTy = ME->getType();
-
- // Check if the receiver was nil and the return value a struct.
- if (RetTy->isRecordType()) {
- if (Pred->getParentMap().isConsumedExpr(ME)) {
- // The [0 ...] expressions will return garbage. Flag either an
- // explicit or implicit error. Because of the structure of this
- // function we currently do not bifurfacte the state graph at
- // this point.
- // FIXME: We should bifurcate and fill the returned struct with
- // garbage.
- if (ExplodedNode* N = Builder->generateNode(ME, StNull, Pred)) {
- N->markAsSink();
- if (StNotNull)
- NilReceiverStructRetImplicit.insert(N);
- else
- NilReceiverStructRetExplicit.insert(N);
- }
- }
- }
- else {
- ASTContext& Ctx = getContext();
- if (RetTy != Ctx.VoidTy) {
- if (Pred->getParentMap().isConsumedExpr(ME)) {
- // sizeof(void *)
- const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);
- // sizeof(return type)
- const uint64_t returnTypeSize = Ctx.getTypeSize(ME->getType());
-
- if (voidPtrSize < returnTypeSize) {
- if (ExplodedNode* N = Builder->generateNode(ME, StNull, Pred)) {
- N->markAsSink();
- if (StNotNull)
- NilReceiverLargerThanVoidPtrRetImplicit.insert(N);
- else
- NilReceiverLargerThanVoidPtrRetExplicit.insert(N);
- }
- }
- else if (!StNotNull) {
- // Handle the safe cases where the return value is 0 if the
- // receiver is nil.
- //
- // FIXME: For now take the conservative approach that we only
- // return null values if we *know* that the receiver is nil.
- // This is because we can have surprises like:
- //
- // ... = [[NSScreens screens] objectAtIndex:0];
- //
- // What can happen is that [... screens] could return nil, but
- // it most likely isn't nil. We should assume the semantics
- // of this case unless we have *a lot* more knowledge.
- //
- SVal V = ValMgr.makeZeroVal(ME->getType());
- MakeNode(Dst, ME, Pred, StNull->BindExpr(ME, V));
- return;
- }
- }
- }
- }
- // We have handled the cases where the receiver is nil. The remainder
- // of this method should assume that the receiver is not nil.
- if (!StNotNull)
- return;
-
- state = StNotNull;
- }
-
- // Check if the "raise" message was sent.
- if (ME->getSelector() == RaiseSel)
- RaisesException = true;
+ // Handle previsits checks.
+ ExplodedNodeSet Src, DstTmp;
+ Src.Add(Pred);
+
+ if (CheckerVisit(ME, DstTmp, Src, true)) {
+ Dst.insert(DstTmp);
+ return;
}
- else {
-
- IdentifierInfo* ClsName = ME->getClassName();
- Selector S = ME->getSelector();
-
- // Check for special instance methods.
+
+ unsigned size = Dst.size();
- if (!NSExceptionII) {
- ASTContext& Ctx = getContext();
+ for (ExplodedNodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end();
+ DI!=DE; ++DI) {
+ Pred = *DI;
+ bool RaisesException = false;
- NSExceptionII = &Ctx.Idents.get("NSException");
+ if (ME->getReceiver()) {
+ // Check if the "raise" message was sent.
+ if (ME->getSelector() == RaiseSel)
+ RaisesException = true;
}
+ else {
- if (ClsName == NSExceptionII) {
-
- enum { NUM_RAISE_SELECTORS = 2 };
-
- // Lazily create a cache of the selectors.
+ IdentifierInfo* ClsName = ME->getClassName();
+ Selector S = ME->getSelector();
- if (!NSExceptionInstanceRaiseSelectors) {
+ // Check for special instance methods.
+ if (!NSExceptionII) {
ASTContext& Ctx = getContext();
- NSExceptionInstanceRaiseSelectors = new Selector[NUM_RAISE_SELECTORS];
+ NSExceptionII = &Ctx.Idents.get("NSException");
+ }
- llvm::SmallVector<IdentifierInfo*, NUM_RAISE_SELECTORS> II;
- unsigned idx = 0;
+ if (ClsName == NSExceptionII) {
- // raise:format:
- II.push_back(&Ctx.Idents.get("raise"));
- II.push_back(&Ctx.Idents.get("format"));
- NSExceptionInstanceRaiseSelectors[idx++] =
- Ctx.Selectors.getSelector(II.size(), &II[0]);
+ enum { NUM_RAISE_SELECTORS = 2 };
- // raise:format::arguments:
- II.push_back(&Ctx.Idents.get("arguments"));
- NSExceptionInstanceRaiseSelectors[idx++] =
- Ctx.Selectors.getSelector(II.size(), &II[0]);
- }
+ // Lazily create a cache of the selectors.
- for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i)
- if (S == NSExceptionInstanceRaiseSelectors[i]) {
- RaisesException = true; break;
- }
- }
- }
+ if (!NSExceptionInstanceRaiseSelectors) {
- // Check for any arguments that are uninitialized/undefined.
+ ASTContext& Ctx = getContext();
- for (ObjCMessageExpr::arg_iterator I = ME->arg_begin(), E = ME->arg_end();
- I != E; ++I) {
+ NSExceptionInstanceRaiseSelectors = new Selector[NUM_RAISE_SELECTORS];
- if (state->getSVal(*I).isUndef()) {
+ llvm::SmallVector<IdentifierInfo*, NUM_RAISE_SELECTORS> II;
+ unsigned idx = 0;
- // Generate an error node for passing an uninitialized/undefined value
- // as an argument to a message expression. This node is a sink.
- ExplodedNode* N = Builder->generateNode(ME, state, Pred);
+ // raise:format:
+ II.push_back(&Ctx.Idents.get("raise"));
+ II.push_back(&Ctx.Idents.get("format"));
+ NSExceptionInstanceRaiseSelectors[idx++] =
+ Ctx.Selectors.getSelector(II.size(), &II[0]);
- if (N) {
- N->markAsSink();
- MsgExprUndefArgs[N] = *I;
- }
+ // raise:format::arguments:
+ II.push_back(&Ctx.Idents.get("arguments"));
+ NSExceptionInstanceRaiseSelectors[idx++] =
+ Ctx.Selectors.getSelector(II.size(), &II[0]);
+ }
- return;
+ for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i)
+ if (S == NSExceptionInstanceRaiseSelectors[i]) {
+ RaisesException = true; break;
+ }
+ }
}
- }
- // Handle previsits checks.
- ExplodedNodeSet Src, DstTmp;
- Src.Add(Pred);
- CheckerVisit(ME, DstTmp, Src, true);
-
- // Check if we raise an exception. For now treat these as sinks. Eventually
- // we will want to handle exceptions properly.
- SaveAndRestore<bool> OldSink(Builder->BuildSinks);
- if (RaisesException)
- Builder->BuildSinks = true;
+ // Check if we raise an exception. For now treat these as sinks. Eventually
+ // we will want to handle exceptions properly.
+ SaveAndRestore<bool> OldSink(Builder->BuildSinks);
+ if (RaisesException)
+ Builder->BuildSinks = true;
- // Dispatch to plug-in transfer function.
- unsigned size = Dst.size();
- SaveOr OldHasGen(Builder->HasGeneratedNode);
-
- for (ExplodedNodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end();
- DI!=DE; ++DI)
- EvalObjCMessageExpr(Dst, ME, *DI);
+ // Dispatch to plug-in transfer function.
+ SaveOr OldHasGen(Builder->HasGeneratedNode);
+ EvalObjCMessageExpr(Dst, ME, 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 && !Builder->HasGeneratedNode)
- MakeNode(Dst, ME, Pred, state);
+ MakeNode(Dst, ME, Pred, GetState(Pred));
}
//===----------------------------------------------------------------------===//
@@ -2157,7 +2117,7 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred,
namespace {
// This class is used by VisitInitListExpr as an item in a worklist
// for processing the values contained in an InitListExpr.
-class VISIBILITY_HIDDEN InitListWLItem {
+class InitListWLItem {
public:
llvm::ImmutableList<SVal> Vals;
ExplodedNode* N;
@@ -2246,8 +2206,6 @@ void GRExprEngine::VisitInitListExpr(InitListExpr* E, ExplodedNode* Pred,
return;
}
-
- printf("InitListExpr type = %s\n", T.getAsString().c_str());
assert(0 && "unprocessed InitListExpr type");
}
@@ -2689,6 +2647,8 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
else
Visit(LHS, Pred, Tmp1);
+ ExplodedNodeSet Tmp3;
+
for (ExplodedNodeSet::iterator I1=Tmp1.begin(), E1=Tmp1.end(); I1!=E1; ++I1) {
SVal LeftV = (*I1)->getState()->getSVal(LHS);
ExplodedNodeSet Tmp2;
@@ -2723,7 +2683,7 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
// Simulate the effects of a "store": bind the value of the RHS
// to the L-Value represented by the LHS.
- EvalStore(Dst, B, LHS, *I2, state->BindExpr(B, ExprVal), LeftV, RightV);
+ EvalStore(Tmp3, B, LHS, *I2, state->BindExpr(B, ExprVal), LeftV, RightV);
continue;
}
@@ -2735,28 +2695,17 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
if (Result.isUnknown()) {
if (OldSt != state) {
// Generate a new node if we have already created a new state.
- MakeNode(Dst, B, *I2, state);
+ MakeNode(Tmp3, B, *I2, state);
}
else
- Dst.Add(*I2);
+ Tmp3.Add(*I2);
continue;
}
state = state->BindExpr(B, Result);
- if (Result.isUndef()) {
- // The operands were *not* undefined, but the result is undefined.
- // This is a special node that should be flagged as an error.
- if (ExplodedNode *UndefNode = Builder->generateNode(B, state, *I2)){
- UndefNode->markAsSink();
- UndefResults.insert(UndefNode);
- }
- continue;
- }
-
- // Otherwise, create a new node.
- MakeNode(Dst, B, *I2, state);
+ MakeNode(Tmp3, B, *I2, state);
continue;
}
@@ -2809,15 +2758,6 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
RightV, CTy),
state, B->getType(), CTy);
- if (Result.isUndef()) {
- // The operands were not undefined, but the result is undefined.
- if (ExplodedNode* UndefNode = Builder->generateNode(B, state, *I3)) {
- UndefNode->markAsSink();
- UndefResults.insert(UndefNode);
- }
- continue;
- }
-
// EXPERIMENTAL: "Conjured" symbols.
// FIXME: Handle structs.
@@ -2844,11 +2784,13 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
llvm::tie(state, LHSVal) = SVator.EvalCast(Result, state, LTy, CTy);
}
- EvalStore(Dst, B, LHS, *I3, state->BindExpr(B, Result),
+ EvalStore(Tmp3, B, LHS, *I3, state->BindExpr(B, Result),
location, LHSVal);
}
}
}
+
+ CheckerVisit(B, Dst, Tmp3, false);
}
//===----------------------------------------------------------------------===//
@@ -2870,8 +2812,11 @@ static SourceManager* GraphPrintSourceManager;
namespace llvm {
template<>
-struct VISIBILITY_HIDDEN DOTGraphTraits<ExplodedNode*> :
+struct DOTGraphTraits<ExplodedNode*> :
public DefaultDOTGraphTraits {
+
+ DOTGraphTraits (bool isSimple=false) : DefaultDOTGraphTraits(isSimple) {}
+
// FIXME: Since we do not cache error nodes in GRExprEngine now, this does not
// work.
static std::string getNodeAttributes(const ExplodedNode* N, void*) {
@@ -2888,15 +2833,14 @@ 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\"";
-
+#endif
return "";
}
- static std::string getNodeLabel(const ExplodedNode* N, void*,bool ShortNames){
+ static std::string getNodeLabel(const ExplodedNode* N, void*){
std::string sbuf;
llvm::raw_string_ostream Out(sbuf);
diff --git a/lib/Analysis/GRExprEngineExperimentalChecks.cpp b/lib/Analysis/GRExprEngineExperimentalChecks.cpp
index 2fb7e9fa482f..33479b0cb7e5 100644
--- a/lib/Analysis/GRExprEngineExperimentalChecks.cpp
+++ b/lib/Analysis/GRExprEngineExperimentalChecks.cpp
@@ -31,6 +31,8 @@ void clang::RegisterExperimentalInternalChecks(GRExprEngine &Eng) {
// Note that this must be registered after ReturnStackAddresEngsChecker.
RegisterReturnPointerRangeChecker(Eng);
+
+ RegisterFixedAddressChecker(Eng);
RegisterPointerSubChecker(Eng);
RegisterPointerArithChecker(Eng);
RegisterCastToStructChecker(Eng);
diff --git a/lib/Analysis/GRExprEngineInternalChecks.cpp b/lib/Analysis/GRExprEngineInternalChecks.cpp
deleted file mode 100644
index d0f60fde5b1b..000000000000
--- a/lib/Analysis/GRExprEngineInternalChecks.cpp
+++ /dev/null
@@ -1,400 +0,0 @@
-//=-- GRExprEngineInternalChecks.cpp - 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 the BugType classes used by GRExprEngine to report
-// bugs derived from builtin checks in the path-sensitive engine.
-//
-//===----------------------------------------------------------------------===//
-
-#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/UndefinedAssignmentChecker.h"
-#include "clang/Analysis/PathDiagnostic.h"
-#include "clang/Basic/SourceManager.h"
-#include "llvm/Support/Compiler.h"
-#include "llvm/Support/raw_ostream.h"
-
-using namespace clang;
-using namespace clang::bugreporter;
-
-//===----------------------------------------------------------------------===//
-// Utility functions.
-//===----------------------------------------------------------------------===//
-
-template <typename ITERATOR> inline
-ExplodedNode* GetNode(ITERATOR I) {
- return *I;
-}
-
-template <> inline
-ExplodedNode* GetNode(GRExprEngine::undef_arg_iterator I) {
- return I->first;
-}
-
-//===----------------------------------------------------------------------===//
-// Bug Descriptions.
-//===----------------------------------------------------------------------===//
-namespace clang {
-class BuiltinBugReport : public RangedBugReport {
-public:
- BuiltinBugReport(BugType& bt, const char* desc,
- ExplodedNode *n)
- : RangedBugReport(bt, desc, n) {}
-
- BuiltinBugReport(BugType& bt, const char *shortDesc, const char *desc,
- ExplodedNode *n)
- : RangedBugReport(bt, shortDesc, desc, n) {}
-
- void registerInitialVisitors(BugReporterContext& BRC,
- const ExplodedNode* N);
-};
-
-void BuiltinBugReport::registerInitialVisitors(BugReporterContext& BRC,
- const ExplodedNode* N) {
- static_cast<BuiltinBug&>(getBugType()).registerInitialVisitors(BRC, N, this);
-}
-
-template <typename ITER>
-void BuiltinBug::Emit(BugReporter& BR, ITER I, ITER E) {
- for (; I != E; ++I) BR.EmitReport(new BuiltinBugReport(*this, desc.c_str(),
- GetNode(I)));
-}
-
-class VISIBILITY_HIDDEN NilReceiverStructRet : public BuiltinBug {
-public:
- NilReceiverStructRet(GRExprEngine* eng) :
- BuiltinBug(eng, "'nil' receiver with struct return type") {}
-
- void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
- for (GRExprEngine::nil_receiver_struct_ret_iterator
- I=Eng.nil_receiver_struct_ret_begin(),
- E=Eng.nil_receiver_struct_ret_end(); I!=E; ++I) {
-
- std::string sbuf;
- llvm::raw_string_ostream os(sbuf);
- PostStmt P = cast<PostStmt>((*I)->getLocation());
- const ObjCMessageExpr *ME = cast<ObjCMessageExpr>(P.getStmt());
- os << "The receiver in the message expression is 'nil' and results in the"
- " returned value (of type '"
- << ME->getType().getAsString()
- << "') to be garbage or otherwise undefined";
-
- BuiltinBugReport *R = new BuiltinBugReport(*this, os.str().c_str(), *I);
- R->addRange(ME->getReceiver()->getSourceRange());
- BR.EmitReport(R);
- }
- }
-
- void registerInitialVisitors(BugReporterContext& BRC,
- const ExplodedNode* N,
- BuiltinBugReport *R) {
- registerTrackNullOrUndefValue(BRC, GetReceiverExpr(N), N);
- }
-};
-
-class VISIBILITY_HIDDEN NilReceiverLargerThanVoidPtrRet : public BuiltinBug {
-public:
- NilReceiverLargerThanVoidPtrRet(GRExprEngine* eng) :
- BuiltinBug(eng,
- "'nil' receiver with return type larger than sizeof(void *)") {}
-
- void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
- for (GRExprEngine::nil_receiver_larger_than_voidptr_ret_iterator
- I=Eng.nil_receiver_larger_than_voidptr_ret_begin(),
- E=Eng.nil_receiver_larger_than_voidptr_ret_end(); I!=E; ++I) {
-
- std::string sbuf;
- llvm::raw_string_ostream os(sbuf);
- PostStmt P = cast<PostStmt>((*I)->getLocation());
- const ObjCMessageExpr *ME = cast<ObjCMessageExpr>(P.getStmt());
- os << "The receiver in the message expression is 'nil' and results in the"
- " returned value (of type '"
- << ME->getType().getAsString()
- << "' and of size "
- << Eng.getContext().getTypeSize(ME->getType()) / 8
- << " bytes) to be garbage or otherwise undefined";
-
- BuiltinBugReport *R = new BuiltinBugReport(*this, os.str().c_str(), *I);
- R->addRange(ME->getReceiver()->getSourceRange());
- BR.EmitReport(R);
- }
- }
- void registerInitialVisitors(BugReporterContext& BRC,
- const ExplodedNode* N,
- BuiltinBugReport *R) {
- registerTrackNullOrUndefValue(BRC, GetReceiverExpr(N), N);
- }
-};
-
-class VISIBILITY_HIDDEN UndefResult : public BuiltinBug {
-public:
- UndefResult(GRExprEngine* eng)
- : BuiltinBug(eng,"Undefined or garbage result",
- "Result of operation is garbage or undefined") {}
-
- void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
- for (GRExprEngine::undef_result_iterator I=Eng.undef_results_begin(),
- E = Eng.undef_results_end(); I!=E; ++I) {
-
- ExplodedNode *N = *I;
- const Stmt *S = N->getLocationAs<PostStmt>()->getStmt();
- BuiltinBugReport *report = NULL;
-
- if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S)) {
- llvm::SmallString<256> sbuf;
- llvm::raw_svector_ostream OS(sbuf);
- const GRState *ST = N->getState();
- const Expr *Ex = NULL;
- bool isLeft = true;
-
- if (ST->getSVal(B->getLHS()).isUndef()) {
- Ex = B->getLHS()->IgnoreParenCasts();
- isLeft = true;
- }
- else if (ST->getSVal(B->getRHS()).isUndef()) {
- Ex = B->getRHS()->IgnoreParenCasts();
- isLeft = false;
- }
-
- if (Ex) {
- OS << "The " << (isLeft ? "left" : "right")
- << " operand of '"
- << BinaryOperator::getOpcodeStr(B->getOpcode())
- << "' is a garbage value";
- }
- else {
- // Neither operand was undefined, but the result is undefined.
- OS << "The result of the '"
- << BinaryOperator::getOpcodeStr(B->getOpcode())
- << "' expression is undefined";
- }
-
- // FIXME: Use StringRefs to pass string information.
- report = new BuiltinBugReport(*this, OS.str().str().c_str(), N);
- if (Ex) report->addRange(Ex->getSourceRange());
- }
- else {
- report = new BuiltinBugReport(*this,
- "Expression evaluates to an uninitialized"
- " or undefined value", N);
- }
-
- BR.EmitReport(report);
- }
- }
-
- void registerInitialVisitors(BugReporterContext& BRC,
- const ExplodedNode* N,
- BuiltinBugReport *R) {
-
- const Stmt *S = N->getLocationAs<StmtPoint>()->getStmt();
- const Stmt *X = S;
-
- if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S)) {
- const GRState *ST = N->getState();
- if (ST->getSVal(B->getLHS()).isUndef())
- X = B->getLHS();
- else if (ST->getSVal(B->getRHS()).isUndef())
- X = B->getRHS();
- }
-
- registerTrackNullOrUndefValue(BRC, X, N);
- }
-};
-
-class VISIBILITY_HIDDEN ArgReport : public BuiltinBugReport {
- const Stmt *Arg;
-public:
- ArgReport(BugType& bt, const char* desc, ExplodedNode *n,
- const Stmt *arg)
- : BuiltinBugReport(bt, desc, n), Arg(arg) {}
-
- ArgReport(BugType& bt, const char *shortDesc, const char *desc,
- ExplodedNode *n, const Stmt *arg)
- : BuiltinBugReport(bt, shortDesc, desc, n), Arg(arg) {}
-
- const Stmt *getArg() const { return Arg; }
-};
-
-class VISIBILITY_HIDDEN BadArg : public BuiltinBug {
-public:
- BadArg(GRExprEngine* eng=0) : BuiltinBug(eng,"Uninitialized argument",
- "Pass-by-value argument in function call is undefined") {}
-
- BadArg(GRExprEngine* eng, const char* d)
- : BuiltinBug(eng,"Uninitialized argument", d) {}
-
- void registerInitialVisitors(BugReporterContext& BRC,
- const ExplodedNode* N,
- BuiltinBugReport *R) {
- registerTrackNullOrUndefValue(BRC, static_cast<ArgReport*>(R)->getArg(),
- N);
- }
-};
-
-class VISIBILITY_HIDDEN BadMsgExprArg : public BadArg {
-public:
- BadMsgExprArg(GRExprEngine* eng)
- : BadArg(eng,"Pass-by-value argument in message expression is undefined"){}
-
- void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
- for (GRExprEngine::UndefArgsTy::iterator I=Eng.msg_expr_undef_arg_begin(),
- E = Eng.msg_expr_undef_arg_end(); I!=E; ++I) {
- // Generate a report for this bug.
- ArgReport *report = new ArgReport(*this, desc.c_str(), I->first,
- I->second);
- report->addRange(I->second->getSourceRange());
- BR.EmitReport(report);
- }
- }
-};
-
-class VISIBILITY_HIDDEN BadReceiver : public BuiltinBug {
-public:
- BadReceiver(GRExprEngine* eng)
- : BuiltinBug(eng,"Uninitialized receiver",
- "Receiver in message expression is an uninitialized value") {}
-
- void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
- for (GRExprEngine::ErrorNodes::iterator I=Eng.undef_receivers_begin(),
- End = Eng.undef_receivers_end(); I!=End; ++I) {
-
- // Generate a report for this bug.
- BuiltinBugReport *report = new BuiltinBugReport(*this, desc.c_str(), *I);
- ExplodedNode* N = *I;
- const Stmt *S = cast<PostStmt>(N->getLocation()).getStmt();
- const Expr* E = cast<ObjCMessageExpr>(S)->getReceiver();
- assert (E && "Receiver cannot be NULL");
- report->addRange(E->getSourceRange());
- BR.EmitReport(report);
- }
- }
-
- void registerInitialVisitors(BugReporterContext& BRC,
- const ExplodedNode* N,
- BuiltinBugReport *R) {
- registerTrackNullOrUndefValue(BRC, GetReceiverExpr(N), N);
- }
-};
-
-class VISIBILITY_HIDDEN UndefBranch : public BuiltinBug {
- struct VISIBILITY_HIDDEN FindUndefExpr {
- GRStateManager& VM;
- const GRState* St;
-
- FindUndefExpr(GRStateManager& V, const GRState* S) : VM(V), St(S) {}
-
- Expr* FindExpr(Expr* Ex) {
- if (!MatchesCriteria(Ex))
- return 0;
-
- for (Stmt::child_iterator I=Ex->child_begin(), E=Ex->child_end();I!=E;++I)
- if (Expr* ExI = dyn_cast_or_null<Expr>(*I)) {
- Expr* E2 = FindExpr(ExI);
- if (E2) return E2;
- }
-
- return Ex;
- }
-
- bool MatchesCriteria(Expr* Ex) { return St->getSVal(Ex).isUndef(); }
- };
-
-public:
- UndefBranch(GRExprEngine *eng)
- : BuiltinBug(eng,"Use of garbage value",
- "Branch condition evaluates to an undefined or garbage value")
- {}
-
- void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
- for (GRExprEngine::undef_branch_iterator I=Eng.undef_branches_begin(),
- E=Eng.undef_branches_end(); I!=E; ++I) {
-
- // What's going on here: we want to highlight the subexpression of the
- // condition that is the most likely source of the "uninitialized
- // branch condition." We do a recursive walk of the condition's
- // subexpressions and roughly look for the most nested subexpression
- // that binds to Undefined. We then highlight that expression's range.
- BlockEdge B = cast<BlockEdge>((*I)->getLocation());
- Expr* Ex = cast<Expr>(B.getSrc()->getTerminatorCondition());
- assert (Ex && "Block must have a terminator.");
-
- // Get the predecessor node and check if is a PostStmt with the Stmt
- // being the terminator condition. We want to inspect the state
- // of that node instead because it will contain main information about
- // the subexpressions.
- assert (!(*I)->pred_empty());
-
- // Note: any predecessor will do. They should have identical state,
- // since all the BlockEdge did was act as an error sink since the value
- // had to already be undefined.
- ExplodedNode *N = *(*I)->pred_begin();
- ProgramPoint P = N->getLocation();
- const GRState* St = (*I)->getState();
-
- if (PostStmt* PS = dyn_cast<PostStmt>(&P))
- if (PS->getStmt() == Ex)
- St = N->getState();
-
- FindUndefExpr FindIt(Eng.getStateManager(), St);
- Ex = FindIt.FindExpr(Ex);
-
- ArgReport *R = new ArgReport(*this, desc.c_str(), *I, Ex);
- R->addRange(Ex->getSourceRange());
- BR.EmitReport(R);
- }
- }
-
- void registerInitialVisitors(BugReporterContext& BRC,
- const ExplodedNode* N,
- BuiltinBugReport *R) {
- registerTrackNullOrUndefValue(BRC, static_cast<ArgReport*>(R)->getArg(),
- N);
- }
-};
-
-} // end clang namespace
-
-//===----------------------------------------------------------------------===//
-// Check registration.
-//===----------------------------------------------------------------------===//
-
-void GRExprEngine::RegisterInternalChecks() {
- // Register internal "built-in" BugTypes with the BugReporter. These BugTypes
- // are different than what probably many checks will do since they don't
- // create BugReports on-the-fly but instead wait until GRExprEngine finishes
- // analyzing a function. Generation of BugReport objects is done via a call
- // to 'FlushReports' from BugReporter.
- BR.Register(new UndefBranch(this));
- BR.Register(new UndefResult(this));
- BR.Register(new BadMsgExprArg(this));
- BR.Register(new BadReceiver(this));
- BR.Register(new NilReceiverStructRet(this));
- BR.Register(new NilReceiverLargerThanVoidPtrRet(this));
-
- // The following checks do not need to have their associated BugTypes
- // 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 UndefinedAssignmentChecker());
-
- 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
index a9077bf75715..5b7a7572ed7d 100644
--- a/lib/Analysis/GRExprEngineInternalChecks.h
+++ b/lib/Analysis/GRExprEngineInternalChecks.h
@@ -20,7 +20,6 @@ namespace clang {
class GRExprEngine;
void RegisterAttrNonNullChecker(GRExprEngine &Eng);
-void RegisterBadCallChecker(GRExprEngine &Eng);
void RegisterDereferenceChecker(GRExprEngine &Eng);
void RegisterDivZeroChecker(GRExprEngine &Eng);
void RegisterReturnPointerRangeChecker(GRExprEngine &Eng);
@@ -31,9 +30,12 @@ void RegisterPointerSubChecker(GRExprEngine &Eng);
void RegisterPointerArithChecker(GRExprEngine &Eng);
void RegisterFixedAddressChecker(GRExprEngine &Eng);
void RegisterCastToStructChecker(GRExprEngine &Eng);
-void RegisterUndefinedArgChecker(GRExprEngine &Eng);
+void RegisterCallAndMessageChecker(GRExprEngine &Eng);
void RegisterArrayBoundChecker(GRExprEngine &Eng);
void RegisterUndefinedArraySubscriptChecker(GRExprEngine &Eng);
+void RegisterUndefinedAssignmentChecker(GRExprEngine &Eng);
+void RegisterUndefBranchChecker(GRExprEngine &Eng);
+void RegisterUndefResultChecker(GRExprEngine &Eng);
} // end clang namespace
#endif
diff --git a/lib/Analysis/GRState.cpp b/lib/Analysis/GRState.cpp
index 23ee0b2258bd..a56859dde5bf 100644
--- a/lib/Analysis/GRState.cpp
+++ b/lib/Analysis/GRState.cpp
@@ -232,7 +232,7 @@ const GRState* GRStateManager::addGDM(const GRState* St, void* Key, void* Data){
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN ScanReachableSymbols : public SubRegionMap::Visitor {
+class ScanReachableSymbols : public SubRegionMap::Visitor {
typedef llvm::DenseSet<const MemRegion*> VisitedRegionsTy;
VisitedRegionsTy visited;
@@ -308,6 +308,27 @@ bool GRState::scanReachableSymbols(SVal val, SymbolVisitor& visitor) const {
return S.scan(val);
}
+bool GRState::scanReachableSymbols(const SVal *I, const SVal *E,
+ SymbolVisitor &visitor) const {
+ ScanReachableSymbols S(this, visitor);
+ for ( ; I != E; ++I) {
+ if (S.scan(*I))
+ return true;
+ }
+ return false;
+}
+
+bool GRState::scanReachableSymbols(const MemRegion * const *I,
+ const MemRegion * const *E,
+ SymbolVisitor &visitor) const {
+ ScanReachableSymbols S(this, visitor);
+ for ( ; I != E; ++I) {
+ if (S.scan(*I))
+ return true;
+ }
+ return false;
+}
+
//===----------------------------------------------------------------------===//
// Queries.
//===----------------------------------------------------------------------===//
diff --git a/lib/Analysis/LiveVariables.cpp b/lib/Analysis/LiveVariables.cpp
index 2510445a7f31..84e268f3fdaa 100644
--- a/lib/Analysis/LiveVariables.cpp
+++ b/lib/Analysis/LiveVariables.cpp
@@ -19,9 +19,9 @@
#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
#include "clang/Analysis/FlowSensitive/DataflowSolver.h"
#include "clang/Analysis/Support/SaveAndRestore.h"
+#include "clang/Analysis/PathSensitive/AnalysisContext.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
@@ -38,7 +38,7 @@ static const bool Dead = false;
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN RegisterDecls
+class RegisterDecls
: public CFGRecStmtDeclVisitor<RegisterDecls> {
LiveVariables::AnalysisDataTy& AD;
@@ -77,10 +77,12 @@ public:
};
} // end anonymous namespace
-LiveVariables::LiveVariables(ASTContext& Ctx, CFG& cfg) {
+LiveVariables::LiveVariables(AnalysisContext &AC) {
// Register all referenced VarDecls.
+ CFG &cfg = *AC.getCFG();
getAnalysisData().setCFG(cfg);
- getAnalysisData().setContext(Ctx);
+ getAnalysisData().setContext(AC.getASTContext());
+ getAnalysisData().AC = &AC;
RegisterDecls R(getAnalysisData());
cfg.VisitBlockStmts(R);
@@ -92,7 +94,7 @@ LiveVariables::LiveVariables(ASTContext& Ctx, CFG& cfg) {
namespace {
-class VISIBILITY_HIDDEN TransferFuncs : public CFGRecStmtVisitor<TransferFuncs>{
+class TransferFuncs : public CFGRecStmtVisitor<TransferFuncs>{
LiveVariables::AnalysisDataTy& AD;
LiveVariables::ValTy LiveState;
public:
@@ -103,6 +105,7 @@ public:
void VisitDeclRefExpr(DeclRefExpr* DR);
void VisitBinaryOperator(BinaryOperator* B);
+ void VisitBlockExpr(BlockExpr *B);
void VisitAssign(BinaryOperator* B);
void VisitDeclStmt(DeclStmt* DS);
void BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt* S);
@@ -153,7 +156,17 @@ void TransferFuncs::VisitTerminator(CFGBlock* B) {
void TransferFuncs::VisitDeclRefExpr(DeclRefExpr* DR) {
if (VarDecl* V = dyn_cast<VarDecl>(DR->getDecl()))
- LiveState(V,AD) = Alive;
+ LiveState(V, AD) = Alive;
+}
+
+void TransferFuncs::VisitBlockExpr(BlockExpr *BE) {
+ AnalysisContext::referenced_decls_iterator I, E;
+ llvm::tie(I, E) = AD.AC->getReferencedBlockVars(BE->getBlockDecl());
+ for ( ; I != E ; ++I) {
+ DeclBitVector_Types::Idx i = AD.getIdx(*I);
+ if (i.isValid())
+ LiveState.getBit(i) = Alive;
+ }
}
void TransferFuncs::VisitBinaryOperator(BinaryOperator* B) {
diff --git a/lib/Analysis/MallocChecker.cpp b/lib/Analysis/MallocChecker.cpp
index 93e708332ed7..204c7b320e65 100644
--- a/lib/Analysis/MallocChecker.cpp
+++ b/lib/Analysis/MallocChecker.cpp
@@ -46,9 +46,9 @@ struct RefState {
}
};
-class VISIBILITY_HIDDEN RegionState {};
+class RegionState {};
-class VISIBILITY_HIDDEN MallocChecker : public CheckerVisitor<MallocChecker> {
+class MallocChecker : public CheckerVisitor<MallocChecker> {
BuiltinBug *BT_DoubleFree;
BuiltinBug *BT_Leak;
IdentifierInfo *II_malloc;
@@ -65,7 +65,7 @@ private:
void MallocMem(CheckerContext &C, const CallExpr *CE);
void FreeMem(CheckerContext &C, const CallExpr *CE);
};
-}
+} // end anonymous namespace
namespace clang {
template <>
@@ -112,9 +112,7 @@ void MallocChecker::MallocMem(CheckerContext &C, const CallExpr *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));
+ C.addTransition(state->set<RegionState>(Sym, RefState::getAllocated(CE)));
}
void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) {
@@ -128,7 +126,7 @@ void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) {
// Check double free.
if (RS->isReleased()) {
- ExplodedNode *N = C.GenerateNode(CE, true);
+ ExplodedNode *N = C.GenerateSink();
if (N) {
if (!BT_DoubleFree)
BT_DoubleFree = new BuiltinBug("Double free",
@@ -144,7 +142,7 @@ void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) {
// Normal free.
const GRState *FreedState
= state->set<RegionState>(Sym, RefState::getReleased(CE));
- C.addTransition(C.GenerateNode(CE, FreedState));
+ C.addTransition(FreedState);
}
void MallocChecker::EvalDeadSymbols(CheckerContext &C, const Stmt *S,
@@ -158,7 +156,7 @@ void MallocChecker::EvalDeadSymbols(CheckerContext &C, const Stmt *S,
return;
if (RS->isAllocated()) {
- ExplodedNode *N = C.GenerateNode(S, true);
+ ExplodedNode *N = C.GenerateSink();
if (N) {
if (!BT_Leak)
BT_Leak = new BuiltinBug("Memory leak",
@@ -173,6 +171,7 @@ void MallocChecker::EvalDeadSymbols(CheckerContext &C, const Stmt *S,
void MallocChecker::EvalEndPath(GREndPathNodeBuilder &B, void *tag,
GRExprEngine &Eng) {
+ SaveAndRestore<bool> OldHasGen(B.HasGeneratedNode);
const GRState *state = B.getState();
typedef llvm::ImmutableMap<SymbolRef, RefState> SymMap;
SymMap M = state->get<RegionState>();
@@ -212,7 +211,5 @@ void MallocChecker::PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S) {
if (RS->isAllocated())
state = state->set<RegionState>(Sym, RefState::getEscaped(S));
- ExplodedNode *N = C.GenerateNode(S, state);
- if (N)
- C.addTransition(N);
+ C.addTransition(state);
}
diff --git a/lib/Analysis/MemRegion.cpp b/lib/Analysis/MemRegion.cpp
index 8c0b85c0c729..af8bd16ee681 100644
--- a/lib/Analysis/MemRegion.cpp
+++ b/lib/Analysis/MemRegion.cpp
@@ -17,15 +17,25 @@
#include "clang/Analysis/PathSensitive/MemRegion.h"
#include "clang/Analysis/PathSensitive/ValueManager.h"
#include "clang/Analysis/PathSensitive/AnalysisContext.h"
+#include "clang/AST/StmtVisitor.h"
using namespace clang;
//===----------------------------------------------------------------------===//
-// Basic methods.
+// Object destruction.
//===----------------------------------------------------------------------===//
MemRegion::~MemRegion() {}
+MemRegionManager::~MemRegionManager() {
+ // All regions and their data are BumpPtrAllocated. No need to call
+ // their destructors.
+}
+
+//===----------------------------------------------------------------------===//
+// Basic methods.
+//===----------------------------------------------------------------------===//
+
bool SubRegion::isSubRegionOf(const MemRegion* R) const {
const MemRegion* r = getSuperRegion();
while (r != 0) {
@@ -126,15 +136,39 @@ void ElementRegion::Profile(llvm::FoldingSetNodeID& ID) const {
ElementRegion::ProfileRegion(ID, ElementType, Index, superRegion);
}
-void CodeTextRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
- const FunctionDecl *FD,
- const MemRegion*) {
- ID.AddInteger(MemRegion::CodeTextRegionKind);
+void FunctionTextRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
+ const FunctionDecl *FD,
+ const MemRegion*) {
+ ID.AddInteger(MemRegion::FunctionTextRegionKind);
ID.AddPointer(FD);
}
-void CodeTextRegion::Profile(llvm::FoldingSetNodeID& ID) const {
- CodeTextRegion::ProfileRegion(ID, FD, superRegion);
+void FunctionTextRegion::Profile(llvm::FoldingSetNodeID& ID) const {
+ FunctionTextRegion::ProfileRegion(ID, FD, superRegion);
+}
+
+void BlockTextRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
+ const BlockDecl *BD, CanQualType,
+ const MemRegion*) {
+ ID.AddInteger(MemRegion::BlockTextRegionKind);
+ ID.AddPointer(BD);
+}
+
+void BlockTextRegion::Profile(llvm::FoldingSetNodeID& ID) const {
+ BlockTextRegion::ProfileRegion(ID, BD, locTy, superRegion);
+}
+
+void BlockDataRegion::ProfileRegion(llvm::FoldingSetNodeID& ID,
+ const BlockTextRegion *BC,
+ const LocationContext *LC,
+ const MemRegion *) {
+ ID.AddInteger(MemRegion::BlockDataRegionKind);
+ ID.AddPointer(BC);
+ ID.AddPointer(LC);
+}
+
+void BlockDataRegion::Profile(llvm::FoldingSetNodeID& ID) const {
+ BlockDataRegion::ProfileRegion(ID, BC, LC, NULL);
}
//===----------------------------------------------------------------------===//
@@ -160,10 +194,19 @@ void AllocaRegion::dumpToStream(llvm::raw_ostream& os) const {
os << "alloca{" << (void*) Ex << ',' << Cnt << '}';
}
-void CodeTextRegion::dumpToStream(llvm::raw_ostream& os) const {
+void FunctionTextRegion::dumpToStream(llvm::raw_ostream& os) const {
os << "code{" << getDecl()->getDeclName().getAsString() << '}';
}
+void BlockTextRegion::dumpToStream(llvm::raw_ostream& os) const {
+ os << "block_code{" << (void*) this << '}';
+}
+
+void BlockDataRegion::dumpToStream(llvm::raw_ostream& os) const {
+ os << "block_data{" << BC << '}';
+}
+
+
void CompoundLiteralRegion::dumpToStream(llvm::raw_ostream& os) const {
// FIXME: More elaborate pretty-printing.
os << "{ " << (void*) CL << " }";
@@ -259,6 +302,18 @@ VarRegion* MemRegionManager::getVarRegion(const VarDecl *D,
return getRegion<VarRegion>(D, LC);
}
+BlockDataRegion *MemRegionManager::getBlockDataRegion(const BlockTextRegion *BC,
+ const LocationContext *LC)
+{
+ // FIXME: Once we implement scope handling, we will need to properly lookup
+ // 'D' to the proper LocationContext. For now, just strip down to the
+ // StackFrame.
+ while (!isa<StackFrameContext>(LC))
+ LC = LC->getParent();
+
+ return getSubRegion<BlockDataRegion>(BC, LC, getStackRegion());
+}
+
CompoundLiteralRegion*
MemRegionManager::getCompoundLiteralRegion(const CompoundLiteralExpr* CL) {
return getRegion<CompoundLiteralRegion>(CL);
@@ -287,10 +342,17 @@ MemRegionManager::getElementRegion(QualType elementType, SVal Idx,
return R;
}
-CodeTextRegion *MemRegionManager::getCodeTextRegion(const FunctionDecl *FD) {
- return getRegion<CodeTextRegion>(FD);
+FunctionTextRegion *
+MemRegionManager::getFunctionTextRegion(const FunctionDecl *FD) {
+ return getRegion<FunctionTextRegion>(FD);
+}
+
+BlockTextRegion *MemRegionManager::getBlockTextRegion(const BlockDecl *BD,
+ CanQualType locTy) {
+ return getRegion<BlockTextRegion>(BD, locTy);
}
+
/// getSymbolicRegion - Retrieve or create a "symbolic" memory region.
SymbolicRegion* MemRegionManager::getSymbolicRegion(SymbolRef sym) {
return getRegion<SymbolicRegion>(sym);
@@ -473,3 +535,53 @@ RegionRawOffset ElementRegion::getAsRawOffset() const {
return RegionRawOffset(superR, offset);
}
+//===----------------------------------------------------------------------===//
+// BlockDataRegion
+//===----------------------------------------------------------------------===//
+
+void BlockDataRegion::LazyInitializeReferencedVars() {
+ if (ReferencedVars)
+ return;
+
+ AnalysisContext *AC = LC->getAnalysisContext();
+ AnalysisContext::referenced_decls_iterator I, E;
+ llvm::tie(I, E) = AC->getReferencedBlockVars(BC->getDecl());
+
+ if (I == E) {
+ ReferencedVars = (void*) 0x1;
+ return;
+ }
+
+ MemRegionManager &MemMgr = *getMemRegionManager();
+ llvm::BumpPtrAllocator &A = MemMgr.getAllocator();
+ BumpVectorContext BC(A);
+
+ typedef BumpVector<const MemRegion*> VarVec;
+ VarVec *BV = (VarVec*) A.Allocate<VarVec>();
+ new (BV) VarVec(BC, (E - I) / sizeof(*I));
+
+ for ( ; I != E; ++I)
+ BV->push_back(MemMgr.getVarRegion(*I, LC), BC);
+
+ ReferencedVars = BV;
+}
+
+BlockDataRegion::referenced_vars_iterator
+BlockDataRegion::referenced_vars_begin() const {
+ const_cast<BlockDataRegion*>(this)->LazyInitializeReferencedVars();
+
+ BumpVector<const MemRegion*> *Vec =
+ static_cast<BumpVector<const MemRegion*>*>(ReferencedVars);
+
+ return Vec == (void*) 0x1 ? NULL : Vec->begin();
+}
+
+BlockDataRegion::referenced_vars_iterator
+BlockDataRegion::referenced_vars_end() const {
+ const_cast<BlockDataRegion*>(this)->LazyInitializeReferencedVars();
+
+ BumpVector<const MemRegion*> *Vec =
+ static_cast<BumpVector<const MemRegion*>*>(ReferencedVars);
+
+ return Vec == (void*) 0x1 ? NULL : Vec->end();
+}
diff --git a/lib/Analysis/NSAutoreleasePoolChecker.cpp b/lib/Analysis/NSAutoreleasePoolChecker.cpp
index e0a8d0dc5f73..2ff04878f7ab 100644
--- a/lib/Analysis/NSAutoreleasePoolChecker.cpp
+++ b/lib/Analysis/NSAutoreleasePoolChecker.cpp
@@ -19,14 +19,13 @@
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
#include "BasicObjCFoundationChecks.h"
-#include "llvm/Support/Compiler.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Decl.h"
using namespace clang;
namespace {
-class VISIBILITY_HIDDEN NSAutoreleasePoolChecker
+class NSAutoreleasePoolChecker
: public CheckerVisitor<NSAutoreleasePoolChecker> {
Selector releaseS;
@@ -65,6 +64,9 @@ NSAutoreleasePoolChecker::PreVisitObjCMessageExpr(CheckerContext &C,
// the type of the expression.
const ObjCObjectPointerType* PT =
receiver->getType()->getAs<ObjCObjectPointerType>();
+
+ if (!PT)
+ return;
const ObjCInterfaceDecl* OD = PT->getInterfaceDecl();
if (!OD)
return;
diff --git a/lib/Analysis/NSErrorChecker.cpp b/lib/Analysis/NSErrorChecker.cpp
index 93b617b115d9..e3cf57fd0c1b 100644
--- a/lib/Analysis/NSErrorChecker.cpp
+++ b/lib/Analysis/NSErrorChecker.cpp
@@ -20,7 +20,6 @@
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
#include "clang/Analysis/PathSensitive/Checkers/DereferenceChecker.h"
#include "BasicObjCFoundationChecks.h"
-#include "llvm/Support/Compiler.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Decl.h"
#include "llvm/ADT/SmallVector.h"
@@ -28,7 +27,7 @@
using namespace clang;
namespace {
-class VISIBILITY_HIDDEN NSErrorChecker : public BugType {
+class NSErrorChecker : public BugType {
const Decl &CodeDecl;
const bool isNSErrorWarning;
IdentifierInfo * const II;
@@ -117,7 +116,7 @@ void NSErrorChecker::EmitRetTyWarning(BugReporter& BR, const Decl& CodeDecl) {
BR.EmitBasicReport(isNSErrorWarning
? "Bad return type when passing NSError**"
: "Bad return type when passing CFError*",
- getCategory().c_str(), os.str().c_str(),
+ getCategory(), os.str(),
CodeDecl.getLocation());
}
@@ -229,7 +228,7 @@ void NSErrorChecker::CheckParamDeref(const VarDecl *Param,
os << Param->getNameAsString() << "' may be null.";
- BugReport *report = new BugReport(*this, os.str().c_str(), *I);
+ BugReport *report = new BugReport(*this, os.str(), *I);
// FIXME: Notable symbols are now part of the report. We should
// add support for notable symbols in BugReport.
// BR.addNotableSymbol(SV->getSymbol());
diff --git a/lib/Analysis/PointerArithChecker.cpp b/lib/Analysis/PointerArithChecker.cpp
index 93823484e1d0..370233ce38bd 100644
--- a/lib/Analysis/PointerArithChecker.cpp
+++ b/lib/Analysis/PointerArithChecker.cpp
@@ -18,7 +18,7 @@
using namespace clang;
namespace {
-class VISIBILITY_HIDDEN PointerArithChecker
+class PointerArithChecker
: public CheckerVisitor<PointerArithChecker> {
BuiltinBug *BT;
public:
@@ -53,7 +53,7 @@ void PointerArithChecker::PreVisitBinaryOperator(CheckerContext &C,
if (isa<VarRegion>(LR) || isa<CodeTextRegion>(LR) ||
isa<CompoundLiteralRegion>(LR)) {
- if (ExplodedNode *N = C.GenerateNode(B)) {
+ if (ExplodedNode *N = C.GenerateNode()) {
if (!BT)
BT = new BuiltinBug("Dangerous pointer arithmetic",
"Pointer arithmetic done on non-array variables "
diff --git a/lib/Analysis/PointerSubChecker.cpp b/lib/Analysis/PointerSubChecker.cpp
index 4c7906f4beba..c597a2580751 100644
--- a/lib/Analysis/PointerSubChecker.cpp
+++ b/lib/Analysis/PointerSubChecker.cpp
@@ -19,7 +19,7 @@
using namespace clang;
namespace {
-class VISIBILITY_HIDDEN PointerSubChecker
+class PointerSubChecker
: public CheckerVisitor<PointerSubChecker> {
BuiltinBug *BT;
public:
@@ -61,7 +61,7 @@ void PointerSubChecker::PreVisitBinaryOperator(CheckerContext &C,
if (isa<SymbolicRegion>(BaseLR) || isa<SymbolicRegion>(BaseRR))
return;
- if (ExplodedNode *N = C.GenerateNode(B)) {
+ if (ExplodedNode *N = C.GenerateNode()) {
if (!BT)
BT = new BuiltinBug("Pointer subtraction",
"Subtraction of two pointers that do not point to "
diff --git a/lib/Analysis/PthreadLockChecker.cpp b/lib/Analysis/PthreadLockChecker.cpp
index 66206616b008..e95095c7975e 100644
--- a/lib/Analysis/PthreadLockChecker.cpp
+++ b/lib/Analysis/PthreadLockChecker.cpp
@@ -21,7 +21,7 @@
using namespace clang;
namespace {
-class VISIBILITY_HIDDEN PthreadLockChecker
+class PthreadLockChecker
: public CheckerVisitor<PthreadLockChecker> {
BugType *BT;
public:
@@ -42,7 +42,7 @@ public:
} // end anonymous namespace
// GDM Entry for tracking lock state.
-namespace { class VISIBILITY_HIDDEN LockSet {}; }
+namespace { class LockSet {}; }
namespace clang {
template <> struct GRStateTrait<LockSet> :
public GRStatePartialTrait<llvm::ImmutableSet<const MemRegion*> > {
@@ -59,8 +59,8 @@ 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());
+ const FunctionTextRegion *R =
+ dyn_cast_or_null<FunctionTextRegion>(state->getSVal(Callee).getAsRegion());
if (!R)
return;
diff --git a/lib/Analysis/RangeConstraintManager.cpp b/lib/Analysis/RangeConstraintManager.cpp
index f5cae698f924..7330b6261479 100644
--- a/lib/Analysis/RangeConstraintManager.cpp
+++ b/lib/Analysis/RangeConstraintManager.cpp
@@ -17,7 +17,6 @@
#include "clang/Analysis/PathSensitive/GRStateTrait.h"
#include "clang/Analysis/PathSensitive/GRTransferFuncs.h"
#include "clang/Analysis/ManagerRegistry.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableSet.h"
@@ -25,14 +24,14 @@
using namespace clang;
-namespace { class VISIBILITY_HIDDEN ConstraintRange {}; }
+namespace { class ConstraintRange {}; }
static int ConstraintRangeIndex = 0;
/// A Range represents the closed range [from, to]. The caller must
/// guarantee that from <= to. Note that Range is immutable, so as not
/// to subvert RangeSet's immutability.
namespace {
-class VISIBILITY_HIDDEN Range : public std::pair<const llvm::APSInt*,
+class Range : public std::pair<const llvm::APSInt*,
const llvm::APSInt*> {
public:
Range(const llvm::APSInt &from, const llvm::APSInt &to)
@@ -59,7 +58,7 @@ public:
};
-class VISIBILITY_HIDDEN RangeTrait : public llvm::ImutContainerInfo<Range> {
+class RangeTrait : public llvm::ImutContainerInfo<Range> {
public:
// When comparing if one Range is less than another, we should compare
// the actual APSInt values instead of their pointers. This keeps the order
@@ -74,7 +73,7 @@ public:
/// RangeSet contains a set of ranges. If the set is empty, then
/// there the value of a symbol is overly constrained and there are no
/// possible values for that symbol.
-class VISIBILITY_HIDDEN RangeSet {
+class RangeSet {
typedef llvm::ImmutableSet<Range, RangeTrait> PrimRangeSet;
PrimRangeSet ranges; // no need to make const, since it is an
// ImmutableSet - this allows default operator=
@@ -232,7 +231,7 @@ struct GRStateTrait<ConstraintRange>
}
namespace {
-class VISIBILITY_HIDDEN RangeConstraintManager : public SimpleConstraintManager{
+class RangeConstraintManager : public SimpleConstraintManager{
RangeSet GetRange(const GRState *state, SymbolRef sym);
public:
RangeConstraintManager() {}
diff --git a/lib/Analysis/RegionStore.cpp b/lib/Analysis/RegionStore.cpp
index ae3fa14c2a26..e645172a5b66 100644
--- a/lib/Analysis/RegionStore.cpp
+++ b/lib/Analysis/RegionStore.cpp
@@ -25,7 +25,6 @@
#include "llvm/ADT/ImmutableMap.h"
#include "llvm/ADT/ImmutableList.h"
#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/Compiler.h"
using namespace clang;
@@ -86,10 +85,10 @@ typedef llvm::ImmutableMap<const MemRegion*, BindingVal> RegionBindings;
//===----------------------------------------------------------------------===//
namespace {
-struct VISIBILITY_HIDDEN minimal_features_tag {};
-struct VISIBILITY_HIDDEN maximal_features_tag {};
+struct minimal_features_tag {};
+struct maximal_features_tag {};
-class VISIBILITY_HIDDEN RegionStoreFeatures {
+class RegionStoreFeatures {
bool SupportsFields;
bool SupportsRemaining;
@@ -114,7 +113,7 @@ public:
// MemRegions represent chunks of memory with a size (their "extent"). This
// GDM entry tracks the extents for regions. Extents are in bytes.
//
-namespace { class VISIBILITY_HIDDEN RegionExtents {}; }
+namespace { class RegionExtents {}; }
static int RegionExtentsIndex = 0;
namespace clang {
template<> struct GRStateTrait<RegionExtents>
@@ -141,7 +140,7 @@ static bool IsAnyPointerOrIntptr(QualType ty, ASTContext &Ctx) {
namespace {
-class VISIBILITY_HIDDEN RegionStoreSubRegionMap : public SubRegionMap {
+class RegionStoreSubRegionMap : public SubRegionMap {
typedef llvm::ImmutableSet<const MemRegion*> SetTy;
typedef llvm::DenseMap<const MemRegion*, SetTy> Map;
SetTy::Factory F;
@@ -188,7 +187,7 @@ public:
}
};
-class VISIBILITY_HIDDEN RegionStoreManager : public StoreManager {
+class RegionStoreManager : public StoreManager {
const RegionStoreFeatures Features;
RegionBindings::Factory RBFactory;
@@ -215,6 +214,13 @@ public:
/// getDefaultBinding - Returns an SVal* representing an optional default
/// binding associated with a region and its subregions.
Optional<SVal> getDefaultBinding(RegionBindings B, const MemRegion *R);
+
+ /// setImplicitDefaultValue - Set the default binding for the provided
+ /// MemRegion to the value implicitly defined for compound literals when
+ /// the value is not specified.
+ const GRState *setImplicitDefaultValue(const GRState *state,
+ const MemRegion *R,
+ QualType T);
/// getLValueString - Returns an SVal representing the lvalue of a
/// StringLiteral. Within RegionStore a StringLiteral has an
@@ -705,7 +711,9 @@ DefinedOrUnknownSVal RegionStoreManager::getSizeInElements(const GRState *state,
assert(0 && "Cannot index into a MemSpace");
return UnknownVal();
- case MemRegion::CodeTextRegionKind:
+ case MemRegion::FunctionTextRegionKind:
+ case MemRegion::BlockTextRegionKind:
+ case MemRegion::BlockDataRegionKind:
// Technically this can happen if people do funny things with casts.
return UnknownVal();
@@ -850,7 +858,9 @@ SVal RegionStoreManager::EvalBinOp(const GRState *state,
case MemRegion::ObjCIvarRegionKind:
return UnknownVal();
- case MemRegion::CodeTextRegionKind:
+ case MemRegion::FunctionTextRegionKind:
+ case MemRegion::BlockTextRegionKind:
+ case MemRegion::BlockDataRegionKind:
// Technically this can happen if people do funny things with casts.
return UnknownVal();
@@ -1437,6 +1447,30 @@ RegionStoreManager::BindCompoundLiteral(const GRState *state,
return Bind(state, loc::MemRegionVal(R), V);
}
+const GRState *RegionStoreManager::setImplicitDefaultValue(const GRState *state,
+ const MemRegion *R,
+ QualType T) {
+ Store store = state->getStore();
+ RegionBindings B = GetRegionBindings(store);
+ SVal V;
+
+ if (Loc::IsLocType(T))
+ V = ValMgr.makeNull();
+ else if (T->isIntegerType())
+ V = ValMgr.makeZeroVal(T);
+ else if (T->isStructureType() || T->isArrayType()) {
+ // Set the default value to a zero constant when it is a structure
+ // or array. The type doesn't really matter.
+ V = ValMgr.makeZeroVal(ValMgr.getContext().IntTy);
+ }
+ else {
+ return state;
+ }
+
+ B = RBFactory.Add(B, R, BindingVal(V, BindingVal::Default));
+ return state->makeWithStore(B.getRoot());
+}
+
const GRState *RegionStoreManager::BindArray(const GRState *state,
const TypedRegion* R,
SVal Init) {
@@ -1478,6 +1512,10 @@ const GRState *RegionStoreManager::BindArray(const GRState *state,
return CopyLazyBindings(*LCV, state, R);
// Remaining case: explicit compound values.
+
+ if (Init.isUnknown())
+ return setImplicitDefaultValue(state, R, ElementTy);
+
nonloc::CompoundVal& CV = cast<nonloc::CompoundVal>(Init);
nonloc::CompoundVal::iterator VI = CV.begin(), VE = CV.end();
uint64_t i = 0;
@@ -1497,17 +1535,10 @@ const GRState *RegionStoreManager::BindArray(const GRState *state,
state = Bind(state, ValMgr.makeLoc(ER), *VI);
}
- // If the init list is shorter than the array length, set the array default
- // value.
- if (i < size) {
- if (ElementTy->isIntegerType()) {
- SVal V = ValMgr.makeZeroVal(ElementTy);
- Store store = state->getStore();
- RegionBindings B = GetRegionBindings(store);
- B = RBFactory.Add(B, R, BindingVal(V, BindingVal::Default));
- state = state->makeWithStore(B.getRoot());
- }
- }
+ // If the init list is shorter than the array length, set the
+ // array default value.
+ if (i < size)
+ state = setImplicitDefaultValue(state, R, ElementTy);
return state;
}
@@ -1619,9 +1650,9 @@ void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc,
llvm::OwningPtr<RegionStoreSubRegionMap>
SubRegions(getRegionStoreSubRegionMap(store));
- // Do a pass over the regions in the store. For VarRegions we check if
- // the variable is still live and if so add it to the list of live roots.
- // For other regions we populate our region backmap.
+ // Do a pass over the regions in the store. For VarRegions we check if
+ // the variable is still live and if so add it to the list of live roots.
+ // For other regions we populate our region backmap.
llvm::SmallVector<const MemRegion*, 10> IntermediateRoots;
// Scan the direct bindings for "intermediate" roots.
@@ -1719,8 +1750,21 @@ tryAgain:
// Mark the symbol for any live SymbolicRegion as "live". This means we
// should continue to track that symbol.
- if (const SymbolicRegion* SymR = dyn_cast<SymbolicRegion>(R))
+ if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(R))
SymReaper.markLive(SymR->getSymbol());
+
+ // For BlockDataRegions, enqueue all VarRegions for that are referenced
+ // via BlockDeclRefExprs.
+ if (const BlockDataRegion *BD = dyn_cast<BlockDataRegion>(R)) {
+ for (BlockDataRegion::referenced_vars_iterator
+ RI = BD->referenced_vars_begin(), RE = BD->referenced_vars_end();
+ RI != RE; ++RI)
+ WorkList.push_back(std::make_pair(state_N, *RI));
+
+ // No possible data bindings on a BlockDataRegion. Continue to the
+ // next region in the worklist.
+ continue;
+ }
Store store_N = state_N->getStore();
RegionBindings B_N = GetRegionBindings(store_N);
diff --git a/lib/Analysis/ReturnPointerRangeChecker.cpp b/lib/Analysis/ReturnPointerRangeChecker.cpp
index 44887b2625da..ab0fcab4219e 100644
--- a/lib/Analysis/ReturnPointerRangeChecker.cpp
+++ b/lib/Analysis/ReturnPointerRangeChecker.cpp
@@ -20,7 +20,7 @@
using namespace clang;
namespace {
-class VISIBILITY_HIDDEN ReturnPointerRangeChecker :
+class ReturnPointerRangeChecker :
public CheckerVisitor<ReturnPointerRangeChecker> {
BuiltinBug *BT;
public:
@@ -70,7 +70,7 @@ void ReturnPointerRangeChecker::PreVisitReturnStmt(CheckerContext &C,
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);
+ ExplodedNode *N = C.GenerateSink(StOutBound);
if (!N)
return;
@@ -91,7 +91,6 @@ void ReturnPointerRangeChecker::PreVisitReturnStmt(CheckerContext &C,
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
index e4be8712d09b..3a6d8a41c069 100644
--- a/lib/Analysis/ReturnStackAddressChecker.cpp
+++ b/lib/Analysis/ReturnStackAddressChecker.cpp
@@ -17,12 +17,13 @@
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
#include "clang/Analysis/PathSensitive/BugReporter.h"
#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallString.h"
using namespace clang;
namespace {
-class VISIBILITY_HIDDEN ReturnStackAddressChecker :
+class ReturnStackAddressChecker :
public CheckerVisitor<ReturnStackAddressChecker> {
BuiltinBug *BT;
public:
@@ -53,7 +54,7 @@ void ReturnStackAddressChecker::PreVisitReturnStmt(CheckerContext &C,
if (!R || !R->hasStackStorage())
return;
- ExplodedNode *N = C.GenerateNode(RS, C.getState(), true);
+ ExplodedNode *N = C.GenerateSink();
if (!N)
return;
@@ -83,6 +84,14 @@ void ReturnStackAddressChecker::PreVisitReturnStmt(CheckerContext &C,
<< C.getSourceManager().getInstantiationLineNumber(L)
<< " returned to caller";
}
+ else if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(R)) {
+ const BlockDecl *BD = BR->getCodeRegion()->getDecl();
+ SourceLocation L = BD->getLocStart();
+ range = BD->getSourceRange();
+ os << "Address of stack-allocated block declared on line "
+ << C.getSourceManager().getInstantiationLineNumber(L)
+ << " returned to caller";
+ }
else {
os << "Address of stack memory associated with local variable '"
<< R->getString() << "' returned.";
diff --git a/lib/Analysis/ReturnUndefChecker.cpp b/lib/Analysis/ReturnUndefChecker.cpp
index 796c7608c86d..7cd71265805b 100644
--- a/lib/Analysis/ReturnUndefChecker.cpp
+++ b/lib/Analysis/ReturnUndefChecker.cpp
@@ -22,7 +22,7 @@
using namespace clang;
namespace {
-class VISIBILITY_HIDDEN ReturnUndefChecker :
+class ReturnUndefChecker :
public CheckerVisitor<ReturnUndefChecker> {
BuiltinBug *BT;
public:
@@ -50,7 +50,7 @@ void ReturnUndefChecker::PreVisitReturnStmt(CheckerContext &C,
if (!C.getState()->getSVal(RetE).isUndef())
return;
- ExplodedNode *N = C.GenerateNode(RS, C.getState(), true);
+ ExplodedNode *N = C.GenerateSink();
if (!N)
return;
diff --git a/lib/Analysis/SVals.cpp b/lib/Analysis/SVals.cpp
index d5d36e3b9090..9163b2725273 100644
--- a/lib/Analysis/SVals.cpp
+++ b/lib/Analysis/SVals.cpp
@@ -51,7 +51,7 @@ bool SVal::hasConjuredSymbol() const {
const FunctionDecl *SVal::getAsFunctionDecl() const {
if (const loc::MemRegionVal* X = dyn_cast<loc::MemRegionVal>(this)) {
const MemRegion* R = X->getRegion();
- if (const CodeTextRegion *CTR = R->getAs<CodeTextRegion>())
+ if (const FunctionTextRegion *CTR = R->getAs<FunctionTextRegion>())
return CTR->getDecl();
}
diff --git a/lib/Analysis/SimpleSValuator.cpp b/lib/Analysis/SimpleSValuator.cpp
index 4487aa9d3028..2afcd3e847cd 100644
--- a/lib/Analysis/SimpleSValuator.cpp
+++ b/lib/Analysis/SimpleSValuator.cpp
@@ -13,12 +13,11 @@
#include "clang/Analysis/PathSensitive/SValuator.h"
#include "clang/Analysis/PathSensitive/GRState.h"
-#include "llvm/Support/Compiler.h"
using namespace clang;
namespace {
-class VISIBILITY_HIDDEN SimpleSValuator : public SValuator {
+class SimpleSValuator : public SValuator {
protected:
virtual SVal EvalCastNL(NonLoc val, QualType castTy);
virtual SVal EvalCastL(Loc val, QualType castTy);
diff --git a/lib/Analysis/Store.cpp b/lib/Analysis/Store.cpp
index 2fd72ac0a148..2fd573c4764d 100644
--- a/lib/Analysis/Store.cpp
+++ b/lib/Analysis/Store.cpp
@@ -85,7 +85,10 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy)
assert(0 && "Invalid region cast");
break;
}
- case MemRegion::CodeTextRegionKind: {
+
+ case MemRegion::FunctionTextRegionKind:
+ case MemRegion::BlockTextRegionKind:
+ case MemRegion::BlockDataRegionKind: {
// CodeTextRegion should be cast to only a function or block pointer type,
// although they can in practice be casted to anything, e.g, void*, char*,
// etc.
@@ -194,12 +197,11 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy)
/// as another region.
SVal StoreManager::CastRetrievedVal(SVal V, const TypedRegion *R,
QualType castTy) {
- ASTContext &Ctx = ValMgr.getContext();
-
if (castTy.isNull())
return V;
- assert(Ctx.hasSameUnqualifiedType(castTy, R->getValueType(Ctx)));
+ assert(ValMgr.getContext().hasSameUnqualifiedType(castTy,
+ R->getValueType(ValMgr.getContext())));
return V;
}
diff --git a/lib/Analysis/UndefBranchChecker.cpp b/lib/Analysis/UndefBranchChecker.cpp
new file mode 100644
index 000000000000..c739d1ac4b22
--- /dev/null
+++ b/lib/Analysis/UndefBranchChecker.cpp
@@ -0,0 +1,117 @@
+//=== UndefBranchChecker.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 UndefBranchChecker, which checks for undefined branch
+// condition.
+//
+//===----------------------------------------------------------------------===//
+
+#include "GRExprEngineInternalChecks.h"
+#include "clang/Analysis/PathSensitive/Checker.h"
+
+using namespace clang;
+
+namespace {
+
+class UndefBranchChecker : public Checker {
+ BuiltinBug *BT;
+
+ struct FindUndefExpr {
+ GRStateManager& VM;
+ const GRState* St;
+
+ FindUndefExpr(GRStateManager& V, const GRState* S) : VM(V), St(S) {}
+
+ Expr* FindExpr(Expr* Ex) {
+ if (!MatchesCriteria(Ex))
+ return 0;
+
+ for (Stmt::child_iterator I=Ex->child_begin(), E=Ex->child_end();I!=E;++I)
+ if (Expr* ExI = dyn_cast_or_null<Expr>(*I)) {
+ Expr* E2 = FindExpr(ExI);
+ if (E2) return E2;
+ }
+
+ return Ex;
+ }
+
+ bool MatchesCriteria(Expr* Ex) { return St->getSVal(Ex).isUndef(); }
+ };
+
+public:
+ UndefBranchChecker() : BT(0) {}
+ static void *getTag();
+ void VisitBranchCondition(GRBranchNodeBuilder &Builder, GRExprEngine &Eng,
+ Stmt *Condition, void *tag);
+};
+
+}
+
+void clang::RegisterUndefBranchChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new UndefBranchChecker());
+}
+
+void *UndefBranchChecker::getTag() {
+ static int x;
+ return &x;
+}
+
+void UndefBranchChecker::VisitBranchCondition(GRBranchNodeBuilder &Builder,
+ GRExprEngine &Eng,
+ Stmt *Condition, void *tag) {
+ const GRState *state = Builder.getState();
+ SVal X = state->getSVal(Condition);
+ if (X.isUndef()) {
+ ExplodedNode *N = Builder.generateNode(state, true);
+ if (N) {
+ N->markAsSink();
+ if (!BT)
+ BT = new BuiltinBug("Branch condition evaluates to a garbage value");
+
+ // What's going on here: we want to highlight the subexpression of the
+ // condition that is the most likely source of the "uninitialized
+ // branch condition." We do a recursive walk of the condition's
+ // subexpressions and roughly look for the most nested subexpression
+ // that binds to Undefined. We then highlight that expression's range.
+ BlockEdge B = cast<BlockEdge>(N->getLocation());
+ Expr* Ex = cast<Expr>(B.getSrc()->getTerminatorCondition());
+ assert (Ex && "Block must have a terminator.");
+
+ // Get the predecessor node and check if is a PostStmt with the Stmt
+ // being the terminator condition. We want to inspect the state
+ // of that node instead because it will contain main information about
+ // the subexpressions.
+ assert (!N->pred_empty());
+
+ // Note: any predecessor will do. They should have identical state,
+ // since all the BlockEdge did was act as an error sink since the value
+ // had to already be undefined.
+ ExplodedNode *PrevN = *N->pred_begin();
+ ProgramPoint P = PrevN->getLocation();
+ const GRState* St = N->getState();
+
+ if (PostStmt* PS = dyn_cast<PostStmt>(&P))
+ if (PS->getStmt() == Ex)
+ St = PrevN->getState();
+
+ FindUndefExpr FindIt(Eng.getStateManager(), St);
+ Ex = FindIt.FindExpr(Ex);
+
+ // Emit the bug report.
+ EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getDescription(),N);
+ R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Ex);
+ R->addRange(Ex->getSourceRange());
+
+ Eng.getBugReporter().EmitReport(R);
+ }
+
+ Builder.markInfeasible(true);
+ Builder.markInfeasible(false);
+ }
+}
diff --git a/lib/Analysis/UndefResultChecker.cpp b/lib/Analysis/UndefResultChecker.cpp
new file mode 100644
index 000000000000..acc86dda5a97
--- /dev/null
+++ b/lib/Analysis/UndefResultChecker.cpp
@@ -0,0 +1,86 @@
+//=== UndefResultChecker.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines UndefResultChecker, a builtin check in GRExprEngine that
+// performs checks for undefined results of non-assignment binary operators.
+//
+//===----------------------------------------------------------------------===//
+
+#include "GRExprEngineInternalChecks.h"
+#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+#include "clang/Analysis/PathSensitive/GRExprEngine.h"
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+
+using namespace clang;
+
+namespace {
+class UndefResultChecker
+ : public CheckerVisitor<UndefResultChecker> {
+
+ BugType *BT;
+
+public:
+ UndefResultChecker() : BT(0) {}
+ static void *getTag() { static int tag = 0; return &tag; }
+ void PostVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B);
+};
+} // end anonymous namespace
+
+void clang::RegisterUndefResultChecker(GRExprEngine &Eng) {
+ Eng.registerCheck(new UndefResultChecker());
+}
+
+void UndefResultChecker::PostVisitBinaryOperator(CheckerContext &C,
+ const BinaryOperator *B) {
+ const GRState *state = C.getState();
+ if (state->getSVal(B).isUndef()) {
+ // Generate an error node.
+ ExplodedNode *N = C.GenerateSink();
+ if (!N)
+ return;
+
+ if (!BT)
+ BT = new BuiltinBug("Result of operation is garbage or undefined");
+
+ llvm::SmallString<256> sbuf;
+ llvm::raw_svector_ostream OS(sbuf);
+ const Expr *Ex = NULL;
+ bool isLeft = true;
+
+ if (state->getSVal(B->getLHS()).isUndef()) {
+ Ex = B->getLHS()->IgnoreParenCasts();
+ isLeft = true;
+ }
+ else if (state->getSVal(B->getRHS()).isUndef()) {
+ Ex = B->getRHS()->IgnoreParenCasts();
+ isLeft = false;
+ }
+
+ if (Ex) {
+ OS << "The " << (isLeft ? "left" : "right")
+ << " operand of '"
+ << BinaryOperator::getOpcodeStr(B->getOpcode())
+ << "' is a garbage value";
+ }
+ else {
+ // Neither operand was undefined, but the result is undefined.
+ OS << "The result of the '"
+ << BinaryOperator::getOpcodeStr(B->getOpcode())
+ << "' expression is undefined";
+ }
+ EnhancedBugReport *report = new EnhancedBugReport(*BT, OS.str(), N);
+ if (Ex) {
+ report->addRange(Ex->getSourceRange());
+ report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Ex);
+ }
+ else
+ report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, B);
+ C.EmitReport(report);
+ }
+}
diff --git a/lib/Analysis/UndefinedArgChecker.cpp b/lib/Analysis/UndefinedArgChecker.cpp
deleted file mode 100644
index 923a7e1bed0b..000000000000
--- a/lib/Analysis/UndefinedArgChecker.cpp
+++ /dev/null
@@ -1,56 +0,0 @@
-//===--- UndefinedArgChecker.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 BadCallChecker, a builtin check in GRExprEngine that performs
-// checks for undefined arguments.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
-#include "clang/Analysis/PathSensitive/BugReporter.h"
-#include "GRExprEngineInternalChecks.h"
-
-using namespace clang;
-
-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,
- const CallExpr *CE){
- for (CallExpr::const_arg_iterator I = CE->arg_begin(), E = CE->arg_end();
- I != E; ++I) {
- if (C.getState()->getSVal(*I).isUndef()) {
- if (ExplodedNode *N = C.GenerateNode(CE, true)) {
- if (!BT)
- 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(), 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
index 887c7755fe45..d6aacaf1f85e 100644
--- a/lib/Analysis/UndefinedArraySubscriptChecker.cpp
+++ b/lib/Analysis/UndefinedArraySubscriptChecker.cpp
@@ -19,7 +19,7 @@
using namespace clang;
namespace {
-class VISIBILITY_HIDDEN UndefinedArraySubscriptChecker
+class UndefinedArraySubscriptChecker
: public CheckerVisitor<UndefinedArraySubscriptChecker> {
BugType *BT;
public:
@@ -41,7 +41,7 @@ void
UndefinedArraySubscriptChecker::PreVisitArraySubscriptExpr(CheckerContext &C,
const ArraySubscriptExpr *A) {
if (C.getState()->getSVal(A->getIdx()).isUndef()) {
- if (ExplodedNode *N = C.GenerateNode(A, true)) {
+ if (ExplodedNode *N = C.GenerateSink()) {
if (!BT)
BT = new BuiltinBug("Array subscript is undefined");
diff --git a/lib/Analysis/UndefinedAssignmentChecker.cpp b/lib/Analysis/UndefinedAssignmentChecker.cpp
index b8062f359562..4630b823a91e 100644
--- a/lib/Analysis/UndefinedAssignmentChecker.cpp
+++ b/lib/Analysis/UndefinedAssignmentChecker.cpp
@@ -12,11 +12,29 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Analysis/PathSensitive/Checkers/UndefinedAssignmentChecker.h"
+#include "GRExprEngineInternalChecks.h"
+#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
#include "clang/Analysis/PathSensitive/BugReporter.h"
using namespace clang;
+namespace {
+class UndefinedAssignmentChecker
+ : public CheckerVisitor<UndefinedAssignmentChecker> {
+ BugType *BT;
+public:
+ UndefinedAssignmentChecker() : BT(0) {}
+ static void *getTag();
+ virtual void PreVisitBind(CheckerContext &C, const Stmt *AssignE,
+ const Stmt *StoreE, SVal location,
+ SVal val);
+};
+}
+
+void clang::RegisterUndefinedAssignmentChecker(GRExprEngine &Eng){
+ Eng.registerCheck(new UndefinedAssignmentChecker());
+}
+
void *UndefinedAssignmentChecker::getTag() {
static int x = 0;
return &x;
@@ -30,7 +48,7 @@ void UndefinedAssignmentChecker::PreVisitBind(CheckerContext &C,
if (!val.isUndef())
return;
- ExplodedNode *N = C.GenerateNode(StoreE, true);
+ ExplodedNode *N = C.GenerateSink();
if (!N)
return;
diff --git a/lib/Analysis/UninitializedValues.cpp b/lib/Analysis/UninitializedValues.cpp
index 8e7b15862d66..6fa4b539dc40 100644
--- a/lib/Analysis/UninitializedValues.cpp
+++ b/lib/Analysis/UninitializedValues.cpp
@@ -17,7 +17,6 @@
#include "clang/Analysis/AnalysisDiagnostic.h"
#include "clang/AST/ASTContext.h"
#include "clang/Analysis/FlowSensitive/DataflowSolver.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/ADT/SmallPtrSet.h"
@@ -29,7 +28,7 @@ using namespace clang;
namespace {
-class VISIBILITY_HIDDEN RegisterDecls
+class RegisterDecls
: public CFGRecStmtDeclVisitor<RegisterDecls> {
UninitializedValues::AnalysisDataTy& AD;
@@ -52,7 +51,7 @@ void UninitializedValues::InitializeValues(const CFG& cfg) {
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN TransferFuncs
+class TransferFuncs
: public CFGStmtVisitor<TransferFuncs,bool> {
UninitializedValues::ValTy V;
@@ -269,7 +268,7 @@ namespace {
UninitializedValues_ValueTypes::ObserverTy::~ObserverTy() {}
namespace {
-class VISIBILITY_HIDDEN UninitializedValuesChecker
+class UninitializedValuesChecker
: public UninitializedValues::ObserverTy {
ASTContext &Ctx;
diff --git a/lib/Analysis/VLASizeChecker.cpp b/lib/Analysis/VLASizeChecker.cpp
index 799a73e293c8..2690d6f0cffc 100644
--- a/lib/Analysis/VLASizeChecker.cpp
+++ b/lib/Analysis/VLASizeChecker.cpp
@@ -20,7 +20,7 @@
using namespace clang;
namespace {
-class VISIBILITY_HIDDEN VLASizeChecker : public CheckerVisitor<VLASizeChecker> {
+class VLASizeChecker : public CheckerVisitor<VLASizeChecker> {
BugType *BT_zero;
BugType *BT_undef;
@@ -55,7 +55,7 @@ void VLASizeChecker::PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS) {
if (sizeV.isUndef()) {
// Generate an error node.
- ExplodedNode *N = C.GenerateNode(DS, true);
+ ExplodedNode *N = C.GenerateSink();
if (!N)
return;
@@ -78,7 +78,7 @@ void VLASizeChecker::PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS) {
llvm::tie(stateNotZero, stateZero) = state->Assume(sizeD);
if (stateZero && !stateNotZero) {
- ExplodedNode* N = C.GenerateNode(DS, stateZero, true);
+ ExplodedNode* N = C.GenerateSink(stateZero);
if (!BT_zero)
BT_zero = new BuiltinBug("Declared variable-length array (VLA) has zero "
"size");
@@ -92,6 +92,5 @@ void VLASizeChecker::PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS) {
}
// From this point on, assume that the size is not zero.
- if (state != stateNotZero)
- C.addTransition(C.GenerateNode(DS, stateNotZero));
+ C.addTransition(stateNotZero);
}
diff --git a/lib/Analysis/ValueManager.cpp b/lib/Analysis/ValueManager.cpp
index fe670e79b3b5..22a821149dbb 100644
--- a/lib/Analysis/ValueManager.cpp
+++ b/lib/Analysis/ValueManager.cpp
@@ -138,6 +138,15 @@ ValueManager::getDerivedRegionValueSymbolVal(SymbolRef parentSymbol,
}
DefinedSVal ValueManager::getFunctionPointer(const FunctionDecl* FD) {
- CodeTextRegion *R = MemMgr.getCodeTextRegion(FD);
+ CodeTextRegion *R = MemMgr.getFunctionTextRegion(FD);
return loc::MemRegionVal(R);
}
+
+DefinedSVal ValueManager::getBlockPointer(const BlockDecl *D,
+ CanQualType locTy,
+ const LocationContext *LC) {
+ BlockTextRegion *BC = MemMgr.getBlockTextRegion(D, locTy);
+ BlockDataRegion *BD = MemMgr.getBlockDataRegion(BC, LC);
+ return loc::MemRegionVal(BD);
+}
+
diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp
index b6c4df87f272..a1f97f4eeb24 100644
--- a/lib/Basic/TargetInfo.cpp
+++ b/lib/Basic/TargetInfo.cpp
@@ -44,6 +44,7 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) {
Char16Type = UnsignedShort;
Char32Type = UnsignedInt;
Int64Type = SignedLongLong;
+ SigAtomicType = SignedInt;
FloatFormat = &llvm::APFloat::IEEEsingle;
DoubleFormat = &llvm::APFloat::IEEEdouble;
LongDoubleFormat = &llvm::APFloat::IEEEdouble;
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index 07c2bb960bcf..e5a4c434c341 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -313,6 +313,42 @@ public:
}
};
+// PS3 PPU Target
+template<typename Target>
+class PS3PPUTargetInfo : public OSTargetInfo<Target> {
+protected:
+ virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ std::vector<char> &Defs) const {
+ // PS3 PPU defines.
+ Define(Defs, "__PPU__", "1");
+ Define(Defs, "__CELLOS_LV2__", "1");
+ Define(Defs, "__ELF__", "1");
+ }
+public:
+ PS3PPUTargetInfo(const std::string& triple)
+ : OSTargetInfo<Target>(triple) {
+ this->UserLabelPrefix = "";
+ }
+};
+
+// FIXME: Need a real SPU target.
+// PS3 SPU Target
+template<typename Target>
+class PS3SPUTargetInfo : public OSTargetInfo<Target> {
+protected:
+ virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple,
+ std::vector<char> &Defs) const {
+ // PS3 PPU defines.
+ Define(Defs, "__SPU__", "1");
+ Define(Defs, "__ELF__", "1");
+ }
+public:
+ PS3SPUTargetInfo(const std::string& triple)
+ : OSTargetInfo<Target>(triple) {
+ this->UserLabelPrefix = "";
+ }
+};
+
// AuroraUX target
template<typename Target>
class AuroraUXTargetInfo : public OSTargetInfo<Target> {
@@ -445,6 +481,11 @@ void PPCTargetInfo::getTargetDefines(const LangOptions &Opts,
// FIXME: Should be controlled by command line option.
Define(Defs, "__LONG_DOUBLE_128__");
+
+ if (Opts.AltiVec) {
+ Define(Defs, "__VEC__", "10206");
+ Define(Defs, "__ALTIVEC__", "1");
+ }
}
@@ -1492,6 +1533,7 @@ namespace {
UIntMaxType = UnsignedLong;
IntPtrType = SignedShort;
PtrDiffType = SignedInt;
+ SigAtomicType = SignedLong;
FloatWidth = 32;
FloatAlign = 32;
DoubleWidth = 32;
@@ -1559,6 +1601,7 @@ namespace {
UIntMaxType = UnsignedLong;
IntPtrType = SignedShort;
PtrDiffType = SignedInt;
+ SigAtomicType = SignedLong;
DescriptionString = "e-p:16:8:8-i8:8:8-i16:8:8-i32:8:8-n8:16";
}
virtual void getTargetDefines(const LangOptions &Opts,
@@ -1990,6 +2033,8 @@ static TargetInfo *AllocateTarget(const std::string &T) {
case llvm::Triple::ppc64:
if (os == llvm::Triple::Darwin)
return new DarwinTargetInfo<PPC64TargetInfo>(T);
+ else if (os == llvm::Triple::Lv2)
+ return new PS3PPUTargetInfo<PPC64TargetInfo>(T);
return new PPC64TargetInfo(T);
case llvm::Triple::sparc:
@@ -1999,6 +2044,10 @@ static TargetInfo *AllocateTarget(const std::string &T) {
return new SolarisSparcV8TargetInfo(T);
return new SparcV8TargetInfo(T);
+ // FIXME: Need a real SPU target.
+ case llvm::Triple::cellspu:
+ return new PS3SPUTargetInfo<PPC64TargetInfo>(T);
+
case llvm::Triple::systemz:
return new SystemZTargetInfo(T);
diff --git a/lib/Basic/TokenKinds.cpp b/lib/Basic/TokenKinds.cpp
index 4afeaf01b776..8cdc1e31950c 100644
--- a/lib/Basic/TokenKinds.cpp
+++ b/lib/Basic/TokenKinds.cpp
@@ -30,59 +30,8 @@ const char *tok::getTokenName(enum TokenKind Kind) {
const char *tok::getTokenSimpleSpelling(enum TokenKind Kind) {
switch (Kind) {
- case tok::l_square: return "[";
- case tok::r_square: return "]";
- case tok::l_paren: return "(";
- case tok::r_paren: return ")";
- case tok::l_brace: return "{";
- case tok::r_brace: return "}";
- case tok::period: return ".";
- case tok::ellipsis: return "...";
- case tok::amp: return "&";
- case tok::ampamp: return "&&";
- case tok::ampequal: return "&=";
- case tok::star: return "*";
- case tok::starequal: return "*=";
- case tok::plus: return "+";
- case tok::plusplus: return "++";
- case tok::plusequal: return "+=";
- case tok::minus: return "-";
- case tok::arrow: return "->";
- case tok::minusminus: return "--";
- case tok::minusequal: return "-=";
- case tok::tilde: return "~";
- case tok::exclaim: return "!";
- case tok::exclaimequal: return "!=";
- case tok::slash: return "/";
- case tok::slashequal: return "/=";
- case tok::percent: return "%";
- case tok::percentequal: return "%=";
- case tok::less: return "<";
- case tok::lessless: return "<<";
- case tok::lessequal: return "<=";
- case tok::lesslessequal: return "<<=";
- case tok::greater: return ">";
- case tok::greatergreater: return ">>";
- case tok::greaterequal: return ">=";
- case tok::greatergreaterequal: return ">>=";
- case tok::caret: return "^";
- case tok::caretequal: return "^=";
- case tok::pipe: return "|";
- case tok::pipepipe: return "||";
- case tok::pipeequal: return "|=";
- case tok::question: return "?";
- case tok::colon: return ":";
- case tok::semi: return ";";
- case tok::equal: return "=";
- case tok::equalequal: return "==";
- case tok::comma: return ",";
- case tok::hash: return "#";
- case tok::hashhash: return "##";
- case tok::hashat: return "#@";
- case tok::periodstar: return ".*";
- case tok::arrowstar: return "->*";
- case tok::coloncolon: return "::";
- case tok::at: return "@";
+#define PUNCTUATOR(X,Y) case X: return Y;
+#include "clang/Basic/TokenKinds.def"
default: break;
}
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index bc9eb67674ff..2df779ce9f52 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -291,14 +291,14 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
(VD->getType().isObjCGCWeak() ? BLOCK_FIELD_IS_WEAK : 0);
llvm::Value *Loc = LocalDeclMap[VD];
Loc = Builder.CreateStructGEP(Loc, 1, "forwarding");
- Loc = Builder.CreateLoad(Loc, false);
+ Loc = Builder.CreateLoad(Loc);
Builder.CreateStore(Loc, Addr);
++helpersize;
continue;
} else
E = new (getContext()) DeclRefExpr (cast<NamedDecl>(VD),
- VD->getType(), SourceLocation(),
- false, false);
+ VD->getType(),
+ SourceLocation());
}
if (BDRE->isByRef()) {
NoteForHelper[helpersize].flag = BLOCK_FIELD_IS_BYREF |
@@ -331,7 +331,7 @@ llvm::Value *CodeGenFunction::BuildBlockLiteralTmp(const BlockExpr *BE) {
"block.literal");
Ty = llvm::PointerType::get(Ty, 0);
Loc = Builder.CreateBitCast(Loc, Ty);
- Loc = Builder.CreateLoad(Loc, false);
+ Loc = Builder.CreateLoad(Loc);
// Loc = Builder.CreateBitCast(Loc, Ty);
}
Builder.CreateStore(Loc, Addr);
@@ -494,7 +494,7 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr* E) {
E->arg_begin(), E->arg_end());
// Load the function.
- llvm::Value *Func = Builder.CreateLoad(FuncPtr, false, "tmp");
+ llvm::Value *Func = Builder.CreateLoad(FuncPtr, "tmp");
QualType ResultType = FnType->getAs<FunctionType>()->getResultType();
@@ -551,9 +551,9 @@ llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const BlockDeclRefExpr *E) {
const llvm::Type *Ty = PtrStructTy;
Ty = llvm::PointerType::get(Ty, 0);
V = Builder.CreateBitCast(V, Ty);
- V = Builder.CreateLoad(V, false);
+ V = Builder.CreateLoad(V);
V = Builder.CreateStructGEP(V, 1, "forwarding");
- V = Builder.CreateLoad(V, false);
+ V = Builder.CreateLoad(V);
V = Builder.CreateBitCast(V, PtrStructTy);
V = Builder.CreateStructGEP(V, getByRefValueLLVMField(VD),
VD->getNameAsString());
@@ -836,7 +836,7 @@ uint64_t BlockFunction::getBlockOffset(const BlockDeclRefExpr *BDRE) {
0, QualType(PadTy), 0, VarDecl::None);
Expr *E;
E = new (getContext()) DeclRefExpr(PadDecl, PadDecl->getType(),
- SourceLocation(), false, false);
+ SourceLocation());
BlockDeclRefDecls.push_back(E);
}
BlockDeclRefDecls.push_back(BDRE);
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
index 399b8733e720..be4c27ce53ad 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -530,7 +530,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Value *Ptr = EmitScalarExpr(E->getArg(0));
const llvm::Type *ElTy =
cast<llvm::PointerType>(Ptr->getType())->getElementType();
- Builder.CreateStore(llvm::Constant::getNullValue(ElTy), Ptr, true);
+ llvm::StoreInst *Store =
+ Builder.CreateStore(llvm::Constant::getNullValue(ElTy), Ptr);
+ Store->setVolatile(true);
return RValue::get(0);
}
@@ -813,6 +815,13 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,
Ops[0] = Builder.CreateBitCast(Ops[0], PtrTy);
return Builder.CreateStore(Ops[1], Ops[0]);
}
+ case X86::BI__builtin_ia32_palignr128:
+ case X86::BI__builtin_ia32_palignr: {
+ Function *F = CGM.getIntrinsic(BuiltinID == X86::BI__builtin_ia32_palignr128 ?
+ Intrinsic::x86_ssse3_palign_r_128 :
+ Intrinsic::x86_ssse3_palign_r);
+ return Builder.CreateCall(F, &Ops[0], &Ops[0] + Ops.size());
+ }
}
}
diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp
index b1d30a68bbb7..34d1c8d984a1 100644
--- a/lib/CodeGen/CGCXX.cpp
+++ b/lib/CodeGen/CGCXX.cpp
@@ -151,8 +151,7 @@ CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D,
"thread safe statics are currently not supported!");
llvm::SmallString<256> GuardVName;
- llvm::raw_svector_ostream GuardVOut(GuardVName);
- mangleGuardVariable(CGM.getMangleContext(), &D, GuardVOut);
+ CGM.getMangleContext().mangleGuardVariable(&D, GuardVName);
// Create the guard variable.
llvm::GlobalValue *GuardV =
@@ -197,11 +196,6 @@ RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD,
assert(MD->isInstance() &&
"Trying to emit a member call expr on a static method!");
- // A call to a trivial destructor requires no code generation.
- if (const CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(MD))
- if (Destructor->isTrivial())
- return RValue::get(0);
-
const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
CallArgList Args;
@@ -275,6 +269,14 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE) {
This = BaseLV.getAddress();
}
+ if (MD->isCopyAssignment() && MD->isTrivial()) {
+ // We don't like to generate the trivial copy assignment operator when
+ // it isn't necessary; just produce the proper effect here.
+ llvm::Value *RHS = EmitLValue(*CE->arg_begin()).getAddress();
+ EmitAggregateCopy(This, RHS, CE->getType());
+ return RValue::get(This);
+ }
+
// C++ [class.virtual]p12:
// Explicit qualification with the scope operator (5.1) suppresses the
// virtual call mechanism.
@@ -284,6 +286,8 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE) {
llvm::Value *Callee;
if (const CXXDestructorDecl *Destructor
= dyn_cast<CXXDestructorDecl>(MD)) {
+ if (Destructor->isTrivial())
+ return RValue::get(0);
if (MD->isVirtual() && !ME->hasQualifier() &&
!canDevirtualizeMemberFunctionCalls(ME->getBase())) {
Callee = BuildVirtualCall(Destructor, Dtor_Complete, This, Ty);
@@ -464,26 +468,31 @@ llvm::Value *CodeGenFunction::LoadCXXThis() {
/// It is assumed that all relevant checks have been made by the caller.
void
CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D,
- const ConstantArrayType *ArrayTy,
- llvm::Value *ArrayPtr) {
+ const ConstantArrayType *ArrayTy,
+ llvm::Value *ArrayPtr,
+ CallExpr::const_arg_iterator ArgBeg,
+ CallExpr::const_arg_iterator ArgEnd) {
+
const llvm::Type *SizeTy = ConvertType(getContext().getSizeType());
llvm::Value * NumElements =
llvm::ConstantInt::get(SizeTy,
getContext().getConstantArrayElementCount(ArrayTy));
- EmitCXXAggrConstructorCall(D, NumElements, ArrayPtr);
+ EmitCXXAggrConstructorCall(D, NumElements, ArrayPtr, ArgBeg, ArgEnd);
}
void
CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D,
- llvm::Value *NumElements,
- llvm::Value *ArrayPtr) {
+ llvm::Value *NumElements,
+ llvm::Value *ArrayPtr,
+ CallExpr::const_arg_iterator ArgBeg,
+ CallExpr::const_arg_iterator ArgEnd) {
const llvm::Type *SizeTy = ConvertType(getContext().getSizeType());
// Create a temporary for the loop index and initialize it with 0.
llvm::Value *IndexPtr = CreateTempAlloca(SizeTy, "loop.index");
llvm::Value *Zero = llvm::Constant::getNullValue(SizeTy);
- Builder.CreateStore(Zero, IndexPtr, false);
+ Builder.CreateStore(Zero, IndexPtr);
// Start the loop with a block that tests the condition.
llvm::BasicBlock *CondBlock = createBasicBlock("for.cond");
@@ -507,15 +516,31 @@ CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D,
Counter = Builder.CreateLoad(IndexPtr);
llvm::Value *Address = Builder.CreateInBoundsGEP(ArrayPtr, Counter,
"arrayidx");
- EmitCXXConstructorCall(D, Ctor_Complete, Address, 0, 0);
+ // C++ [class.temporary]p4:
+ // There are two contexts in which temporaries are destroyed at a different
+ // point than the end of the full- expression. The first context is when a
+ // default constructor is called to initialize an element of an array.
+ // If the constructor has one or more default arguments, the destruction of
+ // every temporary created in a default argument expression is sequenced
+ // before the construction of the next array element, if any.
+
+ // Keep track of the current number of live temporaries.
+ unsigned OldNumLiveTemporaries = LiveTemporaries.size();
+
+ EmitCXXConstructorCall(D, Ctor_Complete, Address, ArgBeg, ArgEnd);
+
+ // Pop temporaries.
+ while (LiveTemporaries.size() > OldNumLiveTemporaries)
+ PopCXXTemporary();
+
EmitBlock(ContinueBlock);
// Emit the increment of the loop counter.
llvm::Value *NextVal = llvm::ConstantInt::get(SizeTy, 1);
Counter = Builder.CreateLoad(IndexPtr);
NextVal = Builder.CreateAdd(Counter, NextVal, "inc");
- Builder.CreateStore(NextVal, IndexPtr, false);
+ Builder.CreateStore(NextVal, IndexPtr);
// Finally, branch back up to the condition for the next iteration.
EmitBranch(CondBlock);
@@ -551,7 +576,7 @@ CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D,
llvm::Value *IndexPtr = CreateTempAlloca(llvm::Type::getInt64Ty(VMContext),
"loop.index");
// Index = ElementCount;
- Builder.CreateStore(UpperCount, IndexPtr, false);
+ Builder.CreateStore(UpperCount, IndexPtr);
// Start the loop with a block that tests the condition.
llvm::BasicBlock *CondBlock = createBasicBlock("for.cond");
@@ -578,23 +603,14 @@ CodeGenFunction::EmitCXXAggrDestructorCall(const CXXDestructorDecl *D,
Counter = Builder.CreateLoad(IndexPtr);
Counter = Builder.CreateSub(Counter, One);
llvm::Value *Address = Builder.CreateInBoundsGEP(This, Counter, "arrayidx");
- 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);
+ EmitCXXDestructorCall(D, Dtor_Complete, Address);
EmitBlock(ContinueBlock);
// Emit the decrement of the loop counter.
Counter = Builder.CreateLoad(IndexPtr);
Counter = Builder.CreateSub(Counter, One, "dec");
- Builder.CreateStore(Counter, IndexPtr, false);
+ Builder.CreateStore(Counter, IndexPtr);
// Finally, branch back up to the condition for the next iteration.
EmitBranch(CondBlock);
@@ -664,6 +680,10 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
EmitAggregateCopy(This, Src, Ty);
return;
}
+ } else if (D->isTrivial()) {
+ // FIXME: Track down why we're trying to generate calls to the trivial
+ // default constructor!
+ return;
}
llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Type);
@@ -674,6 +694,15 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *D,
CXXDtorType Type,
llvm::Value *This) {
+ if (D->isVirtual()) {
+ const llvm::Type *Ty =
+ CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(D),
+ /*isVariadic=*/false);
+
+ llvm::Value *Callee = BuildVirtualCall(D, Dtor_Deleting, This, Ty);
+ EmitCXXMemberCall(D, Callee, This, 0, 0);
+ return;
+ }
llvm::Value *Callee = CGM.GetAddrOfCXXDestructor(D, Type);
EmitCXXMemberCall(D, Callee, This, 0, 0);
@@ -715,7 +744,8 @@ CodeGenFunction::EmitCXXConstructExpr(llvm::Value *Dest,
BasePtr = llvm::PointerType::getUnqual(BasePtr);
llvm::Value *BaseAddrPtr =
Builder.CreateBitCast(Dest, BasePtr);
- EmitCXXAggrConstructorCall(CD, Array, BaseAddrPtr);
+ EmitCXXAggrConstructorCall(CD, Array, BaseAddrPtr,
+ E->arg_begin(), E->arg_end());
}
else
// Call the constructor.
@@ -744,7 +774,7 @@ CodeGenModule::GetAddrOfCXXConstructor(const CXXConstructorDecl *D,
CXXCtorType Type) {
const FunctionProtoType *FPT = D->getType()->getAs<FunctionProtoType>();
const llvm::FunctionType *FTy =
- getTypes().GetFunctionType(getTypes().getFunctionInfo(D),
+ getTypes().GetFunctionType(getTypes().getFunctionInfo(D, Type),
FPT->isVariadic());
const char *Name = getMangledCXXCtorName(D, Type);
@@ -755,8 +785,7 @@ CodeGenModule::GetAddrOfCXXConstructor(const CXXConstructorDecl *D,
const char *CodeGenModule::getMangledCXXCtorName(const CXXConstructorDecl *D,
CXXCtorType Type) {
llvm::SmallString<256> Name;
- llvm::raw_svector_ostream Out(Name);
- mangleCXXCtor(getMangleContext(), D, Type, Out);
+ getMangleContext().mangleCXXCtor(D, Type, Name);
Name += '\0';
return UniqueMangledName(Name.begin(), Name.end());
@@ -764,9 +793,9 @@ 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);
+ EmitGlobalDefinition(GlobalDecl(D, Dtor_Deleting));
+ EmitGlobalDefinition(GlobalDecl(D, Dtor_Complete));
+ EmitGlobalDefinition(GlobalDecl(D, Dtor_Base));
}
void CodeGenModule::EmitCXXDestructor(const CXXDestructorDecl *D,
@@ -783,7 +812,7 @@ llvm::Function *
CodeGenModule::GetAddrOfCXXDestructor(const CXXDestructorDecl *D,
CXXDtorType Type) {
const llvm::FunctionType *FTy =
- getTypes().GetFunctionType(getTypes().getFunctionInfo(D), false);
+ getTypes().GetFunctionType(getTypes().getFunctionInfo(D, Type), false);
const char *Name = getMangledCXXDtorName(D, Type);
return cast<llvm::Function>(
@@ -793,59 +822,61 @@ CodeGenModule::GetAddrOfCXXDestructor(const CXXDestructorDecl *D,
const char *CodeGenModule::getMangledCXXDtorName(const CXXDestructorDecl *D,
CXXDtorType Type) {
llvm::SmallString<256> Name;
- llvm::raw_svector_ostream Out(Name);
- mangleCXXDtor(getMangleContext(), D, Type, Out);
+ getMangleContext().mangleCXXDtor(D, Type, Name);
Name += '\0';
return UniqueMangledName(Name.begin(), Name.end());
}
-llvm::Constant *CodeGenFunction::GenerateThunk(llvm::Function *Fn,
- const CXXMethodDecl *MD,
- bool Extern, int64_t nv,
- int64_t v) {
- return GenerateCovariantThunk(Fn, MD, Extern, nv, v, 0, 0);
+llvm::Constant *
+CodeGenFunction::GenerateThunk(llvm::Function *Fn, const CXXMethodDecl *MD,
+ bool Extern,
+ const ThunkAdjustment &ThisAdjustment) {
+ return GenerateCovariantThunk(Fn, MD, Extern,
+ CovariantThunkAdjustment(ThisAdjustment,
+ ThunkAdjustment()));
}
-llvm::Value *CodeGenFunction::DynamicTypeAdjust(llvm::Value *V, int64_t nv,
- int64_t v) {
- llvm::Type *Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext),
- 0);
+llvm::Value *
+CodeGenFunction::DynamicTypeAdjust(llvm::Value *V,
+ const ThunkAdjustment &Adjustment) {
+ const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext);
+
const llvm::Type *OrigTy = V->getType();
- if (nv) {
+ if (Adjustment.NonVirtual) {
// Do the non-virtual adjustment
- V = Builder.CreateBitCast(V, Ptr8Ty);
- V = Builder.CreateConstInBoundsGEP1_64(V, nv);
- V = Builder.CreateBitCast(V, OrigTy);
- }
- if (v) {
- // Do the virtual this adjustment
- const llvm::Type *PtrDiffTy =
- ConvertType(getContext().getPointerDiffType());
- llvm::Type *PtrPtr8Ty, *PtrPtrDiffTy;
- PtrPtr8Ty = llvm::PointerType::get(Ptr8Ty, 0);
- PtrPtrDiffTy = llvm::PointerType::get(PtrDiffTy, 0);
- llvm::Value *ThisVal = Builder.CreateBitCast(V, Ptr8Ty);
- V = Builder.CreateBitCast(V, PtrPtrDiffTy->getPointerTo());
- V = Builder.CreateLoad(V, "vtable");
- llvm::Value *VTablePtr = V;
- assert(v % (LLVMPointerWidth/8) == 0 && "vtable entry unaligned");
- v /= LLVMPointerWidth/8;
- V = Builder.CreateConstInBoundsGEP1_64(VTablePtr, v);
- V = Builder.CreateLoad(V);
- V = Builder.CreateGEP(ThisVal, V);
+ V = Builder.CreateBitCast(V, Int8PtrTy);
+ V = Builder.CreateConstInBoundsGEP1_64(V, Adjustment.NonVirtual);
V = Builder.CreateBitCast(V, OrigTy);
}
- return V;
+
+ if (!Adjustment.Virtual)
+ return V;
+
+ assert(Adjustment.Virtual % (LLVMPointerWidth / 8) == 0 &&
+ "vtable entry unaligned");
+
+ // Do the virtual this adjustment
+ const llvm::Type *PtrDiffTy = ConvertType(getContext().getPointerDiffType());
+ const llvm::Type *PtrDiffPtrTy = PtrDiffTy->getPointerTo();
+
+ llvm::Value *ThisVal = Builder.CreateBitCast(V, Int8PtrTy);
+ V = Builder.CreateBitCast(V, PtrDiffPtrTy->getPointerTo());
+ V = Builder.CreateLoad(V, "vtable");
+
+ llvm::Value *VTablePtr = V;
+ uint64_t VirtualAdjustment = Adjustment.Virtual / (LLVMPointerWidth / 8);
+ V = Builder.CreateConstInBoundsGEP1_64(VTablePtr, VirtualAdjustment);
+ V = Builder.CreateLoad(V);
+ V = Builder.CreateGEP(ThisVal, V);
+
+ return Builder.CreateBitCast(V, OrigTy);
}
-llvm::Constant *CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn,
- const CXXMethodDecl *MD,
- bool Extern,
- int64_t nv_t,
- int64_t v_t,
- int64_t nv_r,
- int64_t v_r) {
+llvm::Constant *
+CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn,
+ const CXXMethodDecl *MD, bool Extern,
+ const CovariantThunkAdjustment &Adjustment) {
QualType ResultType = MD->getType()->getAs<FunctionType>()->getResultType();
FunctionArgList Args;
@@ -878,16 +909,23 @@ llvm::Constant *CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn,
llvm::Value *Callee = CGM.GetAddrOfFunction(MD, Ty);
CallArgList CallArgs;
+ bool ShouldAdjustReturnPointer = true;
QualType ArgType = MD->getThisType(getContext());
llvm::Value *Arg = Builder.CreateLoad(LocalDeclMap[ThisDecl], "this");
- if (nv_t || v_t) {
+ if (!Adjustment.ThisAdjustment.isEmpty()) {
// Do the this adjustment.
const llvm::Type *OrigTy = Callee->getType();
- Arg = DynamicTypeAdjust(Arg, nv_t, v_t);
- if (nv_r || v_r) {
- Callee = CGM.BuildCovariantThunk(MD, Extern, 0, 0, nv_r, v_r);
+ Arg = DynamicTypeAdjust(Arg, Adjustment.ThisAdjustment);
+
+ if (!Adjustment.ReturnAdjustment.isEmpty()) {
+ const CovariantThunkAdjustment &ReturnAdjustment =
+ CovariantThunkAdjustment(ThunkAdjustment(),
+ Adjustment.ReturnAdjustment);
+
+ Callee = CGM.BuildCovariantThunk(MD, Extern, ReturnAdjustment);
+
Callee = Builder.CreateBitCast(Callee, OrigTy);
- nv_r = v_r = 0;
+ ShouldAdjustReturnPointer = false;
}
}
@@ -906,7 +944,7 @@ llvm::Constant *CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn,
RValue RV = EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs),
Callee, CallArgs, MD);
- if (nv_r || v_r) {
+ if (ShouldAdjustReturnPointer && !Adjustment.ReturnAdjustment.isEmpty()) {
bool CanBeZero = !(ResultType->isReferenceType()
// FIXME: attr nonnull can't be zero either
/* || ResultType->hasAttr<NonNullAttr>() */ );
@@ -921,7 +959,8 @@ llvm::Constant *CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn,
Builder.CreateCondBr(Builder.CreateICmpNE(RV.getScalarVal(), Zero),
NonZeroBlock, ZeroBlock);
EmitBlock(NonZeroBlock);
- llvm::Value *NZ = DynamicTypeAdjust(RV.getScalarVal(), nv_r, v_r);
+ llvm::Value *NZ =
+ DynamicTypeAdjust(RV.getScalarVal(), Adjustment.ReturnAdjustment);
EmitBranch(ContBlock);
EmitBlock(ZeroBlock);
llvm::Value *Z = RV.getScalarVal();
@@ -932,7 +971,8 @@ llvm::Constant *CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn,
RVOrZero->addIncoming(Z, ZeroBlock);
RV = RValue::get(RVOrZero);
} else
- RV = RValue::get(DynamicTypeAdjust(RV.getScalarVal(), nv_r, v_r));
+ RV = RValue::get(DynamicTypeAdjust(RV.getScalarVal(),
+ Adjustment.ReturnAdjustment));
}
if (!ResultType->isVoidType())
@@ -942,11 +982,13 @@ llvm::Constant *CodeGenFunction::GenerateCovariantThunk(llvm::Function *Fn,
return Fn;
}
-llvm::Constant *CodeGenModule::BuildThunk(const CXXMethodDecl *MD, bool Extern,
- int64_t nv, int64_t v) {
+llvm::Constant *
+CodeGenModule::BuildThunk(const CXXMethodDecl *MD, bool Extern,
+ const ThunkAdjustment &ThisAdjustment) {
+
llvm::SmallString<256> OutName;
- llvm::raw_svector_ostream Out(OutName);
- mangleThunk(getMangleContext(), MD, nv, v, Out);
+ getMangleContext().mangleThunk(MD, ThisAdjustment, OutName);
+
llvm::GlobalVariable::LinkageTypes linktype;
linktype = llvm::GlobalValue::WeakAnyLinkage;
if (!Extern)
@@ -957,20 +999,18 @@ llvm::Constant *CodeGenModule::BuildThunk(const CXXMethodDecl *MD, bool Extern,
getTypes().GetFunctionType(getTypes().getFunctionInfo(MD),
FPT->isVariadic());
- llvm::Function *Fn = llvm::Function::Create(FTy, linktype, Out.str(),
+ llvm::Function *Fn = llvm::Function::Create(FTy, linktype, OutName.str(),
&getModule());
- CodeGenFunction(*this).GenerateThunk(Fn, MD, Extern, nv, v);
+ CodeGenFunction(*this).GenerateThunk(Fn, MD, Extern, ThisAdjustment);
llvm::Constant *m = llvm::ConstantExpr::getBitCast(Fn, Ptr8Ty);
return m;
}
-llvm::Constant *CodeGenModule::BuildCovariantThunk(const CXXMethodDecl *MD,
- bool Extern, int64_t nv_t,
- int64_t v_t, int64_t nv_r,
- int64_t v_r) {
+llvm::Constant *
+CodeGenModule::BuildCovariantThunk(const CXXMethodDecl *MD, bool Extern,
+ const CovariantThunkAdjustment &Adjustment) {
llvm::SmallString<256> OutName;
- llvm::raw_svector_ostream Out(OutName);
- mangleCovariantThunk(getMangleContext(), MD, nv_t, v_t, nv_r, v_r, Out);
+ getMangleContext().mangleCovariantThunk(MD, Adjustment, OutName);
llvm::GlobalVariable::LinkageTypes linktype;
linktype = llvm::GlobalValue::WeakAnyLinkage;
if (!Extern)
@@ -981,10 +1021,9 @@ llvm::Constant *CodeGenModule::BuildCovariantThunk(const CXXMethodDecl *MD,
getTypes().GetFunctionType(getTypes().getFunctionInfo(MD),
FPT->isVariadic());
- llvm::Function *Fn = llvm::Function::Create(FTy, linktype, Out.str(),
+ llvm::Function *Fn = llvm::Function::Create(FTy, linktype, OutName.str(),
&getModule());
- CodeGenFunction(*this).GenerateCovariantThunk(Fn, MD, Extern, nv_t, v_t, nv_r,
- v_r);
+ CodeGenFunction(*this).GenerateCovariantThunk(Fn, MD, Extern, Adjustment);
llvm::Constant *m = llvm::ConstantExpr::getBitCast(Fn, Ptr8Ty);
return m;
}
@@ -1016,7 +1055,7 @@ CodeGenFunction::GetVirtualCXXBaseClassOffset(llvm::Value *This,
return VBaseOffset;
}
-static llvm::Value *BuildVirtualCall(CodeGenFunction &CGF, int64_t VtableIndex,
+static llvm::Value *BuildVirtualCall(CodeGenFunction &CGF, uint64_t VtableIndex,
llvm::Value *This, const llvm::Type *Ty) {
Ty = Ty->getPointerTo()->getPointerTo()->getPointerTo();
@@ -1032,7 +1071,7 @@ llvm::Value *
CodeGenFunction::BuildVirtualCall(const CXXMethodDecl *MD, llvm::Value *This,
const llvm::Type *Ty) {
MD = MD->getCanonicalDecl();
- int64_t VtableIndex = CGM.getVtableInfo().getMethodVtableIndex(MD);
+ uint64_t VtableIndex = CGM.getVtableInfo().getMethodVtableIndex(MD);
return ::BuildVirtualCall(*this, VtableIndex, This, Ty);
}
@@ -1041,7 +1080,7 @@ llvm::Value *
CodeGenFunction::BuildVirtualCall(const CXXDestructorDecl *DD, CXXDtorType Type,
llvm::Value *&This, const llvm::Type *Ty) {
DD = cast<CXXDestructorDecl>(DD->getCanonicalDecl());
- int64_t VtableIndex =
+ uint64_t VtableIndex =
CGM.getVtableInfo().getMethodVtableIndex(GlobalDecl(DD, Type));
return ::BuildVirtualCall(*this, VtableIndex, This, Ty);
@@ -1065,7 +1104,7 @@ void CodeGenFunction::EmitClassAggrMemberwiseCopy(llvm::Value *Dest,
"loop.index");
llvm::Value* zeroConstant =
llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext));
- Builder.CreateStore(zeroConstant, IndexPtr, false);
+ Builder.CreateStore(zeroConstant, IndexPtr);
// Start the loop with a block that tests the condition.
llvm::BasicBlock *CondBlock = createBasicBlock("for.cond");
llvm::BasicBlock *AfterFor = createBasicBlock("for.end");
@@ -1115,7 +1154,7 @@ void CodeGenFunction::EmitClassAggrMemberwiseCopy(llvm::Value *Dest,
llvm::Value *NextVal = llvm::ConstantInt::get(Counter->getType(), 1);
Counter = Builder.CreateLoad(IndexPtr);
NextVal = Builder.CreateAdd(Counter, NextVal, "inc");
- Builder.CreateStore(NextVal, IndexPtr, false);
+ Builder.CreateStore(NextVal, IndexPtr);
// Finally, branch back up to the condition for the next iteration.
EmitBranch(CondBlock);
@@ -1142,7 +1181,7 @@ void CodeGenFunction::EmitClassAggrCopyAssignment(llvm::Value *Dest,
"loop.index");
llvm::Value* zeroConstant =
llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext));
- Builder.CreateStore(zeroConstant, IndexPtr, false);
+ Builder.CreateStore(zeroConstant, IndexPtr);
// Start the loop with a block that tests the condition.
llvm::BasicBlock *CondBlock = createBasicBlock("for.cond");
llvm::BasicBlock *AfterFor = createBasicBlock("for.end");
@@ -1199,7 +1238,7 @@ void CodeGenFunction::EmitClassAggrCopyAssignment(llvm::Value *Dest,
llvm::Value *NextVal = llvm::ConstantInt::get(Counter->getType(), 1);
Counter = Builder.CreateLoad(IndexPtr);
NextVal = Builder.CreateAdd(Counter, NextVal, "inc");
- Builder.CreateStore(NextVal, IndexPtr, false);
+ Builder.CreateStore(NextVal, IndexPtr);
// Finally, branch back up to the condition for the next iteration.
EmitBranch(CondBlock);
@@ -1216,10 +1255,10 @@ void CodeGenFunction::EmitClassMemberwiseCopy(
const CXXRecordDecl *ClassDecl,
const CXXRecordDecl *BaseClassDecl, QualType Ty) {
if (ClassDecl) {
- Dest = GetAddressCXXOfBaseClass(Dest, ClassDecl, BaseClassDecl,
- /*NullCheckValue=*/false);
- Src = GetAddressCXXOfBaseClass(Src, ClassDecl, BaseClassDecl,
- /*NullCheckValue=*/false);
+ Dest = GetAddressOfBaseClass(Dest, ClassDecl, BaseClassDecl,
+ /*NullCheckValue=*/false);
+ Src = GetAddressOfBaseClass(Src, ClassDecl, BaseClassDecl,
+ /*NullCheckValue=*/false);
}
if (BaseClassDecl->hasTrivialCopyConstructor()) {
EmitAggregateCopy(Dest, Src, Ty);
@@ -1255,10 +1294,10 @@ void CodeGenFunction::EmitClassCopyAssignment(
const CXXRecordDecl *BaseClassDecl,
QualType Ty) {
if (ClassDecl) {
- Dest = GetAddressCXXOfBaseClass(Dest, ClassDecl, BaseClassDecl,
- /*NullCheckValue=*/false);
- Src = GetAddressCXXOfBaseClass(Src, ClassDecl, BaseClassDecl,
- /*NullCheckValue=*/false);
+ Dest = GetAddressOfBaseClass(Dest, ClassDecl, BaseClassDecl,
+ /*NullCheckValue=*/false);
+ Src = GetAddressOfBaseClass(Src, ClassDecl, BaseClassDecl,
+ /*NullCheckValue=*/false);
}
if (BaseClassDecl->hasTrivialCopyAssignment()) {
EmitAggregateCopy(Dest, Src, Ty);
@@ -1297,6 +1336,7 @@ CodeGenFunction::SynthesizeDefaultConstructor(const CXXConstructorDecl *Ctor,
CXXCtorType Type,
llvm::Function *Fn,
const FunctionArgList &Args) {
+ assert(!Ctor->isTrivial() && "shouldn't need to generate trivial ctor");
StartFunction(GlobalDecl(Ctor, Type), Ctor->getResultType(), Fn, Args,
SourceLocation());
EmitCtorPrologue(Ctor, Type);
@@ -1326,6 +1366,7 @@ CodeGenFunction::SynthesizeCXXCopyConstructor(const CXXConstructorDecl *Ctor,
const CXXRecordDecl *ClassDecl = Ctor->getParent();
assert(!ClassDecl->hasUserDeclaredCopyConstructor() &&
"SynthesizeCXXCopyConstructor - copy constructor has definition already");
+ assert(!Ctor->isTrivial() && "shouldn't need to generate trivial ctor");
StartFunction(GlobalDecl(Ctor, Type), Ctor->getResultType(), Fn, Args,
SourceLocation());
@@ -1349,10 +1390,11 @@ CodeGenFunction::SynthesizeCXXCopyConstructor(const CXXConstructorDecl *Ctor,
Base->getType());
}
- for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
- FieldEnd = ClassDecl->field_end();
- Field != FieldEnd; ++Field) {
- QualType FieldType = getContext().getCanonicalType((*Field)->getType());
+ 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());
const ConstantArrayType *Array =
getContext().getAsConstantArrayType(FieldType);
if (Array)
@@ -1361,8 +1403,8 @@ CodeGenFunction::SynthesizeCXXCopyConstructor(const CXXConstructorDecl *Ctor,
if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
CXXRecordDecl *FieldClassDecl
= cast<CXXRecordDecl>(FieldClassType->getDecl());
- LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0);
- LValue RHS = EmitLValueForField(LoadOfSrc, *Field, false, 0);
+ LValue LHS = EmitLValueForField(LoadOfThis, Field, false, 0);
+ LValue RHS = EmitLValueForField(LoadOfSrc, Field, false, 0);
if (Array) {
const llvm::Type *BasePtr = ConvertType(FieldType);
BasePtr = llvm::PointerType::getUnqual(BasePtr);
@@ -1378,9 +1420,28 @@ CodeGenFunction::SynthesizeCXXCopyConstructor(const CXXConstructorDecl *Ctor,
0 /*ClassDecl*/, FieldClassDecl, FieldType);
continue;
}
+
+ if (Field->getType()->isReferenceType()) {
+ unsigned FieldIndex = CGM.getTypes().getLLVMFieldNo(Field);
+
+ llvm::Value *LHS = Builder.CreateStructGEP(LoadOfThis, FieldIndex,
+ "lhs.ref");
+
+ llvm::Value *RHS = Builder.CreateStructGEP(LoadOfThis, FieldIndex,
+ "rhs.ref");
+
+ // Load the value in RHS.
+ RHS = Builder.CreateLoad(RHS);
+
+ // And store it in the LHS
+ Builder.CreateStore(RHS, LHS);
+
+ continue;
+ }
// Do a built-in assignment of scalar data members.
- LValue LHS = EmitLValueForField(LoadOfThis, *Field, false, 0);
- LValue RHS = EmitLValueForField(LoadOfSrc, *Field, false, 0);
+ LValue LHS = EmitLValueForField(LoadOfThis, Field, false, 0);
+ LValue RHS = EmitLValueForField(LoadOfSrc, Field, false, 0);
+
if (!hasAggregateLLVMType(Field->getType())) {
RValue RVRHS = EmitLoadOfLValue(RHS, Field->getType());
EmitStoreThroughLValue(RVRHS, LHS, Field->getType());
@@ -1498,9 +1559,9 @@ static void EmitBaseInitializer(CodeGenFunction &CGF,
const Type *BaseType = BaseInit->getBaseClass();
CXXRecordDecl *BaseClassDecl =
cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl());
- llvm::Value *V = CGF.GetAddressCXXOfBaseClass(ThisPtr, ClassDecl,
- BaseClassDecl,
- /*NullCheckValue=*/false);
+ llvm::Value *V = CGF.GetAddressOfBaseClass(ThisPtr, ClassDecl,
+ BaseClassDecl,
+ /*NullCheckValue=*/false);
CGF.EmitCXXConstructorCall(BaseInit->getConstructor(),
CtorType, V,
BaseInit->const_arg_begin(),
@@ -1564,7 +1625,9 @@ static void EmitMemberInitializer(CodeGenFunction &CGF,
llvm::Value *BaseAddrPtr =
CGF.Builder.CreateBitCast(LHS.getAddress(), BasePtr);
CGF.EmitCXXAggrConstructorCall(MemberInit->getConstructor(),
- Array, BaseAddrPtr);
+ Array, BaseAddrPtr,
+ MemberInit->const_arg_begin(),
+ MemberInit->const_arg_end());
}
else
CGF.EmitCXXConstructorCall(MemberInit->getConstructor(),
@@ -1714,12 +1777,12 @@ void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD,
// Ignore trivial destructors.
if (BaseClassDecl->hasTrivialDestructor())
continue;
-
- llvm::Value *V = GetAddressCXXOfBaseClass(LoadCXXThis(),
- ClassDecl, BaseClassDecl,
- /*NullCheckValue=*/false);
- EmitCXXDestructorCall(BaseClassDecl->getDestructor(getContext()),
- Dtor_Base, V);
+ const CXXDestructorDecl *D = BaseClassDecl->getDestructor(getContext());
+
+ llvm::Value *V = GetAddressOfBaseClass(LoadCXXThis(),
+ ClassDecl, BaseClassDecl,
+ /*NullCheckValue=*/false);
+ EmitCXXDestructorCall(D, Dtor_Base, V);
}
// If we're emitting a base destructor, we don't want to emit calls to the
@@ -1727,10 +1790,21 @@ void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD,
if (DtorType == Dtor_Base)
return;
- // FIXME: Handle virtual bases.
+ // 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.");
+ const CXXBaseSpecifier &Base = *I;
+ CXXRecordDecl *BaseClassDecl
+ = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
+
+ // Ignore trivial destructors.
+ if (BaseClassDecl->hasTrivialDestructor())
+ continue;
+ const CXXDestructorDecl *D = BaseClassDecl->getDestructor(getContext());
+ llvm::Value *V = GetAddressOfBaseClass(LoadCXXThis(),
+ ClassDecl, BaseClassDecl,
+ /*NullCheckValue=*/false);
+ EmitCXXDestructorCall(D, Dtor_Base, V);
}
// If we have a deleting destructor, emit a call to the delete operator.
@@ -1752,9 +1826,3 @@ void CodeGenFunction::SynthesizeDefaultDestructor(const CXXDestructorDecl *Dtor,
EmitDtorEpilogue(Dtor, DtorType);
FinishFunction();
}
-
-// 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/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index d0c7d03f20ef..decc73c6d458 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -91,6 +91,42 @@ const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXMethodDecl *MD) {
getCallingConventionForDecl(MD));
}
+const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXConstructorDecl *D,
+ CXXCtorType Type) {
+ llvm::SmallVector<QualType, 16> ArgTys;
+
+ // Add the 'this' pointer.
+ ArgTys.push_back(D->getThisType(Context));
+
+ // Check if we need to add a VTT parameter (which has type void **).
+ if (Type == Ctor_Base && D->getParent()->getNumVBases() != 0)
+ ArgTys.push_back(Context.getPointerType(Context.VoidPtrTy));
+
+ const FunctionProtoType *FTP = D->getType()->getAs<FunctionProtoType>();
+ for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i)
+ ArgTys.push_back(FTP->getArgType(i));
+ return getFunctionInfo(FTP->getResultType(), ArgTys,
+ getCallingConventionForDecl(D));
+}
+
+const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const CXXDestructorDecl *D,
+ CXXDtorType Type) {
+ llvm::SmallVector<QualType, 16> ArgTys;
+
+ // Add the 'this' pointer.
+ ArgTys.push_back(D->getThisType(Context));
+
+ // Check if we need to add a VTT parameter (which has type void **).
+ if (Type == Dtor_Base && D->getParent()->getNumVBases() != 0)
+ ArgTys.push_back(Context.getPointerType(Context.VoidPtrTy));
+
+ const FunctionProtoType *FTP = D->getType()->getAs<FunctionProtoType>();
+ for (unsigned i = 0, e = FTP->getNumArgs(); i != e; ++i)
+ ArgTys.push_back(FTP->getArgType(i));
+ return getFunctionInfo(FTP->getResultType(), ArgTys,
+ getCallingConventionForDecl(D));
+}
+
const CGFunctionInfo &CodeGenTypes::getFunctionInfo(const FunctionDecl *FD) {
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD))
if (MD->isInstance())
@@ -418,6 +454,32 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI, bool IsVariadic) {
return llvm::FunctionType::get(ResultType, ArgTys, IsVariadic);
}
+static bool HasIncompleteReturnTypeOrArgumentTypes(const FunctionProtoType *T) {
+ if (const TagType *TT = T->getResultType()->getAs<TagType>()) {
+ if (!TT->getDecl()->isDefinition())
+ return true;
+ }
+
+ for (unsigned i = 0, e = T->getNumArgs(); i != e; ++i) {
+ if (const TagType *TT = T->getArgType(i)->getAs<TagType>()) {
+ if (!TT->getDecl()->isDefinition())
+ return true;
+ }
+ }
+
+ return false;
+}
+
+const llvm::Type *
+CodeGenTypes::GetFunctionTypeForVtable(const CXXMethodDecl *MD) {
+ const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
+
+ if (!HasIncompleteReturnTypeOrArgumentTypes(FPT))
+ return GetFunctionType(getFunctionInfo(MD), FPT->isVariadic());
+
+ return llvm::OpaqueType::get(getLLVMContext());
+}
+
void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI,
const Decl *TargetDecl,
AttributeListType &PAL,
diff --git a/lib/CodeGen/CGCXXClass.cpp b/lib/CodeGen/CGClass.cpp
index 533aabc8616e..b3c2b986d190 100644
--- a/lib/CodeGen/CGCXXClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -1,4 +1,4 @@
-//===--- CGCXXClass.cpp - Emit LLVM Code for C++ classes ------------------===//
+//===--- CGClass.cpp - Emit LLVM Code for C++ classes ---------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -31,9 +31,6 @@ 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 =
@@ -75,7 +72,7 @@ static llvm::Value *GetCXXBaseClassOffset(CodeGenFunction &CGF,
const CXXRecordDecl *ClassDecl,
const CXXRecordDecl *BaseClassDecl) {
CXXBasePaths Paths(/*FindAmbiguities=*/false,
- /*RecordPaths=*/true, /*DetectVirtual=*/true);
+ /*RecordPaths=*/true, /*DetectVirtual=*/false);
if (!const_cast<CXXRecordDecl *>(ClassDecl)->
isDerivedFrom(const_cast<CXXRecordDecl *>(BaseClassDecl), Paths)) {
assert(false && "Class must be derived from the passed in base class!");
@@ -84,21 +81,20 @@ static llvm::Value *GetCXXBaseClassOffset(CodeGenFunction &CGF,
unsigned Start = 0;
llvm::Value *VirtualOffset = 0;
- if (const RecordType *RT = Paths.getDetectedVirtual()) {
- const CXXRecordDecl *VBase = cast<CXXRecordDecl>(RT->getDecl());
-
- VirtualOffset =
- CGF.GetVirtualCXXBaseClassOffset(BaseValue, ClassDecl, VBase);
-
- const CXXBasePath &Path = Paths.front();
- unsigned e = Path.size();
- for (Start = 0; Start != e; ++Start) {
- const CXXBasePathElement& Element = Path[Start];
-
- if (Element.Class == VBase)
- break;
+
+ const CXXBasePath &Path = Paths.front();
+ const CXXRecordDecl *VBase = 0;
+ for (unsigned i = 0, e = Path.size(); i != e; ++i) {
+ const CXXBasePathElement& Element = Path[i];
+ if (Element.Base->isVirtual()) {
+ Start = i+1;
+ QualType VBaseType = Element.Base->getType();
+ VBase = cast<CXXRecordDecl>(VBaseType->getAs<RecordType>()->getDecl());
}
}
+ if (VBase)
+ VirtualOffset =
+ CGF.GetVirtualCXXBaseClassOffset(BaseValue, ClassDecl, VBase);
uint64_t Offset =
ComputeNonVirtualBaseClassOffset(CGF.getContext(), Paths, Start);
@@ -117,10 +113,10 @@ static llvm::Value *GetCXXBaseClassOffset(CodeGenFunction &CGF,
}
llvm::Value *
-CodeGenFunction::GetAddressCXXOfBaseClass(llvm::Value *BaseValue,
- const CXXRecordDecl *ClassDecl,
- const CXXRecordDecl *BaseClassDecl,
- bool NullCheckValue) {
+CodeGenFunction::GetAddressOfBaseClass(llvm::Value *Value,
+ const CXXRecordDecl *ClassDecl,
+ const CXXRecordDecl *BaseClassDecl,
+ bool NullCheckValue) {
QualType BTy =
getContext().getCanonicalType(
getContext().getTypeDeclType(const_cast<CXXRecordDecl*>(BaseClassDecl)));
@@ -128,7 +124,7 @@ CodeGenFunction::GetAddressCXXOfBaseClass(llvm::Value *BaseValue,
if (ClassDecl == BaseClassDecl) {
// Just cast back.
- return Builder.CreateBitCast(BaseValue, BasePtrTy);
+ return Builder.CreateBitCast(Value, BasePtrTy);
}
llvm::BasicBlock *CastNull = 0;
@@ -141,8 +137,8 @@ CodeGenFunction::GetAddressCXXOfBaseClass(llvm::Value *BaseValue,
CastEnd = createBasicBlock("cast.end");
llvm::Value *IsNull =
- Builder.CreateICmpEQ(BaseValue,
- llvm::Constant::getNullValue(BaseValue->getType()));
+ Builder.CreateICmpEQ(Value,
+ llvm::Constant::getNullValue(Value->getType()));
Builder.CreateCondBr(IsNull, CastNull, CastNotNull);
EmitBlock(CastNotNull);
}
@@ -150,16 +146,16 @@ CodeGenFunction::GetAddressCXXOfBaseClass(llvm::Value *BaseValue,
const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(VMContext);
llvm::Value *Offset =
- GetCXXBaseClassOffset(*this, BaseValue, ClassDecl, BaseClassDecl);
+ GetCXXBaseClassOffset(*this, Value, ClassDecl, BaseClassDecl);
if (Offset) {
// Apply the offset.
- BaseValue = Builder.CreateBitCast(BaseValue, Int8PtrTy);
- BaseValue = Builder.CreateGEP(BaseValue, Offset, "add.ptr");
+ Value = Builder.CreateBitCast(Value, Int8PtrTy);
+ Value = Builder.CreateGEP(Value, Offset, "add.ptr");
}
// Cast back.
- BaseValue = Builder.CreateBitCast(BaseValue, BasePtrTy);
+ Value = Builder.CreateBitCast(Value, BasePtrTy);
if (NullCheckValue) {
Builder.CreateBr(CastEnd);
@@ -167,13 +163,73 @@ CodeGenFunction::GetAddressCXXOfBaseClass(llvm::Value *BaseValue,
Builder.CreateBr(CastEnd);
EmitBlock(CastEnd);
- llvm::PHINode *PHI = Builder.CreatePHI(BaseValue->getType());
+ llvm::PHINode *PHI = Builder.CreatePHI(Value->getType());
+ PHI->reserveOperandSpace(2);
+ PHI->addIncoming(Value, CastNotNull);
+ PHI->addIncoming(llvm::Constant::getNullValue(Value->getType()),
+ CastNull);
+ Value = PHI;
+ }
+
+ return Value;
+}
+
+llvm::Value *
+CodeGenFunction::GetAddressOfDerivedClass(llvm::Value *Value,
+ const CXXRecordDecl *ClassDecl,
+ const CXXRecordDecl *DerivedClassDecl,
+ bool NullCheckValue) {
+ QualType DerivedTy =
+ getContext().getCanonicalType(
+ getContext().getTypeDeclType(const_cast<CXXRecordDecl*>(DerivedClassDecl)));
+ const llvm::Type *DerivedPtrTy = ConvertType(DerivedTy)->getPointerTo();
+
+ if (ClassDecl == DerivedClassDecl) {
+ // Just cast back.
+ return Builder.CreateBitCast(Value, DerivedPtrTy);
+ }
+
+ llvm::BasicBlock *CastNull = 0;
+ llvm::BasicBlock *CastNotNull = 0;
+ llvm::BasicBlock *CastEnd = 0;
+
+ if (NullCheckValue) {
+ CastNull = createBasicBlock("cast.null");
+ CastNotNull = createBasicBlock("cast.notnull");
+ CastEnd = createBasicBlock("cast.end");
+
+ llvm::Value *IsNull =
+ Builder.CreateICmpEQ(Value,
+ llvm::Constant::getNullValue(Value->getType()));
+ Builder.CreateCondBr(IsNull, CastNull, CastNotNull);
+ EmitBlock(CastNotNull);
+ }
+
+ llvm::Value *Offset = GetCXXBaseClassOffset(*this, Value, DerivedClassDecl,
+ ClassDecl);
+ if (Offset) {
+ // Apply the offset.
+ Value = Builder.CreatePtrToInt(Value, Offset->getType());
+ Value = Builder.CreateSub(Value, Offset);
+ Value = Builder.CreateIntToPtr(Value, DerivedPtrTy);
+ } else {
+ // Just cast.
+ Value = Builder.CreateBitCast(Value, DerivedPtrTy);
+ }
+
+ if (NullCheckValue) {
+ Builder.CreateBr(CastEnd);
+ EmitBlock(CastNull);
+ Builder.CreateBr(CastEnd);
+ EmitBlock(CastEnd);
+
+ llvm::PHINode *PHI = Builder.CreatePHI(Value->getType());
PHI->reserveOperandSpace(2);
- PHI->addIncoming(BaseValue, CastNotNull);
- PHI->addIncoming(llvm::Constant::getNullValue(BaseValue->getType()),
+ PHI->addIncoming(Value, CastNotNull);
+ PHI->addIncoming(llvm::Constant::getNullValue(Value->getType()),
CastNull);
- BaseValue = PHI;
+ Value = PHI;
}
- return BaseValue;
+ return Value;
}
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index 055166721085..317da7e46a75 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -95,10 +95,10 @@ llvm::DICompileUnit CGDebugInfo::getOrCreateCompileUnit(SourceLocation Loc) {
// file at a time.
bool isMain = false;
const LangOptions &LO = M->getLangOptions();
- const char *MainFileName = LO.getMainFileName();
+ const CodeGenOptions &CGO = M->getCodeGenOpts();
if (isMainCompileUnitCreated == false) {
- if (MainFileName) {
- if (!strcmp(AbsFileName.getLast().c_str(), MainFileName))
+ if (!CGO.MainFileName.empty()) {
+ if (AbsFileName.getLast() == CGO.MainFileName)
isMain = true;
} else {
if (Loc.isValid() && SM.isFromMainFile(Loc))
@@ -417,7 +417,7 @@ llvm::DIType CGDebugInfo::CreateType(const TypedefType *Ty,
llvm::DIType DbgTy =
DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_typedef, Unit,
- Ty->getDecl()->getNameAsCString(),
+ Ty->getDecl()->getName(),
DefUnit, Line, 0, 0, 0, 0, Src);
return DbgTy;
}
@@ -482,7 +482,7 @@ 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, Decl->getNameAsString().data(),
+ DebugFactory.CreateCompositeType(Tag, Unit, Decl->getName(),
DefUnit, Line, 0, 0, 0, 0,
llvm::DIType(), llvm::DIArray());
@@ -507,10 +507,10 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty,
FieldDecl *Field = *I;
llvm::DIType FieldTy = getOrCreateType(Field->getType(), Unit);
- const char *FieldName = Field->getNameAsCString();
+ llvm::StringRef FieldName = Field->getName();
// Ignore unnamed fields.
- if (!FieldName)
+ if (FieldName.empty())
continue;
// Get the location for the field.
@@ -558,7 +558,7 @@ llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty,
uint64_t Align = M->getContext().getTypeAlign(Ty);
llvm::DICompositeType RealDecl =
- DebugFactory.CreateCompositeType(Tag, Unit, Decl->getNameAsString().data(),
+ DebugFactory.CreateCompositeType(Tag, Unit, Decl->getName(),
DefUnit, Line, Size, Align, 0, 0,
llvm::DIType(), Elements);
@@ -592,7 +592,7 @@ 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, Decl->getNameAsCString(),
+ DebugFactory.CreateCompositeType(Tag, Unit, Decl->getName(),
DefUnit, Line, 0, 0, 0, 0,
llvm::DIType(), llvm::DIArray(),
RuntimeLang);
@@ -628,10 +628,10 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
ObjCIvarDecl *Field = *I;
llvm::DIType FieldTy = getOrCreateType(Field->getType(), Unit);
- const char *FieldName = Field->getNameAsCString();
+ llvm::StringRef FieldName = Field->getName();
// Ignore unnamed fields.
- if (!FieldName)
+ if (FieldName.empty())
continue;
// Get the location for the field.
@@ -682,7 +682,7 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
uint64_t Align = M->getContext().getTypeAlign(Ty);
llvm::DICompositeType RealDecl =
- DebugFactory.CreateCompositeType(Tag, Unit, Decl->getNameAsCString(), DefUnit,
+ DebugFactory.CreateCompositeType(Tag, Unit, Decl->getName(), DefUnit,
Line, Size, Align, 0, 0, llvm::DIType(),
Elements, RuntimeLang);
@@ -703,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->getNameAsCString(),
+ Enumerators.push_back(DebugFactory.CreateEnumerator(Enum->getName(),
Enum->getInitVal().getZExtValue()));
}
@@ -728,7 +728,7 @@ llvm::DIType CGDebugInfo::CreateType(const EnumType *Ty,
llvm::DIType DbgTy =
DebugFactory.CreateCompositeType(llvm::dwarf::DW_TAG_enumeration_type,
- Unit, Decl->getNameAsCString(), DefUnit, Line,
+ Unit, Decl->getName(), DefUnit, Line,
Size, Align, 0, 0,
llvm::DIType(), EltArray);
return DbgTy;
@@ -1104,7 +1104,7 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag,
FieldAlign = Align*8;
FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
- Decl->getNameAsCString(), DefUnit,
+ Decl->getName(), DefUnit,
0, FieldSize, FieldAlign,
FieldOffset, 0, FieldTy);
EltTys.push_back(FieldTy);
@@ -1135,7 +1135,7 @@ void CGDebugInfo::EmitDeclare(const VarDecl *Decl, unsigned Tag,
// Create the descriptor for the variable.
llvm::DIVariable D =
DebugFactory.CreateVariable(Tag, llvm::DIDescriptor(RegionStack.back()),
- Decl->getNameAsCString(),
+ Decl->getName(),
Unit, Line, Ty);
// Insert an llvm.dbg.declare into the current block.
llvm::Instruction *Call =
@@ -1282,7 +1282,7 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag,
XOffset = FieldOffset;
FieldTy = DebugFactory.CreateDerivedType(llvm::dwarf::DW_TAG_member, Unit,
- Decl->getNameAsCString(), DefUnit,
+ Decl->getName(), DefUnit,
0, FieldSize, FieldAlign,
FieldOffset, 0, FieldTy);
EltTys.push_back(FieldTy);
@@ -1336,7 +1336,7 @@ void CGDebugInfo::EmitDeclare(const BlockDeclRefExpr *BDRE, unsigned Tag,
// Create the descriptor for the variable.
llvm::DIVariable D =
DebugFactory.CreateComplexVariable(Tag, llvm::DIDescriptor(RegionStack.back()),
- Decl->getNameAsCString(), Unit, Line, Ty,
+ Decl->getName(), Unit, Line, Ty,
addr);
// Insert an llvm.dbg.declare into the current block.
llvm::Instruction *Call =
@@ -1392,9 +1392,9 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
T = M->getContext().getConstantArrayType(ET, ConstVal,
ArrayType::Normal, 0);
}
- const char *DeclName = Decl->getNameAsCString();
+ llvm::StringRef DeclName = Decl->getName();
DebugFactory.CreateGlobalVariable(getContext(Decl, Unit), DeclName, DeclName,
- NULL, Unit, LineNo,
+ llvm::StringRef(), Unit, LineNo,
getOrCreateType(T, Unit),
Var->hasInternalLinkage(),
true/*definition*/, Var);
@@ -1409,7 +1409,7 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
PresumedLoc PLoc = SM.getPresumedLoc(Decl->getLocation());
unsigned LineNo = PLoc.isInvalid() ? 0 : PLoc.getLine();
- const char *Name = Decl->getNameAsCString();
+ llvm::StringRef Name = Decl->getName();
QualType T = M->getContext().getObjCInterfaceType(Decl);
if (T->isIncompleteArrayType()) {
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index 349ede51c63b..c0472830925d 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -30,7 +30,9 @@ using namespace CodeGen;
void CodeGenFunction::EmitDecl(const Decl &D) {
switch (D.getKind()) {
- default: assert(0 && "Unknown decl kind!");
+ default:
+ CGM.ErrorUnsupported(&D, "decl");
+ return;
case Decl::ParmVar:
assert(0 && "Parmdecls should not be in declstmts!");
case Decl::Function: // void X();
@@ -38,7 +40,9 @@ void CodeGenFunction::EmitDecl(const Decl &D) {
case Decl::Enum: // enum X;
case Decl::EnumConstant: // enum ? { X = ? }
case Decl::CXXRecord: // struct/union/class X; [C++]
- case Decl::UsingDirective: // using X; [C++]
+ case Decl::Using: // using X; [C++]
+ case Decl::UsingShadow:
+ case Decl::UsingDirective: // using namespace X; [C++]
// None of these decls require codegen support.
return;
@@ -372,7 +376,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
{
// Push a cleanup block and restore the stack there.
- CleanupScope scope(*this);
+ DelayedCleanupBlock scope(*this);
V = Builder.CreateLoad(Stack, "tmp");
llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::stackrestore);
@@ -517,7 +521,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
if (const ConstantArrayType *Array =
getContext().getAsConstantArrayType(Ty)) {
- CleanupScope Scope(*this);
+ DelayedCleanupBlock Scope(*this);
QualType BaseElementTy = getContext().getBaseElementType(Array);
const llvm::Type *BasePtr = ConvertType(BaseElementTy);
BasePtr = llvm::PointerType::getUnqual(BasePtr);
@@ -528,7 +532,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
// Make sure to jump to the exit block.
EmitBranch(Scope.getCleanupExitBlock());
} else {
- CleanupScope Scope(*this);
+ DelayedCleanupBlock Scope(*this);
EmitCXXDestructorCall(D, Dtor_Complete, DeclPtr);
}
}
@@ -541,7 +545,7 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
llvm::Constant* F = CGM.GetAddrOfFunction(FD);
assert(F && "Could not find function!");
- CleanupScope scope(*this);
+ DelayedCleanupBlock scope(*this);
const CGFunctionInfo &Info = CGM.getTypes().getFunctionInfo(FD);
@@ -562,9 +566,9 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
}
if (needsDispose && CGM.getLangOptions().getGCMode() != LangOptions::GCOnly) {
- CleanupScope scope(*this);
+ DelayedCleanupBlock scope(*this);
llvm::Value *V = Builder.CreateStructGEP(DeclPtr, 1, "forwarding");
- V = Builder.CreateLoad(V, false);
+ V = Builder.CreateLoad(V);
BuildBlockRelease(V);
}
}
diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp
index adfd0055f936..420e275becd1 100644
--- a/lib/CodeGen/CGException.cpp
+++ b/lib/CodeGen/CGException.cpp
@@ -11,6 +11,10 @@
//
//===----------------------------------------------------------------------===//
+#include "clang/AST/StmtCXX.h"
+
+#include "llvm/Intrinsics.h"
+
#include "CodeGenFunction.h"
using namespace clang;
using namespace CodeGen;
@@ -35,29 +39,158 @@ static llvm::Constant *getThrowFn(CodeGenFunction &CGF) {
std::vector<const llvm::Type*> Args(3, Int8PtrTy);
const llvm::FunctionType *FTy =
- llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()),
- Args, false);
+ llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()),
+ Args, false);
return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_throw");
}
+static llvm::Constant *getReThrowFn(CodeGenFunction &CGF) {
+ // void __cxa_rethrow ();
+
+ const llvm::FunctionType *FTy =
+ llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false);
+
+ return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_rethrow");
+}
+
+static llvm::Constant *getBeginCatchFn(CodeGenFunction &CGF) {
+ // void* __cxa_begin_catch ();
+
+ const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
+ std::vector<const llvm::Type*> Args(1, Int8PtrTy);
+
+ const llvm::FunctionType *FTy =
+ llvm::FunctionType::get(Int8PtrTy, Args, false);
+
+ return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_begin_catch");
+}
+
+static llvm::Constant *getEndCatchFn(CodeGenFunction &CGF) {
+ // void __cxa_end_catch ();
+
+ const llvm::FunctionType *FTy =
+ llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false);
+
+ return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_end_catch");
+}
+
+// FIXME: Eventually this will all go into the backend. Set from the target for
+// now.
+static int using_sjlj_exceptions = 0;
+
+static llvm::Constant *getUnwindResumeOrRethrowFn(CodeGenFunction &CGF) {
+ const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
+ std::vector<const llvm::Type*> Args(1, Int8PtrTy);
+
+ const llvm::FunctionType *FTy =
+ llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), Args,
+ false);
+
+ if (using_sjlj_exceptions)
+ return CGF.CGM.CreateRuntimeFunction(FTy, "_Unwind_SjLj_Resume");
+ return CGF.CGM.CreateRuntimeFunction(FTy, "_Unwind_Resume_or_Rethrow");
+}
+
+// CopyObject - Utility to copy an object. Calls copy constructor as necessary.
+// N is casted to the right type.
+static void CopyObject(CodeGenFunction &CGF, const Expr *E, llvm::Value *N) {
+ QualType ObjectType = E->getType();
+
+ // Store the throw exception in the exception object.
+ if (!CGF.hasAggregateLLVMType(ObjectType)) {
+ llvm::Value *Value = CGF.EmitScalarExpr(E);
+ const llvm::Type *ValuePtrTy = Value->getType()->getPointerTo(0);
+
+ CGF.Builder.CreateStore(Value, CGF.Builder.CreateBitCast(N, ValuePtrTy));
+ } else {
+ const llvm::Type *Ty = CGF.ConvertType(ObjectType)->getPointerTo(0);
+ const CXXRecordDecl *RD;
+ RD = cast<CXXRecordDecl>(ObjectType->getAs<RecordType>()->getDecl());
+ llvm::Value *This = CGF.Builder.CreateBitCast(N, Ty);
+ if (RD->hasTrivialCopyConstructor()) {
+ CGF.EmitAggExpr(E, This, false);
+ } else if (CXXConstructorDecl *CopyCtor
+ = RD->getCopyConstructor(CGF.getContext(), 0)) {
+ // FIXME: region management
+ llvm::Value *Src = CGF.EmitLValue(E).getAddress();
+
+ // Stolen from EmitClassAggrMemberwiseCopy
+ llvm::Value *Callee = CGF.CGM.GetAddrOfCXXConstructor(CopyCtor,
+ Ctor_Complete);
+ CallArgList CallArgs;
+ CallArgs.push_back(std::make_pair(RValue::get(This),
+ CopyCtor->getThisType(CGF.getContext())));
+
+ // Push the Src ptr.
+ CallArgs.push_back(std::make_pair(RValue::get(Src),
+ CopyCtor->getParamDecl(0)->getType()));
+ QualType ResultType =
+ CopyCtor->getType()->getAs<FunctionType>()->getResultType();
+ CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(ResultType, CallArgs),
+ Callee, CallArgs, CopyCtor);
+ // FIXME: region management
+ } else
+ CGF.ErrorUnsupported(E, "uncopyable object");
+ }
+}
+
+// CopyObject - Utility to copy an object. Calls copy constructor as necessary.
+// N is casted to the right type.
+static void CopyObject(CodeGenFunction &CGF, QualType ObjectType,
+ llvm::Value *E, llvm::Value *N) {
+ // Store the throw exception in the exception object.
+ if (!CGF.hasAggregateLLVMType(ObjectType)) {
+ llvm::Value *Value = E;
+ const llvm::Type *ValuePtrTy = Value->getType()->getPointerTo(0);
+
+ CGF.Builder.CreateStore(Value, CGF.Builder.CreateBitCast(N, ValuePtrTy));
+ } else {
+ const llvm::Type *Ty = CGF.ConvertType(ObjectType)->getPointerTo(0);
+ const CXXRecordDecl *RD;
+ RD = cast<CXXRecordDecl>(ObjectType->getAs<RecordType>()->getDecl());
+ llvm::Value *This = CGF.Builder.CreateBitCast(N, Ty);
+ if (RD->hasTrivialCopyConstructor()) {
+ CGF.EmitAggregateCopy(This, E, ObjectType);
+ } else if (CXXConstructorDecl *CopyCtor
+ = RD->getCopyConstructor(CGF.getContext(), 0)) {
+ // FIXME: region management
+ llvm::Value *Src = E;
+
+ // Stolen from EmitClassAggrMemberwiseCopy
+ llvm::Value *Callee = CGF.CGM.GetAddrOfCXXConstructor(CopyCtor,
+ Ctor_Complete);
+ CallArgList CallArgs;
+ CallArgs.push_back(std::make_pair(RValue::get(This),
+ CopyCtor->getThisType(CGF.getContext())));
+
+ // Push the Src ptr.
+ CallArgs.push_back(std::make_pair(RValue::get(Src),
+ CopyCtor->getParamDecl(0)->getType()));
+ QualType ResultType =
+ CopyCtor->getType()->getAs<FunctionType>()->getResultType();
+ CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(ResultType, CallArgs),
+ Callee, CallArgs, CopyCtor);
+ // FIXME: region management
+ } else
+ llvm::llvm_unreachable("uncopyable object");
+ }
+}
+
void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) {
- // FIXME: Handle rethrows.
if (!E->getSubExpr()) {
- ErrorUnsupported(E, "rethrow expression");
+ Builder.CreateCall(getReThrowFn(*this))->setDoesNotReturn();
+ Builder.CreateUnreachable();
+
+ // Clear the insertion point to indicate we are in unreachable code.
+ Builder.ClearInsertionPoint();
return;
}
QualType ThrowType = E->getSubExpr()->getType();
- // FIXME: We only handle non-class types for now.
- if (ThrowType->isRecordType()) {
- ErrorUnsupported(E, "throw expression");
- return;
- }
-
// FIXME: Handle cleanup.
if (!CleanupEntries.empty()){
- ErrorUnsupported(E, "throw expression");
+ ErrorUnsupported(E, "throw expression with cleanup entries");
return;
}
@@ -71,28 +204,11 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) {
llvm::ConstantInt::get(SizeTy, TypeSize),
"exception");
- // Store the throw exception in the exception object.
- if (!hasAggregateLLVMType(ThrowType)) {
- llvm::Value *Value = EmitScalarExpr(E->getSubExpr());
- const llvm::Type *ValuePtrTy = Value->getType()->getPointerTo(0);
-
- Builder.CreateStore(Value, Builder.CreateBitCast(ExceptionPtr, ValuePtrTy));
- } else {
- // FIXME: Handle complex and aggregate expressions.
- ErrorUnsupported(E, "throw expression");
- }
+ CopyObject(*this, E->getSubExpr(), ExceptionPtr);
// Now throw the exception.
const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext());
-
- llvm::SmallString<256> OutName;
- llvm::raw_svector_ostream Out(OutName);
- mangleCXXRtti(CGM.getMangleContext(), ThrowType, Out);
-
- // FIXME: Is it OK to use CreateRuntimeVariable for this?
- llvm::Constant *TypeInfo =
- CGM.CreateRuntimeVariable(llvm::Type::getInt8Ty(getLLVMContext()),
- OutName.c_str());
+ llvm::Constant *TypeInfo = CGM.GenerateRtti(ThrowType);
llvm::Constant *Dtor = llvm::Constant::getNullValue(Int8PtrTy);
llvm::CallInst *ThrowCall =
@@ -103,3 +219,217 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) {
// Clear the insertion point to indicate we are in unreachable code.
Builder.ClearInsertionPoint();
}
+
+void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) {
+#if 1
+ EmitStmt(S.getTryBlock());
+ if (0) {
+ getBeginCatchFn(*this);
+ getEndCatchFn(*this);
+ getUnwindResumeOrRethrowFn(*this);
+ CopyObject(*this, QualType(), 0, 0);
+ }
+#else
+ // FIXME: The below is still just a sketch of the code we need.
+ // Pointer to the personality function
+ llvm::Constant *Personality =
+ CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty
+ (VMContext),
+ true),
+ "__gxx_personality_v0");
+ Personality = llvm::ConstantExpr::getBitCast(Personality, PtrToInt8Ty);
+
+ llvm::BasicBlock *PrevLandingPad = getInvokeDest();
+ llvm::BasicBlock *TryHandler = createBasicBlock("try.handler");
+#if 0
+ llvm::BasicBlock *FinallyBlock = createBasicBlock("finally");
+#endif
+ llvm::BasicBlock *FinallyRethrow = createBasicBlock("finally.throw");
+ llvm::BasicBlock *FinallyEnd = createBasicBlock("finally.end");
+
+#if 0
+ // Push an EH context entry, used for handling rethrows.
+ PushCleanupBlock(FinallyBlock);
+#endif
+
+ // Emit the statements in the try {} block
+ setInvokeDest(TryHandler);
+
+ EmitStmt(S.getTryBlock());
+
+ // Jump to end if there is no exception
+ EmitBranchThroughCleanup(FinallyEnd);
+
+ // Emit the handlers
+ EmitBlock(TryHandler);
+
+ const llvm::IntegerType *Int8Ty;
+ const llvm::PointerType *PtrToInt8Ty;
+ Int8Ty = llvm::Type::getInt8Ty(VMContext);
+ // C string type. Used in lots of places.
+ PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty);
+ llvm::Constant *Null = llvm::ConstantPointerNull::get(PtrToInt8Ty);
+ llvm::SmallVector<llvm::Value*, 8> SelectorArgs;
+ llvm::Value *llvm_eh_exception =
+ CGM.getIntrinsic(llvm::Intrinsic::eh_exception);
+ llvm::Value *llvm_eh_selector =
+ CGM.getIntrinsic(llvm::Intrinsic::eh_selector);
+ llvm::Value *llvm_eh_typeid_for =
+ CGM.getIntrinsic(llvm::Intrinsic::eh_typeid_for);
+ // Exception object
+ llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc");
+ llvm::Value *RethrowPtr = CreateTempAlloca(Exc->getType(), "_rethrow");
+
+ SelectorArgs.push_back(Exc);
+ SelectorArgs.push_back(Personality);
+
+ bool HasCatchAll = false;
+ for (unsigned i = 0; i<S.getNumHandlers(); ++i) {
+ const CXXCatchStmt *C = S.getHandler(i);
+ VarDecl *CatchParam = C->getExceptionDecl();
+ if (CatchParam) {
+ llvm::Value *EHType = CGM.GenerateRtti(C->getCaughtType().getNonReferenceType());
+ SelectorArgs.push_back(EHType);
+ } else {
+ // null indicates catch all
+ SelectorArgs.push_back(Null);
+ HasCatchAll = true;
+ }
+ }
+
+ // We use a cleanup unless there was already a catch all.
+ if (!HasCatchAll) {
+ SelectorArgs.push_back(Null);
+ }
+
+ // Find which handler was matched.
+ llvm::Value *Selector
+ = Builder.CreateCall(llvm_eh_selector, SelectorArgs.begin(),
+ SelectorArgs.end(), "selector");
+ for (unsigned i = 0; i<S.getNumHandlers(); ++i) {
+ const CXXCatchStmt *C = S.getHandler(i);
+ VarDecl *CatchParam = C->getExceptionDecl();
+ Stmt *CatchBody = C->getHandlerBlock();
+
+ llvm::BasicBlock *Next = 0;
+
+ if (SelectorArgs[i+2] != Null) {
+ llvm::BasicBlock *Match = createBasicBlock("match");
+ Next = createBasicBlock("catch.next");
+ const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext());
+ llvm::Value *Id
+ = Builder.CreateCall(llvm_eh_typeid_for,
+ Builder.CreateBitCast(SelectorArgs[i+2],
+ Int8PtrTy));
+ Builder.CreateCondBr(Builder.CreateICmpEQ(Selector, Id),
+ Match, Next);
+ EmitBlock(Match);
+ }
+
+ llvm::BasicBlock *MatchEnd = createBasicBlock("match.end");
+ llvm::BasicBlock *MatchHandler = createBasicBlock("match.handler");
+
+ PushCleanupBlock(MatchEnd);
+ setInvokeDest(MatchHandler);
+
+ llvm::Value *ExcObject = Builder.CreateCall(getBeginCatchFn(*this), Exc);
+
+ // Bind the catch parameter if it exists.
+ if (CatchParam) {
+ QualType CatchType = CatchParam->getType().getNonReferenceType();
+ if (!CatchType.getTypePtr()->isPointerType())
+ CatchType = getContext().getPointerType(CatchType);
+ ExcObject =
+ Builder.CreateBitCast(ExcObject, ConvertType(CatchType));
+ // CatchParam is a ParmVarDecl because of the grammar
+ // construction used to handle this, but for codegen purposes
+ // we treat this as a local decl.
+ EmitLocalBlockVarDecl(*CatchParam);
+#if 0
+ // FIXME: objects with ctors, references
+ Builder.CreateStore(ExcObject, GetAddrOfLocalVar(CatchParam));
+#else
+ CopyObject(*this, CatchParam->getType().getNonReferenceType(),
+ ExcObject, GetAddrOfLocalVar(CatchParam));
+#endif
+ }
+
+ EmitStmt(CatchBody);
+ EmitBranchThroughCleanup(FinallyEnd);
+
+ EmitBlock(MatchHandler);
+
+ llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc");
+ // We are required to emit this call to satisfy LLVM, even
+ // though we don't use the result.
+ llvm::SmallVector<llvm::Value*, 8> Args;
+ Args.push_back(Exc);
+ Args.push_back(Personality);
+ Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
+ 0));
+ Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end());
+ Builder.CreateStore(Exc, RethrowPtr);
+ EmitBranchThroughCleanup(FinallyRethrow);
+
+ CodeGenFunction::CleanupBlockInfo Info = PopCleanupBlock();
+
+ EmitBlock(MatchEnd);
+
+ // Unfortunately, we also have to generate another EH frame here
+ // in case this throws.
+ llvm::BasicBlock *MatchEndHandler =
+ createBasicBlock("match.end.handler");
+ llvm::BasicBlock *Cont = createBasicBlock("myinvoke.cont");
+ Builder.CreateInvoke(getEndCatchFn(*this),
+ Cont, MatchEndHandler,
+ Args.begin(), Args.begin());
+
+ EmitBlock(Cont);
+ if (Info.SwitchBlock)
+ EmitBlock(Info.SwitchBlock);
+ if (Info.EndBlock)
+ EmitBlock(Info.EndBlock);
+
+ EmitBlock(MatchEndHandler);
+ Exc = Builder.CreateCall(llvm_eh_exception, "exc");
+ // We are required to emit this call to satisfy LLVM, even
+ // though we don't use the result.
+ Args.clear();
+ Args.push_back(Exc);
+ Args.push_back(Personality);
+ Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
+ 0));
+ Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end());
+ Builder.CreateStore(Exc, RethrowPtr);
+ EmitBranchThroughCleanup(FinallyRethrow);
+
+ if (Next)
+ EmitBlock(Next);
+ }
+ if (!HasCatchAll)
+ EmitBranchThroughCleanup(FinallyRethrow);
+
+ CodeGenFunction::CleanupBlockInfo Info = PopCleanupBlock();
+
+ setInvokeDest(PrevLandingPad);
+
+#if 0
+ EmitBlock(FinallyBlock);
+
+ if (Info.SwitchBlock)
+ EmitBlock(Info.SwitchBlock);
+ if (Info.EndBlock)
+ EmitBlock(Info.EndBlock);
+
+ // Branch around the rethrow code.
+ EmitBranch(FinallyEnd);
+#endif
+
+ EmitBlock(FinallyRethrow);
+ Builder.CreateCall(getUnwindResumeOrRethrowFn(*this),
+ Builder.CreateLoad(RethrowPtr));
+ Builder.CreateUnreachable();
+
+ EmitBlock(FinallyEnd);
+#endif
+}
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index 2a544c560931..63fca2d4ddab 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -137,7 +137,7 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E,
const CXXDestructorDecl *Dtor =
ClassDecl->getDestructor(getContext());
- CleanupScope scope(*this);
+ DelayedCleanupBlock scope(*this);
EmitCXXDestructorCall(Dtor, Dtor_Complete, Val.getAggregateAddr());
}
}
@@ -148,8 +148,8 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E,
if (BaseClassDecl) {
llvm::Value *Derived = Val.getAggregateAddr();
llvm::Value *Base =
- GetAddressCXXOfBaseClass(Derived, DerivedClassDecl, BaseClassDecl,
- /*NullCheckValue=*/false);
+ GetAddressOfBaseClass(Derived, DerivedClassDecl, BaseClassDecl,
+ /*NullCheckValue=*/false);
return RValue::get(Base);
}
}
@@ -258,8 +258,6 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
case Expr::BlockDeclRefExprClass:
return EmitBlockDeclRefLValue(cast<BlockDeclRefExpr>(E));
- case Expr::CXXConditionDeclExprClass:
- return EmitCXXConditionDeclLValue(cast<CXXConditionDeclExpr>(E));
case Expr::CXXTemporaryObjectExprClass:
case Expr::CXXConstructExprClass:
return EmitCXXConstructLValue(cast<CXXConstructExpr>(E));
@@ -314,9 +312,12 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
llvm::Value *CodeGenFunction::EmitLoadOfScalar(llvm::Value *Addr, bool Volatile,
QualType Ty) {
- llvm::Value *V = Builder.CreateLoad(Addr, Volatile, "tmp");
+ llvm::LoadInst *Load = Builder.CreateLoad(Addr, "tmp");
+ if (Volatile)
+ Load->setVolatile(true);
// Bool can have different representation in memory than in registers.
+ llvm::Value *V = Load;
if (Ty->isBooleanType())
if (V->getType() != llvm::Type::getInt1Ty(VMContext))
V = Builder.CreateTrunc(V, llvm::Type::getInt1Ty(VMContext), "tobool");
@@ -830,6 +831,24 @@ static LValue EmitGlobalVarDeclLValue(CodeGenFunction &CGF,
return LV;
}
+static LValue EmitFunctionDeclLValue(CodeGenFunction &CGF,
+ const Expr *E, const FunctionDecl *FD) {
+ llvm::Value* V = CGF.CGM.GetAddrOfFunction(FD);
+ if (!FD->hasPrototype()) {
+ if (const FunctionProtoType *Proto =
+ FD->getType()->getAs<FunctionProtoType>()) {
+ // Ugly case: for a K&R-style definition, the type of the definition
+ // isn't the same as the type of a use. Correct for this with a
+ // bitcast.
+ QualType NoProtoType =
+ CGF.getContext().getFunctionNoProtoType(Proto->getResultType());
+ NoProtoType = CGF.getContext().getPointerType(NoProtoType);
+ V = CGF.Builder.CreateBitCast(V, CGF.ConvertType(NoProtoType), "tmp");
+ }
+ }
+ return LValue::MakeAddr(V, CGF.MakeQualifiers(E->getType()));
+}
+
LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
const NamedDecl *ND = E->getDecl();
@@ -851,7 +870,7 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
if (VD->hasAttr<BlocksAttr>()) {
V = Builder.CreateStructGEP(V, 1, "forwarding");
- V = Builder.CreateLoad(V, false);
+ V = Builder.CreateLoad(V);
V = Builder.CreateStructGEP(V, getByRefValueLLVMField(VD),
VD->getNameAsString());
}
@@ -863,22 +882,8 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
return LV;
}
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
- llvm::Value* V = CGM.GetAddrOfFunction(FD);
- if (!FD->hasPrototype()) {
- if (const FunctionProtoType *Proto =
- FD->getType()->getAs<FunctionProtoType>()) {
- // Ugly case: for a K&R-style definition, the type of the definition
- // isn't the same as the type of a use. Correct for this with a
- // bitcast.
- QualType NoProtoType =
- getContext().getFunctionNoProtoType(Proto->getResultType());
- NoProtoType = getContext().getPointerType(NoProtoType);
- V = Builder.CreateBitCast(V, ConvertType(NoProtoType), "tmp");
- }
- }
- return LValue::MakeAddr(V, MakeQualifiers(E->getType()));
- }
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND))
+ return EmitFunctionDeclLValue(*this, E, FD);
if (E->getQualifier()) {
// FIXME: the qualifier check does not seem sufficient here
@@ -1165,7 +1170,10 @@ LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) {
if (VarDecl *VD = dyn_cast<VarDecl>(ND))
return EmitGlobalVarDeclLValue(*this, E, VD);
-
+
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND))
+ return EmitFunctionDeclLValue(*this, E, FD);
+
assert(false && "Unhandled member declaration!");
return LValue();
}
@@ -1328,8 +1336,8 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
// Perform the derived-to-base conversion
llvm::Value *Base =
- GetAddressCXXOfBaseClass(LV.getAddress(), DerivedClassDecl,
- BaseClassDecl, /*NullCheckValue=*/false);
+ GetAddressOfBaseClass(LV.getAddress(), DerivedClassDecl,
+ BaseClassDecl, /*NullCheckValue=*/false);
return LValue::MakeAddr(Base, MakeQualifiers(E->getType()));
}
@@ -1340,7 +1348,23 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {
return LValue::MakeAddr(Temp, MakeQualifiers(E->getType()));
}
case CastExpr::CK_BaseToDerived: {
- return EmitUnsupportedLValue(E, "base-to-derived cast lvalue");
+ const RecordType *BaseClassTy =
+ E->getSubExpr()->getType()->getAs<RecordType>();
+ CXXRecordDecl *BaseClassDecl =
+ cast<CXXRecordDecl>(BaseClassTy->getDecl());
+
+ const RecordType *DerivedClassTy = E->getType()->getAs<RecordType>();
+ CXXRecordDecl *DerivedClassDecl =
+ cast<CXXRecordDecl>(DerivedClassTy->getDecl());
+
+ LValue LV = EmitLValue(E->getSubExpr());
+
+ // Perform the base-to-derived conversion
+ llvm::Value *Derived =
+ GetAddressOfDerivedClass(LV.getAddress(), BaseClassDecl,
+ DerivedClassDecl, /*NullCheckValue=*/false);
+
+ return LValue::MakeAddr(Derived, MakeQualifiers(E->getType()));
}
case CastExpr::CK_BitCast: {
// This must be a reinterpret_cast (or c-style equivalent).
@@ -1460,12 +1484,6 @@ LValue CodeGenFunction::EmitVAArgExprLValue(const VAArgExpr *E) {
return LValue::MakeAddr(Temp, MakeQualifiers(E->getType()));
}
-LValue
-CodeGenFunction::EmitCXXConditionDeclLValue(const CXXConditionDeclExpr *E) {
- EmitLocalBlockVarDecl(*E->getVarDecl());
- return EmitDeclRefLValue(E);
-}
-
LValue CodeGenFunction::EmitCXXConstructLValue(const CXXConstructExpr *E) {
llvm::Value *Temp = CreateTempAlloca(ConvertTypeForMem(E->getType()), "tmp");
EmitCXXConstructExpr(Temp, E);
diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp
index 0e10368ab04e..d225d907c8ae 100644
--- a/lib/CodeGen/CGExprAgg.cpp
+++ b/lib/CodeGen/CGExprAgg.cpp
@@ -20,7 +20,6 @@
#include "llvm/Constants.h"
#include "llvm/Function.h"
#include "llvm/GlobalVariable.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/Intrinsics.h"
using namespace clang;
using namespace CodeGen;
@@ -30,7 +29,7 @@ using namespace CodeGen;
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN AggExprEmitter : public StmtVisitor<AggExprEmitter> {
+class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
CodeGenFunction &CGF;
CGBuilderTy &Builder;
llvm::Value *DestPtr;
@@ -223,6 +222,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
break;
}
+ case CastExpr::CK_DerivedToBaseMemberPointer:
case CastExpr::CK_BaseToDerivedMemberPointer: {
QualType SrcType = E->getSubExpr()->getType();
@@ -242,16 +242,22 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
llvm::Value *DstAdj = Builder.CreateStructGEP(DestPtr, 1, "dst.adj");
// Now See if we need to update the adjustment.
- const CXXRecordDecl *SrcDecl =
+ const CXXRecordDecl *BaseDecl =
cast<CXXRecordDecl>(SrcType->getAs<MemberPointerType>()->
getClass()->getAs<RecordType>()->getDecl());
- const CXXRecordDecl *DstDecl =
+ const CXXRecordDecl *DerivedDecl =
cast<CXXRecordDecl>(E->getType()->getAs<MemberPointerType>()->
getClass()->getAs<RecordType>()->getDecl());
-
- llvm::Constant *Adj = CGF.CGM.GetCXXBaseClassOffset(DstDecl, SrcDecl);
- if (Adj)
- SrcAdj = Builder.CreateAdd(SrcAdj, Adj, "adj");
+ if (E->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer)
+ std::swap(DerivedDecl, BaseDecl);
+
+ llvm::Constant *Adj = CGF.CGM.GetCXXBaseClassOffset(DerivedDecl, BaseDecl);
+ if (Adj) {
+ if (E->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer)
+ SrcAdj = Builder.CreateSub(SrcAdj, Adj, "adj");
+ else
+ SrcAdj = Builder.CreateAdd(SrcAdj, Adj, "adj");
+ }
Builder.CreateStore(SrcAdj, DstAdj, VolatileDest);
break;
@@ -389,21 +395,21 @@ void AggExprEmitter::VisitConditionalOperator(const ConditionalOperator *E) {
llvm::Value *Cond = CGF.EvaluateExprAsBool(E->getCond());
Builder.CreateCondBr(Cond, LHSBlock, RHSBlock);
- CGF.PushConditionalTempDestruction();
+ CGF.StartConditionalBranch();
CGF.EmitBlock(LHSBlock);
// Handle the GNU extension for missing LHS.
assert(E->getLHS() && "Must have LHS for aggregate value");
Visit(E->getLHS());
- CGF.PopConditionalTempDestruction();
+ CGF.FinishConditionalBranch();
CGF.EmitBranch(ContBlock);
- CGF.PushConditionalTempDestruction();
+ CGF.StartConditionalBranch();
CGF.EmitBlock(RHSBlock);
Visit(E->getRHS());
- CGF.PopConditionalTempDestruction();
+ CGF.FinishConditionalBranch();
CGF.EmitBranch(ContBlock);
CGF.EmitBlock(ContBlock);
diff --git a/lib/CodeGen/CGCXXExpr.cpp b/lib/CodeGen/CGExprCXX.cpp
index cd7d21b3b951..b982c15683ec 100644
--- a/lib/CodeGen/CGCXXExpr.cpp
+++ b/lib/CodeGen/CGExprCXX.cpp
@@ -1,4 +1,4 @@
-//===--- CGCXXExpr.cpp - Emit LLVM Code for C++ expressions ---------------===//
+//===--- CGExprCXX.cpp - Emit LLVM Code for C++ expressions ---------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -83,38 +83,41 @@ static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF,
static void EmitNewInitializer(CodeGenFunction &CGF, const CXXNewExpr *E,
llvm::Value *NewPtr,
llvm::Value *NumElements) {
+ if (E->isArray()) {
+ if (CXXConstructorDecl *Ctor = E->getConstructor())
+ CGF.EmitCXXAggrConstructorCall(Ctor, NumElements, NewPtr,
+ E->constructor_arg_begin(),
+ E->constructor_arg_end());
+ return;
+ }
+
QualType AllocType = E->getAllocatedType();
- if (!E->isArray()) {
- if (CXXConstructorDecl *Ctor = E->getConstructor()) {
- CGF.EmitCXXConstructorCall(Ctor, Ctor_Complete, NewPtr,
- E->constructor_arg_begin(),
- E->constructor_arg_end());
+ if (CXXConstructorDecl *Ctor = E->getConstructor()) {
+ CGF.EmitCXXConstructorCall(Ctor, Ctor_Complete, NewPtr,
+ E->constructor_arg_begin(),
+ E->constructor_arg_end());
- return;
- }
+ return;
+ }
- // We have a POD type.
- if (E->getNumConstructorArgs() == 0)
- return;
+ // We have a POD type.
+ if (E->getNumConstructorArgs() == 0)
+ return;
- assert(E->getNumConstructorArgs() == 1 &&
- "Can only have one argument to initializer of POD type.");
+ assert(E->getNumConstructorArgs() == 1 &&
+ "Can only have one argument to initializer of POD type.");
- const Expr *Init = E->getConstructorArg(0);
+ const Expr *Init = E->getConstructorArg(0);
- if (!CGF.hasAggregateLLVMType(AllocType))
- CGF.Builder.CreateStore(CGF.EmitScalarExpr(Init), NewPtr);
- else if (AllocType->isAnyComplexType())
- CGF.EmitComplexExprIntoAddr(Init, NewPtr,
- AllocType.isVolatileQualified());
- else
- CGF.EmitAggExpr(Init, NewPtr, AllocType.isVolatileQualified());
- return;
- }
-
- if (CXXConstructorDecl *Ctor = E->getConstructor())
- CGF.EmitCXXAggrConstructorCall(Ctor, NumElements, NewPtr);
+ if (!CGF.hasAggregateLLVMType(AllocType))
+ CGF.EmitStoreOfScalar(CGF.EmitScalarExpr(Init), NewPtr,
+ AllocType.isVolatileQualified(), AllocType);
+ else if (AllocType->isAnyComplexType())
+ CGF.EmitComplexExprIntoAddr(Init, NewPtr,
+ AllocType.isVolatileQualified());
+ else
+ CGF.EmitAggExpr(Init, NewPtr, AllocType.isVolatileQualified());
}
llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
@@ -359,7 +362,7 @@ llvm::Value * CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) {
return Builder.CreateBitCast(CGM.GenerateRttiRef(RD), LTy);
return Builder.CreateBitCast(CGM.GenerateRtti(RD), LTy);
}
- return Builder.CreateBitCast(CGM.GenerateRttiNonClass(Ty), LTy);
+ return Builder.CreateBitCast(CGM.GenerateRtti(Ty), LTy);
}
Expr *subE = E->getExprOperand();
Ty = subE->getType();
@@ -403,7 +406,7 @@ llvm::Value * CodeGenFunction::EmitCXXTypeidExpr(const CXXTypeidExpr *E) {
}
return Builder.CreateBitCast(CGM.GenerateRtti(RD), LTy);
}
- return Builder.CreateBitCast(CGM.GenerateRttiNonClass(Ty), LTy);
+ return Builder.CreateBitCast(CGM.GenerateRtti(Ty), LTy);
}
llvm::Value *CodeGenFunction::EmitDynamicCast(llvm::Value *V,
diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp
index 9e81e4fbeabe..7fa8ffbd5515 100644
--- a/lib/CodeGen/CGExprComplex.cpp
+++ b/lib/CodeGen/CGExprComplex.cpp
@@ -18,7 +18,6 @@
#include "llvm/Constants.h"
#include "llvm/Function.h"
#include "llvm/ADT/SmallString.h"
-#include "llvm/Support/Compiler.h"
using namespace clang;
using namespace CodeGen;
@@ -29,7 +28,7 @@ using namespace CodeGen;
typedef CodeGenFunction::ComplexPairTy ComplexPairTy;
namespace {
-class VISIBILITY_HIDDEN ComplexExprEmitter
+class ComplexExprEmitter
: public StmtVisitor<ComplexExprEmitter, ComplexPairTy> {
CodeGenFunction &CGF;
CGBuilderTy &Builder;
@@ -261,34 +260,18 @@ public:
/// load the real and imaginary pieces, returning them as Real/Imag.
ComplexPairTy ComplexExprEmitter::EmitLoadOfComplex(llvm::Value *SrcPtr,
bool isVolatile) {
- llvm::SmallString<64> Name(SrcPtr->getName().begin(),
- SrcPtr->getName().end());
-
llvm::Value *Real=0, *Imag=0;
if (!IgnoreReal) {
- // FIXME: Clean this up once builder takes Twine/StringRef.
- Name += ".realp";
- llvm::Value *RealPtr = Builder.CreateStructGEP(SrcPtr, 0,
- Name.str().str().c_str());
-
- Name.pop_back(); // .realp -> .real
- // FIXME: Clean this up once builder takes Twine/StringRef.
- Real = Builder.CreateLoad(RealPtr, isVolatile,
- Name.str().str().c_str());
- Name.resize(Name.size()-4); // .real -> .imagp
+ llvm::Value *RealP = Builder.CreateStructGEP(SrcPtr, 0,
+ SrcPtr->getName() + ".realp");
+ Real = Builder.CreateLoad(RealP, isVolatile, SrcPtr->getName() + ".real");
}
if (!IgnoreImag) {
- Name += "imagp";
-
- // FIXME: Clean this up once builder takes Twine/StringRef.
- llvm::Value *ImagPtr = Builder.CreateStructGEP(SrcPtr, 1,
- Name.str().str().c_str());
-
- Name.pop_back(); // .imagp -> .imag
- // FIXME: Clean this up once builder takes Twine/StringRef.
- Imag = Builder.CreateLoad(ImagPtr, isVolatile, Name.str().str().c_str());
+ llvm::Value *ImagP = Builder.CreateStructGEP(SrcPtr, 1,
+ SrcPtr->getName() + ".imagp");
+ Imag = Builder.CreateLoad(ImagP, isVolatile, SrcPtr->getName() + ".imag");
}
return ComplexPairTy(Real, Imag);
}
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp
index 40b845dba050..9289f78d557a 100644
--- a/lib/CodeGen/CGExprConstant.cpp
+++ b/lib/CodeGen/CGExprConstant.cpp
@@ -22,14 +22,12 @@
#include "llvm/Constants.h"
#include "llvm/Function.h"
#include "llvm/GlobalVariable.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/Target/TargetData.h"
using namespace clang;
using namespace CodeGen;
namespace {
-
-class VISIBILITY_HIDDEN ConstStructBuilder {
+class ConstStructBuilder {
CodeGenModule &CGM;
CodeGenFunction *CGF;
@@ -377,7 +375,7 @@ public:
}
};
-class VISIBILITY_HIDDEN ConstExprEmitter :
+class ConstExprEmitter :
public StmtVisitor<ConstExprEmitter, llvm::Constant*> {
CodeGenModule &CGM;
CodeGenFunction *CGF;
@@ -413,9 +411,10 @@ public:
// Get the function pointer (or index if this is a virtual function).
if (MD->isVirtual()) {
- int64_t Index = CGM.getVtableInfo().getMethodVtableIndex(MD);
+ uint64_t Index = CGM.getVtableInfo().getMethodVtableIndex(MD);
- Values[0] = llvm::ConstantInt::get(PtrDiffTy, Index + 1);
+ // The pointer is 1 + the virtual table offset in bytes.
+ Values[0] = llvm::ConstantInt::get(PtrDiffTy, (Index * 8) + 1);
} else {
llvm::Constant *FuncPtr = CGM.GetAddrOfFunction(MD);
@@ -673,7 +672,7 @@ public:
if (ILE->getType()->isArrayType())
return EmitArrayInitialization(ILE);
- if (ILE->getType()->isStructureType())
+ if (ILE->getType()->isRecordType())
return EmitStructInitialization(ILE);
if (ILE->getType()->isUnionType())
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index e9bbf35fcd8d..c1cbecc9fa85 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -24,7 +24,6 @@
#include "llvm/GlobalVariable.h"
#include "llvm/Intrinsics.h"
#include "llvm/Module.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/Support/CFG.h"
#include "llvm/Target/TargetData.h"
#include <cstdarg>
@@ -45,7 +44,7 @@ struct BinOpInfo {
};
namespace {
-class VISIBILITY_HIDDEN ScalarExprEmitter
+class ScalarExprEmitter
: public StmtVisitor<ScalarExprEmitter, Value*> {
CodeGenFunction &CGF;
CGBuilderTy &Builder;
@@ -141,8 +140,11 @@ public:
// l-values.
Value *VisitDeclRefExpr(DeclRefExpr *E) {
- if (const EnumConstantDecl *EC = dyn_cast<EnumConstantDecl>(E->getDecl()))
- return llvm::ConstantInt::get(VMContext, EC->getInitVal());
+ Expr::EvalResult Result;
+ if (E->Evaluate(Result, CGF.getContext()) && Result.Val.isInt()) {
+ assert(!Result.HasSideEffects && "Constant declref with side-effect?!");
+ return llvm::ConstantInt::get(VMContext, Result.Val.getInt());
+ }
return EmitLoadOfLValue(E);
}
Value *VisitObjCSelectorExpr(ObjCSelectorExpr *E) {
@@ -167,7 +169,7 @@ public:
Value *VisitArraySubscriptExpr(ArraySubscriptExpr *E);
Value *VisitShuffleVectorExpr(ShuffleVectorExpr *E);
- Value *VisitMemberExpr(Expr *E) { return EmitLoadOfLValue(E); }
+ Value *VisitMemberExpr(MemberExpr *E);
Value *VisitExtVectorElementExpr(Expr *E) { return EmitLoadOfLValue(E); }
Value *VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
return EmitLoadOfLValue(E);
@@ -184,14 +186,14 @@ public:
Value *VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E) {
return llvm::Constant::getNullValue(ConvertType(E->getType()));
}
- Value *VisitCastExpr(const CastExpr *E) {
+ Value *VisitCastExpr(CastExpr *E) {
// Make sure to evaluate VLA bounds now so that we have them for later.
if (E->getType()->isVariablyModifiedType())
CGF.EmitVLASize(E->getType());
return EmitCastExpr(E);
}
- Value *EmitCastExpr(const CastExpr *E);
+ Value *EmitCastExpr(CastExpr *E);
Value *VisitCallExpr(const CallExpr *E) {
if (E->getCallReturnType()->isReferenceType())
@@ -558,6 +560,17 @@ Value *ScalarExprEmitter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) {
Value* SV = llvm::ConstantVector::get(indices.begin(), indices.size());
return Builder.CreateShuffleVector(V1, V2, SV, "shuffle");
}
+Value *ScalarExprEmitter::VisitMemberExpr(MemberExpr *E) {
+ Expr::EvalResult Result;
+ if (E->Evaluate(Result, CGF.getContext()) && Result.Val.isInt()) {
+ if (E->isArrow())
+ CGF.EmitScalarExpr(E->getBase());
+ else
+ EmitLValue(E->getBase());
+ return llvm::ConstantInt::get(VMContext, Result.Val.getInt());
+ }
+ return EmitLoadOfLValue(E);
+}
Value *ScalarExprEmitter::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
TestAndClearIgnoreResultAssign();
@@ -748,23 +761,40 @@ Value *ScalarExprEmitter::VisitInitListExpr(InitListExpr *E) {
return V;
}
+static bool ShouldNullCheckClassCastValue(const CastExpr *CE) {
+ const Expr *E = CE->getSubExpr();
+
+ if (isa<CXXThisExpr>(E)) {
+ // We always assume that 'this' is never null.
+ return false;
+ }
+
+ if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(CE)) {
+ // And that lvalue casts are never null.
+ if (ICE->isLvalueCast())
+ return false;
+ }
+
+ return true;
+}
+
// VisitCastExpr - Emit code for an explicit or implicit cast. Implicit casts
// have to handle a more broad range of conversions than explicit casts, as they
// handle things like function to ptr-to-function decay etc.
-Value *ScalarExprEmitter::EmitCastExpr(const CastExpr *CE) {
- const Expr *E = CE->getSubExpr();
+Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) {
+ Expr *E = CE->getSubExpr();
QualType DestTy = CE->getType();
CastExpr::CastKind Kind = CE->getCastKind();
if (!DestTy->isVoidType())
TestAndClearIgnoreResultAssign();
+ // Since almost all cast kinds apply to scalars, this switch doesn't have
+ // a default case, so the compiler will warn on a missing case. The cases
+ // are in the same order as in the CastKind enum.
switch (Kind) {
- default:
- //return CGF.ErrorUnsupported(E, "type of cast");
- break;
-
case CastExpr::CK_Unknown:
+ // FIXME: All casts should have a known kind!
//assert(0 && "Unknown cast kind!");
break;
@@ -775,6 +805,18 @@ Value *ScalarExprEmitter::EmitCastExpr(const CastExpr *CE) {
case CastExpr::CK_NoOp:
return Visit(const_cast<Expr*>(E));
+ case CastExpr::CK_BaseToDerived: {
+ const CXXRecordDecl *BaseClassDecl =
+ E->getType()->getCXXRecordDeclForPointerType();
+ const CXXRecordDecl *DerivedClassDecl =
+ DestTy->getCXXRecordDeclForPointerType();
+
+ Value *Src = Visit(const_cast<Expr*>(E));
+
+ bool NullCheckValue = ShouldNullCheckClassCastValue(CE);
+ return CGF.GetAddressOfDerivedClass(Src, BaseClassDecl, DerivedClassDecl,
+ NullCheckValue);
+ }
case CastExpr::CK_DerivedToBase: {
const RecordType *DerivedClassTy =
E->getType()->getAs<PointerType>()->getPointeeType()->getAs<RecordType>();
@@ -787,23 +829,19 @@ Value *ScalarExprEmitter::EmitCastExpr(const CastExpr *CE) {
Value *Src = Visit(const_cast<Expr*>(E));
- bool NullCheckValue = true;
-
- if (isa<CXXThisExpr>(E)) {
- // We always assume that 'this' is never null.
- NullCheckValue = false;
- } else if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(CE)) {
- // And that lvalue casts are never null.
- if (ICE->isLvalueCast())
- NullCheckValue = false;
- }
- return CGF.GetAddressCXXOfBaseClass(Src, DerivedClassDecl, BaseClassDecl,
- NullCheckValue);
+ bool NullCheckValue = ShouldNullCheckClassCastValue(CE);
+ return CGF.GetAddressOfBaseClass(Src, DerivedClassDecl, BaseClassDecl,
+ NullCheckValue);
+ }
+ 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_ToUnion: {
+ 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!");
@@ -828,6 +866,35 @@ Value *ScalarExprEmitter::EmitCastExpr(const CastExpr *CE) {
case CastExpr::CK_NullToMemberPointer:
return CGF.CGM.EmitNullConstant(DestTy);
+ case CastExpr::CK_BaseToDerivedMemberPointer:
+ case CastExpr::CK_DerivedToBaseMemberPointer: {
+ Value *Src = Visit(E);
+
+ // See if we need to adjust the pointer.
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(E->getType()->getAs<MemberPointerType>()->
+ getClass()->getAs<RecordType>()->getDecl());
+ const CXXRecordDecl *DerivedDecl =
+ cast<CXXRecordDecl>(CE->getType()->getAs<MemberPointerType>()->
+ getClass()->getAs<RecordType>()->getDecl());
+ if (CE->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer)
+ std::swap(DerivedDecl, BaseDecl);
+
+ llvm::Constant *Adj = CGF.CGM.GetCXXBaseClassOffset(DerivedDecl, BaseDecl);
+ if (Adj) {
+ if (CE->getCastKind() == CastExpr::CK_DerivedToBaseMemberPointer)
+ Src = Builder.CreateSub(Src, Adj, "adj");
+ else
+ Src = Builder.CreateAdd(Src, Adj, "adj");
+ }
+ return Src;
+ }
+
+ case CastExpr::CK_UserDefinedConversion:
+ case CastExpr::CK_ConstructorConversion:
+ assert(0 && "Should be unreachable!");
+ break;
+
case CastExpr::CK_IntegralToPointer: {
Value *Src = Visit(const_cast<Expr*>(E));
@@ -841,23 +908,14 @@ Value *ScalarExprEmitter::EmitCastExpr(const CastExpr *CE) {
return Builder.CreateIntToPtr(IntResult, ConvertType(DestTy));
}
-
case CastExpr::CK_PointerToIntegral: {
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));
@@ -879,7 +937,40 @@ Value *ScalarExprEmitter::EmitCastExpr(const CastExpr *CE) {
llvm::Value *Yay = Builder.CreateShuffleVector(UnV, UnV, Mask, "splat");
return Yay;
}
+ case CastExpr::CK_IntegralCast:
+ case CastExpr::CK_IntegralToFloating:
+ case CastExpr::CK_FloatingToIntegral:
+ case CastExpr::CK_FloatingCast:
+ return EmitScalarConversion(Visit(E), E->getType(), DestTy);
+ case CastExpr::CK_MemberPointerToBoolean: {
+ const MemberPointerType* T = E->getType()->getAs<MemberPointerType>();
+
+ if (T->getPointeeType()->isFunctionType()) {
+ // We have a member function pointer.
+ llvm::Value *Ptr = CGF.CreateTempAlloca(ConvertType(E->getType()));
+
+ CGF.EmitAggExpr(E, Ptr, /*VolatileDest=*/false);
+
+ // Get the pointer.
+ llvm::Value *FuncPtr = Builder.CreateStructGEP(Ptr, 0, "src.ptr");
+ FuncPtr = Builder.CreateLoad(FuncPtr);
+
+ llvm::Value *IsNotNull =
+ Builder.CreateICmpNE(FuncPtr,
+ llvm::Constant::getNullValue(FuncPtr->getType()),
+ "tobool");
+
+ return IsNotNull;
+ }
+
+ // We have a regular member pointer.
+ Value *Ptr = Visit(const_cast<Expr*>(E));
+ llvm::Value *IsNotNull =
+ Builder.CreateICmpNE(Ptr, CGF.CGM.EmitNullConstant(E->getType()),
+ "tobool");
+ return IsNotNull;
+ }
}
// Handle cases where the source is an non-complex type.
@@ -924,7 +1015,7 @@ Value *ScalarExprEmitter::VisitBlockDeclRefExpr(const BlockDeclRefExpr *E) {
llvm::Value *V = CGF.GetAddrOfBlockDecl(E);
if (E->getType().isObjCGCWeak())
return CGF.CGM.getObjCRuntime().EmitObjCWeakRead(CGF, V);
- return Builder.CreateLoad(V, false, "tmp");
+ return Builder.CreateLoad(V, "tmp");
}
//===----------------------------------------------------------------------===//
@@ -1583,10 +1674,10 @@ Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E) {
PI != PE; ++PI)
PN->addIncoming(llvm::ConstantInt::getFalse(VMContext), *PI);
- CGF.PushConditionalTempDestruction();
+ CGF.StartConditionalBranch();
CGF.EmitBlock(RHSBlock);
Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS());
- CGF.PopConditionalTempDestruction();
+ CGF.FinishConditionalBranch();
// Reaquire the RHS block, as there may be subblocks inserted.
RHSBlock = Builder.GetInsertBlock();
@@ -1633,13 +1724,13 @@ Value *ScalarExprEmitter::VisitBinLOr(const BinaryOperator *E) {
PI != PE; ++PI)
PN->addIncoming(llvm::ConstantInt::getTrue(VMContext), *PI);
- CGF.PushConditionalTempDestruction();
+ CGF.StartConditionalBranch();
// Emit the RHS condition as a bool value.
CGF.EmitBlock(RHSBlock);
Value *RHSCond = CGF.EvaluateExprAsBool(E->getRHS());
- CGF.PopConditionalTempDestruction();
+ CGF.FinishConditionalBranch();
// Reaquire the RHS block, as there may be subblocks inserted.
RHSBlock = Builder.GetInsertBlock();
@@ -1753,7 +1844,7 @@ VisitConditionalOperator(const ConditionalOperator *E) {
Builder.CreateCondBr(CondBoolVal, LHSBlock, RHSBlock);
}
- CGF.PushConditionalTempDestruction();
+ CGF.StartConditionalBranch();
CGF.EmitBlock(LHSBlock);
// Handle the GNU extension for missing LHS.
@@ -1763,15 +1854,15 @@ VisitConditionalOperator(const ConditionalOperator *E) {
else // Perform promotions, to handle cases like "short ?: int"
LHS = EmitScalarConversion(CondVal, E->getCond()->getType(), E->getType());
- CGF.PopConditionalTempDestruction();
+ CGF.FinishConditionalBranch();
LHSBlock = Builder.GetInsertBlock();
CGF.EmitBranch(ContBlock);
- CGF.PushConditionalTempDestruction();
+ CGF.StartConditionalBranch();
CGF.EmitBlock(RHSBlock);
Value *RHS = Visit(E->getRHS());
- CGF.PopConditionalTempDestruction();
+ CGF.FinishConditionalBranch();
RHSBlock = Builder.GetInsertBlock();
CGF.EmitBranch(ContBlock);
diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp
index b431daa958f0..be772c7fa311 100644
--- a/lib/CodeGen/CGObjCGNU.cpp
+++ b/lib/CodeGen/CGObjCGNU.cpp
@@ -747,9 +747,14 @@ llvm::Constant *CGObjCGNU::GenerateProtocolList(
std::vector<llvm::Constant*> Elements;
for (const std::string *iter = Protocols.begin(), *endIter = Protocols.end();
iter != endIter ; iter++) {
- llvm::Constant *protocol = ExistingProtocols[*iter];
- if (!protocol)
+ llvm::Constant *protocol = 0;
+ llvm::StringMap<llvm::Constant*>::iterator value =
+ ExistingProtocols.find(*iter);
+ if (value == ExistingProtocols.end()) {
protocol = GenerateEmptyProtocol(*iter);
+ } else {
+ protocol = value->getValue();
+ }
llvm::Constant *Ptr = llvm::ConstantExpr::getBitCast(protocol,
PtrToInt8Ty);
Elements.push_back(Ptr);
@@ -1366,8 +1371,8 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() {
ConstantStrings.size() + 1);
ConstantStrings.push_back(NULLPtr);
- const char *StringClass = CGM.getLangOptions().ObjCConstantStringClass;
- if (!StringClass) StringClass = "NXConstantString";
+ llvm::StringRef StringClass = CGM.getLangOptions().ObjCConstantStringClass;
+ if (StringClass.empty()) StringClass = "NXConstantString";
Elements.push_back(MakeConstantString(StringClass,
".objc_static_class_name"));
Elements.push_back(llvm::ConstantArray::get(StaticsArrayTy,
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index 4355e66feecd..2e8ab2987db3 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -2993,7 +2993,7 @@ llvm::Value *CGObjCMac::EmitClassRef(CGBuilderTy &Builder,
4, true);
}
- return Builder.CreateLoad(Entry, false, "tmp");
+ return Builder.CreateLoad(Entry, "tmp");
}
llvm::Value *CGObjCMac::EmitSelector(CGBuilderTy &Builder, Selector Sel) {
@@ -3009,7 +3009,7 @@ llvm::Value *CGObjCMac::EmitSelector(CGBuilderTy &Builder, Selector Sel) {
4, true);
}
- return Builder.CreateLoad(Entry, false, "tmp");
+ return Builder.CreateLoad(Entry, "tmp");
}
llvm::Constant *CGObjCCommonMac::GetClassName(IdentifierInfo *Ident) {
@@ -4516,7 +4516,7 @@ llvm::Value *CGObjCNonFragileABIMac::GenerateProtocolRef(CGBuilderTy &Builder,
llvm::GlobalVariable *PTGV = CGM.getModule().getGlobalVariable(ProtocolName);
if (PTGV)
- return Builder.CreateLoad(PTGV, false, "tmp");
+ return Builder.CreateLoad(PTGV, "tmp");
PTGV = new llvm::GlobalVariable(
CGM.getModule(),
Init->getType(), false,
@@ -4526,7 +4526,7 @@ llvm::Value *CGObjCNonFragileABIMac::GenerateProtocolRef(CGBuilderTy &Builder,
PTGV->setSection("__DATA, __objc_protorefs, coalesced, no_dead_strip");
PTGV->setVisibility(llvm::GlobalValue::HiddenVisibility);
CGM.AddUsedGlobal(PTGV);
- return Builder.CreateLoad(PTGV, false, "tmp");
+ return Builder.CreateLoad(PTGV, "tmp");
}
/// GenerateCategory - Build metadata for a category implementation.
@@ -5031,8 +5031,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitIvarOffset(
CodeGen::CodeGenFunction &CGF,
const ObjCInterfaceDecl *Interface,
const ObjCIvarDecl *Ivar) {
- return CGF.Builder.CreateLoad(ObjCIvarOffsetVariable(Interface, Ivar),
- false, "ivar");
+ return CGF.Builder.CreateLoad(ObjCIvarOffsetVariable(Interface, Ivar),"ivar");
}
CodeGen::RValue CGObjCNonFragileABIMac::EmitMessageSend(
@@ -5187,7 +5186,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitClassRef(CGBuilderTy &Builder,
CGM.AddUsedGlobal(Entry);
}
- return Builder.CreateLoad(Entry, false, "tmp");
+ return Builder.CreateLoad(Entry, "tmp");
}
llvm::Value *
@@ -5210,7 +5209,7 @@ CGObjCNonFragileABIMac::EmitSuperClassRef(CGBuilderTy &Builder,
CGM.AddUsedGlobal(Entry);
}
- return Builder.CreateLoad(Entry, false, "tmp");
+ return Builder.CreateLoad(Entry, "tmp");
}
/// EmitMetaClassRef - Return a Value * of the address of _class_t
@@ -5220,7 +5219,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CGBuilderTy &Builder,
const ObjCInterfaceDecl *ID) {
llvm::GlobalVariable * &Entry = MetaClassReferences[ID->getIdentifier()];
if (Entry)
- return Builder.CreateLoad(Entry, false, "tmp");
+ return Builder.CreateLoad(Entry, "tmp");
std::string MetaClassName(getMetaclassSymbolPrefix() + ID->getNameAsString());
llvm::GlobalVariable *MetaClassGV = GetClassGlobal(MetaClassName);
@@ -5236,7 +5235,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CGBuilderTy &Builder,
Entry->setSection("__DATA, __objc_superrefs, regular, no_dead_strip");
CGM.AddUsedGlobal(Entry);
- return Builder.CreateLoad(Entry, false, "tmp");
+ return Builder.CreateLoad(Entry, "tmp");
}
/// GetClass - Return a reference to the class for the given interface
@@ -5323,7 +5322,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitSelector(CGBuilderTy &Builder,
CGM.AddUsedGlobal(Entry);
}
- return Builder.CreateLoad(Entry, false, "tmp");
+ return Builder.CreateLoad(Entry, "tmp");
}
/// EmitObjCIvarAssign - Code gen for assigning to a __strong object.
/// objc_assign_ivar (id src, id *dst, ptrdiff_t)
diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp
index a63c8325ffa7..1a9bc3917092 100644
--- a/lib/CodeGen/CGRecordLayoutBuilder.cpp
+++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp
@@ -330,36 +330,6 @@ void CGRecordLayoutBuilder::CheckForMemberPointer(const FieldDecl *FD) {
}
-static const CXXMethodDecl *GetKeyFunction(const RecordDecl *D) {
- const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D);
- if (!RD || !RD->isDynamicClass())
- return 0;
-
- for (CXXRecordDecl::method_iterator I = RD->method_begin(),
- E = RD->method_end(); I != E; ++I) {
- const CXXMethodDecl *MD = *I;
-
- if (!MD->isVirtual())
- continue;
-
- if (MD->isPure())
- continue;
-
- // FIXME: This doesn't work. If we have an out of line body, that body will
- // set the MD to have a body, what we want to know is, was the body present
- // inside the declaration of the class. For now, we just avoid the problem
- // by pretending there is no key function.
- return 0;
- if (MD->getBody())
- continue;
-
- // We found it.
- return MD;
- }
-
- return 0;
-}
-
CGRecordLayout *
CGRecordLayoutBuilder::ComputeLayout(CodeGenTypes &Types,
const RecordDecl *D) {
@@ -389,7 +359,5 @@ CGRecordLayoutBuilder::ComputeLayout(CodeGenTypes &Types,
Types.addBitFieldInfo(Info.FD, Info.FieldNo, Info.Start, Info.Size);
}
- const CXXMethodDecl *KeyFunction = GetKeyFunction(D);
-
- return new CGRecordLayout(Ty, Builder.ContainsMemberPointer, KeyFunction);
+ return new CGRecordLayout(Ty, Builder.ContainsMemberPointer);
}
diff --git a/lib/CodeGen/CGRtti.cpp b/lib/CodeGen/CGRtti.cpp
index 79d866427f0b..43fcb31858f8 100644
--- a/lib/CodeGen/CGRtti.cpp
+++ b/lib/CodeGen/CGRtti.cpp
@@ -49,9 +49,8 @@ public:
llvm::Constant *BuildName(QualType Ty, bool Hidden, bool Extern) {
llvm::SmallString<256> OutName;
- llvm::raw_svector_ostream Out(OutName);
- mangleCXXRttiName(CGM.getMangleContext(), Ty, Out);
- llvm::StringRef Name = Out.str();
+ CGM.getMangleContext().mangleCXXRttiName(Ty, OutName);
+ llvm::StringRef Name = OutName.str();
llvm::GlobalVariable::LinkageTypes linktype;
linktype = llvm::GlobalValue::LinkOnceODRLinkage;
@@ -99,9 +98,8 @@ public:
return llvm::Constant::getNullValue(Int8PtrTy);
llvm::SmallString<256> OutName;
- llvm::raw_svector_ostream Out(OutName);
- mangleCXXRtti(CGM.getMangleContext(), Ty, Out);
- llvm::StringRef Name = Out.str();
+ CGM.getMangleContext().mangleCXXRtti(Ty, OutName);
+ llvm::StringRef Name = OutName.str();
C = CGM.getModule().getGlobalVariable(Name);
if (C)
@@ -194,10 +192,9 @@ public:
llvm::Constant *C;
llvm::SmallString<256> OutName;
- llvm::raw_svector_ostream Out(OutName);
- mangleCXXRtti(CGM.getMangleContext(), CGM.getContext().getTagDeclType(RD),
- Out);
- llvm::StringRef Name = Out.str();
+ CGM.getMangleContext().mangleCXXRtti(CGM.getContext().getTagDeclType(RD),
+ OutName);
+ llvm::StringRef Name = OutName.str();
llvm::GlobalVariable *GV;
GV = CGM.getModule().getGlobalVariable(Name);
@@ -260,13 +257,6 @@ public:
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);
- }
-
bool DecideExtern(QualType Ty) {
// For this type, see if all components are never in an anonymous namespace.
if (const MemberPointerType *MPT = Ty->getAs<MemberPointerType>())
@@ -297,9 +287,8 @@ public:
llvm::Constant *C;
llvm::SmallString<256> OutName;
- llvm::raw_svector_ostream Out(OutName);
- mangleCXXRtti(CGM.getMangleContext(), Ty, Out);
- llvm::StringRef Name = Out.str();
+ CGM.getMangleContext().mangleCXXRtti(Ty, OutName);
+ llvm::StringRef Name = OutName.str();
llvm::GlobalVariable *GV;
GV = CGM.getModule().getGlobalVariable(Name);
@@ -338,10 +327,10 @@ public:
info.push_back(BuildInt(flags));
info.push_back(BuildInt(0));
- info.push_back(BuildType2(PTy));
+ info.push_back(BuildType(PTy));
if (PtrMem)
- info.push_back(BuildType2(BTy));
+ info.push_back(BuildType(BTy));
// We always generate these as hidden, only the name isn't hidden.
return finish(info, GV, Name, true, Extern);
@@ -351,9 +340,8 @@ public:
llvm::Constant *C;
llvm::SmallString<256> OutName;
- llvm::raw_svector_ostream Out(OutName);
- mangleCXXRtti(CGM.getMangleContext(), Ty, Out);
- llvm::StringRef Name = Out.str();
+ CGM.getMangleContext().mangleCXXRtti(Ty, OutName);
+ llvm::StringRef Name = OutName.str();
llvm::GlobalVariable *GV;
GV = CGM.getModule().getGlobalVariable(Name);
@@ -376,6 +364,11 @@ public:
llvm::Constant *BuildType(QualType Ty) {
const clang::Type &Type
= *CGM.getContext().getCanonicalType(Ty).getTypePtr();
+
+ if (const RecordType *RT = Ty.getTypePtr()->getAs<RecordType>())
+ if (const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()))
+ return Buildclass_type_info(RD);
+
switch (Type.getTypeClass()) {
default: {
assert(0 && "typeid expression");
@@ -426,7 +419,7 @@ llvm::Constant *CodeGenModule::GenerateRtti(const CXXRecordDecl *RD) {
return b.Buildclass_type_info(RD);
}
-llvm::Constant *CodeGenModule::GenerateRttiNonClass(QualType Ty) {
+llvm::Constant *CodeGenModule::GenerateRtti(QualType Ty) {
RttiBuilder b(*this);
return b.BuildType(Ty);
diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp
index b6d7b3990452..bbd546261800 100644
--- a/lib/CodeGen/CGStmt.cpp
+++ b/lib/CodeGen/CGStmt.cpp
@@ -153,9 +153,7 @@ RValue CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast,
}
// Keep track of the current cleanup stack depth.
- size_t CleanupStackDepth = CleanupEntries.size();
- bool OldDidCallStackSave = DidCallStackSave;
- DidCallStackSave = false;
+ CleanupScope Scope(*this);
for (CompoundStmt::const_body_iterator I = S.body_begin(),
E = S.body_end()-GetLast; I != E; ++I)
@@ -185,10 +183,6 @@ RValue CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast,
RV = EmitAnyExpr(cast<Expr>(LastStmt), AggLoc);
}
- DidCallStackSave = OldDidCallStackSave;
-
- EmitCleanupBlocks(CleanupStackDepth);
-
return RV;
}
@@ -294,6 +288,10 @@ void CodeGenFunction::EmitIndirectGotoStmt(const IndirectGotoStmt &S) {
void CodeGenFunction::EmitIfStmt(const IfStmt &S) {
// C99 6.8.4.1: The first substatement is executed if the expression compares
// unequal to 0. The condition must be a scalar type.
+ CleanupScope ConditionScope(*this);
+
+ if (S.getConditionVariable())
+ EmitLocalBlockVarDecl(*S.getConditionVariable());
// If the condition constant folds and can be elided, try to avoid emitting
// the condition and the dead arm of the if/else.
@@ -306,8 +304,10 @@ void CodeGenFunction::EmitIfStmt(const IfStmt &S) {
// If the skipped block has no labels in it, just emit the executed block.
// This avoids emitting dead code and simplifies the CFG substantially.
if (!ContainsLabel(Skipped)) {
- if (Executed)
+ if (Executed) {
+ CleanupScope ExecutedScope(*this);
EmitStmt(Executed);
+ }
return;
}
}
@@ -322,14 +322,20 @@ void CodeGenFunction::EmitIfStmt(const IfStmt &S) {
EmitBranchOnBoolExpr(S.getCond(), ThenBlock, ElseBlock);
// Emit the 'then' code.
- EmitBlock(ThenBlock);
- EmitStmt(S.getThen());
+ EmitBlock(ThenBlock);
+ {
+ CleanupScope ThenScope(*this);
+ EmitStmt(S.getThen());
+ }
EmitBranch(ContBlock);
// Emit the 'else' code if present.
if (const Stmt *Else = S.getElse()) {
EmitBlock(ElseBlock);
- EmitStmt(Else);
+ {
+ CleanupScope ElseScope(*this);
+ EmitStmt(Else);
+ }
EmitBranch(ContBlock);
}
@@ -347,15 +353,37 @@ void CodeGenFunction::EmitWhileStmt(const WhileStmt &S) {
// body of the loop.
llvm::BasicBlock *ExitBlock = createBasicBlock("while.end");
llvm::BasicBlock *LoopBody = createBasicBlock("while.body");
+ llvm::BasicBlock *CleanupBlock = 0;
+ llvm::BasicBlock *EffectiveExitBlock = ExitBlock;
// Store the blocks to use for break and continue.
BreakContinueStack.push_back(BreakContinue(ExitBlock, LoopHeader));
+ // C++ [stmt.while]p2:
+ // When the condition of a while statement is a declaration, the
+ // scope of the variable that is declared extends from its point
+ // of declaration (3.3.2) to the end of the while statement.
+ // [...]
+ // The object created in a condition is destroyed and created
+ // with each iteration of the loop.
+ CleanupScope ConditionScope(*this);
+
+ if (S.getConditionVariable()) {
+ EmitLocalBlockVarDecl(*S.getConditionVariable());
+
+ // If this condition variable requires cleanups, create a basic
+ // block to handle those cleanups.
+ if (ConditionScope.requiresCleanups()) {
+ CleanupBlock = createBasicBlock("while.cleanup");
+ EffectiveExitBlock = CleanupBlock;
+ }
+ }
+
// Evaluate the conditional in the while header. C99 6.8.5.1: The
// evaluation of the controlling expression takes place before each
// execution of the loop body.
llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());
-
+
// while(1) is common, avoid extra exit blocks. Be sure
// to correctly handle break/continue though.
bool EmitBoolCondBranch = true;
@@ -365,23 +393,39 @@ void CodeGenFunction::EmitWhileStmt(const WhileStmt &S) {
// As long as the condition is true, go to the loop body.
if (EmitBoolCondBranch)
- Builder.CreateCondBr(BoolCondVal, LoopBody, ExitBlock);
-
+ Builder.CreateCondBr(BoolCondVal, LoopBody, EffectiveExitBlock);
+
// Emit the loop body.
- EmitBlock(LoopBody);
- EmitStmt(S.getBody());
+ {
+ CleanupScope BodyScope(*this);
+ EmitBlock(LoopBody);
+ EmitStmt(S.getBody());
+ }
BreakContinueStack.pop_back();
- // Cycle to the condition.
- EmitBranch(LoopHeader);
+ if (CleanupBlock) {
+ // If we have a cleanup block, jump there to perform cleanups
+ // before looping.
+ EmitBranch(CleanupBlock);
+
+ // Emit the cleanup block, performing cleanups for the condition
+ // and then jumping to either the loop header or the exit block.
+ EmitBlock(CleanupBlock);
+ ConditionScope.ForceCleanup();
+ Builder.CreateCondBr(BoolCondVal, LoopHeader, ExitBlock);
+ } else {
+ // Cycle to the condition.
+ EmitBranch(LoopHeader);
+ }
// Emit the exit block.
EmitBlock(ExitBlock, true);
+
// The LoopHeader typically is just a branch if we skipped emitting
// a branch, try to erase it.
- if (!EmitBoolCondBranch)
+ if (!EmitBoolCondBranch && !CleanupBlock)
SimplifyForwardingBlocks(LoopHeader);
}
@@ -435,6 +479,7 @@ void CodeGenFunction::EmitDoStmt(const DoStmt &S) {
void CodeGenFunction::EmitForStmt(const ForStmt &S) {
// FIXME: What do we do if the increment (f.e.) contains a stmt expression,
// which contains a continue/break?
+ CleanupScope ForScope(*this);
// Evaluate the first part before the loop.
if (S.getInit())
@@ -443,18 +488,34 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S) {
// Start the loop with a block that tests the condition.
llvm::BasicBlock *CondBlock = createBasicBlock("for.cond");
llvm::BasicBlock *AfterFor = createBasicBlock("for.end");
-
+ llvm::BasicBlock *IncBlock = 0;
+ llvm::BasicBlock *CondCleanup = 0;
+ llvm::BasicBlock *EffectiveExitBlock = AfterFor;
EmitBlock(CondBlock);
- // Evaluate the condition if present. If not, treat it as a
- // non-zero-constant according to 6.8.5.3p2, aka, true.
+ // Create a cleanup scope for the condition variable cleanups.
+ CleanupScope ConditionScope(*this);
+
+ llvm::Value *BoolCondVal = 0;
if (S.getCond()) {
+ // If the for statement has a condition scope, emit the local variable
+ // declaration.
+ if (S.getConditionVariable()) {
+ EmitLocalBlockVarDecl(*S.getConditionVariable());
+
+ if (ConditionScope.requiresCleanups()) {
+ CondCleanup = createBasicBlock("for.cond.cleanup");
+ EffectiveExitBlock = CondCleanup;
+ }
+ }
+
// As long as the condition is true, iterate the loop.
llvm::BasicBlock *ForBody = createBasicBlock("for.body");
// C99 6.8.5p2/p4: The first substatement is executed if the expression
// compares unequal to 0. The condition must be a scalar type.
- EmitBranchOnBoolExpr(S.getCond(), ForBody, AfterFor);
+ BoolCondVal = EvaluateExprAsBool(S.getCond());
+ Builder.CreateCondBr(BoolCondVal, ForBody, EffectiveExitBlock);
EmitBlock(ForBody);
} else {
@@ -466,7 +527,7 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S) {
// condition as the continue block.
llvm::BasicBlock *ContinueBlock;
if (S.getInc())
- ContinueBlock = createBasicBlock("for.inc");
+ ContinueBlock = IncBlock = createBasicBlock("for.inc");
else
ContinueBlock = CondBlock;
@@ -479,18 +540,34 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S) {
DI->setLocation(S.getSourceRange().getBegin());
DI->EmitRegionStart(CurFn, Builder);
}
- EmitStmt(S.getBody());
+
+ {
+ // Create a separate cleanup scope for the body, in case it is not
+ // a compound statement.
+ CleanupScope BodyScope(*this);
+ EmitStmt(S.getBody());
+ }
BreakContinueStack.pop_back();
// If there is an increment, emit it next.
if (S.getInc()) {
- EmitBlock(ContinueBlock);
+ EmitBlock(IncBlock);
EmitStmt(S.getInc());
}
// Finally, branch back up to the condition for the next iteration.
- EmitBranch(CondBlock);
+ if (CondCleanup) {
+ // Branch to the cleanup block.
+ EmitBranch(CondCleanup);
+
+ // Emit the cleanup block, which branches back to the loop body or
+ // outside of the for statement once it is done.
+ EmitBlock(CondCleanup);
+ ConditionScope.ForceCleanup();
+ Builder.CreateCondBr(BoolCondVal, CondBlock, AfterFor);
+ } else
+ EmitBranch(CondBlock);
if (DI) {
DI->setLocation(S.getSourceRange().getEnd());
DI->EmitRegionEnd(CurFn, Builder);
@@ -686,6 +763,11 @@ void CodeGenFunction::EmitDefaultStmt(const DefaultStmt &S) {
}
void CodeGenFunction::EmitSwitchStmt(const SwitchStmt &S) {
+ CleanupScope ConditionScope(*this);
+
+ if (S.getConditionVariable())
+ EmitLocalBlockVarDecl(*S.getConditionVariable());
+
llvm::Value *CondV = EmitScalarExpr(S.getCond());
// Handle nested switch statements.
diff --git a/lib/CodeGen/CGCXXTemp.cpp b/lib/CodeGen/CGTemporaries.cpp
index 4768556f6bca..5cfc7efade42 100644
--- a/lib/CodeGen/CGCXXTemp.cpp
+++ b/lib/CodeGen/CGTemporaries.cpp
@@ -1,4 +1,4 @@
-//===--- CGCXXTemp.cpp - Emit LLVM Code for C++ temporaries ---------------===//
+//===--- CGTemporaries.cpp - Emit LLVM Code for C++ temporaries -----------===//
//
// The LLVM Compiler Infrastructure
//
@@ -23,7 +23,7 @@ void CodeGenFunction::PushCXXTemporary(const CXXTemporary *Temporary,
// Check if temporaries need to be conditional. If so, we'll create a
// condition boolean, initialize it to 0 and
- if (!ConditionalTempDestructionStack.empty()) {
+ if (ConditionalBranchLevel != 0) {
CondPtr = CreateTempAlloca(llvm::Type::getInt1Ty(VMContext), "cond");
// Initialize it to false. This initialization takes place right after
@@ -141,23 +141,3 @@ LValue CodeGenFunction::EmitCXXExprWithTemporariesLValue(
return LV;
}
-
-void
-CodeGenFunction::PushConditionalTempDestruction() {
- // Store the current number of live temporaries.
- ConditionalTempDestructionStack.push_back(LiveTemporaries.size());
-}
-
-void CodeGenFunction::PopConditionalTempDestruction() {
- size_t NumLiveTemporaries = ConditionalTempDestructionStack.back();
- ConditionalTempDestructionStack.pop_back();
-
- // Pop temporaries.
- while (LiveTemporaries.size() > NumLiveTemporaries) {
- assert(LiveTemporaries.back().CondPtr &&
- "Conditional temporary must have a cond ptr!");
-
- PopCXXTemporary();
- }
-}
-
diff --git a/lib/CodeGen/CGVtable.cpp b/lib/CodeGen/CGVtable.cpp
index 9be1a3b22b33..715aa4c03c10 100644
--- a/lib/CodeGen/CGVtable.cpp
+++ b/lib/CodeGen/CGVtable.cpp
@@ -13,13 +13,15 @@
#include "CodeGenModule.h"
#include "CodeGenFunction.h"
-
+#include "clang/AST/CXXInheritance.h"
#include "clang/AST/RecordLayout.h"
+#include "llvm/ADT/DenseSet.h"
#include <cstdio>
using namespace clang;
using namespace CodeGen;
+namespace {
class VtableBuilder {
public:
/// Index_t - Vtable index type.
@@ -52,54 +54,110 @@ private:
llvm::DenseMap<GlobalDecl, Index_t> NonVirtualOffset;
llvm::DenseMap<const CXXRecordDecl *, Index_t> VBIndex;
- typedef llvm::DenseMap<GlobalDecl, int> Pures_t;
- Pures_t Pures;
- typedef std::pair<Index_t, Index_t> CallOffset;
- typedef llvm::DenseMap<GlobalDecl, CallOffset> Thunks_t;
- Thunks_t Thunks;
- typedef llvm::DenseMap<GlobalDecl,
- std::pair<std::pair<CallOffset, CallOffset>,
- CanQualType> > CovariantThunks_t;
- CovariantThunks_t CovariantThunks;
+ /// PureVirtualFunction - Points to __cxa_pure_virtual.
+ llvm::Constant *PureVirtualFn;
+
+ /// Thunk - Represents a single thunk.
+ struct Thunk {
+ Thunk()
+ : Index(0) { }
+
+ Thunk(uint64_t Index, const ThunkAdjustment &Adjustment)
+ : Index(Index), Adjustment(Adjustment) { }
+
+ /// Index - The index in the vtable.
+ uint64_t Index;
+
+ /// Adjustment - The thunk adjustment.
+ ThunkAdjustment Adjustment;
+ };
+
+ /// Thunks - The thunks in a vtable.
+ typedef llvm::DenseMap<GlobalDecl, Thunk> ThunksMapTy;
+ ThunksMapTy Thunks;
+
+ /// CovariantThunk - Represents a single covariant thunk.
+ struct CovariantThunk {
+ CovariantThunk()
+ : Index(0) { }
+
+ CovariantThunk(uint64_t Index, const ThunkAdjustment &ThisAdjustment,
+ const ThunkAdjustment &ReturnAdjustment,
+ CanQualType ReturnType)
+ : Index(Index), Adjustment(ThisAdjustment, ReturnAdjustment),
+ ReturnType(ReturnType) { }
+
+ // Index - The index in the vtable.
+ uint64_t Index;
+
+ /// Adjustment - The covariant thunk adjustment.
+ CovariantThunkAdjustment Adjustment;
+
+ /// ReturnType - The return type of the function.
+ CanQualType ReturnType;
+ };
+
+ /// CovariantThunks - The covariant thunks in a vtable.
+ typedef llvm::DenseMap<GlobalDecl, CovariantThunk> CovariantThunksMapTy;
+ CovariantThunksMapTy CovariantThunks;
+
+ /// PureVirtualMethods - Pure virtual methods.
+ typedef llvm::DenseSet<GlobalDecl> PureVirtualMethodsSetTy;
+ PureVirtualMethodsSetTy PureVirtualMethods;
+
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;
+ // subAddressPoints - 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> &subAddressPoints;
typedef CXXRecordDecl::method_iterator method_iter;
const bool Extern;
const uint32_t LLVMPointerWidth;
Index_t extra;
typedef std::vector<std::pair<const CXXRecordDecl *, int64_t> > Path_t;
- llvm::Constant *cxa_pure;
+ static llvm::DenseMap<CtorVtable_t, int64_t>&
+ AllocAddressPoint(CodeGenModule &cgm, const CXXRecordDecl *l,
+ const CXXRecordDecl *c) {
+ CodeGenModule::AddrMap_t *&oref = cgm.AddressPoints[l];
+ if (oref == 0)
+ oref = new CodeGenModule::AddrMap_t;
+
+ llvm::DenseMap<CtorVtable_t, int64_t> *&ref = (*oref)[c];
+ if (ref == 0)
+ ref = new llvm::DenseMap<CtorVtable_t, int64_t>;
+ return *ref;
+ }
+
+ /// getPureVirtualFn - Return the __cxa_pure_virtual function.
+ llvm::Constant* getPureVirtualFn() {
+ if (!PureVirtualFn) {
+ const llvm::FunctionType *Ty =
+ llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
+ /*isVarArg=*/false);
+ PureVirtualFn = wrap(CGM.CreateRuntimeFunction(Ty, "__cxa_pure_virtual"));
+ }
+
+ return PureVirtualFn;
+ }
+
public:
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>),
+ CGM(cgm), PureVirtualFn(0),subAddressPoints(AllocAddressPoint(cgm, l, c)),
Extern(!l->isInAnonymousNamespace()),
- LLVMPointerWidth(cgm.getContext().Target.getPointerWidth(0)) {
+ LLVMPointerWidth(cgm.getContext().Target.getPointerWidth(0)) {
Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0);
-
- // Calculate pointer for ___cxa_pure_virtual.
- const llvm::FunctionType *FTy;
- std::vector<const llvm::Type*> ArgTys;
- const llvm::Type *ResultType = llvm::Type::getVoidTy(VMContext);
- FTy = llvm::FunctionType::get(ResultType, ArgTys, false);
- cxa_pure = wrap(CGM.CreateRuntimeFunction(FTy, "__cxa_pure_virtual"));
}
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);
@@ -147,8 +205,6 @@ public:
SeenVBase.clear();
}
- Index_t VBlookup(CXXRecordDecl *D, CXXRecordDecl *B);
-
Index_t getNVOffset_1(const CXXRecordDecl *D, const CXXRecordDecl *B,
Index_t Offset = 0) {
@@ -194,7 +250,7 @@ public:
CXXRecordDecl *D = cast<CXXRecordDecl>(qD->getAs<RecordType>()->getDecl());
CXXRecordDecl *B = cast<CXXRecordDecl>(qB->getAs<RecordType>()->getDecl());
if (D != Class)
- return VBlookup(D, B);
+ return CGM.getVtableInfo().getVirtualBaseOffsetIndex(D, B);
llvm::DenseMap<const CXXRecordDecl *, Index_t>::iterator i;
i = VBIndex.find(B);
if (i != VBIndex.end())
@@ -242,22 +298,23 @@ public:
CanQualType oret = CGM.getContext().getCanonicalType(nc_oret);
QualType nc_ret = MD->getType()->getAs<FunctionType>()->getResultType();
CanQualType ret = CGM.getContext().getCanonicalType(nc_ret);
- CallOffset ReturnOffset = std::make_pair(0, 0);
+ ThunkAdjustment ReturnAdjustment;
if (oret != ret) {
// FIXME: calculate offsets for covariance
- if (CovariantThunks.count(OMD)) {
- oret = CovariantThunks[OMD].second;
- CovariantThunks.erase(OMD);
+ CovariantThunksMapTy::iterator i = CovariantThunks.find(OMD);
+ if (i != CovariantThunks.end()) {
+ oret = i->second.ReturnType;
+ CovariantThunks.erase(i);
}
// FIXME: Double check oret
Index_t nv = getNVOffset(oret, ret)/8;
- ReturnOffset = std::make_pair(nv, getVbaseOffset(oret, ret));
+ ReturnAdjustment = ThunkAdjustment(nv, getVbaseOffset(oret, ret));
}
Index[GD] = i;
submethods[i] = m;
if (isPure)
- Pures[GD] = 1;
- Pures.erase(OGD);
+ PureVirtualMethods.insert(GD);
+ PureVirtualMethods.erase(OGD);
Thunks.erase(OGD);
if (MorallyVirtual || VCall.count(OGD)) {
Index_t &idx = VCall[OGD];
@@ -278,35 +335,38 @@ public:
(int)VCalls[idx-1], Class->getNameAsCString()));
}
VCall[GD] = idx;
- int64_t O = NonVirtualOffset[GD];
- int v = -((idx+extra+2)*LLVMPointerWidth/8);
+ int64_t NonVirtualAdjustment = NonVirtualOffset[GD];
+ int64_t VirtualAdjustment =
+ -((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);
+ VirtualAdjustment = 0;
+
+ ThunkAdjustment ThisAdjustment(NonVirtualAdjustment,
+ VirtualAdjustment);
+
// 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[GD] = std::make_pair(std::make_pair(ThisOffset,
- ReturnOffset),
- oret);
- else if (!isPure && (ThisOffset.first || ThisOffset.second))
- Thunks[GD] = ThisOffset;
+ if (!ReturnAdjustment.isEmpty()) {
+ CovariantThunks[GD] =
+ CovariantThunk(i, ThisAdjustment, ReturnAdjustment, oret);
+ } else if (!isPure && !ThisAdjustment.isEmpty())
+ Thunks[GD] = Thunk(i, ThisAdjustment);
return true;
}
// FIXME: finish off
- int64_t O = VCallOffset[OGD] - OverrideOffset/8;
+ int64_t NonVirtualAdjustment = VCallOffset[OGD] - OverrideOffset/8;
- if (O || ReturnOffset.first || ReturnOffset.second) {
- CallOffset ThisOffset = std::make_pair(O, 0);
+ if (NonVirtualAdjustment || !ReturnAdjustment.isEmpty()) {
+ ThunkAdjustment ThisAdjustment(NonVirtualAdjustment, 0);
- if (ReturnOffset.first || ReturnOffset.second)
- CovariantThunks[GD] = std::make_pair(std::make_pair(ThisOffset,
- ReturnOffset),
- oret);
- else if (!isPure)
- Thunks[GD] = ThisOffset;
+ if (!ReturnAdjustment.isEmpty()) {
+ CovariantThunks[GD] =
+ CovariantThunk(i, ThisAdjustment, ReturnAdjustment, oret);
+ } else if (!isPure)
+ Thunks[GD] = Thunk(i, ThisAdjustment);
}
return true;
}
@@ -316,40 +376,39 @@ public:
}
void InstallThunks() {
- for (Thunks_t::iterator i = Thunks.begin(), e = Thunks.end();
+ for (ThunksMapTy::const_iterator i = Thunks.begin(), e = Thunks.end();
i != e; ++i) {
GlobalDecl GD = i->first;
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
- assert(!MD->isPure() && "Trying to thunk a pure");
- 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);
+ assert(!MD->isPure() && "Can't thunk pure virtual methods!");
+
+ const Thunk& Thunk = i->second;
+ assert(Thunk.Index == Index[GD] && "Thunk index mismatch!");
+
+ submethods[Thunk.Index] = CGM.BuildThunk(MD, Extern, Thunk.Adjustment);
}
Thunks.clear();
- for (CovariantThunks_t::iterator i = CovariantThunks.begin(),
- e = CovariantThunks.end();
- i != e; ++i) {
+
+ for (CovariantThunksMapTy::const_iterator i = CovariantThunks.begin(),
+ e = CovariantThunks.end(); i != e; ++i) {
GlobalDecl GD = i->first;
const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
if (MD->isPure())
continue;
- 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;
- Index_t v_r = i->second.first.second.second;
- submethods[idx] = CGM.BuildCovariantThunk(MD, Extern, nv_t, v_t, nv_r,
- v_r);
+
+ const CovariantThunk &Thunk = i->second;
+ assert(Thunk.Index == Index[GD] && "Thunk index mismatch!");
+ submethods[Thunk.Index] =
+ CGM.BuildCovariantThunk(MD, Extern, Thunk.Adjustment);
}
CovariantThunks.clear();
- for (Pures_t::iterator i = Pures.begin(), e = Pures.end();
- i != e; ++i) {
- GlobalDecl GD = i->first;
- Index_t idx = Index[GD];
- submethods[idx] = cxa_pure;
+
+ for (PureVirtualMethodsSetTy::iterator i = PureVirtualMethods.begin(),
+ e = PureVirtualMethods.end(); i != e; ++i) {
+ GlobalDecl GD = *i;
+ submethods[Index[GD]] = getPureVirtualFn();
}
- Pures.clear();
+ PureVirtualMethods.clear();
}
llvm::Constant *WrapAddrOf(GlobalDecl GD) {
@@ -358,10 +417,7 @@ public:
if (const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(MD))
return wrap(CGM.GetAddrOfCXXDestructor(Dtor, GD.getDtorType()));
- const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
- const llvm::Type *Ty =
- CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
- FPT->isVariadic());
+ const llvm::Type *Ty = CGM.getTypes().GetFunctionTypeForVtable(MD);
return wrap(CGM.GetAddrOfFunction(MD, Ty));
}
@@ -397,7 +453,7 @@ public:
}
void AddMethod(const GlobalDecl GD, bool MorallyVirtual, Index_t Offset,
- bool ForVirtualBase, int64_t CurrentVBaseOffset) {
+ int64_t CurrentVBaseOffset) {
llvm::Constant *m = WrapAddrOf(GD);
// If we can find a previously allocated slot for this, reuse it.
@@ -413,7 +469,7 @@ public:
D1(printf(" vfn for %s at %d\n", MD->getNameAsString().c_str(),
(int)Index[GD]));
if (MD->isPure())
- Pures[GD] = 1;
+ PureVirtualMethods.insert(GD);
if (MorallyVirtual) {
VCallOffset[GD] = Offset/8;
Index_t &idx = VCall[GD];
@@ -429,8 +485,7 @@ public:
}
void AddMethods(const CXXRecordDecl *RD, bool MorallyVirtual,
- Index_t Offset, bool RDisVirtualBase,
- int64_t CurrentVBaseOffset) {
+ Index_t Offset, int64_t CurrentVBaseOffset) {
for (method_iter mi = RD->method_begin(), me = RD->method_end(); mi != me;
++mi) {
const CXXMethodDecl *MD = *mi;
@@ -441,12 +496,11 @@ public:
// For destructors, add both the complete and the deleting destructor
// to the vtable.
AddMethod(GlobalDecl(DD, Dtor_Complete), MorallyVirtual, Offset,
- RDisVirtualBase, CurrentVBaseOffset);
+ CurrentVBaseOffset);
AddMethod(GlobalDecl(DD, Dtor_Deleting), MorallyVirtual, Offset,
- RDisVirtualBase, CurrentVBaseOffset);
- } else
- AddMethod(MD, MorallyVirtual, Offset, RDisVirtualBase,
CurrentVBaseOffset);
+ } else
+ AddMethod(MD, MorallyVirtual, Offset, CurrentVBaseOffset);
}
}
@@ -495,7 +549,7 @@ public:
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;
+ subAddressPoints[std::make_pair(RD, Offset)] = AddressPoint;
// Now also add the address point for all our primary bases.
while (1) {
@@ -511,7 +565,7 @@ public:
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;
+ subAddressPoints[std::make_pair(RD, Offset)] = AddressPoint;
}
}
@@ -572,7 +626,7 @@ public:
void Primaries(const CXXRecordDecl *RD, bool MorallyVirtual, int64_t Offset,
bool updateVBIndex, Index_t current_vbindex,
- bool RDisVirtualBase, int64_t CurrentVBaseOffset) {
+ int64_t CurrentVBaseOffset) {
if (!RD->isDynamicClass())
return;
@@ -591,21 +645,20 @@ public:
if (!PrimaryBaseWasVirtual)
Primaries(PrimaryBase, PrimaryBaseWasVirtual|MorallyVirtual, Offset,
- updateVBIndex, current_vbindex, PrimaryBaseWasVirtual,
- BaseCurrentVBaseOffset);
+ updateVBIndex, current_vbindex, 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, CurrentVBaseOffset);
+ AddMethods(RD, MorallyVirtual, Offset, CurrentVBaseOffset);
}
void VBPrimaries(const CXXRecordDecl *RD, bool MorallyVirtual, int64_t Offset,
bool updateVBIndex, Index_t current_vbindex,
bool RDisVirtualBase, int64_t CurrentVBaseOffset,
- bool bottom=false) {
+ bool bottom) {
if (!RD->isDynamicClass())
return;
@@ -626,7 +679,7 @@ public:
VBPrimaries(PrimaryBase, PrimaryBaseWasVirtual|MorallyVirtual, Offset,
updateVBIndex, current_vbindex, PrimaryBaseWasVirtual,
- BaseCurrentVBaseOffset);
+ BaseCurrentVBaseOffset, false);
}
D1(printf(" doing vbase entries for %s most derived %s\n",
@@ -635,7 +688,7 @@ public:
if (RDisVirtualBase || bottom) {
Primaries(RD, MorallyVirtual, Offset, updateVBIndex, current_vbindex,
- RDisVirtualBase, CurrentVBaseOffset);
+ CurrentVBaseOffset);
}
}
@@ -718,30 +771,223 @@ public:
}
};
+}
+
+/// TypeConversionRequiresAdjustment - Returns whether conversion from a
+/// derived type to a base type requires adjustment.
+static bool
+TypeConversionRequiresAdjustment(ASTContext &Ctx,
+ const CXXRecordDecl *DerivedDecl,
+ const CXXRecordDecl *BaseDecl) {
+ CXXBasePaths Paths(/*FindAmbiguities=*/false,
+ /*RecordPaths=*/true, /*DetectVirtual=*/true);
+ if (!const_cast<CXXRecordDecl *>(DerivedDecl)->
+ isDerivedFrom(const_cast<CXXRecordDecl *>(BaseDecl), Paths)) {
+ assert(false && "Class must be derived from the passed in base class!");
+ return false;
+ }
+
+ // If we found a virtual base we always want to require adjustment.
+ if (Paths.getDetectedVirtual())
+ return true;
+
+ const CXXBasePath &Path = Paths.front();
+
+ for (size_t Start = 0, End = Path.size(); Start != End; ++Start) {
+ const CXXBasePathElement &Element = Path[Start];
+
+ // Check the base class offset.
+ const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(Element.Class);
+
+ const RecordType *BaseType = Element.Base->getType()->getAs<RecordType>();
+ const CXXRecordDecl *Base = cast<CXXRecordDecl>(BaseType->getDecl());
+
+ if (Layout.getBaseClassOffset(Base) != 0) {
+ // This requires an adjustment.
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool
+TypeConversionRequiresAdjustment(ASTContext &Ctx,
+ QualType DerivedType, QualType BaseType) {
+ // Canonicalize the types.
+ QualType CanDerivedType = Ctx.getCanonicalType(DerivedType);
+ QualType CanBaseType = Ctx.getCanonicalType(BaseType);
+
+ assert(CanDerivedType->getTypeClass() == CanBaseType->getTypeClass() &&
+ "Types must have same type class!");
+
+ if (CanDerivedType == CanBaseType) {
+ // No adjustment needed.
+ return false;
+ }
+
+ if (const ReferenceType *RT = dyn_cast<ReferenceType>(CanDerivedType)) {
+ CanDerivedType = RT->getPointeeType();
+ CanBaseType = cast<ReferenceType>(CanBaseType)->getPointeeType();
+ } else if (const PointerType *PT = dyn_cast<PointerType>(CanDerivedType)) {
+ CanDerivedType = PT->getPointeeType();
+ CanBaseType = cast<PointerType>(CanBaseType)->getPointeeType();
+ } else {
+ assert(false && "Unexpected return type!");
+ }
+
+ if (CanDerivedType == CanBaseType) {
+ // No adjustment needed.
+ return false;
+ }
+
+ const CXXRecordDecl *DerivedDecl =
+ cast<CXXRecordDecl>(cast<RecordType>(CanDerivedType)->getDecl());
+
+ const CXXRecordDecl *BaseDecl =
+ cast<CXXRecordDecl>(cast<RecordType>(CanBaseType)->getDecl());
+
+ return TypeConversionRequiresAdjustment(Ctx, DerivedDecl, BaseDecl);
+}
+
+void CGVtableInfo::ComputeMethodVtableIndices(const CXXRecordDecl *RD) {
+
+ // Itanium C++ ABI 2.5.2:
+ // The order of the virtual function pointers in a virtual table is the
+ // order of declaration of the corresponding member functions in the class.
+ //
+ // There is an entry for any virtual function declared in a class,
+ // whether it is a new function or overrides a base class function,
+ // unless it overrides a function from the primary base, and conversion
+ // between their return types does not require an adjustment.
+
+ int64_t CurrentIndex = 0;
+
+ const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
+ const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
+
+ if (PrimaryBase) {
+ assert(PrimaryBase->isDefinition() &&
+ "Should have the definition decl of the primary base!");
-VtableBuilder::Index_t VtableBuilder::VBlookup(CXXRecordDecl *D,
- CXXRecordDecl *B) {
- return CGM.getVtableInfo().getVirtualBaseOffsetIndex(D, B);
+ // Since the record decl shares its vtable pointer with the primary base
+ // we need to start counting at the end of the primary base's vtable.
+ CurrentIndex = getNumVirtualFunctionPointers(PrimaryBase);
+ }
+
+ const CXXDestructorDecl *ImplicitVirtualDtor = 0;
+
+ for (CXXRecordDecl::method_iterator i = RD->method_begin(),
+ e = RD->method_end(); i != e; ++i) {
+ const CXXMethodDecl *MD = *i;
+
+ // We only want virtual methods.
+ if (!MD->isVirtual())
+ continue;
+
+ bool ShouldAddEntryForMethod = true;
+
+ // Check if this method overrides a method in the primary base.
+ for (CXXMethodDecl::method_iterator i = MD->begin_overridden_methods(),
+ e = MD->end_overridden_methods(); i != e; ++i) {
+ const CXXMethodDecl *OverriddenMD = *i;
+ const CXXRecordDecl *OverriddenRD = OverriddenMD->getParent();
+ assert(OverriddenMD->isCanonicalDecl() &&
+ "Should have the canonical decl of the overridden RD!");
+
+ if (OverriddenRD == PrimaryBase) {
+ // Check if converting from the return type of the method to the
+ // return type of the overridden method requires conversion.
+ QualType ReturnType =
+ MD->getType()->getAs<FunctionType>()->getResultType();
+ QualType OverriddenReturnType =
+ OverriddenMD->getType()->getAs<FunctionType>()->getResultType();
+
+ if (!TypeConversionRequiresAdjustment(CGM.getContext(),
+ ReturnType, OverriddenReturnType)) {
+ // This index is shared between the index in the vtable of the primary
+ // base class.
+ if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
+ const CXXDestructorDecl *OverriddenDD =
+ cast<CXXDestructorDecl>(OverriddenMD);
+
+ // Add both the complete and deleting entries.
+ MethodVtableIndices[GlobalDecl(DD, Dtor_Complete)] =
+ getMethodVtableIndex(GlobalDecl(OverriddenDD, Dtor_Complete));
+ MethodVtableIndices[GlobalDecl(DD, Dtor_Deleting)] =
+ getMethodVtableIndex(GlobalDecl(OverriddenDD, Dtor_Deleting));
+ } else {
+ MethodVtableIndices[MD] = getMethodVtableIndex(OverriddenMD);
+ }
+
+ // We don't need to add an entry for this method.
+ ShouldAddEntryForMethod = false;
+ break;
+ }
+ }
+ }
+
+ if (!ShouldAddEntryForMethod)
+ continue;
+
+ if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
+ if (MD->isImplicit()) {
+ assert(!ImplicitVirtualDtor &&
+ "Did already see an implicit virtual dtor!");
+ ImplicitVirtualDtor = DD;
+ continue;
+ }
+
+ // Add the complete dtor.
+ MethodVtableIndices[GlobalDecl(DD, Dtor_Complete)] = CurrentIndex++;
+
+ // Add the deleting dtor.
+ MethodVtableIndices[GlobalDecl(DD, Dtor_Deleting)] = CurrentIndex++;
+ } else {
+ // Add the entry.
+ MethodVtableIndices[MD] = CurrentIndex++;
+ }
+ }
+
+ if (ImplicitVirtualDtor) {
+ // Itanium C++ ABI 2.5.2:
+ // If a class has an implicitly-defined virtual destructor,
+ // its entries come after the declared virtual function pointers.
+
+ // Add the complete dtor.
+ MethodVtableIndices[GlobalDecl(ImplicitVirtualDtor, Dtor_Complete)] =
+ CurrentIndex++;
+
+ // Add the deleting dtor.
+ MethodVtableIndices[GlobalDecl(ImplicitVirtualDtor, Dtor_Deleting)] =
+ CurrentIndex++;
+ }
+
+ NumVirtualFunctionPointers[RD] = CurrentIndex;
}
-int64_t CGVtableInfo::getMethodVtableIndex(GlobalDecl GD) {
+uint64_t CGVtableInfo::getNumVirtualFunctionPointers(const CXXRecordDecl *RD) {
+ llvm::DenseMap<const CXXRecordDecl *, uint64_t>::iterator I =
+ NumVirtualFunctionPointers.find(RD);
+ if (I != NumVirtualFunctionPointers.end())
+ return I->second;
+
+ ComputeMethodVtableIndices(RD);
+
+ I = NumVirtualFunctionPointers.find(RD);
+ assert(I != NumVirtualFunctionPointers.end() && "Did not find entry!");
+ return I->second;
+}
+
+uint64_t CGVtableInfo::getMethodVtableIndex(GlobalDecl GD) {
MethodVtableIndicesTy::iterator I = MethodVtableIndices.find(GD);
if (I != MethodVtableIndices.end())
return I->second;
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, RD, 0, CGM);
- D1(printf("vtable %s\n", RD->getNameAsCString()));
- b.GenerateVtableForBase(RD);
- b.GenerateVtableForVBases(RD);
-
- MethodVtableIndices.insert(b.getIndex().begin(),
- b.getIndex().end());
-
+
+ ComputeMethodVtableIndices(RD);
+
I = MethodVtableIndices.find(GD);
assert(I != MethodVtableIndices.end() && "Did not find index!");
return I->second;
@@ -782,22 +1028,25 @@ llvm::Constant *CodeGenModule::GenerateVtable(const CXXRecordDecl *LayoutClass,
const CXXRecordDecl *RD,
uint64_t Offset) {
llvm::SmallString<256> OutName;
- llvm::raw_svector_ostream Out(OutName);
if (LayoutClass != RD)
- mangleCXXCtorVtable(getMangleContext(), LayoutClass, Offset/8, RD, Out);
+ getMangleContext().mangleCXXCtorVtable(LayoutClass, Offset/8, RD, OutName);
else
- mangleCXXVtable(getMangleContext(), RD, Out);
- llvm::StringRef Name = Out.str();
+ getMangleContext().mangleCXXVtable(RD, OutName);
+ llvm::StringRef Name = OutName.str();
std::vector<llvm::Constant *> methods;
llvm::Type *Ptr8Ty=llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext),0);
int64_t AddressPoint;
llvm::GlobalVariable *GV = getModule().getGlobalVariable(Name);
- if (GV && AddressPoints[LayoutClass] && !GV->isDeclaration())
+ if (GV && AddressPoints[LayoutClass] && !GV->isDeclaration()) {
AddressPoint=(*(*(AddressPoints[LayoutClass]))[RD])[std::make_pair(RD,
Offset)];
- else {
+ // FIXME: We can never have 0 address point. Do this for now so gepping
+ // retains the same structure. Later, we'll just assert.
+ if (AddressPoint == 0)
+ AddressPoint = 1;
+ } else {
VtableBuilder b(methods, RD, LayoutClass, Offset, *this);
D1(printf("vtable %s\n", RD->getNameAsCString()));
@@ -807,20 +1056,14 @@ llvm::Constant *CodeGenModule::GenerateVtable(const CXXRecordDecl *LayoutClass,
// then the vtables for all the virtual bases.
b.GenerateVtableForVBases(RD, Offset);
- CodeGenModule::AddrMap_t *&ref = AddressPoints[LayoutClass];
- if (ref == 0)
- ref = new CodeGenModule::AddrMap_t;
-
- (*ref)[RD] = b.getAddressPoints();
-
bool CreateDefinition = true;
if (LayoutClass != RD)
CreateDefinition = true;
else {
- // We have to convert it to have a record layout.
- Types.ConvertTagDeclType(LayoutClass);
- const CGRecordLayout &CGLayout = Types.getCGRecordLayout(LayoutClass);
- if (const CXXMethodDecl *KeyFunction = CGLayout.getKeyFunction()) {
+ const ASTRecordLayout &Layout =
+ getContext().getASTRecordLayout(LayoutClass);
+
+ if (const CXXMethodDecl *KeyFunction = Layout.getKeyFunction()) {
if (!KeyFunction->getBody()) {
// If there is a KeyFunction, and it isn't defined, just build a
// reference to the vtable.
@@ -862,6 +1105,7 @@ llvm::Constant *CodeGenModule::GenerateVtable(const CXXRecordDecl *LayoutClass,
vtable = llvm::ConstantExpr::getInBoundsGetElementPtr(vtable, &AddressPointC,
1);
+ assert(vtable->getType() == Ptr8Ty);
return vtable;
}
@@ -888,7 +1132,7 @@ class VTTBuilder {
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.
+ // retains the same structure. Later we'll just assert.
if (AddressPoint == 0)
AddressPoint = 1;
D1(printf("XXX address point for %s in %s layout %s at offset %d was %d\n",
@@ -1034,9 +1278,8 @@ llvm::Constant *CodeGenModule::GenerateVTT(const CXXRecordDecl *RD) {
return 0;
llvm::SmallString<256> OutName;
- llvm::raw_svector_ostream Out(OutName);
- mangleCXXVTT(getMangleContext(), RD, Out);
- llvm::StringRef Name = Out.str();
+ getMangleContext().mangleCXXVTT(RD, OutName);
+ llvm::StringRef Name = OutName.str();
llvm::GlobalVariable::LinkageTypes linktype;
linktype = llvm::GlobalValue::LinkOnceODRLinkage;
@@ -1073,10 +1316,9 @@ llvm::Constant *CGVtableInfo::getVtable(const CXXRecordDecl *RD) {
vtbl = CGM.GenerateVtable(RD, RD);
bool CreateDefinition = true;
- // We have to convert it to have a record layout.
- CGM.getTypes().ConvertTagDeclType(RD);
- const CGRecordLayout &CGLayout = CGM.getTypes().getCGRecordLayout(RD);
- if (const CXXMethodDecl *KeyFunction = CGLayout.getKeyFunction()) {
+
+ const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
+ if (const CXXMethodDecl *KeyFunction = Layout.getKeyFunction()) {
if (!KeyFunction->getBody()) {
// If there is a KeyFunction, and it isn't defined, just build a
// reference to the vtable.
@@ -1096,3 +1338,31 @@ llvm::Constant *CGVtableInfo::getCtorVtable(const CXXRecordDecl *LayoutClass,
uint64_t Offset) {
return CGM.GenerateVtable(LayoutClass, RD, Offset);
}
+
+void CGVtableInfo::MaybeEmitVtable(GlobalDecl GD) {
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
+ const CXXRecordDecl *RD = MD->getParent();
+
+ const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
+
+ // Get the key function.
+ const CXXMethodDecl *KeyFunction = Layout.getKeyFunction();
+
+ if (!KeyFunction) {
+ // If there's no key function, we don't want to emit the vtable here.
+ return;
+ }
+
+ // Check if we have the key function.
+ if (KeyFunction->getCanonicalDecl() != MD->getCanonicalDecl())
+ return;
+
+ // If the key function is a destructor, we only want to emit the vtable once,
+ // so do it for the complete destructor.
+ if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() != Dtor_Complete)
+ return;
+
+ // Emit the data.
+ GenerateClassData(RD);
+}
+
diff --git a/lib/CodeGen/CGVtable.h b/lib/CodeGen/CGVtable.h
index 78ae670cf35a..5c2b74c9dd86 100644
--- a/lib/CodeGen/CGVtable.h
+++ b/lib/CodeGen/CGVtable.h
@@ -17,56 +17,110 @@
#include "llvm/ADT/DenseMap.h"
#include "GlobalDecl.h"
+namespace llvm {
+ class Constant;
+}
+
namespace clang {
- class CXXMethodDecl;
class CXXRecordDecl;
-
+
namespace CodeGen {
class CodeGenModule;
-
+
+/// ThunkAdjustment - Virtual and non-virtual adjustment for thunks.
+class ThunkAdjustment {
+public:
+ ThunkAdjustment(int64_t NonVirtual, int64_t Virtual)
+ : NonVirtual(NonVirtual),
+ Virtual(Virtual) { }
+
+ ThunkAdjustment()
+ : NonVirtual(0), Virtual(0) { }
+
+ // isEmpty - Return whether this thunk adjustment is empty.
+ bool isEmpty() const {
+ return NonVirtual == 0 && Virtual == 0;
+ }
+
+ /// NonVirtual - The non-virtual adjustment.
+ int64_t NonVirtual;
+
+ /// Virtual - The virtual adjustment.
+ int64_t Virtual;
+};
+
+/// CovariantThunkAdjustment - Adjustment of the 'this' pointer and the
+/// return pointer for covariant thunks.
+class CovariantThunkAdjustment {
+public:
+ CovariantThunkAdjustment(const ThunkAdjustment &ThisAdjustment,
+ const ThunkAdjustment &ReturnAdjustment)
+ : ThisAdjustment(ThisAdjustment), ReturnAdjustment(ReturnAdjustment) { }
+
+ CovariantThunkAdjustment() { }
+
+ ThunkAdjustment ThisAdjustment;
+ ThunkAdjustment ReturnAdjustment;
+};
+
class CGVtableInfo {
CodeGenModule &CGM;
-
+
/// MethodVtableIndices - Contains the index (relative to the vtable address
/// point) where the function pointer for a virtual function is stored.
typedef llvm::DenseMap<GlobalDecl, int64_t> MethodVtableIndicesTy;
MethodVtableIndicesTy MethodVtableIndices;
-
+
typedef std::pair<const CXXRecordDecl *,
const CXXRecordDecl *> ClassPairTy;
-
+
/// VirtualBaseClassIndicies - Contains the index into the vtable where the
/// 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;
+
+ /// NumVirtualFunctionPointers - Contains the number of virtual function
+ /// pointers in the vtable for a given record decl.
+ llvm::DenseMap<const CXXRecordDecl *, uint64_t> NumVirtualFunctionPointers;
+
+ /// getNumVirtualFunctionPointers - Return the number of virtual function
+ /// pointers in the vtable for a given record decl.
+ uint64_t getNumVirtualFunctionPointers(const CXXRecordDecl *RD);
+
+ void ComputeMethodVtableIndices(const CXXRecordDecl *RD);
+
+ /// GenerateClassData - Generate all the class data requires to be generated
+ /// upon definition of a KeyFunction. This includes the vtable, the
+ /// rtti data structure and the VTT.
+ void GenerateClassData(const CXXRecordDecl *RD);
+
public:
- CGVtableInfo(CodeGenModule &CGM)
+ CGVtableInfo(CodeGenModule &CGM)
: CGM(CGM) { }
/// getMethodVtableIndex - Return the index (relative to the vtable address
- /// point) where the function pointer for the given virtual function is
+ /// point) where the function pointer for the given virtual function is
/// stored.
- int64_t getMethodVtableIndex(GlobalDecl GD);
-
+ uint64_t getMethodVtableIndex(GlobalDecl GD);
+
/// getVirtualBaseOffsetIndex - Return the index (relative to the vtable
/// address point) where the offset of the virtual base that contains the
/// given Base is stored, otherwise, if no virtual base contains the given
/// class, return 0. Base must be a virtual base class or an unambigious
/// base.
- int64_t getVirtualBaseOffsetIndex(const CXXRecordDecl *RD,
+ 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);
- /// GenerateClassData - Generate all the class data requires to be generated
- /// upon definition of a KeyFunction. This includes the vtable, the
- /// rtti data structure and the VTT.
- void GenerateClassData(const CXXRecordDecl *RD);
-};
+
+ void MaybeEmitVtable(GlobalDecl GD);
+};
+
}
}
#endif
diff --git a/lib/CodeGen/CMakeLists.txt b/lib/CodeGen/CMakeLists.txt
index 10884a7560f5..92814169d0ab 100644
--- a/lib/CodeGen/CMakeLists.txt
+++ b/lib/CodeGen/CMakeLists.txt
@@ -3,11 +3,9 @@ set(LLVM_NO_RTTI 1)
add_clang_library(clangCodeGen
CGBlocks.cpp
CGBuiltin.cpp
- CGCXX.cpp
- CGCXXClass.cpp
- CGCXXExpr.cpp
- CGCXXTemp.cpp
CGCall.cpp
+ CGClass.cpp
+ CGCXX.cpp
CGDebugInfo.cpp
CGDecl.cpp
CGException.cpp
@@ -15,6 +13,7 @@ add_clang_library(clangCodeGen
CGExprAgg.cpp
CGExprComplex.cpp
CGExprConstant.cpp
+ CGExprCXX.cpp
CGExprScalar.cpp
CGObjC.cpp
CGObjCGNU.cpp
@@ -22,6 +21,7 @@ add_clang_library(clangCodeGen
CGRecordLayoutBuilder.cpp
CGRtti.cpp
CGStmt.cpp
+ CGTemporaries.cpp
CGVtable.cpp
CodeGenFunction.cpp
CodeGenModule.cpp
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index 475c7bfefd1d..6e0a77ca1b0b 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -29,7 +29,8 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm)
Builder(cgm.getModule().getContext()),
DebugInfo(0), IndirectBranch(0),
SwitchInsn(0), CaseRangeBlock(0), InvokeDest(0),
- CXXThisDecl(0) {
+ CXXThisDecl(0), CXXVTTDecl(0),
+ ConditionalBranchLevel(0) {
LLVMIntTy = ConvertType(getContext().IntTy);
LLVMPointerWidth = Target.getPointerWidth(0);
}
@@ -216,6 +217,24 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
}
}
+static bool NeedsVTTParameter(GlobalDecl GD) {
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl());
+
+ // We don't have any virtual bases, just return early.
+ if (!MD->getParent()->getNumVBases())
+ return false;
+
+ // Check if we have a base constructor.
+ if (isa<CXXConstructorDecl>(MD) && GD.getCtorType() == Ctor_Base)
+ return true;
+
+ // Check if we have a base destructor.
+ if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() == Dtor_Base)
+ return true;
+
+ return false;
+}
+
void CodeGenFunction::GenerateCode(GlobalDecl GD,
llvm::Function *Fn) {
const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
@@ -235,6 +254,16 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD,
&getContext().Idents.get("this"),
MD->getThisType(getContext()));
Args.push_back(std::make_pair(CXXThisDecl, CXXThisDecl->getType()));
+
+ // Check if we need a VTT parameter as well.
+ if (NeedsVTTParameter(GD)) {
+ // FIXME: The comment about using a fake decl above applies here too.
+ QualType T = getContext().getPointerType(getContext().VoidPtrTy);
+ CXXVTTDecl =
+ ImplicitParamDecl::Create(getContext(), 0, SourceLocation(),
+ &getContext().Idents.get("vtt"), T);
+ Args.push_back(std::make_pair(CXXVTTDecl, CXXVTTDecl->getType()));
+ }
}
}
@@ -317,6 +346,10 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD,
// Destroy the 'this' declaration.
if (CXXThisDecl)
CXXThisDecl->Destroy(getContext());
+
+ // Destroy the VTT declaration.
+ if (CXXVTTDecl)
+ CXXVTTDecl->Destroy(getContext());
}
/// ContainsLabel - Return true if the statement contains a label in it. If
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index d96c3551010e..7f3204587a95 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -133,17 +133,17 @@ public:
/// block.
CleanupBlockInfo PopCleanupBlock();
- /// CleanupScope - RAII object that will create a cleanup block and set the
- /// insert point to that block. When destructed, it sets the insert point to
- /// the previous block and pushes a new cleanup entry on the stack.
- class CleanupScope {
+ /// DelayedCleanupBlock - RAII object that will create a cleanup block and set
+ /// the insert point to that block. When destructed, it sets the insert point
+ /// to the previous block and pushes a new cleanup entry on the stack.
+ class DelayedCleanupBlock {
CodeGenFunction& CGF;
llvm::BasicBlock *CurBB;
llvm::BasicBlock *CleanupEntryBB;
llvm::BasicBlock *CleanupExitBB;
public:
- CleanupScope(CodeGenFunction &cgf)
+ DelayedCleanupBlock(CodeGenFunction &cgf)
: CGF(cgf), CurBB(CGF.Builder.GetInsertBlock()),
CleanupEntryBB(CGF.createBasicBlock("cleanup")), CleanupExitBB(0) {
CGF.Builder.SetInsertPoint(CleanupEntryBB);
@@ -155,7 +155,7 @@ public:
return CleanupExitBB;
}
- ~CleanupScope() {
+ ~DelayedCleanupBlock() {
CGF.PushCleanupBlock(CleanupEntryBB, CleanupExitBB);
// FIXME: This is silly, move this into the builder.
if (CurBB)
@@ -165,6 +165,50 @@ public:
}
};
+ /// \brief Enters a new scope for capturing cleanups, all of which will be
+ /// executed once the scope is exited.
+ class CleanupScope {
+ CodeGenFunction& CGF;
+ size_t CleanupStackDepth;
+ bool OldDidCallStackSave;
+ bool PerformCleanup;
+
+ CleanupScope(const CleanupScope &); // DO NOT IMPLEMENT
+ CleanupScope &operator=(const CleanupScope &); // DO NOT IMPLEMENT
+
+ public:
+ /// \brief Enter a new cleanup scope.
+ explicit CleanupScope(CodeGenFunction &CGF)
+ : CGF(CGF), PerformCleanup(true)
+ {
+ CleanupStackDepth = CGF.CleanupEntries.size();
+ OldDidCallStackSave = CGF.DidCallStackSave;
+ }
+
+ /// \brief Exit this cleanup scope, emitting any accumulated
+ /// cleanups.
+ ~CleanupScope() {
+ if (PerformCleanup) {
+ CGF.DidCallStackSave = OldDidCallStackSave;
+ CGF.EmitCleanupBlocks(CleanupStackDepth);
+ }
+ }
+
+ /// \brief Determine whether this scope requires any cleanups.
+ bool requiresCleanups() const {
+ return CGF.CleanupEntries.size() > CleanupStackDepth;
+ }
+
+ /// \brief Force the emission of cleanups now, instead of waiting
+ /// until this object is destroyed.
+ void ForceCleanup() {
+ assert(PerformCleanup && "Already forced cleanup");
+ CGF.DidCallStackSave = OldDidCallStackSave;
+ CGF.EmitCleanupBlocks(CleanupStackDepth);
+ PerformCleanup = false;
+ }
+ };
+
/// EmitCleanupBlocks - Takes the old cleanup stack size and emits the cleanup
/// blocks that have been added.
void EmitCleanupBlocks(size_t OldCleanupStackSize);
@@ -176,27 +220,31 @@ public:
/// this behavior for branches?
void EmitBranchThroughCleanup(llvm::BasicBlock *Dest);
- /// PushConditionalTempDestruction - Should be called before a conditional
- /// part of an expression is emitted. For example, before the RHS of the
- /// expression below is emitted:
+ /// StartConditionalBranch - Should be called before a conditional part of an
+ /// expression is emitted. For example, before the RHS of the expression below
+ /// is emitted:
///
/// b && f(T());
///
- /// This is used to make sure that any temporaryes created in the conditional
+ /// This is used to make sure that any temporaries created in the conditional
/// branch are only destroyed if the branch is taken.
- void PushConditionalTempDestruction();
+ void StartConditionalBranch() {
+ ++ConditionalBranchLevel;
+ }
- /// PopConditionalTempDestruction - Should be called after a conditional
- /// part of an expression has been emitted.
- void PopConditionalTempDestruction();
+ /// FinishConditionalBranch - Should be called after a conditional part of an
+ /// expression has been emitted.
+ void FinishConditionalBranch() {
+ --ConditionalBranchLevel;
+ }
private:
CGDebugInfo *DebugInfo;
- /// 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.
+ /// 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;
/// LocalDeclMap - This keeps track of the LLVM allocas or globals for local C
@@ -269,10 +317,15 @@ private:
/// BlockScopes - Map of which "cleanup scope" scope basic blocks have.
BlockScopeMap BlockScopes;
- /// CXXThisDecl - When parsing an C++ function, this will hold the implicit
- /// 'this' declaration.
+ /// CXXThisDecl - When generating code for a C++ member function,
+ /// this will hold the implicit 'this' declaration.
ImplicitParamDecl *CXXThisDecl;
+ /// CXXVTTDecl - When generating code for a base object constructor or
+ /// base object destructor with virtual bases, this will hold the implicit
+ /// VTT parameter.
+ ImplicitParamDecl *CXXVTTDecl;
+
/// CXXLiveTemporaryInfo - Holds information about a live C++ temporary.
struct CXXLiveTemporaryInfo {
/// Temporary - The live temporary.
@@ -284,9 +337,9 @@ private:
/// DtorBlock - The destructor block.
llvm::BasicBlock *DtorBlock;
- /// CondPtr - If this is a conditional temporary, this is the pointer to
- /// the condition variable that states whether the destructor should be
- /// called or not.
+ /// CondPtr - If this is a conditional temporary, this is the pointer to the
+ /// condition variable that states whether the destructor should be called
+ /// or not.
llvm::Value *CondPtr;
CXXLiveTemporaryInfo(const CXXTemporary *temporary,
@@ -298,10 +351,10 @@ private:
llvm::SmallVector<CXXLiveTemporaryInfo, 4> LiveTemporaries;
- /// ConditionalTempDestructionStack - Contains the number of live temporaries
- /// when PushConditionalTempDestruction was called. This is used so that
- /// we know how many temporaries were created by a certain expression.
- llvm::SmallVector<size_t, 4> ConditionalTempDestructionStack;
+ /// ConditionalBranchLevel - Contains the nesting level of the current
+ /// conditional branch. This is used so that we know if a temporary should be
+ /// destroyed conditionally.
+ unsigned ConditionalBranchLevel;
/// ByrefValueInfoMap - For each __block variable, contains a pair of the LLVM
@@ -384,15 +437,17 @@ public:
/// 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.
- llvm::Value *DynamicTypeAdjust(llvm::Value *V, int64_t nv, int64_t v);
+ llvm::Value *DynamicTypeAdjust(llvm::Value *V,
+ const ThunkAdjustment &Adjustment);
/// GenerateThunk - Generate a thunk for the given method
llvm::Constant *GenerateThunk(llvm::Function *Fn, const CXXMethodDecl *MD,
- bool Extern, int64_t nv, int64_t v);
- llvm::Constant *GenerateCovariantThunk(llvm::Function *Fn,
- const CXXMethodDecl *MD, bool Extern,
- int64_t nv_t, int64_t v_t,
- int64_t nv_r, int64_t v_r);
+ bool Extern,
+ const ThunkAdjustment &ThisAdjustment);
+ llvm::Constant *
+ GenerateCovariantThunk(llvm::Function *Fn, const CXXMethodDecl *MD,
+ bool Extern,
+ const CovariantThunkAdjustment &Adjustment);
void EmitCtorPrologue(const CXXConstructorDecl *CD, CXXCtorType Type);
@@ -416,8 +471,8 @@ public:
const FunctionArgList &Args);
/// EmitDtorEpilogue - Emit all code that comes at the end of class's
- /// destructor. This is to call destructors on members and base classes
- /// in reverse order of their construction.
+ /// destructor. This is to call destructors on members and base classes in
+ /// reverse order of their construction.
void EmitDtorEpilogue(const CXXDestructorDecl *Dtor,
CXXDtorType Type);
@@ -461,9 +516,9 @@ public:
/// label maps to.
llvm::BasicBlock *getBasicBlockForLabel(const LabelStmt *S);
- /// SimplifyForwardingBlocks - If the given basic block is only a
- /// branch to another basic block, simplify it. This assumes that no
- /// other code could potentially reference the basic block.
+ /// SimplifyForwardingBlocks - If the given basic block is only a branch to
+ /// another basic block, simplify it. This assumes that no other code could
+ /// potentially reference the basic block.
void SimplifyForwardingBlocks(llvm::BasicBlock *BB);
/// EmitBlock - Emit the given block \arg BB and set it as the insert point,
@@ -579,9 +634,9 @@ public:
// instruction in LLVM instead once it works well enough.
llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty);
- // EmitVLASize - Generate code for any VLA size expressions that might occur
- // in a variably modified type. If Ty is a VLA, will return the value that
- // corresponds to the size in bytes of the VLA type. Will return 0 otherwise.
+ /// EmitVLASize - Generate code for any VLA size expressions that might occur
+ /// in a variably modified type. If Ty is a VLA, will return the value that
+ /// corresponds to the size in bytes of the VLA type. Will return 0 otherwise.
///
/// This function can be called with a null (unreachable) insert point.
llvm::Value *EmitVLASize(QualType Ty);
@@ -594,15 +649,20 @@ public:
/// generating code for an C++ member function.
llvm::Value *LoadCXXThis();
- /// GetAddressCXXOfBaseClass - This function will add the necessary delta
- /// to the load of 'this' and returns address of the base class.
+ /// GetAddressOfBaseClass - This function will add the necessary delta to the
+ /// load of 'this' and returns address of the base class.
// FIXME. This currently only does a derived to non-virtual base conversion.
// Other kinds of conversions will come later.
- llvm::Value *GetAddressCXXOfBaseClass(llvm::Value *BaseValue,
+ llvm::Value *GetAddressOfBaseClass(llvm::Value *Value,
+ const CXXRecordDecl *ClassDecl,
+ const CXXRecordDecl *BaseClassDecl,
+ bool NullCheckValue);
+
+ llvm::Value *GetAddressOfDerivedClass(llvm::Value *Value,
const CXXRecordDecl *ClassDecl,
- const CXXRecordDecl *BaseClassDecl,
+ const CXXRecordDecl *DerivedClassDecl,
bool NullCheckValue);
-
+
llvm::Value *
GetVirtualCXXBaseClassOffset(llvm::Value *This,
const CXXRecordDecl *ClassDecl,
@@ -637,10 +697,15 @@ public:
void EmitCXXAggrConstructorCall(const CXXConstructorDecl *D,
const ConstantArrayType *ArrayTy,
- llvm::Value *ArrayPtr);
+ llvm::Value *ArrayPtr,
+ CallExpr::const_arg_iterator ArgBeg,
+ CallExpr::const_arg_iterator ArgEnd);
+
void EmitCXXAggrConstructorCall(const CXXConstructorDecl *D,
llvm::Value *NumElements,
- llvm::Value *ArrayPtr);
+ llvm::Value *ArrayPtr,
+ CallExpr::const_arg_iterator ArgBeg,
+ CallExpr::const_arg_iterator ArgEnd);
void EmitCXXAggrDestructorCall(const CXXDestructorDecl *D,
const ArrayType *Array,
@@ -858,7 +923,6 @@ public:
LValue EmitBlockDeclRefLValue(const BlockDeclRefExpr *E);
- LValue EmitCXXConditionDeclLValue(const CXXConditionDeclExpr *E);
LValue EmitCXXConstructLValue(const CXXConstructExpr *E);
LValue EmitCXXBindTemporaryLValue(const CXXBindTemporaryExpr *E);
LValue EmitCXXExprWithTemporariesLValue(const CXXExprWithTemporaries *E);
@@ -880,9 +944,8 @@ public:
/// result type, and using the given argument list which specifies both the
/// LLVM arguments and the types they were derived from.
///
- /// \param TargetDecl - If given, the decl of the function in a
- /// direct call; used to set attributes on the call (noreturn,
- /// etc.).
+ /// \param TargetDecl - If given, the decl of the function in a direct call;
+ /// used to set attributes on the call (noreturn, etc.).
RValue EmitCall(const CGFunctionInfo &FnInfo,
llvm::Value *Callee,
const CallArgList &Args,
@@ -994,15 +1057,14 @@ public:
/// LoadComplexFromAddr - Load a complex number from the specified address.
ComplexPairTy LoadComplexFromAddr(llvm::Value *SrcAddr, bool SrcIsVolatile);
- /// CreateStaticBlockVarDecl - Create a zero-initialized LLVM global
- /// for a static block var decl.
+ /// CreateStaticBlockVarDecl - Create a zero-initialized LLVM global for a
+ /// static block var decl.
llvm::GlobalVariable * CreateStaticBlockVarDecl(const VarDecl &D,
const char *Separator,
- llvm::GlobalValue::LinkageTypes
- Linkage);
+ llvm::GlobalValue::LinkageTypes Linkage);
- /// EmitStaticCXXBlockVarDeclInit - Create the initializer for a C++
- /// runtime initialized static block var decl.
+ /// EmitStaticCXXBlockVarDeclInit - Create the initializer for a C++ runtime
+ /// initialized static block var decl.
void EmitStaticCXXBlockVarDeclInit(const VarDecl &D,
llvm::GlobalVariable *GV);
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 195acc5bc157..4b3b122b71cf 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -21,6 +21,7 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/RecordLayout.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceManager.h"
@@ -160,19 +161,13 @@ const char *CodeGenModule::getMangledName(const GlobalDecl &GD) {
/// the unmangled name.
///
const char *CodeGenModule::getMangledName(const NamedDecl *ND) {
- // In C, functions with no attributes never need to be mangled. Fastpath them.
- if (!getLangOptions().CPlusPlus && !ND->hasAttrs()) {
+ if (!getMangleContext().shouldMangleDeclName(ND)) {
assert(ND->getIdentifier() && "Attempt to mangle unnamed decl.");
return ND->getNameAsCString();
}
llvm::SmallString<256> Name;
- llvm::raw_svector_ostream Out(Name);
- if (!mangleName(getMangleContext(), ND, Out)) {
- assert(ND->getIdentifier() && "Attempt to mangle unnamed decl.");
- return ND->getNameAsCString();
- }
-
+ getMangleContext().mangleName(ND, Name);
Name += '\0';
return UniqueMangledName(Name.begin(), Name.end());
}
@@ -353,8 +348,12 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D,
else if (Features.getStackProtectorMode() == LangOptions::SSPReq)
F->addFnAttr(llvm::Attribute::StackProtectReq);
- if (const AlignedAttr *AA = D->getAttr<AlignedAttr>())
- F->setAlignment(AA->getAlignment()/8);
+ if (const AlignedAttr *AA = D->getAttr<AlignedAttr>()) {
+ unsigned width = Context.Target.getCharWidth();
+ F->setAlignment(AA->getAlignment() / width);
+ while ((AA = AA->getNext<AlignedAttr>()))
+ F->setAlignment(std::max(F->getAlignment(), AA->getAlignment() / width));
+ }
// C++ ABI requires 2-byte alignment for member functions.
if (F->getAlignment() < 2 && isa<CXXMethodDecl>(D))
F->setAlignment(2);
@@ -551,7 +550,7 @@ bool CodeGenModule::MayDeferGeneration(const ValueDecl *Global) {
// cannot be.
if (VD->isInAnonymousNamespace())
return true;
- if (VD->getStorageClass() == VarDecl::Static) {
+ if (VD->getLinkage() == VarDecl::InternalLinkage) {
// Initializer has side effects?
if (VD->getInit() && VD->getInit()->HasSideEffects(Context))
return false;
@@ -616,16 +615,9 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) {
Context.getSourceManager(),
"Generating code for declaration");
- if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
- const CXXRecordDecl *RD = MD->getParent();
- // We have to convert it to have a record layout.
- Types.ConvertTagDeclType(RD);
- const CGRecordLayout &CGLayout = Types.getCGRecordLayout(RD);
- // A definition of a KeyFunction, generates all the class data, such
- // as vtable, rtti and the VTT.
- if (CGLayout.getKeyFunction() == MD)
- getVtableInfo().GenerateClassData(RD);
- }
+ if (isa<CXXMethodDecl>(D))
+ getVtableInfo().MaybeEmitVtable(GD);
+
if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(D))
EmitCXXConstructor(CD, GD.getCtorType());
else if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(D))
@@ -697,143 +689,20 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(const char *MangledName,
// A called constructor which has no definition or declaration need be
// synthesized.
else if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD)) {
- const CXXRecordDecl *ClassDecl =
- cast<CXXRecordDecl>(CD->getDeclContext());
- if (CD->isCopyConstructor(getContext()))
- DeferredCopyConstructorToEmit(D);
- else if (!ClassDecl->hasUserDeclaredConstructor())
+ if (CD->isImplicit())
+ DeferredDeclsToEmit.push_back(D);
+ } else if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(FD)) {
+ if (DD->isImplicit())
+ DeferredDeclsToEmit.push_back(D);
+ } else if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
+ if (MD->isCopyAssignment() && MD->isImplicit())
DeferredDeclsToEmit.push_back(D);
}
- else if (isa<CXXDestructorDecl>(FD))
- DeferredDestructorToEmit(D);
- else if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD))
- if (MD->isCopyAssignment())
- DeferredCopyAssignmentToEmit(D);
}
return F;
}
-/// Defer definition of copy constructor(s) which need be implicitly defined.
-void CodeGenModule::DeferredCopyConstructorToEmit(GlobalDecl CopyCtorDecl) {
- const CXXConstructorDecl *CD =
- cast<CXXConstructorDecl>(CopyCtorDecl.getDecl());
- const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(CD->getDeclContext());
- if (ClassDecl->hasTrivialCopyConstructor() ||
- ClassDecl->hasUserDeclaredCopyConstructor())
- return;
-
- // First make sure all direct base classes and virtual bases and non-static
- // data mebers which need to have their copy constructors implicitly defined
- // are defined. 12.8.p7
- for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin();
- Base != ClassDecl->bases_end(); ++Base) {
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
- if (CXXConstructorDecl *BaseCopyCtor =
- BaseClassDecl->getCopyConstructor(Context, 0))
- GetAddrOfCXXConstructor(BaseCopyCtor, Ctor_Complete);
- }
-
- for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
- FieldEnd = ClassDecl->field_end();
- Field != FieldEnd; ++Field) {
- QualType FieldType = Context.getCanonicalType((*Field)->getType());
- if (const ArrayType *Array = Context.getAsArrayType(FieldType))
- FieldType = Array->getElementType();
- if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
- if ((*Field)->isAnonymousStructOrUnion())
- continue;
- CXXRecordDecl *FieldClassDecl
- = cast<CXXRecordDecl>(FieldClassType->getDecl());
- if (CXXConstructorDecl *FieldCopyCtor =
- FieldClassDecl->getCopyConstructor(Context, 0))
- GetAddrOfCXXConstructor(FieldCopyCtor, Ctor_Complete);
- }
- }
- DeferredDeclsToEmit.push_back(CopyCtorDecl);
-}
-
-/// Defer definition of copy assignments which need be implicitly defined.
-void CodeGenModule::DeferredCopyAssignmentToEmit(GlobalDecl CopyAssignDecl) {
- const CXXMethodDecl *CD = cast<CXXMethodDecl>(CopyAssignDecl.getDecl());
- const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(CD->getDeclContext());
-
- if (ClassDecl->hasTrivialCopyAssignment() ||
- ClassDecl->hasUserDeclaredCopyAssignment())
- return;
-
- // First make sure all direct base classes and virtual bases and non-static
- // data mebers which need to have their copy assignments implicitly defined
- // are defined. 12.8.p12
- for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin();
- Base != ClassDecl->bases_end(); ++Base) {
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
- const CXXMethodDecl *MD = 0;
- if (!BaseClassDecl->hasTrivialCopyAssignment() &&
- !BaseClassDecl->hasUserDeclaredCopyAssignment() &&
- BaseClassDecl->hasConstCopyAssignment(getContext(), MD))
- GetAddrOfFunction(MD, 0);
- }
-
- for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
- FieldEnd = ClassDecl->field_end();
- Field != FieldEnd; ++Field) {
- QualType FieldType = Context.getCanonicalType((*Field)->getType());
- if (const ArrayType *Array = Context.getAsArrayType(FieldType))
- FieldType = Array->getElementType();
- if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
- if ((*Field)->isAnonymousStructOrUnion())
- continue;
- CXXRecordDecl *FieldClassDecl
- = cast<CXXRecordDecl>(FieldClassType->getDecl());
- const CXXMethodDecl *MD = 0;
- if (!FieldClassDecl->hasTrivialCopyAssignment() &&
- !FieldClassDecl->hasUserDeclaredCopyAssignment() &&
- FieldClassDecl->hasConstCopyAssignment(getContext(), MD))
- GetAddrOfFunction(MD, 0);
- }
- }
- DeferredDeclsToEmit.push_back(CopyAssignDecl);
-}
-
-void CodeGenModule::DeferredDestructorToEmit(GlobalDecl DtorDecl) {
- const CXXDestructorDecl *DD = cast<CXXDestructorDecl>(DtorDecl.getDecl());
- const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(DD->getDeclContext());
- if (ClassDecl->hasTrivialDestructor() ||
- ClassDecl->hasUserDeclaredDestructor())
- return;
-
- for (CXXRecordDecl::base_class_const_iterator Base = ClassDecl->bases_begin();
- Base != ClassDecl->bases_end(); ++Base) {
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
- if (const CXXDestructorDecl *BaseDtor =
- BaseClassDecl->getDestructor(Context))
- GetAddrOfCXXDestructor(BaseDtor, Dtor_Complete);
- }
-
- for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
- FieldEnd = ClassDecl->field_end();
- Field != FieldEnd; ++Field) {
- QualType FieldType = Context.getCanonicalType((*Field)->getType());
- if (const ArrayType *Array = Context.getAsArrayType(FieldType))
- FieldType = Array->getElementType();
- if (const RecordType *FieldClassType = FieldType->getAs<RecordType>()) {
- if ((*Field)->isAnonymousStructOrUnion())
- continue;
- CXXRecordDecl *FieldClassDecl
- = cast<CXXRecordDecl>(FieldClassType->getDecl());
- if (const CXXDestructorDecl *FieldDtor =
- FieldClassDecl->getDestructor(Context))
- GetAddrOfCXXDestructor(FieldDtor, Dtor_Complete);
- }
- }
- DeferredDeclsToEmit.push_back(DtorDecl);
-}
-
-
/// GetAddrOfFunction - Return the address of the given function. If Ty is
/// non-null, then this function will use the specified type if it has to
/// create it (this occurs when we see a definition of the function).
@@ -982,9 +851,8 @@ GetLinkageForVariable(ASTContext &Context, const VarDecl *VD) {
return CodeGenModule::GVA_TemplateInstantiation;
}
}
-
- // Static variables get internal linkage.
- if (VD->getStorageClass() == VarDecl::Static)
+
+ if (VD->getLinkage() == VarDecl::InternalLinkage)
return CodeGenModule::GVA_Internal;
return CodeGenModule::GVA_StrongExternal;
@@ -1097,7 +965,7 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
GV->setLinkage(llvm::GlobalVariable::WeakAnyLinkage);
} else if (Linkage == GVA_TemplateInstantiation)
GV->setLinkage(llvm::GlobalVariable::WeakAnyLinkage);
- else if (!CodeGenOpts.NoCommon &&
+ else if (!getLangOptions().CPlusPlus && !CodeGenOpts.NoCommon &&
!D->hasExternalStorage() && !D->getInit() &&
!D->getAttr<SectionAttr>()) {
GV->setLinkage(llvm::GlobalVariable::CommonLinkage);
@@ -1734,6 +1602,10 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
case Decl::NamespaceAlias:
break;
case Decl::CXXConstructor:
+ // Skip function templates
+ if (cast<FunctionDecl>(D)->getDescribedFunctionTemplate())
+ return;
+
EmitCXXConstructors(cast<CXXConstructorDecl>(D));
break;
case Decl::CXXDestructor:
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index c8562d6745eb..78bc4ed845d8 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -231,15 +231,16 @@ public:
llvm::Constant *GenerateRttiRef(const CXXRecordDecl *RD);
/// GenerateRttiNonClass - Generate the rtti information for the given
/// non-class type.
- llvm::Constant *GenerateRttiNonClass(QualType Ty);
+ llvm::Constant *GenerateRtti(QualType Ty);
+
+ /// BuildThunk - Build a thunk for the given method.
+ llvm::Constant *BuildThunk(const CXXMethodDecl *MD, bool Extern,
+ const ThunkAdjustment &ThisAdjustment);
- /// BuildThunk - Build a thunk for the given method
- llvm::Constant *BuildThunk(const CXXMethodDecl *MD, bool Extern, int64_t nv,
- int64_t v);
/// BuildCoVariantThunk - Build a thunk for the given method
- llvm::Constant *BuildCovariantThunk(const CXXMethodDecl *MD, bool Extern,
- int64_t nv_t, int64_t v_t,
- int64_t nv_r, int64_t v_r);
+ llvm::Constant *
+ BuildCovariantThunk(const CXXMethodDecl *MD, bool Extern,
+ const CovariantThunkAdjustment &Adjustment);
typedef std::pair<const CXXRecordDecl *, uint64_t> CtorVtable_t;
typedef llvm::DenseMap<const CXXRecordDecl *,
@@ -427,9 +428,6 @@ private:
llvm::Constant *GetOrCreateLLVMGlobal(const char *MangledName,
const llvm::PointerType *PTy,
const VarDecl *D);
- void DeferredCopyConstructorToEmit(GlobalDecl D);
- void DeferredCopyAssignmentToEmit(GlobalDecl D);
- void DeferredDestructorToEmit(GlobalDecl D);
/// SetCommonAttributes - Set attributes which are common to any
/// form of a global definition (alias, Objective-C method,
diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp
index 1f83f37e0479..c89879fdb6c4 100644
--- a/lib/CodeGen/CodeGenTypes.cpp
+++ b/lib/CodeGen/CodeGenTypes.cpp
@@ -38,7 +38,13 @@ CodeGenTypes::~CodeGenTypes() {
I = CGRecordLayouts.begin(), E = CGRecordLayouts.end();
I != E; ++I)
delete I->second;
- CGRecordLayouts.clear();
+ {
+ llvm::FoldingSet<CGFunctionInfo>::iterator
+ I = FunctionInfos.begin(), E = FunctionInfos.end();
+ while (I != E)
+ delete &*I++;
+ }
+ delete TheABIInfo;
}
/// ConvertType - Convert the specified type to its LLVM form.
@@ -197,6 +203,7 @@ const llvm::Type *CodeGenTypes::ConvertNewType(QualType T) {
case BuiltinType::Void:
case BuiltinType::ObjCId:
case BuiltinType::ObjCClass:
+ case BuiltinType::ObjCSel:
// LLVM void type can only be used as the result of a function call. Just
// map to the same as char.
return llvm::IntegerType::get(getLLVMContext(), 8);
diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h
index f447549f669c..2ff602f900fa 100644
--- a/lib/CodeGen/CodeGenTypes.h
+++ b/lib/CodeGen/CodeGenTypes.h
@@ -20,6 +20,7 @@
#include <vector>
#include "CGCall.h"
+#include "CGCXX.h"
namespace llvm {
class FunctionType;
@@ -34,6 +35,8 @@ namespace llvm {
namespace clang {
class ABIInfo;
class ASTContext;
+ class CXXConstructorDecl;
+ class CXXDestructorDecl;
class CXXMethodDecl;
class FieldDecl;
class FunctionProtoType;
@@ -61,17 +64,9 @@ namespace CodeGen {
/// is a member pointer, or a struct that contains a member pointer.
bool ContainsMemberPointer;
- /// KeyFunction - The key function of the record layout (if one exists),
- /// which is the first non-pure virtual function that is not inline at the
- /// point of class definition.
- /// See http://www.codesourcery.com/public/cxx-abi/abi.html#vague-vtable.
- const CXXMethodDecl *KeyFunction;
-
public:
- CGRecordLayout(const llvm::Type *T, bool ContainsMemberPointer,
- const CXXMethodDecl *KeyFunction)
- : LLVMType(T), ContainsMemberPointer(ContainsMemberPointer),
- KeyFunction(KeyFunction) { }
+ CGRecordLayout(const llvm::Type *T, bool ContainsMemberPointer)
+ : LLVMType(T), ContainsMemberPointer(ContainsMemberPointer) { }
/// getLLVMType - Return llvm type associated with this record.
const llvm::Type *getLLVMType() const {
@@ -81,10 +76,6 @@ namespace CodeGen {
bool containsMemberPointer() const {
return ContainsMemberPointer;
}
-
- const CXXMethodDecl *getKeyFunction() const {
- return KeyFunction;
- }
};
/// CodeGenTypes - This class organizes the cross-module state that is used
@@ -173,6 +164,12 @@ public:
const llvm::FunctionType *GetFunctionType(const CGFunctionInfo &Info,
bool IsVariadic);
+
+ /// GetFunctionTypeForVtable - Get the LLVM function type for use in a vtable,
+ /// given a CXXMethodDecl. If the method to has an incomplete return type,
+ /// and/or incomplete argument types, this will return the opaque type.
+ const llvm::Type *GetFunctionTypeForVtable(const CXXMethodDecl *MD);
+
const CGRecordLayout &getCGRecordLayout(const TagDecl*) const;
/// getLLVMFieldNo - Return llvm::StructType element number
@@ -192,7 +189,11 @@ public:
const CGFunctionInfo &getFunctionInfo(const FunctionDecl *FD);
const CGFunctionInfo &getFunctionInfo(const CXXMethodDecl *MD);
const CGFunctionInfo &getFunctionInfo(const ObjCMethodDecl *MD);
-
+ const CGFunctionInfo &getFunctionInfo(const CXXConstructorDecl *D,
+ CXXCtorType Type);
+ const CGFunctionInfo &getFunctionInfo(const CXXDestructorDecl *D,
+ CXXDtorType Type);
+
// getFunctionInfo - Get the function info for a member function.
const CGFunctionInfo &getFunctionInfo(const CXXRecordDecl *RD,
const FunctionProtoType *FTP);
diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp
index 0a7124de3621..d6f7808c4073 100644
--- a/lib/CodeGen/Mangle.cpp
+++ b/lib/CodeGen/Mangle.cpp
@@ -23,100 +23,111 @@
#include "clang/AST/ExprCXX.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/StringExtras.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ErrorHandling.h"
+#include "CGVtable.h"
using namespace clang;
+using namespace CodeGen;
namespace {
- class VISIBILITY_HIDDEN CXXNameMangler {
- MangleContext &Context;
- llvm::raw_ostream &Out;
-
- const CXXMethodDecl *Structor;
- unsigned StructorType;
- CXXCtorType CtorType;
-
- llvm::DenseMap<uintptr_t, unsigned> Substitutions;
-
- public:
- CXXNameMangler(MangleContext &C, llvm::raw_ostream &os)
- : Context(C), Out(os), Structor(0), StructorType(0) { }
-
- bool mangle(const NamedDecl *D);
- void mangleCalloffset(int64_t nv, int64_t v);
- void mangleThunk(const FunctionDecl *FD, int64_t nv, int64_t v);
- void mangleCovariantThunk(const FunctionDecl *FD,
- int64_t nv_t, int64_t v_t,
- int64_t nv_r, int64_t v_r);
- void mangleGuardVariable(const VarDecl *D);
-
- 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);
-
- private:
- bool mangleSubstitution(const NamedDecl *ND);
- bool mangleSubstitution(QualType T);
- bool mangleSubstitution(uintptr_t Ptr);
-
- bool mangleStandardSubstitution(const NamedDecl *ND);
-
- void addSubstitution(const NamedDecl *ND) {
- ND = cast<NamedDecl>(ND->getCanonicalDecl());
+
+static const CXXMethodDecl *getStructor(const CXXMethodDecl *MD) {
+ assert((isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD)) &&
+ "Passed in decl is not a ctor or dtor!");
+
+ if (const TemplateDecl *TD = MD->getPrimaryTemplate()) {
+ MD = cast<CXXMethodDecl>(TD->getTemplatedDecl());
- addSubstitution(reinterpret_cast<uintptr_t>(ND));
- }
- void addSubstitution(QualType T);
- void addSubstitution(uintptr_t Ptr);
+ assert((isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD)) &&
+ "Templated decl is not a ctor or dtor!");
+ }
- bool mangleFunctionDecl(const FunctionDecl *FD);
-
- void mangleFunctionEncoding(const FunctionDecl *FD);
- void mangleName(const NamedDecl *ND);
- void mangleName(const TemplateDecl *TD,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs);
- void mangleUnqualifiedName(const NamedDecl *ND);
- void mangleUnscopedName(const NamedDecl *ND);
- void mangleUnscopedTemplateName(const TemplateDecl *ND);
- void mangleSourceName(const IdentifierInfo *II);
- void mangleLocalName(const NamedDecl *ND);
- void mangleNestedName(const NamedDecl *ND);
- void mangleNestedName(const TemplateDecl *TD,
- const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs);
- void manglePrefix(const DeclContext *DC);
- void mangleTemplatePrefix(const TemplateDecl *ND);
- void mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity);
- void mangleQualifiers(Qualifiers Quals);
- void mangleType(QualType T);
-
- // Declare manglers for every type class.
+ return MD;
+}
+
+/// CXXNameMangler - Manage the mangling of a single name.
+class CXXNameMangler {
+ MangleContext &Context;
+ llvm::raw_svector_ostream Out;
+
+ const CXXMethodDecl *Structor;
+ unsigned StructorType;
+
+ llvm::DenseMap<uintptr_t, unsigned> Substitutions;
+
+public:
+ CXXNameMangler(MangleContext &C, llvm::SmallVectorImpl<char> &Res)
+ : Context(C), Out(Res), Structor(0), StructorType(0) { }
+ CXXNameMangler(MangleContext &C, llvm::SmallVectorImpl<char> &Res,
+ const CXXConstructorDecl *D, CXXCtorType Type)
+ : Context(C), Out(Res), Structor(getStructor(D)), StructorType(Type) { }
+ CXXNameMangler(MangleContext &C, llvm::SmallVectorImpl<char> &Res,
+ const CXXDestructorDecl *D, CXXDtorType Type)
+ : Context(C), Out(Res), Structor(getStructor(D)), StructorType(Type) { }
+
+ llvm::raw_svector_ostream &getStream() { return Out; }
+
+ void mangle(const NamedDecl *D, llvm::StringRef Prefix = "_Z");
+ void mangleCallOffset(const ThunkAdjustment &Adjustment);
+ void mangleNumber(int64_t Number);
+ void mangleFunctionEncoding(const FunctionDecl *FD);
+ void mangleName(const NamedDecl *ND);
+ void mangleType(QualType T);
+
+private:
+ bool mangleSubstitution(const NamedDecl *ND);
+ bool mangleSubstitution(QualType T);
+ bool mangleSubstitution(uintptr_t Ptr);
+
+ 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);
+ void addSubstitution(uintptr_t Ptr);
+
+ bool mangleFunctionDecl(const FunctionDecl *FD);
+
+ void mangleName(const TemplateDecl *TD,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs);
+ void mangleUnqualifiedName(const NamedDecl *ND);
+ void mangleUnscopedName(const NamedDecl *ND);
+ void mangleUnscopedTemplateName(const TemplateDecl *ND);
+ void mangleSourceName(const IdentifierInfo *II);
+ void mangleLocalName(const NamedDecl *ND);
+ void mangleNestedName(const NamedDecl *ND);
+ void mangleNestedName(const TemplateDecl *TD,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs);
+ void manglePrefix(const DeclContext *DC);
+ void mangleTemplatePrefix(const TemplateDecl *ND);
+ void mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity);
+ void mangleQualifiers(Qualifiers Quals);
+
+ // Declare manglers for every type class.
#define ABSTRACT_TYPE(CLASS, PARENT)
#define NON_CANONICAL_TYPE(CLASS, PARENT)
#define TYPE(CLASS, PARENT) void mangleType(const CLASS##Type *T);
#include "clang/AST/TypeNodes.def"
- void mangleType(const TagType*);
- void mangleBareFunctionType(const FunctionType *T,
- bool MangleReturnType);
- void mangleExpression(const Expr *E);
- void mangleCXXCtorType(CXXCtorType T);
- void mangleCXXDtorType(CXXDtorType T);
-
- void mangleTemplateArgs(const TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs);
- void mangleTemplateArgumentList(const TemplateArgumentList &L);
- void mangleTemplateArgument(const TemplateArgument &A);
-
- void mangleTemplateParameter(unsigned Index);
- };
+ void mangleType(const TagType*);
+ void mangleBareFunctionType(const FunctionType *T,
+ bool MangleReturnType);
+ void mangleExpression(const Expr *E);
+ void mangleCXXCtorType(CXXCtorType T);
+ void mangleCXXDtorType(CXXDtorType T);
+
+ void mangleTemplateArgs(const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs);
+ void mangleTemplateArgumentList(const TemplateArgumentList &L);
+ void mangleTemplateArgument(const TemplateArgument &A);
+
+ void mangleTemplateParameter(unsigned Index);
+};
}
static bool isInCLinkageSpecification(const Decl *D) {
@@ -130,132 +141,72 @@ static bool isInCLinkageSpecification(const Decl *D) {
return false;
}
-bool CXXNameMangler::mangleFunctionDecl(const FunctionDecl *FD) {
+bool MangleContext::shouldMangleDeclName(const NamedDecl *D) {
+ // In C, functions with no attributes never need to be mangled. Fastpath them.
+ if (!getASTContext().getLangOptions().CPlusPlus && !D->hasAttrs())
+ return false;
+
+ // Any decl can be declared with __asm("foo") on it, and this takes precedence
+ // over all other naming in the .o file.
+ if (D->hasAttr<AsmLabelAttr>())
+ return true;
+
// Clang's "overloadable" attribute extension to C/C++ implies name mangling
// (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;
+ const FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
+ if (FD && (FD->hasAttr<OverloadableAttr>() || isa<CXXMethodDecl>(FD) ||
+ !FD->getDeclName().isIdentifier()))
+ return true;
- // No mangling in an "implicit extern C" header.
- if (FD->getLocation().isValid() &&
- Context.getASTContext().getSourceManager().
- isInExternCSystemHeader(FD->getLocation()))
- return false;
+ // Otherwise, no mangling is done outside C++ mode.
+ if (!getASTContext().getLangOptions().CPlusPlus)
+ return false;
- // No name mangling in a C linkage specification.
- if (isInCLinkageSpecification(FD))
- return false;
- }
+ // No mangling in an "implicit extern C" header.
+ if (D->getLocation().isValid() &&
+ getASTContext().getSourceManager().
+ isInExternCSystemHeader(D->getLocation()))
+ return false;
+
+ // C functions, "main", and variables at global scope are not
+ // mangled.
+ if ((FD && FD->isMain()) ||
+ (!FD && D->getDeclContext()->isTranslationUnit()) ||
+ isInCLinkageSpecification(D))
+ return false;
- // If we get here, mangle the decl name!
- Out << "_Z";
- mangleFunctionEncoding(FD);
return true;
}
-bool CXXNameMangler::mangle(const NamedDecl *D) {
+void CXXNameMangler::mangle(const NamedDecl *D, llvm::StringRef Prefix) {
// Any decl can be declared with __asm("foo") on it, and this takes precedence
// over all other naming in the .o file.
if (const AsmLabelAttr *ALA = D->getAttr<AsmLabelAttr>()) {
// If we have an asm name, then we use it as the mangling.
Out << '\01'; // LLVM IR Marker for __asm("foo")
Out << ALA->getLabel();
- return true;
+ return;
}
// <mangled-name> ::= _Z <encoding>
// ::= <data name>
// ::= <special-name>
-
- // FIXME: Actually use a visitor to decode these?
+ Out << Prefix;
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
- return mangleFunctionDecl(FD);
-
- if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
- if (!Context.getASTContext().getLangOptions().CPlusPlus ||
- isInCLinkageSpecification(D) ||
- D->getDeclContext()->isTranslationUnit())
- return false;
-
- Out << "_Z";
- mangleName(VD);
- return true;
- }
-
- return false;
-}
-
-void CXXNameMangler::mangleCXXCtor(const CXXConstructorDecl *D,
- CXXCtorType Type) {
- assert(!Structor && "Structor already set!");
- Structor = D;
- StructorType = Type;
-
- mangle(D);
-}
-
-void CXXNameMangler::mangleCXXDtor(const CXXDestructorDecl *D,
- CXXDtorType Type) {
- assert(!Structor && "Structor already set!");
- Structor = D;
- StructorType = Type;
-
- mangle(D);
-}
-
-void CXXNameMangler::mangleCXXVtable(const CXXRecordDecl *RD) {
- // <special-name> ::= TV <type> # virtual table
- Out << "_ZTV";
- mangleName(RD);
-}
-
-void CXXNameMangler::mangleCXXVTT(const CXXRecordDecl *RD) {
- // <special-name> ::= TT <type> # VTT structure
- Out << "_ZTT";
- 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";
-
- 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
-
- Out << "_ZGV";
- mangleName(D);
+ mangleFunctionEncoding(FD);
+ else
+ mangleName(cast<VarDecl>(D));
}
void CXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) {
// <encoding> ::= <function name> <bare-function-type>
mangleName(FD);
+ // Don't mangle in the type if this isn't a decl we should typically mangle.
+ if (!Context.shouldMangleDeclName(FD))
+ return;
+
// Whether the mangling of a function type includes the return type depends on
// the context and the nature of the function. The rules for deciding whether
// the return type is included are:
@@ -277,7 +228,7 @@ void CXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) {
if (!(isa<CXXConstructorDecl>(FD) || isa<CXXDestructorDecl>(FD) ||
isa<CXXConversionDecl>(FD)))
MangleReturnType = true;
-
+
// Mangle the type of the primary template.
FD = PrimaryTemplate->getTemplatedDecl();
}
@@ -290,15 +241,16 @@ void CXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) {
mangleBareFunctionType(FT, MangleReturnType);
}
-static bool isStdNamespace(const DeclContext *DC) {
- if (!DC->isNamespace() || !DC->getParent()->isTranslationUnit())
- return false;
-
- const NamespaceDecl *NS = cast<NamespaceDecl>(DC);
+static bool isStdNamespace(const NamespaceDecl *NS) {
const IdentifierInfo *II = NS->getOriginalNamespace()->getIdentifier();
return II && II->isStr("std");
}
+static bool isStdNamespace(const DeclContext *DC) {
+ return DC->isNamespace() && DC->getParent()->isTranslationUnit() &&
+ isStdNamespace(cast<NamespaceDecl>(DC));
+}
+
static const TemplateDecl *
isTemplate(const NamedDecl *ND, const TemplateArgumentList *&TemplateArgs) {
// Check if we have a function template.
@@ -315,7 +267,7 @@ isTemplate(const NamedDecl *ND, const TemplateArgumentList *&TemplateArgs) {
TemplateArgs = &Spec->getTemplateArgs();
return Spec->getSpecializedTemplate();
}
-
+
return 0;
}
@@ -328,7 +280,7 @@ void CXXNameMangler::mangleName(const NamedDecl *ND) {
const DeclContext *DC = ND->getDeclContext();
while (isa<LinkageSpecDecl>(DC))
DC = DC->getParent();
-
+
if (DC->isTranslationUnit() || isStdNamespace(DC)) {
// Check if we have a template.
const TemplateArgumentList *TemplateArgs = 0;
@@ -341,24 +293,24 @@ void CXXNameMangler::mangleName(const NamedDecl *ND) {
mangleUnscopedName(ND);
return;
}
-
+
if (isa<FunctionDecl>(DC)) {
mangleLocalName(ND);
return;
}
-
+
mangleNestedName(ND);
}
-void CXXNameMangler::mangleName(const TemplateDecl *TD,
+void CXXNameMangler::mangleName(const TemplateDecl *TD,
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs) {
const DeclContext *DC = TD->getDeclContext();
while (isa<LinkageSpecDecl>(DC)) {
- assert(cast<LinkageSpecDecl>(DC)->getLanguage() ==
+ assert(cast<LinkageSpecDecl>(DC)->getLanguage() ==
LinkageSpecDecl::lang_cxx && "Unexpected linkage decl!");
DC = DC->getParent();
}
-
+
if (DC->isTranslationUnit() || isStdNamespace(DC)) {
mangleUnscopedTemplateName(TD);
mangleTemplateArgs(TemplateArgs, NumTemplateArgs);
@@ -372,7 +324,7 @@ void CXXNameMangler::mangleUnscopedName(const NamedDecl *ND) {
// ::= St <unqualified-name> # ::std::
if (isStdNamespace(ND->getDeclContext()))
Out << "St";
-
+
mangleUnqualifiedName(ND);
}
@@ -381,61 +333,39 @@ void CXXNameMangler::mangleUnscopedTemplateName(const TemplateDecl *ND) {
// ::= <substitution>
if (mangleSubstitution(ND))
return;
-
+
mangleUnscopedName(ND->getTemplatedDecl());
addSubstitution(ND);
}
-void CXXNameMangler::mangleCalloffset(int64_t nv, int64_t v) {
+void CXXNameMangler::mangleNumber(int64_t Number) {
+ // <number> ::= [n] <non-negative decimal integer>
+ if (Number < 0) {
+ Out << 'n';
+ Number = -Number;
+ }
+
+ Out << Number;
+}
+
+void CXXNameMangler::mangleCallOffset(const ThunkAdjustment &Adjustment) {
// <call-offset> ::= h <nv-offset> _
// ::= v <v-offset> _
// <nv-offset> ::= <offset number> # non-virtual base override
- // <v-offset> ::= <offset nubmer> _ <virtual offset number>
+ // <v-offset> ::= <offset number> _ <virtual offset number>
// # virtual base override, with vcall offset
- if (v == 0) {
- Out << "h";
- if (nv < 0) {
- Out << "n";
- nv = -nv;
- }
- Out << nv;
- } else {
- Out << "v";
- if (nv < 0) {
- Out << "n";
- nv = -nv;
- }
- Out << nv;
- Out << "_";
- if (v < 0) {
- Out << "n";
- v = -v;
- }
- Out << v;
+ if (!Adjustment.Virtual) {
+ Out << 'h';
+ mangleNumber(Adjustment.NonVirtual);
+ Out << '_';
+ return;
}
- Out << "_";
-}
-
-void CXXNameMangler::mangleThunk(const FunctionDecl *FD, int64_t nv,
- int64_t v) {
- // <special-name> ::= T <call-offset> <base encoding>
- // # base is the nominal target function of thunk
- Out << "_ZT";
- mangleCalloffset(nv, v);
- mangleFunctionEncoding(FD);
-}
-
- void CXXNameMangler::mangleCovariantThunk(const FunctionDecl *FD,
- int64_t nv_t, int64_t v_t,
- int64_t nv_r, int64_t v_r) {
- // <special-name> ::= Tc <call-offset> <call-offset> <base encoding>
- // # base is the nominal target function of thunk
- // # first call-offset is 'this' adjustment
- // # second call-offset is result adjustment
- Out << "_ZTc";
- mangleCalloffset(nv_t, v_t);
- mangleCalloffset(nv_r, v_r);
- mangleFunctionEncoding(FD);
+
+ Out << 'v';
+ mangleNumber(Adjustment.NonVirtual);
+ Out << '_';
+ mangleNumber(Adjustment.Virtual);
+ Out << '_';
}
void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND) {
@@ -453,13 +383,13 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND) {
Out << "12_GLOBAL__N_1";
break;
}
- }
+ }
if (const IdentifierInfo *II = Name.getAsIdentifierInfo()) {
mangleSourceName(II);
break;
}
-
+
// We must have an anonymous struct.
const TagDecl *TD = cast<TagDecl>(ND);
if (const TypedefDecl *D = TD->getTypedefForAnonDecl()) {
@@ -470,12 +400,12 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND) {
mangleSourceName(D->getDeclName().getAsIdentifierInfo());
break;
}
-
+
// Get a unique id for the anonymous struct.
uint64_t AnonStructId = Context.getAnonymousStructId(TD);
// Mangle it as a source name in the form
- // [n] $_<id>
+ // [n] $_<id>
// where n is the length of the string.
llvm::SmallString<8> Str;
Str += "$_";
@@ -525,6 +455,12 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND) {
cast<FunctionDecl>(ND)->getNumParams());
break;
+ case DeclarationName::CXXLiteralOperatorName:
+ // Guessing based on existing ABI.
+ Out << "ul";
+ mangleSourceName(Name.getCXXLiteralIdentifier());
+ break;
+
case DeclarationName::CXXUsingDirective:
assert(false && "Can't mangle a using directive name!");
break;
@@ -545,29 +481,29 @@ void CXXNameMangler::mangleNestedName(const NamedDecl *ND) {
Out << 'N';
if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(ND))
mangleQualifiers(Qualifiers::fromCVRMask(Method->getTypeQualifiers()));
-
+
// Check if we have a template.
const TemplateArgumentList *TemplateArgs = 0;
- if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) {
+ if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) {
mangleTemplatePrefix(TD);
mangleTemplateArgumentList(*TemplateArgs);
} else {
manglePrefix(ND->getDeclContext());
mangleUnqualifiedName(ND);
}
-
+
Out << 'E';
}
-void CXXNameMangler::mangleNestedName(const TemplateDecl *TD,
+void CXXNameMangler::mangleNestedName(const TemplateDecl *TD,
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs) {
// <nested-name> ::= N [<CV-qualifiers>] <template-prefix> <template-args> E
Out << 'N';
-
+
mangleTemplatePrefix(TD);
mangleTemplateArgs(TemplateArgs, NumTemplateArgs);
-
+
Out << 'E';
}
@@ -591,23 +527,23 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC) {
while (isa<LinkageSpecDecl>(DC))
DC = DC->getParent();
-
+
if (DC->isTranslationUnit())
return;
-
+
if (mangleSubstitution(cast<NamedDecl>(DC)))
return;
// Check if we have a template.
const TemplateArgumentList *TemplateArgs = 0;
- if (const TemplateDecl *TD = isTemplate(cast<NamedDecl>(DC), TemplateArgs)) {
+ if (const TemplateDecl *TD = isTemplate(cast<NamedDecl>(DC), TemplateArgs)) {
mangleTemplatePrefix(TD);
mangleTemplateArgumentList(*TemplateArgs);
} else {
manglePrefix(DC->getParent());
mangleUnqualifiedName(cast<NamedDecl>(DC));
}
-
+
addSubstitution(cast<NamedDecl>(DC));
}
@@ -618,12 +554,12 @@ void CXXNameMangler::mangleTemplatePrefix(const TemplateDecl *ND) {
if (mangleSubstitution(ND))
return;
-
+
// FIXME: <template-param>
-
+
manglePrefix(ND->getDeclContext());
mangleUnqualifiedName(ND->getTemplatedDecl());
-
+
addSubstitution(ND);
}
@@ -838,6 +774,7 @@ void CXXNameMangler::mangleType(const BuiltinType *T) {
break;
case BuiltinType::ObjCId: Out << "11objc_object"; break;
case BuiltinType::ObjCClass: Out << "10objc_class"; break;
+ case BuiltinType::ObjCSel: Out << "13objc_selector"; break;
}
}
@@ -992,7 +929,7 @@ void CXXNameMangler::mangleType(const FixedWidthIntType *T) {
void CXXNameMangler::mangleType(const TemplateSpecializationType *T) {
TemplateDecl *TD = T->getTemplateName().getAsTemplateDecl();
assert(TD && "FIXME: Support dependent template names!");
-
+
mangleName(TD, T->getArgs(), T->getNumArgs());
}
@@ -1001,7 +938,7 @@ void CXXNameMangler::mangleType(const TypenameType *T) {
Out << 'N';
const Type *QTy = T->getQualifier()->getAsType();
- if (const TemplateSpecializationType *TST =
+ if (const TemplateSpecializationType *TST =
dyn_cast<TemplateSpecializationType>(QTy)) {
if (!mangleSubstitution(QualType(TST, 0))) {
TemplateDecl *TD = TST->getTemplateName().getAsTemplateDecl();
@@ -1010,7 +947,7 @@ void CXXNameMangler::mangleType(const TypenameType *T) {
mangleTemplateArgs(TST->getArgs(), TST->getNumArgs());
addSubstitution(QualType(TST, 0));
}
- } else if (const TemplateTypeParmType *TTPT =
+ } else if (const TemplateTypeParmType *TTPT =
dyn_cast<TemplateTypeParmType>(QTy)) {
// We use the QualType mangle type variant here because it handles
// substitutions.
@@ -1019,7 +956,7 @@ void CXXNameMangler::mangleType(const TypenameType *T) {
assert(false && "Unhandled type!");
mangleSourceName(T->getIdentifier());
-
+
Out << 'E';
}
@@ -1047,7 +984,7 @@ void CXXNameMangler::mangleExpression(const Expr *E) {
case Expr::DeclRefExprClass: {
const Decl *D = cast<DeclRefExpr>(E)->getDecl();
-
+
switch (D->getKind()) {
default: assert(false && "Unhandled decl kind!");
case Decl::NonTypeTemplateParm: {
@@ -1057,23 +994,23 @@ void CXXNameMangler::mangleExpression(const Expr *E) {
}
}
-
+
break;
}
-
- case Expr::UnresolvedDeclRefExprClass: {
- const UnresolvedDeclRefExpr *DRE = cast<UnresolvedDeclRefExpr>(E);
+
+ case Expr::DependentScopeDeclRefExprClass: {
+ const DependentScopeDeclRefExpr *DRE = cast<DependentScopeDeclRefExpr>(E);
const Type *QTy = DRE->getQualifier()->getAsType();
assert(QTy && "Qualifier was not type!");
// ::= sr <type> <unqualified-name> # dependent name
Out << "sr";
mangleType(QualType(QTy, 0));
-
+
assert(DRE->getDeclName().getNameKind() == DeclarationName::Identifier &&
"Unhandled decl name kind!");
mangleSourceName(DRE->getDeclName().getAsIdentifierInfo());
-
+
break;
}
@@ -1122,13 +1059,8 @@ void CXXNameMangler::mangleCXXDtorType(CXXDtorType T) {
void CXXNameMangler::mangleTemplateArgumentList(const TemplateArgumentList &L) {
// <template-args> ::= I <template-arg>+ E
Out << "I";
-
- for (unsigned i = 0, e = L.size(); i != e; ++i) {
- const TemplateArgument &A = L[i];
-
- mangleTemplateArgument(A);
- }
-
+ for (unsigned i = 0, e = L.size(); i != e; ++i)
+ mangleTemplateArgument(L[i]);
Out << "E";
}
@@ -1136,11 +1068,8 @@ void CXXNameMangler::mangleTemplateArgs(const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs) {
// <template-args> ::= I <template-arg>+ E
Out << "I";
-
- for (unsigned i = 0; i != NumTemplateArgs; ++i) {
+ for (unsigned i = 0; i != NumTemplateArgs; ++i)
mangleTemplateArgument(TemplateArgs[i]);
- }
-
Out << "E";
}
@@ -1161,14 +1090,12 @@ void CXXNameMangler::mangleTemplateArgument(const TemplateArgument &A) {
mangleExpression(A.getAsExpr());
Out << 'E';
break;
- case TemplateArgument::Integral:
+ case TemplateArgument::Integral: {
// <expr-primary> ::= L <type> <value number> E # integer literal
+ const llvm::APSInt *Integral = A.getAsIntegral();
Out << 'L';
-
mangleType(A.getIntegralType());
-
- const llvm::APSInt *Integral = A.getAsIntegral();
if (A.getIntegralType()->isBooleanType()) {
// Boolean values are encoded as 0/1.
Out << (Integral->getBoolValue() ? '1' : '0');
@@ -1177,10 +1104,27 @@ void CXXNameMangler::mangleTemplateArgument(const TemplateArgument &A) {
Out << 'n';
Integral->abs().print(Out, false);
}
+ Out << 'E';
+ break;
+ }
+ case TemplateArgument::Declaration: {
+ // <expr-primary> ::= L <mangled-name> E # external name
+ // FIXME: Clang produces AST's where pointer-to-member-function expressions
+ // and pointer-to-function expressions are represented as a declaration not
+ // an expression; this is not how gcc represents them and this changes the
+ // mangling.
+ Out << 'L';
+ // References to external entities use the mangled name; if the name would
+ // not normally be manged then mangle it as unqualified.
+ //
+ // FIXME: The ABI specifies that external names here should have _Z, but
+ // gcc leaves this off.
+ mangle(cast<NamedDecl>(A.getAsDecl()), "Z");
Out << 'E';
break;
}
+ }
}
void CXXNameMangler::mangleTemplateParameter(unsigned Index) {
@@ -1198,7 +1142,7 @@ bool CXXNameMangler::mangleSubstitution(const NamedDecl *ND) {
// Try one of the standard substitutions first.
if (mangleStandardSubstitution(ND))
return true;
-
+
ND = cast<NamedDecl>(ND->getCanonicalDecl());
return mangleSubstitution(reinterpret_cast<uintptr_t>(ND));
}
@@ -1208,79 +1152,79 @@ bool CXXNameMangler::mangleSubstitution(QualType T) {
if (const RecordType *RT = T->getAs<RecordType>())
return mangleSubstitution(RT->getDecl());
}
-
+
uintptr_t TypePtr = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr());
return mangleSubstitution(TypePtr);
}
bool CXXNameMangler::mangleSubstitution(uintptr_t Ptr) {
- llvm::DenseMap<uintptr_t, unsigned>::iterator I =
+ llvm::DenseMap<uintptr_t, unsigned>::iterator I =
Substitutions.find(Ptr);
if (I == Substitutions.end())
return false;
-
+
unsigned SeqID = I->second;
if (SeqID == 0)
Out << "S_";
else {
SeqID--;
-
+
// <seq-id> is encoded in base-36, using digits and upper case letters.
char Buffer[10];
char *BufferPtr = Buffer + 9;
-
+
*BufferPtr = 0;
if (SeqID == 0) *--BufferPtr = '0';
-
+
while (SeqID) {
assert(BufferPtr > Buffer && "Buffer overflow!");
-
+
unsigned char c = static_cast<unsigned char>(SeqID) % 36;
-
+
*--BufferPtr = (c < 10 ? '0' + c : 'A' + c - 10);
SeqID /= 36;
}
-
+
Out << 'S' << BufferPtr << '_';
}
-
+
return true;
}
static bool isCharType(QualType T) {
if (T.isNull())
return false;
-
+
return T->isSpecificBuiltinType(BuiltinType::Char_S) ||
T->isSpecificBuiltinType(BuiltinType::Char_U);
}
-/// isCharSpecialization - Returns whether a given type is a template
+/// isCharSpecialization - Returns whether a given type is a template
/// specialization of a given name with a single argument of type char.
static bool isCharSpecialization(QualType T, const char *Name) {
if (T.isNull())
return false;
-
+
const RecordType *RT = T->getAs<RecordType>();
if (!RT)
return false;
-
- const ClassTemplateSpecializationDecl *SD =
+
+ const ClassTemplateSpecializationDecl *SD =
dyn_cast<ClassTemplateSpecializationDecl>(RT->getDecl());
if (!SD)
return false;
if (!isStdNamespace(SD->getDeclContext()))
return false;
-
+
const TemplateArgumentList &TemplateArgs = SD->getTemplateArgs();
if (TemplateArgs.size() != 1)
return false;
-
+
if (!isCharType(TemplateArgs[0].getAsType()))
return false;
-
+
return SD->getIdentifier()->getName() == Name;
}
@@ -1298,55 +1242,55 @@ bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) {
if (const ClassTemplateDecl *TD = dyn_cast<ClassTemplateDecl>(ND)) {
if (!isStdNamespace(TD->getDeclContext()))
return false;
-
+
// <substitution> ::= Sa # ::std::allocator
if (TD->getIdentifier()->isStr("allocator")) {
Out << "Sa";
return true;
}
-
+
// <<substitution> ::= Sb # ::std::basic_string
if (TD->getIdentifier()->isStr("basic_string")) {
Out << "Sb";
return true;
}
}
-
- if (const ClassTemplateSpecializationDecl *SD =
+
+ if (const ClassTemplateSpecializationDecl *SD =
dyn_cast<ClassTemplateSpecializationDecl>(ND)) {
// <substitution> ::= Ss # ::std::basic_string<char,
// ::std::char_traits<char>,
// ::std::allocator<char> >
if (SD->getIdentifier()->isStr("basic_string")) {
const TemplateArgumentList &TemplateArgs = SD->getTemplateArgs();
-
+
if (TemplateArgs.size() != 3)
return false;
-
+
if (!isCharType(TemplateArgs[0].getAsType()))
return false;
-
+
if (!isCharSpecialization(TemplateArgs[1].getAsType(), "char_traits"))
return false;
-
+
if (!isCharSpecialization(TemplateArgs[2].getAsType(), "allocator"))
return false;
Out << "Ss";
return true;
}
-
- // <substitution> ::= So # ::std::basic_ostream<char,
+
+ // <substitution> ::= So # ::std::basic_ostream<char,
// ::std::char_traits<char> >
if (SD->getIdentifier()->isStr("basic_ostream")) {
const TemplateArgumentList &TemplateArgs = SD->getTemplateArgs();
-
+
if (TemplateArgs.size() != 2)
return false;
-
+
if (!isCharType(TemplateArgs[0].getAsType()))
return false;
-
+
if (!isCharSpecialization(TemplateArgs[1].getAsType(), "char_traits"))
return false;
@@ -1364,138 +1308,144 @@ void CXXNameMangler::addSubstitution(QualType T) {
return;
}
}
-
+
uintptr_t TypePtr = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr());
addSubstitution(TypePtr);
}
void CXXNameMangler::addSubstitution(uintptr_t Ptr) {
unsigned SeqID = Substitutions.size();
-
- assert(!Substitutions.count(Ptr) && "Substitution already exists!");
- Substitutions[Ptr] = SeqID;
-}
-
-namespace clang {
- /// \brief Mangles the name of the declaration D and emits that name to the
- /// given output stream.
- ///
- /// If the declaration D requires a mangled name, this routine will emit that
- /// mangled name to \p os and return true. Otherwise, \p os will be unchanged
- /// and this routine will return false. In this case, the caller should just
- /// emit the identifier of the declaration (\c D->getIdentifier()) as its
- /// name.
- bool mangleName(MangleContext &Context, const NamedDecl *D,
- llvm::raw_ostream &os) {
- assert(!isa<CXXConstructorDecl>(D) &&
- "Use mangleCXXCtor for constructor decls!");
- assert(!isa<CXXDestructorDecl>(D) &&
- "Use mangleCXXDtor for destructor decls!");
-
- PrettyStackTraceDecl CrashInfo(const_cast<NamedDecl *>(D), SourceLocation(),
- Context.getASTContext().getSourceManager(),
- "Mangling declaration");
-
- CXXNameMangler Mangler(Context, os);
- if (!Mangler.mangle(D))
- return false;
-
- os.flush();
- return true;
- }
-
- /// \brief Mangles the a thunk with the offset n for the declaration D and
- /// emits that name to the given output stream.
- void mangleThunk(MangleContext &Context, const FunctionDecl *FD,
- int64_t nv, int64_t v, llvm::raw_ostream &os) {
- // FIXME: Hum, we might have to thunk these, fix.
- assert(!isa<CXXDestructorDecl>(FD) &&
- "Use mangleCXXDtor for destructor decls!");
-
- CXXNameMangler Mangler(Context, os);
- Mangler.mangleThunk(FD, nv, v);
- os.flush();
- }
-
- /// \brief Mangles the a covariant thunk for the declaration D and emits that
- /// name to the given output stream.
- void mangleCovariantThunk(MangleContext &Context, const FunctionDecl *FD,
- int64_t nv_t, int64_t v_t,
- int64_t nv_r, int64_t v_r,
- llvm::raw_ostream &os) {
- // FIXME: Hum, we might have to thunk these, fix.
- assert(!isa<CXXDestructorDecl>(FD) &&
- "Use mangleCXXDtor for destructor decls!");
-
- CXXNameMangler Mangler(Context, os);
- Mangler.mangleCovariantThunk(FD, nv_t, v_t, nv_r, v_r);
- os.flush();
- }
-
- /// mangleGuardVariable - Returns the mangled name for a guard variable
- /// for the passed in VarDecl.
- void mangleGuardVariable(MangleContext &Context, const VarDecl *D,
- llvm::raw_ostream &os) {
- CXXNameMangler Mangler(Context, os);
- Mangler.mangleGuardVariable(D);
-
- os.flush();
- }
-
- void mangleCXXCtor(MangleContext &Context, const CXXConstructorDecl *D,
- CXXCtorType Type, llvm::raw_ostream &os) {
- CXXNameMangler Mangler(Context, os);
- Mangler.mangleCXXCtor(D, Type);
- os.flush();
- }
-
- void mangleCXXDtor(MangleContext &Context, const CXXDestructorDecl *D,
- CXXDtorType Type, llvm::raw_ostream &os) {
- CXXNameMangler Mangler(Context, os);
- Mangler.mangleCXXDtor(D, Type);
+ assert(!Substitutions.count(Ptr) && "Substitution already exists!");
+ Substitutions[Ptr] = SeqID;
+}
- os.flush();
- }
+//
- void mangleCXXVtable(MangleContext &Context, const CXXRecordDecl *RD,
- llvm::raw_ostream &os) {
- CXXNameMangler Mangler(Context, os);
- Mangler.mangleCXXVtable(RD);
+/// \brief Mangles the name of the declaration D and emits that name to the
+/// given output stream.
+///
+/// If the declaration D requires a mangled name, this routine will emit that
+/// mangled name to \p os and return true. Otherwise, \p os will be unchanged
+/// and this routine will return false. In this case, the caller should just
+/// emit the identifier of the declaration (\c D->getIdentifier()) as its
+/// name.
+void MangleContext::mangleName(const NamedDecl *D,
+ llvm::SmallVectorImpl<char> &Res) {
+ assert((isa<FunctionDecl>(D) || isa<VarDecl>(D)) &&
+ "Invalid mangleName() call, argument is not a variable or function!");
+ assert(!isa<CXXConstructorDecl>(D) && !isa<CXXDestructorDecl>(D) &&
+ "Invalid mangleName() call on 'structor decl!");
+
+ PrettyStackTraceDecl CrashInfo(D, SourceLocation(),
+ getASTContext().getSourceManager(),
+ "Mangling declaration");
+
+ CXXNameMangler Mangler(*this, Res);
+ return Mangler.mangle(D);
+}
+
+void MangleContext::mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type,
+ llvm::SmallVectorImpl<char> &Res) {
+ CXXNameMangler Mangler(*this, Res, D, Type);
+ Mangler.mangle(D);
+}
+
+void MangleContext::mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type,
+ llvm::SmallVectorImpl<char> &Res) {
+ CXXNameMangler Mangler(*this, Res, D, Type);
+ Mangler.mangle(D);
+}
+
+/// \brief Mangles the a thunk with the offset n for the declaration D and
+/// emits that name to the given output stream.
+void MangleContext::mangleThunk(const FunctionDecl *FD,
+ const ThunkAdjustment &ThisAdjustment,
+ llvm::SmallVectorImpl<char> &Res) {
+ // FIXME: Hum, we might have to thunk these, fix.
+ assert(!isa<CXXDestructorDecl>(FD) &&
+ "Use mangleCXXDtor for destructor decls!");
- os.flush();
- }
-
- void mangleCXXVTT(MangleContext &Context, const CXXRecordDecl *RD,
- llvm::raw_ostream &os) {
- CXXNameMangler Mangler(Context, os);
- Mangler.mangleCXXVTT(RD);
+ // <special-name> ::= T <call-offset> <base encoding>
+ // # base is the nominal target function of thunk
+ CXXNameMangler Mangler(*this, Res);
+ Mangler.getStream() << "_ZT";
+ Mangler.mangleCallOffset(ThisAdjustment);
+ Mangler.mangleFunctionEncoding(FD);
+}
+
+/// \brief Mangles the a covariant thunk for the declaration D and emits that
+/// name to the given output stream.
+void
+MangleContext::mangleCovariantThunk(const FunctionDecl *FD,
+ const CovariantThunkAdjustment& Adjustment,
+ llvm::SmallVectorImpl<char> &Res) {
+ // FIXME: Hum, we might have to thunk these, fix.
+ assert(!isa<CXXDestructorDecl>(FD) &&
+ "Use mangleCXXDtor for destructor decls!");
- os.flush();
- }
+ // <special-name> ::= Tc <call-offset> <call-offset> <base encoding>
+ // # base is the nominal target function of thunk
+ // # first call-offset is 'this' adjustment
+ // # second call-offset is result adjustment
+ CXXNameMangler Mangler(*this, Res);
+ Mangler.getStream() << "_ZTc";
+ Mangler.mangleCallOffset(Adjustment.ThisAdjustment);
+ Mangler.mangleCallOffset(Adjustment.ReturnAdjustment);
+ Mangler.mangleFunctionEncoding(FD);
+}
- 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);
+/// mangleGuardVariable - Returns the mangled name for a guard variable
+/// for the passed in VarDecl.
+void MangleContext::mangleGuardVariable(const VarDecl *D,
+ llvm::SmallVectorImpl<char> &Res) {
+ // <special-name> ::= GV <object name> # Guard variable for one-time
+ // # initialization
+ CXXNameMangler Mangler(*this, Res);
+ Mangler.getStream() << "_ZGV";
+ Mangler.mangleName(D);
+}
- os.flush();
- }
+void MangleContext::mangleCXXVtable(const CXXRecordDecl *RD,
+ llvm::SmallVectorImpl<char> &Res) {
+ // <special-name> ::= TV <type> # virtual table
+ CXXNameMangler Mangler(*this, Res);
+ Mangler.getStream() << "_ZTV";
+ Mangler.mangleName(RD);
+}
- void mangleCXXRtti(MangleContext &Context, QualType Ty,
- llvm::raw_ostream &os) {
- CXXNameMangler Mangler(Context, os);
- Mangler.mangleCXXRtti(Ty);
+void MangleContext::mangleCXXVTT(const CXXRecordDecl *RD,
+ llvm::SmallVectorImpl<char> &Res) {
+ // <special-name> ::= TT <type> # VTT structure
+ CXXNameMangler Mangler(*this, Res);
+ Mangler.getStream() << "_ZTT";
+ Mangler.mangleName(RD);
+}
- os.flush();
- }
+void MangleContext::mangleCXXCtorVtable(const CXXRecordDecl *RD, int64_t Offset,
+ const CXXRecordDecl *Type,
+ llvm::SmallVectorImpl<char> &Res) {
+ // <special-name> ::= TC <type> <offset number> _ <base type>
+ CXXNameMangler Mangler(*this, Res);
+ Mangler.getStream() << "_ZTC";
+ Mangler.mangleName(RD);
+ Mangler.getStream() << Offset;
+ Mangler.getStream() << "_";
+ Mangler.mangleName(Type);
+}
- void mangleCXXRttiName(MangleContext &Context, QualType Ty,
- llvm::raw_ostream &os) {
- CXXNameMangler Mangler(Context, os);
- Mangler.mangleCXXRttiName(Ty);
+void MangleContext::mangleCXXRtti(QualType Ty,
+ llvm::SmallVectorImpl<char> &Res) {
+ // <special-name> ::= TI <type> # typeinfo structure
+ CXXNameMangler Mangler(*this, Res);
+ Mangler.getStream() << "_ZTI";
+ Mangler.mangleType(Ty);
+}
- os.flush();
- }
+void MangleContext::mangleCXXRttiName(QualType Ty,
+ llvm::SmallVectorImpl<char> &Res) {
+ // <special-name> ::= TS <type> # typeinfo name (null terminated byte string)
+ CXXNameMangler Mangler(*this, Res);
+ Mangler.getStream() << "_ZTS";
+ Mangler.mangleType(Ty);
}
diff --git a/lib/CodeGen/Mangle.h b/lib/CodeGen/Mangle.h
index 458708fca6ad..65b1d9f9618d 100644
--- a/lib/CodeGen/Mangle.h
+++ b/lib/CodeGen/Mangle.h
@@ -23,7 +23,7 @@
#include "llvm/ADT/DenseMap.h"
namespace llvm {
- class raw_ostream;
+ template<typename T> class SmallVectorImpl;
}
namespace clang {
@@ -34,50 +34,59 @@ namespace clang {
class NamedDecl;
class VarDecl;
- class MangleContext {
- ASTContext &Context;
-
- llvm::DenseMap<const TagDecl *, uint64_t> AnonStructIds;
+namespace CodeGen {
+ class CovariantThunkAdjustment;
+ class ThunkAdjustment;
+
+/// MangleContext - Context for tracking state which persists across multiple
+/// calls to the C++ name mangler.
+class MangleContext {
+ ASTContext &Context;
- public:
- explicit MangleContext(ASTContext &Context)
+ llvm::DenseMap<const TagDecl *, uint64_t> AnonStructIds;
+
+public:
+ explicit MangleContext(ASTContext &Context)
: Context(Context) { }
-
- ASTContext &getASTContext() const { return Context; }
-
- uint64_t getAnonymousStructId(const TagDecl *TD) {
- std::pair<llvm::DenseMap<const TagDecl *,
- uint64_t>::iterator, bool> Result =
+
+ ASTContext &getASTContext() const { return Context; }
+
+ uint64_t getAnonymousStructId(const TagDecl *TD) {
+ std::pair<llvm::DenseMap<const TagDecl *,
+ uint64_t>::iterator, bool> Result =
AnonStructIds.insert(std::make_pair(TD, AnonStructIds.size()));
- return Result.first->second;
- }
- };
+ return Result.first->second;
+ }
+
+ /// @name Mangler Entry Points
+ /// @{
- bool mangleName(MangleContext &Context, const NamedDecl *D,
- llvm::raw_ostream &os);
- void mangleThunk(MangleContext &Context, const FunctionDecl *FD,
- int64_t n, int64_t vn, llvm::raw_ostream &os);
- void mangleCovariantThunk(MangleContext &Context, const FunctionDecl *FD,
- int64_t nv_t, int64_t v_t,
- int64_t nv_r, int64_t v_r,
- llvm::raw_ostream &os);
- void mangleGuardVariable(MangleContext &Context, const VarDecl *D,
- llvm::raw_ostream &os);
- void mangleCXXVtable(MangleContext &Context, const CXXRecordDecl *RD,
- 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,
- CXXDtorType Type, llvm::raw_ostream &os);
+ bool shouldMangleDeclName(const NamedDecl *D);
+
+ void mangleName(const NamedDecl *D, llvm::SmallVectorImpl<char> &);
+ void mangleThunk(const FunctionDecl *FD,
+ const ThunkAdjustment &ThisAdjustment,
+ llvm::SmallVectorImpl<char> &);
+ void mangleCovariantThunk(const FunctionDecl *FD,
+ const CovariantThunkAdjustment& Adjustment,
+ llvm::SmallVectorImpl<char> &);
+ void mangleGuardVariable(const VarDecl *D, llvm::SmallVectorImpl<char> &);
+ void mangleCXXVtable(const CXXRecordDecl *RD, llvm::SmallVectorImpl<char> &);
+ void mangleCXXVTT(const CXXRecordDecl *RD, llvm::SmallVectorImpl<char> &);
+ void mangleCXXCtorVtable(const CXXRecordDecl *RD, int64_t Offset,
+ const CXXRecordDecl *Type,
+ llvm::SmallVectorImpl<char> &);
+ void mangleCXXRtti(QualType T, llvm::SmallVectorImpl<char> &);
+ void mangleCXXRttiName(QualType T, llvm::SmallVectorImpl<char> &);
+ void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type,
+ llvm::SmallVectorImpl<char> &);
+ void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type,
+ llvm::SmallVectorImpl<char> &);
+
+ /// @}
+};
+
+}
}
#endif
diff --git a/lib/CodeGen/ModuleBuilder.cpp b/lib/CodeGen/ModuleBuilder.cpp
index 1d8f31dd9b24..017059df80fa 100644
--- a/lib/CodeGen/ModuleBuilder.cpp
+++ b/lib/CodeGen/ModuleBuilder.cpp
@@ -22,13 +22,11 @@
#include "llvm/LLVMContext.h"
#include "llvm/Module.h"
#include "llvm/Target/TargetData.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/ADT/OwningPtr.h"
using namespace clang;
-
namespace {
- class VISIBILITY_HIDDEN CodeGeneratorImpl : public CodeGenerator {
+ class CodeGeneratorImpl : public CodeGenerator {
Diagnostic &Diags;
llvm::OwningPtr<const llvm::TargetData> TD;
ASTContext *Ctx;
diff --git a/lib/CodeGen/TargetABIInfo.cpp b/lib/CodeGen/TargetABIInfo.cpp
index ba0bc6668e27..2bc61753a031 100644
--- a/lib/CodeGen/TargetABIInfo.cpp
+++ b/lib/CodeGen/TargetABIInfo.cpp
@@ -771,7 +771,7 @@ void X86_64ABIInfo::classify(QualType Ty,
// reference.
if (hasNonTrivialDestructorOrCopyConstructor(RT))
return;
-
+
const RecordDecl *RD = RT->getDecl();
// Assume variable sized types are passed in memory.
@@ -782,6 +782,32 @@ void X86_64ABIInfo::classify(QualType Ty,
// Reset Lo class, this will be recomputed.
Current = NoClass;
+
+ // If this is a C++ record, classify the bases first.
+ if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
+ for (CXXRecordDecl::base_class_const_iterator i = CXXRD->bases_begin(),
+ e = CXXRD->bases_end(); i != e; ++i) {
+ assert(!i->isVirtual() && !i->getType()->isDependentType() &&
+ "Unexpected base class!");
+ const CXXRecordDecl *Base =
+ cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
+
+ // Classify this field.
+ //
+ // AMD64-ABI 3.2.3p2: Rule 3. If the size of the aggregate exceeds a
+ // single eightbyte, each is classified separately. Each eightbyte gets
+ // initialized to class NO_CLASS.
+ Class FieldLo, FieldHi;
+ uint64_t Offset = OffsetBase + Layout.getBaseClassOffset(Base);
+ classify(i->getType(), Context, Offset, FieldLo, FieldHi);
+ Lo = merge(Lo, FieldLo);
+ Hi = merge(Hi, FieldHi);
+ if (Lo == Memory || Hi == Memory)
+ break;
+ }
+ }
+
+ // Classify the fields one at a time, merging the results.
unsigned idx = 0;
for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end();
i != e; ++i, ++idx) {
diff --git a/lib/Driver/ArgList.cpp b/lib/Driver/ArgList.cpp
index ea75c34ea566..8a57d14932d3 100644
--- a/lib/Driver/ArgList.cpp
+++ b/lib/Driver/ArgList.cpp
@@ -17,6 +17,23 @@
using namespace clang::driver;
+void arg_iterator::SkipToNextArg() {
+ for (; Current != Args.end(); ++Current) {
+ // Done if there are no filters.
+ if (!Id0.isValid())
+ break;
+
+ // Otherwise require a match.
+ const Option &O = (*Current)->getOption();
+ if (O.matches(Id0) ||
+ (Id1.isValid() && O.matches(Id1)) ||
+ (Id2.isValid() && O.matches(Id2)))
+ break;
+ }
+}
+
+//
+
ArgList::ArgList(arglist_type &_Args) : Args(_Args) {
}
@@ -98,95 +115,46 @@ void ArgList::AddLastArg(ArgStringList &Output, OptSpecifier Id) const {
}
}
-void ArgList::AddAllArgs(ArgStringList &Output, OptSpecifier Id0) const {
- // FIXME: Make fast.
- for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
- const Arg *A = *it;
- if (A->getOption().matches(Id0)) {
- A->claim();
- A->render(*this, Output);
- }
- }
-}
-
-void ArgList::AddAllArgs(ArgStringList &Output, OptSpecifier Id0,
- OptSpecifier Id1) const {
- // FIXME: Make fast.
- for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
- const Arg *A = *it;
- if (A->getOption().matches(Id0) || A->getOption().matches(Id1)) {
- A->claim();
- A->render(*this, Output);
- }
- }
-}
-
void ArgList::AddAllArgs(ArgStringList &Output, OptSpecifier Id0,
OptSpecifier Id1, OptSpecifier Id2) const {
- // FIXME: Make fast.
- for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
- const Arg *A = *it;
- if (A->getOption().matches(Id0) || A->getOption().matches(Id1) ||
- A->getOption().matches(Id2)) {
- A->claim();
- A->render(*this, Output);
- }
- }
-}
-
-void ArgList::AddAllArgValues(ArgStringList &Output, OptSpecifier Id0) const {
- // FIXME: Make fast.
- for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
- const Arg *A = *it;
- if (A->getOption().matches(Id0)) {
- A->claim();
- for (unsigned i = 0, e = A->getNumValues(); i != e; ++i)
- Output.push_back(A->getValue(*this, i));
- }
+ for (arg_iterator it = filtered_begin(Id0, Id1, Id2),
+ ie = filtered_end(); it != ie; ++it) {
+ it->claim();
+ it->render(*this, Output);
}
}
void ArgList::AddAllArgValues(ArgStringList &Output, OptSpecifier Id0,
- OptSpecifier Id1) const {
- // FIXME: Make fast.
- for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
- const Arg *A = *it;
- if (A->getOption().matches(Id0) || A->getOption().matches(Id1)) {
- A->claim();
- for (unsigned i = 0, e = A->getNumValues(); i != e; ++i)
- Output.push_back(A->getValue(*this, i));
- }
+ OptSpecifier Id1, OptSpecifier Id2) const {
+ for (arg_iterator it = filtered_begin(Id0, Id1, Id2),
+ ie = filtered_end(); it != ie; ++it) {
+ it->claim();
+ for (unsigned i = 0, e = it->getNumValues(); i != e; ++i)
+ Output.push_back(it->getValue(*this, i));
}
}
void ArgList::AddAllArgsTranslated(ArgStringList &Output, OptSpecifier Id0,
const char *Translation,
bool Joined) const {
- // FIXME: Make fast.
- for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
- const Arg *A = *it;
- if (A->getOption().matches(Id0)) {
- A->claim();
-
- if (Joined) {
- std::string Value = Translation;
- Value += A->getValue(*this, 0);
- Output.push_back(MakeArgString(Value.c_str()));
- } else {
- Output.push_back(Translation);
- Output.push_back(A->getValue(*this, 0));
- }
+ for (arg_iterator it = filtered_begin(Id0),
+ ie = filtered_end(); it != ie; ++it) {
+ it->claim();
+
+ if (Joined) {
+ Output.push_back(MakeArgString(llvm::StringRef(Translation) +
+ it->getValue(*this, 0)));
+ } else {
+ Output.push_back(Translation);
+ Output.push_back(it->getValue(*this, 0));
}
}
}
void ArgList::ClaimAllArgs(OptSpecifier Id0) const {
- // FIXME: Make fast.
- for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
- const Arg *A = *it;
- if (A->getOption().matches(Id0))
- A->claim();
- }
+ for (arg_iterator it = filtered_begin(Id0),
+ ie = filtered_end(); it != ie; ++it)
+ it->claim();
}
const char *ArgList::MakeArgString(const llvm::Twine &T) const {
diff --git a/lib/Driver/CC1Options.cpp b/lib/Driver/CC1Options.cpp
index 672fe0401e48..13f84c07df50 100644
--- a/lib/Driver/CC1Options.cpp
+++ b/lib/Driver/CC1Options.cpp
@@ -8,19 +8,14 @@
//===----------------------------------------------------------------------===//
#include "clang/Driver/CC1Options.h"
-#include "clang/Driver/OptTable.h"
#include "clang/Driver/Option.h"
-
+#include "clang/Driver/OptTable.h"
+using namespace clang;
using namespace clang::driver;
using namespace clang::driver::options;
using namespace clang::driver::cc1options;
static OptTable::Info CC1InfoTable[] = {
- // The InputOption info
- { "<input>", 0, 0, Option::InputClass, DriverOption, 0, OPT_INVALID, OPT_INVALID },
- // The UnknownOption info
- { "<unknown>", 0, 0, Option::UnknownClass, 0, 0, OPT_INVALID, OPT_INVALID },
-
#define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
HELPTEXT, METAVAR) \
{ NAME, HELPTEXT, METAVAR, Option::KIND##Class, FLAGS, PARAM, \
diff --git a/lib/Driver/Compilation.cpp b/lib/Driver/Compilation.cpp
index ffa627ad2810..b819cda89c09 100644
--- a/lib/Driver/Compilation.cpp
+++ b/lib/Driver/Compilation.cpp
@@ -85,9 +85,16 @@ bool Compilation::CleanupFileList(const ArgStringList &Files,
for (ArgStringList::const_iterator
it = Files.begin(), ie = Files.end(); it != ie; ++it) {
+
llvm::sys::Path P(*it);
std::string Error;
+ if (!P.isRegularFile()) {
+ // If we have a special file in our list, i.e. /dev/null
+ // then don't call eraseFromDisk() and just continue.
+ continue;
+ }
+
if (P.eraseFromDisk(false, &Error)) {
// Failure is only failure if the file doesn't exist. There is a
// race condition here due to the limited interface of
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index b40dc27740d0..87357cf08a3b 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -965,10 +965,9 @@ void Driver::BuildJobs(Compilation &C) const {
if (isa<FlagOption>(Opt)) {
bool DuplicateClaimed = false;
- // FIXME: Use iterator.
- for (ArgList::const_iterator it = C.getArgs().begin(),
- ie = C.getArgs().end(); it != ie; ++it) {
- if ((*it)->isClaimed() && (*it)->getOption().matches(&Opt)) {
+ for (arg_iterator it = C.getArgs().filtered_begin(&Opt),
+ ie = C.getArgs().filtered_end(); it != ie; ++it) {
+ if ((*it)->isClaimed()) {
DuplicateClaimed = true;
break;
}
diff --git a/lib/Driver/DriverOptions.cpp b/lib/Driver/DriverOptions.cpp
index eddaee0546cc..d1af95cd4504 100644
--- a/lib/Driver/DriverOptions.cpp
+++ b/lib/Driver/DriverOptions.cpp
@@ -15,11 +15,6 @@ using namespace clang::driver;
using namespace clang::driver::options;
static OptTable::Info InfoTable[] = {
- // The InputOption info
- { "<input>", 0, 0, Option::InputClass, DriverOption, 0, OPT_INVALID, OPT_INVALID },
- // The UnknownOption info
- { "<unknown>", 0, 0, Option::UnknownClass, 0, 0, OPT_INVALID, OPT_INVALID },
-
#define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
HELPTEXT, METAVAR) \
{ NAME, HELPTEXT, METAVAR, Option::KIND##Class, FLAGS, PARAM, \
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 5f0551b138ed..eb165cf6a531 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -130,13 +130,9 @@ void Clang::AddPreprocessingOptions(const Driver &D,
// wonky, but we include looking for .gch so we can support seamless
// replacement into a build system already set up to be generating
// .gch files.
- //
- // FIXME: Use iterator.
- for (ArgList::const_iterator
- it = Args.begin(), ie = Args.end(); it != ie; ++it) {
- const Arg *A = *it;
- if (!A->getOption().matches(options::OPT_clang_i_Group))
- continue;
+ for (arg_iterator it = Args.filtered_begin(options::OPT_clang_i_Group),
+ ie = Args.filtered_end(); it != ie; ++it) {
+ const Arg *A = it;
if (A->getOption().matches(options::OPT_include)) {
// Use PCH if the user requested it, except for C++ (for now).
@@ -209,7 +205,7 @@ void Clang::AddPreprocessingOptions(const Driver &D,
/// getARMTargetCPU - Get the (LLVM) name of the ARM cpu we are targetting.
//
// FIXME: tblgen this.
-static llvm::StringRef getARMTargetCPU(const ArgList &Args) {
+static const char *getARMTargetCPU(const ArgList &Args) {
// FIXME: Warn on inconsistent use of -mcpu and -march.
// If we have -mcpu=, use that.
@@ -370,7 +366,8 @@ void Clang::AddARMTargetArgs(const ArgList &Args,
CmdArgs.push_back(ABIName);
// Set the CPU based on -march= and -mcpu=.
- CmdArgs.push_back(Args.MakeArgString("-mcpu=" + getARMTargetCPU(Args)));
+ CmdArgs.push_back("-mcpu");
+ CmdArgs.push_back(getARMTargetCPU(Args));
// Select the float ABI as determined by -msoft-float, -mhard-float, and
// -mfloat-abi=.
@@ -421,15 +418,15 @@ void Clang::AddARMTargetArgs(const ArgList &Args,
// Floating point operations and argument passing are soft.
//
// FIXME: This changes CPP defines, we need -target-soft-float.
- CmdArgs.push_back("-soft-float");
- CmdArgs.push_back("-float-abi=soft");
+ CmdArgs.push_back("-msoft-float");
+ CmdArgs.push_back("-mfloat-abi=soft");
} else if (FloatABI == "softfp") {
// Floating point operations are hard, but argument passing is soft.
- CmdArgs.push_back("-float-abi=soft");
+ CmdArgs.push_back("-mfloat-abi=soft");
} else {
// Floating point operations and argument passing are hard.
assert(FloatABI == "hard" && "Invalid float abi!");
- CmdArgs.push_back("-float-abi=hard");
+ CmdArgs.push_back("-mfloat-abi=hard");
}
}
@@ -440,12 +437,12 @@ void Clang::AddX86TargetArgs(const ArgList &Args,
true) ||
Args.hasArg(options::OPT_mkernel) ||
Args.hasArg(options::OPT_fapple_kext))
- CmdArgs.push_back("--disable-red-zone");
+ CmdArgs.push_back("-disable-red-zone");
if (Args.hasFlag(options::OPT_msoft_float,
options::OPT_mno_soft_float,
false))
- CmdArgs.push_back("--no-implicit-float");
+ CmdArgs.push_back("-no-implicit-float");
const char *CPUName = 0;
if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
@@ -479,29 +476,25 @@ void Clang::AddX86TargetArgs(const ArgList &Args,
}
if (CPUName) {
- CmdArgs.push_back("--mcpu");
+ CmdArgs.push_back("-mcpu");
CmdArgs.push_back(CPUName);
}
- // FIXME: Use iterator.
- for (ArgList::const_iterator
- it = Args.begin(), ie = Args.end(); it != ie; ++it) {
- const Arg *A = *it;
- if (A->getOption().matches(options::OPT_m_x86_Features_Group)) {
- llvm::StringRef Name = A->getOption().getName();
+ for (arg_iterator it = Args.filtered_begin(options::OPT_m_x86_Features_Group),
+ ie = Args.filtered_end(); it != ie; ++it) {
+ llvm::StringRef Name = it->getOption().getName();
+ it->claim();
- // Skip over "-m".
- assert(Name.startswith("-m") && "Invalid feature name.");
- Name = Name.substr(2);
+ // Skip over "-m".
+ assert(Name.startswith("-m") && "Invalid feature name.");
+ Name = Name.substr(2);
- bool IsNegative = Name.startswith("no-");
- if (IsNegative)
- Name = Name.substr(3);
+ bool IsNegative = Name.startswith("no-");
+ if (IsNegative)
+ Name = Name.substr(3);
- A->claim();
- CmdArgs.push_back("-target-feature");
- CmdArgs.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name));
- }
+ CmdArgs.push_back("-target-feature");
+ CmdArgs.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name));
}
}
@@ -707,39 +700,42 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
else
Model = getToolChain().GetDefaultRelocationModel();
}
- CmdArgs.push_back("--relocation-model");
- CmdArgs.push_back(Model);
+ if (llvm::StringRef(Model) != "pic") {
+ CmdArgs.push_back("-mrelocation-model");
+ CmdArgs.push_back(Model);
+ }
// Infer the __PIC__ value.
//
// FIXME: This isn't quite right on Darwin, which always sets
// __PIC__=2.
if (strcmp(Model, "pic") == 0 || strcmp(Model, "dynamic-no-pic") == 0) {
- if (Args.hasArg(options::OPT_fPIC))
- CmdArgs.push_back("-pic-level=2");
- else
- CmdArgs.push_back("-pic-level=1");
+ CmdArgs.push_back("-pic-level");
+ CmdArgs.push_back(Args.hasArg(options::OPT_fPIC) ? "2" : "1");
}
+ if (!Args.hasFlag(options::OPT_fmerge_all_constants,
+ options::OPT_fno_merge_all_constants))
+ CmdArgs.push_back("-no-merge-all-constants");
+
+ // LLVM Code Generator Options.
- if (Args.hasArg(options::OPT_ftime_report))
- CmdArgs.push_back("--time-passes");
// FIXME: Set --enable-unsafe-fp-math.
if (Args.hasFlag(options::OPT_fno_omit_frame_pointer,
options::OPT_fomit_frame_pointer))
- CmdArgs.push_back("--disable-fp-elim");
+ CmdArgs.push_back("-mdisable-fp-elim");
if (!Args.hasFlag(options::OPT_fzero_initialized_in_bss,
- options::OPT_fno_zero_initialized_in_bss,
- true))
- CmdArgs.push_back("--nozero-initialized-in-bss");
+ options::OPT_fno_zero_initialized_in_bss))
+ CmdArgs.push_back("-mno-zero-initialized-in-bss");
if (Args.hasArg(options::OPT_dA) || Args.hasArg(options::OPT_fverbose_asm))
- CmdArgs.push_back("--asm-verbose");
- if (Args.hasArg(options::OPT_fdebug_pass_structure))
- CmdArgs.push_back("--debug-pass=Structure");
- if (Args.hasArg(options::OPT_fdebug_pass_arguments))
- CmdArgs.push_back("--debug-pass=Arguments");
- if (!Args.hasFlag(options::OPT_fmerge_all_constants,
- options::OPT_fno_merge_all_constants))
- CmdArgs.push_back("--no-merge-all-constants");
+ CmdArgs.push_back("-masm-verbose");
+ if (Args.hasArg(options::OPT_fdebug_pass_structure)) {
+ CmdArgs.push_back("-mdebug-pass");
+ CmdArgs.push_back("Structure");
+ }
+ if (Args.hasArg(options::OPT_fdebug_pass_arguments)) {
+ CmdArgs.push_back("-mdebug-pass");
+ CmdArgs.push_back("Arguments");
+ }
// This is a coarse approximation of what llvm-gcc actually does, both
// -fasynchronous-unwind-tables and -fnon-call-exceptions interact in more
@@ -751,15 +747,18 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
!Args.hasArg(options::OPT_mkernel));
if (Args.hasFlag(options::OPT_funwind_tables, options::OPT_fno_unwind_tables,
AsynchronousUnwindTables))
- CmdArgs.push_back("--unwind-tables=1");
- else
- CmdArgs.push_back("--unwind-tables=0");
+ CmdArgs.push_back("-munwind-tables");
+
+ if (Arg *A = Args.getLastArg(options::OPT_flimited_precision_EQ)) {
+ CmdArgs.push_back("-mlimit-float-precision");
+ CmdArgs.push_back(A->getValue(Args));
+ }
// FIXME: Handle -mtune=.
(void) Args.hasArg(options::OPT_mtune_EQ);
if (Arg *A = Args.getLastArg(options::OPT_mcmodel_EQ)) {
- CmdArgs.push_back("-code-model");
+ CmdArgs.push_back("-mcode-model");
CmdArgs.push_back(A->getValue(Args));
}
@@ -785,11 +784,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
getToolChain().IsMathErrnoDefault()))
CmdArgs.push_back("-fno-math-errno");
- if (Arg *A = Args.getLastArg(options::OPT_flimited_precision_EQ)) {
- CmdArgs.push_back("--limit-float-precision");
- CmdArgs.push_back(A->getValue(Args));
- }
-
Arg *Unsupported;
if ((Unsupported = Args.getLastArg(options::OPT_MG)) ||
(Unsupported = Args.getLastArg(options::OPT_MQ)) ||
@@ -865,7 +859,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
if (Args.hasArg(options::OPT__relocatable_pch))
- CmdArgs.push_back("--relocatable-pch");
+ CmdArgs.push_back("-relocatable-pch");
if (Arg *A = Args.getLastArg(options::OPT_fconstant_string_class_EQ)) {
CmdArgs.push_back("-fconstant-string-class");
@@ -873,13 +867,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
}
// Pass -fmessage-length=.
+ CmdArgs.push_back("-fmessage-length");
if (Arg *A = Args.getLastArg(options::OPT_fmessage_length_EQ)) {
- A->render(Args, CmdArgs);
+ CmdArgs.push_back(A->getValue(Args));
} else {
// If -fmessage-length=N was not specified, determine whether this is a
// terminal and, if so, implicitly define -fmessage-length appropriately.
unsigned N = llvm::sys::Process::StandardErrColumns();
- CmdArgs.push_back("-fmessage-length");
CmdArgs.push_back(Args.MakeArgString(llvm::Twine(N)));
}
@@ -931,30 +925,26 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-fblocks");
}
+ // -fexceptions=0 is default.
if (needsExceptions(Args, InputType, getToolChain().getTriple()))
CmdArgs.push_back("-fexceptions");
- else
- CmdArgs.push_back("-fexceptions=0");
// -frtti is default.
if (!Args.hasFlag(options::OPT_frtti, options::OPT_fno_rtti))
CmdArgs.push_back("-fno-rtti");
// -fsigned-char is default.
- if (!Args.hasFlag(options::OPT_fsigned_char,
- options::OPT_funsigned_char,
+ if (!Args.hasFlag(options::OPT_fsigned_char, options::OPT_funsigned_char,
isSignedCharDefault(getToolChain().getTriple())))
- CmdArgs.push_back("-fsigned-char=0");
+ CmdArgs.push_back("-fno-signed-char");
// -fms-extensions=0 is default.
- if (Args.hasFlag(options::OPT_fms_extensions,
- options::OPT_fno_ms_extensions,
+ 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,
+ if (!Args.hasFlag(options::OPT_fnext_runtime, options::OPT_fgnu_runtime,
getToolChain().getTriple().getOS() == llvm::Triple::Darwin))
CmdArgs.push_back("-fgnu-runtime");
@@ -1092,15 +1082,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Explicitly warn that these options are unsupported, even though
// we are allowing compilation to continue.
- // FIXME: Use iterator.
- for (ArgList::const_iterator
- it = Args.begin(), ie = Args.end(); it != ie; ++it) {
- const Arg *A = *it;
- if (A->getOption().matches(options::OPT_pg)) {
- A->claim();
- D.Diag(clang::diag::warn_drv_clang_unsupported)
- << A->getAsString(Args);
- }
+ for (arg_iterator it = Args.filtered_begin(options::OPT_pg),
+ ie = Args.filtered_end(); it != ie; ++it) {
+ it->claim();
+ D.Diag(clang::diag::warn_drv_clang_unsupported) << it->getAsString(Args);
}
// Claim some arguments which clang supports automatically.
@@ -1113,15 +1098,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
// Claim some arguments which clang doesn't support, but we don't
// care to warn the user about.
-
- // FIXME: Use iterator.
- for (ArgList::const_iterator
- it = Args.begin(), ie = Args.end(); it != ie; ++it) {
- const Arg *A = *it;
- if (A->getOption().matches(options::OPT_clang_ignored_f_Group) ||
- A->getOption().matches(options::OPT_clang_ignored_m_Group))
- A->claim();
- }
+ Args.ClaimAllArgs(options::OPT_clang_ignored_f_Group);
+ Args.ClaimAllArgs(options::OPT_clang_ignored_m_Group);
}
void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
@@ -1394,18 +1372,13 @@ void darwin::CC1::AddCC1OptionsArgs(const ArgList &Args, ArgStringList &CmdArgs,
// used to inhibit the default -fno-builtin-str{cat,cpy}.
//
// FIXME: Should we grow a better way to deal with "removing" args?
- //
- // FIXME: Use iterator.
- for (ArgList::const_iterator it = Args.begin(),
- ie = Args.end(); it != ie; ++it) {
- const Arg *A = *it;
- if (A->getOption().matches(options::OPT_f_Group) ||
- A->getOption().matches(options::OPT_fsyntax_only)) {
- if (!A->getOption().matches(options::OPT_fbuiltin_strcat) &&
- !A->getOption().matches(options::OPT_fbuiltin_strcpy)) {
- A->claim();
- A->render(Args, CmdArgs);
- }
+ for (arg_iterator it = Args.filtered_begin(options::OPT_f_Group,
+ options::OPT_fsyntax_only),
+ ie = Args.filtered_end(); it != ie; ++it) {
+ if (!it->getOption().matches(options::OPT_fbuiltin_strcat) &&
+ !it->getOption().matches(options::OPT_fbuiltin_strcpy)) {
+ it->claim();
+ it->render(Args, CmdArgs);
}
}
} else
diff --git a/lib/Driver/Types.cpp b/lib/Driver/Types.cpp
index 750286b66c96..339767722716 100644
--- a/lib/Driver/Types.cpp
+++ b/lib/Driver/Types.cpp
@@ -135,6 +135,7 @@ types::ID types::lookupTypeForExtension(const char *Ext) {
.Case("CC", TY_CXX)
.Case("cp", TY_CXX)
.Case("hh", TY_CXXHeader)
+ .Case("hpp", TY_CXXHeader)
.Case("ads", TY_Ada)
.Case("adb", TY_Ada)
.Case("ast", TY_AST)
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index e3cd6ddd08d6..f647c8a23705 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -14,25 +14,28 @@
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/PCHReader.h"
#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTConsumer.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/AST/StmtVisitor.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Frontend/FrontendOptions.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"
+#include "llvm/LLVMContext.h"
#include "llvm/System/Path.h"
-
using namespace clang;
-ASTUnit::ASTUnit(DiagnosticClient *diagClient) : tempFile(false) {
+ASTUnit::ASTUnit(DiagnosticClient *diagClient) : tempFile(false) {
Diags.setClient(diagClient ? diagClient : new TextDiagnosticBuffer());
}
-ASTUnit::~ASTUnit() {
+ASTUnit::~ASTUnit() {
if (tempFile)
llvm::sys::Path(getPCHFileName()).eraseFromDisk();
-
+
// The ASTUnit object owns the DiagnosticClient.
delete Diags.getClient();
}
@@ -41,7 +44,7 @@ namespace {
/// \brief Gathers information from PCHReader that will be used to initialize
/// a Preprocessor.
-class VISIBILITY_HIDDEN PCHInfoCollector : public PCHReaderListener {
+class PCHInfoCollector : public PCHReaderListener {
LangOptions &LangOpt;
HeaderSearch &HSI;
std::string &TargetTriple;
@@ -171,3 +174,90 @@ ASTUnit *ASTUnit::LoadFromPCHFile(const std::string &Filename,
return AST.take();
}
+
+namespace {
+
+class NullAction : public ASTFrontendAction {
+ virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
+ llvm::StringRef InFile) {
+ return new ASTConsumer();
+ }
+
+public:
+ virtual bool hasCodeCompletionSupport() const { return false; }
+};
+
+}
+
+ASTUnit *ASTUnit::LoadFromCompilerInvocation(const CompilerInvocation &CI,
+ Diagnostic &Diags,
+ bool OnlyLocalDecls,
+ bool UseBumpAllocator) {
+ // Create the compiler instance to use for building the AST.
+ CompilerInstance Clang(&llvm::getGlobalContext(), false);
+ llvm::OwningPtr<ASTUnit> AST;
+ NullAction Act;
+
+ Clang.getInvocation() = CI;
+
+ Clang.setDiagnostics(&Diags);
+ Clang.setDiagnosticClient(Diags.getClient());
+
+ // Create the target instance.
+ Clang.setTarget(TargetInfo::CreateTargetInfo(Clang.getDiagnostics(),
+ Clang.getTargetOpts()));
+ if (!Clang.hasTarget())
+ goto error;
+
+ // Inform the target of the language options.
+ //
+ // FIXME: We shouldn't need to do this, the target should be immutable once
+ // created. This complexity should be lifted elsewhere.
+ Clang.getTarget().setForcedLangOptions(Clang.getLangOpts());
+
+ assert(Clang.getFrontendOpts().Inputs.size() == 1 &&
+ "Invocation must have exactly one source file!");
+ assert(Clang.getFrontendOpts().Inputs[0].first != FrontendOptions::IK_AST &&
+ "FIXME: AST inputs not yet supported here!");
+
+ // Create the AST unit.
+ //
+ // FIXME: Use the provided diagnostic client.
+ AST.reset(new ASTUnit());
+
+ // Create a file manager object to provide access to and cache the filesystem.
+ Clang.setFileManager(&AST->getFileManager());
+
+ // Create the source manager.
+ Clang.setSourceManager(&AST->getSourceManager());
+
+ // Create the preprocessor.
+ Clang.createPreprocessor();
+
+ if (!Act.BeginSourceFile(Clang, Clang.getFrontendOpts().Inputs[0].second,
+ /*IsAST=*/false))
+ goto error;
+
+ Act.Execute();
+
+ // Steal the created context and preprocessor, and take back the source and
+ // file managers.
+ AST->Ctx.reset(Clang.takeASTContext());
+ AST->PP.reset(Clang.takePreprocessor());
+ Clang.takeSourceManager();
+ Clang.takeFileManager();
+
+ Act.EndSourceFile();
+
+ Clang.takeDiagnosticClient();
+ Clang.takeDiagnostics();
+
+ return AST.take();
+
+error:
+ Clang.takeSourceManager();
+ Clang.takeFileManager();
+ Clang.takeDiagnosticClient();
+ Clang.takeDiagnostics();
+ return 0;
+}
diff --git a/lib/Frontend/AnalysisConsumer.cpp b/lib/Frontend/AnalysisConsumer.cpp
index ede3d474c848..5df1eceb8850 100644
--- a/lib/Frontend/AnalysisConsumer.cpp
+++ b/lib/Frontend/AnalysisConsumer.cpp
@@ -30,7 +30,6 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Frontend/PathDiagnosticClients.h"
#include "clang/Lex/Preprocessor.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/System/Path.h"
#include "llvm/System/Program.h"
@@ -62,7 +61,7 @@ CreatePlistHTMLDiagnosticClient(const std::string& prefix,
namespace {
- class VISIBILITY_HIDDEN AnalysisConsumer : public ASTConsumer {
+ class AnalysisConsumer : public ASTConsumer {
public:
typedef void (*CodeAction)(AnalysisConsumer &C, AnalysisManager &M, Decl *D);
@@ -312,7 +311,8 @@ static void ActionWarnUninitVals(AnalysisConsumer &C, AnalysisManager& mgr,
}
-static void ActionGRExprEngine(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D,
+static void ActionGRExprEngine(AnalysisConsumer &C, AnalysisManager& mgr,
+ Decl *D,
GRTransferFuncs* tf) {
llvm::OwningPtr<GRTransferFuncs> TF(tf);
@@ -327,10 +327,6 @@ static void ActionGRExprEngine(AnalysisConsumer &C, AnalysisManager& mgr, Decl *
return;
GRExprEngine Eng(mgr);
-
- Eng.setTransferFunctions(tf);
- Eng.RegisterInternalChecks(); // FIXME: Internal checks should just
- // automatically register.
if (C.Opts.EnableExperimentalInternalChecks)
RegisterExperimentalInternalChecks(Eng);
@@ -339,6 +335,8 @@ static void ActionGRExprEngine(AnalysisConsumer &C, AnalysisManager& mgr, Decl *
if (C.Opts.EnableExperimentalChecks)
RegisterExperimentalChecks(Eng);
+
+ Eng.setTransferFunctions(tf);
// Set the graph auditor.
llvm::OwningPtr<ExplodedNode::Auditor> Auditor;
@@ -455,26 +453,8 @@ static void ActionWarnSizeofPointer(AnalysisConsumer &C, AnalysisManager &mgr,
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.
- GRExprEngine Eng(mgr);
-
- Eng.setTransferFunctions(TF.get());
- Eng.RegisterInternalChecks();
- RegisterAppleChecks(Eng, *D);
-
- // Execute the worklist algorithm.
- Eng.ExecuteWorkList(mgr.getStackFrame(D));
-
- // Visualize the exploded graph.
- if (mgr.shouldVisualizeGraphviz())
- Eng.ViewGraph(mgr.shouldTrimGraph());
+ ActionGRExprEngine(C, mgr, D, CreateCallInliner(mgr.getASTContext()));
}
//===----------------------------------------------------------------------===//
diff --git a/lib/Frontend/Backend.cpp b/lib/Frontend/Backend.cpp
index bc56029e73d2..9dc109da65ef 100644
--- a/lib/Frontend/Backend.cpp
+++ b/lib/Frontend/Backend.cpp
@@ -25,12 +25,9 @@
#include "llvm/Bitcode/ReaderWriter.h"
#include "llvm/CodeGen/RegAllocRegistry.h"
#include "llvm/CodeGen/SchedulerRegistry.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/Support/FormattedStream.h"
#include "llvm/Support/StandardPasses.h"
#include "llvm/Support/Timer.h"
-#include "llvm/System/Path.h"
-#include "llvm/System/Program.h"
#include "llvm/Target/SubtargetFeature.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetMachine.h"
@@ -39,10 +36,11 @@ using namespace clang;
using namespace llvm;
namespace {
- class VISIBILITY_HIDDEN BackendConsumer : public ASTConsumer {
+ class BackendConsumer : public ASTConsumer {
BackendAction Action;
- CodeGenOptions CodeGenOpts;
- TargetOptions TargetOpts;
+ const CodeGenOptions &CodeGenOpts;
+ const LangOptions &LangOpts;
+ const TargetOptions &TargetOpts;
llvm::raw_ostream *AsmOutStream;
llvm::formatted_raw_ostream FormattedOutStream;
ASTContext *Context;
@@ -78,10 +76,12 @@ namespace {
public:
BackendConsumer(BackendAction action, Diagnostic &Diags,
const LangOptions &langopts, const CodeGenOptions &compopts,
- const TargetOptions &targetopts, const std::string &infile,
- llvm::raw_ostream* OS, LLVMContext& C) :
+ const TargetOptions &targetopts, bool TimePasses,
+ const std::string &infile, llvm::raw_ostream *OS,
+ LLVMContext& C) :
Action(action),
CodeGenOpts(compopts),
+ LangOpts(langopts),
TargetOpts(targetopts),
AsmOutStream(OS),
LLVMIRGeneration("LLVM IR Generation Time"),
@@ -94,8 +94,7 @@ namespace {
FormattedOutStream.setStream(*AsmOutStream,
formatted_raw_ostream::PRESERVE_STREAM);
- // Enable -time-passes if -ftime-report is enabled.
- llvm::TimePassesIsEnabled = CodeGenOpts.TimePasses;
+ llvm::TimePassesIsEnabled = TimePasses;
}
~BackendConsumer() {
@@ -109,7 +108,7 @@ namespace {
virtual void Initialize(ASTContext &Ctx) {
Context = &Ctx;
- if (CodeGenOpts.TimePasses)
+ if (llvm::TimePassesIsEnabled)
LLVMIRGeneration.startTimer();
Gen->Initialize(Ctx);
@@ -118,7 +117,7 @@ namespace {
ModuleProvider = new ExistingModuleProvider(TheModule);
TheTargetData = new llvm::TargetData(Ctx.Target.getTargetDescription());
- if (CodeGenOpts.TimePasses)
+ if (llvm::TimePassesIsEnabled)
LLVMIRGeneration.stopTimer();
}
@@ -127,24 +126,24 @@ namespace {
Context->getSourceManager(),
"LLVM IR generation of declaration");
- if (CodeGenOpts.TimePasses)
+ if (llvm::TimePassesIsEnabled)
LLVMIRGeneration.startTimer();
Gen->HandleTopLevelDecl(D);
- if (CodeGenOpts.TimePasses)
+ if (llvm::TimePassesIsEnabled)
LLVMIRGeneration.stopTimer();
}
virtual void HandleTranslationUnit(ASTContext &C) {
{
PrettyStackTraceString CrashInfo("Per-file LLVM IR generation");
- if (CodeGenOpts.TimePasses)
+ if (llvm::TimePassesIsEnabled)
LLVMIRGeneration.startTimer();
Gen->HandleTranslationUnit(C);
- if (CodeGenOpts.TimePasses)
+ if (llvm::TimePassesIsEnabled)
LLVMIRGeneration.stopTimer();
}
@@ -215,11 +214,50 @@ bool BackendConsumer::AddEmitPasses(std::string &Error) {
return false;
}
+ // FIXME: Expose these capabilities via actual APIs!!!! Aside from just
+ // being gross, this is also totally broken if we ever care about
+ // concurrency.
+ std::vector<const char *> BackendArgs;
+ BackendArgs.push_back("clang"); // Fake program name.
+ if (CodeGenOpts.AsmVerbose)
+ BackendArgs.push_back("-asm-verbose");
+ if (!CodeGenOpts.CodeModel.empty()) {
+ BackendArgs.push_back("-code-model");
+ BackendArgs.push_back(CodeGenOpts.CodeModel.c_str());
+ }
+ if (!CodeGenOpts.DebugPass.empty()) {
+ BackendArgs.push_back("-debug-pass");
+ BackendArgs.push_back(CodeGenOpts.DebugPass.c_str());
+ }
+ if (CodeGenOpts.DisableFPElim)
+ BackendArgs.push_back("-disable-fp-elim");
+ if (!CodeGenOpts.FloatABI.empty()) {
+ BackendArgs.push_back("-float-abi");
+ BackendArgs.push_back(CodeGenOpts.FloatABI.c_str());
+ }
+ if (!CodeGenOpts.LimitFloatPrecision.empty()) {
+ BackendArgs.push_back("-limit-float-precision");
+ BackendArgs.push_back(CodeGenOpts.LimitFloatPrecision.c_str());
+ }
+ if (CodeGenOpts.NoZeroInitializedInBSS)
+ BackendArgs.push_back("-nozero-initialized-in-bss");
+ if (CodeGenOpts.SoftFloat)
+ BackendArgs.push_back("-soft-float");
+ BackendArgs.push_back("-relocation-model");
+ BackendArgs.push_back(CodeGenOpts.RelocationModel.c_str());
+ if (llvm::TimePassesIsEnabled)
+ BackendArgs.push_back("-time-passes");
+ if (CodeGenOpts.UnwindTables)
+ BackendArgs.push_back("-unwind-tables");
+ BackendArgs.push_back(0);
+ llvm::cl::ParseCommandLineOptions(BackendArgs.size() - 1,
+ (char**) &BackendArgs[0]);
+
std::string FeaturesStr;
if (TargetOpts.CPU.size() || TargetOpts.Features.size()) {
SubtargetFeatures Features;
Features.setCPU(TargetOpts.CPU);
- for (std::vector<std::string>::iterator
+ for (std::vector<std::string>::const_iterator
it = TargetOpts.Features.begin(),
ie = TargetOpts.Features.end(); it != ie; ++it)
Features.AddFeature(*it);
@@ -306,7 +344,7 @@ void BackendConsumer::CreatePasses() {
llvm::createStandardModulePasses(PM, OptLevel, CodeGenOpts.OptimizeSize,
CodeGenOpts.UnitAtATime,
CodeGenOpts.UnrollLoops,
- CodeGenOpts.SimplifyLibCalls,
+ /*SimplifyLibCalls=*/!LangOpts.NoBuiltin,
/*HaveExceptions=*/true,
InliningPass);
}
@@ -318,7 +356,7 @@ void BackendConsumer::EmitAssembly() {
if (!TheModule || !TheTargetData)
return;
- TimeRegion Region(CodeGenOpts.TimePasses ? &CodeGenerationTime : 0);
+ TimeRegion Region(llvm::TimePassesIsEnabled ? &CodeGenerationTime : 0);
// Make sure IR generation is happy with the module. This is
// released by the module provider.
@@ -375,9 +413,10 @@ ASTConsumer *clang::CreateBackendConsumer(BackendAction Action,
const LangOptions &LangOpts,
const CodeGenOptions &CodeGenOpts,
const TargetOptions &TargetOpts,
+ bool TimePasses,
const std::string& InFile,
llvm::raw_ostream* OS,
LLVMContext& C) {
return new BackendConsumer(Action, Diags, LangOpts, CodeGenOpts,
- TargetOpts, InFile, OS, C);
+ TargetOpts, TimePasses, InFile, OS, C);
}
diff --git a/lib/Frontend/CMakeLists.txt b/lib/Frontend/CMakeLists.txt
index 3f0f43099c69..03123d303f0c 100644
--- a/lib/Frontend/CMakeLists.txt
+++ b/lib/Frontend/CMakeLists.txt
@@ -21,6 +21,7 @@ add_clang_library(clangFrontend
HTMLPrint.cpp
InitHeaderSearch.cpp
InitPreprocessor.cpp
+ LangStandards.cpp
PCHReader.cpp
PCHReaderDecl.cpp
PCHReaderStmt.cpp
diff --git a/lib/Frontend/CacheTokens.cpp b/lib/Frontend/CacheTokens.cpp
index 339a1c466bc9..7296246df21a 100644
--- a/lib/Frontend/CacheTokens.cpp
+++ b/lib/Frontend/CacheTokens.cpp
@@ -22,7 +22,6 @@
#include "clang/Lex/Preprocessor.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringMap.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/System/Path.h"
@@ -40,7 +39,7 @@ using namespace clang::io;
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN PTHEntry {
+class PTHEntry {
Offset TokenData, PPCondData;
public:
@@ -54,7 +53,7 @@ public:
};
-class VISIBILITY_HIDDEN PTHEntryKeyVariant {
+class PTHEntryKeyVariant {
union { const FileEntry* FE; const char* Path; };
enum { IsFE = 0x1, IsDE = 0x2, IsNoExist = 0x0 } Kind;
struct stat *StatBuf;
@@ -105,7 +104,7 @@ public:
}
};
-class VISIBILITY_HIDDEN FileEntryPTHEntryInfo {
+class FileEntryPTHEntryInfo {
public:
typedef PTHEntryKeyVariant key_type;
typedef key_type key_type_ref;
@@ -169,7 +168,7 @@ typedef llvm::DenseMap<const IdentifierInfo*,uint32_t> IDMap;
typedef llvm::StringMap<OffsetOpt, llvm::BumpPtrAllocator> CachedStrsTy;
namespace {
-class VISIBILITY_HIDDEN PTHWriter {
+class PTHWriter {
IDMap IM;
llvm::raw_fd_ostream& Out;
Preprocessor& PP;
@@ -483,7 +482,8 @@ void PTHWriter::GeneratePTH(const std::string *MainFile) {
if (!B) continue;
FileID FID = SM.createFileID(FE, SourceLocation(), SrcMgr::C_User);
- Lexer L(FID, SM, LOpts);
+ const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID);
+ Lexer L(FID, FromFile, SM, LOpts);
PM.insert(FE, LexTokens(L));
}
@@ -577,7 +577,7 @@ public:
};
namespace {
-class VISIBILITY_HIDDEN PTHIdentifierTableTrait {
+class PTHIdentifierTableTrait {
public:
typedef PTHIdKey* key_type;
typedef key_type key_type_ref;
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
index 0365761c840e..1083d5ef1c02 100644
--- a/lib/Frontend/CompilerInstance.cpp
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -27,7 +27,9 @@
#include "llvm/LLVMContext.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/Timer.h"
#include "llvm/System/Path.h"
+#include "llvm/System/Program.h"
using namespace clang;
CompilerInstance::CompilerInstance(llvm::LLVMContext *_LLVMContext,
@@ -255,6 +257,16 @@ void CompilerInstance::createCodeCompletionConsumer() {
getFrontendOpts().DebugCodeCompletionPrinter,
getFrontendOpts().ShowMacrosInCodeCompletion,
llvm::outs()));
+
+ if (CompletionConsumer->isOutputBinary() &&
+ llvm::sys::Program::ChangeStdoutToBinary()) {
+ getPreprocessor().getDiagnostics().Report(diag::err_fe_stdout_binary);
+ CompletionConsumer.reset();
+ }
+}
+
+void CompilerInstance::createFrontendTimer() {
+ FrontendTimer.reset(new llvm::Timer("Clang front-end timer"));
}
CodeCompleteConsumer *
@@ -321,7 +333,7 @@ CompilerInstance::createOutputFile(llvm::StringRef OutputPath,
&OutputPathName);
if (!OS) {
// FIXME: Don't fail this way.
- llvm::errs() << "ERROR: " << Error << "\n";
+ llvm::errs() << "error: " << Error << "\n";
::exit(1);
}
@@ -353,16 +365,16 @@ CompilerInstance::createOutputFile(llvm::StringRef OutputPath,
OutFile = "-";
}
- llvm::raw_fd_ostream *OS =
+ llvm::OwningPtr<llvm::raw_fd_ostream> OS(
new llvm::raw_fd_ostream(OutFile.c_str(), Error,
- (Binary ? llvm::raw_fd_ostream::F_Binary : 0));
- if (!OS)
+ (Binary ? llvm::raw_fd_ostream::F_Binary : 0)));
+ if (!Error.empty())
return 0;
if (ResultPathName)
*ResultPathName = OutFile;
- return OS;
+ return OS.take();
}
// Initialization Utilities
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index b4a79c6d1efb..c5375079506b 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -8,20 +8,32 @@
//===----------------------------------------------------------------------===//
#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/Version.h"
+#include "clang/Driver/Arg.h"
+#include "clang/Driver/ArgList.h"
+#include "clang/Driver/CC1Options.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/OptTable.h"
+#include "clang/Driver/Option.h"
+#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Frontend/LangStandard.h"
+#include "clang/Frontend/PCHReader.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/System/Host.h"
+#include "llvm/System/Path.h"
using namespace clang;
-void CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
- const llvm::SmallVectorImpl<llvm::StringRef> &Args) {
-}
-
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;
+ case NAME: return "-" CMDFLAG;
#include "clang/Frontend/Analyses.def"
}
}
@@ -56,6 +68,10 @@ static const char *getAnalysisDiagClientName(AnalysisDiagClients Kind) {
}
}
+//===----------------------------------------------------------------------===//
+// Serialization (to args)
+//===----------------------------------------------------------------------===//
+
static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts,
std::vector<std::string> &Res) {
for (unsigned i = 0, e = Opts.AnalysisList.size(); i != e; ++i)
@@ -93,7 +109,7 @@ static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts,
if (Opts.EnableExperimentalChecks)
Res.push_back("-analyzer-experimental-checks");
if (Opts.EnableExperimentalInternalChecks)
- Res.push_back("-analyzer-experimental-internal-checls");
+ Res.push_back("-analyzer-experimental-internal-checks");
}
static void CodeGenOptsToArgs(const CodeGenOptions &Opts,
@@ -106,20 +122,56 @@ static void CodeGenOptsToArgs(const CodeGenOptions &Opts,
Res.push_back("-disable-red-zone");
if (!Opts.MergeAllConstants)
Res.push_back("-fno-merge-all-constants");
- // NoCommon is only derived.
+ if (Opts.NoCommon)
+ Res.push_back("-fno-common");
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);
+ } else if (Opts.OptimizationLevel != 0)
+ Res.push_back("-O" + llvm::utostr(Opts.OptimizationLevel));
+ if (!Opts.MainFileName.empty()) {
+ Res.push_back("-main-file-name");
+ Res.push_back(Opts.MainFileName);
+ }
// SimplifyLibCalls is only derived.
// TimePasses is only derived.
// UnitAtATime is unused.
// UnrollLoops is only derived.
// VerifyModule is only derived.
// Inlining is only derived.
+
+ if (Opts.AsmVerbose)
+ Res.push_back("-masm-verbose");
+ if (!Opts.CodeModel.empty()) {
+ Res.push_back("-mcode-model");
+ Res.push_back(Opts.CodeModel);
+ }
+ if (!Opts.DebugPass.empty()) {
+ Res.push_back("-mdebug-pass");
+ Res.push_back(Opts.DebugPass);
+ }
+ if (Opts.DisableFPElim)
+ Res.push_back("-mdisable-fp-elim");
+ if (!Opts.FloatABI.empty()) {
+ Res.push_back("-mfloat-abi");
+ Res.push_back(Opts.FloatABI);
+ }
+ if (!Opts.LimitFloatPrecision.empty()) {
+ Res.push_back("-mlimit-float-precision");
+ Res.push_back(Opts.LimitFloatPrecision);
+ }
+ if (Opts.NoZeroInitializedInBSS)
+ Res.push_back("-mno-zero-initialized-bss");
+ if (Opts.SoftFloat)
+ Res.push_back("-msoft-float");
+ if (Opts.UnwindTables)
+ Res.push_back("-munwind-tables");
+ if (Opts.RelocationModel != "pic") {
+ Res.push_back("-mrelocation-model");
+ Res.push_back(Opts.RelocationModel);
+ }
}
static void DependencyOutputOptsToArgs(const DependencyOutputOptions &Opts,
@@ -178,18 +230,18 @@ static void DiagnosticOptsToArgs(const DiagnosticOptions &Opts,
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";
+ 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!");
@@ -247,7 +299,7 @@ static void FrontendOptsToArgs(const FrontendOptions &Opts,
if (Opts.ShowMacrosInCodeCompletion)
Res.push_back("-code-completion-macros");
if (Opts.ShowStats)
- Res.push_back("-stats");
+ Res.push_back("-print-stats");
if (Opts.ShowTimers)
Res.push_back("-ftime-report");
@@ -305,13 +357,13 @@ static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts,
/// 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))
+ 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");
+ Res.push_back("-iquote");
} else if (E.Group == frontend::System) {
Res.push_back("-isystem");
} else {
@@ -391,8 +443,8 @@ static void LangOptsToArgs(const LangOptions &Opts,
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");
+ if (Opts.Exceptions)
+ Res.push_back("-fexceptions");
if (!Opts.Rtti)
Res.push_back("-fno-rtti");
if (!Opts.NeXTRuntime)
@@ -406,7 +458,7 @@ static void LangOptsToArgs(const LangOptions &Opts,
if (Opts.POSIXThreads)
Res.push_back("-pthread");
if (Opts.Blocks)
- Res.push_back("-fblocks=1");
+ Res.push_back("-fblocks");
if (Opts.EmitAllDecls)
Res.push_back("-femit-all-decls");
if (!Opts.MathErrno)
@@ -425,12 +477,13 @@ static void LangOptsToArgs(const LangOptions &Opts,
}
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");
+ // FIXME: Don't forget to update when the default changes!
+ if (Opts.AccessControl)
+ Res.push_back("-faccess-control");
+ if (!Opts.CharIsSigned)
+ Res.push_back("-fno-signed-char");
+ if (Opts.ShortWChar)
+ Res.push_back("-fshort-wchar");
if (!Opts.ElideConstructors)
Res.push_back("-fno-elide-constructors");
if (Opts.getGCMode() != LangOptions::NonGC) {
@@ -444,7 +497,7 @@ static void LangOptsToArgs(const LangOptions &Opts,
if (Opts.getVisibilityMode() != LangOptions::Default) {
Res.push_back("-fvisibility");
if (Opts.getVisibilityMode() == LangOptions::Hidden) {
- Res.push_back("default");
+ Res.push_back("hidden");
} else {
assert(Opts.getVisibilityMode() == LangOptions::Protected &&
"Invalid visibility!");
@@ -455,15 +508,11 @@ static void LangOptsToArgs(const LangOptions &Opts,
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) {
+ if (!Opts.ObjCConstantStringClass.empty()) {
Res.push_back("-fconstant-string-class");
Res.push_back(Opts.ObjCConstantStringClass);
}
@@ -472,28 +521,34 @@ static void LangOptsToArgs(const LangOptions &Opts,
static void PreprocessorOptsToArgs(const PreprocessorOptions &Opts,